diff --git a/bridge/conf/config.json b/bridge/conf/config.json index 13e99b05e..04906fc76 100644 --- a/bridge/conf/config.json +++ b/bridge/conf/config.json @@ -27,12 +27,8 @@ "gas_price_diff": 50000 }, "finalize_batch_interval_sec": 0, - "message_sender_private_keys": [ - "1212121212121212121212121212121212121212121212121212121212121212" - ], - "gas_oracle_sender_private_keys": [ - "1313131313131313131313131313131313131313131313131313131313131313" - ] + "message_sender_private_key": "1212121212121212121212121212121212121212121212121212121212121212", + "gas_oracle_sender_private_key": "1313131313131313131313131313131313131313131313131313131313131313" } }, "l2_config": { @@ -62,15 +58,10 @@ "gas_price_diff": 50000 }, "finalize_batch_interval_sec": 0, - "message_sender_private_keys": [ - "1212121212121212121212121212121212121212121212121212121212121212" - ], - "gas_oracle_sender_private_keys": [ - "1313131313131313131313131313131313131313131313131313131313131313" - ], - "rollup_sender_private_keys": [ - "1414141414141414141414141414141414141414141414141414141414141414" - ] + "message_sender_private_key": "1212121212121212121212121212121212121212121212121212121212121212", + "gas_oracle_sender_private_key": "1313131313131313131313131313131313131313131313131313131313131313", + "commit_sender_private_key": "1414141414141414141414141414141414141414141414141414141414141414", + "finalize_sender_private_key": "1515151515151515151515151515151515151515151515151515151515151515" }, "chunk_proposer_config": { "max_tx_gas_per_chunk": 1123456, diff --git a/bridge/go.mod b/bridge/go.mod index e18ab5962..2a6919a9c 100644 --- a/bridge/go.mod +++ b/bridge/go.mod @@ -4,13 +4,11 @@ go 1.19 require ( github.com/agiledragon/gomonkey/v2 v2.9.0 - github.com/orcaman/concurrent-map v1.0.0 github.com/orcaman/concurrent-map/v2 v2.0.1 github.com/scroll-tech/go-ethereum v1.10.14-0.20230804022247-26eeb40ea3ca github.com/smartystreets/goconvey v1.8.0 github.com/stretchr/testify v1.8.3 github.com/urfave/cli/v2 v2.25.7 - golang.org/x/sync v0.3.0 gorm.io/gorm v1.25.2 ) @@ -53,6 +51,7 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect golang.org/x/crypto v0.11.0 // indirect + golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.10.0 // indirect golang.org/x/time v0.3.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/bridge/go.sum b/bridge/go.sum index b472d6655..4e902ba4c 100644 --- a/bridge/go.sum +++ b/bridge/go.sum @@ -84,8 +84,6 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/orcaman/concurrent-map v1.0.0 h1:I/2A2XPCb4IuQWcQhBhSwGfiuybl/J0ev9HDbW65HOY= -github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/6lP/L/zp6c= github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q0Jv47PLaNK++uCdOM= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= diff --git a/bridge/internal/config/config_test.go b/bridge/internal/config/config_test.go index 43d466fc9..d62b78d83 100644 --- a/bridge/internal/config/config_test.go +++ b/bridge/internal/config/config_test.go @@ -15,10 +15,6 @@ func TestConfig(t *testing.T) { cfg, err := NewConfig("../../conf/config.json") assert.NoError(t, err) - assert.Len(t, cfg.L1Config.RelayerConfig.MessageSenderPrivateKeys, 1) - assert.Len(t, cfg.L2Config.RelayerConfig.MessageSenderPrivateKeys, 1) - assert.Len(t, cfg.L2Config.RelayerConfig.RollupSenderPrivateKeys, 1) - data, err := json.Marshal(cfg) assert.NoError(t, err) diff --git a/bridge/internal/config/relayer.go b/bridge/internal/config/relayer.go index adb3725fe..b33239a09 100644 --- a/bridge/internal/config/relayer.go +++ b/bridge/internal/config/relayer.go @@ -34,12 +34,11 @@ type SenderConfig struct { // The interval (in seconds) to check balance and top up sender's accounts CheckBalanceTime uint64 `json:"check_balance_time"` // The sender's pending count limit. - PendingLimit int `json:"pending_limit,omitempty"` + PendingLimit int `json:"pending_limit"` } // RelayerConfig loads relayer configuration items. // What we need to pay attention to is that -// `MessageSenderPrivateKeys` and `RollupSenderPrivateKeys` cannot have common private keys. type RelayerConfig struct { // RollupContractAddress store the rollup contract address. RollupContractAddress common.Address `json:"rollup_contract_address,omitempty"` @@ -56,9 +55,10 @@ type RelayerConfig struct { // MessageRelayMinGasLimit to avoid OutOfGas error MessageRelayMinGasLimit uint64 `json:"message_relay_min_gas_limit,omitempty"` // The private key of the relayer - MessageSenderPrivateKeys []*ecdsa.PrivateKey `json:"-"` - GasOracleSenderPrivateKeys []*ecdsa.PrivateKey `json:"-"` - RollupSenderPrivateKeys []*ecdsa.PrivateKey `json:"-"` + MessageSenderPrivateKey *ecdsa.PrivateKey `json:"-"` + GasOracleSenderPrivateKey *ecdsa.PrivateKey `json:"-"` + CommitSenderPrivateKey *ecdsa.PrivateKey `json:"-"` + FinalizeSenderPrivateKey *ecdsa.PrivateKey `json:"-"` } // GasOracleConfig The config for updating gas price oracle. @@ -72,46 +72,61 @@ type GasOracleConfig struct { // relayerConfigAlias RelayerConfig alias name type relayerConfigAlias RelayerConfig +func convertAndCheck(key string, uniqueAddressesSet map[string]struct{}) (*ecdsa.PrivateKey, error) { + if key == "" { + return nil, nil + } + + privKey, err := crypto.ToECDSA(common.FromHex(key)) + if err != nil { + return nil, err + } + + addr := crypto.PubkeyToAddress(privKey.PublicKey).Hex() + if _, exists := uniqueAddressesSet[addr]; exists { + return nil, fmt.Errorf("detected duplicated address for private key: %s", addr) + } + uniqueAddressesSet[addr] = struct{}{} + + return privKey, nil +} + // UnmarshalJSON unmarshal relayer_config struct. func (r *RelayerConfig) UnmarshalJSON(input []byte) error { - var jsonConfig struct { + var privateKeysConfig struct { relayerConfigAlias - // The private key of the relayer - MessageSenderPrivateKeys []string `json:"message_sender_private_keys"` - GasOracleSenderPrivateKeys []string `json:"gas_oracle_sender_private_keys"` - RollupSenderPrivateKeys []string `json:"rollup_sender_private_keys,omitempty"` + MessageSenderPrivateKey string `json:"message_sender_private_key"` + GasOracleSenderPrivateKey string `json:"gas_oracle_sender_private_key"` + CommitSenderPrivateKey string `json:"commit_sender_private_key"` + FinalizeSenderPrivateKey string `json:"finalize_sender_private_key"` } - if err := json.Unmarshal(input, &jsonConfig); err != nil { - return err + var err error + if err = json.Unmarshal(input, &privateKeysConfig); err != nil { + return fmt.Errorf("failed to unmarshal private keys config: %w", err) } - *r = RelayerConfig(jsonConfig.relayerConfigAlias) + *r = RelayerConfig(privateKeysConfig.relayerConfigAlias) - // Get messenger private key list. - for _, privStr := range jsonConfig.MessageSenderPrivateKeys { - priv, err := crypto.ToECDSA(common.FromHex(privStr)) - if err != nil { - return fmt.Errorf("incorrect private_key_list format, err: %v", err) - } - r.MessageSenderPrivateKeys = append(r.MessageSenderPrivateKeys, priv) + uniqueAddressesSet := make(map[string]struct{}) + + r.MessageSenderPrivateKey, err = convertAndCheck(privateKeysConfig.MessageSenderPrivateKey, uniqueAddressesSet) + if err != nil { + return fmt.Errorf("error converting and checking message sender private key: %w", err) } - // Get gas oracle private key list. - for _, privStr := range jsonConfig.GasOracleSenderPrivateKeys { - priv, err := crypto.ToECDSA(common.FromHex(privStr)) - if err != nil { - return fmt.Errorf("incorrect private_key_list format, err: %v", err) - } - r.GasOracleSenderPrivateKeys = append(r.GasOracleSenderPrivateKeys, priv) + r.GasOracleSenderPrivateKey, err = convertAndCheck(privateKeysConfig.GasOracleSenderPrivateKey, uniqueAddressesSet) + if err != nil { + return fmt.Errorf("error converting and checking gas oracle sender private key: %w", err) } - // Get rollup private key - for _, privStr := range jsonConfig.RollupSenderPrivateKeys { - priv, err := crypto.ToECDSA(common.FromHex(privStr)) - if err != nil { - return fmt.Errorf("incorrect prover_private_key format, err: %v", err) - } - r.RollupSenderPrivateKeys = append(r.RollupSenderPrivateKeys, priv) + r.CommitSenderPrivateKey, err = convertAndCheck(privateKeysConfig.CommitSenderPrivateKey, uniqueAddressesSet) + if err != nil { + return fmt.Errorf("error converting and checking commit sender private key: %w", err) + } + + r.FinalizeSenderPrivateKey, err = convertAndCheck(privateKeysConfig.FinalizeSenderPrivateKey, uniqueAddressesSet) + if err != nil { + return fmt.Errorf("error converting and checking finalize sender private key: %w", err) } return nil @@ -119,28 +134,20 @@ func (r *RelayerConfig) UnmarshalJSON(input []byte) error { // MarshalJSON marshal RelayerConfig config, transfer private keys. func (r *RelayerConfig) MarshalJSON() ([]byte, error) { - jsonConfig := struct { + privateKeysConfig := struct { relayerConfigAlias // The private key of the relayer - MessageSenderPrivateKeys []string `json:"message_sender_private_keys"` - GasOracleSenderPrivateKeys []string `json:"gas_oracle_sender_private_keys,omitempty"` - RollupSenderPrivateKeys []string `json:"rollup_sender_private_keys,omitempty"` - }{relayerConfigAlias(*r), nil, nil, nil} + MessageSenderPrivateKey string `json:"message_sender_private_key"` + GasOracleSenderPrivateKey string `json:"gas_oracle_sender_private_key"` + CommitSenderPrivateKey string `json:"commit_sender_private_key"` + FinalizeSenderPrivateKey string `json:"finalize_sender_private_key"` + }{} - // Transfer message sender private keys to hex type. - for _, priv := range r.MessageSenderPrivateKeys { - jsonConfig.MessageSenderPrivateKeys = append(jsonConfig.MessageSenderPrivateKeys, common.Bytes2Hex(crypto.FromECDSA(priv))) - } + privateKeysConfig.relayerConfigAlias = relayerConfigAlias(*r) + privateKeysConfig.MessageSenderPrivateKey = common.Bytes2Hex(crypto.FromECDSA(r.MessageSenderPrivateKey)) + privateKeysConfig.GasOracleSenderPrivateKey = common.Bytes2Hex(crypto.FromECDSA(r.GasOracleSenderPrivateKey)) + privateKeysConfig.CommitSenderPrivateKey = common.Bytes2Hex(crypto.FromECDSA(r.CommitSenderPrivateKey)) + privateKeysConfig.FinalizeSenderPrivateKey = common.Bytes2Hex(crypto.FromECDSA(r.FinalizeSenderPrivateKey)) - // Transfer rollup sender private keys to hex type. - for _, priv := range r.GasOracleSenderPrivateKeys { - jsonConfig.GasOracleSenderPrivateKeys = append(jsonConfig.GasOracleSenderPrivateKeys, common.Bytes2Hex(crypto.FromECDSA(priv))) - } - - // Transfer rollup sender private keys to hex type. - for _, priv := range r.RollupSenderPrivateKeys { - jsonConfig.RollupSenderPrivateKeys = append(jsonConfig.RollupSenderPrivateKeys, common.Bytes2Hex(crypto.FromECDSA(priv))) - } - - return json.Marshal(&jsonConfig) + return json.Marshal(&privateKeysConfig) } diff --git a/bridge/internal/controller/relayer/l1_relayer.go b/bridge/internal/controller/relayer/l1_relayer.go index 1a58fc2de..16c093fe8 100644 --- a/bridge/internal/controller/relayer/l1_relayer.go +++ b/bridge/internal/controller/relayer/l1_relayer.go @@ -3,6 +3,7 @@ package relayer import ( "context" "errors" + "fmt" "math/big" // not sure if this will make problems when relay with l1geth @@ -57,19 +58,16 @@ type Layer1Relayer struct { // NewLayer1Relayer will return a new instance of Layer1RelayerClient func NewLayer1Relayer(ctx context.Context, db *gorm.DB, cfg *config.RelayerConfig) (*Layer1Relayer, error) { - messageSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.MessageSenderPrivateKeys) + messageSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.MessageSenderPrivateKey) if err != nil { - addr := crypto.PubkeyToAddress(cfg.MessageSenderPrivateKeys[0].PublicKey) - log.Error("new MessageSender failed", "main address", addr.String(), "err", err) - return nil, err + addr := crypto.PubkeyToAddress(cfg.MessageSenderPrivateKey.PublicKey) + return nil, fmt.Errorf("new message sender failed for address %s, err: %v", addr.Hex(), err) } - // @todo make sure only one sender is available - gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderPrivateKeys) + gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderPrivateKey) if err != nil { - addr := crypto.PubkeyToAddress(cfg.GasOracleSenderPrivateKeys[0].PublicKey) - log.Error("new GasOracleSender failed", "main address", addr.String(), "err", err) - return nil, err + addr := crypto.PubkeyToAddress(cfg.GasOracleSenderPrivateKey.PublicKey) + return nil, fmt.Errorf("new gas oracle sender failed for address %s, err: %v", addr.Hex(), err) } var minGasPrice uint64 diff --git a/bridge/internal/controller/relayer/l2_relayer.go b/bridge/internal/controller/relayer/l2_relayer.go index b9f614c07..7313c8287 100644 --- a/bridge/internal/controller/relayer/l2_relayer.go +++ b/bridge/internal/controller/relayer/l2_relayer.go @@ -11,6 +11,7 @@ import ( "github.com/scroll-tech/go-ethereum/accounts/abi" "github.com/scroll-tech/go-ethereum/common" gethTypes "github.com/scroll-tech/go-ethereum/core/types" + "github.com/scroll-tech/go-ethereum/crypto" "github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/log" gethMetrics "github.com/scroll-tech/go-ethereum/metrics" @@ -53,8 +54,9 @@ type Layer2Relayer struct { messageSender *sender.Sender l1MessengerABI *abi.ABI - rollupSender *sender.Sender - l1RollupABI *abi.ABI + commitSender *sender.Sender + finalizeSender *sender.Sender + l1RollupABI *abi.ABI gasOracleSender *sender.Sender l2GasOracleABI *abi.ABI @@ -80,23 +82,28 @@ type Layer2Relayer struct { // NewLayer2Relayer will return a new instance of Layer2RelayerClient func NewLayer2Relayer(ctx context.Context, l2Client *ethclient.Client, db *gorm.DB, cfg *config.RelayerConfig, initGenesis bool) (*Layer2Relayer, error) { - // @todo use different sender for relayer, block commit and proof finalize - messageSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.MessageSenderPrivateKeys) + messageSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.MessageSenderPrivateKey) if err != nil { - log.Error("Failed to create messenger sender", "err", err) - return nil, err + addr := crypto.PubkeyToAddress(cfg.MessageSenderPrivateKey.PublicKey) + return nil, fmt.Errorf("new message sender failed for address %s, err: %w", addr.Hex(), err) } - rollupSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.RollupSenderPrivateKeys) + commitSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.CommitSenderPrivateKey) if err != nil { - log.Error("Failed to create rollup sender", "err", err) - return nil, err + addr := crypto.PubkeyToAddress(cfg.CommitSenderPrivateKey.PublicKey) + return nil, fmt.Errorf("new commit sender failed for address %s, err: %w", addr.Hex(), err) } - gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderPrivateKeys) + finalizeSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.FinalizeSenderPrivateKey) if err != nil { - log.Error("Failed to create gas oracle sender", "err", err) - return nil, err + addr := crypto.PubkeyToAddress(cfg.FinalizeSenderPrivateKey.PublicKey) + return nil, fmt.Errorf("new finalize sender failed for address %s, err: %w", addr.Hex(), err) + } + + gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderPrivateKey) + if err != nil { + addr := crypto.PubkeyToAddress(cfg.GasOracleSenderPrivateKey.PublicKey) + return nil, fmt.Errorf("new gas oracle sender failed for address %s, err: %w", addr.Hex(), err) } var minGasPrice uint64 @@ -127,8 +134,9 @@ func NewLayer2Relayer(ctx context.Context, l2Client *ethclient.Client, db *gorm. messageSender: messageSender, l1MessengerABI: bridgeAbi.L1ScrollMessengerABI, - rollupSender: rollupSender, - l1RollupABI: bridgeAbi.ScrollChainABI, + commitSender: commitSender, + finalizeSender: finalizeSender, + l1RollupABI: bridgeAbi.ScrollChainABI, gasOracleSender: gasOracleSender, l2GasOracleABI: bridgeAbi.L2GasPriceOracleABI, @@ -230,7 +238,7 @@ func (r *Layer2Relayer) commitGenesisBatch(batchHash string, batchHeader []byte, } // submit genesis batch to L1 rollup contract - txHash, err := r.rollupSender.SendTransaction(batchHash, &r.cfg.RollupContractAddress, big.NewInt(0), calldata, 0) + txHash, err := r.commitSender.SendTransaction(batchHash, &r.cfg.RollupContractAddress, big.NewInt(0), calldata, 0) if err != nil { return fmt.Errorf("failed to send import genesis batch tx to L1, error: %v", err) } @@ -245,14 +253,14 @@ func (r *Layer2Relayer) commitGenesisBatch(batchHash string, batchHeader []byte, select { // print progress case <-ticker.C: - log.Info("Waiting for confirmation", "pending count", r.rollupSender.PendingCount()) + log.Info("Waiting for confirmation") // timeout case <-time.After(5 * time.Minute): return fmt.Errorf("import genesis timeout after 5 minutes, original txHash: %v", txHash.String()) // handle confirmation - case confirmation := <-r.rollupSender.ConfirmChan(): + case confirmation := <-r.commitSender.ConfirmChan(): if confirmation.ID != batchHash { return fmt.Errorf("unexpected import genesis confirmation id, expected: %v, got: %v", batchHash, confirmation.ID) } @@ -374,7 +382,7 @@ func (r *Layer2Relayer) ProcessPendingBatches() { // send transaction txID := batch.Hash + "-commit" - txHash, err := r.rollupSender.SendTransaction(txID, &r.cfg.RollupContractAddress, big.NewInt(0), calldata, 0) + txHash, err := r.commitSender.SendTransaction(txID, &r.cfg.RollupContractAddress, big.NewInt(0), calldata, 0) if err != nil { log.Error( "Failed to send commitBatch tx to layer1", @@ -468,7 +476,7 @@ func (r *Layer2Relayer) ProcessCommittedBatches() { txID := hash + "-finalize" // add suffix `-finalize` to avoid duplication with commit tx in unit tests - txHash, err := r.rollupSender.SendTransaction(txID, &r.cfg.RollupContractAddress, big.NewInt(0), data, 0) + txHash, err := r.finalizeSender.SendTransaction(txID, &r.cfg.RollupContractAddress, big.NewInt(0), data, 0) finalizeTxHash := &txHash if err != nil { if !errors.Is(err, sender.ErrNoAvailableAccount) && !errors.Is(err, sender.ErrFullPending) { @@ -577,7 +585,9 @@ func (r *Layer2Relayer) handleConfirmLoop(ctx context.Context) { return case confirmation := <-r.messageSender.ConfirmChan(): r.handleConfirmation(confirmation) - case confirmation := <-r.rollupSender.ConfirmChan(): + case confirmation := <-r.commitSender.ConfirmChan(): + r.handleConfirmation(confirmation) + case confirmation := <-r.finalizeSender.ConfirmChan(): r.handleConfirmation(confirmation) case cfm := <-r.gasOracleSender.ConfirmChan(): if !cfm.IsSuccessful { diff --git a/bridge/internal/controller/relayer/l2_relayer_test.go b/bridge/internal/controller/relayer/l2_relayer_test.go index c45edd39f..ef9c75939 100644 --- a/bridge/internal/controller/relayer/l2_relayer_test.go +++ b/bridge/internal/controller/relayer/l2_relayer_test.go @@ -106,7 +106,7 @@ func testL2RelayerProcessCommittedBatches(t *testing.T) { assert.Equal(t, types.RollupFinalizing, statuses[0]) } -func testL2RelayerRollupConfirm(t *testing.T) { +func testL2RelayerCommitConfirm(t *testing.T) { db := setupL2RelayerDB(t) defer database.CloseDB(db) @@ -118,8 +118,8 @@ func testL2RelayerRollupConfirm(t *testing.T) { assert.NoError(t, err) // Simulate message confirmations. - processingKeys := []string{"committed-1", "committed-2", "finalized-1", "finalized-2"} - isSuccessful := []bool{true, false, true, false} + processingKeys := []string{"committed-1", "committed-2"} + isSuccessful := []bool{true, false} batchOrm := orm.NewBatch(db) batchHashes := make([]string, len(processingKeys)) @@ -129,29 +129,68 @@ func testL2RelayerRollupConfirm(t *testing.T) { batchHashes[i] = batch.Hash } - for i, key := range processingKeys[:2] { + for i, key := range processingKeys { l2Relayer.processingCommitment.Store(key, batchHashes[i]) - l2Relayer.rollupSender.SendConfirmation(&sender.Confirmation{ + l2Relayer.commitSender.SendConfirmation(&sender.Confirmation{ ID: key, IsSuccessful: isSuccessful[i], TxHash: common.HexToHash("0x123456789abcdef"), }) } - for i, key := range processingKeys[2:] { - l2Relayer.processingFinalization.Store(key, batchHashes[i+2]) - l2Relayer.rollupSender.SendConfirmation(&sender.Confirmation{ - ID: key, - IsSuccessful: isSuccessful[i+2], - TxHash: common.HexToHash("0x123456789abcdef"), - }) - } - // Check the database for the updated status using TryTimes. ok := utils.TryTimes(5, func() bool { expectedStatuses := []types.RollupStatus{ types.RollupCommitted, types.RollupCommitFailed, + } + + for i, batchHash := range batchHashes { + batchInDB, err := batchOrm.GetBatches(context.Background(), map[string]interface{}{"hash": batchHash}, nil, 0) + if err != nil || len(batchInDB) != 1 || types.RollupStatus(batchInDB[0].RollupStatus) != expectedStatuses[i] { + return false + } + } + return true + }) + assert.True(t, ok) +} + +func testL2RelayerFinalizeConfirm(t *testing.T) { + db := setupL2RelayerDB(t) + defer database.CloseDB(db) + + // Create and set up the Layer2 Relayer. + l2Cfg := cfg.L2Config + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + l2Relayer, err := NewLayer2Relayer(ctx, l2Cli, db, l2Cfg.RelayerConfig, false) + assert.NoError(t, err) + + // Simulate message confirmations. + processingKeys := []string{"finalized-1", "finalized-2"} + isSuccessful := []bool{true, false} + + batchOrm := orm.NewBatch(db) + batchHashes := make([]string, len(processingKeys)) + for i := range batchHashes { + batch, err := batchOrm.InsertBatch(context.Background(), 0, 1, chunkHash1.Hex(), chunkHash2.Hex(), []*types.Chunk{chunk1, chunk2}) + assert.NoError(t, err) + batchHashes[i] = batch.Hash + } + + for i, key := range processingKeys { + l2Relayer.processingFinalization.Store(key, batchHashes[i]) + l2Relayer.finalizeSender.SendConfirmation(&sender.Confirmation{ + ID: key, + IsSuccessful: isSuccessful[i], + TxHash: common.HexToHash("0x123456789abcdef"), + }) + } + + // Check the database for the updated status using TryTimes. + ok := utils.TryTimes(5, func() bool { + expectedStatuses := []types.RollupStatus{ types.RollupFinalized, types.RollupFinalizeFailed, } diff --git a/bridge/internal/controller/relayer/relayer_test.go b/bridge/internal/controller/relayer/relayer_test.go index 910d68743..0e7c19484 100644 --- a/bridge/internal/controller/relayer/relayer_test.go +++ b/bridge/internal/controller/relayer/relayer_test.go @@ -97,7 +97,8 @@ func TestFunctions(t *testing.T) { t.Run("TestCreateNewRelayer", testCreateNewRelayer) t.Run("TestL2RelayerProcessPendingBatches", testL2RelayerProcessPendingBatches) t.Run("TestL2RelayerProcessCommittedBatches", testL2RelayerProcessCommittedBatches) - t.Run("TestL2RelayerRollupConfirm", testL2RelayerRollupConfirm) + t.Run("TestL2RelayerCommitConfirm", testL2RelayerCommitConfirm) + t.Run("TestL2RelayerFinalizeConfirm", testL2RelayerFinalizeConfirm) t.Run("TestL2RelayerGasOracleConfirm", testL2RelayerGasOracleConfirm) t.Run("TestLayer2RelayerProcessGasPriceOracle", testLayer2RelayerProcessGasPriceOracle) } diff --git a/bridge/internal/controller/sender/account_pool.go b/bridge/internal/controller/sender/account_pool.go deleted file mode 100644 index 05acf73dc..000000000 --- a/bridge/internal/controller/sender/account_pool.go +++ /dev/null @@ -1,165 +0,0 @@ -package sender - -import ( - "context" - "crypto/ecdsa" - "fmt" - "math/big" - - "github.com/scroll-tech/go-ethereum/accounts/abi/bind" - "github.com/scroll-tech/go-ethereum/common" - "github.com/scroll-tech/go-ethereum/core/types" - "github.com/scroll-tech/go-ethereum/ethclient" - "github.com/scroll-tech/go-ethereum/log" -) - -type accountPool struct { - client *ethclient.Client - - minBalance *big.Int - accounts map[common.Address]*bind.TransactOpts - accsCh chan *bind.TransactOpts -} - -// newAccounts creates an accountPool instance. -func newAccountPool(ctx context.Context, minBalance *big.Int, client *ethclient.Client, privs []*ecdsa.PrivateKey) (*accountPool, error) { - accs := &accountPool{ - client: client, - minBalance: minBalance, - accounts: make(map[common.Address]*bind.TransactOpts, len(privs)), - accsCh: make(chan *bind.TransactOpts, len(privs)+2), - } - - // get chainID from client - chainID, err := client.ChainID(ctx) - if err != nil { - return nil, err - } - - for _, privStr := range privs { - auth, err := bind.NewKeyedTransactorWithChainID(privStr, chainID) - if err != nil { - log.Error("failed to create account", "chainID", chainID.String(), "err", err) - return nil, err - } - - // Set pending nonce - nonce, err := client.PendingNonceAt(ctx, auth.From) - if err != nil { - return nil, err - } - auth.Nonce = big.NewInt(int64(nonce)) - accs.accounts[auth.From] = auth - accs.accsCh <- auth - } - - return accs, accs.checkAndSetBalances(ctx) -} - -// getAccount get auth from channel. -func (a *accountPool) getAccount() *bind.TransactOpts { - select { - case auth := <-a.accsCh: - return auth - default: - return nil - } -} - -// releaseAccount set used auth into channel. -func (a *accountPool) releaseAccount(auth *bind.TransactOpts) { - a.accsCh <- auth -} - -// reSetNonce reset nonce if send signed tx failed. -func (a *accountPool) resetNonce(ctx context.Context, auth *bind.TransactOpts) { - nonce, err := a.client.PendingNonceAt(ctx, auth.From) - if err != nil { - log.Warn("failed to reset nonce", "address", auth.From.String(), "err", err) - return - } - auth.Nonce = big.NewInt(int64(nonce)) -} - -// checkAndSetBalance check balance and set min balance. -func (a *accountPool) checkAndSetBalances(ctx context.Context) error { - var ( - root *bind.TransactOpts - maxBls = big.NewInt(0) - lostAuths []*bind.TransactOpts - ) - - for addr, auth := range a.accounts { - bls, err := a.client.BalanceAt(ctx, addr, nil) - if err != nil || bls.Cmp(a.minBalance) < 0 { - if err != nil { - log.Warn("failed to get balance", "address", addr.String(), "err", err) - return err - } - lostAuths = append(lostAuths, auth) - continue - } else if bls.Cmp(maxBls) > 0 { // Find the biggest balance account. - root, maxBls = auth, bls - } - } - if root == nil { - return fmt.Errorf("no account has enough balance") - } - if len(lostAuths) == 0 { - return nil - } - - var ( - tx *types.Transaction - err error - ) - for _, auth := range lostAuths { - tx, err = a.createSignedTx(root, &auth.From, a.minBalance) - if err != nil { - return err - } - err = a.client.SendTransaction(ctx, tx) - if err != nil { - log.Error("Failed to send balance to account", "err", err) - return err - } - log.Debug("send balance to account", "account", auth.From.String(), "balance", a.minBalance.String()) - } - // wait util mined - if _, err = bind.WaitMined(ctx, a.client, tx); err != nil { - return err - } - - // Reset root's nonce. - a.resetNonce(ctx, root) - - return nil -} - -func (a *accountPool) createSignedTx(from *bind.TransactOpts, to *common.Address, value *big.Int) (*types.Transaction, error) { - gasPrice, err := a.client.SuggestGasPrice(context.Background()) - if err != nil { - return nil, err - } - gasPrice.Mul(gasPrice, big.NewInt(2)) - - // Get pending nonce - nonce, err := a.client.PendingNonceAt(context.Background(), from.From) - if err != nil { - return nil, err - } - - tx := types.NewTx(&types.LegacyTx{ - Nonce: nonce, - To: to, - Value: value, - Gas: 500000, - GasPrice: gasPrice, - }) - signedTx, err := from.Signer(from.From, tx) - if err != nil { - return nil, err - } - - return signedTx, nil -} diff --git a/bridge/internal/controller/sender/sender.go b/bridge/internal/controller/sender/sender.go index 5eed5f7d5..d7d99adc2 100644 --- a/bridge/internal/controller/sender/sender.go +++ b/bridge/internal/controller/sender/sender.go @@ -39,10 +39,6 @@ var ( ErrFullPending = errors.New("sender's pending pool is full") ) -var ( - defaultPendingLimit = 10 -) - // Confirmation struct used to indicate transaction confirmation details type Confirmation struct { ID string @@ -75,8 +71,8 @@ type Sender struct { chainID *big.Int // The chain id of the endpoint ctx context.Context - // account fields. - auths *accountPool + auth *bind.TransactOpts + minBalance *big.Int blockNumber uint64 // Current block number on chain. baseFeePerGas uint64 // Current base fee per gas on chain @@ -88,27 +84,34 @@ type Sender struct { // NewSender returns a new instance of transaction sender // txConfirmationCh is used to notify confirmed transaction -func NewSender(ctx context.Context, config *config.SenderConfig, privs []*ecdsa.PrivateKey) (*Sender, error) { +func NewSender(ctx context.Context, config *config.SenderConfig, priv *ecdsa.PrivateKey) (*Sender, error) { client, err := ethclient.Dial(config.Endpoint) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to dial eth client, err: %w", err) } // get chainID from client chainID, err := client.ChainID(ctx) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to get chain ID, err: %w", err) } - auths, err := newAccountPool(ctx, config.MinBalance, client, privs) + auth, err := bind.NewKeyedTransactorWithChainID(priv, chainID) if err != nil { - return nil, fmt.Errorf("failed to create account pool, err: %v", err) + return nil, fmt.Errorf("failed to create transactor with chain ID %v, err: %w", chainID, err) } + // Set pending nonce + nonce, err := client.PendingNonceAt(ctx, auth.From) + if err != nil { + return nil, fmt.Errorf("failed to get pending nonce for address %s, err: %w", auth.From.Hex(), err) + } + auth.Nonce = big.NewInt(int64(nonce)) + // get header by number header, err := client.HeaderByNumber(ctx, nil) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to get header by number, err: %w", err) } var baseFeePerGas uint64 @@ -116,21 +119,17 @@ func NewSender(ctx context.Context, config *config.SenderConfig, privs []*ecdsa. if header.BaseFee != nil { baseFeePerGas = header.BaseFee.Uint64() } else { - return nil, errors.New("DynamicFeeTxType not supported, header.BaseFee nil") + return nil, errors.New("dynamic fee tx type not supported: header.BaseFee is nil") } } - // initialize pending limit with a default value - if config.PendingLimit == 0 { - config.PendingLimit = defaultPendingLimit - } - sender := &Sender{ ctx: ctx, config: config, client: client, chainID: chainID, - auths: auths, + auth: auth, + minBalance: config.MinBalance, confirmCh: make(chan *Confirmation, 128), blockNumber: header.Number.Uint64(), baseFeePerGas: baseFeePerGas, @@ -175,11 +174,6 @@ func (s *Sender) SendConfirmation(cfm *Confirmation) { s.confirmCh <- cfm } -// NumberOfAccounts return the count of accounts. -func (s *Sender) NumberOfAccounts() int { - return len(s.auths.accounts) -} - func (s *Sender) getFeeData(auth *bind.TransactOpts, target *common.Address, value *big.Int, data []byte, minGasLimit uint64) (*FeeData, error) { if s.config.TxType == DynamicFeeTxType { return s.estimateDynamicGas(auth, target, value, data, minGasLimit) @@ -188,53 +182,39 @@ func (s *Sender) getFeeData(auth *bind.TransactOpts, target *common.Address, val } // SendTransaction send a signed L2tL1 transaction. -func (s *Sender) SendTransaction(ID string, target *common.Address, value *big.Int, data []byte, minGasLimit uint64) (hash common.Hash, err error) { +func (s *Sender) SendTransaction(ID string, target *common.Address, value *big.Int, data []byte, minGasLimit uint64) (common.Hash, error) { if s.IsFull() { return common.Hash{}, ErrFullPending } - // We occupy the ID, in case some other threads call with the same ID in the same time if ok := s.pendingTxs.SetIfAbsent(ID, nil); !ok { - return common.Hash{}, fmt.Errorf("has the repeat tx ID, ID: %s", ID) + return common.Hash{}, fmt.Errorf("repeat transaction ID: %s", ID) } - // get - auth := s.auths.getAccount() - if auth == nil { - s.pendingTxs.Remove(ID) // release the ID on failure - return common.Hash{}, ErrNoAvailableAccount - } - - defer s.auths.releaseAccount(auth) - defer func() { - if err != nil { - s.pendingTxs.Remove(ID) // release the ID on failure - } - }() var ( feeData *FeeData tx *types.Transaction + err error ) - // estimate gas fee - if feeData, err = s.getFeeData(auth, target, value, data, minGasLimit); err != nil { - return + if feeData, err = s.getFeeData(s.auth, target, value, data, minGasLimit); err != nil { + return common.Hash{}, fmt.Errorf("failed to get fee data, err: %w", err) } - if tx, err = s.createAndSendTx(auth, feeData, target, value, data, nil); err == nil { - // add pending transaction to queue - pending := &PendingTransaction{ - tx: tx, - id: ID, - signer: auth, - submitAt: atomic.LoadUint64(&s.blockNumber), - feeData: feeData, - } - s.pendingTxs.Set(ID, pending) - return tx.Hash(), nil + if tx, err = s.createAndSendTx(s.auth, feeData, target, value, data, nil); err != nil { + return common.Hash{}, fmt.Errorf("failed to create and send transaction, err: %w", err) } - return + // add pending transaction + pending := &PendingTransaction{ + tx: tx, + id: ID, + signer: s.auth, + submitAt: atomic.LoadUint64(&s.blockNumber), + feeData: feeData, + } + s.pendingTxs.Set(ID, pending) + return tx.Hash(), nil } -func (s *Sender) createAndSendTx(auth *bind.TransactOpts, feeData *FeeData, target *common.Address, value *big.Int, data []byte, overrideNonce *uint64) (tx *types.Transaction, err error) { +func (s *Sender) createAndSendTx(auth *bind.TransactOpts, feeData *FeeData, target *common.Address, value *big.Int, data []byte, overrideNonce *uint64) (*types.Transaction, error) { var ( nonce = auth.Nonce.Uint64() txData types.TxData @@ -292,26 +272,36 @@ func (s *Sender) createAndSendTx(auth *bind.TransactOpts, feeData *FeeData, targ } // sign and send - tx, err = auth.Signer(auth.From, types.NewTx(txData)) + tx, err := auth.Signer(auth.From, types.NewTx(txData)) if err != nil { log.Error("failed to sign tx", "err", err) - return + return nil, err } if err = s.client.SendTransaction(s.ctx, tx); err != nil { log.Error("failed to send tx", "tx hash", tx.Hash().String(), "err", err) // Check if contain nonce, and reset nonce // only reset nonce when it is not from resubmit if strings.Contains(err.Error(), "nonce") && overrideNonce == nil { - s.auths.resetNonce(context.Background(), auth) + s.resetNonce(context.Background()) } - return + return nil, err } // update nonce when it is not from resubmit if overrideNonce == nil { auth.Nonce = big.NewInt(int64(nonce + 1)) } - return + return tx, nil +} + +// reSetNonce reset nonce if send signed tx failed. +func (s *Sender) resetNonce(ctx context.Context) { + nonce, err := s.client.PendingNonceAt(ctx, s.auth.From) + if err != nil { + log.Warn("failed to reset nonce", "address", s.auth.From.String(), "err", err) + return + } + s.auth.Nonce = big.NewInt(int64(nonce)) } func (s *Sender) resubmitTransaction(feeData *FeeData, auth *bind.TransactOpts, tx *types.Transaction) (*types.Transaction, error) { @@ -448,6 +438,22 @@ func (s *Sender) checkPendingTransaction(header *types.Header, confirmed uint64) } } +// checkBalance checks balance and print error log if balance is under a threshold. +func (s *Sender) checkBalance(ctx context.Context) error { + bls, err := s.client.BalanceAt(ctx, s.auth.From, nil) + if err != nil { + log.Warn("failed to get balance", "address", s.auth.From.String(), "err", err) + return err + } + + if bls.Cmp(s.minBalance) < 0 { + return fmt.Errorf("insufficient account balance - actual balance: %s, minimum required balance: %s", + bls.String(), s.minBalance.String()) + } + + return nil +} + // Loop is the main event loop func (s *Sender) loop(ctx context.Context) { checkTick := time.NewTicker(time.Duration(s.config.CheckPendingTime) * time.Second) @@ -474,7 +480,9 @@ func (s *Sender) loop(ctx context.Context) { s.checkPendingTransaction(header, confirmed) case <-checkBalanceTicker.C: // Check and set balance. - _ = s.auths.checkAndSetBalances(ctx) + if err := s.checkBalance(ctx); err != nil { + log.Error("check balance, err: %w", err) + } case <-ctx.Done(): return case <-s.stopCh: diff --git a/bridge/internal/controller/sender/sender_test.go b/bridge/internal/controller/sender/sender_test.go index cff929883..1c96ff721 100644 --- a/bridge/internal/controller/sender/sender_test.go +++ b/bridge/internal/controller/sender/sender_test.go @@ -7,10 +7,8 @@ import ( "math/big" "strconv" "testing" - "time" "github.com/agiledragon/gomonkey/v2" - cmap "github.com/orcaman/concurrent-map" "github.com/scroll-tech/go-ethereum/accounts/abi/bind" "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/core/types" @@ -18,7 +16,6 @@ import ( "github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/rpc" "github.com/stretchr/testify/assert" - "golang.org/x/sync/errgroup" "scroll-tech/common/docker" @@ -28,10 +25,10 @@ import ( const TXBatch = 50 var ( - privateKeys []*ecdsa.PrivateKey - cfg *config.Config - base *docker.App - txTypes = []string{"LegacyTx", "AccessListTx", "DynamicFeeTx"} + privateKey *ecdsa.PrivateKey + cfg *config.Config + base *docker.App + txTypes = []string{"LegacyTx", "AccessListTx", "DynamicFeeTx"} ) func TestMain(m *testing.M) { @@ -50,7 +47,7 @@ func setupEnv(t *testing.T) { priv, err := crypto.HexToECDSA("1212121212121212121212121212121212121212121212121212121212121212") assert.NoError(t, err) // Load default private key. - privateKeys = []*ecdsa.PrivateKey{priv} + privateKey = priv cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L1gethImg.Endpoint() cfg.L1Config.RelayerConfig.SenderConfig.CheckBalanceTime = 1 @@ -62,15 +59,10 @@ func TestSender(t *testing.T) { t.Run("test new sender", testNewSender) t.Run("test pending limit", testPendLimit) - t.Run("test min gas limit", testMinGasLimit) t.Run("test resubmit transaction", testResubmitTransaction) t.Run("test resubmit transaction with rising base fee", testResubmitTransactionWithRisingBaseFee) t.Run("test check pending transaction", testCheckPendingTransaction) - - t.Run("test 1 account sender", func(t *testing.T) { testBatchSender(t, 1) }) - t.Run("test 3 account sender", func(t *testing.T) { testBatchSender(t, 3) }) - t.Run("test 8 account sender", func(t *testing.T) { testBatchSender(t, 8) }) } func testNewSender(t *testing.T) { @@ -78,7 +70,7 @@ func testNewSender(t *testing.T) { // exit by Stop() cfgCopy1 := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy1.TxType = txType - newSender1, err := NewSender(context.Background(), &cfgCopy1, privateKeys) + newSender1, err := NewSender(context.Background(), &cfgCopy1, privateKey) assert.NoError(t, err) newSender1.Stop() @@ -86,7 +78,7 @@ func testNewSender(t *testing.T) { cfgCopy2 := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy2.TxType = txType subCtx, cancel := context.WithCancel(context.Background()) - _, err = NewSender(subCtx, &cfgCopy2, privateKeys) + _, err = NewSender(subCtx, &cfgCopy2, privateKey) assert.NoError(t, err) cancel() } @@ -98,7 +90,7 @@ func testPendLimit(t *testing.T) { cfgCopy.TxType = txType cfgCopy.Confirmations = rpc.LatestBlockNumber cfgCopy.PendingLimit = 2 - newSender, err := NewSender(context.Background(), &cfgCopy, privateKeys) + newSender, err := NewSender(context.Background(), &cfgCopy, privateKey) assert.NoError(t, err) for i := 0; i < 2*newSender.PendingLimit(); i++ { @@ -115,7 +107,7 @@ func testMinGasLimit(t *testing.T) { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType cfgCopy.Confirmations = rpc.LatestBlockNumber - newSender, err := NewSender(context.Background(), &cfgCopy, privateKeys) + newSender, err := NewSender(context.Background(), &cfgCopy, privateKey) assert.NoError(t, err) client, err := ethclient.Dial(cfgCopy.Endpoint) @@ -143,13 +135,12 @@ func testResubmitTransaction(t *testing.T) { for _, txType := range txTypes { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKeys) + s, err := NewSender(context.Background(), &cfgCopy, privateKey) assert.NoError(t, err) - auth := s.auths.getAccount() - tx := types.NewTransaction(auth.Nonce.Uint64(), common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil) - feeData, err := s.getFeeData(auth, &common.Address{}, big.NewInt(0), nil, 0) + tx := types.NewTransaction(s.auth.Nonce.Uint64(), common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil) + feeData, err := s.getFeeData(s.auth, &common.Address{}, big.NewInt(0), nil, 0) assert.NoError(t, err) - _, err = s.resubmitTransaction(feeData, auth, tx) + _, err = s.resubmitTransaction(feeData, s.auth, tx) assert.NoError(t, err) s.Stop() } @@ -160,17 +151,16 @@ func testResubmitTransactionWithRisingBaseFee(t *testing.T) { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKeys) + s, err := NewSender(context.Background(), &cfgCopy, privateKey) assert.NoError(t, err) - auth := s.auths.getAccount() - tx := types.NewTransaction(auth.Nonce.Uint64(), common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil) + tx := types.NewTransaction(s.auth.Nonce.Uint64(), common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil) s.baseFeePerGas = 1000 - feeData, err := s.getFeeData(auth, &common.Address{}, big.NewInt(0), nil, 0) + feeData, err := s.getFeeData(s.auth, &common.Address{}, big.NewInt(0), nil, 0) assert.NoError(t, err) // bump the basefee by 10x s.baseFeePerGas *= 10 // resubmit and check that the gas fee has been adjusted accordingly - newTx, err := s.resubmitTransaction(feeData, auth, tx) + newTx, err := s.resubmitTransaction(feeData, s.auth, tx) assert.NoError(t, err) escalateMultipleNum := new(big.Int).SetUint64(s.config.EscalateMultipleNum) @@ -196,14 +186,13 @@ func testCheckPendingTransaction(t *testing.T) { for _, txType := range txTypes { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKeys) + s, err := NewSender(context.Background(), &cfgCopy, privateKey) assert.NoError(t, err) header := &types.Header{Number: big.NewInt(100), BaseFee: big.NewInt(100)} confirmed := uint64(100) receipt := &types.Receipt{Status: types.ReceiptStatusSuccessful, BlockNumber: big.NewInt(90)} - auth := s.auths.getAccount() - tx := types.NewTransaction(auth.Nonce.Uint64(), common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil) + tx := types.NewTransaction(s.auth.Nonce.Uint64(), common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil) testCases := []struct { name string @@ -280,66 +269,3 @@ func testCheckPendingTransaction(t *testing.T) { s.Stop() } } - -func testBatchSender(t *testing.T, batchSize int) { - for _, txType := range txTypes { - for len(privateKeys) < batchSize { - priv, err := crypto.GenerateKey() - assert.NoError(t, err) - privateKeys = append(privateKeys, priv) - } - - cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig - cfgCopy.Confirmations = rpc.LatestBlockNumber - cfgCopy.PendingLimit = batchSize * TXBatch - cfgCopy.TxType = txType - newSender, err := NewSender(context.Background(), &cfgCopy, privateKeys) - assert.NoError(t, err) - - // send transactions - var ( - eg errgroup.Group - idCache = cmap.New() - confirmCh = newSender.ConfirmChan() - ) - for idx := 0; idx < newSender.NumberOfAccounts(); idx++ { - index := idx - eg.Go(func() error { - for i := 0; i < TXBatch; i++ { - toAddr := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d") - id := strconv.Itoa(i + index*1000) - _, err := newSender.SendTransaction(id, &toAddr, big.NewInt(1), nil, 0) - if errors.Is(err, ErrNoAvailableAccount) || errors.Is(err, ErrFullPending) { - <-time.After(time.Second) - continue - } - assert.NoError(t, err) - idCache.Set(id, struct{}{}) - } - return nil - }) - } - assert.NoError(t, eg.Wait()) - t.Logf("successful send batch txs, batch size: %d, total count: %d", newSender.NumberOfAccounts(), TXBatch*newSender.NumberOfAccounts()) - - // avoid 10 mins cause testcase panic - after := time.After(80 * time.Second) - isDone := false - for !isDone { - select { - case cmsg := <-confirmCh: - assert.Equal(t, true, cmsg.IsSuccessful) - _, exist := idCache.Pop(cmsg.ID) - assert.Equal(t, true, exist) - // Receive all confirmed txs. - if idCache.Count() == 0 { - isDone = true - } - case <-after: - t.Error("newSender test failed because of timeout") - isDone = true - } - } - newSender.Stop() - } -} diff --git a/bridge/internal/controller/watcher/l2_watcher_test.go b/bridge/internal/controller/watcher/l2_watcher_test.go index 8444cdb73..523566dde 100644 --- a/bridge/internal/controller/watcher/l2_watcher_test.go +++ b/bridge/internal/controller/watcher/l2_watcher_test.go @@ -50,7 +50,7 @@ func testCreateNewWatcherAndStop(t *testing.T) { l1cfg := cfg.L1Config l1cfg.RelayerConfig.SenderConfig.Confirmations = rpc.LatestBlockNumber - newSender, err := sender.NewSender(context.Background(), l1cfg.RelayerConfig.SenderConfig, l1cfg.RelayerConfig.MessageSenderPrivateKeys) + newSender, err := sender.NewSender(context.Background(), l1cfg.RelayerConfig.SenderConfig, l1cfg.RelayerConfig.MessageSenderPrivateKey) assert.NoError(t, err) // Create several transactions and commit to block @@ -71,7 +71,7 @@ func testFetchRunningMissingBlocks(t *testing.T) { _, db := setupL2Watcher(t) defer database.CloseDB(db) - auth := prepareAuth(t, l2Cli, cfg.L2Config.RelayerConfig.MessageSenderPrivateKeys[0]) + auth := prepareAuth(t, l2Cli, cfg.L2Config.RelayerConfig.MessageSenderPrivateKey) // deploy mock bridge _, tx, _, err := mock_bridge.DeployMockBridgeL2(auth, l2Cli) diff --git a/bridge/tests/bridge_test.go b/bridge/tests/bridge_test.go index b6ba14170..dc24d4e3e 100644 --- a/bridge/tests/bridge_test.go +++ b/bridge/tests/bridge_test.go @@ -83,10 +83,10 @@ func setupEnv(t *testing.T) { l2Cfg.Confirmations = 0 l2Cfg.RelayerConfig.SenderConfig.Confirmations = 0 - l1Auth, err = bind.NewKeyedTransactorWithChainID(bridgeApp.Config.L2Config.RelayerConfig.MessageSenderPrivateKeys[0], base.L1gethImg.ChainID()) + l1Auth, err = bind.NewKeyedTransactorWithChainID(bridgeApp.Config.L2Config.RelayerConfig.MessageSenderPrivateKey, base.L1gethImg.ChainID()) assert.NoError(t, err) - l2Auth, err = bind.NewKeyedTransactorWithChainID(bridgeApp.Config.L1Config.RelayerConfig.MessageSenderPrivateKeys[0], base.L2gethImg.ChainID()) + l2Auth, err = bind.NewKeyedTransactorWithChainID(bridgeApp.Config.L1Config.RelayerConfig.MessageSenderPrivateKey, base.L2gethImg.ChainID()) assert.NoError(t, err) } diff --git a/common/docker/l1geth/genesis.json b/common/docker/l1geth/genesis.json index a919e723a..894b31df0 100644 --- a/common/docker/l1geth/genesis.json +++ b/common/docker/l1geth/genesis.json @@ -35,6 +35,9 @@ "1e32abcfe6db15c1570709e3fc02725335f50a47": { "balance": "0x200000000000000000000000000000000000000000000000000000000000000" }, + "33e0F539E31B35170FAaA062af703b76a8282bf7": { + "balance": "0x200000000000000000000000000000000000000000000000000000000000000" + }, "7363726f6c6c6c20000000000000000000000014": { "code": "0x608060405234801561001057600080fd5b50600436106100f55760003560e01c806340c10f19116100975780639dc29fac116100665780639dc29fac14610286578063a457c2d7146102a2578063a9059cbb146102d2578063dd62ed3e14610302576100f5565b806340c10f191461020057806356189cb41461021c57806370a082311461023857806395d89b4114610268576100f5565b8063222f5be0116100d3578063222f5be01461016657806323b872dd14610182578063313ce567146101b257806339509351146101d0576100f5565b806306fdde03146100fa578063095ea7b31461011857806318160ddd14610148575b600080fd5b610102610332565b60405161010f9190610f27565b60405180910390f35b610132600480360381019061012d9190610fe2565b6103c4565b60405161013f919061103d565b60405180910390f35b6101506103e7565b60405161015d9190611067565b60405180910390f35b610180600480360381019061017b9190611082565b6103f1565b005b61019c60048036038101906101979190611082565b610401565b6040516101a9919061103d565b60405180910390f35b6101ba610430565b6040516101c791906110f1565b60405180910390f35b6101ea60048036038101906101e59190610fe2565b610439565b6040516101f7919061103d565b60405180910390f35b61021a60048036038101906102159190610fe2565b610470565b005b61023660048036038101906102319190611082565b61047e565b005b610252600480360381019061024d919061110c565b61048e565b60405161025f9190611067565b60405180910390f35b6102706104d6565b60405161027d9190610f27565b60405180910390f35b6102a0600480360381019061029b9190610fe2565b610568565b005b6102bc60048036038101906102b79190610fe2565b610576565b6040516102c9919061103d565b60405180910390f35b6102ec60048036038101906102e79190610fe2565b6105ed565b6040516102f9919061103d565b60405180910390f35b61031c60048036038101906103179190611139565b610610565b6040516103299190611067565b60405180910390f35b606060038054610341906111a8565b80601f016020809104026020016040519081016040528092919081815260200182805461036d906111a8565b80156103ba5780601f1061038f576101008083540402835291602001916103ba565b820191906000526020600020905b81548152906001019060200180831161039d57829003601f168201915b5050505050905090565b6000806103cf610697565b90506103dc81858561069f565b600191505092915050565b6000600254905090565b6103fc838383610868565b505050565b60008061040c610697565b9050610419858285610ade565b610424858585610868565b60019150509392505050565b60006012905090565b600080610444610697565b90506104658185856104568589610610565b6104609190611208565b61069f565b600191505092915050565b61047a8282610b6a565b5050565b61048983838361069f565b505050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6060600480546104e5906111a8565b80601f0160208091040260200160405190810160405280929190818152602001828054610511906111a8565b801561055e5780601f106105335761010080835404028352916020019161055e565b820191906000526020600020905b81548152906001019060200180831161054157829003601f168201915b5050505050905090565b6105728282610cc0565b5050565b600080610581610697565b9050600061058f8286610610565b9050838110156105d4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105cb906112ae565b60405180910390fd5b6105e1828686840361069f565b60019250505092915050565b6000806105f8610697565b9050610605818585610868565b600191505092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361070e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161070590611340565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361077d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610774906113d2565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360405161085b9190611067565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108ce90611464565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610946576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093d906114f6565b60405180910390fd5b610951838383610e8d565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156109d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ce90611588565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610ac59190611067565b60405180910390a3610ad8848484610e92565b50505050565b6000610aea8484610610565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610b645781811015610b56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b4d906115f4565b60405180910390fd5b610b63848484840361069f565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610bd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bd090611660565b60405180910390fd5b610be560008383610e8d565b8060026000828254610bf79190611208565b92505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610ca89190611067565b60405180910390a3610cbc60008383610e92565b5050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610d2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d26906116f2565b60405180910390fd5b610d3b82600083610e8d565b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015610dc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610db890611784565b60405180910390fd5b8181036000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610e749190611067565b60405180910390a3610e8883600084610e92565b505050565b505050565b505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610ed1578082015181840152602081019050610eb6565b60008484015250505050565b6000601f19601f8301169050919050565b6000610ef982610e97565b610f038185610ea2565b9350610f13818560208601610eb3565b610f1c81610edd565b840191505092915050565b60006020820190508181036000830152610f418184610eee565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610f7982610f4e565b9050919050565b610f8981610f6e565b8114610f9457600080fd5b50565b600081359050610fa681610f80565b92915050565b6000819050919050565b610fbf81610fac565b8114610fca57600080fd5b50565b600081359050610fdc81610fb6565b92915050565b60008060408385031215610ff957610ff8610f49565b5b600061100785828601610f97565b925050602061101885828601610fcd565b9150509250929050565b60008115159050919050565b61103781611022565b82525050565b6000602082019050611052600083018461102e565b92915050565b61106181610fac565b82525050565b600060208201905061107c6000830184611058565b92915050565b60008060006060848603121561109b5761109a610f49565b5b60006110a986828701610f97565b93505060206110ba86828701610f97565b92505060406110cb86828701610fcd565b9150509250925092565b600060ff82169050919050565b6110eb816110d5565b82525050565b600060208201905061110660008301846110e2565b92915050565b60006020828403121561112257611121610f49565b5b600061113084828501610f97565b91505092915050565b600080604083850312156111505761114f610f49565b5b600061115e85828601610f97565b925050602061116f85828601610f97565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806111c057607f821691505b6020821081036111d3576111d2611179565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061121382610fac565b915061121e83610fac565b9250828201905080821115611236576112356111d9565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000611298602583610ea2565b91506112a38261123c565b604082019050919050565b600060208201905081810360008301526112c78161128b565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b600061132a602483610ea2565b9150611335826112ce565b604082019050919050565b600060208201905081810360008301526113598161131d565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b60006113bc602283610ea2565b91506113c782611360565b604082019050919050565b600060208201905081810360008301526113eb816113af565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b600061144e602583610ea2565b9150611459826113f2565b604082019050919050565b6000602082019050818103600083015261147d81611441565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b60006114e0602383610ea2565b91506114eb82611484565b604082019050919050565b6000602082019050818103600083015261150f816114d3565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b6000611572602683610ea2565b915061157d82611516565b604082019050919050565b600060208201905081810360008301526115a181611565565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b60006115de601d83610ea2565b91506115e9826115a8565b602082019050919050565b6000602082019050818103600083015261160d816115d1565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b600061164a601f83610ea2565b915061165582611614565b602082019050919050565b600060208201905081810360008301526116798161163d565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b60006116dc602183610ea2565b91506116e782611680565b604082019050919050565b6000602082019050818103600083015261170b816116cf565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b600061176e602283610ea2565b915061177982611712565b604082019050919050565b6000602082019050818103600083015261179d81611761565b905091905056fea26469706673582212206a0466cc8279c36801cc7618e809890da047e4518cddd96836b2e2250be5535764736f6c63430008100033", "storage": { diff --git a/common/version/version.go b/common/version/version.go index 5ded11f78..6efd634fc 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -6,7 +6,7 @@ import ( "strings" ) -var tag = "v4.1.34" +var tag = "v4.1.35" var commit = func() string { if info, ok := debug.ReadBuildInfo(); ok { diff --git a/tests/integration-test/contracts_test.go b/tests/integration-test/contracts_test.go index d1ba0d85f..9e227af8c 100644 --- a/tests/integration-test/contracts_test.go +++ b/tests/integration-test/contracts_test.go @@ -26,7 +26,7 @@ func TestERC20(t *testing.T) { token, err := erc20.NewERC20Mock(erc20Address, l2Cli) assert.NoError(t, err) - auth, err := bind.NewKeyedTransactorWithChainID(bridgeApp.Config.L2Config.RelayerConfig.MessageSenderPrivateKeys[0], base.L2gethImg.ChainID()) + auth, err := bind.NewKeyedTransactorWithChainID(bridgeApp.Config.L2Config.RelayerConfig.MessageSenderPrivateKey, base.L2gethImg.ChainID()) assert.NoError(t, err) authBls0, err := token.BalanceOf(nil, auth.From) @@ -57,7 +57,7 @@ func TestGreeter(t *testing.T) { l2Cli, err := base.L2Client() assert.Nil(t, err) - auth, err := bind.NewKeyedTransactorWithChainID(bridgeApp.Config.L2Config.RelayerConfig.MessageSenderPrivateKeys[0], base.L2gethImg.ChainID()) + auth, err := bind.NewKeyedTransactorWithChainID(bridgeApp.Config.L2Config.RelayerConfig.MessageSenderPrivateKey, base.L2gethImg.ChainID()) assert.NoError(t, err) token, err := greeter.NewGreeter(greeterAddress, l2Cli)