Skip to content

Commit

Permalink
consensus: fix renewal payout validation
Browse files Browse the repository at this point in the history
  • Loading branch information
n8maninger authored and ChrisSchinnerl committed Dec 3, 2024
1 parent 866a892 commit 1173eac
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 5 deletions.
22 changes: 17 additions & 5 deletions consensus/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -780,12 +780,24 @@ func validateV2FileContracts(ms *MidState, txn types.V2Transaction) error {
case *types.V2FileContractRenewal:
renewal := *r

if fc.RenterPublicKey != renewal.NewContract.RenterPublicKey {
return fmt.Errorf("file contract renewal %v changes renter public key", i)
} else if fc.HostPublicKey != renewal.NewContract.HostPublicKey {
return fmt.Errorf("file contract renewal %v changes host public key", i)
}

// validate that the renewal value is equal to existing contract's value.
// This must be done as a sum of the outputs, since the individual payouts may have
// changed in an unbroadcast revision.
totalPayout := renewal.FinalRenterOutput.Value.Add(renewal.RenterRollover).
Add(renewal.FinalHostOutput.Value).Add(renewal.HostRollover)
existingPayout := fc.RenterOutput.Value.Add(fc.HostOutput.Value)
if totalPayout != existingPayout {
return fmt.Errorf("file contract renewal %d renewal payout (%s) does not match existing contract payout %s", i, totalPayout, existingPayout)
}

newContractCost := renewal.NewContract.RenterOutput.Value.Add(renewal.NewContract.HostOutput.Value).Add(ms.base.V2FileContractTax(renewal.NewContract))
if totalRenter := renewal.FinalRenterOutput.Value.Add(renewal.RenterRollover); totalRenter != fc.RenterOutput.Value {
return fmt.Errorf("file contract renewal %v renter payout plus rollover (%d H) does not match old contract payout (%d H)", i, totalRenter, fc.RenterOutput.Value)
} else if totalHost := renewal.FinalHostOutput.Value.Add(renewal.HostRollover); totalHost != fc.HostOutput.Value {
return fmt.Errorf("file contract renewal %v host payout plus rollover (%d H) does not match old contract payout (%d H)", i, totalHost, fc.HostOutput.Value)
} else if rollover := renewal.RenterRollover.Add(renewal.HostRollover); rollover.Cmp(newContractCost) > 0 {
if rollover := renewal.RenterRollover.Add(renewal.HostRollover); rollover.Cmp(newContractCost) > 0 {
return fmt.Errorf("file contract renewal %v has rollover (%d H) exceeding new contract cost (%d H)", i, rollover, newContractCost)
} else if err := validateContract(renewal.NewContract); err != nil {
return fmt.Errorf("file contract renewal %v initial revision %s", i, err)
Expand Down
22 changes: 22 additions & 0 deletions consensus/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1925,6 +1925,28 @@ func TestV2RenewalResolution(t *testing.T) {
},
errString: "invalid host signature",
},
{
desc: "invalid renewal - different host key",
renewFn: func(txn *types.V2Transaction) {
renewal := txn.FileContractResolutions[0].Resolution.(*types.V2FileContractRenewal)
sk := types.GeneratePrivateKey()
renewal.NewContract.HostPublicKey = sk.PublicKey()
contractSigHash := cs.ContractSigHash(renewal.NewContract)
renewal.NewContract.HostSignature = sk.SignHash(contractSigHash)
},
errString: "changes host public key",
},
{
desc: "invalid renewal - different renter key",
renewFn: func(txn *types.V2Transaction) {
renewal := txn.FileContractResolutions[0].Resolution.(*types.V2FileContractRenewal)
sk := types.GeneratePrivateKey()
renewal.NewContract.RenterPublicKey = sk.PublicKey()
contractSigHash := cs.ContractSigHash(renewal.NewContract)
renewal.NewContract.RenterSignature = sk.SignHash(contractSigHash)
},
errString: "changes renter public key",
},
{
desc: "invalid renewal - not enough host funds",
renewFn: func(txn *types.V2Transaction) {
Expand Down
4 changes: 4 additions & 0 deletions rhp/v4/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,12 @@ func (r *RPCRenewContractResponse) maxLen() int {

func (r *RPCRenewContractSecondResponse) encodeTo(e *types.Encoder) {
r.RenterRenewalSignature.EncodeTo(e)
r.RenterContractSignature.EncodeTo(e)
types.EncodeSlice(e, r.RenterSatisfiedPolicies)
}
func (r *RPCRenewContractSecondResponse) decodeFrom(d *types.Decoder) {
r.RenterRenewalSignature.DecodeFrom(d)
r.RenterContractSignature.DecodeFrom(d)
types.DecodeSlice(d, &r.RenterSatisfiedPolicies)
}
func (r *RPCRenewContractSecondResponse) maxLen() int {
Expand Down Expand Up @@ -331,10 +333,12 @@ func (r *RPCRefreshContractResponse) maxLen() int {

func (r *RPCRefreshContractSecondResponse) encodeTo(e *types.Encoder) {
r.RenterRenewalSignature.EncodeTo(e)
r.RenterContractSignature.EncodeTo(e)
types.EncodeSlice(e, r.RenterSatisfiedPolicies)
}
func (r *RPCRefreshContractSecondResponse) decodeFrom(d *types.Decoder) {
r.RenterRenewalSignature.DecodeFrom(d)
r.RenterContractSignature.DecodeFrom(d)
types.DecodeSlice(d, &r.RenterSatisfiedPolicies)
}
func (r *RPCRefreshContractSecondResponse) maxLen() int {
Expand Down
2 changes: 2 additions & 0 deletions rhp/v4/rhp.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ type (
// RPCRefreshContractSecondResponse implements Object.
RPCRefreshContractSecondResponse struct {
RenterRenewalSignature types.Signature `json:"renterRenewalSignature"`
RenterContractSignature types.Signature `json:"renterContractSignature"`
RenterSatisfiedPolicies []types.SatisfiedPolicy `json:"renterSatisfiedPolicies"`
}
// RPCRefreshContractThirdResponse implements Object.
Expand Down Expand Up @@ -344,6 +345,7 @@ type (
// RPCRenewContractSecondResponse implements Object.
RPCRenewContractSecondResponse struct {
RenterRenewalSignature types.Signature `json:"renterRenewalSignature"`
RenterContractSignature types.Signature `json:"renterContractSignature"`
RenterSatisfiedPolicies []types.SatisfiedPolicy `json:"renterSatisfiedPolicies"`
}
// RPCRenewContractThirdResponse implements Object.
Expand Down

0 comments on commit 1173eac

Please sign in to comment.