Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(sender): support web3signer #1524

Merged
merged 16 commits into from
Oct 3, 2024
61 changes: 58 additions & 3 deletions common/testcontainers/testcontainers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -112,6 +113,47 @@ 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)
}

// 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{
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 {
Expand Down Expand Up @@ -153,6 +195,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()
Expand Down Expand Up @@ -201,6 +251,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
Expand Down
9 changes: 9 additions & 0 deletions common/testcontainers/testcontainers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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)
}
7 changes: 7 additions & 0 deletions common/testcontainers/web3signerconf/keyconf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type: "file-raw"
keyType: "SECP256K1"
privateKey: "0x1313131313131313131313131313131313131313131313131313131313131313"
---
type: "file-raw"
keyType: "SECP256K1"
privateKey: "0x1212121212121212121212121212121212121212121212121212121212121212"
2 changes: 1 addition & 1 deletion common/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
20 changes: 16 additions & 4 deletions rollup/conf/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
"l1_base_fee_default": 15000000000,
"l1_blob_base_fee_default": 1
},
"gas_oracle_sender_private_key": "1313131313131313131313131313131313131313131313131313131313131313"
"gas_oracle_sender_signer_config": {
"signer_type": "PrivateKey",
"private_key": "1313131313131313131313131313131313131313131313131313131313131313"
}
}
},
"l2_config": {
Expand Down Expand Up @@ -60,9 +63,18 @@
"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": "PrivateKey",
"private_key": "1313131313131313131313131313131313131313131313131313131313131313"
},
"commit_sender_signer_config": {
"signer_type": "PrivateKey",
"private_key": "1414141414141414141414141414141414141414141414141414141414141414"
},
"finalize_sender_signer_config": {
"signer_type": "PrivateKey",
"private_key": "1515151515151515151515151515151515151515151515151515151515151515"
},
"l1_commit_gas_limit_multiplier": 1.2
},
"chunk_proposer_config": {
Expand Down
24 changes: 12 additions & 12 deletions rollup/internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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_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")

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, "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)
})
}
17 changes: 13 additions & 4 deletions rollup/internal/config/relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand All @@ -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, 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) in case of RemoteSigner signerType
SignerAddress string `json:"signer_address"` // address of signer
}
13 changes: 3 additions & 10 deletions rollup/internal/controller/relayer/l1_relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -54,18 +52,13 @@ 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:
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.
Expand Down
83 changes: 40 additions & 43 deletions rollup/internal/controller/relayer/l2_relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package relayer

import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
Expand Down Expand Up @@ -76,18 +75,33 @@ 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)

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 private keys provided by config, err: %v", err)
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())
}

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.
Expand All @@ -96,16 +110,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.
Expand Down Expand Up @@ -1287,35 +1299,20 @@ func (r *Layer2Relayer) StopSenders() {
}
}

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 {
colinlyguo marked this conversation as resolved.
Show resolved Hide resolved
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())
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
NazariiDenha marked this conversation as resolved.
Show resolved Hide resolved
default:
return common.Address{}, fmt.Errorf("failed to determine signer address, unknown signer type: %v", config.SignerType)
}

return gasOracleKey, commitKey, finalizeKey, nil
}
Loading
Loading