mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-12 07:28:08 -05:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6b9176ef2 | ||
|
|
09f087ab16 | ||
|
|
e3c87e6547 | ||
|
|
a1d1cbc2e5 | ||
|
|
404a625cb4 | ||
|
|
736d850be1 |
@@ -17,6 +17,7 @@ RUN --mount=target=. \
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV CGO_LDFLAGS="-Wl,--no-as-needed -ldl"
|
||||
RUN apt update && apt install vim netcat-openbsd net-tools curl -y
|
||||
COPY --from=builder /bin/bridgehistoryapi-api /bin/
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["bridgehistoryapi-api"]
|
||||
|
||||
@@ -17,7 +17,7 @@ RUN --mount=target=. \
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV CGO_LDFLAGS="-Wl,--no-as-needed -ldl"
|
||||
RUN apt update && apt install ca-certificates -y
|
||||
RUN apt update && apt install ca-certificates vim netcat-openbsd net-tools curl -y
|
||||
RUN update-ca-certificates
|
||||
COPY --from=builder /bin/bridgehistoryapi-fetcher /bin/
|
||||
WORKDIR /app
|
||||
|
||||
@@ -40,6 +40,7 @@ FROM ubuntu:20.04
|
||||
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/src/coordinator/internal/logic/verifier/lib
|
||||
ENV CGO_LDFLAGS="-Wl,--no-as-needed -ldl"
|
||||
# ENV CHAIN_ID=534353
|
||||
RUN apt update && apt install vim netcat-openbsd net-tools curl -y
|
||||
RUN mkdir -p /src/coordinator/internal/logic/verifier/lib
|
||||
COPY --from=builder /bin/lib /src/coordinator/internal/logic/verifier/lib
|
||||
COPY --from=builder /bin/coordinator_api /bin/
|
||||
|
||||
@@ -19,9 +19,8 @@ RUN --mount=target=. \
|
||||
|
||||
# Pull coordinator into a second stage deploy ubuntu container
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV CGO_LDFLAGS="-Wl,--no-as-needed -ldl"
|
||||
|
||||
RUN apt update && apt install vim netcat-openbsd net-tools curl -y
|
||||
COPY --from=builder /bin/coordinator_cron /bin/
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["coordinator_cron"]
|
||||
|
||||
@@ -21,7 +21,7 @@ RUN --mount=target=. \
|
||||
# Pull gas_oracle into a second stage deploy ubuntu container
|
||||
FROM ubuntu:20.04
|
||||
|
||||
RUN apt update && apt install ca-certificates -y
|
||||
RUN apt update && apt install vim netcat-openbsd net-tools curl ca-certificates -y
|
||||
|
||||
ENV CGO_LDFLAGS="-ldl"
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ RUN --mount=target=. \
|
||||
# Pull rollup_relayer into a second stage deploy ubuntu container
|
||||
FROM ubuntu:20.04
|
||||
|
||||
RUN apt update && apt install ca-certificates -y
|
||||
RUN apt update && apt install vim netcat-openbsd net-tools curl ca-certificates -y
|
||||
|
||||
ENV CGO_LDFLAGS="-ldl"
|
||||
|
||||
|
||||
@@ -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,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 {
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
7
common/testcontainers/web3signerconf/keyconf.yaml
Normal file
7
common/testcontainers/web3signerconf/keyconf.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
type: "file-raw"
|
||||
keyType: "SECP256K1"
|
||||
privateKey: "0x1313131313131313131313131313131313131313131313131313131313131313"
|
||||
---
|
||||
type: "file-raw"
|
||||
keyType: "SECP256K1"
|
||||
privateKey: "0x1212121212121212121212121212121212121212121212121212121212121212"
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
var tag = "v4.4.60"
|
||||
var tag = "v4.4.65"
|
||||
|
||||
var commit = func() string {
|
||||
if info, ok := debug.ReadBuildInfo(); ok {
|
||||
|
||||
@@ -24,7 +24,12 @@
|
||||
"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_signer_config": {
|
||||
"private_key": "1313131313131313131313131313131313131313131313131313131313131313"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"l2_config": {
|
||||
@@ -60,9 +65,24 @@
|
||||
"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_signer_config": {
|
||||
"private_key": "1313131313131313131313131313131313131313131313131313131313131313"
|
||||
}
|
||||
},
|
||||
"commit_sender_signer_config": {
|
||||
"signer_type": "PrivateKey",
|
||||
"private_key_signer_config": {
|
||||
"private_key": "1414141414141414141414141414141414141414141414141414141414141414"
|
||||
}
|
||||
},
|
||||
"finalize_sender_signer_config": {
|
||||
"signer_type": "PrivateKey",
|
||||
"private_key_signer_config": {
|
||||
"private_key": "1515151515151515151515151515151515151515151515151515151515151515"
|
||||
}
|
||||
},
|
||||
"l1_commit_gas_limit_multiplier": 1.2
|
||||
},
|
||||
"chunk_proposer_config": {
|
||||
|
||||
@@ -61,24 +61,25 @@ 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_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)
|
||||
|
||||
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, "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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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,21 @@ 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 config corresponding to type
|
||||
type SignerConfig struct {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -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.
|
||||
|
||||
@@ -2,7 +2,6 @@ package relayer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
@@ -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)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse private keys provided by config, err: %v", err)
|
||||
}
|
||||
|
||||
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, 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 +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.
|
||||
@@ -450,6 +462,18 @@ func (r *Layer2Relayer) ProcessPendingBatches() {
|
||||
log.Error("UpdateCommitTxHashAndRollupStatus failed", "hash", dbBatch.Hash, "index", dbBatch.Index, "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
var maxBlockHeight uint64
|
||||
var totalGasUsed uint64
|
||||
for _, dbChunk := range dbChunks {
|
||||
if dbChunk.EndBlockNumber > maxBlockHeight {
|
||||
maxBlockHeight = dbChunk.EndBlockNumber
|
||||
}
|
||||
totalGasUsed += dbChunk.TotalL2TxGas
|
||||
}
|
||||
r.metrics.rollupL2RelayerCommitBlockHeight.Set(float64(maxBlockHeight))
|
||||
r.metrics.rollupL2RelayerCommitThroughput.Add(float64(totalGasUsed))
|
||||
|
||||
r.metrics.rollupL2RelayerProcessPendingBatchSuccessTotal.Inc()
|
||||
log.Info("Sent the commitBatch tx to layer1", "batch index", dbBatch.Index, "batch hash", dbBatch.Hash, "tx hash", txHash.String())
|
||||
}
|
||||
@@ -1275,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))
|
||||
func addrFromSignerConfig(config *config.SignerConfig) (common.Address, error) {
|
||||
switch config.SignerType {
|
||||
case sender.PrivateKeySignerType:
|
||||
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.RemoteSignerType:
|
||||
if config.RemoteSignerConfig.SignerAddress == "" {
|
||||
return common.Address{}, fmt.Errorf("signer address is empty")
|
||||
}
|
||||
return common.HexToAddress(config.RemoteSignerConfig.SignerAddress), nil
|
||||
default:
|
||||
return common.Address{}, fmt.Errorf("failed to determine signer address, unknown signer type: %v", config.SignerType)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ type l2RelayerMetrics struct {
|
||||
rollupL2RelayerProcessPendingBundlesFinalizedSuccessTotal prometheus.Counter
|
||||
rollupL2BundlesFinalizedConfirmedTotal prometheus.Counter
|
||||
rollupL2BundlesFinalizedConfirmedFailedTotal prometheus.Counter
|
||||
|
||||
rollupL2RelayerCommitBlockHeight prometheus.Gauge
|
||||
rollupL2RelayerCommitThroughput prometheus.Counter
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -123,6 +126,14 @@ func initL2RelayerMetrics(reg prometheus.Registerer) *l2RelayerMetrics {
|
||||
Name: "rollup_layer2_bundles_finalized_confirmed_failed_total",
|
||||
Help: "Total number of failed confirmations for finalized bundles on layer2.",
|
||||
}),
|
||||
rollupL2RelayerCommitBlockHeight: promauto.With(reg).NewGauge(prometheus.GaugeOpts{
|
||||
Name: "rollup_l2_relayer_commit_block_height",
|
||||
Help: "The latest block height committed by the L2 relayer",
|
||||
}),
|
||||
rollupL2RelayerCommitThroughput: promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "rollup_l2_relayer_commit_throughput",
|
||||
Help: "The cumulative gas used in blocks committed by the L2 relayer",
|
||||
}),
|
||||
}
|
||||
})
|
||||
return l2RelayerMetric
|
||||
|
||||
@@ -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,
|
||||
@@ -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() == RemoteSignerType { // web3signer doesn't support access list
|
||||
return gasLimitWithoutAccessList, nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -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,15 @@ 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.
|
||||
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 +85,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,18 +100,17 @@ 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,
|
||||
@@ -122,7 +118,7 @@ func NewSender(ctx context.Context, config *config.SenderConfig, priv *ecdsa.Pri
|
||||
gethClient: gethclient.New(rpcClient),
|
||||
client: client,
|
||||
chainID: chainID,
|
||||
auth: auth,
|
||||
transactionSigner: transactionSigner,
|
||||
db: db,
|
||||
pendingTransactionOrm: orm.NewPendingTransaction(db),
|
||||
confirmCh: make(chan *Confirmation, 128),
|
||||
@@ -146,7 +142,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 +213,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 +232,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 +264,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 +285,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 +322,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 +346,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(),
|
||||
}
|
||||
|
||||
@@ -473,7 +470,7 @@ func (s *Sender) resubmitTransaction(tx *gethTypes.Transaction, baseFee, blobBas
|
||||
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 +512,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 +569,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 +577,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 +620,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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"}
|
||||
@@ -53,6 +55,9 @@ func TestMain(m *testing.M) {
|
||||
if testApps != nil {
|
||||
testApps.Free()
|
||||
}
|
||||
if testAppsSignerTest != nil {
|
||||
testAppsSignerTest.Free()
|
||||
}
|
||||
}()
|
||||
m.Run()
|
||||
}
|
||||
@@ -65,7 +70,14 @@ 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",
|
||||
PrivateKeySignerConfig: &config.PrivateKeySignerConfig{
|
||||
PrivateKey: privateKeyString,
|
||||
},
|
||||
}
|
||||
priv, err := crypto.HexToECDSA(privateKeyString)
|
||||
assert.NoError(t, err)
|
||||
privateKey = priv
|
||||
|
||||
@@ -148,7 +160,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 +168,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 +182,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 +218,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 +274,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 +314,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 +355,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 +404,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 +441,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 +450,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 +483,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 +495,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 +551,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 +600,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 +642,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 +702,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 +772,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 +849,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 +901,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++ {
|
||||
|
||||
156
rollup/internal/controller/sender/transaction_signer.go
Normal file
156
rollup/internal/controller/sender/transaction_signer.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package sender
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/accounts/abi/bind"
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/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/rpc"
|
||||
|
||||
"scroll-tech/rollup/internal/config"
|
||||
)
|
||||
|
||||
const (
|
||||
// PrivateKeySignerType
|
||||
PrivateKeySignerType = "PrivateKey"
|
||||
|
||||
// RemoteSignerType
|
||||
RemoteSignerType = "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.PrivateKeySignerConfig.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,
|
||||
addr: crypto.PubkeyToAddress(privKey.PublicKey),
|
||||
}, nil
|
||||
case RemoteSignerType:
|
||||
if config.RemoteSignerConfig.SignerAddress == "" {
|
||||
return nil, fmt.Errorf("failed to create RemoteSigner, signer address is empty")
|
||||
}
|
||||
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.RemoteSignerConfig.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.Info("failed to sign tx", "address", ts.addr.String(), "err", err)
|
||||
return nil, err
|
||||
}
|
||||
return signedTx, nil
|
||||
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)
|
||||
}
|
||||
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)
|
||||
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) {
|
||||
ts.nonce = nonce
|
||||
}
|
||||
|
||||
func (ts *TransactionSigner) GetNonce() uint64 {
|
||||
return ts.nonce
|
||||
}
|
||||
|
||||
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"`
|
||||
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 string `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: common.Bytes2Hex(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: 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())
|
||||
}
|
||||
}
|
||||
122
rollup/internal/controller/sender/transaction_signer_test.go
Normal file
122
rollup/internal/controller/sender/transaction_signer_test.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package sender
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"os"
|
||||
"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"
|
||||
|
||||
"scroll-tech/common/testcontainers"
|
||||
|
||||
"scroll-tech/rollup/internal/config"
|
||||
)
|
||||
|
||||
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: RemoteSignerType,
|
||||
RemoteSignerConfig: &config.RemoteSignerConfig{
|
||||
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,
|
||||
PrivateKeySignerConfig: &config.PrivateKeySignerConfig{
|
||||
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),
|
||||
},
|
||||
}
|
||||
var signedTx1 *gethTypes.Transaction
|
||||
var signedTx2 *gethTypes.Transaction
|
||||
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)
|
||||
}
|
||||
@@ -53,6 +53,9 @@ type BatchProposer struct {
|
||||
|
||||
// total number of times that batch proposer stops early due to compressed data compatibility breach
|
||||
compressedDataCompatibilityBreachTotal prometheus.Counter
|
||||
|
||||
batchProposeBlockHeight prometheus.Gauge
|
||||
batchProposeThroughput prometheus.Counter
|
||||
}
|
||||
|
||||
// NewBatchProposer creates a new BatchProposer instance.
|
||||
@@ -134,6 +137,14 @@ func NewBatchProposer(ctx context.Context, cfg *config.BatchProposerConfig, chai
|
||||
Name: "rollup_propose_batch_estimate_blob_size_time",
|
||||
Help: "Time taken to estimate blob size for the chunk.",
|
||||
}),
|
||||
batchProposeBlockHeight: promauto.With(reg).NewGauge(prometheus.GaugeOpts{
|
||||
Name: "rollup_batch_propose_block_height",
|
||||
Help: "The block height of the latest proposed batch",
|
||||
}),
|
||||
batchProposeThroughput: promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "rollup_batch_propose_throughput",
|
||||
Help: "The total gas used in proposed batches",
|
||||
}),
|
||||
}
|
||||
|
||||
return p
|
||||
@@ -195,6 +206,18 @@ func (p *BatchProposer) updateDBBatchInfo(batch *encoding.Batch, codecVersion en
|
||||
p.recordAllBatchMetrics(metrics)
|
||||
}
|
||||
|
||||
if len(batch.Chunks) > 0 && len(batch.Chunks[len(batch.Chunks)-1].Blocks) > 0 {
|
||||
lastChunk := batch.Chunks[len(batch.Chunks)-1]
|
||||
lastBlock := lastChunk.Blocks[len(lastChunk.Blocks)-1]
|
||||
p.batchProposeBlockHeight.Set(float64(lastBlock.Header.Number.Uint64()))
|
||||
}
|
||||
|
||||
var totalGasUsed uint64
|
||||
for _, chunk := range batch.Chunks {
|
||||
totalGasUsed += chunk.L2GasUsed()
|
||||
}
|
||||
p.batchProposeThroughput.Add(float64(totalGasUsed))
|
||||
|
||||
p.proposeBatchUpdateInfoTotal.Inc()
|
||||
err := p.db.Transaction(func(dbTX *gorm.DB) error {
|
||||
dbBatch, dbErr := p.batchOrm.InsertBatch(p.ctx, batch, codecConfig, *metrics, dbTX)
|
||||
|
||||
@@ -2,6 +2,7 @@ package watcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
@@ -146,6 +147,12 @@ func (p *BundleProposer) proposeBundle() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if firstChunk == nil {
|
||||
log.Error("first chunk not found", "start chunk index", batches[0].StartChunkIndex, "start batch index", batches[0].Index, "firstUnbundledBatchIndex", firstUnbundledBatchIndex)
|
||||
return errors.New("first chunk not found in proposeBundle")
|
||||
}
|
||||
|
||||
hardforkName := forks.GetHardforkName(p.chainCfg, firstChunk.StartBlockNumber, firstChunk.StartBlockTime)
|
||||
codecVersion := encoding.CodecVersion(batches[0].CodecVersion)
|
||||
for i := 1; i < len(batches); i++ {
|
||||
|
||||
@@ -56,6 +56,9 @@ type ChunkProposer struct {
|
||||
|
||||
// total number of times that chunk proposer stops early due to compressed data compatibility breach
|
||||
compressedDataCompatibilityBreachTotal prometheus.Counter
|
||||
|
||||
chunkProposeBlockHeight prometheus.Gauge
|
||||
chunkProposeThroughput prometheus.Counter
|
||||
}
|
||||
|
||||
// NewChunkProposer creates a new ChunkProposer instance.
|
||||
@@ -150,6 +153,14 @@ func NewChunkProposer(ctx context.Context, cfg *config.ChunkProposerConfig, chai
|
||||
Name: "rollup_propose_chunk_estimate_blob_size_time",
|
||||
Help: "Time taken to estimate blob size for the chunk.",
|
||||
}),
|
||||
chunkProposeBlockHeight: promauto.With(reg).NewGauge(prometheus.GaugeOpts{
|
||||
Name: "rollup_chunk_propose_block_height",
|
||||
Help: "The block height of the latest proposed chunk",
|
||||
}),
|
||||
chunkProposeThroughput: promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "rollup_chunk_propose_throughput",
|
||||
Help: "The total gas used in proposed chunks",
|
||||
}),
|
||||
}
|
||||
|
||||
return p
|
||||
@@ -214,6 +225,11 @@ func (p *ChunkProposer) updateDBChunkInfo(chunk *encoding.Chunk, codecVersion en
|
||||
p.recordAllChunkMetrics(metrics)
|
||||
}
|
||||
|
||||
if len(chunk.Blocks) > 0 {
|
||||
p.chunkProposeBlockHeight.Set(float64(chunk.Blocks[len(chunk.Blocks)-1].Header.Number.Uint64()))
|
||||
}
|
||||
p.chunkProposeThroughput.Add(float64(chunk.L2GasUsed()))
|
||||
|
||||
p.proposeChunkUpdateInfoTotal.Inc()
|
||||
err := p.db.Transaction(func(dbTX *gorm.DB) error {
|
||||
dbChunk, err := p.chunkOrm.InsertChunk(p.ctx, chunk, codecConfig, *metrics, dbTX)
|
||||
|
||||
@@ -127,6 +127,7 @@ func (w *L2WatcherClient) getAndStoreBlocks(ctx context.Context, from, to uint64
|
||||
return fmt.Errorf("failed to GetBlockByNumberOrHash: %v. number: %v", err, number)
|
||||
}
|
||||
if block.RowConsumption == nil {
|
||||
w.metrics.fetchNilRowConsumptionBlockTotal.Inc()
|
||||
return fmt.Errorf("fetched block does not contain RowConsumption. number: %v", number)
|
||||
}
|
||||
|
||||
@@ -151,6 +152,7 @@ func (w *L2WatcherClient) getAndStoreBlocks(ctx context.Context, from, to uint64
|
||||
return fmt.Errorf("failed to estimate block L1 commit calldata size: %v", err)
|
||||
}
|
||||
w.metrics.rollupL2BlockL1CommitCalldataSize.Set(float64(blockL1CommitCalldataSize))
|
||||
w.metrics.rollupL2WatcherSyncThroughput.Add(float64(block.Header.GasUsed))
|
||||
}
|
||||
if err := w.l2BlockOrm.InsertL2Blocks(w.ctx, blocks); err != nil {
|
||||
return fmt.Errorf("failed to batch insert BlockTraces: %v", err)
|
||||
|
||||
@@ -12,6 +12,9 @@ type l2WatcherMetrics struct {
|
||||
fetchRunningMissingBlocksHeight prometheus.Gauge
|
||||
rollupL2BlocksFetchedGap prometheus.Gauge
|
||||
rollupL2BlockL1CommitCalldataSize prometheus.Gauge
|
||||
fetchNilRowConsumptionBlockTotal prometheus.Counter
|
||||
|
||||
rollupL2WatcherSyncThroughput prometheus.Counter
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -38,6 +41,14 @@ func initL2WatcherMetrics(reg prometheus.Registerer) *l2WatcherMetrics {
|
||||
Name: "rollup_l2_block_l1_commit_calldata_size",
|
||||
Help: "The l1 commitBatch calldata size of the l2 block",
|
||||
}),
|
||||
fetchNilRowConsumptionBlockTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "rollup_l2_watcher_fetch_nil_row_consumption_block_total",
|
||||
Help: "The total number of occurrences where a fetched block has nil RowConsumption",
|
||||
}),
|
||||
rollupL2WatcherSyncThroughput: promauto.With(reg).NewCounter(prometheus.CounterOpts{
|
||||
Name: "rollup_l2_watcher_sync_throughput",
|
||||
Help: "The cumulative gas used in blocks that L2 watcher sync",
|
||||
}),
|
||||
}
|
||||
})
|
||||
return l2WatcherMetric
|
||||
|
||||
@@ -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.PrivateKeySignerConfig.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.PrivateKeySignerConfig.PrivateKey))
|
||||
assert.NoError(t, err)
|
||||
l2Auth, err = bind.NewKeyedTransactorWithChainID(pKey, l2GethChainID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -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.PrivateKeySignerConfig.PrivateKey))
|
||||
assert.NoError(t, err)
|
||||
auth, err := bind.NewKeyedTransactorWithChainID(pKey, chainID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
Reference in New Issue
Block a user