Skip to content

Commit

Permalink
rhp4: fix missing signatures, add regression checks
Browse files Browse the repository at this point in the history
  • Loading branch information
n8maninger committed Dec 3, 2024
1 parent 2bcb90e commit 83ba3e0
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 11 deletions.
1 change: 1 addition & 0 deletions rhp/v4/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ func RPCAppendSectors(ctx context.Context, t TransportClient, cs consensus.State
} else if !contract.Revision.HostPublicKey.VerifyHash(sigHash, hostSignature.HostSignature) {
return RPCAppendSectorsResult{}, rhp4.ErrInvalidSignature
}
revision.HostSignature = hostSignature.HostSignature
return RPCAppendSectorsResult{
Revision: revision,
Usage: usage,
Expand Down
24 changes: 24 additions & 0 deletions rhp/v4/rpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,27 @@ func TestAppendSectors(t *testing.T) {
}
revision := formResult.Contract

assertLastRevision := func(t *testing.T) {
t.Helper()

lastRev, err := rhp4.RPCLatestRevision(context.Background(), transport, revision.ID)
if err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(lastRev, revision.Revision) {
t.Log(lastRev)
t.Log(revision.Revision)
t.Fatalf("expected last revision to match")
}

sigHash := cm.TipState().ContractSigHash(revision.Revision)
if !renterKey.PublicKey().VerifyHash(sigHash, lastRev.RenterSignature) {
t.Fatal("renter signature invalid")
} else if !hostKey.PublicKey().VerifyHash(sigHash, lastRev.HostSignature) {
t.Fatal("host signature invalid")
}
}
assertLastRevision(t)

cs := cm.TipState()
account := proto4.Account(renterKey.PublicKey())

Expand All @@ -876,6 +897,7 @@ func TestAppendSectors(t *testing.T) {
t.Fatal(err)
}
revision.Revision = fundResult.Revision
assertLastRevision(t)

token := proto4.AccountToken{
Account: account,
Expand Down Expand Up @@ -915,6 +937,8 @@ func TestAppendSectors(t *testing.T) {
if appendResult.Revision.FileMerkleRoot != proto4.MetaRoot(roots) {
t.Fatal("root mismatch")
}
revision.Revision = appendResult.Revision
assertLastRevision(t)

// read the sectors back
buf := bytes.NewBuffer(make([]byte, 0, proto4.SectorSize))
Expand Down
13 changes: 2 additions & 11 deletions rhp/v4/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,6 @@ import (
"lukechampine.com/frand"
)

const (
sectorsPerTiB = (1 << 40) / (1 << 22)
memoryPer1TiB = sectorsPerTiB * 32

sectorsPer10TiB = 10 * sectorsPerTiB
memoryPer10TiB = sectorsPer10TiB * 32

sectorsPer100TiB = 100 * sectorsPerTiB
memoryPer100TiB = sectorsPer100TiB * 32
)

var protocolVersion = [3]byte{4, 0, 0}

type (
Expand Down Expand Up @@ -435,6 +424,7 @@ func (s *Server) handleRPCFundAccounts(stream net.Conn) error {
if !revision.RenterPublicKey.VerifyHash(sigHash, req.RenterSignature) {
return rhp4.ErrInvalidSignature
}
revision.RenterSignature = req.RenterSignature
revision.HostSignature = s.hostKey.SignHash(sigHash)

balances, err := s.contractor.CreditAccountsWithContract(req.Deposits, req.ContractID, revision, usage)
Expand Down Expand Up @@ -498,6 +488,7 @@ func (s *Server) handleRPCSectorRoots(stream net.Conn) error {

// sign the revision
revision.HostSignature = s.hostKey.SignHash(sigHash)
revision.RenterSignature = req.RenterSignature

// update the contract
err = s.contractor.ReviseV2Contract(req.ContractID, revision, state.Roots, usage)
Expand Down
37 changes: 37 additions & 0 deletions testutil/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"sync"
"testing"

"go.sia.tech/core/consensus"
proto4 "go.sia.tech/core/rhp/v4"
"go.sia.tech/core/types"
"go.sia.tech/coreutils/chain"
Expand Down Expand Up @@ -119,6 +120,13 @@ func (ec *EphemeralContractor) AddV2Contract(formationSet rhp4.TransactionSet, _
}
fc := formationTxn.FileContracts[0]

sigHash := consensus.State{}.ContractSigHash(fc)
if !fc.RenterPublicKey.VerifyHash(sigHash, fc.RenterSignature) {
return errors.New("invalid renter signature")
} else if !fc.HostPublicKey.VerifyHash(sigHash, fc.HostSignature) {
return errors.New("invalid host signature")
}

contractID := formationTxn.V2FileContractID(formationTxn.ID(), 0)
if _, ok := ec.contracts[contractID]; ok {
return errors.New("contract already exists")
Expand Down Expand Up @@ -160,6 +168,13 @@ func (ec *EphemeralContractor) RenewV2Contract(renewalSet rhp4.TransactionSet, _
return errors.New("contract already exists")
}

sigHash := consensus.State{}.ContractSigHash(renewal.NewContract)
if !existing.RenterPublicKey.VerifyHash(sigHash, renewal.NewContract.RenterSignature) {
return errors.New("invalid renter signature")
} else if !existing.HostPublicKey.VerifyHash(sigHash, renewal.NewContract.HostSignature) {
return errors.New("invalid host signature")
}

delete(ec.contracts, existingID) // remove the existing contract
ec.contracts[contractID] = renewal.NewContract
ec.roots[contractID] = append([]types.Hash256(nil), ec.roots[existingID]...)
Expand All @@ -179,6 +194,13 @@ func (ec *EphemeralContractor) ReviseV2Contract(contractID types.FileContractID,
return errors.New("revision number must be greater than existing")
}

sigHash := consensus.State{}.ContractSigHash(revision)
if !existing.RenterPublicKey.VerifyHash(sigHash, revision.RenterSignature) {
return errors.New("invalid renter signature")
} else if !existing.HostPublicKey.VerifyHash(sigHash, revision.HostSignature) {
return errors.New("invalid host signature")
}

ec.contracts[contractID] = revision
ec.roots[contractID] = append([]types.Hash256(nil), roots...)
return nil
Expand All @@ -202,11 +224,26 @@ func (ec *EphemeralContractor) CreditAccountsWithContract(deposits []proto4.Acco
ec.mu.Lock()
defer ec.mu.Unlock()

existing, ok := ec.contracts[contractID]
if !ok {
return nil, errors.New("contract not found")
} else if revision.RevisionNumber <= existing.RevisionNumber {
return nil, errors.New("revision number must be greater than existing")
}

sigHash := consensus.State{}.ContractSigHash(revision)
if !existing.RenterPublicKey.VerifyHash(sigHash, revision.RenterSignature) {
return nil, errors.New("invalid renter signature")
} else if !existing.HostPublicKey.VerifyHash(sigHash, revision.HostSignature) {
return nil, errors.New("invalid host signature")
}

var balance = make([]types.Currency, 0, len(deposits))
for _, deposit := range deposits {
ec.accounts[deposit.Account] = ec.accounts[deposit.Account].Add(deposit.Amount)
balance = append(balance, ec.accounts[deposit.Account])
}

ec.contracts[contractID] = revision
return balance, nil
}
Expand Down

0 comments on commit 83ba3e0

Please sign in to comment.