Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factor out validator wallets and transaction builder into separate packages #1868

Merged
merged 4 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions arbnode/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -827,15 +828,15 @@ 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.NewContract(dp, existingWalletAddress, deployInfo.ValidatorWalletCreator, deployInfo.Rollup, l1Reader, txOptsValidator, int64(deployInfo.DeployedAt), func(common.Address) {}, getExtraGas)
if err != nil {
return nil, err
}
} else {
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.NewEOA(dp, deployInfo.Rollup, l1client, txOptsValidator, getExtraGas)
if err != nil {
return nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/nitro/nitro.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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())
}
Expand Down
5 changes: 3 additions & 2 deletions staker/l1_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -45,7 +46,7 @@ type L1Validator struct {
rollupAddress common.Address
validatorUtils *rollupgen.ValidatorUtils
client arbutil.L1Interface
builder *ValidatorTxBuilder
builder *txbuilder.Builder
wallet ValidatorWalletInterface
callOpts bind.CallOpts

Expand All @@ -66,7 +67,7 @@ func NewL1Validator(
txStreamer TransactionStreamerInterface,
blockValidator *BlockValidator,
) (*L1Validator, error) {
builder, err := NewValidatorTxBuilder(wallet)
builder, err := txbuilder.NewBuilder(wallet)
if err != nil {
return nil, err
}
Expand Down
26 changes: 24 additions & 2 deletions staker/staker.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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.Builder, 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,
Expand Down Expand Up @@ -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,
Expand Down
45 changes: 34 additions & 11 deletions staker/builder_backend.go → staker/txbuilder/builder.go
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -15,20 +15,29 @@ import (
"github.com/offchainlabs/nitro/arbutil"
)

// ValidatorTxBuilder combines any transactions sent to it via SendTransaction into one batch,
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, *Builder, common.Address) (*types.Transaction, error)
AuthIfEoa() *bind.TransactOpts
}

// 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
isAuthFake bool
wallet ValidatorWalletInterface
}

func NewValidatorTxBuilder(wallet ValidatorWalletInterface) (*ValidatorTxBuilder, error) {
func NewBuilder(wallet ValidatorWalletInterface) (*Builder, error) {
randKey, err := crypto.GenerateKey()
if err != nil {
return nil, err
Expand All @@ -43,30 +52,30 @@ func NewValidatorTxBuilder(wallet ValidatorWalletInterface) (*ValidatorTxBuilder
}
isAuthFake = true
}
return &ValidatorTxBuilder{
return &Builder{
builderAuth: builderAuth,
wallet: wallet,
L1Interface: wallet.L1Client(),
isAuthFake: isAuthFake,
}, 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 {
Expand All @@ -80,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
Expand All @@ -98,6 +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 *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 *Builder) BuilderAuth() *bind.TransactOpts {
return b.builderAuth
}

func (b *Builder) WalletAddress() *common.Address {
return b.wallet.Address()
}
Loading