From 7a4ab5efff1c91c3aabef9a42504144f69cb327d Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Thu, 26 Sep 2024 13:53:53 +0200 Subject: [PATCH 01/16] support web3signer and make signing configurable (privte key or remote signer) --- rollup/conf/config.json | 23 ++- rollup/internal/config/config_test.go | 24 +-- rollup/internal/config/relayer.go | 17 +- .../internal/controller/relayer/l1_relayer.go | 12 +- .../internal/controller/relayer/l2_relayer.go | 54 +------ .../internal/controller/sender/estimategas.go | 10 +- rollup/internal/controller/sender/sender.go | 78 ++++----- .../internal/controller/sender/sender_test.go | 47 +++--- .../controller/sender/transaction_signer.go | 152 ++++++++++++++++++ 9 files changed, 275 insertions(+), 142 deletions(-) create mode 100644 rollup/internal/controller/sender/transaction_signer.go diff --git a/rollup/conf/config.json b/rollup/conf/config.json index 457e42fe5..8b3574ac9 100644 --- a/rollup/conf/config.json +++ b/rollup/conf/config.json @@ -24,7 +24,11 @@ "l1_base_fee_default": 15000000000, "l1_blob_base_fee_default": 1 }, - "gas_oracle_sender_private_key": "1313131313131313131313131313131313131313131313131313131313131313" + "gas_oracle_sender_signer_config": { + "signer_type": "RemoteSigner", + "remoteSignerUrl": "http://127.0.0.1:9000", + "signer_address": "0x03a1Bba60B5Aa37094cf16123AdD674c01589488" + } } }, "l2_config": { @@ -60,9 +64,20 @@ "enable_test_env_bypass_features": true, "finalize_batch_without_proof_timeout_sec": 7200, "finalize_bundle_without_proof_timeout_sec": 7200, - "gas_oracle_sender_private_key": "1313131313131313131313131313131313131313131313131313131313131313", - "commit_sender_private_key": "1414141414141414141414141414141414141414141414141414141414141414", - "finalize_sender_private_key": "1515151515151515151515151515151515151515151515151515151515151515", + "gas_oracle_sender_signer_config": { + "signer_type": "RemoteSigner", + "remoteSignerUrl": "http://127.0.0.1:9000", + "signer_address": "0x03a1Bba60B5Aa37094cf16123AdD674c01589488" + }, + "commit_sender_signer_config": { + "signer_type": "PrivateKey", + "private_key": "1414141414141414141414141414141414141414141414141414141414141414" + }, + "finalize_sender_signer_config": { + "signer_type": "RemoteSigner", + "remoteSignerUrl": "http://127.0.0.1:9000", + "signer_address": "0x33e0F539E31B35170FAaA062af703b76a8282bf7" + }, "l1_commit_gas_limit_multiplier": 1.2 }, "chunk_proposer_config": { diff --git a/rollup/internal/config/config_test.go b/rollup/internal/config/config_test.go index 585a4e5c9..accc32440 100644 --- a/rollup/internal/config/config_test.go +++ b/rollup/internal/config/config_test.go @@ -61,24 +61,24 @@ func TestConfig(t *testing.T) { assert.NoError(t, err) os.Setenv("SCROLL_ROLLUP_DB_CONFIG_DSN", "postgres://test:test@postgresql:5432/scroll?sslmode=disable") - os.Setenv("SCROLL_ROLLUP_L1_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_PRIVATE_KEY", "1616161616161616161616161616161616161616161616161616161616161616") - os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_PRIVATE_KEY", "1717171717171717171717171717171717171717171717171717171717171717") - os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_COMMIT_SENDER_PRIVATE_KEY", "1818181818181818181818181818181818181818181818181818181818181818") - os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_FINALIZE_SENDER_PRIVATE_KEY", "1919191919191919191919191919191919191919191919191919191919191919") + os.Setenv("SCROLL_ROLLUP_L1_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_SIGNER_CONFIG_SIGNER_ADDRESS", "0x03a1Bba60B5Aa37094cf16123AdD674c01589489") + os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_SIGNER_CONFIG_SIGNER_ADDRESS", "0x03a1Bba60B5Aa37094cf16123AdD674c01589480") + os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_COMMIT_SENDER_SIGNER_CONFIG_PRIVATE_KEY", "1818181818181818181818181818181818181818181818181818181818181818") + os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_FINALIZE_SENDER_SIGNER_CONFIG_SIGNER_ADDRESS", "0x33e0F539E31B35170FAaA062af703b76a8282bf8") cfg2, err := NewConfig("../../conf/config.json") assert.NoError(t, err) assert.NotEqual(t, cfg.DBConfig.DSN, cfg2.DBConfig.DSN) - assert.NotEqual(t, cfg.L1Config.RelayerConfig.GasOracleSenderPrivateKey, cfg2.L1Config.RelayerConfig.GasOracleSenderPrivateKey) - assert.NotEqual(t, cfg.L2Config.RelayerConfig.GasOracleSenderPrivateKey, cfg2.L2Config.RelayerConfig.GasOracleSenderPrivateKey) - assert.NotEqual(t, cfg.L2Config.RelayerConfig.CommitSenderPrivateKey, cfg2.L2Config.RelayerConfig.CommitSenderPrivateKey) - assert.NotEqual(t, cfg.L2Config.RelayerConfig.FinalizeSenderPrivateKey, cfg2.L2Config.RelayerConfig.FinalizeSenderPrivateKey) + assert.NotEqual(t, cfg.L1Config.RelayerConfig.GasOracleSenderSignerConfig, cfg2.L1Config.RelayerConfig.GasOracleSenderSignerConfig) + assert.NotEqual(t, cfg.L2Config.RelayerConfig.GasOracleSenderSignerConfig, cfg2.L2Config.RelayerConfig.GasOracleSenderSignerConfig) + assert.NotEqual(t, cfg.L2Config.RelayerConfig.CommitSenderSignerConfig, cfg2.L2Config.RelayerConfig.CommitSenderSignerConfig) + assert.NotEqual(t, cfg.L2Config.RelayerConfig.FinalizeSenderSignerConfig, cfg2.L2Config.RelayerConfig.FinalizeSenderSignerConfig) assert.Equal(t, cfg2.DBConfig.DSN, "postgres://test:test@postgresql:5432/scroll?sslmode=disable") - assert.Equal(t, "1616161616161616161616161616161616161616161616161616161616161616", cfg2.L1Config.RelayerConfig.GasOracleSenderPrivateKey) - assert.Equal(t, "1717171717171717171717171717171717171717171717171717171717171717", cfg2.L2Config.RelayerConfig.GasOracleSenderPrivateKey) - assert.Equal(t, "1818181818181818181818181818181818181818181818181818181818181818", cfg2.L2Config.RelayerConfig.CommitSenderPrivateKey) - assert.Equal(t, "1919191919191919191919191919191919191919191919191919191919191919", cfg2.L2Config.RelayerConfig.FinalizeSenderPrivateKey) + assert.Equal(t, "0x03a1Bba60B5Aa37094cf16123AdD674c01589489", cfg2.L1Config.RelayerConfig.GasOracleSenderSignerConfig.SignerAddress) + assert.Equal(t, "0x03a1Bba60B5Aa37094cf16123AdD674c01589480", cfg2.L2Config.RelayerConfig.GasOracleSenderSignerConfig.SignerAddress) + assert.Equal(t, "1818181818181818181818181818181818181818181818181818181818181818", cfg2.L2Config.RelayerConfig.CommitSenderSignerConfig.PrivateKey) + assert.Equal(t, "0x33e0F539E31B35170FAaA062af703b76a8282bf8", cfg2.L2Config.RelayerConfig.FinalizeSenderSignerConfig.SignerAddress) }) } diff --git a/rollup/internal/config/relayer.go b/rollup/internal/config/relayer.go index 02f828ba8..fe776ebf2 100644 --- a/rollup/internal/config/relayer.go +++ b/rollup/internal/config/relayer.go @@ -54,10 +54,11 @@ type RelayerConfig struct { ChainMonitor *ChainMonitor `json:"chain_monitor"` // L1CommitGasLimitMultiplier multiplier for fallback gas limit in commitBatch txs L1CommitGasLimitMultiplier float64 `json:"l1_commit_gas_limit_multiplier,omitempty"` - // The private key of the relayer - GasOracleSenderPrivateKey string `json:"gas_oracle_sender_private_key"` - CommitSenderPrivateKey string `json:"commit_sender_private_key"` - FinalizeSenderPrivateKey string `json:"finalize_sender_private_key"` + + // Configs of transaction signers (GasOracle, Commit, Finalize) + GasOracleSenderSignerConfig *SignerConfig `json:"gas_oracle_sender_signer_config"` + CommitSenderSignerConfig *SignerConfig `json:"commit_sender_signer_config"` + FinalizeSenderSignerConfig *SignerConfig `json:"finalize_sender_signer_config"` // Indicates if bypass features specific to testing environments are enabled. EnableTestEnvBypassFeatures bool `json:"enable_test_env_bypass_features"` @@ -84,3 +85,11 @@ type GasOracleConfig struct { L1BaseFeeDefault uint64 `json:"l1_base_fee_default"` L1BlobBaseFeeDefault uint64 `json:"l1_blob_base_fee_default"` } + +// SignerConfig - config of signer, contains type and private_key/address,remoteUrl depending on type +type SignerConfig struct { + SignerType string `json:"signer_type"` // type of signer can be PrivateKey or RemoteSigner + PrivateKey string `json:"private_key"` // private key of signer in case of PrivateKey signerType + RemoteSignerUrl string `json:"remote_signer_url"` // remote signer url (web3signer) if case of RemoteSigner signerType + SignerAddress string `json:"signer_address"` // address of signer +} diff --git a/rollup/internal/controller/relayer/l1_relayer.go b/rollup/internal/controller/relayer/l1_relayer.go index 8dde48df6..523396bf3 100644 --- a/rollup/internal/controller/relayer/l1_relayer.go +++ b/rollup/internal/controller/relayer/l1_relayer.go @@ -10,8 +10,6 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/scroll-tech/go-ethereum/accounts/abi" - "github.com/scroll-tech/go-ethereum/common" - "github.com/scroll-tech/go-ethereum/crypto" "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/params" "gorm.io/gorm" @@ -57,15 +55,9 @@ func NewLayer1Relayer(ctx context.Context, db *gorm.DB, cfg *config.RelayerConfi switch serviceType { case ServiceTypeL1GasOracle: - pKey, err := crypto.ToECDSA(common.FromHex(cfg.GasOracleSenderPrivateKey)) + gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderSignerConfig, "l1_relayer", "gas_oracle_sender", types.SenderTypeL1GasOracle, db, reg) if err != nil { - return nil, fmt.Errorf("new gas oracle sender failed, err: %v", err) - } - - gasOracleSender, err = sender.NewSender(ctx, cfg.SenderConfig, pKey, "l1_relayer", "gas_oracle_sender", types.SenderTypeL1GasOracle, db, reg) - if err != nil { - addr := crypto.PubkeyToAddress(pKey.PublicKey) - return nil, fmt.Errorf("new gas oracle sender failed for address %s, err: %v", addr.Hex(), err) + return nil, fmt.Errorf("new gas oracle sender failed, err: %w", err) } // Ensure test features aren't enabled on the scroll mainnet. diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index d7bcfd07e..9aed24ba4 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -2,7 +2,6 @@ package relayer import ( "context" - "crypto/ecdsa" "errors" "fmt" "math/big" @@ -21,7 +20,6 @@ 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/crypto/kzg4844" "github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/log" @@ -76,18 +74,13 @@ 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, chainCfg *params.ChainConfig, initGenesis bool, serviceType ServiceType, reg prometheus.Registerer) (*Layer2Relayer, error) { - gasOracleSenderPrivateKey, commitSenderPrivateKey, finalizeSenderPrivateKey, err := parsePrivateKeys(cfg) - if err != nil { - return nil, fmt.Errorf("failed to parse private keys provided by config, err: %v", err) - } var gasOracleSender, commitSender, finalizeSender *sender.Sender switch serviceType { case ServiceTypeL2GasOracle: - gasOracleSender, err = sender.NewSender(ctx, cfg.SenderConfig, gasOracleSenderPrivateKey, "l2_relayer", "gas_oracle_sender", types.SenderTypeL2GasOracle, db, reg) + gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderSignerConfig, "l2_relayer", "gas_oracle_sender", types.SenderTypeL2GasOracle, db, reg) if err != nil { - addr := crypto.PubkeyToAddress(gasOracleSenderPrivateKey.PublicKey) - return nil, fmt.Errorf("new gas oracle sender failed for address %s, err: %w", addr.Hex(), err) + return nil, fmt.Errorf("new gas oracle sender failed, err: %w", err) } // Ensure test features aren't enabled on the ethereum mainnet. @@ -96,16 +89,14 @@ func NewLayer2Relayer(ctx context.Context, l2Client *ethclient.Client, db *gorm. } case ServiceTypeL2RollupRelayer: - commitSender, err = sender.NewSender(ctx, cfg.SenderConfig, commitSenderPrivateKey, "l2_relayer", "commit_sender", types.SenderTypeCommitBatch, db, reg) + commitSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.CommitSenderSignerConfig, "l2_relayer", "commit_sender", types.SenderTypeCommitBatch, db, reg) if err != nil { - addr := crypto.PubkeyToAddress(commitSenderPrivateKey.PublicKey) - return nil, fmt.Errorf("new commit sender failed for address %s, err: %w", addr.Hex(), err) + return nil, fmt.Errorf("new commit sender failed, err: %w", err) } - finalizeSender, err = sender.NewSender(ctx, cfg.SenderConfig, finalizeSenderPrivateKey, "l2_relayer", "finalize_sender", types.SenderTypeFinalizeBatch, db, reg) + finalizeSender, err = sender.NewSender(ctx, cfg.SenderConfig, cfg.FinalizeSenderSignerConfig, "l2_relayer", "finalize_sender", types.SenderTypeFinalizeBatch, db, reg) if err != nil { - addr := crypto.PubkeyToAddress(finalizeSenderPrivateKey.PublicKey) - return nil, fmt.Errorf("new finalize sender failed for address %s, err: %w", addr.Hex(), err) + return nil, fmt.Errorf("new finalize sender failed, err: %w", err) } // Ensure test features aren't enabled on the ethereum mainnet. @@ -1286,36 +1277,3 @@ func (r *Layer2Relayer) StopSenders() { r.finalizeSender.Stop() } } - -func parsePrivateKeys(cfg *config.RelayerConfig) (*ecdsa.PrivateKey, *ecdsa.PrivateKey, *ecdsa.PrivateKey, error) { - parseKey := func(hexKey string) (*ecdsa.PrivateKey, error) { - return crypto.ToECDSA(common.FromHex(hexKey)) - } - - gasOracleKey, err := parseKey(cfg.GasOracleSenderPrivateKey) - if err != nil { - return nil, nil, nil, fmt.Errorf("parse gas oracle sender private key failed: %w", err) - } - - commitKey, err := parseKey(cfg.CommitSenderPrivateKey) - if err != nil { - return nil, nil, nil, fmt.Errorf("parse commit sender private key failed: %w", err) - } - - finalizeKey, err := parseKey(cfg.FinalizeSenderPrivateKey) - if err != nil { - return nil, nil, nil, fmt.Errorf("parse finalize sender private key failed: %w", err) - } - - // Check if all three private keys are different - addrGasOracle := crypto.PubkeyToAddress(gasOracleKey.PublicKey) - addrCommit := crypto.PubkeyToAddress(commitKey.PublicKey) - addrFinalize := crypto.PubkeyToAddress(finalizeKey.PublicKey) - - if addrGasOracle == addrCommit || addrGasOracle == addrFinalize || addrCommit == addrFinalize { - return nil, nil, nil, fmt.Errorf("gas oracle, commit, and finalize sender addresses must be different. Got: Gas Oracle=%s, Commit=%s, Finalize=%s", - addrGasOracle.Hex(), addrCommit.Hex(), addrFinalize.Hex()) - } - - return gasOracleKey, commitKey, finalizeKey, nil -} diff --git a/rollup/internal/controller/sender/estimategas.go b/rollup/internal/controller/sender/estimategas.go index b1e368237..9d3d5b74d 100644 --- a/rollup/internal/controller/sender/estimategas.go +++ b/rollup/internal/controller/sender/estimategas.go @@ -25,8 +25,8 @@ func (s *Sender) estimateLegacyGas(to *common.Address, data []byte, fallbackGasL gasLimit, _, err := s.estimateGasLimit(to, data, nil, gasPrice, nil, nil, nil) if err != nil { - log.Error("estimateLegacyGas estimateGasLimit failure", "gas price", gasPrice, "from", s.auth.From.String(), - "nonce", s.auth.Nonce.Uint64(), "to address", to.String(), "fallback gas limit", fallbackGasLimit, "error", err) + log.Error("estimateLegacyGas estimateGasLimit failure", "gas price", gasPrice, "from", s.transactionSigner.GetAddr().String(), + "nonce", s.transactionSigner.GetNonce(), "to address", to.String(), "fallback gas limit", fallbackGasLimit, "error", err) if fallbackGasLimit == 0 { return nil, err } @@ -56,7 +56,7 @@ func (s *Sender) estimateDynamicGas(to *common.Address, data []byte, baseFee uin gasLimit, accessList, err := s.estimateGasLimit(to, data, nil, nil, gasTipCap, gasFeeCap, nil) if err != nil { log.Error("estimateDynamicGas estimateGasLimit failure", - "from", s.auth.From.String(), "nonce", s.auth.Nonce.Uint64(), "to address", to.String(), + "from", s.transactionSigner.GetAddr().String(), "nonce", s.transactionSigner.GetNonce(), "to address", to.String(), "fallback gas limit", fallbackGasLimit, "error", err) if fallbackGasLimit == 0 { return nil, err @@ -93,7 +93,7 @@ func (s *Sender) estimateBlobGas(to *common.Address, data []byte, sidecar *gethT gasLimit, accessList, err := s.estimateGasLimit(to, data, sidecar, nil, gasTipCap, gasFeeCap, blobGasFeeCap) if err != nil { log.Error("estimateBlobGas estimateGasLimit failure", - "from", s.auth.From.String(), "nonce", s.auth.Nonce.Uint64(), "to address", to.String(), + "from", s.transactionSigner.GetAddr().String(), "nonce", s.transactionSigner.GetNonce(), "to address", to.String(), "fallback gas limit", fallbackGasLimit, "error", err) if fallbackGasLimit == 0 { return nil, err @@ -117,7 +117,7 @@ func (s *Sender) estimateBlobGas(to *common.Address, data []byte, sidecar *gethT func (s *Sender) estimateGasLimit(to *common.Address, data []byte, sidecar *gethTypes.BlobTxSidecar, gasPrice, gasTipCap, gasFeeCap, blobGasFeeCap *big.Int) (uint64, *types.AccessList, error) { msg := ethereum.CallMsg{ - From: s.auth.From, + From: s.transactionSigner.GetAddr(), To: to, GasPrice: gasPrice, GasTipCap: gasTipCap, diff --git a/rollup/internal/controller/sender/sender.go b/rollup/internal/controller/sender/sender.go index 73165ab96..507ada960 100644 --- a/rollup/internal/controller/sender/sender.go +++ b/rollup/internal/controller/sender/sender.go @@ -3,7 +3,6 @@ package sender import ( "bytes" "context" - "crypto/ecdsa" "errors" "fmt" "math/big" @@ -12,7 +11,6 @@ import ( "github.com/holiman/uint256" "github.com/prometheus/client_golang/prometheus" - "github.com/scroll-tech/go-ethereum/accounts/abi/bind" "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/consensus/misc" gethTypes "github.com/scroll-tech/go-ethereum/core/types" @@ -67,16 +65,16 @@ type FeeData struct { // Sender Transaction sender to send transaction to l1/l2 geth type Sender struct { - config *config.SenderConfig - gethClient *gethclient.Client - client *ethclient.Client // The client to retrieve on chain data or send transaction. - chainID *big.Int // The chain id of the endpoint - ctx context.Context - service string - name string - senderType types.SenderType - - auth *bind.TransactOpts + config *config.SenderConfig + gethClient *gethclient.Client + client *ethclient.Client // The client to retrieve on chain data or send transaction. + rpcClient *rpc.Client + transactionSigner *TransactionSigner + chainID *big.Int // The chain id of the endpoint + ctx context.Context + service string + name string + senderType types.SenderType db *gorm.DB pendingTransactionOrm *orm.PendingTransaction @@ -88,7 +86,7 @@ type Sender struct { } // NewSender returns a new instance of transaction sender -func NewSender(ctx context.Context, config *config.SenderConfig, priv *ecdsa.PrivateKey, service, name string, senderType types.SenderType, db *gorm.DB, reg prometheus.Registerer) (*Sender, error) { +func NewSender(ctx context.Context, config *config.SenderConfig, signerConfig *config.SignerConfig, service, name string, senderType types.SenderType, db *gorm.DB, reg prometheus.Registerer) (*Sender, error) { if config.EscalateMultipleNum <= config.EscalateMultipleDen { return nil, fmt.Errorf("invalid params, EscalateMultipleNum; %v, EscalateMultipleDen: %v", config.EscalateMultipleNum, config.EscalateMultipleDen) } @@ -103,26 +101,26 @@ func NewSender(ctx context.Context, config *config.SenderConfig, priv *ecdsa.Pri if err != nil { return nil, fmt.Errorf("failed to get chain ID, err: %w", err) } - - auth, err := bind.NewKeyedTransactorWithChainID(priv, chainID) + transactionSigner, err := NewTransactionSigner(signerConfig, chainID) if err != nil { - return nil, fmt.Errorf("failed to create transactor with chain ID %v, err: %w", chainID, err) + return nil, fmt.Errorf("failed to create transaction signer, err: %w", err) } // Set pending nonce - nonce, err := client.PendingNonceAt(ctx, auth.From) + nonce, err := client.PendingNonceAt(ctx, transactionSigner.GetAddr()) if err != nil { - return nil, fmt.Errorf("failed to get pending nonce for address %s, err: %w", auth.From.Hex(), err) + return nil, fmt.Errorf("failed to get pending nonce for address %s, err: %w", transactionSigner.GetAddr(), err) } - auth.Nonce = big.NewInt(int64(nonce)) + transactionSigner.SetNonce(nonce) sender := &Sender{ ctx: ctx, config: config, gethClient: gethclient.New(rpcClient), client: client, + rpcClient: rpcClient, chainID: chainID, - auth: auth, + transactionSigner: transactionSigner, db: db, pendingTransactionOrm: orm.NewPendingTransaction(db), confirmCh: make(chan *Confirmation, 128), @@ -146,7 +144,7 @@ func (s *Sender) GetChainID() *big.Int { // Stop stop the sender module. func (s *Sender) Stop() { close(s.stopCh) - log.Info("sender stopped", "name", s.name, "service", s.service, "address", s.auth.From.String()) + log.Info("sender stopped", "name", s.name, "service", s.service, "address", s.transactionSigner.GetAddr().String()) } // ConfirmChan channel used to communicate with transaction sender @@ -217,18 +215,18 @@ func (s *Sender) SendTransaction(contextID string, target *common.Address, data if feeData, err = s.getFeeData(target, data, sidecar, baseFee, blobBaseFee, fallbackGasLimit); err != nil { s.metrics.sendTransactionFailureGetFee.WithLabelValues(s.service, s.name).Inc() - log.Error("failed to get fee data", "from", s.auth.From.String(), "nonce", s.auth.Nonce.Uint64(), "fallback gas limit", fallbackGasLimit, "err", err) + log.Error("failed to get fee data", "from", s.transactionSigner.GetAddr().String(), "nonce", s.transactionSigner.GetNonce(), "fallback gas limit", fallbackGasLimit, "err", err) return common.Hash{}, fmt.Errorf("failed to get fee data, err: %w", err) } if tx, err = s.createAndSendTx(feeData, target, data, sidecar, nil); err != nil { s.metrics.sendTransactionFailureSendTx.WithLabelValues(s.service, s.name).Inc() - log.Error("failed to create and send tx (non-resubmit case)", "from", s.auth.From.String(), "nonce", s.auth.Nonce.Uint64(), "err", err) + log.Error("failed to create and send tx (non-resubmit case)", "from", s.transactionSigner.GetAddr().String(), "nonce", s.transactionSigner.GetNonce(), "err", err) return common.Hash{}, fmt.Errorf("failed to create and send transaction, err: %w", err) } if err = s.pendingTransactionOrm.InsertPendingTransaction(s.ctx, contextID, s.getSenderMeta(), tx, blockNumber); err != nil { - log.Error("failed to insert transaction", "from", s.auth.From.String(), "nonce", s.auth.Nonce.Uint64(), "err", err) + log.Error("failed to insert transaction", "from", s.transactionSigner.GetAddr().String(), "nonce", s.transactionSigner.GetNonce(), "err", err) return common.Hash{}, fmt.Errorf("failed to insert transaction, err: %w", err) } return tx.Hash(), nil @@ -236,7 +234,7 @@ func (s *Sender) SendTransaction(contextID string, target *common.Address, data func (s *Sender) createAndSendTx(feeData *FeeData, target *common.Address, data []byte, sidecar *gethTypes.BlobTxSidecar, overrideNonce *uint64) (*gethTypes.Transaction, error) { var ( - nonce = s.auth.Nonce.Uint64() + nonce = s.transactionSigner.GetNonce() txData gethTypes.TxData ) @@ -268,7 +266,7 @@ func (s *Sender) createAndSendTx(feeData *FeeData, target *common.Address, data } } else { if target == nil { - log.Error("blob transaction to address cannot be nil", "address", s.auth.From.String(), "chainID", s.chainID.Uint64(), "nonce", s.auth.Nonce.Uint64()) + log.Error("blob transaction to address cannot be nil", "address", s.transactionSigner.GetAddr().String(), "chainID", s.chainID.Uint64(), "nonce", s.transactionSigner.GetNonce()) return nil, errors.New("blob transaction to address cannot be nil") } @@ -289,14 +287,15 @@ func (s *Sender) createAndSendTx(feeData *FeeData, target *common.Address, data } // sign and send - signedTx, err := s.auth.Signer(s.auth.From, gethTypes.NewTx(txData)) + tx := gethTypes.NewTx(txData) + signedTx, err := s.transactionSigner.SignTransaction(s.ctx, tx) if err != nil { - log.Error("failed to sign tx", "address", s.auth.From.String(), "err", err) + log.Error("failed to sign tx", "address", s.transactionSigner.GetAddr().String(), "err", err) return nil, err } if err = s.client.SendTransaction(s.ctx, signedTx); err != nil { - log.Error("failed to send tx", "tx hash", signedTx.Hash().String(), "from", s.auth.From.String(), "nonce", signedTx.Nonce(), "err", err) + log.Error("failed to send tx", "tx hash", signedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", signedTx.Nonce(), "err", err) // Check if contain nonce, and reset nonce // only reset nonce when it is not from resubmit if strings.Contains(err.Error(), "nonce too low") && overrideNonce == nil { @@ -325,19 +324,19 @@ func (s *Sender) createAndSendTx(feeData *FeeData, target *common.Address, data // update nonce when it is not from resubmit if overrideNonce == nil { - s.auth.Nonce = big.NewInt(int64(nonce + 1)) + s.transactionSigner.SetNonce(nonce + 1) } return signedTx, 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) + nonce, err := s.client.PendingNonceAt(ctx, s.transactionSigner.GetAddr()) if err != nil { - log.Warn("failed to reset nonce", "address", s.auth.From.String(), "err", err) + log.Warn("failed to reset nonce", "address", s.transactionSigner.GetAddr().String(), "err", err) return } - s.auth.Nonce = big.NewInt(int64(nonce)) + s.transactionSigner.SetNonce(nonce) } func (s *Sender) resubmitTransaction(tx *gethTypes.Transaction, baseFee, blobBaseFee uint64) (*gethTypes.Transaction, error) { @@ -349,7 +348,7 @@ func (s *Sender) resubmitTransaction(tx *gethTypes.Transaction, baseFee, blobBas txInfo := map[string]interface{}{ "tx_hash": tx.Hash().String(), "tx_type": s.config.TxType, - "from": s.auth.From.String(), + "from": s.transactionSigner.GetAddr().String(), "nonce": tx.Nonce(), } @@ -470,10 +469,11 @@ func (s *Sender) resubmitTransaction(tx *gethTypes.Transaction, baseFee, blobBas log.Info("Transaction gas adjustment details", "service", s.service, "name", s.name, "txInfo", txInfo) nonce := tx.Nonce() + tx.Hash() s.metrics.resubmitTransactionTotal.WithLabelValues(s.service, s.name).Inc() tx, err := s.createAndSendTx(&feeData, tx.To(), tx.Data(), tx.BlobTxSidecar(), &nonce) if err != nil { - log.Error("failed to create and send tx (resubmit case)", "from", s.auth.From.String(), "nonce", nonce, "err", err) + log.Error("failed to create and send tx (resubmit case)", "from", s.transactionSigner.GetAddr().String(), "nonce", nonce, "err", err) return nil, err } return tx, nil @@ -515,7 +515,7 @@ func (s *Sender) checkPendingTransaction() { err := s.db.Transaction(func(dbTX *gorm.DB) error { // Update the status of the transaction to TxStatusConfirmed. if err := s.pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(s.ctx, tx.Hash(), types.TxStatusConfirmed, dbTX); err != nil { - log.Error("failed to update transaction status by tx hash", "hash", tx.Hash().String(), "sender meta", s.getSenderMeta(), "from", s.auth.From.String(), "nonce", tx.Nonce(), "err", err) + log.Error("failed to update transaction status by tx hash", "hash", tx.Hash().String(), "sender meta", s.getSenderMeta(), "from", s.transactionSigner.GetAddr().String(), "nonce", tx.Nonce(), "err", err) return err } // Update other transactions with the same nonce and sender address as failed. @@ -572,7 +572,7 @@ func (s *Sender) checkPendingTransaction() { "service", s.service, "name", s.name, "hash", tx.Hash().String(), - "from", s.auth.From.String(), + "from", s.transactionSigner.GetAddr().String(), "nonce", tx.Nonce(), "submitBlockNumber", txnToCheck.SubmitBlockNumber, "currentBlockNumber", blockNumber, @@ -580,7 +580,7 @@ func (s *Sender) checkPendingTransaction() { if newTx, err := s.resubmitTransaction(tx, baseFee, blobBaseFee); err != nil { s.metrics.resubmitTransactionFailedTotal.WithLabelValues(s.service, s.name).Inc() - log.Error("failed to resubmit transaction", "context ID", txnToCheck.ContextID, "sender meta", s.getSenderMeta(), "from", s.auth.From.String(), "nonce", tx.Nonce(), "err", err) + log.Error("failed to resubmit transaction", "context ID", txnToCheck.ContextID, "sender meta", s.getSenderMeta(), "from", s.transactionSigner.GetAddr().String(), "nonce", tx.Nonce(), "err", err) } else { err := s.db.Transaction(func(dbTX *gorm.DB) error { // Update the status of the original transaction as replaced, while still checking its confirmation status. @@ -623,7 +623,7 @@ func (s *Sender) getSenderMeta() *orm.SenderMeta { return &orm.SenderMeta{ Name: s.name, Service: s.service, - Address: s.auth.From, + Address: s.transactionSigner.GetAddr(), Type: s.senderType, } } diff --git a/rollup/internal/controller/sender/sender_test.go b/rollup/internal/controller/sender/sender_test.go index 2d3573c32..98719513d 100644 --- a/rollup/internal/controller/sender/sender_test.go +++ b/rollup/internal/controller/sender/sender_test.go @@ -38,7 +38,9 @@ import ( ) var ( + privateKeyString string privateKey *ecdsa.PrivateKey + signerConfig *config.SignerConfig cfg *config.Config testApps *testcontainers.TestcontainerApps txTypes = []string{"LegacyTx", "DynamicFeeTx", "DynamicFeeTx"} @@ -65,7 +67,12 @@ func setupEnv(t *testing.T) { var err error cfg, err = config.NewConfig("../../../conf/config.json") assert.NoError(t, err) - priv, err := crypto.HexToECDSA("1212121212121212121212121212121212121212121212121212121212121212") + privateKeyString = "1212121212121212121212121212121212121212121212121212121212121212" + signerConfig = &config.SignerConfig{ + SignerType: "PrivateKey", + PrivateKey: privateKeyString, + } + priv, err := crypto.HexToECDSA(privateKeyString) assert.NoError(t, err) privateKey = priv @@ -148,7 +155,7 @@ func testNewSender(t *testing.T) { // exit by Stop() cfgCopy1 := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy1.TxType = txType - newSender1, err := NewSender(context.Background(), &cfgCopy1, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + newSender1, err := NewSender(context.Background(), &cfgCopy1, signerConfig, "test", "test", types.SenderTypeUnknown, db, nil) assert.NoError(t, err) newSender1.Stop() @@ -156,7 +163,7 @@ func testNewSender(t *testing.T) { cfgCopy2 := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy2.TxType = txType subCtx, cancel := context.WithCancel(context.Background()) - _, err = NewSender(subCtx, &cfgCopy2, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + _, err = NewSender(subCtx, &cfgCopy2, signerConfig, "test", "test", types.SenderTypeUnknown, db, nil) assert.NoError(t, err) cancel() } @@ -170,7 +177,7 @@ func testSendAndRetrieveTransaction(t *testing.T) { cfgCopy := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeUnknown, db, nil) assert.NoError(t, err) hash, err := s.SendTransaction("0", &common.Address{}, nil, txBlob[i], 0) @@ -206,7 +213,7 @@ func testFallbackGasLimit(t *testing.T) { cfgCopy := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType cfgCopy.Confirmations = rpc.LatestBlockNumber - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeUnknown, db, nil) assert.NoError(t, err) client, err := ethclient.Dial(cfgCopy.Endpoint) @@ -262,7 +269,7 @@ func testResubmitZeroGasPriceTransaction(t *testing.T) { cfgCopy := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeUnknown, db, nil) assert.NoError(t, err) feeData := &FeeData{ gasPrice: big.NewInt(0), @@ -302,7 +309,7 @@ func testAccessListTransactionGasLimit(t *testing.T) { cfgCopy := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeUnknown, db, nil) assert.NoError(t, err) l2GasOracleABI, err := bridgeAbi.L2GasPriceOracleMetaData.GetAbi() @@ -343,7 +350,7 @@ func testResubmitNonZeroGasPriceTransaction(t *testing.T) { cfgCopy.EscalateMultipleNum = 110 cfgCopy.EscalateMultipleDen = 100 cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeUnknown, db, nil) assert.NoError(t, err) feeData := &FeeData{ gasPrice: big.NewInt(1000000000), @@ -392,7 +399,7 @@ func testResubmitUnderpricedTransaction(t *testing.T) { cfgCopy.EscalateMultipleNum = 109 cfgCopy.EscalateMultipleDen = 100 cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeUnknown, db, nil) assert.NoError(t, err) feeData := &FeeData{ gasPrice: big.NewInt(1000000000), @@ -429,7 +436,7 @@ func testResubmitDynamicFeeTransactionWithRisingBaseFee(t *testing.T) { cfgCopy := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeUnknown, db, nil) assert.NoError(t, err) patchGuard := gomonkey.ApplyMethodFunc(s.client, "SendTransaction", func(_ context.Context, _ *gethTypes.Transaction) error { @@ -438,7 +445,7 @@ func testResubmitDynamicFeeTransactionWithRisingBaseFee(t *testing.T) { defer patchGuard.Reset() tx := gethTypes.NewTx(&gethTypes.DynamicFeeTx{ - Nonce: s.auth.Nonce.Uint64(), + Nonce: s.transactionSigner.GetNonce(), To: &common.Address{}, Data: nil, Gas: 21000, @@ -471,7 +478,7 @@ func testResubmitBlobTransactionWithRisingBaseFeeAndBlobBaseFee(t *testing.T) { cfgCopy := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy.TxType = DynamicFeeTxType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeUnknown, db, nil) assert.NoError(t, err) patchGuard := gomonkey.ApplyMethodFunc(s.client, "SendTransaction", func(_ context.Context, _ *gethTypes.Transaction) error { @@ -483,7 +490,7 @@ func testResubmitBlobTransactionWithRisingBaseFeeAndBlobBaseFee(t *testing.T) { assert.NoError(t, err) tx := gethTypes.NewTx(&gethTypes.BlobTx{ ChainID: uint256.MustFromBig(s.chainID), - Nonce: s.auth.Nonce.Uint64(), + Nonce: s.transactionSigner.GetNonce(), GasTipCap: uint256.MustFromBig(big.NewInt(0)), GasFeeCap: uint256.MustFromBig(big.NewInt(0)), Gas: 21000, @@ -539,7 +546,7 @@ func testResubmitNonceGappedTransaction(t *testing.T) { // stop background check pending transaction cfgCopy.CheckPendingTime = math.MaxUint32 - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeUnknown, db, nil) assert.NoError(t, err) patchGuard1 := gomonkey.ApplyMethodFunc(s.client, "SendTransaction", func(_ context.Context, _ *gethTypes.Transaction) error { @@ -588,7 +595,7 @@ func testCheckPendingTransactionTxConfirmed(t *testing.T) { cfgCopy := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeCommitBatch, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeCommitBatch, db, nil) assert.NoError(t, err) patchGuard1 := gomonkey.ApplyMethodFunc(s.client, "SendTransaction", func(_ context.Context, _ *gethTypes.Transaction) error { @@ -630,7 +637,7 @@ func testCheckPendingTransactionResubmitTxConfirmed(t *testing.T) { cfgCopy := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType cfgCopy.EscalateBlocks = 0 - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeFinalizeBatch, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeFinalizeBatch, db, nil) assert.NoError(t, err) patchGuard1 := gomonkey.ApplyMethodFunc(s.client, "SendTransaction", func(_ context.Context, _ *gethTypes.Transaction) error { @@ -690,7 +697,7 @@ func testCheckPendingTransactionReplacedTxConfirmed(t *testing.T) { cfgCopy := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType cfgCopy.EscalateBlocks = 0 - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeL1GasOracle, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeL1GasOracle, db, nil) assert.NoError(t, err) patchGuard1 := gomonkey.ApplyMethodFunc(s.client, "SendTransaction", func(_ context.Context, _ *gethTypes.Transaction) error { @@ -760,7 +767,7 @@ func testCheckPendingTransactionTxMultipleTimesWithOnlyOneTxPending(t *testing.T cfgCopy := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType cfgCopy.EscalateBlocks = 0 - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeCommitBatch, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeCommitBatch, db, nil) assert.NoError(t, err) patchGuard1 := gomonkey.ApplyMethodFunc(s.client, "SendTransaction", func(_ context.Context, _ *gethTypes.Transaction) error { @@ -837,7 +844,7 @@ func testBlobTransactionWithBlobhashOpContractCall(t *testing.T) { cfgCopy := *cfg.L2Config.RelayerConfig.SenderConfig cfgCopy.TxType = DynamicFeeTxType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeL1GasOracle, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeL1GasOracle, db, nil) assert.NoError(t, err) defer s.Stop() @@ -889,7 +896,7 @@ func testSendBlobCarryingTxOverLimit(t *testing.T) { sqlDB, err := db.DB() assert.NoError(t, err) assert.NoError(t, migrate.ResetDB(sqlDB)) - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeCommitBatch, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, signerConfig, "test", "test", types.SenderTypeCommitBatch, db, nil) assert.NoError(t, err) for i := 0; i < int(cfgCopy.MaxPendingBlobTxs); i++ { diff --git a/rollup/internal/controller/sender/transaction_signer.go b/rollup/internal/controller/sender/transaction_signer.go new file mode 100644 index 000000000..3905fc019 --- /dev/null +++ b/rollup/internal/controller/sender/transaction_signer.go @@ -0,0 +1,152 @@ +package sender + +import ( + "context" + "fmt" + "math/big" + "scroll-tech/rollup/internal/config" + + "github.com/scroll-tech/go-ethereum/accounts/abi/bind" + "github.com/scroll-tech/go-ethereum/common/hexutil" + gethTypes "github.com/scroll-tech/go-ethereum/core/types" + "github.com/scroll-tech/go-ethereum/crypto" + "github.com/scroll-tech/go-ethereum/log" + + "github.com/scroll-tech/go-ethereum/common" + "github.com/scroll-tech/go-ethereum/rpc" +) + +const ( + // PrivateKeySignerType + PrivateKeySignerType = "PrivateKey" + + // RemoteSignerSignerType + RemoteSignerSignerType = "RemoteSigner" +) + +// TransactionSigner signs given transactions +type TransactionSigner struct { + config *config.SignerConfig + auth *bind.TransactOpts + rpcClient *rpc.Client + nonce uint64 + addr common.Address +} + +func NewTransactionSigner(config *config.SignerConfig, chainID *big.Int) (*TransactionSigner, error) { + switch config.SignerType { + case PrivateKeySignerType: + privKey, err := crypto.ToECDSA(common.FromHex(config.PrivateKey)) + if err != nil { + return nil, fmt.Errorf("parse sender private key failed: %w", err) + } + auth, err := bind.NewKeyedTransactorWithChainID(privKey, chainID) + if err != nil { + return nil, fmt.Errorf("failed to create transactor with chain ID %v, err: %w", chainID, err) + } + return &TransactionSigner{ + config: config, + auth: auth, + rpcClient: nil, + addr: crypto.PubkeyToAddress(privKey.PublicKey), + }, nil + case RemoteSignerSignerType: + rpcClient, err := rpc.Dial(config.RemoteSignerUrl) + if err != nil { + return nil, fmt.Errorf("failed to dial rpc client, err: %w", err) + } + return &TransactionSigner{ + config: config, + rpcClient: rpcClient, + addr: common.HexToAddress(config.SignerAddress), + }, nil + default: + return nil, fmt.Errorf("failed to create new transaction signer, unknown type: %v", config.SignerType) + } +} + +func (ts *TransactionSigner) SignTransaction(ctx context.Context, tx *gethTypes.Transaction) (*gethTypes.Transaction, error) { + switch ts.config.SignerType { + case PrivateKeySignerType: + signedTx, err := ts.auth.Signer(ts.addr, tx) + if err != nil { + log.Error("failed to sign tx", "address", ts.addr.String(), "err", err) + return nil, err + } + return signedTx, nil + case RemoteSignerSignerType: + rpcTx, err := txDataToRpcTx(&ts.addr, tx) + if err != nil { + return nil, fmt.Errorf("failed to convert txData to rpc transaction, err: %w", err) + } + var result hexutil.Bytes + err = ts.rpcClient.CallContext(ctx, &result, "eth_signTransaction", rpcTx) + if err != nil { + return nil, err + } + signedTx := new(gethTypes.Transaction) + if err := signedTx.UnmarshalBinary(result); err != nil { + return nil, err + } + return signedTx, nil + default: + // this shouldn't happen, because SignerType is checked during creation + return nil, fmt.Errorf("shouldn't happen, unknown signer type") + } +} + +func (ts *TransactionSigner) SetNonce(nonce uint64) { + if ts.config.SignerType == PrivateKeySignerType { + ts.auth.Nonce = big.NewInt(int64(nonce)) + } + ts.nonce = nonce +} + +func (ts *TransactionSigner) GetNonce() uint64 { + return ts.nonce +} + +func (ts *TransactionSigner) GetAddr() common.Address { + return ts.addr +} + +// RpcTransaction transaction that will be send through rpc to web3Signer +type RpcTransaction struct { + From *common.Address `json:"from"` + To *common.Address `json:"to"` + Gas uint64 `json:"gas"` + GasPrice *big.Int `json:"gasPrice,omitempty"` + MaxPriorityFeePerGas *big.Int `json:"MaxPriorityFeePerGas,omitempty"` + MaxFeePerGas *big.Int `json:"maxFeePerGas,omitempty"` + Nonce uint64 `json:"nonce"` + Value *big.Int `json:"value"` + Data []byte `json:"data"` +} + +func txDataToRpcTx(from *common.Address, tx *gethTypes.Transaction) (*RpcTransaction, error) { + switch tx.Type() { + case gethTypes.LegacyTxType: + return &RpcTransaction{ + From: from, + To: tx.To(), + Gas: tx.Gas(), + GasPrice: tx.GasPrice(), + Nonce: tx.Nonce(), + Value: tx.Value(), + Data: tx.Data(), + }, nil + case gethTypes.DynamicFeeTxType: + return &RpcTransaction{ + From: from, + To: tx.To(), + Gas: tx.Gas(), + MaxPriorityFeePerGas: tx.GasTipCap(), + MaxFeePerGas: tx.GasFeeCap(), + Nonce: tx.Nonce(), + Value: tx.Value(), + Data: tx.Data(), + }, nil + default: // other tx types (BlobTx) currently not supported by web3signer + return nil, fmt.Errorf("failed to convert tx to RpcTransaction, unsupported tx type, %d", tx.Type()) + } +} From f865869a30403a76036b008b7de675a1a49e8b42 Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Thu, 26 Sep 2024 16:11:50 +0200 Subject: [PATCH 02/16] add tests and docker container for web3signer --- common/testcontainers/testcontainers.go | 59 ++++++++- .../web3signerconf/keyconf.yaml | 3 + .../internal/controller/sender/sender_test.go | 3 + .../controller/sender/transaction_signer.go | 8 +- .../sender/transaction_signer_test.go | 114 ++++++++++++++++++ 5 files changed, 180 insertions(+), 7 deletions(-) create mode 100644 common/testcontainers/web3signerconf/keyconf.yaml create mode 100644 rollup/internal/controller/sender/transaction_signer_test.go diff --git a/common/testcontainers/testcontainers.go b/common/testcontainers/testcontainers.go index 3a042a9c6..7adcd6eee 100644 --- a/common/testcontainers/testcontainers.go +++ b/common/testcontainers/testcontainers.go @@ -21,9 +21,10 @@ import ( // TestcontainerApps testcontainers struct type TestcontainerApps struct { - postgresContainer *postgres.PostgresContainer - l2GethContainer *testcontainers.DockerContainer - poSL1Container compose.ComposeStack + postgresContainer *postgres.PostgresContainer + l2GethContainer *testcontainers.DockerContainer + poSL1Container compose.ComposeStack + web3SignerContainer *testcontainers.DockerContainer // common time stamp in nanoseconds. Timestamp int @@ -112,6 +113,45 @@ func (t *TestcontainerApps) StartPoSL1Container() error { return nil } +func (t *TestcontainerApps) StartWeb3SignerContainer(chainId int) error { + if t.web3SignerContainer != nil && t.web3SignerContainer.IsRunning() { + return nil + } + var ( + err error + rootDir string + ) + if rootDir, err = findProjectRootDir(); err != nil { + return fmt.Errorf("failed to find project root directory: %v", err) + } + web3SignerConfDir := filepath.Join(rootDir, "common", "testcontainers", "web3signerconf") + + req := testcontainers.ContainerRequest{ + Image: "consensys/web3signer:develop", + ExposedPorts: []string{"9000/tcp"}, + Cmd: []string{"--key-config-path", "/web3signerconf/", "eth1", "--chain-id", fmt.Sprintf("%d", chainId)}, + Files: []testcontainers.ContainerFile{ + { + HostFilePath: web3SignerConfDir, + ContainerFilePath: "/", + FileMode: 0o777, + }, + }, + WaitingFor: wait.ForLog("ready to handle signing requests"), + } + genericContainerReq := testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + } + container, err := testcontainers.GenericContainer(context.Background(), genericContainerReq) + if err != nil { + log.Printf("failed to start web3signer container: %s", err) + return err + } + t.web3SignerContainer, _ = container.(*testcontainers.DockerContainer) + return nil +} + // GetPoSL1EndPoint returns the endpoint of the running PoS L1 endpoint func (t *TestcontainerApps) GetPoSL1EndPoint() (string, error) { if t.poSL1Container == nil { @@ -153,6 +193,14 @@ func (t *TestcontainerApps) GetL2GethEndPoint() (string, error) { return endpoint, nil } +// GetL2GethEndPoint returns the endpoint of the running L2Geth container +func (t *TestcontainerApps) GetWeb3SignerEndpoint() (string, error) { + if t.web3SignerContainer == nil || !t.web3SignerContainer.IsRunning() { + return "", errors.New("web3signer is not running") + } + return t.web3SignerContainer.PortEndpoint(context.Background(), "9000/tcp", "http") +} + // GetGormDBClient returns a gorm.DB by connecting to the running postgres container func (t *TestcontainerApps) GetGormDBClient() (*gorm.DB, error) { endpoint, err := t.GetDBEndPoint() @@ -201,6 +249,11 @@ func (t *TestcontainerApps) Free() { t.poSL1Container = nil } } + if t.web3SignerContainer != nil && t.web3SignerContainer.IsRunning() { + if err := t.web3SignerContainer.Terminate(ctx); err != nil { + log.Printf("failed to stop web3signer container: %s", err) + } + } } // findProjectRootDir find project root directory diff --git a/common/testcontainers/web3signerconf/keyconf.yaml b/common/testcontainers/web3signerconf/keyconf.yaml new file mode 100644 index 000000000..1a8ec9675 --- /dev/null +++ b/common/testcontainers/web3signerconf/keyconf.yaml @@ -0,0 +1,3 @@ +type: "file-raw" +keyType: "SECP256K1" +privateKey: "0x1212121212121212121212121212121212121212121212121212121212121212" \ No newline at end of file diff --git a/rollup/internal/controller/sender/sender_test.go b/rollup/internal/controller/sender/sender_test.go index 98719513d..25e96a961 100644 --- a/rollup/internal/controller/sender/sender_test.go +++ b/rollup/internal/controller/sender/sender_test.go @@ -55,6 +55,9 @@ func TestMain(m *testing.M) { if testApps != nil { testApps.Free() } + if testAppsSignerTest != nil { + testAppsSignerTest.Free() + } }() m.Run() } diff --git a/rollup/internal/controller/sender/transaction_signer.go b/rollup/internal/controller/sender/transaction_signer.go index 3905fc019..248f434e7 100644 --- a/rollup/internal/controller/sender/transaction_signer.go +++ b/rollup/internal/controller/sender/transaction_signer.go @@ -116,11 +116,11 @@ type RpcTransaction struct { To *common.Address `json:"to"` Gas uint64 `json:"gas"` GasPrice *big.Int `json:"gasPrice,omitempty"` - MaxPriorityFeePerGas *big.Int `json:"MaxPriorityFeePerGas,omitempty"` + MaxPriorityFeePerGas *big.Int `json:"maxPriorityFeePerGas,omitempty"` MaxFeePerGas *big.Int `json:"maxFeePerGas,omitempty"` Nonce uint64 `json:"nonce"` Value *big.Int `json:"value"` - Data []byte `json:"data"` + Data string `json:"data"` } func txDataToRpcTx(from *common.Address, tx *gethTypes.Transaction) (*RpcTransaction, error) { @@ -133,7 +133,7 @@ func txDataToRpcTx(from *common.Address, tx *gethTypes.Transaction) (*RpcTransac GasPrice: tx.GasPrice(), Nonce: tx.Nonce(), Value: tx.Value(), - Data: tx.Data(), + Data: common.Bytes2Hex(tx.Data()), }, nil case gethTypes.DynamicFeeTxType: return &RpcTransaction{ @@ -144,7 +144,7 @@ func txDataToRpcTx(from *common.Address, tx *gethTypes.Transaction) (*RpcTransac MaxFeePerGas: tx.GasFeeCap(), Nonce: tx.Nonce(), Value: tx.Value(), - Data: tx.Data(), + Data: common.Bytes2Hex(tx.Data()), }, nil default: // other tx types (BlobTx) currently not supported by web3signer return nil, fmt.Errorf("failed to convert tx to RpcTransaction, unsupported tx type, %d", tx.Type()) diff --git a/rollup/internal/controller/sender/transaction_signer_test.go b/rollup/internal/controller/sender/transaction_signer_test.go new file mode 100644 index 000000000..74464db0e --- /dev/null +++ b/rollup/internal/controller/sender/transaction_signer_test.go @@ -0,0 +1,114 @@ +package sender + +import ( + "context" + "math/big" + "os" + "scroll-tech/common/testcontainers" + "scroll-tech/rollup/internal/config" + "testing" + + "github.com/holiman/uint256" + "github.com/scroll-tech/go-ethereum/common" + gethTypes "github.com/scroll-tech/go-ethereum/core/types" + "github.com/scroll-tech/go-ethereum/log" + "github.com/stretchr/testify/assert" +) + +var ( + testAppsSignerTest *testcontainers.TestcontainerApps + chainId int +) + +func setupEnvSignerTest(t *testing.T) { + glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.LogfmtFormat())) + glogger.Verbosity(log.LvlInfo) + log.Root().SetHandler(glogger) + + chainId = 1 + testAppsSignerTest = testcontainers.NewTestcontainerApps() + assert.NoError(t, testAppsSignerTest.StartWeb3SignerContainer(chainId)) +} + +func TestTransactionSigner(t *testing.T) { + setupEnvSignerTest(t) + t.Run("test both signer types", testBothSignerTypes) +} + +func testBothSignerTypes(t *testing.T) { + endpoint, err := testAppsSignerTest.GetWeb3SignerEndpoint() + assert.NoError(t, err) + + // create remote signer + remoteSignerConf := &config.SignerConfig{ + SignerType: RemoteSignerSignerType, + SignerAddress: "0x1C5A77d9FA7eF466951B2F01F724BCa3A5820b63", + RemoteSignerUrl: endpoint, + } + remoteSigner, err := NewTransactionSigner(remoteSignerConf, big.NewInt(int64(chainId))) + assert.NoError(t, err) + remoteSigner.SetNonce(2) + + // create private key signer + privateKeySignerConf := &config.SignerConfig{ + SignerType: PrivateKeySignerType, + PrivateKey: "1212121212121212121212121212121212121212121212121212121212121212", + } + privateKeySigner, err := NewTransactionSigner(privateKeySignerConf, big.NewInt(int64(chainId))) + assert.NoError(t, err) + privateKeySigner.SetNonce(2) + + assert.Equal(t, remoteSigner.GetAddr(), privateKeySigner.GetAddr()) + + to := common.BytesToAddress([]byte{0, 1, 2, 3}) + data := []byte("data") + + // check LegacyTx and DynamicFeeTx - transactions supported by web3signer + txDatas := []gethTypes.TxData{ + &gethTypes.LegacyTx{ + Nonce: remoteSigner.GetNonce(), + GasPrice: big.NewInt(1000), + Gas: 10000, + To: &to, + Data: data, + }, + &gethTypes.DynamicFeeTx{ + Nonce: remoteSigner.GetNonce(), + Gas: 10000, + To: &to, + Data: data, + ChainID: big.NewInt(int64(chainId)), + GasTipCap: big.NewInt(2000), + GasFeeCap: big.NewInt(3000), + }, + } + for _, txData := range txDatas { + tx := gethTypes.NewTx(txData) + + signedTx1, err := remoteSigner.SignTransaction(context.Background(), tx) + assert.NoError(t, err) + + signedTx2, err := privateKeySigner.SignTransaction(context.Background(), tx) + assert.NoError(t, err) + + assert.Equal(t, signedTx1.Hash(), signedTx2.Hash()) + } + + // BlobTx is not supported + txData := &gethTypes.BlobTx{ + Nonce: remoteSigner.GetNonce(), + Gas: 10000, + To: to, + Data: data, + ChainID: uint256.NewInt(1), + GasTipCap: uint256.NewInt(2000), + GasFeeCap: uint256.NewInt(3000), + BlobFeeCap: uint256.NewInt(1), + BlobHashes: []common.Hash{}, + Sidecar: nil, + } + tx := gethTypes.NewTx(txData) + + _, err = remoteSigner.SignTransaction(context.Background(), tx) + assert.Error(t, err) +} From 1eee1edc7286d5eecc239d637604b4b6893fde76 Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Thu, 26 Sep 2024 16:16:03 +0200 Subject: [PATCH 03/16] bump version --- common/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/version/version.go b/common/version/version.go index a3a2028ff..a06c232c1 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -5,7 +5,7 @@ import ( "runtime/debug" ) -var tag = "v4.4.63" +var tag = "v4.4.64" var commit = func() string { if info, ok := debug.ReadBuildInfo(); ok { From c394a26c96a00135b010e7341975ecf1a402c2bb Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Thu, 26 Sep 2024 16:16:46 +0200 Subject: [PATCH 04/16] fix lint --- rollup/internal/controller/sender/transaction_signer.go | 1 + rollup/internal/controller/sender/transaction_signer_test.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rollup/internal/controller/sender/transaction_signer.go b/rollup/internal/controller/sender/transaction_signer.go index 248f434e7..c47d1fd3c 100644 --- a/rollup/internal/controller/sender/transaction_signer.go +++ b/rollup/internal/controller/sender/transaction_signer.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math/big" + "scroll-tech/rollup/internal/config" "github.com/scroll-tech/go-ethereum/accounts/abi/bind" diff --git a/rollup/internal/controller/sender/transaction_signer_test.go b/rollup/internal/controller/sender/transaction_signer_test.go index 74464db0e..8254a541b 100644 --- a/rollup/internal/controller/sender/transaction_signer_test.go +++ b/rollup/internal/controller/sender/transaction_signer_test.go @@ -5,9 +5,10 @@ import ( "math/big" "os" "scroll-tech/common/testcontainers" - "scroll-tech/rollup/internal/config" "testing" + "scroll-tech/rollup/internal/config" + "github.com/holiman/uint256" "github.com/scroll-tech/go-ethereum/common" gethTypes "github.com/scroll-tech/go-ethereum/core/types" From dfc5c2c97747104515d1ce97cf0ff32319e012b1 Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Thu, 26 Sep 2024 16:25:26 +0200 Subject: [PATCH 05/16] fix lint --- rollup/internal/controller/relayer/l1_relayer.go | 3 ++- rollup/internal/controller/relayer/l2_relayer.go | 5 +++-- .../internal/controller/sender/transaction_signer_test.go | 6 ++++-- rollup/tests/bridge_test.go | 4 ++-- tests/integration-test/contracts_test.go | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/rollup/internal/controller/relayer/l1_relayer.go b/rollup/internal/controller/relayer/l1_relayer.go index 523396bf3..d7f857263 100644 --- a/rollup/internal/controller/relayer/l1_relayer.go +++ b/rollup/internal/controller/relayer/l1_relayer.go @@ -52,10 +52,11 @@ type Layer1Relayer struct { // NewLayer1Relayer will return a new instance of Layer1RelayerClient func NewLayer1Relayer(ctx context.Context, db *gorm.DB, cfg *config.RelayerConfig, chainCfg *params.ChainConfig, serviceType ServiceType, reg prometheus.Registerer) (*Layer1Relayer, error) { var gasOracleSender *sender.Sender + var err error switch serviceType { case ServiceTypeL1GasOracle: - gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderSignerConfig, "l1_relayer", "gas_oracle_sender", types.SenderTypeL1GasOracle, db, reg) + gasOracleSender, err = sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderSignerConfig, "l1_relayer", "gas_oracle_sender", types.SenderTypeL1GasOracle, db, reg) if err != nil { return nil, fmt.Errorf("new gas oracle sender failed, err: %w", err) } diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 9aed24ba4..371143355 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -76,9 +76,10 @@ type Layer2Relayer struct { func NewLayer2Relayer(ctx context.Context, l2Client *ethclient.Client, db *gorm.DB, cfg *config.RelayerConfig, chainCfg *params.ChainConfig, initGenesis bool, serviceType ServiceType, reg prometheus.Registerer) (*Layer2Relayer, error) { var gasOracleSender, commitSender, finalizeSender *sender.Sender + var err error switch serviceType { case ServiceTypeL2GasOracle: - gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderSignerConfig, "l2_relayer", "gas_oracle_sender", types.SenderTypeL2GasOracle, db, reg) + gasOracleSender, err = sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderSignerConfig, "l2_relayer", "gas_oracle_sender", types.SenderTypeL2GasOracle, db, reg) if err != nil { return nil, fmt.Errorf("new gas oracle sender failed, err: %w", err) } @@ -89,7 +90,7 @@ func NewLayer2Relayer(ctx context.Context, l2Client *ethclient.Client, db *gorm. } case ServiceTypeL2RollupRelayer: - commitSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.CommitSenderSignerConfig, "l2_relayer", "commit_sender", types.SenderTypeCommitBatch, db, reg) + commitSender, err = sender.NewSender(ctx, cfg.SenderConfig, cfg.CommitSenderSignerConfig, "l2_relayer", "commit_sender", types.SenderTypeCommitBatch, db, reg) if err != nil { return nil, fmt.Errorf("new commit sender failed, err: %w", err) } diff --git a/rollup/internal/controller/sender/transaction_signer_test.go b/rollup/internal/controller/sender/transaction_signer_test.go index 8254a541b..b8878f8b0 100644 --- a/rollup/internal/controller/sender/transaction_signer_test.go +++ b/rollup/internal/controller/sender/transaction_signer_test.go @@ -83,13 +83,15 @@ func testBothSignerTypes(t *testing.T) { GasFeeCap: big.NewInt(3000), }, } + var signedTx1 *gethTypes.Transaction + var signedTx2 *gethTypes.Transaction for _, txData := range txDatas { tx := gethTypes.NewTx(txData) - signedTx1, err := remoteSigner.SignTransaction(context.Background(), tx) + signedTx1, err = remoteSigner.SignTransaction(context.Background(), tx) assert.NoError(t, err) - signedTx2, err := privateKeySigner.SignTransaction(context.Background(), tx) + signedTx2, err = privateKeySigner.SignTransaction(context.Background(), tx) assert.NoError(t, err) assert.Equal(t, signedTx1.Hash(), signedTx2.Hash()) diff --git a/rollup/tests/bridge_test.go b/rollup/tests/bridge_test.go index e24edda94..fb272839b 100644 --- a/rollup/tests/bridge_test.go +++ b/rollup/tests/bridge_test.go @@ -105,12 +105,12 @@ func setupEnv(t *testing.T) { l2Cfg.Confirmations = 0 l2Cfg.RelayerConfig.SenderConfig.Confirmations = 0 - pKey, err := crypto.ToECDSA(common.FromHex(l2Cfg.RelayerConfig.CommitSenderPrivateKey)) + pKey, err := crypto.ToECDSA(common.FromHex(l2Cfg.RelayerConfig.CommitSenderSignerConfig.PrivateKey)) assert.NoError(t, err) l1Auth, err = bind.NewKeyedTransactorWithChainID(pKey, l1GethChainID) assert.NoError(t, err) - pKey, err = crypto.ToECDSA(common.FromHex(l2Cfg.RelayerConfig.GasOracleSenderPrivateKey)) + pKey, err = crypto.ToECDSA(common.FromHex(l2Cfg.RelayerConfig.GasOracleSenderSignerConfig.PrivateKey)) assert.NoError(t, err) l2Auth, err = bind.NewKeyedTransactorWithChainID(pKey, l2GethChainID) assert.NoError(t, err) diff --git a/tests/integration-test/contracts_test.go b/tests/integration-test/contracts_test.go index f1c1412c9..6d34a5b9d 100644 --- a/tests/integration-test/contracts_test.go +++ b/tests/integration-test/contracts_test.go @@ -68,7 +68,7 @@ func testGreeter(t *testing.T) { chainID, err := l2Cli.ChainID(context.Background()) assert.NoError(t, err) - pKey, err := crypto.ToECDSA(common.FromHex(rollupApp.Config.L2Config.RelayerConfig.CommitSenderPrivateKey)) + pKey, err := crypto.ToECDSA(common.FromHex(rollupApp.Config.L2Config.RelayerConfig.CommitSenderSignerConfig.PrivateKey)) assert.NoError(t, err) auth, err := bind.NewKeyedTransactorWithChainID(pKey, chainID) assert.NoError(t, err) From 419d17aa6f3151fbd5ba05e0d84d13152e5b5fcf Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Thu, 26 Sep 2024 16:28:07 +0200 Subject: [PATCH 06/16] add test for container --- common/testcontainers/testcontainers_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/common/testcontainers/testcontainers_test.go b/common/testcontainers/testcontainers_test.go index 3eceb6b44..52271fb1c 100644 --- a/common/testcontainers/testcontainers_test.go +++ b/common/testcontainers/testcontainers_test.go @@ -44,6 +44,11 @@ func TestNewTestcontainerApps(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, ethclient) + assert.NoError(t, testApps.StartWeb3SignerContainer(1)) + endpoint, err = testApps.GetWeb3SignerEndpoint() + assert.NoError(t, err) + assert.NotEmpty(t, endpoint) + // test free testcontainers testApps.Free() endpoint, err = testApps.GetDBEndPoint() @@ -57,4 +62,8 @@ func TestNewTestcontainerApps(t *testing.T) { endpoint, err = testApps.GetPoSL1EndPoint() assert.EqualError(t, err, "PoS L1 container is not running") assert.Empty(t, endpoint) + + endpoint, err = testApps.GetWeb3SignerEndpoint() + assert.EqualError(t, err, "web3signer is not running") + assert.Empty(t, endpoint) } From 1a4788558160792573c17a7fd25b79f44315141b Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Thu, 26 Sep 2024 16:31:46 +0200 Subject: [PATCH 07/16] fix test --- rollup/tests/bridge_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollup/tests/bridge_test.go b/rollup/tests/bridge_test.go index fb272839b..f4e6ea8bc 100644 --- a/rollup/tests/bridge_test.go +++ b/rollup/tests/bridge_test.go @@ -110,7 +110,7 @@ func setupEnv(t *testing.T) { l1Auth, err = bind.NewKeyedTransactorWithChainID(pKey, l1GethChainID) assert.NoError(t, err) - pKey, err = crypto.ToECDSA(common.FromHex(l2Cfg.RelayerConfig.GasOracleSenderSignerConfig.PrivateKey)) + pKey, err = crypto.ToECDSA(common.FromHex("1313131313131313131313131313131313131313131313131313131313131313")) assert.NoError(t, err) l2Auth, err = bind.NewKeyedTransactorWithChainID(pKey, l2GethChainID) assert.NoError(t, err) From b4faf72754a770283ed5f6191a5eebe92f12dcbd Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Thu, 26 Sep 2024 16:37:29 +0200 Subject: [PATCH 08/16] cleanup --- rollup/internal/controller/sender/sender.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/rollup/internal/controller/sender/sender.go b/rollup/internal/controller/sender/sender.go index 507ada960..035186ce1 100644 --- a/rollup/internal/controller/sender/sender.go +++ b/rollup/internal/controller/sender/sender.go @@ -68,7 +68,6 @@ type Sender struct { config *config.SenderConfig gethClient *gethclient.Client client *ethclient.Client // The client to retrieve on chain data or send transaction. - rpcClient *rpc.Client transactionSigner *TransactionSigner chainID *big.Int // The chain id of the endpoint ctx context.Context @@ -118,7 +117,6 @@ func NewSender(ctx context.Context, config *config.SenderConfig, signerConfig *c config: config, gethClient: gethclient.New(rpcClient), client: client, - rpcClient: rpcClient, chainID: chainID, transactionSigner: transactionSigner, db: db, From bfb38d7c97fe09c963d818a55838453fddbef025 Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Thu, 26 Sep 2024 16:44:00 +0200 Subject: [PATCH 09/16] change config to use private key in testing --- rollup/conf/config.json | 15 ++++++--------- rollup/tests/bridge_test.go | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/rollup/conf/config.json b/rollup/conf/config.json index 8b3574ac9..7cd783f58 100644 --- a/rollup/conf/config.json +++ b/rollup/conf/config.json @@ -25,9 +25,8 @@ "l1_blob_base_fee_default": 1 }, "gas_oracle_sender_signer_config": { - "signer_type": "RemoteSigner", - "remoteSignerUrl": "http://127.0.0.1:9000", - "signer_address": "0x03a1Bba60B5Aa37094cf16123AdD674c01589488" + "signer_type": "PrivateKey", + "private_key": "1313131313131313131313131313131313131313131313131313131313131313" } } }, @@ -65,18 +64,16 @@ "finalize_batch_without_proof_timeout_sec": 7200, "finalize_bundle_without_proof_timeout_sec": 7200, "gas_oracle_sender_signer_config": { - "signer_type": "RemoteSigner", - "remoteSignerUrl": "http://127.0.0.1:9000", - "signer_address": "0x03a1Bba60B5Aa37094cf16123AdD674c01589488" + "signer_type": "PrivateKey", + "private_key": "1313131313131313131313131313131313131313131313131313131313131313" }, "commit_sender_signer_config": { "signer_type": "PrivateKey", "private_key": "1414141414141414141414141414141414141414141414141414141414141414" }, "finalize_sender_signer_config": { - "signer_type": "RemoteSigner", - "remoteSignerUrl": "http://127.0.0.1:9000", - "signer_address": "0x33e0F539E31B35170FAaA062af703b76a8282bf7" + "signer_type": "PrivateKey", + "private_key": "1515151515151515151515151515151515151515151515151515151515151515" }, "l1_commit_gas_limit_multiplier": 1.2 }, diff --git a/rollup/tests/bridge_test.go b/rollup/tests/bridge_test.go index f4e6ea8bc..fb272839b 100644 --- a/rollup/tests/bridge_test.go +++ b/rollup/tests/bridge_test.go @@ -110,7 +110,7 @@ func setupEnv(t *testing.T) { l1Auth, err = bind.NewKeyedTransactorWithChainID(pKey, l1GethChainID) assert.NoError(t, err) - pKey, err = crypto.ToECDSA(common.FromHex("1313131313131313131313131313131313131313131313131313131313131313")) + pKey, err = crypto.ToECDSA(common.FromHex(l2Cfg.RelayerConfig.GasOracleSenderSignerConfig.PrivateKey)) assert.NoError(t, err) l2Auth, err = bind.NewKeyedTransactorWithChainID(pKey, l2GethChainID) assert.NoError(t, err) From 7b6d97d5c9eea9f0377b8ca499013a00e60d191d Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Thu, 26 Sep 2024 17:07:10 +0200 Subject: [PATCH 10/16] fix confi test --- rollup/internal/config/config_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rollup/internal/config/config_test.go b/rollup/internal/config/config_test.go index accc32440..8a49a4053 100644 --- a/rollup/internal/config/config_test.go +++ b/rollup/internal/config/config_test.go @@ -61,10 +61,10 @@ func TestConfig(t *testing.T) { assert.NoError(t, err) os.Setenv("SCROLL_ROLLUP_DB_CONFIG_DSN", "postgres://test:test@postgresql:5432/scroll?sslmode=disable") - os.Setenv("SCROLL_ROLLUP_L1_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_SIGNER_CONFIG_SIGNER_ADDRESS", "0x03a1Bba60B5Aa37094cf16123AdD674c01589489") - os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_SIGNER_CONFIG_SIGNER_ADDRESS", "0x03a1Bba60B5Aa37094cf16123AdD674c01589480") + os.Setenv("SCROLL_ROLLUP_L1_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_SIGNER_CONFIG_PRIVATE_KEY", "1616161616161616161616161616161616161616161616161616161616161616") + os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_SIGNER_CONFIG_PRIVATE_KEY", "1717171717171717171717171717171717171717171717171717171717171717") os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_COMMIT_SENDER_SIGNER_CONFIG_PRIVATE_KEY", "1818181818181818181818181818181818181818181818181818181818181818") - os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_FINALIZE_SENDER_SIGNER_CONFIG_SIGNER_ADDRESS", "0x33e0F539E31B35170FAaA062af703b76a8282bf8") + os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_FINALIZE_SENDER_SIGNER_CONFIG_PRIVATE_KEY", "1919191919191919191919191919191919191919191919191919191919191919") cfg2, err := NewConfig("../../conf/config.json") assert.NoError(t, err) @@ -76,9 +76,9 @@ func TestConfig(t *testing.T) { assert.NotEqual(t, cfg.L2Config.RelayerConfig.FinalizeSenderSignerConfig, cfg2.L2Config.RelayerConfig.FinalizeSenderSignerConfig) assert.Equal(t, cfg2.DBConfig.DSN, "postgres://test:test@postgresql:5432/scroll?sslmode=disable") - assert.Equal(t, "0x03a1Bba60B5Aa37094cf16123AdD674c01589489", cfg2.L1Config.RelayerConfig.GasOracleSenderSignerConfig.SignerAddress) - assert.Equal(t, "0x03a1Bba60B5Aa37094cf16123AdD674c01589480", cfg2.L2Config.RelayerConfig.GasOracleSenderSignerConfig.SignerAddress) + assert.Equal(t, "1616161616161616161616161616161616161616161616161616161616161616", cfg2.L1Config.RelayerConfig.GasOracleSenderSignerConfig.PrivateKey) + assert.Equal(t, "1717171717171717171717171717171717171717171717171717171717171717", cfg2.L2Config.RelayerConfig.GasOracleSenderSignerConfig.PrivateKey) assert.Equal(t, "1818181818181818181818181818181818181818181818181818181818181818", cfg2.L2Config.RelayerConfig.CommitSenderSignerConfig.PrivateKey) - assert.Equal(t, "0x33e0F539E31B35170FAaA062af703b76a8282bf8", cfg2.L2Config.RelayerConfig.FinalizeSenderSignerConfig.SignerAddress) + assert.Equal(t, "1919191919191919191919191919191919191919191919191919191919191919", cfg2.L2Config.RelayerConfig.FinalizeSenderSignerConfig.PrivateKey) }) } From 04119769be5ed19fae3d823c40de05b4218d54c8 Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Fri, 27 Sep 2024 16:38:15 +0200 Subject: [PATCH 11/16] address comments --- rollup/internal/controller/sender/sender.go | 1 - rollup/internal/controller/sender/transaction_signer.go | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rollup/internal/controller/sender/sender.go b/rollup/internal/controller/sender/sender.go index 035186ce1..2c206a8d6 100644 --- a/rollup/internal/controller/sender/sender.go +++ b/rollup/internal/controller/sender/sender.go @@ -467,7 +467,6 @@ func (s *Sender) resubmitTransaction(tx *gethTypes.Transaction, baseFee, blobBas log.Info("Transaction gas adjustment details", "service", s.service, "name", s.name, "txInfo", txInfo) nonce := tx.Nonce() - tx.Hash() s.metrics.resubmitTransactionTotal.WithLabelValues(s.service, s.name).Inc() tx, err := s.createAndSendTx(&feeData, tx.To(), tx.Data(), tx.BlobTxSidecar(), &nonce) if err != nil { diff --git a/rollup/internal/controller/sender/transaction_signer.go b/rollup/internal/controller/sender/transaction_signer.go index c47d1fd3c..e500bd3fc 100644 --- a/rollup/internal/controller/sender/transaction_signer.go +++ b/rollup/internal/controller/sender/transaction_signer.go @@ -52,6 +52,9 @@ func NewTransactionSigner(config *config.SignerConfig, chainID *big.Int) (*Trans addr: crypto.PubkeyToAddress(privKey.PublicKey), }, nil case RemoteSignerSignerType: + if config.SignerAddress == "" { + return nil, fmt.Errorf("failed to create RemoteSigner, signer address is empty") + } rpcClient, err := rpc.Dial(config.RemoteSignerUrl) if err != nil { return nil, fmt.Errorf("failed to dial rpc client, err: %w", err) @@ -97,9 +100,6 @@ func (ts *TransactionSigner) SignTransaction(ctx context.Context, tx *gethTypes. } func (ts *TransactionSigner) SetNonce(nonce uint64) { - if ts.config.SignerType == PrivateKeySignerType { - ts.auth.Nonce = big.NewInt(int64(nonce)) - } ts.nonce = nonce } From 79e3c70f4d7c9ad204f8c164ff4bca96b8245fee Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Sun, 29 Sep 2024 22:06:42 +0200 Subject: [PATCH 12/16] address comments --- rollup/internal/config/relayer.go | 4 +- .../internal/controller/relayer/l2_relayer.go | 38 +++++++++++++++++++ .../controller/sender/transaction_signer.go | 14 +++---- .../sender/transaction_signer_test.go | 7 ++-- 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/rollup/internal/config/relayer.go b/rollup/internal/config/relayer.go index fe776ebf2..78202c996 100644 --- a/rollup/internal/config/relayer.go +++ b/rollup/internal/config/relayer.go @@ -86,10 +86,10 @@ type GasOracleConfig struct { L1BlobBaseFeeDefault uint64 `json:"l1_blob_base_fee_default"` } -// SignerConfig - config of signer, contains type and private_key/address,remoteUrl depending on type +// SignerConfig - config of signer, contains type, private key (for PrivateKey type), address and remote URL (for RemoteSigner type) type SignerConfig struct { SignerType string `json:"signer_type"` // type of signer can be PrivateKey or RemoteSigner PrivateKey string `json:"private_key"` // private key of signer in case of PrivateKey signerType - RemoteSignerUrl string `json:"remote_signer_url"` // remote signer url (web3signer) if case of RemoteSigner signerType + RemoteSignerUrl string `json:"remote_signer_url"` // remote signer url (web3signer) in case of RemoteSigner signerType SignerAddress string `json:"signer_address"` // address of signer } diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 371143355..57997b3fe 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -20,6 +20,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/crypto/kzg4844" "github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/log" @@ -77,6 +78,25 @@ func NewLayer2Relayer(ctx context.Context, l2Client *ethclient.Client, db *gorm. var gasOracleSender, commitSender, finalizeSender *sender.Sender var err error + + // check that all 3 signer addresses are different, because there will be a problem in managing nonce for different senders + gasOracleSenderAddr, err := addrFromSignerConfig(cfg.GasOracleSenderSignerConfig) + if err != nil { + return nil, fmt.Errorf("failed to parse addr from gas oracle signer config, err: %v", err) + } + commitSenderAddr, err := addrFromSignerConfig(cfg.CommitSenderSignerConfig) + if err != nil { + return nil, fmt.Errorf("failed to parse addr from commit sender config, err: %v", err) + } + finalizeSenderAddr, err := addrFromSignerConfig(cfg.FinalizeSenderSignerConfig) + if err != nil { + return nil, fmt.Errorf("failed to parse addr from finalize sender config, err: %v", err) + } + if gasOracleSenderAddr == commitSenderAddr || gasOracleSenderAddr == finalizeSenderAddr || commitSenderAddr == finalizeSenderAddr { + return nil, fmt.Errorf("gas oracle, commit, and finalize sender addresses must be different. Got: Gas Oracle=%s, Commit=%s, Finalize=%s", + gasOracleSenderAddr.Hex(), commitSenderAddr.Hex(), finalizeSenderAddr.Hex()) + } + switch serviceType { case ServiceTypeL2GasOracle: gasOracleSender, err = sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderSignerConfig, "l2_relayer", "gas_oracle_sender", types.SenderTypeL2GasOracle, db, reg) @@ -1278,3 +1298,21 @@ func (r *Layer2Relayer) StopSenders() { r.finalizeSender.Stop() } } + +func addrFromSignerConfig(config *config.SignerConfig) (common.Address, error) { + switch config.SignerType { + case sender.PrivateKeySignerType: + privKey, err := crypto.ToECDSA(common.FromHex(config.PrivateKey)) + if err != nil { + return common.Address{}, fmt.Errorf("parse sender private key failed: %w", err) + } + return crypto.PubkeyToAddress(privKey.PublicKey), nil + case sender.RemoteSignerSignerType: + if config.SignerAddress == "" { + return common.Address{}, fmt.Errorf("signer address is empty") + } + return common.HexToAddress(config.SignerAddress), nil + default: + return common.Address{}, fmt.Errorf("failed to determine signer address, unknown signer type: %v", config.SignerType) + } +} diff --git a/rollup/internal/controller/sender/transaction_signer.go b/rollup/internal/controller/sender/transaction_signer.go index e500bd3fc..6250bd545 100644 --- a/rollup/internal/controller/sender/transaction_signer.go +++ b/rollup/internal/controller/sender/transaction_signer.go @@ -5,16 +5,15 @@ import ( "fmt" "math/big" - "scroll-tech/rollup/internal/config" - "github.com/scroll-tech/go-ethereum/accounts/abi/bind" + "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common/hexutil" gethTypes "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/crypto" "github.com/scroll-tech/go-ethereum/log" - - "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/rpc" + + "scroll-tech/rollup/internal/config" ) const ( @@ -46,10 +45,9 @@ func NewTransactionSigner(config *config.SignerConfig, chainID *big.Int) (*Trans return nil, fmt.Errorf("failed to create transactor with chain ID %v, err: %w", chainID, err) } return &TransactionSigner{ - config: config, - auth: auth, - rpcClient: nil, - addr: crypto.PubkeyToAddress(privKey.PublicKey), + config: config, + auth: auth, + addr: crypto.PubkeyToAddress(privKey.PublicKey), }, nil case RemoteSignerSignerType: if config.SignerAddress == "" { diff --git a/rollup/internal/controller/sender/transaction_signer_test.go b/rollup/internal/controller/sender/transaction_signer_test.go index b8878f8b0..fa877b42e 100644 --- a/rollup/internal/controller/sender/transaction_signer_test.go +++ b/rollup/internal/controller/sender/transaction_signer_test.go @@ -4,16 +4,17 @@ import ( "context" "math/big" "os" - "scroll-tech/common/testcontainers" "testing" - "scroll-tech/rollup/internal/config" - "github.com/holiman/uint256" "github.com/scroll-tech/go-ethereum/common" gethTypes "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/log" "github.com/stretchr/testify/assert" + + "scroll-tech/common/testcontainers" + + "scroll-tech/rollup/internal/config" ) var ( From 9d9570137279e376d9c744dafc5d83af510cf4b5 Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Mon, 30 Sep 2024 10:30:39 +0200 Subject: [PATCH 13/16] add comment --- common/testcontainers/testcontainers.go | 2 ++ common/testcontainers/web3signerconf/keyconf.yaml | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/common/testcontainers/testcontainers.go b/common/testcontainers/testcontainers.go index 7adcd6eee..eb53152cd 100644 --- a/common/testcontainers/testcontainers.go +++ b/common/testcontainers/testcontainers.go @@ -124,6 +124,8 @@ func (t *TestcontainerApps) StartWeb3SignerContainer(chainId int) error { if rootDir, err = findProjectRootDir(); err != nil { return fmt.Errorf("failed to find project root directory: %v", err) } + + // web3signerconf/keyconf.yaml may contain multiple keys configured and web3signer then choses one corresponding to from field of tx web3SignerConfDir := filepath.Join(rootDir, "common", "testcontainers", "web3signerconf") req := testcontainers.ContainerRequest{ diff --git a/common/testcontainers/web3signerconf/keyconf.yaml b/common/testcontainers/web3signerconf/keyconf.yaml index 1a8ec9675..317f8763f 100644 --- a/common/testcontainers/web3signerconf/keyconf.yaml +++ b/common/testcontainers/web3signerconf/keyconf.yaml @@ -1,3 +1,7 @@ type: "file-raw" keyType: "SECP256K1" +privateKey: "0x1313131313131313131313131313131313131313131313131313131313131313" +--- +type: "file-raw" +keyType: "SECP256K1" privateKey: "0x1212121212121212121212121212121212121212121212121212121212121212" \ No newline at end of file From 0a5e73a840c363cc4857dd3d0cfc98bd0924eb3e Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Mon, 30 Sep 2024 19:55:14 +0200 Subject: [PATCH 14/16] estimate gas without access list for remote signer --- rollup/internal/controller/sender/estimategas.go | 3 ++- rollup/internal/controller/sender/transaction_signer.go | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rollup/internal/controller/sender/estimategas.go b/rollup/internal/controller/sender/estimategas.go index 9d3d5b74d..ca7945fc2 100644 --- a/rollup/internal/controller/sender/estimategas.go +++ b/rollup/internal/controller/sender/estimategas.go @@ -136,7 +136,8 @@ func (s *Sender) estimateGasLimit(to *common.Address, data []byte, sidecar *geth return 0, nil, err } - if s.config.TxType == LegacyTxType { + if s.config.TxType == LegacyTxType || + s.transactionSigner.GetType() == RemoteSignerSignerType { // web3signer doesn't support access list return gasLimitWithoutAccessList, nil, nil } diff --git a/rollup/internal/controller/sender/transaction_signer.go b/rollup/internal/controller/sender/transaction_signer.go index 6250bd545..ed768ac29 100644 --- a/rollup/internal/controller/sender/transaction_signer.go +++ b/rollup/internal/controller/sender/transaction_signer.go @@ -109,6 +109,10 @@ func (ts *TransactionSigner) GetAddr() common.Address { return ts.addr } +func (ts *TransactionSigner) GetType() string { + return ts.config.SignerType +} + // RpcTransaction transaction that will be send through rpc to web3Signer type RpcTransaction struct { From *common.Address `json:"from"` From 840f194e47ddd3fe28c7507c2a43d9bfec3b508c Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Wed, 2 Oct 2024 13:58:39 +0200 Subject: [PATCH 15/16] split config in 2 --- rollup/conf/config.json | 16 ++++++++++++---- rollup/internal/config/config_test.go | 17 +++++++++-------- rollup/internal/config/relayer.go | 16 +++++++++++++--- .../internal/controller/relayer/l2_relayer.go | 8 ++++---- .../internal/controller/sender/estimategas.go | 2 +- .../internal/controller/sender/sender_test.go | 4 +++- .../controller/sender/transaction_signer.go | 19 ++++++++++--------- .../sender/transaction_signer_test.go | 12 ++++++++---- rollup/tests/bridge_test.go | 4 ++-- 9 files changed, 62 insertions(+), 36 deletions(-) diff --git a/rollup/conf/config.json b/rollup/conf/config.json index 7cd783f58..50d6b5726 100644 --- a/rollup/conf/config.json +++ b/rollup/conf/config.json @@ -26,7 +26,9 @@ }, "gas_oracle_sender_signer_config": { "signer_type": "PrivateKey", - "private_key": "1313131313131313131313131313131313131313131313131313131313131313" + "private_key_signer_config": { + "private_key": "1313131313131313131313131313131313131313131313131313131313131313" + } } } }, @@ -65,15 +67,21 @@ "finalize_bundle_without_proof_timeout_sec": 7200, "gas_oracle_sender_signer_config": { "signer_type": "PrivateKey", - "private_key": "1313131313131313131313131313131313131313131313131313131313131313" + "private_key_signer_config": { + "private_key": "1313131313131313131313131313131313131313131313131313131313131313" + } }, "commit_sender_signer_config": { "signer_type": "PrivateKey", - "private_key": "1414141414141414141414141414141414141414141414141414141414141414" + "private_key_signer_config": { + "private_key": "1414141414141414141414141414141414141414141414141414141414141414" + } }, "finalize_sender_signer_config": { "signer_type": "PrivateKey", - "private_key": "1515151515151515151515151515151515151515151515151515151515151515" + "private_key_signer_config": { + "private_key": "1515151515151515151515151515151515151515151515151515151515151515" + } }, "l1_commit_gas_limit_multiplier": 1.2 }, diff --git a/rollup/internal/config/config_test.go b/rollup/internal/config/config_test.go index 8a49a4053..3374205b2 100644 --- a/rollup/internal/config/config_test.go +++ b/rollup/internal/config/config_test.go @@ -61,10 +61,10 @@ func TestConfig(t *testing.T) { assert.NoError(t, err) os.Setenv("SCROLL_ROLLUP_DB_CONFIG_DSN", "postgres://test:test@postgresql:5432/scroll?sslmode=disable") - os.Setenv("SCROLL_ROLLUP_L1_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_SIGNER_CONFIG_PRIVATE_KEY", "1616161616161616161616161616161616161616161616161616161616161616") - os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_SIGNER_CONFIG_PRIVATE_KEY", "1717171717171717171717171717171717171717171717171717171717171717") - os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_COMMIT_SENDER_SIGNER_CONFIG_PRIVATE_KEY", "1818181818181818181818181818181818181818181818181818181818181818") - os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_FINALIZE_SENDER_SIGNER_CONFIG_PRIVATE_KEY", "1919191919191919191919191919191919191919191919191919191919191919") + os.Setenv("SCROLL_ROLLUP_L1_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_SIGNER_CONFIG_PRIVATE_KEY_SIGNER_CONFIG_PRIVATE_KEY", "1616161616161616161616161616161616161616161616161616161616161616") + os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_GAS_ORACLE_SENDER_SIGNER_CONFIG_PRIVATE_KEY_SIGNER_CONFIG_PRIVATE_KEY", "1717171717171717171717171717171717171717171717171717171717171717") + os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_COMMIT_SENDER_SIGNER_CONFIG_PRIVATE_KEY_SIGNER_CONFIG_PRIVATE_KEY", "1818181818181818181818181818181818181818181818181818181818181818") + os.Setenv("SCROLL_ROLLUP_L2_CONFIG_RELAYER_CONFIG_FINALIZE_SENDER_SIGNER_CONFIG_PRIVATE_KEY_SIGNER_CONFIG_PRIVATE_KEY", "1919191919191919191919191919191919191919191919191919191919191919") cfg2, err := NewConfig("../../conf/config.json") assert.NoError(t, err) @@ -76,9 +76,10 @@ func TestConfig(t *testing.T) { assert.NotEqual(t, cfg.L2Config.RelayerConfig.FinalizeSenderSignerConfig, cfg2.L2Config.RelayerConfig.FinalizeSenderSignerConfig) assert.Equal(t, cfg2.DBConfig.DSN, "postgres://test:test@postgresql:5432/scroll?sslmode=disable") - assert.Equal(t, "1616161616161616161616161616161616161616161616161616161616161616", cfg2.L1Config.RelayerConfig.GasOracleSenderSignerConfig.PrivateKey) - assert.Equal(t, "1717171717171717171717171717171717171717171717171717171717171717", cfg2.L2Config.RelayerConfig.GasOracleSenderSignerConfig.PrivateKey) - assert.Equal(t, "1818181818181818181818181818181818181818181818181818181818181818", cfg2.L2Config.RelayerConfig.CommitSenderSignerConfig.PrivateKey) - assert.Equal(t, "1919191919191919191919191919191919191919191919191919191919191919", cfg2.L2Config.RelayerConfig.FinalizeSenderSignerConfig.PrivateKey) + assert.Equal(t, "1414141414141414141414141414141414141414141414141414141414141414", cfg.L2Config.RelayerConfig.CommitSenderSignerConfig.PrivateKeySignerConfig.PrivateKey) + assert.Equal(t, "1616161616161616161616161616161616161616161616161616161616161616", cfg2.L1Config.RelayerConfig.GasOracleSenderSignerConfig.PrivateKeySignerConfig.PrivateKey) + assert.Equal(t, "1717171717171717171717171717171717171717171717171717171717171717", cfg2.L2Config.RelayerConfig.GasOracleSenderSignerConfig.PrivateKeySignerConfig.PrivateKey) + assert.Equal(t, "1818181818181818181818181818181818181818181818181818181818181818", cfg2.L2Config.RelayerConfig.CommitSenderSignerConfig.PrivateKeySignerConfig.PrivateKey) + assert.Equal(t, "1919191919191919191919191919191919191919191919191919191919191919", cfg2.L2Config.RelayerConfig.FinalizeSenderSignerConfig.PrivateKeySignerConfig.PrivateKey) }) } diff --git a/rollup/internal/config/relayer.go b/rollup/internal/config/relayer.go index 78202c996..f6b022c54 100644 --- a/rollup/internal/config/relayer.go +++ b/rollup/internal/config/relayer.go @@ -86,10 +86,20 @@ type GasOracleConfig struct { L1BlobBaseFeeDefault uint64 `json:"l1_blob_base_fee_default"` } -// SignerConfig - config of signer, contains type, private key (for PrivateKey type), address and remote URL (for RemoteSigner type) +// SignerConfig - config of signer, contains type and config corresponding to type type SignerConfig struct { - SignerType string `json:"signer_type"` // type of signer can be PrivateKey or RemoteSigner - PrivateKey string `json:"private_key"` // private key of signer in case of PrivateKey signerType + SignerType string `json:"signer_type"` // type of signer can be PrivateKey or RemoteSigner + PrivateKeySignerConfig *PrivateKeySignerConfig `json:"private_key_signer_config"` + RemoteSignerConfig *RemoteSignerConfig `json:"remote_signer_config"` +} + +// PrivateKeySignerConfig - config of private signer, contains private key +type PrivateKeySignerConfig struct { + PrivateKey string `json:"private_key"` // private key of signer in case of PrivateKey signerType +} + +// RemoteSignerConfig - config of private signer, contains address and remote URL +type RemoteSignerConfig struct { RemoteSignerUrl string `json:"remote_signer_url"` // remote signer url (web3signer) in case of RemoteSigner signerType SignerAddress string `json:"signer_address"` // address of signer } diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 57997b3fe..63e5cbdce 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -1302,16 +1302,16 @@ func (r *Layer2Relayer) StopSenders() { func addrFromSignerConfig(config *config.SignerConfig) (common.Address, error) { switch config.SignerType { case sender.PrivateKeySignerType: - privKey, err := crypto.ToECDSA(common.FromHex(config.PrivateKey)) + privKey, err := crypto.ToECDSA(common.FromHex(config.PrivateKeySignerConfig.PrivateKey)) if err != nil { return common.Address{}, fmt.Errorf("parse sender private key failed: %w", err) } return crypto.PubkeyToAddress(privKey.PublicKey), nil - case sender.RemoteSignerSignerType: - if config.SignerAddress == "" { + case sender.RemoteSignerType: + if config.RemoteSignerConfig.SignerAddress == "" { return common.Address{}, fmt.Errorf("signer address is empty") } - return common.HexToAddress(config.SignerAddress), nil + return common.HexToAddress(config.RemoteSignerConfig.SignerAddress), nil default: return common.Address{}, fmt.Errorf("failed to determine signer address, unknown signer type: %v", config.SignerType) } diff --git a/rollup/internal/controller/sender/estimategas.go b/rollup/internal/controller/sender/estimategas.go index ca7945fc2..e0498cecb 100644 --- a/rollup/internal/controller/sender/estimategas.go +++ b/rollup/internal/controller/sender/estimategas.go @@ -137,7 +137,7 @@ func (s *Sender) estimateGasLimit(to *common.Address, data []byte, sidecar *geth } if s.config.TxType == LegacyTxType || - s.transactionSigner.GetType() == RemoteSignerSignerType { // web3signer doesn't support access list + s.transactionSigner.GetType() == RemoteSignerType { // web3signer doesn't support access list return gasLimitWithoutAccessList, nil, nil } diff --git a/rollup/internal/controller/sender/sender_test.go b/rollup/internal/controller/sender/sender_test.go index 25e96a961..6f2af46c2 100644 --- a/rollup/internal/controller/sender/sender_test.go +++ b/rollup/internal/controller/sender/sender_test.go @@ -73,7 +73,9 @@ func setupEnv(t *testing.T) { privateKeyString = "1212121212121212121212121212121212121212121212121212121212121212" signerConfig = &config.SignerConfig{ SignerType: "PrivateKey", - PrivateKey: privateKeyString, + PrivateKeySignerConfig: &config.PrivateKeySignerConfig{ + PrivateKey: privateKeyString, + }, } priv, err := crypto.HexToECDSA(privateKeyString) assert.NoError(t, err) diff --git a/rollup/internal/controller/sender/transaction_signer.go b/rollup/internal/controller/sender/transaction_signer.go index ed768ac29..5bc4c5df1 100644 --- a/rollup/internal/controller/sender/transaction_signer.go +++ b/rollup/internal/controller/sender/transaction_signer.go @@ -20,8 +20,8 @@ const ( // PrivateKeySignerType PrivateKeySignerType = "PrivateKey" - // RemoteSignerSignerType - RemoteSignerSignerType = "RemoteSigner" + // RemoteSignerType + RemoteSignerType = "RemoteSigner" ) // TransactionSigner signs given transactions @@ -36,7 +36,7 @@ type TransactionSigner struct { func NewTransactionSigner(config *config.SignerConfig, chainID *big.Int) (*TransactionSigner, error) { switch config.SignerType { case PrivateKeySignerType: - privKey, err := crypto.ToECDSA(common.FromHex(config.PrivateKey)) + privKey, err := crypto.ToECDSA(common.FromHex(config.PrivateKeySignerConfig.PrivateKey)) if err != nil { return nil, fmt.Errorf("parse sender private key failed: %w", err) } @@ -49,18 +49,18 @@ func NewTransactionSigner(config *config.SignerConfig, chainID *big.Int) (*Trans auth: auth, addr: crypto.PubkeyToAddress(privKey.PublicKey), }, nil - case RemoteSignerSignerType: - if config.SignerAddress == "" { + case RemoteSignerType: + if config.RemoteSignerConfig.SignerAddress == "" { return nil, fmt.Errorf("failed to create RemoteSigner, signer address is empty") } - rpcClient, err := rpc.Dial(config.RemoteSignerUrl) + rpcClient, err := rpc.Dial(config.RemoteSignerConfig.RemoteSignerUrl) if err != nil { return nil, fmt.Errorf("failed to dial rpc client, err: %w", err) } return &TransactionSigner{ config: config, rpcClient: rpcClient, - addr: common.HexToAddress(config.SignerAddress), + addr: common.HexToAddress(config.RemoteSignerConfig.SignerAddress), }, nil default: return nil, fmt.Errorf("failed to create new transaction signer, unknown type: %v", config.SignerType) @@ -72,11 +72,11 @@ func (ts *TransactionSigner) SignTransaction(ctx context.Context, tx *gethTypes. case PrivateKeySignerType: signedTx, err := ts.auth.Signer(ts.addr, tx) if err != nil { - log.Error("failed to sign tx", "address", ts.addr.String(), "err", err) + log.Info("failed to sign tx", "address", ts.addr.String(), "err", err) return nil, err } return signedTx, nil - case RemoteSignerSignerType: + case RemoteSignerType: rpcTx, err := txDataToRpcTx(&ts.addr, tx) if err != nil { return nil, fmt.Errorf("failed to convert txData to rpc transaction, err: %w", err) @@ -84,6 +84,7 @@ func (ts *TransactionSigner) SignTransaction(ctx context.Context, tx *gethTypes. var result hexutil.Bytes err = ts.rpcClient.CallContext(ctx, &result, "eth_signTransaction", rpcTx) if err != nil { + log.Info("failed to call remote rpc", "err", err) return nil, err } signedTx := new(gethTypes.Transaction) diff --git a/rollup/internal/controller/sender/transaction_signer_test.go b/rollup/internal/controller/sender/transaction_signer_test.go index fa877b42e..5937cb8c8 100644 --- a/rollup/internal/controller/sender/transaction_signer_test.go +++ b/rollup/internal/controller/sender/transaction_signer_test.go @@ -43,9 +43,11 @@ func testBothSignerTypes(t *testing.T) { // create remote signer remoteSignerConf := &config.SignerConfig{ - SignerType: RemoteSignerSignerType, - SignerAddress: "0x1C5A77d9FA7eF466951B2F01F724BCa3A5820b63", - RemoteSignerUrl: endpoint, + SignerType: RemoteSignerType, + RemoteSignerConfig: &config.RemoteSignerConfig{ + SignerAddress: "0x1C5A77d9FA7eF466951B2F01F724BCa3A5820b63", + RemoteSignerUrl: endpoint, + }, } remoteSigner, err := NewTransactionSigner(remoteSignerConf, big.NewInt(int64(chainId))) assert.NoError(t, err) @@ -54,7 +56,9 @@ func testBothSignerTypes(t *testing.T) { // create private key signer privateKeySignerConf := &config.SignerConfig{ SignerType: PrivateKeySignerType, - PrivateKey: "1212121212121212121212121212121212121212121212121212121212121212", + PrivateKeySignerConfig: &config.PrivateKeySignerConfig{ + PrivateKey: "1212121212121212121212121212121212121212121212121212121212121212", + }, } privateKeySigner, err := NewTransactionSigner(privateKeySignerConf, big.NewInt(int64(chainId))) assert.NoError(t, err) diff --git a/rollup/tests/bridge_test.go b/rollup/tests/bridge_test.go index fb272839b..3ab88f843 100644 --- a/rollup/tests/bridge_test.go +++ b/rollup/tests/bridge_test.go @@ -105,12 +105,12 @@ func setupEnv(t *testing.T) { l2Cfg.Confirmations = 0 l2Cfg.RelayerConfig.SenderConfig.Confirmations = 0 - pKey, err := crypto.ToECDSA(common.FromHex(l2Cfg.RelayerConfig.CommitSenderSignerConfig.PrivateKey)) + pKey, err := crypto.ToECDSA(common.FromHex(l2Cfg.RelayerConfig.CommitSenderSignerConfig.PrivateKeySignerConfig.PrivateKey)) assert.NoError(t, err) l1Auth, err = bind.NewKeyedTransactorWithChainID(pKey, l1GethChainID) assert.NoError(t, err) - pKey, err = crypto.ToECDSA(common.FromHex(l2Cfg.RelayerConfig.GasOracleSenderSignerConfig.PrivateKey)) + pKey, err = crypto.ToECDSA(common.FromHex(l2Cfg.RelayerConfig.GasOracleSenderSignerConfig.PrivateKeySignerConfig.PrivateKey)) assert.NoError(t, err) l2Auth, err = bind.NewKeyedTransactorWithChainID(pKey, l2GethChainID) assert.NoError(t, err) From 9a0dd939f6742595c50fd42d936706e388b8a342 Mon Sep 17 00:00:00 2001 From: Nazarii Denha Date: Wed, 2 Oct 2024 14:03:04 +0200 Subject: [PATCH 16/16] small fix --- tests/integration-test/contracts_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration-test/contracts_test.go b/tests/integration-test/contracts_test.go index 6d34a5b9d..4483f394b 100644 --- a/tests/integration-test/contracts_test.go +++ b/tests/integration-test/contracts_test.go @@ -68,7 +68,7 @@ func testGreeter(t *testing.T) { chainID, err := l2Cli.ChainID(context.Background()) assert.NoError(t, err) - pKey, err := crypto.ToECDSA(common.FromHex(rollupApp.Config.L2Config.RelayerConfig.CommitSenderSignerConfig.PrivateKey)) + pKey, err := crypto.ToECDSA(common.FromHex(rollupApp.Config.L2Config.RelayerConfig.CommitSenderSignerConfig.PrivateKeySignerConfig.PrivateKey)) assert.NoError(t, err) auth, err := bind.NewKeyedTransactorWithChainID(pKey, chainID) assert.NoError(t, err)