From 04ba09439e33492f78bcbed23243993686941b78 Mon Sep 17 00:00:00 2001 From: Stefano Charissis Date: Thu, 16 Jan 2025 18:02:56 +1100 Subject: [PATCH] feat: nat; per-validator configuration. --- op-nat/gate.go | 16 ++- op-nat/gate_test.go | 96 ++++++++++++++ op-nat/nat.go | 8 +- op-nat/nat_test.go | 117 ++++++++++++++++++ op-nat/suite.go | 14 ++- op-nat/suite_test.go | 65 ++++++++++ op-nat/test.go | 19 ++- op-nat/test_test.go | 103 +++++++++++++++ op-nat/validator.go | 2 +- .../suites/{deposit-suite.go => deposit.go} | 5 + op-nat/validators/suites/load-test.go | 7 ++ op-nat/validators/suites/simple-transfer.go | 1 + .../tests/network-get-blocknumber.go | 2 +- .../validators/tests/network-get-chainid.go | 2 +- op-nat/validators/tests/simple-deposit.go | 16 ++- op-nat/validators/tests/simple-transfer.go | 2 +- op-nat/validators/tests/tx-fuzz.go | 36 ++++-- 17 files changed, 478 insertions(+), 33 deletions(-) create mode 100644 op-nat/gate_test.go create mode 100644 op-nat/nat_test.go create mode 100644 op-nat/suite_test.go create mode 100644 op-nat/test_test.go rename op-nat/validators/suites/{deposit-suite.go => deposit.go} (66%) diff --git a/op-nat/gate.go b/op-nat/gate.go index 1b520a22137c..7ca58c708809 100644 --- a/op-nat/gate.go +++ b/op-nat/gate.go @@ -12,24 +12,34 @@ var _ Validator = &Gate{} // A Gate is a collection of suites and/or tests. type Gate struct { ID string - Validators []Validator + Validators []Validator // Validators can be Suites or Tests + Params map[string]interface{} } // Run runs all the tests in the gate. // Returns the overall result of the gate and an error if any of the tests failed. -func (g Gate) Run(ctx context.Context, log log.Logger, cfg Config) (ValidatorResult, error) { +// Gate-specific params are passed in as `_` because we haven't implemented them yet. +func (g Gate) Run(ctx context.Context, log log.Logger, cfg Config, _ interface{}) (ValidatorResult, error) { log.Info("", "type", g.Type(), "id", g.Name()) allPassed := true results := []ValidatorResult{} var allErrors error for _, validator := range g.Validators { - res, err := validator.Run(ctx, log, cfg) + // We don't want Gates to have Gates + if validator == nil || validator.Type() == "Gate" { + continue + } + // Get params + params := g.Params[validator.Name()] + + res, err := validator.Run(ctx, log, cfg, params) if err != nil || !res.Passed { allPassed = false allErrors = errors.Join(allErrors, err) } results = append(results, res) } + log.Info("", "type", g.Type(), "id", g.Name(), "passed", allPassed, "error", allErrors) return ValidatorResult{ ID: g.ID, Type: g.Type(), diff --git a/op-nat/gate_test.go b/op-nat/gate_test.go new file mode 100644 index 000000000000..4fb832f7c5f1 --- /dev/null +++ b/op-nat/gate_test.go @@ -0,0 +1,96 @@ +package nat + +import ( + "context" + "testing" + + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGate(t *testing.T) { + t.Run("passes when all validators pass", func(t *testing.T) { + gate := &Gate{ + Validators: []Validator{ + &Test{ + ID: "test1", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + return true, nil + }, + }, + &Test{ + ID: "test2", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + return true, nil + }, + }, + }, + } + + result, err := gate.Run(context.Background(), log.New(), Config{}, nil) + + require.NoError(t, err) + assert.True(t, result.Passed) + }) + + t.Run("fails if any validator fails", func(t *testing.T) { + gate := &Gate{ + Validators: []Validator{ + &Test{ + ID: "test1", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + return true, nil + }, + }, + &Test{ + ID: "test2", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + return false, nil + }, + }, + }, + } + + result, err := gate.Run(context.Background(), log.New(), Config{}, nil) + + require.NoError(t, err) + assert.False(t, result.Passed) + }) + + t.Run("doesnt stop on validator failure", func(t *testing.T) { + executionOrder := []string{} + + gate := &Gate{ + Validators: []Validator{ + &Test{ + ID: "test1", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + executionOrder = append(executionOrder, "test1") + return true, nil + }, + }, + &Test{ + ID: "test2", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + executionOrder = append(executionOrder, "test2") + return false, nil + }, + }, + &Test{ + ID: "test3", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + executionOrder = append(executionOrder, "test3") + return true, nil + }, + }, + }, + } + + result, err := gate.Run(context.Background(), log.New(), Config{}, nil) + + require.NoError(t, err) + assert.False(t, result.Passed) + assert.Equal(t, []string{"test1", "test2", "test3"}, executionOrder, "shouldnt stop on validator failure") + }) +} diff --git a/op-nat/nat.go b/op-nat/nat.go index 856eaeb10966..703ca131e512 100644 --- a/op-nat/nat.go +++ b/op-nat/nat.go @@ -19,6 +19,7 @@ type nat struct { ctx context.Context log log.Logger config *Config + params map[string]interface{} version string results []ValidatorResult @@ -36,6 +37,7 @@ func New(ctx context.Context, config *Config, log log.Logger, version string) (* return &nat{ ctx: ctx, config: config, + params: map[string]interface{}{}, log: log, version: version, }, nil @@ -48,7 +50,11 @@ func (n *nat) Start(ctx context.Context) error { n.running.Store(true) for _, validator := range n.config.Validators { n.log.Info("Running acceptance tests...") - result, err := validator.Run(ctx, n.log, *n.config) + + // Get test-specific parameters if they exist + params := n.params[validator.Name()] + + result, err := validator.Run(ctx, n.log, *n.config, params) n.log.Info("Completed validator", "validator", validator.Name(), "type", validator.Type(), "passed", result.Passed, "error", err) if err != nil { n.log.Error("Error running validator", "validator", validator.Name(), "error", err) diff --git a/op-nat/nat_test.go b/op-nat/nat_test.go new file mode 100644 index 000000000000..9c9d3e00bba3 --- /dev/null +++ b/op-nat/nat_test.go @@ -0,0 +1,117 @@ +package nat + +import ( + "context" + "testing" + + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNATParameterization(t *testing.T) { + // Create a test that records its received parameters + var receivedParams interface{} + testFn := func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + receivedParams = params + return true, nil + } + + test := &Test{ + ID: "test-with-params", + DefaultParams: map[string]string{"value": "default"}, + Fn: testFn, + } + + // Create a basic config with our test + cfg := &Config{ + Validators: []Validator{test}, + SenderSecretKey: "0x0", + ReceiverPublicKeys: []string{"0x0"}, + ReceiverPrivateKeys: []string{"0x0"}, + } + logger := log.New() + + t.Run("uses default parameters when none provided", func(t *testing.T) { + nat, err := New(context.Background(), cfg, logger, "test") + require.NoError(t, err) + t.Cleanup(func() { + err := nat.Stop(context.Background()) + require.NoError(t, err) + }) + + err = nat.Start(context.Background()) + require.NoError(t, err) + + assert.Equal(t, test.DefaultParams, receivedParams) + }) + + t.Run("uses custom parameters when provided", func(t *testing.T) { + nat, err := New(context.Background(), cfg, logger, "test") + require.NoError(t, err) + t.Cleanup(func() { + err := nat.Stop(context.Background()) + require.NoError(t, err) + }) + + customParams := map[string]string{"value": "custom"} + nat.params = map[string]interface{}{ + test.ID: customParams, + } + + err = nat.Start(context.Background()) + require.NoError(t, err) + + assert.Equal(t, customParams, receivedParams) + }) + + t.Run("different test instances can have different parameters", func(t *testing.T) { + // Create two instances with different parameters + nat1, err := New(context.Background(), cfg, logger, "test1") + require.NoError(t, err) + nat1.params = map[string]interface{}{ + test.ID: map[string]string{"value": "instance1"}, + } + + nat2, err := New(context.Background(), cfg, logger, "test2") + require.NoError(t, err) + nat2.params = map[string]interface{}{ + test.ID: map[string]string{"value": "instance2"}, + } + + t.Cleanup(func() { + err := nat1.Stop(context.Background()) + require.NoError(t, err) + err = nat2.Stop(context.Background()) + require.NoError(t, err) + }) + + // Run first instance + err = nat1.Start(context.Background()) + require.NoError(t, err) + assert.Equal(t, map[string]string{"value": "instance1"}, receivedParams) + + // Run second instance + err = nat2.Start(context.Background()) + require.NoError(t, err) + assert.Equal(t, map[string]string{"value": "instance2"}, receivedParams) + }) + + t.Run("results are properly recorded", func(t *testing.T) { + nat, err := New(context.Background(), cfg, logger, "test") + require.NoError(t, err) + t.Cleanup(func() { + err := nat.Stop(context.Background()) + require.NoError(t, err) + }) + nat.params = make(map[string]interface{}) + + err = nat.Start(context.Background()) + require.NoError(t, err) + + require.Len(t, nat.results, 1) + assert.Equal(t, "test-with-params", nat.results[0].ID) + assert.Equal(t, "Test", nat.results[0].Type) + assert.True(t, nat.results[0].Passed) + }) +} diff --git a/op-nat/suite.go b/op-nat/suite.go index 268dca404609..0a8c719039aa 100644 --- a/op-nat/suite.go +++ b/op-nat/suite.go @@ -11,25 +11,31 @@ var _ Validator = &Suite{} // A Suite is a collection of tests. type Suite struct { - ID string - Tests []Test + ID string + Tests []Test + TestsParams map[string]interface{} } // Run runs all the tests in the suite. // Returns the overall result of the suite and an error if any of the tests failed. -func (s Suite) Run(ctx context.Context, log log.Logger, cfg Config) (ValidatorResult, error) { +// Suite-specific params are passed in as `_` because we haven't implemented them yet. +func (s Suite) Run(ctx context.Context, log log.Logger, cfg Config, _ interface{}) (ValidatorResult, error) { log.Info("", "type", s.Type(), "id", s.Name()) allPassed := true results := []ValidatorResult{} var allErrors error for _, test := range s.Tests { - res, err := test.Run(ctx, log, cfg) + // Get test-specific params + params := s.TestsParams[test.ID] + + res, err := test.Run(ctx, log, cfg, params) if err != nil || !res.Passed { allPassed = false allErrors = errors.Join(allErrors, err) } results = append(results, res) } + log.Info("", "type", s.Type(), "id", s.Name(), "passed", allPassed, "error", allErrors) return ValidatorResult{ ID: s.ID, Type: s.Type(), diff --git a/op-nat/suite_test.go b/op-nat/suite_test.go new file mode 100644 index 000000000000..8d4ca18994b6 --- /dev/null +++ b/op-nat/suite_test.go @@ -0,0 +1,65 @@ +package nat + +import ( + "context" + "testing" + + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSuite(t *testing.T) { + t.Run("runs all tests in order", func(t *testing.T) { + executionOrder := []string{} + + suite := &Suite{ + Tests: []Test{ + { + ID: "test1", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + executionOrder = append(executionOrder, "test1") + return true, nil + }, + }, + { + ID: "test2", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + executionOrder = append(executionOrder, "test2") + return true, nil + }, + }, + }, + } + + result, err := suite.Run(context.Background(), log.New(), Config{}, nil) + + require.NoError(t, err) + assert.True(t, result.Passed) + assert.Equal(t, []string{"test1", "test2"}, executionOrder) + }) + + t.Run("fails if any test fails", func(t *testing.T) { + suite := &Suite{ + Tests: []Test{ + { + ID: "test1", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + return true, nil + }, + }, + { + ID: "test2", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + return false, nil + }, + }, + }, + } + + result, err := suite.Run(context.Background(), log.New(), Config{}, nil) + + require.NoError(t, err) + assert.False(t, result.Passed) + }) +} diff --git a/op-nat/test.go b/op-nat/test.go index b343179e40d3..516a16cb6f93 100644 --- a/op-nat/test.go +++ b/op-nat/test.go @@ -10,18 +10,27 @@ import ( var _ Validator = &Test{} type Test struct { - ID string - Fn func(ctx context.Context, log log.Logger, cfg Config) (bool, error) + ID string + DefaultParams interface{} + Fn func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) } -func (t Test) Run(ctx context.Context, log log.Logger, cfg Config) (ValidatorResult, error) { +func (t Test) Run(ctx context.Context, log log.Logger, cfg Config, params interface{}) (ValidatorResult, error) { if t.Fn == nil { return ValidatorResult{ Passed: false, }, fmt.Errorf("test function is nil") } - log.Info("", "type", t.Type(), "id", t.Name()) - passed, err := t.Fn(ctx, log, cfg) + + // Use default params if none provided + testParams := t.DefaultParams + if params != nil { + testParams = params + } + + log.Info("", "type", t.Type(), "id", t.Name(), "params", testParams) + passed, err := t.Fn(ctx, log, cfg, testParams) + log.Info("", "type", t.Type(), "id", t.Name(), "params", testParams, "passed", passed, "error", err) return ValidatorResult{ ID: t.ID, Type: t.Type(), diff --git a/op-nat/test_test.go b/op-nat/test_test.go new file mode 100644 index 000000000000..14b18c60f465 --- /dev/null +++ b/op-nat/test_test.go @@ -0,0 +1,103 @@ +package nat + +import ( + "context" + "testing" + + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTest(t *testing.T) { + t.Run("uses default parameters", func(t *testing.T) { + defaultParams := map[string]string{"key": "value"} + var receivedParams interface{} + + test := &Test{ + ID: "test-default-params", + DefaultParams: defaultParams, + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + receivedParams = params + return true, nil + }, + } + + result, err := test.Run(context.Background(), log.New(), Config{}, nil) + + require.NoError(t, err) + assert.True(t, result.Passed) + assert.Equal(t, defaultParams, receivedParams) + }) + + t.Run("uses provided parameters", func(t *testing.T) { + customParams := map[string]string{"custom": "param"} + var receivedParams interface{} + + test := &Test{ + ID: "test-custom-params", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + receivedParams = params + return true, nil + }, + } + + result, err := test.Run(context.Background(), log.New(), Config{}, customParams) + + require.NoError(t, err) + assert.True(t, result.Passed) + assert.Equal(t, customParams, receivedParams) + }) + + t.Run("returns correct result based on Fn return value", func(t *testing.T) { + testCases := []struct { + name string + fnReturn bool + fnErr error + expectPassed bool + expectErr error + }{ + { + name: "returns true when Fn returns true", + fnReturn: true, + fnErr: nil, + expectPassed: true, + expectErr: nil, + }, + { + name: "returns false when Fn returns false", + fnReturn: false, + fnErr: nil, + expectPassed: false, + expectErr: nil, + }, + { + name: "propagates error from Fn", + fnReturn: false, + fnErr: assert.AnError, + expectPassed: false, + expectErr: assert.AnError, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + test := &Test{ + ID: "test-return-values", + Fn: func(ctx context.Context, log log.Logger, cfg Config, params interface{}) (bool, error) { + return tc.fnReturn, tc.fnErr + }, + } + + result, err := test.Run(context.Background(), log.New(), Config{}, nil) + + if tc.expectErr != nil { + assert.Equal(t, tc.expectErr, err) + } else { + require.NoError(t, err) + assert.Equal(t, tc.expectPassed, result.Passed) + } + }) + } + }) +} diff --git a/op-nat/validator.go b/op-nat/validator.go index 2b6ac515fb06..dbf2af94d353 100644 --- a/op-nat/validator.go +++ b/op-nat/validator.go @@ -7,7 +7,7 @@ import ( ) type Validator interface { - Run(ctx context.Context, log log.Logger, cfg Config) (ValidatorResult, error) + Run(ctx context.Context, log log.Logger, cfg Config, params interface{}) (ValidatorResult, error) Name() string Type() string } diff --git a/op-nat/validators/suites/deposit-suite.go b/op-nat/validators/suites/deposit.go similarity index 66% rename from op-nat/validators/suites/deposit-suite.go rename to op-nat/validators/suites/deposit.go index 5fa06dac2bf2..403ce895e4db 100644 --- a/op-nat/validators/suites/deposit-suite.go +++ b/op-nat/validators/suites/deposit.go @@ -10,4 +10,9 @@ var DepositSuite = nat.Suite{ Tests: []nat.Test{ tests.SimpleDeposit, }, + TestsParams: map[string]interface{}{ + tests.SimpleDeposit.ID: tests.SimpleDepositParams{ + MaxBalanceChecks: 24, + }, + }, } diff --git a/op-nat/validators/suites/load-test.go b/op-nat/validators/suites/load-test.go index 67fa3a8b7b00..f4bc5b370ef8 100644 --- a/op-nat/validators/suites/load-test.go +++ b/op-nat/validators/suites/load-test.go @@ -10,4 +10,11 @@ var LoadTest = nat.Suite{ Tests: []nat.Test{ tests.TxFuzz, }, + TestsParams: map[string]interface{}{ + "tx-fuzz": tests.TxFuzzParams{ + NSlotsToRunFor: 1, + TxPerAccount: 2, + GenerateAccessList: false, + }, + }, } diff --git a/op-nat/validators/suites/simple-transfer.go b/op-nat/validators/suites/simple-transfer.go index 6df644178734..c832ef22ab92 100644 --- a/op-nat/validators/suites/simple-transfer.go +++ b/op-nat/validators/suites/simple-transfer.go @@ -10,4 +10,5 @@ var SimpleTransfer = nat.Suite{ Tests: []nat.Test{ tests.SimpleTransfer, }, + TestsParams: map[string]interface{}{}, } diff --git a/op-nat/validators/tests/network-get-blocknumber.go b/op-nat/validators/tests/network-get-blocknumber.go index bd3c3fd91ab4..bfa5d1008c06 100644 --- a/op-nat/validators/tests/network-get-blocknumber.go +++ b/op-nat/validators/tests/network-get-blocknumber.go @@ -12,7 +12,7 @@ import ( // NetworkGetBlockNumber is a test that checks if RPC call `BlockNumber` is working. var NetworkGetBlockNumber = nat.Test{ ID: "network-get-block-number", - Fn: func(ctx context.Context, log log.Logger, config nat.Config) (bool, error) { + Fn: func(ctx context.Context, log log.Logger, config nat.Config, _ interface{}) (bool, error) { network, err := network.NewNetwork(ctx, log, config.RPCURL, "kurtosis-l2") if err != nil { return false, fmt.Errorf("failed to setup network") diff --git a/op-nat/validators/tests/network-get-chainid.go b/op-nat/validators/tests/network-get-chainid.go index 8f3471f39c8a..57e542f0f3bd 100644 --- a/op-nat/validators/tests/network-get-chainid.go +++ b/op-nat/validators/tests/network-get-chainid.go @@ -13,7 +13,7 @@ import ( // NetworkGetChainID is a test that checks if the RPC call `ChainID` is working. var NetworkGetChainID = nat.Test{ ID: "network-get-chainid", - Fn: func(ctx context.Context, log log.Logger, config nat.Config) (bool, error) { + Fn: func(ctx context.Context, log log.Logger, config nat.Config, _ interface{}) (bool, error) { network, err := network.NewNetwork(ctx, log, config.RPCURL, "kurtosis-l2") if err != nil { return false, fmt.Errorf("failed to setup network") diff --git a/op-nat/validators/tests/simple-deposit.go b/op-nat/validators/tests/simple-deposit.go index bfda057f25c3..22bb7061f24b 100644 --- a/op-nat/validators/tests/simple-deposit.go +++ b/op-nat/validators/tests/simple-deposit.go @@ -14,16 +14,24 @@ import ( "github.com/pkg/errors" ) +type SimpleDepositParams struct { + MaxBalanceChecks int +} + // SimpleTransfer is a test that runs a transfer on a network var SimpleDeposit = nat.Test{ ID: "simple-deposit", - Fn: func(ctx context.Context, log log.Logger, cfg nat.Config) (bool, error) { + DefaultParams: SimpleDepositParams{ + MaxBalanceChecks: 12, + }, + Fn: func(ctx context.Context, log log.Logger, cfg nat.Config, params interface{}) (bool, error) { + p := params.(SimpleDepositParams) l1, l2, wallet, err := SetupSimpleDepositTest(ctx, log, cfg) l2ProxyPortal := common.HexToAddress(cfg.SC.L2[0].Addresses.OptimismPortalProxy) if err != nil { return false, err } - return SimpleDepositTest(ctx, log, l1, l2, wallet, l2ProxyPortal) + return SimpleDepositTest(ctx, log, l1, l2, wallet, l2ProxyPortal, p) }, } @@ -54,7 +62,7 @@ func SetupSimpleDepositTest(ctx context.Context, log log.Logger, config nat.Conf return l1, l2, wallet, nil } -func SimpleDepositTest(ctx context.Context, log log.Logger, l1, l2 *network.Network, wallet *wallet.Wallet, portal common.Address) (bool, error) { +func SimpleDepositTest(ctx context.Context, log log.Logger, l1, l2 *network.Network, wallet *wallet.Wallet, portal common.Address, p SimpleDepositParams) (bool, error) { if l1 == nil || wallet == nil || l2 == nil || len(portal) == 0 { return false, errors.New("error empty arguments provided for SimpleDepositTest") } @@ -109,7 +117,7 @@ func SimpleDepositTest(ctx context.Context, log log.Logger, l1, l2 *network.Netw l1Diff := false l2Diff := false - for i := 0; i < 12; i++ { + for i := 0; i < p.MaxBalanceChecks; i++ { l1Post, err = wallet.GetBalance(ctx, l1) if err != nil { return false, errors.Wrap(err, "error getting l1 balance") diff --git a/op-nat/validators/tests/simple-transfer.go b/op-nat/validators/tests/simple-transfer.go index f9cd5ddd553f..8732a014e13f 100644 --- a/op-nat/validators/tests/simple-transfer.go +++ b/op-nat/validators/tests/simple-transfer.go @@ -15,7 +15,7 @@ import ( // SimpleTransfer is a test that runs a transfer on a network var SimpleTransfer = nat.Test{ ID: "simple-transfer", - Fn: func(ctx context.Context, log log.Logger, cfg nat.Config) (bool, error) { + Fn: func(ctx context.Context, log log.Logger, cfg nat.Config, _ interface{}) (bool, error) { network, walletA, walletB, err := SetupSimpleTransferTest(ctx, log, cfg) if err != nil { return false, err diff --git a/op-nat/validators/tests/tx-fuzz.go b/op-nat/validators/tests/tx-fuzz.go index 26bd6796f84d..fd234b9216eb 100644 --- a/op-nat/validators/tests/tx-fuzz.go +++ b/op-nat/validators/tests/tx-fuzz.go @@ -11,17 +11,29 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" + ethparams "github.com/ethereum/go-ethereum/params" "github.com/pkg/errors" "github.com/scharissis/tx-fuzz/spammer" ) +type TxFuzzParams struct { + NSlotsToRunFor int + TxPerAccount uint64 + GenerateAccessList bool +} + // TxFuzz is a test that runs tx-fuzz. // It runs 3 slots of spam, with 1 transaction per account. var TxFuzz = nat.Test{ ID: "tx-fuzz", - Fn: func(ctx context.Context, log log.Logger, cfg nat.Config) (bool, error) { - err := runBasicSpam(cfg) + DefaultParams: TxFuzzParams{ + NSlotsToRunFor: 120, // Duration of the fuzzing + TxPerAccount: 3, + GenerateAccessList: false, + }, + Fn: func(ctx context.Context, log log.Logger, cfg nat.Config, params interface{}) (bool, error) { + p := params.(TxFuzzParams) + err := runBasicSpam(cfg, p) if err != nil { return false, err } @@ -29,22 +41,22 @@ var TxFuzz = nat.Test{ }, } -func runBasicSpam(config nat.Config) error { - fuzzCfg, err := newConfig(config) +func runBasicSpam(config nat.Config, params TxFuzzParams) error { + fuzzCfg, err := newConfig(config, params) if err != nil { return err } - airdropValue := new(big.Int).Mul(big.NewInt(int64((1+fuzzCfg.N)*1000000)), big.NewInt(params.GWei)) - return spam(fuzzCfg, spammer.SendBasicTransactions, airdropValue) + airdropValue := new(big.Int).Mul(big.NewInt(int64((1+fuzzCfg.N)*1000000)), big.NewInt(ethparams.GWei)) + return spam(fuzzCfg, spammer.SendBasicTransactions, airdropValue, params) } -func spam(config *spammer.Config, spamFn spammer.Spam, airdropValue *big.Int) error { +func spam(config *spammer.Config, spamFn spammer.Spam, airdropValue *big.Int, params TxFuzzParams) error { // Make sure the accounts are unstuck before sending any transactions if err := spammer.Unstuck(config); err != nil { return err } - for nSlots := 0; nSlots < 12; nSlots++ { + for nSlots := 0; nSlots < params.NSlotsToRunFor; nSlots++ { if err := spammer.Airdrop(config, airdropValue); err != nil { return err } @@ -56,9 +68,9 @@ func spam(config *spammer.Config, spamFn spammer.Spam, airdropValue *big.Int) er return nil } -func newConfig(c nat.Config) (*spammer.Config, error) { - txPerAccount := uint64(1) - genAccessList := false +func newConfig(c nat.Config, p TxFuzzParams) (*spammer.Config, error) { + txPerAccount := p.TxPerAccount + genAccessList := p.GenerateAccessList rpcURL := c.RPCURL senderSecretKey := c.SenderSecretKey receiverPublicKeys := c.ReceiverPublicKeys