Skip to content

Commit

Permalink
rhp/v3: disable renew RPC after allow height, disable rhp3 after requ…
Browse files Browse the repository at this point in the history
…ire height
  • Loading branch information
n8maninger committed Aug 20, 2024
1 parent 17241f9 commit 03f26df
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 0 deletions.
7 changes: 7 additions & 0 deletions rhp/v3/rhp.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,13 @@ func (sh *SessionHandler) Serve() error {
return
}

cs := sh.chain.TipState()
// disable rhp3 after v2 require height
if cs.Index.Height >= cs.Network.HardforkV2.RequireHeight {
stream.WriteResponseErr(ErrV2Hardfork)
return
}

go sh.handleHostStream(stream, sessionID, log)
}
}()
Expand Down
21 changes: 21 additions & 0 deletions rhp/v3/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ var (
// ErrNotAcceptingContracts is returned when the host is not accepting
// contracts.
ErrNotAcceptingContracts = errors.New("host is not accepting contracts")

// ErrV2Hardfork is returned when a renter tries to form or renew a contract
// after the v2 hardfork has been activated.
ErrV2Hardfork = errors.New("hardfork v2 is active")

// ErrAfterV2Hardfork is returned when a renter tries to form or renew a
// contract that ends after the v2 hardfork has been activated.
ErrAfterV2Hardfork = errors.New("proof window after hardfork v2 activation")
)

// handleRPCPriceTable sends the host's price table to the renter.
Expand Down Expand Up @@ -239,6 +247,13 @@ func (sh *SessionHandler) handleRPCLatestRevision(s *rhp3.Stream, log *zap.Logge
}

func (sh *SessionHandler) handleRPCRenew(s *rhp3.Stream, log *zap.Logger) (contracts.Usage, error) {
cs := sh.chain.TipState()
// prevent renewing v1 contracts after the allow height
if cs.Index.Height >= cs.Network.HardforkV2.AllowHeight {
s.WriteResponseErr(ErrV2Hardfork)
return contracts.Usage{}, ErrV2Hardfork
}

s.SetDeadline(time.Now().Add(2 * time.Minute))
if !sh.settings.Settings().AcceptingContracts {
s.WriteResponseErr(ErrNotAcceptingContracts)
Expand Down Expand Up @@ -287,6 +302,12 @@ func (sh *SessionHandler) handleRPCRenew(s *rhp3.Stream, log *zap.Logger) (contr
clearingRevision := renewalTxn.FileContractRevisions[0]
renewal := renewalTxn.FileContracts[0]

// prevent forming v1 contracts with proof windows after the v2 hardfork
if renewal.WindowStart >= cs.Network.HardforkV2.RequireHeight {
s.WriteResponseErr(ErrAfterV2Hardfork)
return contracts.Usage{}, ErrAfterV2Hardfork
}

// lock the existing contract
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
Expand Down
65 changes: 65 additions & 0 deletions rhp/v3/rpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package rhp_test
import (
"bytes"
"context"
"errors"
"net"
"path/filepath"
"reflect"
Expand Down Expand Up @@ -579,3 +580,67 @@ func TestRenew(t *testing.T) {
assertRenewal(t, origin.ID(), renewal, 1, origin.Revision.FileMerkleRoot, origin.Revision.Filesize)
})
}

func TestRPCV2(t *testing.T) {
log := zaptest.NewLogger(t)
renterKey, hostKey := types.GeneratePrivateKey(), types.GeneratePrivateKey()
network, genesis := testutil.V2Network()
network.HardforkV2.AllowHeight = 180
network.HardforkV2.RequireHeight = 200
node := testutil.NewHostNode(t, hostKey, network, genesis, log)

// set the host to accept contracts
s := node.Settings.Settings()
s.AcceptingContracts = true
s.NetAddress = "localhost:9983"
if err := node.Settings.UpdateSettings(s); err != nil {
t.Fatal(err)
}

// initialize a storage volume
res := make(chan error)
if _, err := node.Volumes.AddVolume(context.Background(), filepath.Join(t.TempDir(), "storage.dat"), 10, res); err != nil {
t.Fatal(err)
} else if err := <-res; err != nil {
t.Fatal(err)
}

// fund the wallet
testutil.MineAndSync(t, node, node.Wallet.Address(), 150)

// start the node
sh2, sh3 := setupRHP3Host(t, node, hostKey, 10, log)

// form a contract that expires before the hardfork
origin := formContract(t, node.Chain, node.Wallet, sh2.LocalAddr(), renterKey, hostKey.PublicKey(), 20)
// mine a block to confirm the contract
testutil.MineAndSync(t, node, node.Wallet.Address(), 1)

// create a RHP3 session
session, err := proto3.NewSession(context.Background(), hostKey.PublicKey(), sh3.LocalAddr(), node.Chain, node.Wallet)
if err != nil {
t.Fatal(err)
}
defer session.Close()

// try to renew the contract with an ending after the hardfork
renewHeight := network.HardforkV2.RequireHeight
renterFunds := types.Siacoins(10)
additionalCollateral := types.Siacoins(20)
_, _, err = session.RenewContract(&origin, node.Wallet.Address(), renterKey, renterFunds, additionalCollateral, renewHeight)
if !errors.Is(err, rhp3.ErrAfterV2Hardfork) {
t.Fatalf("expected after v2 hardfork error, got %v", err)
}

// mine to activate the v2 hardfork
testutil.MineAndSync(t, node, node.Wallet.Address(), int(network.HardforkV2.AllowHeight-node.Chain.Tip().Height))

// try to renew the contract with an end height before the require height, but after the hardfork activation
renewHeight = origin.Revision.WindowEnd + 10
renterFunds = types.Siacoins(10)
additionalCollateral = types.Siacoins(20)
_, _, err = session.RenewContract(&origin, node.Wallet.Address(), renterKey, renterFunds, additionalCollateral, renewHeight)
if !errors.Is(err, rhp3.ErrV2Hardfork) {
t.Fatalf("expected v2 hardfork error, got %v", err)
}
}

0 comments on commit 03f26df

Please sign in to comment.