From fa69b19e3b69258d516df4b5d0b8ebdb7299a8ac Mon Sep 17 00:00:00 2001 From: Nodar Date: Mon, 18 Sep 2023 13:28:54 +0200 Subject: [PATCH 1/2] Factor out validator wallets and transaction builder into separate packages --- arbnode/node.go | 5 ++- cmd/nitro/nitro.go | 3 +- staker/l1_validator.go | 5 ++- staker/staker.go | 26 +++++++++++- .../builder.go} | 25 ++++++++++- .../contract.go} | 41 ++++++------------- .../eoa.go} | 11 +++-- system_tests/staker_test.go | 11 ++--- 8 files changed, 80 insertions(+), 47 deletions(-) rename staker/{builder_backend.go => txbuilder/builder.go} (80%) rename staker/{validator_wallet.go => validatorwallet/contract.go} (92%) rename staker/{eoa_validator_wallet.go => validatorwallet/eoa.go} (92%) diff --git a/arbnode/node.go b/arbnode/node.go index 5bdc716264..c7c191d1dd 100644 --- a/arbnode/node.go +++ b/arbnode/node.go @@ -43,6 +43,7 @@ import ( "github.com/offchainlabs/nitro/solgen/go/precompilesgen" "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/staker" + "github.com/offchainlabs/nitro/staker/validatorwallet" "github.com/offchainlabs/nitro/util/contracts" "github.com/offchainlabs/nitro/util/headerreader" "github.com/offchainlabs/nitro/util/redisutil" @@ -826,7 +827,7 @@ func createNodeImpl( tmpAddress := common.HexToAddress(config.Staker.ContractWalletAddress) existingWalletAddress = &tmpAddress } - wallet, err = staker.NewContractValidatorWallet(dp, existingWalletAddress, deployInfo.ValidatorWalletCreator, deployInfo.Rollup, l1Reader, txOptsValidator, int64(deployInfo.DeployedAt), func(common.Address) {}, getExtraGas) + wallet, err = validatorwallet.NewContractValidatorWallet(dp, existingWalletAddress, deployInfo.ValidatorWalletCreator, deployInfo.Rollup, l1Reader, txOptsValidator, int64(deployInfo.DeployedAt), func(common.Address) {}, getExtraGas) if err != nil { return nil, err } @@ -834,7 +835,7 @@ func createNodeImpl( if len(config.Staker.ContractWalletAddress) > 0 { return nil, errors.New("validator contract wallet specified but flag to use a smart contract wallet was not specified") } - wallet, err = staker.NewEoaValidatorWallet(dp, deployInfo.Rollup, l1client, txOptsValidator, getExtraGas) + wallet, err = validatorwallet.NewEoaValidatorWallet(dp, deployInfo.Rollup, l1client, txOptsValidator, getExtraGas) if err != nil { return nil, err } diff --git a/cmd/nitro/nitro.go b/cmd/nitro/nitro.go index a7dc7f26f9..50bb092389 100644 --- a/cmd/nitro/nitro.go +++ b/cmd/nitro/nitro.go @@ -51,6 +51,7 @@ import ( _ "github.com/offchainlabs/nitro/nodeInterface" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" "github.com/offchainlabs/nitro/staker" + "github.com/offchainlabs/nitro/staker/validatorwallet" "github.com/offchainlabs/nitro/util/colors" "github.com/offchainlabs/nitro/util/headerreader" "github.com/offchainlabs/nitro/util/rpcclient" @@ -367,7 +368,7 @@ func mainImpl() int { if err != nil { log.Crit("error getting rollup addresses config", "err", err) } - addr, err := staker.GetValidatorWalletContract(ctx, deployInfo.ValidatorWalletCreator, int64(deployInfo.DeployedAt), l1TransactionOptsValidator, l1Reader, true) + addr, err := validatorwallet.GetValidatorWalletContract(ctx, deployInfo.ValidatorWalletCreator, int64(deployInfo.DeployedAt), l1TransactionOptsValidator, l1Reader, true) if err != nil { log.Crit("error creating validator wallet contract", "error", err, "address", l1TransactionOptsValidator.From.Hex()) } diff --git a/staker/l1_validator.go b/staker/l1_validator.go index aa9107fd90..dd3afec659 100644 --- a/staker/l1_validator.go +++ b/staker/l1_validator.go @@ -11,6 +11,7 @@ import ( "time" "github.com/offchainlabs/nitro/arbstate" + "github.com/offchainlabs/nitro/staker/txbuilder" "github.com/offchainlabs/nitro/util/arbmath" "github.com/offchainlabs/nitro/validator" @@ -45,7 +46,7 @@ type L1Validator struct { rollupAddress common.Address validatorUtils *rollupgen.ValidatorUtils client arbutil.L1Interface - builder *ValidatorTxBuilder + builder *txbuilder.ValidatorTxBuilder wallet ValidatorWalletInterface callOpts bind.CallOpts @@ -66,7 +67,7 @@ func NewL1Validator( txStreamer TransactionStreamerInterface, blockValidator *BlockValidator, ) (*L1Validator, error) { - builder, err := NewValidatorTxBuilder(wallet) + builder, err := txbuilder.NewValidatorTxBuilder(wallet) if err != nil { return nil, err } diff --git a/staker/staker.go b/staker/staker.go index 1b6538b161..3c989cb4f1 100644 --- a/staker/staker.go +++ b/staker/staker.go @@ -24,6 +24,7 @@ import ( "github.com/offchainlabs/nitro/arbnode/redislock" "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/cmd/genericconf" + "github.com/offchainlabs/nitro/staker/txbuilder" "github.com/offchainlabs/nitro/util/arbmath" "github.com/offchainlabs/nitro/util/stopwaiter" "github.com/offchainlabs/nitro/validator" @@ -254,6 +255,27 @@ type Staker struct { fatalErr chan<- error } +type ValidatorWalletInterface interface { + Initialize(context.Context) error + // Address must be able to be called concurrently with other functions + Address() *common.Address + // Address must be able to be called concurrently with other functions + AddressOrZero() common.Address + TxSenderAddress() *common.Address + RollupAddress() common.Address + ChallengeManagerAddress() common.Address + L1Client() arbutil.L1Interface + TestTransactions(context.Context, []*types.Transaction) error + ExecuteTransactions(context.Context, *txbuilder.ValidatorTxBuilder, common.Address) (*types.Transaction, error) + TimeoutChallenges(context.Context, []uint64) (*types.Transaction, error) + CanBatchTxs() bool + AuthIfEoa() *bind.TransactOpts + Start(context.Context) + StopAndWait() + // May be nil + DataPoster() *dataposter.DataPoster +} + func NewStaker( l1Reader L1ReaderInterface, wallet ValidatorWalletInterface, @@ -777,8 +799,8 @@ func (s *Staker) handleConflict(ctx context.Context, info *StakerInfo) error { newChallengeManager, err := NewChallengeManager( ctx, s.builder, - s.builder.builderAuth, - *s.builder.wallet.Address(), + s.builder.BuilderAuth(), + *s.builder.WalletAddress(), s.wallet.ChallengeManagerAddress(), *info.CurrentChallenge, s.statelessBlockValidator, diff --git a/staker/builder_backend.go b/staker/txbuilder/builder.go similarity index 80% rename from staker/builder_backend.go rename to staker/txbuilder/builder.go index 1bf15ff027..e0c3c57356 100644 --- a/staker/builder_backend.go +++ b/staker/txbuilder/builder.go @@ -1,7 +1,7 @@ // Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -package staker +package txbuilder import ( "context" @@ -15,6 +15,15 @@ import ( "github.com/offchainlabs/nitro/arbutil" ) +type ValidatorWalletInterface interface { + // Address must be able to be called concurrently with other functions + Address() *common.Address + L1Client() arbutil.L1Interface + TestTransactions(context.Context, []*types.Transaction) error + ExecuteTransactions(context.Context, *ValidatorTxBuilder, common.Address) (*types.Transaction, error) + AuthIfEoa() *bind.TransactOpts +} + // ValidatorTxBuilder combines any transactions sent to it via SendTransaction into one batch, // which is then sent to the validator wallet. // This lets the validator make multiple atomic transactions. @@ -101,3 +110,17 @@ func (b *ValidatorTxBuilder) AuthWithAmount(ctx context.Context, amount *big.Int func (b *ValidatorTxBuilder) Auth(ctx context.Context) (*bind.TransactOpts, error) { return b.AuthWithAmount(ctx, common.Big0) } + +func (b *ValidatorTxBuilder) Transactions() []*types.Transaction { + return b.transactions +} + +// Auth is the same as AuthWithAmount with a 0 amount specified. +// See AuthWithAmount docs for important details. +func (b *ValidatorTxBuilder) BuilderAuth() *bind.TransactOpts { + return b.builderAuth +} + +func (b *ValidatorTxBuilder) WalletAddress() *common.Address { + return b.wallet.Address() +} diff --git a/staker/validator_wallet.go b/staker/validatorwallet/contract.go similarity index 92% rename from staker/validator_wallet.go rename to staker/validatorwallet/contract.go index fb0f5ed956..0ad8504365 100644 --- a/staker/validator_wallet.go +++ b/staker/validatorwallet/contract.go @@ -1,7 +1,7 @@ // Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -package staker +package validatorwallet import ( "context" @@ -22,6 +22,7 @@ import ( "github.com/offchainlabs/nitro/arbnode/dataposter" "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/solgen/go/rollupgen" + "github.com/offchainlabs/nitro/staker/txbuilder" "github.com/offchainlabs/nitro/util/arbmath" "github.com/offchainlabs/nitro/util/headerreader" ) @@ -43,27 +44,6 @@ func init() { walletCreatedID = parsedValidatorWalletCreator.Events["WalletCreated"].ID } -type ValidatorWalletInterface interface { - Initialize(context.Context) error - // Address must be able to be called concurrently with other functions - Address() *common.Address - // Address must be able to be called concurrently with other functions - AddressOrZero() common.Address - TxSenderAddress() *common.Address - RollupAddress() common.Address - ChallengeManagerAddress() common.Address - L1Client() arbutil.L1Interface - TestTransactions(context.Context, []*types.Transaction) error - ExecuteTransactions(context.Context, *ValidatorTxBuilder, common.Address) (*types.Transaction, error) - TimeoutChallenges(context.Context, []uint64) (*types.Transaction, error) - CanBatchTxs() bool - AuthIfEoa() *bind.TransactOpts - Start(context.Context) - StopAndWait() - // May be nil - DataPoster() *dataposter.DataPoster -} - type ContractValidatorWallet struct { con *rollupgen.ValidatorWallet address atomic.Pointer[common.Address] @@ -79,8 +59,6 @@ type ContractValidatorWallet struct { getExtraGas func() uint64 } -var _ ValidatorWalletInterface = (*ContractValidatorWallet)(nil) - func NewContractValidatorWallet(dp *dataposter.DataPoster, address *common.Address, walletFactoryAddr, rollupAddress common.Address, l1Reader *headerreader.HeaderReader, auth *bind.TransactOpts, rollupFromBlock int64, onWalletCreated func(common.Address), getExtraGas func() uint64) (*ContractValidatorWallet, error) { var con *rollupgen.ValidatorWallet @@ -257,8 +235,8 @@ func combineTxes(txes []*types.Transaction) ([][]byte, []common.Address, []*big. } // Not thread safe! Don't call this from multiple threads at the same time. -func (v *ContractValidatorWallet) ExecuteTransactions(ctx context.Context, builder *ValidatorTxBuilder, gasRefunder common.Address) (*types.Transaction, error) { - txes := builder.transactions +func (v *ContractValidatorWallet) ExecuteTransactions(ctx context.Context, builder *txbuilder.ValidatorTxBuilder, gasRefunder common.Address) (*types.Transaction, error) { + txes := builder.Transactions() if len(txes) == 0 { return nil, nil } @@ -273,7 +251,7 @@ func (v *ContractValidatorWallet) ExecuteTransactions(ctx context.Context, build if err != nil { return nil, err } - builder.transactions = nil + builder.ClearTransactions() return arbTx, nil } @@ -314,7 +292,7 @@ func (v *ContractValidatorWallet) ExecuteTransactions(ctx context.Context, build if err != nil { return nil, err } - builder.transactions = nil + builder.ClearTransactions() return arbTx, nil } @@ -422,6 +400,13 @@ func (b *ContractValidatorWallet) DataPoster() *dataposter.DataPoster { return b.dataPoster } +type L1ReaderInterface interface { + Client() arbutil.L1Interface + Subscribe(bool) (<-chan *types.Header, func()) + WaitForTxApproval(ctx context.Context, tx *types.Transaction) (*types.Receipt, error) + UseFinalityData() bool +} + func GetValidatorWalletContract( ctx context.Context, validatorWalletFactoryAddr common.Address, diff --git a/staker/eoa_validator_wallet.go b/staker/validatorwallet/eoa.go similarity index 92% rename from staker/eoa_validator_wallet.go rename to staker/validatorwallet/eoa.go index 5285e96ea9..5f848aa4eb 100644 --- a/staker/eoa_validator_wallet.go +++ b/staker/validatorwallet/eoa.go @@ -1,7 +1,7 @@ // Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -package staker +package validatorwallet import ( "context" @@ -15,6 +15,7 @@ import ( "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/solgen/go/challengegen" "github.com/offchainlabs/nitro/solgen/go/rollupgen" + "github.com/offchainlabs/nitro/staker/txbuilder" ) type EoaValidatorWallet struct { @@ -27,8 +28,6 @@ type EoaValidatorWallet struct { getExtraGas func() uint64 } -var _ ValidatorWalletInterface = (*EoaValidatorWallet)(nil) - func NewEoaValidatorWallet(dataPoster *dataposter.DataPoster, rollupAddress common.Address, l1Client arbutil.L1Interface, auth *bind.TransactOpts, getExtraGas func() uint64) (*EoaValidatorWallet, error) { return &EoaValidatorWallet{ auth: auth, @@ -82,11 +81,11 @@ func (w *EoaValidatorWallet) TestTransactions(context.Context, []*types.Transact return nil } -func (w *EoaValidatorWallet) ExecuteTransactions(ctx context.Context, builder *ValidatorTxBuilder, _ common.Address) (*types.Transaction, error) { - if len(builder.transactions) == 0 { +func (w *EoaValidatorWallet) ExecuteTransactions(ctx context.Context, builder *txbuilder.ValidatorTxBuilder, _ common.Address) (*types.Transaction, error) { + if len(builder.Transactions()) == 0 { return nil, nil } - tx := builder.transactions[0] // we ignore future txs and only execute the first + tx := builder.Transactions()[0] // we ignore future txs and only execute the first return w.postTransaction(ctx, tx) } diff --git a/system_tests/staker_test.go b/system_tests/staker_test.go index 96ea1ee2e7..2f2287a2fb 100644 --- a/system_tests/staker_test.go +++ b/system_tests/staker_test.go @@ -31,6 +31,7 @@ import ( "github.com/offchainlabs/nitro/solgen/go/mocksgen" "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/staker" + "github.com/offchainlabs/nitro/staker/validatorwallet" "github.com/offchainlabs/nitro/util" "github.com/offchainlabs/nitro/util/arbmath" "github.com/offchainlabs/nitro/util/colors" @@ -104,10 +105,10 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) TransferBalance(t, "Faucet", "ValidatorB", balance, l1info, l1client, ctx) l1authB := l1info.GetDefaultTransactOpts("ValidatorB", ctx) - valWalletAddrAPtr, err := staker.GetValidatorWalletContract(ctx, l2nodeA.DeployInfo.ValidatorWalletCreator, 0, &l1authA, l2nodeA.L1Reader, true) + valWalletAddrAPtr, err := validatorwallet.GetValidatorWalletContract(ctx, l2nodeA.DeployInfo.ValidatorWalletCreator, 0, &l1authA, l2nodeA.L1Reader, true) Require(t, err) valWalletAddrA := *valWalletAddrAPtr - valWalletAddrCheck, err := staker.GetValidatorWalletContract(ctx, l2nodeA.DeployInfo.ValidatorWalletCreator, 0, &l1authA, l2nodeA.L1Reader, true) + valWalletAddrCheck, err := validatorwallet.GetValidatorWalletContract(ctx, l2nodeA.DeployInfo.ValidatorWalletCreator, 0, &l1authA, l2nodeA.L1Reader, true) Require(t, err) if valWalletAddrA == *valWalletAddrCheck { Require(t, err, "didn't cache validator wallet address", valWalletAddrA.String(), "vs", valWalletAddrCheck.String()) @@ -134,7 +135,7 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) if err != nil { t.Fatalf("Error creating validator dataposter: %v", err) } - valWalletA, err := staker.NewContractValidatorWallet(dpA, nil, l2nodeA.DeployInfo.ValidatorWalletCreator, l2nodeA.DeployInfo.Rollup, l2nodeA.L1Reader, &l1authA, 0, func(common.Address) {}, func() uint64 { return valConfig.ExtraGas }) + valWalletA, err := validatorwallet.NewContractValidatorWallet(dpA, nil, l2nodeA.DeployInfo.ValidatorWalletCreator, l2nodeA.DeployInfo.Rollup, l2nodeA.L1Reader, &l1authA, 0, func(common.Address) {}, func() uint64 { return valConfig.ExtraGas }) Require(t, err) if honestStakerInactive { valConfig.Strategy = "Defensive" @@ -182,7 +183,7 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) if err != nil { t.Fatalf("Error creating validator dataposter: %v", err) } - valWalletB, err := staker.NewEoaValidatorWallet(dpB, l2nodeB.DeployInfo.Rollup, l2nodeB.L1Reader.Client(), &l1authB, func() uint64 { return 0 }) + valWalletB, err := validatorwallet.NewEoaValidatorWallet(dpB, l2nodeB.DeployInfo.Rollup, l2nodeB.L1Reader.Client(), &l1authB, func() uint64 { return 0 }) Require(t, err) valConfig.Strategy = "MakeNodes" statelessB, err := staker.NewStatelessBlockValidator( @@ -221,7 +222,7 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) if err != nil { t.Fatalf("Error creating validator dataposter: %v", err) } - valWalletC, err := staker.NewContractValidatorWallet(dpC, nil, l2nodeA.DeployInfo.ValidatorWalletCreator, l2nodeA.DeployInfo.Rollup, l2nodeA.L1Reader, nil, 0, func(common.Address) {}, func() uint64 { return 10000 }) + valWalletC, err := validatorwallet.NewContractValidatorWallet(dpC, nil, l2nodeA.DeployInfo.ValidatorWalletCreator, l2nodeA.DeployInfo.Rollup, l2nodeA.L1Reader, nil, 0, func(common.Address) {}, func() uint64 { return 10000 }) Require(t, err) valConfig.Strategy = "Watchtower" stakerC, err := staker.NewStaker( From 921ca50709144997edd0dbe28f38c665e096e6a6 Mon Sep 17 00:00:00 2001 From: Nodar Date: Mon, 18 Sep 2023 13:35:30 +0200 Subject: [PATCH 2/2] Rename wallet structs to reduce verbosity at call sites --- arbnode/node.go | 4 +-- staker/l1_validator.go | 4 +-- staker/staker.go | 2 +- staker/txbuilder/builder.go | 28 ++++++++-------- staker/validatorwallet/contract.go | 52 +++++++++++++++--------------- staker/validatorwallet/eoa.go | 38 +++++++++++----------- system_tests/staker_test.go | 6 ++-- 7 files changed, 67 insertions(+), 67 deletions(-) diff --git a/arbnode/node.go b/arbnode/node.go index c7c191d1dd..c5b79058b5 100644 --- a/arbnode/node.go +++ b/arbnode/node.go @@ -827,7 +827,7 @@ func createNodeImpl( tmpAddress := common.HexToAddress(config.Staker.ContractWalletAddress) existingWalletAddress = &tmpAddress } - wallet, err = validatorwallet.NewContractValidatorWallet(dp, existingWalletAddress, deployInfo.ValidatorWalletCreator, deployInfo.Rollup, l1Reader, txOptsValidator, int64(deployInfo.DeployedAt), func(common.Address) {}, getExtraGas) + wallet, err = validatorwallet.NewContract(dp, existingWalletAddress, deployInfo.ValidatorWalletCreator, deployInfo.Rollup, l1Reader, txOptsValidator, int64(deployInfo.DeployedAt), func(common.Address) {}, getExtraGas) if err != nil { return nil, err } @@ -835,7 +835,7 @@ func createNodeImpl( if len(config.Staker.ContractWalletAddress) > 0 { return nil, errors.New("validator contract wallet specified but flag to use a smart contract wallet was not specified") } - wallet, err = validatorwallet.NewEoaValidatorWallet(dp, deployInfo.Rollup, l1client, txOptsValidator, getExtraGas) + wallet, err = validatorwallet.NewEOA(dp, deployInfo.Rollup, l1client, txOptsValidator, getExtraGas) if err != nil { return nil, err } diff --git a/staker/l1_validator.go b/staker/l1_validator.go index dd3afec659..09bcc64468 100644 --- a/staker/l1_validator.go +++ b/staker/l1_validator.go @@ -46,7 +46,7 @@ type L1Validator struct { rollupAddress common.Address validatorUtils *rollupgen.ValidatorUtils client arbutil.L1Interface - builder *txbuilder.ValidatorTxBuilder + builder *txbuilder.Builder wallet ValidatorWalletInterface callOpts bind.CallOpts @@ -67,7 +67,7 @@ func NewL1Validator( txStreamer TransactionStreamerInterface, blockValidator *BlockValidator, ) (*L1Validator, error) { - builder, err := txbuilder.NewValidatorTxBuilder(wallet) + builder, err := txbuilder.NewBuilder(wallet) if err != nil { return nil, err } diff --git a/staker/staker.go b/staker/staker.go index 3c989cb4f1..d52d1adc77 100644 --- a/staker/staker.go +++ b/staker/staker.go @@ -266,7 +266,7 @@ type ValidatorWalletInterface interface { ChallengeManagerAddress() common.Address L1Client() arbutil.L1Interface TestTransactions(context.Context, []*types.Transaction) error - ExecuteTransactions(context.Context, *txbuilder.ValidatorTxBuilder, common.Address) (*types.Transaction, error) + ExecuteTransactions(context.Context, *txbuilder.Builder, common.Address) (*types.Transaction, error) TimeoutChallenges(context.Context, []uint64) (*types.Transaction, error) CanBatchTxs() bool AuthIfEoa() *bind.TransactOpts diff --git a/staker/txbuilder/builder.go b/staker/txbuilder/builder.go index e0c3c57356..9a5e9df2b5 100644 --- a/staker/txbuilder/builder.go +++ b/staker/txbuilder/builder.go @@ -20,16 +20,16 @@ type ValidatorWalletInterface interface { Address() *common.Address L1Client() arbutil.L1Interface TestTransactions(context.Context, []*types.Transaction) error - ExecuteTransactions(context.Context, *ValidatorTxBuilder, common.Address) (*types.Transaction, error) + ExecuteTransactions(context.Context, *Builder, common.Address) (*types.Transaction, error) AuthIfEoa() *bind.TransactOpts } -// ValidatorTxBuilder combines any transactions sent to it via SendTransaction into one batch, +// Builder combines any transactions sent to it via SendTransaction into one batch, // which is then sent to the validator wallet. // This lets the validator make multiple atomic transactions. // This inherits from an eth client so it can be used as an L1Interface, // where it transparently intercepts calls to SendTransaction and queues them for the next batch. -type ValidatorTxBuilder struct { +type Builder struct { arbutil.L1Interface transactions []*types.Transaction builderAuth *bind.TransactOpts @@ -37,7 +37,7 @@ type ValidatorTxBuilder struct { wallet ValidatorWalletInterface } -func NewValidatorTxBuilder(wallet ValidatorWalletInterface) (*ValidatorTxBuilder, error) { +func NewBuilder(wallet ValidatorWalletInterface) (*Builder, error) { randKey, err := crypto.GenerateKey() if err != nil { return nil, err @@ -52,7 +52,7 @@ func NewValidatorTxBuilder(wallet ValidatorWalletInterface) (*ValidatorTxBuilder } isAuthFake = true } - return &ValidatorTxBuilder{ + return &Builder{ builderAuth: builderAuth, wallet: wallet, L1Interface: wallet.L1Client(), @@ -60,22 +60,22 @@ func NewValidatorTxBuilder(wallet ValidatorWalletInterface) (*ValidatorTxBuilder }, nil } -func (b *ValidatorTxBuilder) BuildingTransactionCount() int { +func (b *Builder) BuildingTransactionCount() int { return len(b.transactions) } -func (b *ValidatorTxBuilder) ClearTransactions() { +func (b *Builder) ClearTransactions() { b.transactions = nil } -func (b *ValidatorTxBuilder) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) { +func (b *Builder) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) { if len(b.transactions) == 0 && !b.isAuthFake { return b.L1Interface.EstimateGas(ctx, call) } return 0, nil } -func (b *ValidatorTxBuilder) SendTransaction(ctx context.Context, tx *types.Transaction) error { +func (b *Builder) SendTransaction(ctx context.Context, tx *types.Transaction) error { b.transactions = append(b.transactions, tx) err := b.wallet.TestTransactions(ctx, b.transactions) if err != nil { @@ -89,7 +89,7 @@ func (b *ValidatorTxBuilder) SendTransaction(ctx context.Context, tx *types.Tran // While this is not currently required, it's recommended not to reuse the returned auth for multiple transactions, // as for an EOA this has the nonce in it. However, the EOA wwallet currently will only publish the first created tx, // which is why that doesn't really matter. -func (b *ValidatorTxBuilder) AuthWithAmount(ctx context.Context, amount *big.Int) (*bind.TransactOpts, error) { +func (b *Builder) AuthWithAmount(ctx context.Context, amount *big.Int) (*bind.TransactOpts, error) { nonce, err := b.NonceAt(ctx, b.builderAuth.From, nil) if err != nil { return nil, err @@ -107,20 +107,20 @@ func (b *ValidatorTxBuilder) AuthWithAmount(ctx context.Context, amount *big.Int // Auth is the same as AuthWithAmount with a 0 amount specified. // See AuthWithAmount docs for important details. -func (b *ValidatorTxBuilder) Auth(ctx context.Context) (*bind.TransactOpts, error) { +func (b *Builder) Auth(ctx context.Context) (*bind.TransactOpts, error) { return b.AuthWithAmount(ctx, common.Big0) } -func (b *ValidatorTxBuilder) Transactions() []*types.Transaction { +func (b *Builder) Transactions() []*types.Transaction { return b.transactions } // Auth is the same as AuthWithAmount with a 0 amount specified. // See AuthWithAmount docs for important details. -func (b *ValidatorTxBuilder) BuilderAuth() *bind.TransactOpts { +func (b *Builder) BuilderAuth() *bind.TransactOpts { return b.builderAuth } -func (b *ValidatorTxBuilder) WalletAddress() *common.Address { +func (b *Builder) WalletAddress() *common.Address { return b.wallet.Address() } diff --git a/staker/validatorwallet/contract.go b/staker/validatorwallet/contract.go index 0ad8504365..3ade358cee 100644 --- a/staker/validatorwallet/contract.go +++ b/staker/validatorwallet/contract.go @@ -44,7 +44,7 @@ func init() { walletCreatedID = parsedValidatorWalletCreator.Events["WalletCreated"].ID } -type ContractValidatorWallet struct { +type Contract struct { con *rollupgen.ValidatorWallet address atomic.Pointer[common.Address] onWalletCreated func(common.Address) @@ -59,8 +59,8 @@ type ContractValidatorWallet struct { getExtraGas func() uint64 } -func NewContractValidatorWallet(dp *dataposter.DataPoster, address *common.Address, walletFactoryAddr, rollupAddress common.Address, l1Reader *headerreader.HeaderReader, auth *bind.TransactOpts, rollupFromBlock int64, onWalletCreated func(common.Address), - getExtraGas func() uint64) (*ContractValidatorWallet, error) { +func NewContract(dp *dataposter.DataPoster, address *common.Address, walletFactoryAddr, rollupAddress common.Address, l1Reader *headerreader.HeaderReader, auth *bind.TransactOpts, rollupFromBlock int64, onWalletCreated func(common.Address), + getExtraGas func() uint64) (*Contract, error) { var con *rollupgen.ValidatorWallet if address != nil { var err error @@ -73,7 +73,7 @@ func NewContractValidatorWallet(dp *dataposter.DataPoster, address *common.Addre if err != nil { return nil, err } - wallet := &ContractValidatorWallet{ + wallet := &Contract{ con: con, onWalletCreated: onWalletCreated, l1Reader: l1Reader, @@ -90,7 +90,7 @@ func NewContractValidatorWallet(dp *dataposter.DataPoster, address *common.Addre return wallet, nil } -func (v *ContractValidatorWallet) validateWallet(ctx context.Context) error { +func (v *Contract) validateWallet(ctx context.Context) error { if v.con == nil || v.auth == nil { return nil } @@ -109,7 +109,7 @@ func (v *ContractValidatorWallet) validateWallet(ctx context.Context) error { return nil } -func (v *ContractValidatorWallet) Initialize(ctx context.Context) error { +func (v *Contract) Initialize(ctx context.Context) error { err := v.populateWallet(ctx, false) if err != nil { return err @@ -124,12 +124,12 @@ func (v *ContractValidatorWallet) Initialize(ctx context.Context) error { } // May be the nil if the wallet hasn't been deployed yet -func (v *ContractValidatorWallet) Address() *common.Address { +func (v *Contract) Address() *common.Address { return v.address.Load() } // May be zero if the wallet hasn't been deployed yet -func (v *ContractValidatorWallet) AddressOrZero() common.Address { +func (v *Contract) AddressOrZero() common.Address { addr := v.address.Load() if addr == nil { return common.Address{} @@ -137,14 +137,14 @@ func (v *ContractValidatorWallet) AddressOrZero() common.Address { return *addr } -func (v *ContractValidatorWallet) TxSenderAddress() *common.Address { +func (v *Contract) TxSenderAddress() *common.Address { if v.auth == nil { return nil } return &v.auth.From } -func (v *ContractValidatorWallet) From() common.Address { +func (v *Contract) From() common.Address { if v.auth == nil { return common.Address{} } @@ -152,7 +152,7 @@ func (v *ContractValidatorWallet) From() common.Address { } // nil value == 0 value -func (v *ContractValidatorWallet) getAuth(ctx context.Context, value *big.Int) (*bind.TransactOpts, error) { +func (v *Contract) getAuth(ctx context.Context, value *big.Int) (*bind.TransactOpts, error) { newAuth := *v.auth newAuth.Context = ctx newAuth.Value = value @@ -164,7 +164,7 @@ func (v *ContractValidatorWallet) getAuth(ctx context.Context, value *big.Int) ( return &newAuth, nil } -func (v *ContractValidatorWallet) executeTransaction(ctx context.Context, tx *types.Transaction, gasRefunder common.Address) (*types.Transaction, error) { +func (v *Contract) executeTransaction(ctx context.Context, tx *types.Transaction, gasRefunder common.Address) (*types.Transaction, error) { auth, err := v.getAuth(ctx, tx.Value()) if err != nil { return nil, err @@ -180,7 +180,7 @@ func (v *ContractValidatorWallet) executeTransaction(ctx context.Context, tx *ty return v.dataPoster.PostTransaction(ctx, time.Now(), auth.Nonce.Uint64(), nil, *v.Address(), data, gas, auth.Value) } -func (v *ContractValidatorWallet) populateWallet(ctx context.Context, createIfMissing bool) error { +func (v *Contract) populateWallet(ctx context.Context, createIfMissing bool) error { if v.con != nil { return nil } @@ -235,7 +235,7 @@ func combineTxes(txes []*types.Transaction) ([][]byte, []common.Address, []*big. } // Not thread safe! Don't call this from multiple threads at the same time. -func (v *ContractValidatorWallet) ExecuteTransactions(ctx context.Context, builder *txbuilder.ValidatorTxBuilder, gasRefunder common.Address) (*types.Transaction, error) { +func (v *Contract) ExecuteTransactions(ctx context.Context, builder *txbuilder.Builder, gasRefunder common.Address) (*types.Transaction, error) { txes := builder.Transactions() if len(txes) == 0 { return nil, nil @@ -296,7 +296,7 @@ func (v *ContractValidatorWallet) ExecuteTransactions(ctx context.Context, build return arbTx, nil } -func (v *ContractValidatorWallet) estimateGas(ctx context.Context, value *big.Int, data []byte) (uint64, error) { +func (v *Contract) estimateGas(ctx context.Context, value *big.Int, data []byte) (uint64, error) { h, err := v.l1Reader.LastHeader(ctx) if err != nil { return 0, fmt.Errorf("getting the last header: %w", err) @@ -325,7 +325,7 @@ func (v *ContractValidatorWallet) estimateGas(ctx context.Context, value *big.In return g + v.getExtraGas(), nil } -func (v *ContractValidatorWallet) TimeoutChallenges(ctx context.Context, challenges []uint64) (*types.Transaction, error) { +func (v *Contract) TimeoutChallenges(ctx context.Context, challenges []uint64) (*types.Transaction, error) { auth, err := v.getAuth(ctx, nil) if err != nil { return nil, err @@ -342,26 +342,26 @@ func (v *ContractValidatorWallet) TimeoutChallenges(ctx context.Context, challen } // gasForTxData returns auth.GasLimit if it's nonzero, otherwise returns estimate. -func (v *ContractValidatorWallet) gasForTxData(ctx context.Context, auth *bind.TransactOpts, data []byte) (uint64, error) { +func (v *Contract) gasForTxData(ctx context.Context, auth *bind.TransactOpts, data []byte) (uint64, error) { if auth.GasLimit != 0 { return auth.GasLimit, nil } return v.estimateGas(ctx, auth.Value, data) } -func (v *ContractValidatorWallet) L1Client() arbutil.L1Interface { +func (v *Contract) L1Client() arbutil.L1Interface { return v.l1Reader.Client() } -func (v *ContractValidatorWallet) RollupAddress() common.Address { +func (v *Contract) RollupAddress() common.Address { return v.rollupAddress } -func (v *ContractValidatorWallet) ChallengeManagerAddress() common.Address { +func (v *Contract) ChallengeManagerAddress() common.Address { return v.challengeManagerAddress } -func (v *ContractValidatorWallet) TestTransactions(ctx context.Context, txs []*types.Transaction) error { +func (v *Contract) TestTransactions(ctx context.Context, txs []*types.Transaction) error { if v.Address() == nil { return nil } @@ -380,23 +380,23 @@ func (v *ContractValidatorWallet) TestTransactions(ctx context.Context, txs []*t return err } -func (v *ContractValidatorWallet) CanBatchTxs() bool { +func (v *Contract) CanBatchTxs() bool { return true } -func (v *ContractValidatorWallet) AuthIfEoa() *bind.TransactOpts { +func (v *Contract) AuthIfEoa() *bind.TransactOpts { return nil } -func (w *ContractValidatorWallet) Start(ctx context.Context) { +func (w *Contract) Start(ctx context.Context) { w.dataPoster.Start(ctx) } -func (b *ContractValidatorWallet) StopAndWait() { +func (b *Contract) StopAndWait() { b.dataPoster.StopAndWait() } -func (b *ContractValidatorWallet) DataPoster() *dataposter.DataPoster { +func (b *Contract) DataPoster() *dataposter.DataPoster { return b.dataPoster } diff --git a/staker/validatorwallet/eoa.go b/staker/validatorwallet/eoa.go index 5f848aa4eb..b2c9f68b56 100644 --- a/staker/validatorwallet/eoa.go +++ b/staker/validatorwallet/eoa.go @@ -18,7 +18,7 @@ import ( "github.com/offchainlabs/nitro/staker/txbuilder" ) -type EoaValidatorWallet struct { +type EOA struct { auth *bind.TransactOpts client arbutil.L1Interface rollupAddress common.Address @@ -28,8 +28,8 @@ type EoaValidatorWallet struct { getExtraGas func() uint64 } -func NewEoaValidatorWallet(dataPoster *dataposter.DataPoster, rollupAddress common.Address, l1Client arbutil.L1Interface, auth *bind.TransactOpts, getExtraGas func() uint64) (*EoaValidatorWallet, error) { - return &EoaValidatorWallet{ +func NewEOA(dataPoster *dataposter.DataPoster, rollupAddress common.Address, l1Client arbutil.L1Interface, auth *bind.TransactOpts, getExtraGas func() uint64) (*EOA, error) { + return &EOA{ auth: auth, client: l1Client, rollupAddress: rollupAddress, @@ -38,7 +38,7 @@ func NewEoaValidatorWallet(dataPoster *dataposter.DataPoster, rollupAddress comm }, nil } -func (w *EoaValidatorWallet) Initialize(ctx context.Context) error { +func (w *EOA) Initialize(ctx context.Context) error { rollup, err := rollupgen.NewRollupUserLogic(w.rollupAddress, w.client) if err != nil { return err @@ -52,36 +52,36 @@ func (w *EoaValidatorWallet) Initialize(ctx context.Context) error { return err } -func (w *EoaValidatorWallet) Address() *common.Address { +func (w *EOA) Address() *common.Address { return &w.auth.From } -func (w *EoaValidatorWallet) AddressOrZero() common.Address { +func (w *EOA) AddressOrZero() common.Address { return w.auth.From } -func (w *EoaValidatorWallet) TxSenderAddress() *common.Address { +func (w *EOA) TxSenderAddress() *common.Address { return &w.auth.From } -func (w *EoaValidatorWallet) L1Client() arbutil.L1Interface { +func (w *EOA) L1Client() arbutil.L1Interface { return w.client } -func (w *EoaValidatorWallet) RollupAddress() common.Address { +func (w *EOA) RollupAddress() common.Address { return w.rollupAddress } -func (w *EoaValidatorWallet) ChallengeManagerAddress() common.Address { +func (w *EOA) ChallengeManagerAddress() common.Address { return w.challengeManagerAddress } -func (w *EoaValidatorWallet) TestTransactions(context.Context, []*types.Transaction) error { +func (w *EOA) TestTransactions(context.Context, []*types.Transaction) error { // We only use the first tx which is checked implicitly by gas estimation return nil } -func (w *EoaValidatorWallet) ExecuteTransactions(ctx context.Context, builder *txbuilder.ValidatorTxBuilder, _ common.Address) (*types.Transaction, error) { +func (w *EOA) ExecuteTransactions(ctx context.Context, builder *txbuilder.Builder, _ common.Address) (*types.Transaction, error) { if len(builder.Transactions()) == 0 { return nil, nil } @@ -89,7 +89,7 @@ func (w *EoaValidatorWallet) ExecuteTransactions(ctx context.Context, builder *t return w.postTransaction(ctx, tx) } -func (w *EoaValidatorWallet) postTransaction(ctx context.Context, baseTx *types.Transaction) (*types.Transaction, error) { +func (w *EOA) postTransaction(ctx context.Context, baseTx *types.Transaction) (*types.Transaction, error) { nonce, err := w.L1Client().NonceAt(ctx, w.auth.From, nil) if err != nil { return nil, err @@ -102,7 +102,7 @@ func (w *EoaValidatorWallet) postTransaction(ctx context.Context, baseTx *types. return newTx, nil } -func (w *EoaValidatorWallet) TimeoutChallenges(ctx context.Context, timeouts []uint64) (*types.Transaction, error) { +func (w *EOA) TimeoutChallenges(ctx context.Context, timeouts []uint64) (*types.Transaction, error) { if len(timeouts) == 0 { return nil, nil } @@ -116,22 +116,22 @@ func (w *EoaValidatorWallet) TimeoutChallenges(ctx context.Context, timeouts []u return w.postTransaction(ctx, tx) } -func (w *EoaValidatorWallet) CanBatchTxs() bool { +func (w *EOA) CanBatchTxs() bool { return false } -func (w *EoaValidatorWallet) AuthIfEoa() *bind.TransactOpts { +func (w *EOA) AuthIfEoa() *bind.TransactOpts { return w.auth } -func (w *EoaValidatorWallet) Start(ctx context.Context) { +func (w *EOA) Start(ctx context.Context) { w.dataPoster.Start(ctx) } -func (b *EoaValidatorWallet) StopAndWait() { +func (b *EOA) StopAndWait() { b.dataPoster.StopAndWait() } -func (b *EoaValidatorWallet) DataPoster() *dataposter.DataPoster { +func (b *EOA) DataPoster() *dataposter.DataPoster { return b.dataPoster } diff --git a/system_tests/staker_test.go b/system_tests/staker_test.go index 2f2287a2fb..d7207271eb 100644 --- a/system_tests/staker_test.go +++ b/system_tests/staker_test.go @@ -135,7 +135,7 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) if err != nil { t.Fatalf("Error creating validator dataposter: %v", err) } - valWalletA, err := validatorwallet.NewContractValidatorWallet(dpA, nil, l2nodeA.DeployInfo.ValidatorWalletCreator, l2nodeA.DeployInfo.Rollup, l2nodeA.L1Reader, &l1authA, 0, func(common.Address) {}, func() uint64 { return valConfig.ExtraGas }) + valWalletA, err := validatorwallet.NewContract(dpA, nil, l2nodeA.DeployInfo.ValidatorWalletCreator, l2nodeA.DeployInfo.Rollup, l2nodeA.L1Reader, &l1authA, 0, func(common.Address) {}, func() uint64 { return valConfig.ExtraGas }) Require(t, err) if honestStakerInactive { valConfig.Strategy = "Defensive" @@ -183,7 +183,7 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) if err != nil { t.Fatalf("Error creating validator dataposter: %v", err) } - valWalletB, err := validatorwallet.NewEoaValidatorWallet(dpB, l2nodeB.DeployInfo.Rollup, l2nodeB.L1Reader.Client(), &l1authB, func() uint64 { return 0 }) + valWalletB, err := validatorwallet.NewEOA(dpB, l2nodeB.DeployInfo.Rollup, l2nodeB.L1Reader.Client(), &l1authB, func() uint64 { return 0 }) Require(t, err) valConfig.Strategy = "MakeNodes" statelessB, err := staker.NewStatelessBlockValidator( @@ -222,7 +222,7 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) if err != nil { t.Fatalf("Error creating validator dataposter: %v", err) } - valWalletC, err := validatorwallet.NewContractValidatorWallet(dpC, nil, l2nodeA.DeployInfo.ValidatorWalletCreator, l2nodeA.DeployInfo.Rollup, l2nodeA.L1Reader, nil, 0, func(common.Address) {}, func() uint64 { return 10000 }) + valWalletC, err := validatorwallet.NewContract(dpC, nil, l2nodeA.DeployInfo.ValidatorWalletCreator, l2nodeA.DeployInfo.Rollup, l2nodeA.L1Reader, nil, 0, func(common.Address) {}, func() uint64 { return 10000 }) Require(t, err) valConfig.Strategy = "Watchtower" stakerC, err := staker.NewStaker(