diff --git a/models/transaction.go b/models/transaction.go index 9b39daa70..c8cb97152 100644 --- a/models/transaction.go +++ b/models/transaction.go @@ -10,9 +10,24 @@ import ( "github.com/onflow/cadence" "github.com/onflow/flow-go/fvm/evm/types" "github.com/onflow/go-ethereum/common" + "github.com/onflow/go-ethereum/core/txpool" gethTypes "github.com/onflow/go-ethereum/core/types" ) +const ( + // txSlotSize is used to calculate how many data slots a single transaction + // takes up based on its size. The slots are used as DoS protection, ensuring + // that validating a new transaction remains a constant operation (in reality + // O(maxslots), where max slots are 4 currently). + TxSlotSize = 32 * 1024 + + // txMaxSize is the maximum size a single transaction can have. This field has + // non-trivial consequences: larger transactions are significantly harder and + // more expensive to propagate; larger transactions also take more resources + // to validate whether they fit into the pool or not. + TxMaxSize = 4 * TxSlotSize // 128KB +) + type Transaction interface { Hash() common.Hash RawSignatureValues() (v *big.Int, r *big.Int, s *big.Int) @@ -204,7 +219,12 @@ func UnmarshalTransaction(value []byte) (Transaction, error) { return TransactionCall{Transaction: tx}, nil } -func ValidateTransaction(tx *gethTypes.Transaction) error { +func ValidateTransaction( + tx *gethTypes.Transaction, + head *gethTypes.Header, + signer gethTypes.Signer, + opts *txpool.ValidationOptions, +) error { txDataLen := len(tx.Data()) // Contract creation doesn't validate call data, handle first @@ -255,5 +275,9 @@ func ValidateTransaction(tx *gethTypes.Transaction) error { } } + if err := txpool.ValidateTransaction(tx, head, signer, opts); err != nil { + return err + } + return nil } diff --git a/models/transaction_test.go b/models/transaction_test.go index e5979e608..d9be007c4 100644 --- a/models/transaction_test.go +++ b/models/transaction_test.go @@ -1,16 +1,27 @@ package models import ( + "crypto/ecdsa" + crand "crypto/rand" _ "embed" "encoding/hex" + "fmt" "math/big" "testing" + "time" + + "math/rand" "github.com/onflow/cadence" "github.com/onflow/cadence/runtime/common" + "github.com/onflow/flow-go/fvm/evm/emulator" "github.com/onflow/flow-go/fvm/evm/types" gethCommon "github.com/onflow/go-ethereum/common" + "github.com/onflow/go-ethereum/core" + "github.com/onflow/go-ethereum/core/txpool" gethTypes "github.com/onflow/go-ethereum/core/types" + "github.com/onflow/go-ethereum/crypto" + "github.com/onflow/go-ethereum/params" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -388,9 +399,41 @@ func TestValidateTransaction(t *testing.T) { }, } + head := &gethTypes.Header{ + Number: big.NewInt(20_182_324), + Time: uint64(time.Now().Unix()), + GasLimit: 30_000_000, + } + emulatorConfig := emulator.NewConfig( + emulator.WithChainID(types.FlowEVMPreviewNetChainID), + emulator.WithBlockNumber(head.Number), + emulator.WithBlockTime(head.Time), + ) + signer := emulator.GetSigner(emulatorConfig) + opts := &txpool.ValidationOptions{ + Config: emulatorConfig.ChainConfig, + Accept: 0 | + 1<