Commit 305cbb62 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge branch 'develop' into feat/xdm-migrate

parents c4ef0d1b 37a91aed
---
'@eth-optimism/contracts-bedrock': patch
---
Use uint64 for arithmetic in XDM's baseGas
---
'@eth-optimism/sdk': patch
---
Adds contract addresses for the Bedrock Alpha testnet
---
'@eth-optimism/contracts-bedrock': patch
'@eth-optimism/sdk': patch
---
Rename the event emitted in the L2ToL1MessagePasser
---
'@eth-optimism/contracts-periphery': patch
---
Goerli nft bridge deployment
---
'@eth-optimism/l2geth': patch
---
add --rpc.evmtimeout flag to configure timeout for eth_call
---
'@eth-optimism/integration-tests': patch
'@eth-optimism/contracts-periphery': patch
---
Fix erc721 factory to match erc21 factory
---
"@eth-optimism/contracts-periphery": patch
---
mainnet nft bridge deployments
---
'@eth-optimism/endpoint-monitor': major
---
Initial release of endpoint monitor
---
'@eth-optimism/ci-builder': patch
---
Pin slither version to 0.9.0
...@@ -2,6 +2,48 @@ version: 2.1 ...@@ -2,6 +2,48 @@ version: 2.1
orbs: orbs:
go: circleci/go@1.5.0 go: circleci/go@1.5.0
gcp-cli: circleci/gcp-cli@2.4.1
commands:
gcp-oidc-authenticate:
description: "Authenticate with GCP using a CircleCI OIDC token."
parameters:
project_id:
type: env_var_name
default: GCP_PROJECT_ID
workload_identity_pool_id:
type: env_var_name
default: GCP_WIP_ID
workload_identity_pool_provider_id:
type: env_var_name
default: GCP_WIP_PROVIDER_ID
service_account_email:
type: env_var_name
default: GCP_SERVICE_ACCOUNT_EMAIL
gcp_cred_config_file_path:
type: string
default: /home/circleci/gcp_cred_config.json
oidc_token_file_path:
type: string
default: /home/circleci/oidc_token.json
steps:
- run:
name: "Create OIDC credential configuration"
command: |
# Store OIDC token in temp file
echo $CIRCLE_OIDC_TOKEN > << parameters.oidc_token_file_path >>
# Create a credential configuration for the generated OIDC ID Token
gcloud iam workload-identity-pools create-cred-config \
"projects/${<< parameters.project_id >>}/locations/global/workloadIdentityPools/${<< parameters.workload_identity_pool_id >>}/providers/${<< parameters.workload_identity_pool_provider_id >>}"\
--output-file="<< parameters.gcp_cred_config_file_path >>" \
--service-account="${<< parameters.service_account_email >>}" \
--credential-source-file=<< parameters.oidc_token_file_path >>
- run:
name: "Authenticate with GCP using OIDC"
command: |
# Configure gcloud to leverage the generated credential configuration
gcloud auth login --brief --cred-file "<< parameters.gcp_cred_config_file_path >>"
# Configure ADC
echo "export GOOGLE_APPLICATION_CREDENTIALS='<< parameters.gcp_cred_config_file_path >>'" | tee -a "$BASH_ENV"
jobs: jobs:
yarn-monorepo: yarn-monorepo:
docker: docker:
...@@ -67,6 +109,7 @@ jobs: ...@@ -67,6 +109,7 @@ jobs:
image: ubuntu-2204:2022.07.1 image: ubuntu-2204:2022.07.1
resource_class: xlarge resource_class: xlarge
steps: steps:
- gcp-oidc-authenticate
# Below is CircleCI recommended way of specifying nameservers on an Ubuntu box: # Below is CircleCI recommended way of specifying nameservers on an Ubuntu box:
# https://support.circleci.com/hc/en-us/articles/7323511028251-How-to-set-custom-DNS-on-Ubuntu-based-images-using-netplan # https://support.circleci.com/hc/en-us/articles/7323511028251-How-to-set-custom-DNS-on-Ubuntu-based-images-using-netplan
- run: sudo sed -i '13 i \ \ \ \ \ \ \ \ \ \ \ \ nameservers:' /etc/netplan/50-cloud-init.yaml - run: sudo sed -i '13 i \ \ \ \ \ \ \ \ \ \ \ \ nameservers:' /etc/netplan/50-cloud-init.yaml
...@@ -101,7 +144,7 @@ jobs: ...@@ -101,7 +144,7 @@ jobs:
- run: - run:
name: Publish name: Publish
command: | command: |
echo "$DOCKER_PASS" | docker login -u "$DOCKER_USERNAME" --password-stdin "<<parameters.repo>>" gcloud auth configure-docker us-central1-docker.pkg.dev
docker push <<parameters.docker_tags>> docker push <<parameters.docker_tags>>
contracts-bedrock-tests: contracts-bedrock-tests:
...@@ -432,7 +475,7 @@ jobs: ...@@ -432,7 +475,7 @@ jobs:
name: Test name: Test
command: | command: |
mkdir -p /test-results mkdir -p /test-results
gotestsum --junitfile /test-results/tests.xml DB_USER=postgres gotestsum --junitfile /test-results/tests.xml
working_directory: <<parameters.working_directory>> working_directory: <<parameters.working_directory>>
- when: - when:
condition: condition:
......
# @eth-optimism/endpoint-monitor # @eth-optimism/endpoint-monitor
## 1.0.0
### Major Changes
- a10c2b49: Initial release of endpoint monitor
{ {
"name": "@eth-optimism/endpoint-monitor", "name": "@eth-optimism/endpoint-monitor",
"version": "0.0.0", "version": "1.0.0",
"private": true, "private": true,
"dependencies": {} "dependencies": {}
} }
# @eth-optimism/indexer # @eth-optimism/indexer
## 0.3.0
### Minor Changes
- 19e581d8: Bedrock support
## 0.2.0 ## 0.2.0
### Minor Changes ### Minor Changes
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"errors" "errors"
"time" "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli" "github.com/urfave/cli"
...@@ -20,15 +21,8 @@ var ( ...@@ -20,15 +21,8 @@ var (
type Config struct { type Config struct {
/* Required Params */ /* Required Params */
// BuildEnv identifies the environment this binary is intended for, i.e.
// production, development, etc.
BuildEnv string
// EthNetworkName identifies the intended Ethereum network.
EthNetworkName string
// ChainID identifies the chain being indexed. // ChainID identifies the chain being indexed.
ChainID int64 ChainID uint64
// L1EthRpc is the HTTP provider URL for L1. // L1EthRpc is the HTTP provider URL for L1.
L1EthRpc string L1EthRpc string
...@@ -36,8 +30,8 @@ type Config struct { ...@@ -36,8 +30,8 @@ type Config struct {
// L2EthRpc is the HTTP provider URL for L1. // L2EthRpc is the HTTP provider URL for L1.
L2EthRpc string L2EthRpc string
// L2GenesisBlockHash is the l2 genesis block hash. // L1AddressManagerAddress is the address of the address manager for L1.
L2GenesisBlockHash string L1AddressManagerAddress string
// PollInterval is the delay between querying L2 for more transaction // PollInterval is the delay between querying L2 for more transaction
// and creating a new batch. // and creating a new batch.
...@@ -68,22 +62,8 @@ type Config struct { ...@@ -68,22 +62,8 @@ type Config struct {
// are printed using JSON. // are printed using JSON.
LogTerminal bool LogTerminal bool
// SentryEnable if true, logs any error messages to sentry. SentryDsn // L1StartBlockNumber is the block number to start indexing L1 from.
// must also be set if SentryEnable is true. L1StartBlockNumber uint64
SentryEnable bool
// SentryDsn is the sentry Data Source Name.
SentryDsn string
// SentryTraceRate the frequency with which Sentry should flush buffered
// events.
SentryTraceRate time.Duration
// StartBlockNumber is the block number to start indexing from.
StartBlockNumber uint64
// StartBlockHash is the block hash to start indexing from.
StartBlockHash string
// ConfDepth is the number of confirmations after which headers are // ConfDepth is the number of confirmations after which headers are
// considered confirmed. // considered confirmed.
...@@ -111,6 +91,13 @@ type Config struct { ...@@ -111,6 +91,13 @@ type Config struct {
// DisableIndexer enables/disables the indexer. // DisableIndexer enables/disables the indexer.
DisableIndexer bool DisableIndexer bool
// Bedrock enabled Bedrock indexing.
Bedrock bool
BedrockL1StandardBridgeAddress common.Address
BedrockOptimismPortalAddress common.Address
} }
// NewConfig parses the Config from the provided flags or environment variables. // NewConfig parses the Config from the provided flags or environment variables.
...@@ -118,33 +105,30 @@ type Config struct { ...@@ -118,33 +105,30 @@ type Config struct {
func NewConfig(ctx *cli.Context) (Config, error) { func NewConfig(ctx *cli.Context) (Config, error) {
cfg := Config{ cfg := Config{
/* Required Flags */ /* Required Flags */
BuildEnv: ctx.GlobalString(flags.BuildEnvFlag.Name), ChainID: ctx.GlobalUint64(flags.ChainIDFlag.Name),
EthNetworkName: ctx.GlobalString(flags.EthNetworkNameFlag.Name), L1EthRpc: ctx.GlobalString(flags.L1EthRPCFlag.Name),
ChainID: ctx.GlobalInt64(flags.ChainIDFlag.Name), L2EthRpc: ctx.GlobalString(flags.L2EthRPCFlag.Name),
L1EthRpc: ctx.GlobalString(flags.L1EthRPCFlag.Name), L1AddressManagerAddress: ctx.GlobalString(flags.L1AddressManagerAddressFlag.Name),
L2EthRpc: ctx.GlobalString(flags.L2EthRPCFlag.Name), DBHost: ctx.GlobalString(flags.DBHostFlag.Name),
L2GenesisBlockHash: ctx.GlobalString(flags.L2GenesisBlockHashFlag.Name), DBPort: ctx.GlobalUint64(flags.DBPortFlag.Name),
DBHost: ctx.GlobalString(flags.DBHostFlag.Name), DBUser: ctx.GlobalString(flags.DBUserFlag.Name),
DBPort: ctx.GlobalUint64(flags.DBPortFlag.Name), DBPassword: ctx.GlobalString(flags.DBPasswordFlag.Name),
DBUser: ctx.GlobalString(flags.DBUserFlag.Name), DBName: ctx.GlobalString(flags.DBNameFlag.Name),
DBPassword: ctx.GlobalString(flags.DBPasswordFlag.Name),
DBName: ctx.GlobalString(flags.DBNameFlag.Name),
/* Optional Flags */ /* Optional Flags */
DisableIndexer: ctx.GlobalBool(flags.DisableIndexer.Name), Bedrock: ctx.GlobalBool(flags.BedrockFlag.Name),
LogLevel: ctx.GlobalString(flags.LogLevelFlag.Name), BedrockL1StandardBridgeAddress: common.HexToAddress(ctx.GlobalString(flags.BedrockL1StandardBridgeAddress.Name)),
LogTerminal: ctx.GlobalBool(flags.LogTerminalFlag.Name), BedrockOptimismPortalAddress: common.HexToAddress(ctx.GlobalString(flags.BedrockOptimismPortalAddress.Name)),
SentryEnable: ctx.GlobalBool(flags.SentryEnableFlag.Name), DisableIndexer: ctx.GlobalBool(flags.DisableIndexer.Name),
SentryDsn: ctx.GlobalString(flags.SentryDsnFlag.Name), LogLevel: ctx.GlobalString(flags.LogLevelFlag.Name),
SentryTraceRate: ctx.GlobalDuration(flags.SentryTraceRateFlag.Name), LogTerminal: ctx.GlobalBool(flags.LogTerminalFlag.Name),
StartBlockNumber: ctx.GlobalUint64(flags.StartBlockNumberFlag.Name), L1StartBlockNumber: ctx.GlobalUint64(flags.L1StartBlockNumberFlag.Name),
StartBlockHash: ctx.GlobalString(flags.StartBlockHashFlag.Name), ConfDepth: ctx.GlobalUint64(flags.ConfDepthFlag.Name),
ConfDepth: ctx.GlobalUint64(flags.ConfDepthFlag.Name), MaxHeaderBatchSize: ctx.GlobalUint64(flags.MaxHeaderBatchSizeFlag.Name),
MaxHeaderBatchSize: ctx.GlobalUint64(flags.MaxHeaderBatchSizeFlag.Name), MetricsServerEnable: ctx.GlobalBool(flags.MetricsServerEnableFlag.Name),
MetricsServerEnable: ctx.GlobalBool(flags.MetricsServerEnableFlag.Name), RESTHostname: ctx.GlobalString(flags.RESTHostnameFlag.Name),
RESTHostname: ctx.GlobalString(flags.RESTHostnameFlag.Name), RESTPort: ctx.GlobalUint64(flags.RESTPortFlag.Name),
RESTPort: ctx.GlobalUint64(flags.RESTPortFlag.Name), MetricsHostname: ctx.GlobalString(flags.MetricsHostnameFlag.Name),
MetricsHostname: ctx.GlobalString(flags.MetricsHostnameFlag.Name), MetricsPort: ctx.GlobalUint64(flags.MetricsPortFlag.Name),
MetricsPort: ctx.GlobalUint64(flags.MetricsPortFlag.Name),
} }
err := ValidateConfig(&cfg) err := ValidateConfig(&cfg)
...@@ -168,9 +152,8 @@ func ValidateConfig(cfg *Config) error { ...@@ -168,9 +152,8 @@ func ValidateConfig(cfg *Config) error {
return err return err
} }
// Ensure the Sentry Data Source Name is set when using Sentry. if cfg.Bedrock && (cfg.BedrockL1StandardBridgeAddress == common.Address{} || cfg.BedrockOptimismPortalAddress == common.Address{}) {
if cfg.SentryEnable && cfg.SentryDsn == "" { return errors.New("must specify l1 standard bridge and optimism portal addresses in bedrock mode")
return ErrSentryDSNNotSet
} }
return nil return nil
......
...@@ -197,6 +197,12 @@ func (d *Database) AddIndexedL1Block(block *IndexedL1Block) error { ...@@ -197,6 +197,12 @@ func (d *Database) AddIndexedL1Block(block *IndexedL1Block) error {
VALUES VALUES
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
` `
const updateWithdrawalStatement = `
UPDATE withdrawals SET (br_withdrawal_finalized_tx_hash, br_withdrawal_finalized_log_index, br_withdrawal_finalized_success) = ($1, $2, $3)
WHERE br_withdrawal_hash = $4
`
return txn(d.db, func(tx *sql.Tx) error { return txn(d.db, func(tx *sql.Tx) error {
_, err := tx.Exec( _, err := tx.Exec(
insertBlockStatement, insertBlockStatement,
...@@ -209,26 +215,39 @@ func (d *Database) AddIndexedL1Block(block *IndexedL1Block) error { ...@@ -209,26 +215,39 @@ func (d *Database) AddIndexedL1Block(block *IndexedL1Block) error {
return err return err
} }
if len(block.Deposits) == 0 { if len(block.Deposits) > 0 {
return nil for _, deposit := range block.Deposits {
_, err = tx.Exec(
insertDepositStatement,
NewGUID(),
deposit.FromAddress.String(),
deposit.ToAddress.String(),
deposit.L1Token.String(),
deposit.L2Token.String(),
deposit.Amount.String(),
deposit.TxHash.String(),
deposit.LogIndex,
block.Hash.String(),
deposit.Data,
)
if err != nil {
return err
}
}
} }
for _, deposit := range block.Deposits { if len(block.FinalizedWithdrawals) > 0 {
_, err = tx.Exec( for _, wd := range block.FinalizedWithdrawals {
insertDepositStatement, _, err = tx.Exec(
NewGUID(), updateWithdrawalStatement,
deposit.FromAddress.String(), wd.TxHash.String(),
deposit.ToAddress.String(), wd.LogIndex,
deposit.L1Token.String(), wd.Success,
deposit.L2Token.String(), wd.WithdrawalHash.String(),
deposit.Amount.String(), )
deposit.TxHash.String(), if err != nil {
deposit.LogIndex, return err
block.Hash.String(), }
deposit.Data,
)
if err != nil {
return err
} }
} }
...@@ -459,19 +478,21 @@ func (d *Database) GetWithdrawalBatch(hash common.Hash) (*StateBatchJSON, error) ...@@ -459,19 +478,21 @@ func (d *Database) GetWithdrawalBatch(hash common.Hash) (*StateBatchJSON, error)
// GetWithdrawalsByAddress returns the list of Withdrawals indexed for the given // GetWithdrawalsByAddress returns the list of Withdrawals indexed for the given
// address paginated by the given params. // address paginated by the given params.
func (d *Database) GetWithdrawalsByAddress(address common.Address, page PaginationParam) (*PaginatedWithdrawals, error) { func (d *Database) GetWithdrawalsByAddress(address common.Address, page PaginationParam, state FinalizationState) (*PaginatedWithdrawals, error) {
selectWithdrawalsStatement := fmt.Sprintf(` selectWithdrawalsStatement := fmt.Sprintf(`
SELECT SELECT
withdrawals.guid, withdrawals.from_address, withdrawals.to_address, withdrawals.guid, withdrawals.from_address, withdrawals.to_address,
withdrawals.amount, withdrawals.tx_hash, withdrawals.data, withdrawals.amount, withdrawals.tx_hash, withdrawals.data,
withdrawals.l1_token, withdrawals.l2_token, withdrawals.l1_token, withdrawals.l2_token,
l2_tokens.name, l2_tokens.symbol, l2_tokens.decimals, l2_tokens.name, l2_tokens.symbol, l2_tokens.decimals,
l2_blocks.number, l2_blocks.timestamp, withdrawals.br_withdrawal_hash l2_blocks.number, l2_blocks.timestamp, withdrawals.br_withdrawal_hash,
withdrawals.br_withdrawal_finalized_tx_hash, withdrawals.br_withdrawal_finalized_log_index,
withdrawals.br_withdrawal_finalized_success
FROM withdrawals FROM withdrawals
INNER JOIN l2_blocks ON withdrawals.block_hash=l2_blocks.hash INNER JOIN l2_blocks ON withdrawals.block_hash=l2_blocks.hash
INNER JOIN l2_tokens ON withdrawals.l2_token=l2_tokens.address INNER JOIN l2_tokens ON withdrawals.l2_token=l2_tokens.address
WHERE withdrawals.from_address = $1 %s ORDER BY l2_blocks.timestamp LIMIT $2 OFFSET $3; WHERE withdrawals.from_address = $1 %s ORDER BY l2_blocks.timestamp LIMIT $2 OFFSET $3;
`, FinalizationStateAny.SQL()) `, state.SQL())
var withdrawals []WithdrawalJSON var withdrawals []WithdrawalJSON
err := txn(d.db, func(tx *sql.Tx) error { err := txn(d.db, func(tx *sql.Tx) error {
...@@ -485,13 +506,16 @@ func (d *Database) GetWithdrawalsByAddress(address common.Address, page Paginati ...@@ -485,13 +506,16 @@ func (d *Database) GetWithdrawalsByAddress(address common.Address, page Paginati
var withdrawal WithdrawalJSON var withdrawal WithdrawalJSON
var l2Token Token var l2Token Token
var wdHash sql.NullString var wdHash sql.NullString
var finTxHash sql.NullString
var finLogIndex sql.NullInt32
var finSuccess sql.NullBool
if err := rows.Scan( if err := rows.Scan(
&withdrawal.GUID, &withdrawal.FromAddress, &withdrawal.ToAddress, &withdrawal.GUID, &withdrawal.FromAddress, &withdrawal.ToAddress,
&withdrawal.Amount, &withdrawal.TxHash, &withdrawal.Data, &withdrawal.Amount, &withdrawal.TxHash, &withdrawal.Data,
&withdrawal.L1Token, &l2Token.Address, &withdrawal.L1Token, &l2Token.Address,
&l2Token.Name, &l2Token.Symbol, &l2Token.Decimals, &l2Token.Name, &l2Token.Symbol, &l2Token.Decimals,
&withdrawal.BlockNumber, &withdrawal.BlockTimestamp, &withdrawal.BlockNumber, &withdrawal.BlockTimestamp,
&wdHash, &wdHash, &finTxHash, &finLogIndex, &finSuccess,
); err != nil { ); err != nil {
return err return err
} }
...@@ -499,6 +523,16 @@ func (d *Database) GetWithdrawalsByAddress(address common.Address, page Paginati ...@@ -499,6 +523,16 @@ func (d *Database) GetWithdrawalsByAddress(address common.Address, page Paginati
if wdHash.Valid { if wdHash.Valid {
withdrawal.BedrockWithdrawalHash = &wdHash.String withdrawal.BedrockWithdrawalHash = &wdHash.String
} }
if finTxHash.Valid {
withdrawal.BedrockFinalizedTxHash = &finTxHash.String
}
if finLogIndex.Valid {
idx := int(finLogIndex.Int32)
withdrawal.BedrockFinalizedLogIndex = &idx
}
if finSuccess.Valid {
withdrawal.BedrockFinalizedSuccess = &finSuccess.Bool
}
withdrawals = append(withdrawals, withdrawal) withdrawals = append(withdrawals, withdrawal)
} }
......
package db package db
import "github.com/ethereum/go-ethereum/common" import (
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/common"
)
var ETHL1Address common.Address var ETHL1Address common.Address
...@@ -13,14 +16,10 @@ var ETHL1Token = &Token{ ...@@ -13,14 +16,10 @@ var ETHL1Token = &Token{
Decimals: 18, Decimals: 18,
} }
// ETHL2Address is a placeholder address for differentiating ETH transactions
// from ERC20 transactions on L2.
var ETHL2Address = common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")
// ETHL2Token is a placeholder token for differentiating ETH transactions from // ETHL2Token is a placeholder token for differentiating ETH transactions from
// ERC20 transactions on L2. // ERC20 transactions on L2.
var ETHL2Token = &Token{ var ETHL2Token = &Token{
Address: ETHL2Address.String(), Address: predeploys.LegacyERC20ETH,
Name: "Ethereum", Name: "Ethereum",
Symbol: "ETH", Symbol: "ETH",
Decimals: 18, Decimals: 18,
......
...@@ -6,11 +6,12 @@ import ( ...@@ -6,11 +6,12 @@ import (
// IndexedL1Block contains the L1 block including the deposits in it. // IndexedL1Block contains the L1 block including the deposits in it.
type IndexedL1Block struct { type IndexedL1Block struct {
Hash common.Hash Hash common.Hash
ParentHash common.Hash ParentHash common.Hash
Number uint64 Number uint64
Timestamp uint64 Timestamp uint64
Deposits []Deposit Deposits []Deposit
FinalizedWithdrawals []FinalizedWithdrawal
} }
// String returns the block hash for the indexed l1 block. // String returns the block hash for the indexed l1 block.
......
...@@ -125,8 +125,8 @@ CREATE TABLE IF NOT EXISTS airdrops ( ...@@ -125,8 +125,8 @@ CREATE TABLE IF NOT EXISTS airdrops (
const updateWithdrawalsTable = ` const updateWithdrawalsTable = `
ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_hash VARCHAR NULL; ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_hash VARCHAR NULL;
ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_finalized_tx_hash VARCHAR NULL; ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_finalized_tx_hash VARCHAR NULL;
ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_finalized_log_index BOOLEAN NULL; ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_finalized_log_index INTEGER NULL;
ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_success BOOLEAN NULL; ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_finalized_success BOOLEAN NULL;
CREATE INDEX IF NOT EXISTS withdrawals_br_withdrawal_hash ON withdrawals(br_withdrawal_hash); CREATE INDEX IF NOT EXISTS withdrawals_br_withdrawal_hash ON withdrawals(br_withdrawal_hash);
` `
......
...@@ -27,19 +27,22 @@ func (w Withdrawal) String() string { ...@@ -27,19 +27,22 @@ func (w Withdrawal) String() string {
// WithdrawalJSON contains Withdrawal data suitable for JSON serialization. // WithdrawalJSON contains Withdrawal data suitable for JSON serialization.
type WithdrawalJSON struct { type WithdrawalJSON struct {
GUID string `json:"guid"` GUID string `json:"guid"`
FromAddress string `json:"from"` FromAddress string `json:"from"`
ToAddress string `json:"to"` ToAddress string `json:"to"`
L1Token string `json:"l1Token"` L1Token string `json:"l1Token"`
L2Token *Token `json:"l2Token"` L2Token *Token `json:"l2Token"`
Amount string `json:"amount"` Amount string `json:"amount"`
Data []byte `json:"data"` Data []byte `json:"data"`
LogIndex uint64 `json:"logIndex"` LogIndex uint64 `json:"logIndex"`
BlockNumber uint64 `json:"blockNumber"` BlockNumber uint64 `json:"blockNumber"`
BlockTimestamp string `json:"blockTimestamp"` BlockTimestamp string `json:"blockTimestamp"`
TxHash string `json:"transactionHash"` TxHash string `json:"transactionHash"`
Batch *StateBatchJSON `json:"batch"` Batch *StateBatchJSON `json:"batch"`
BedrockWithdrawalHash *string `json:"bedrockWithdrawalHash"` BedrockWithdrawalHash *string `json:"bedrockWithdrawalHash"`
BedrockFinalizedTxHash *string `json:"bedrockFinalizedTxHash"`
BedrockFinalizedLogIndex *int `json:"bedrockFinalizedLogIndex"`
BedrockFinalizedSuccess *bool `json:"bedrockFinalizedSuccess"`
} }
type FinalizationState int type FinalizationState int
...@@ -64,9 +67,9 @@ func ParseFinalizationState(in string) FinalizationState { ...@@ -64,9 +67,9 @@ func ParseFinalizationState(in string) FinalizationState {
func (f FinalizationState) SQL() string { func (f FinalizationState) SQL() string {
switch f { switch f {
case FinalizationStateFinalized: case FinalizationStateFinalized:
return "AND withdrawals.l1_block_hash IS NOT NULL" return "AND withdrawals.br_withdrawal_finalized_tx_hash IS NOT NULL"
case FinalizationStateUnfinalized: case FinalizationStateUnfinalized:
return "AND withdrawals.l2_block_hash IS NULL" return "AND withdrawals.br_withdrawal_finalized_tx_hash IS NULL"
} }
return "" return ""
......
...@@ -46,11 +46,11 @@ var ( ...@@ -46,11 +46,11 @@ var (
Required: true, Required: true,
EnvVar: prefixEnvVar("L2_ETH_RPC"), EnvVar: prefixEnvVar("L2_ETH_RPC"),
} }
L2GenesisBlockHashFlag = cli.StringFlag{ L1AddressManagerAddressFlag = cli.StringFlag{
Name: "l2-genesis-block-hash", Name: "l1-address-manager-address",
Usage: "Genesis block hash of the L2 chain", Usage: "Address of the L1 address manager",
Required: true, Required: true,
EnvVar: prefixEnvVar("L2_GENESIS_BLOCK_HASH"), EnvVar: prefixEnvVar("L1_ADDRESS_MANAGER_ADDRESS"),
} }
DBHostFlag = cli.StringFlag{ DBHostFlag = cli.StringFlag{
Name: "db-host", Name: "db-host",
...@@ -83,6 +83,23 @@ var ( ...@@ -83,6 +83,23 @@ var (
EnvVar: prefixEnvVar("DB_NAME"), EnvVar: prefixEnvVar("DB_NAME"),
} }
/* Bedrock Flags */
BedrockFlag = cli.BoolFlag{
Name: "bedrock",
Usage: "Whether or not this indexer should operate in Bedrock mode",
EnvVar: prefixEnvVar("BEDROCK"),
}
BedrockL1StandardBridgeAddress = cli.BoolFlag{
Name: "bedrock.l1-standard-bridge-address",
Usage: "Address of the L1 standard bridge",
EnvVar: prefixEnvVar("BEDROCK_L1_STANDARD_BRIDGE"),
}
BedrockOptimismPortalAddress = cli.BoolFlag{
Name: "bedrock.portal-address",
Usage: "Address of the portal",
EnvVar: prefixEnvVar("BEDROCK_OPTIMISM_PORTAL"),
}
/* Optional Flags */ /* Optional Flags */
DisableIndexer = cli.BoolFlag{ DisableIndexer = cli.BoolFlag{
...@@ -120,18 +137,12 @@ var ( ...@@ -120,18 +137,12 @@ var (
Value: 50 * time.Millisecond, Value: 50 * time.Millisecond,
EnvVar: prefixEnvVar("SENTRY_TRACE_RATE"), EnvVar: prefixEnvVar("SENTRY_TRACE_RATE"),
} }
StartBlockNumberFlag = cli.Uint64Flag{ L1StartBlockNumberFlag = cli.Uint64Flag{
Name: "start-block-number", Name: "start-block-number",
Usage: "The block number to start indexing from. Must be use together with start block hash", Usage: "The block number to start indexing from. Must be use together with start block hash",
Value: 0, Value: 0,
EnvVar: prefixEnvVar("START_BLOCK_NUMBER"), EnvVar: prefixEnvVar("START_BLOCK_NUMBER"),
} }
StartBlockHashFlag = cli.StringFlag{
Name: "start-block-hash",
Usage: "The block hash to start indexing from. Must be use together with start block number",
Value: "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3",
EnvVar: prefixEnvVar("START_BLOCK_HASH"),
}
ConfDepthFlag = cli.Uint64Flag{ ConfDepthFlag = cli.Uint64Flag{
Name: "conf-depth", Name: "conf-depth",
Usage: "The number of confirmations after which headers are considered confirmed", Usage: "The number of confirmations after which headers are considered confirmed",
...@@ -181,7 +192,7 @@ var requiredFlags = []cli.Flag{ ...@@ -181,7 +192,7 @@ var requiredFlags = []cli.Flag{
ChainIDFlag, ChainIDFlag,
L1EthRPCFlag, L1EthRPCFlag,
L2EthRPCFlag, L2EthRPCFlag,
L2GenesisBlockHashFlag, L1AddressManagerAddressFlag,
DBHostFlag, DBHostFlag,
DBPortFlag, DBPortFlag,
DBUserFlag, DBUserFlag,
...@@ -190,6 +201,9 @@ var requiredFlags = []cli.Flag{ ...@@ -190,6 +201,9 @@ var requiredFlags = []cli.Flag{
} }
var optionalFlags = []cli.Flag{ var optionalFlags = []cli.Flag{
BedrockFlag,
BedrockL1StandardBridgeAddress,
BedrockOptimismPortalAddress,
DisableIndexer, DisableIndexer,
LogLevelFlag, LogLevelFlag,
LogTerminalFlag, LogTerminalFlag,
...@@ -198,8 +212,7 @@ var optionalFlags = []cli.Flag{ ...@@ -198,8 +212,7 @@ var optionalFlags = []cli.Flag{
SentryTraceRateFlag, SentryTraceRateFlag,
ConfDepthFlag, ConfDepthFlag,
MaxHeaderBatchSizeFlag, MaxHeaderBatchSizeFlag,
StartBlockNumberFlag, L1StartBlockNumberFlag,
StartBlockHashFlag,
RESTHostnameFlag, RESTHostnameFlag,
RESTPortFlag, RESTPortFlag,
MetricsServerEnableFlag, MetricsServerEnableFlag,
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"time" "time"
"github.com/ethereum-optimism/optimism/indexer/services" "github.com/ethereum-optimism/optimism/indexer/services"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/indexer/metrics" "github.com/ethereum-optimism/optimism/indexer/metrics"
"github.com/ethereum-optimism/optimism/indexer/server" "github.com/ethereum-optimism/optimism/indexer/server"
...@@ -22,7 +23,6 @@ import ( ...@@ -22,7 +23,6 @@ import (
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
sentry "github.com/getsentry/sentry-go"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
...@@ -44,15 +44,9 @@ func Main(gitVersion string) func(ctx *cli.Context) error { ...@@ -44,15 +44,9 @@ func Main(gitVersion string) func(ctx *cli.Context) error {
return err return err
} }
// The call to defer is done here so that any errors logged from
// this point on are posted to Sentry before exiting.
if cfg.SentryEnable {
defer sentry.Flush(2 * time.Second)
}
log.Info("Initializing indexer") log.Info("Initializing indexer")
indexer, err := NewIndexer(cfg, gitVersion) indexer, err := NewIndexer(cfg)
if err != nil { if err != nil {
log.Error("Unable to create indexer", "error", err) log.Error("Unable to create indexer", "error", err)
return err return err
...@@ -87,32 +81,18 @@ type Indexer struct { ...@@ -87,32 +81,18 @@ type Indexer struct {
router *mux.Router router *mux.Router
metrics *metrics.Metrics metrics *metrics.Metrics
db *database.Database
server *http.Server
} }
// NewIndexer initializes the Indexer, gathering any resources // NewIndexer initializes the Indexer, gathering any resources
// that will be needed by the TxIndexer and StateIndexer // that will be needed by the TxIndexer and StateIndexer
// sub-services. // sub-services.
func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) { func NewIndexer(cfg Config) (*Indexer, error) {
ctx := context.Background() ctx := context.Background()
// Set up our logging. If Sentry is enabled, we will use our custom
// log handler that logs to stdout and forwards any error messages to
// Sentry for collection. Otherwise, logs will only be posted to stdout.
var logHandler log.Handler var logHandler log.Handler
if cfg.SentryEnable { if cfg.LogTerminal {
err := sentry.Init(sentry.ClientOptions{
Dsn: cfg.SentryDsn,
Environment: cfg.EthNetworkName,
Release: "indexer@" + gitVersion,
TracesSampleRate: traceRateToFloat64(cfg.SentryTraceRate),
Debug: false,
})
if err != nil {
return nil, err
}
logHandler = SentryStreamHandler(os.Stdout, log.JSONFormat())
} else if cfg.LogTerminal {
logHandler = log.StreamHandler(os.Stdout, log.TerminalFormat(true)) logHandler = log.StreamHandler(os.Stdout, log.TerminalFormat(true))
} else { } else {
logHandler = log.StreamHandler(os.Stdout, log.JSONFormat()) logHandler = log.StreamHandler(os.Stdout, log.JSONFormat())
...@@ -149,8 +129,11 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) { ...@@ -149,8 +129,11 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) {
log.Info("metrics server enabled", "host", cfg.MetricsHostname, "port", cfg.MetricsPort) log.Info("metrics server enabled", "host", cfg.MetricsHostname, "port", cfg.MetricsPort)
} }
dsn := fmt.Sprintf("host=%s port=%d user=%s dbname=%s sslmode=disable", dsn := fmt.Sprintf("host=%s port=%d dbname=%s sslmode=disable",
cfg.DBHost, cfg.DBPort, cfg.DBUser, cfg.DBName) cfg.DBHost, cfg.DBPort, cfg.DBName)
if cfg.DBUser != "" {
dsn += fmt.Sprintf(" user=%s", cfg.DBUser)
}
if cfg.DBPassword != "" { if cfg.DBPassword != "" {
dsn += fmt.Sprintf(" password=%s", cfg.DBPassword) dsn += fmt.Sprintf(" password=%s", cfg.DBPassword)
} }
...@@ -159,17 +142,32 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) { ...@@ -159,17 +142,32 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) {
return nil, err return nil, err
} }
var addrManager services.AddressManager
if cfg.Bedrock {
addrManager, err = services.NewBedrockAddresses(
l1Client,
cfg.BedrockL1StandardBridgeAddress,
cfg.BedrockOptimismPortalAddress,
)
} else {
addrManager, err = services.NewLegacyAddresses(l1Client, common.HexToAddress(cfg.L1AddressManagerAddress))
}
if err != nil {
return nil, err
}
l1IndexingService, err := l1.NewService(l1.ServiceConfig{ l1IndexingService, err := l1.NewService(l1.ServiceConfig{
Context: ctx, Context: ctx,
Metrics: m, Metrics: m,
L1Client: l1Client, L1Client: l1Client,
RawL1Client: rawl1Client, RawL1Client: rawl1Client,
ChainID: big.NewInt(cfg.ChainID), ChainID: new(big.Int).SetUint64(cfg.ChainID),
AddressManager: addrManager,
DB: db, DB: db,
ConfDepth: cfg.ConfDepth, ConfDepth: cfg.ConfDepth,
MaxHeaderBatchSize: cfg.MaxHeaderBatchSize, MaxHeaderBatchSize: cfg.MaxHeaderBatchSize,
StartBlockNumber: cfg.StartBlockNumber, StartBlockNumber: cfg.L1StartBlockNumber,
StartBlockHash: cfg.StartBlockHash, Bedrock: cfg.Bedrock,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -184,7 +182,7 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) { ...@@ -184,7 +182,7 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) {
ConfDepth: cfg.ConfDepth, ConfDepth: cfg.ConfDepth,
MaxHeaderBatchSize: cfg.MaxHeaderBatchSize, MaxHeaderBatchSize: cfg.MaxHeaderBatchSize,
StartBlockNumber: uint64(0), StartBlockNumber: uint64(0),
StartBlockHash: cfg.L2GenesisBlockHash, Bedrock: cfg.Bedrock,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -200,6 +198,7 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) { ...@@ -200,6 +198,7 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) {
airdropService: services.NewAirdrop(db, m), airdropService: services.NewAirdrop(db, m),
router: mux.NewRouter(), router: mux.NewRouter(),
metrics: m, metrics: m,
db: db,
}, nil }, nil
} }
...@@ -212,7 +211,7 @@ func (b *Indexer) Serve() error { ...@@ -212,7 +211,7 @@ func (b *Indexer) Serve() error {
b.router.HandleFunc("/v1/l1/status", b.l1IndexingService.GetIndexerStatus).Methods("GET") b.router.HandleFunc("/v1/l1/status", b.l1IndexingService.GetIndexerStatus).Methods("GET")
b.router.HandleFunc("/v1/l2/status", b.l2IndexingService.GetIndexerStatus).Methods("GET") b.router.HandleFunc("/v1/l2/status", b.l2IndexingService.GetIndexerStatus).Methods("GET")
b.router.HandleFunc("/v1/deposits/0x{address:[a-fA-F0-9]{40}}", b.l1IndexingService.GetDeposits).Methods("GET") b.router.HandleFunc("/v1/deposits/0x{address:[a-fA-F0-9]{40}}", b.l1IndexingService.GetDeposits).Methods("GET")
b.router.HandleFunc("/v1/withdrawal/0x{hash:[a-fA-F0-9]{64}}", b.l2IndexingService.GetWithdrawalStatus).Methods("GET") b.router.HandleFunc("/v1/withdrawal/0x{hash:[a-fA-F0-9]{64}}", b.l2IndexingService.GetWithdrawalBatch).Methods("GET")
b.router.HandleFunc("/v1/withdrawals/0x{address:[a-fA-F0-9]{40}}", b.l2IndexingService.GetWithdrawals).Methods("GET") b.router.HandleFunc("/v1/withdrawals/0x{address:[a-fA-F0-9]{40}}", b.l2IndexingService.GetWithdrawals).Methods("GET")
b.router.HandleFunc("/v1/airdrops/0x{address:[a-fA-F0-9]{40}}", b.airdropService.GetAirdrop) b.router.HandleFunc("/v1/airdrops/0x{address:[a-fA-F0-9]{40}}", b.airdropService.GetAirdrop)
b.router.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { b.router.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
...@@ -228,8 +227,27 @@ func (b *Indexer) Serve() error { ...@@ -228,8 +227,27 @@ func (b *Indexer) Serve() error {
port := strconv.FormatUint(b.cfg.RESTPort, 10) port := strconv.FormatUint(b.cfg.RESTPort, 10)
addr := net.JoinHostPort(b.cfg.RESTHostname, port) addr := net.JoinHostPort(b.cfg.RESTHostname, port)
log.Info("indexer REST server listening on", "addr", addr) b.server = &http.Server{
return http.ListenAndServe(addr, middleware(c.Handler(b.router))) Addr: addr,
Handler: middleware(c.Handler(b.router)),
}
errCh := make(chan error, 1)
go func() {
errCh <- b.server.ListenAndServe()
}()
// Capture server startup errors
<-time.After(10 * time.Millisecond)
select {
case err := <-errCh:
return err
default:
log.Info("indexer REST server listening on", "addr", addr)
return nil
}
} }
// Start starts the starts the indexing service on L1 and L2 chains and also // Start starts the starts the indexing service on L1 and L2 chains and also
...@@ -253,6 +271,14 @@ func (b *Indexer) Start() error { ...@@ -253,6 +271,14 @@ func (b *Indexer) Start() error {
// Stop stops the indexing service on L1 and L2 chains. // Stop stops the indexing service on L1 and L2 chains.
func (b *Indexer) Stop() { func (b *Indexer) Stop() {
b.db.Close()
if b.server != nil {
// background context here so it waits for
// conns to close
_ = b.server.Shutdown(context.Background())
}
if !b.cfg.DisableIndexer { if !b.cfg.DisableIndexer {
b.l1IndexingService.Stop() b.l1IndexingService.Stop()
b.l2IndexingService.Stop() b.l2IndexingService.Stop()
...@@ -274,14 +300,3 @@ func dialEthClientWithTimeout(ctx context.Context, url string) ( ...@@ -274,14 +300,3 @@ func dialEthClientWithTimeout(ctx context.Context, url string) (
} }
return ethclient.NewClient(c), c, nil return ethclient.NewClient(c), c, nil
} }
// traceRateToFloat64 converts a time.Duration into a valid float64 for the
// Sentry client. The client only accepts values between 0.0 and 1.0, so this
// method clamps anything greater than 1 second to 1.0.
func traceRateToFloat64(rate time.Duration) float64 {
rate64 := float64(rate) / float64(time.Second)
if rate64 > 1.0 {
rate64 = 1.0
}
return rate64
}
package integration_tests
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"math/big"
"net/http"
"os"
"testing"
"time"
"github.com/ethereum-optimism/optimism/indexer"
"github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/indexer/services/l1"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require"
_ "github.com/lib/pq"
)
func TestBedrockIndexer(t *testing.T) {
dbParams := createTestDB(t)
cfg := op_e2e.DefaultSystemConfig(t)
cfg.DeployConfig.FinalizationPeriodSeconds = 2
sys, err := cfg.Start()
require.NoError(t, err)
defer sys.Close()
l1Client := sys.Clients["l1"]
l2Client := sys.Clients["sequencer"]
fromAddr := cfg.Secrets.Addresses().Alice
// wait a couple of blocks
require.NoError(t, e2eutils.WaitBlock(e2eutils.TimeoutCtx(t, 30*time.Second), l2Client, 10))
l1SB, err := bindings.NewL1StandardBridge(predeploys.DevL1StandardBridgeAddr, l1Client)
require.NoError(t, err)
l2SB, err := bindings.NewL2StandardBridge(predeploys.L2StandardBridgeAddr, l2Client)
require.NoError(t, err)
portal, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
require.NoError(t, err)
l1Opts, err := bind.NewKeyedTransactorWithChainID(cfg.Secrets.Alice, cfg.L1ChainIDBig())
require.NoError(t, err)
l2Opts, err := bind.NewKeyedTransactorWithChainID(cfg.Secrets.Alice, cfg.L2ChainIDBig())
require.NoError(t, err)
idxrCfg := indexer.Config{
ChainID: cfg.DeployConfig.L1ChainID,
L1EthRpc: sys.Nodes["l1"].HTTPEndpoint(),
L2EthRpc: sys.Nodes["sequencer"].HTTPEndpoint(),
PollInterval: time.Second,
DBHost: dbParams.Host,
DBPort: dbParams.Port,
DBUser: dbParams.User,
DBPassword: dbParams.Password,
DBName: dbParams.Name,
LogLevel: "info",
LogTerminal: true,
L1StartBlockNumber: 0,
ConfDepth: 1,
MaxHeaderBatchSize: 2,
RESTHostname: "127.0.0.1",
RESTPort: 7980,
DisableIndexer: false,
Bedrock: true,
BedrockL1StandardBridgeAddress: predeploys.DevL1StandardBridgeAddr,
BedrockOptimismPortalAddress: predeploys.DevOptimismPortalAddr,
}
idxr, err := indexer.NewIndexer(idxrCfg)
require.NoError(t, err)
errCh := make(chan error, 1)
go func() {
errCh <- idxr.Start()
}()
t.Cleanup(func() {
idxr.Stop()
require.NoError(t, <-errCh)
})
makeURL := func(path string) string {
return fmt.Sprintf("http://%s:%d/%s", idxrCfg.RESTHostname, idxrCfg.RESTPort, path)
}
t.Run("deposit ETH", func(t *testing.T) {
l1Opts.Value = big.NewInt(params.Ether)
depTx, err := l1SB.DepositETH(l1Opts, 200_000, nil)
require.NoError(t, err)
depReceipt, err := e2eutils.WaitReceiptOK(e2eutils.TimeoutCtx(t, 10*time.Second), l1Client, depTx.Hash())
require.NoError(t, err)
require.Greaterf(t, len(depReceipt.Logs), 0, "must have logs")
var l2Hash common.Hash
for _, eLog := range depReceipt.Logs {
if len(eLog.Topics) == 0 || eLog.Topics[0] != derive.DepositEventABIHash {
continue
}
depLog, err := derive.UnmarshalDepositLogEvent(eLog)
require.NoError(t, err)
tx := types.NewTx(depLog)
l2Hash = tx.Hash()
}
require.NotEqual(t, common.Hash{}, l2Hash)
_, err = e2eutils.WaitReceiptOK(e2eutils.TimeoutCtx(t, 15*time.Second), l2Client, l2Hash)
require.NoError(t, err)
// Poll for indexer deposit
var depPage *db.PaginatedDeposits
require.NoError(t, e2eutils.WaitFor(e2eutils.TimeoutCtx(t, 30*time.Second), 100*time.Millisecond, func() (bool, error) {
res := new(db.PaginatedDeposits)
err := getJSON(makeURL(fmt.Sprintf("v1/deposits/%s", fromAddr)), res)
if err != nil {
return false, err
}
if len(res.Deposits) == 0 {
return false, nil
}
depPage = res
return true, nil
}))
// Make sure deposit is what we expect
require.Equal(t, 1, len(depPage.Deposits))
deposit := depPage.Deposits[0]
require.Equal(t, big.NewInt(params.Ether).String(), deposit.Amount)
require.Equal(t, depTx.Hash().String(), deposit.TxHash)
require.Equal(t, depReceipt.BlockNumber.Uint64(), deposit.BlockNumber)
require.Equal(t, fromAddr.String(), deposit.FromAddress)
require.Equal(t, fromAddr.String(), deposit.ToAddress)
require.EqualValues(t, db.ETHL1Token, deposit.L1Token)
require.Equal(t, l1.ZeroAddress.String(), deposit.L2Token)
require.NotEmpty(t, deposit.GUID)
// Perform withdrawal through bridge
l2Opts.Value = big.NewInt(0.5 * params.Ether)
wdTx, err := l2SB.Withdraw(l2Opts, predeploys.LegacyERC20ETHAddr, big.NewInt(0.5*params.Ether), 0, nil)
require.NoError(t, err)
wdReceipt, err := e2eutils.WaitReceiptOK(e2eutils.TimeoutCtx(t, 30*time.Second), l2Client, wdTx.Hash())
require.NoError(t, err)
var wdPage *db.PaginatedWithdrawals
require.NoError(t, e2eutils.WaitFor(e2eutils.TimeoutCtx(t, 30*time.Second), 100*time.Millisecond, func() (bool, error) {
res := new(db.PaginatedWithdrawals)
err := getJSON(makeURL(fmt.Sprintf("v1/withdrawals/%s", fromAddr)), res)
if err != nil {
return false, err
}
if len(res.Withdrawals) == 0 {
return false, nil
}
wdPage = res
return true, nil
}))
require.Equal(t, 1, len(wdPage.Withdrawals))
withdrawal := wdPage.Withdrawals[0]
require.Nil(t, withdrawal.BedrockFinalizedTxHash)
require.Equal(t, big.NewInt(0.5*params.Ether).String(), withdrawal.Amount)
require.Equal(t, wdTx.Hash().String(), withdrawal.TxHash)
require.Equal(t, wdReceipt.BlockNumber.Uint64(), withdrawal.BlockNumber)
// use fromaddr twice here because the user is withdrawing
// to themselves
require.Equal(t, fromAddr.String(), withdrawal.FromAddress)
require.Equal(t, fromAddr.String(), withdrawal.ToAddress)
require.EqualValues(t, l1.ZeroAddress.String(), withdrawal.L1Token)
require.Equal(t, db.ETHL2Token, withdrawal.L2Token)
require.NotEmpty(t, withdrawal.GUID)
finBlockNum, err := withdrawals.WaitForFinalizationPeriod(
e2eutils.TimeoutCtx(t, time.Minute),
l1Client,
predeploys.DevOptimismPortalAddr,
wdReceipt.BlockNumber,
)
require.NoError(t, err)
finHeader, err := l2Client.HeaderByNumber(context.Background(), big.NewInt(int64(finBlockNum)))
require.NoError(t, err)
rpcClient, err := rpc.Dial(sys.Nodes["sequencer"].HTTPEndpoint())
require.NoError(t, err)
proofClient := withdrawals.NewClient(rpcClient)
wParams, err := withdrawals.FinalizeWithdrawalParameters(context.Background(), proofClient, wdTx.Hash(), finHeader)
require.NoError(t, err)
l1Opts.Value = big.NewInt(0)
finTx, err := portal.FinalizeWithdrawalTransaction(
l1Opts,
bindings.TypesWithdrawalTransaction{
Nonce: wParams.Nonce,
Sender: wParams.Sender,
Target: wParams.Target,
Value: wParams.Value,
GasLimit: wParams.GasLimit,
Data: wParams.Data,
},
wParams.BlockNumber,
wParams.OutputRootProof,
wParams.WithdrawalProof,
)
require.NoError(t, err)
finReceipt, err := e2eutils.WaitReceiptOK(e2eutils.TimeoutCtx(t, time.Minute), l1Client, finTx.Hash())
require.NoError(t, err)
wdPage = nil
require.NoError(t, e2eutils.WaitFor(e2eutils.TimeoutCtx(t, 30*time.Second), 100*time.Millisecond, func() (bool, error) {
res := new(db.PaginatedWithdrawals)
err := getJSON(makeURL(fmt.Sprintf("v1/withdrawals/%s", fromAddr)), res)
if err != nil {
return false, err
}
if res.Withdrawals[0].BedrockFinalizedTxHash == nil {
return false, nil
}
wdPage = res
return true, nil
}))
wd := wdPage.Withdrawals[0]
require.Equal(t, finReceipt.TxHash.String(), *wd.BedrockFinalizedTxHash)
require.True(t, *wd.BedrockFinalizedSuccess)
wdPage = new(db.PaginatedWithdrawals)
err = getJSON(makeURL(fmt.Sprintf("v1/withdrawals/%s?finalized=false", fromAddr)), wdPage)
require.NoError(t, err)
require.Equal(t, 0, len(wdPage.Withdrawals))
})
}
type testDBParams struct {
Host string
Port uint64
User string
Password string
Name string
}
func createTestDB(t *testing.T) *testDBParams {
user := os.Getenv("DB_USER")
name := fmt.Sprintf("indexer_test_%d", time.Now().Unix())
dsn := "postgres://"
if user != "" {
dsn += user
dsn += "@"
}
dsn += "localhost:5432?sslmode=disable"
pg, err := sql.Open(
"postgres",
dsn,
)
require.NoError(t, err)
_, err = pg.Exec("CREATE DATABASE " + name)
require.NoError(t, err)
t.Cleanup(func() {
_, err = pg.Exec("DROP DATABASE " + name)
require.NoError(t, err)
pg.Close()
})
return &testDBParams{
Host: "localhost",
Port: 5432,
Name: name,
User: user,
}
}
func getJSON(url string, out interface{}) error {
res, err := http.Get(url)
if err != nil {
return err
}
if res.StatusCode != 200 {
return fmt.Errorf("non-200 status code %d", res.StatusCode)
}
defer res.Body.Close()
dec := json.NewDecoder(res.Body)
return dec.Decode(out)
}
...@@ -21,6 +21,8 @@ type Metrics struct { ...@@ -21,6 +21,8 @@ type Metrics struct {
WithdrawalsCount *prometheus.CounterVec WithdrawalsCount *prometheus.CounterVec
StateBatchesCount prometheus.Counter
L1CatchingUp prometheus.Gauge L1CatchingUp prometheus.Gauge
L2CatchingUp prometheus.Gauge L2CatchingUp prometheus.Gauge
...@@ -72,6 +74,12 @@ func NewMetrics(monitoredTokens map[string]string) *Metrics { ...@@ -72,6 +74,12 @@ func NewMetrics(monitoredTokens map[string]string) *Metrics {
"symbol", "symbol",
}), }),
StateBatchesCount: promauto.NewCounter(prometheus.CounterOpts{
Name: "state_batches_count",
Help: "The number of state batches indexed.",
Namespace: metricsNamespace,
}),
L1CatchingUp: promauto.NewGauge(prometheus.GaugeOpts{ L1CatchingUp: promauto.NewGauge(prometheus.GaugeOpts{
Name: "l1_catching_up", Name: "l1_catching_up",
Help: "Whether or not L1 is far behind the chain tip.", Help: "Whether or not L1 is far behind the chain tip.",
...@@ -160,6 +168,10 @@ func (m *Metrics) RecordWithdrawal(addr common.Address) { ...@@ -160,6 +168,10 @@ func (m *Metrics) RecordWithdrawal(addr common.Address) {
m.WithdrawalsCount.WithLabelValues(sym).Inc() m.WithdrawalsCount.WithLabelValues(sym).Inc()
} }
func (m *Metrics) RecordStateBatches(count int) {
m.StateBatchesCount.Add(float64(count))
}
func (m *Metrics) SetL1CatchingUp(state bool) { func (m *Metrics) SetL1CatchingUp(state bool) {
var catchingUp float64 var catchingUp float64
if state { if state {
......
{ {
"name": "@eth-optimism/indexer", "name": "@eth-optimism/indexer",
"version": "0.2.0", "version": "0.3.0",
"private": true, "private": true,
"license": "MIT" "license": "MIT"
} }
package indexer
import (
"errors"
"io"
"github.com/ethereum/go-ethereum/log"
"github.com/getsentry/sentry-go"
)
var jsonFmt = log.JSONFormat()
// SentryStreamHandler creates a log.Handler that behaves similarly to
// log.StreamHandler, however it writes any log with severity greater than or
// equal to log.LvlError to Sentry. In that case, the passed log.Record is
// encoded using JSON rather than the default terminal output, so that it can be
// captured for debugging in the Sentry dashboard.
func SentryStreamHandler(wr io.Writer, fmtr log.Format) log.Handler {
h := log.FuncHandler(func(r *log.Record) error {
_, err := wr.Write(fmtr.Format(r))
// If this record's severity is log.LvlError or higher,
// serialize the record using JSON and write it to Sentry. We
// also capture the error message separately so that it's easy
// to parse what the error is in the dashboard.
//
// NOTE: The log.Lvl* constants are defined in reverse order of
// their severity, i.e. zero (log.LvlCrit) is the highest
// severity.
if r.Lvl <= log.LvlError {
sentry.WithScope(func(scope *sentry.Scope) {
scope.SetExtra("context", jsonFmt.Format(r))
sentry.CaptureException(errors.New(r.Msg))
})
}
return err
})
return log.LazyHandler(log.SyncHandler(h))
}
package services
import (
"github.com/ethereum-optimism/optimism/indexer/bindings/legacy/scc"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)
type AddressManager interface {
L1StandardBridge() (common.Address, *bindings.L1StandardBridge)
StateCommitmentChain() (common.Address, *scc.StateCommitmentChain)
OptimismPortal() (common.Address, *bindings.OptimismPortal)
}
type LegacyAddresses struct {
l1SB *bindings.L1StandardBridge
l1SBAddr common.Address
scc *scc.StateCommitmentChain
sccAddr common.Address
}
var _ AddressManager = (*LegacyAddresses)(nil)
func NewLegacyAddresses(client bind.ContractBackend, addrMgrAddr common.Address) (AddressManager, error) {
mgr, err := bindings.NewAddressManager(addrMgrAddr, client)
if err != nil {
return nil, err
}
l1SBAddr, err := mgr.GetAddress(nil, "Proxy__OVM_L1StandardBridge")
if err != nil {
return nil, err
}
sccAddr, err := mgr.GetAddress(nil, "StateCommitmentChain")
if err != nil {
return nil, err
}
l1SB, err := bindings.NewL1StandardBridge(l1SBAddr, client)
if err != nil {
return nil, err
}
sccContract, err := scc.NewStateCommitmentChain(sccAddr, client)
if err != nil {
return nil, err
}
return &LegacyAddresses{
l1SB: l1SB,
l1SBAddr: l1SBAddr,
scc: sccContract,
sccAddr: sccAddr,
}, nil
}
func (a *LegacyAddresses) L1StandardBridge() (common.Address, *bindings.L1StandardBridge) {
return a.l1SBAddr, a.l1SB
}
func (a *LegacyAddresses) StateCommitmentChain() (common.Address, *scc.StateCommitmentChain) {
return a.sccAddr, a.scc
}
func (a *LegacyAddresses) OptimismPortal() (common.Address, *bindings.OptimismPortal) {
panic("OptimismPortal not configured on legacy networks - this is a programmer error")
}
type BedrockAddresses struct {
l1SB *bindings.L1StandardBridge
l1SBAddr common.Address
portal *bindings.OptimismPortal
portalAddr common.Address
}
var _ AddressManager = (*BedrockAddresses)(nil)
func NewBedrockAddresses(client bind.ContractBackend, l1SBAddr, portalAddr common.Address) (AddressManager, error) {
l1SB, err := bindings.NewL1StandardBridge(l1SBAddr, client)
if err != nil {
return nil, err
}
portal, err := bindings.NewOptimismPortal(portalAddr, client)
if err != nil {
return nil, err
}
return &BedrockAddresses{
l1SB: l1SB,
l1SBAddr: l1SBAddr,
portal: portal,
portalAddr: portalAddr,
}, nil
}
func (b *BedrockAddresses) L1StandardBridge() (common.Address, *bindings.L1StandardBridge) {
return b.l1SBAddr, b.l1SB
}
func (b *BedrockAddresses) StateCommitmentChain() (common.Address, *scc.StateCommitmentChain) {
panic("SCC not configured on legacy networks - this is a programmer error")
}
func (b *BedrockAddresses) OptimismPortal() (common.Address, *bindings.OptimismPortal) {
return b.portalAddr, b.portal
}
...@@ -5,93 +5,85 @@ import ( ...@@ -5,93 +5,85 @@ import (
"errors" "errors"
"math/big" "math/big"
"github.com/ethereum-optimism/optimism/indexer/bindings/legacy/scc"
"github.com/ethereum-optimism/optimism/indexer/db" "github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/indexer/services"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
// DepositsMap is a collection of deposit objects keyed
// on block hashes.
type DepositsMap map[common.Hash][]db.Deposit type DepositsMap map[common.Hash][]db.Deposit
type WithdrawalsMap map[common.Hash][]db.Withdrawal // Finalizations
// WithdrawalsMap is a collection of withdrawal objects keyed
// on block hashes.
type InitiatedWithdrawalMap map[common.Hash][]db.Withdrawal
// FinalizedWithdrawalsMap is a collection of finalized withdrawal
// objected keyed on block hashes.
type FinalizedWithdrawalsMap map[common.Hash][]db.FinalizedWithdrawal
type Bridge interface { type Bridge interface {
Address() common.Address Address() common.Address
GetDepositsByBlockRange(uint64, uint64) (DepositsMap, error) GetDepositsByBlockRange(context.Context, uint64, uint64) (DepositsMap, error)
GetWithdrawalsByBlockRange(uint64, uint64) (WithdrawalsMap, error)
String() string String() string
} }
type implConfig struct { type implConfig struct {
name string name string
impl string impl string
addr string addr common.Address
}
var defaultBridgeCfgs = map[uint64][]*implConfig{
// Devnet
900: {
{"Standard", "StandardBridge", predeploys.DevL1StandardBridge},
{"ETH", "ETHBridge", predeploys.DevL1StandardBridge},
},
// Goerli
5: {
{"Standard", "StandardBridge", "0xFf94B6C486350aD92561Ba09bad3a59df764Da92"},
{"ETH", "ETHBridge", "0xFf94B6C486350aD92561Ba09bad3a59df764Da92"},
},
} }
var customBridgeCfgs = map[uint64][]*implConfig{ var customBridgeCfgs = map[uint64][]*implConfig{
// Mainnet // Mainnet
1: { 1: {
{"BitBTC", "StandardBridge", "0xaBA2c5F108F7E820C049D5Af70B16ac266c8f128"}, {"BitBTC", "StandardBridge", common.HexToAddress("0xaBA2c5F108F7E820C049D5Af70B16ac266c8f128")},
{"DAI", "StandardBridge", "0x10E6593CDda8c58a1d0f14C5164B376352a55f2F"}, {"DAI", "StandardBridge", common.HexToAddress("0x10E6593CDda8c58a1d0f14C5164B376352a55f2F")},
{"wstETH", "StandardBridge", common.HexToAddress("0x76943C0D61395d8F2edF9060e1533529cAe05dE6")},
}, },
// Kovan // Kovan
42: { 42: {
{"BitBTC", "StandardBridge", "0x0b651A42F32069d62d5ECf4f2a7e5Bd3E9438746"}, {"BitBTC", "StandardBridge", common.HexToAddress("0x0b651A42F32069d62d5ECf4f2a7e5Bd3E9438746")},
{"USX", "StandardBridge", "0x40E862341b2416345F02c41Ac70df08525150dC7"}, {"USX", "StandardBridge", common.HexToAddress("0x40E862341b2416345F02c41Ac70df08525150dC7")},
{"DAI", "StandardBridge", "0xb415e822C4983ecD6B1c1596e8a5f976cf6CD9e3"}, {"DAI", "StandardBridge", common.HexToAddress("0xb415e822C4983ecD6B1c1596e8a5f976cf6CD9e3")},
{"wstETH", "StandardBridge", common.HexToAddress("0x65321bf24210b81500230dCEce14Faa70a9f50a7")},
}, },
} }
func BridgesByChainID(chainID *big.Int, client bind.ContractBackend, ctx context.Context) (map[string]Bridge, error) { func BridgesByChainID(chainID *big.Int, client bind.ContractBackend, addrs services.AddressManager) (map[string]Bridge, error) {
allCfgs := make([]*implConfig, 0) l1SBAddr, _ := addrs.L1StandardBridge()
allCfgs = append(allCfgs, defaultBridgeCfgs[chainID.Uint64()]...) allCfgs := []*implConfig{
{"Standard", "StandardBridge", l1SBAddr},
{"ETH", "ETHBridge", l1SBAddr},
}
allCfgs = append(allCfgs, customBridgeCfgs[chainID.Uint64()]...) allCfgs = append(allCfgs, customBridgeCfgs[chainID.Uint64()]...)
bridges := make(map[string]Bridge) bridges := make(map[string]Bridge)
for _, bridge := range allCfgs { for _, bridge := range allCfgs {
switch bridge.impl { switch bridge.impl {
case "StandardBridge": case "StandardBridge":
l1StandardBridgeAddress := common.HexToAddress(bridge.addr) l1SB, err := bindings.NewL1StandardBridge(bridge.addr, client)
l1StandardBridgeFilter, err := bindings.NewL1StandardBridgeFilterer(l1StandardBridgeAddress, client)
if err != nil { if err != nil {
return nil, err return nil, err
} }
standardBridge := &StandardBridge{ standardBridge := &StandardBridge{
name: bridge.name, name: bridge.name,
ctx: ctx, address: bridge.addr,
address: l1StandardBridgeAddress, contract: l1SB,
client: client,
filterer: l1StandardBridgeFilter,
} }
bridges[bridge.name] = standardBridge bridges[bridge.name] = standardBridge
case "ETHBridge": case "ETHBridge":
l1StandardBridgeAddress := common.HexToAddress(bridge.addr) l1SB, err := bindings.NewL1StandardBridge(bridge.addr, client)
l1EthBridgeFilter, err := bindings.NewL1StandardBridgeFilterer(l1StandardBridgeAddress, client)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ethBridge := &EthBridge{ ethBridge := &EthBridge{
name: bridge.name, name: bridge.name,
ctx: ctx, address: bridge.addr,
address: l1StandardBridgeAddress, contract: l1SB,
client: client,
filterer: l1EthBridgeFilter,
} }
bridges[bridge.name] = ethBridge bridges[bridge.name] = ethBridge
default: default:
...@@ -100,3 +92,12 @@ func BridgesByChainID(chainID *big.Int, client bind.ContractBackend, ctx context ...@@ -100,3 +92,12 @@ func BridgesByChainID(chainID *big.Int, client bind.ContractBackend, ctx context
} }
return bridges, nil return bridges, nil
} }
func StateCommitmentChainScanner(client bind.ContractFilterer, addrs services.AddressManager) (*scc.StateCommitmentChainFilterer, error) {
sccAddr, _ := addrs.StateCommitmentChain()
filter, err := scc.NewStateCommitmentChainFilterer(sccAddr, client)
if err != nil {
return nil, err
}
return filter, nil
}
package bridge
import (
"context"
"errors"
"math/big"
"github.com/ethereum-optimism/optimism/indexer/bindings/legacy/scc"
"github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/indexer/services"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)
// DepositsMap is a collection of deposit objects keyed
// on block hashes.
type DepositsMap map[common.Hash][]db.Deposit
<<<<<<< HEAD
// WithdrawalsMap is a collection of withdrawal objects keyed
// on block hashes.
type WithdrawalsMap map[common.Hash][]db.Withdrawal
// FinalizedWithdrawalsMap is a collection of finalized withdrawal
// objected keyed on block hashes.
=======
type InitiatedWithdrawalMap map[common.Hash][]db.Withdrawal
>>>>>>> 22c039efc (indexer: Upgrade L1 services)
type FinalizedWithdrawalsMap map[common.Hash][]db.FinalizedWithdrawal
type Bridge interface {
Address() common.Address
GetDepositsByBlockRange(context.Context, uint64, uint64) (DepositsMap, error)
String() string
}
type implConfig struct {
name string
impl string
addr common.Address
}
var customBridgeCfgs = map[uint64][]*implConfig{
// Mainnet
1: {
{"BitBTC", "StandardBridge", common.HexToAddress("0xaBA2c5F108F7E820C049D5Af70B16ac266c8f128")},
{"DAI", "StandardBridge", common.HexToAddress("0x10E6593CDda8c58a1d0f14C5164B376352a55f2F")},
{"wstETH", "StandardBridge", common.HexToAddress("0x76943C0D61395d8F2edF9060e1533529cAe05dE6")},
},
// Kovan
42: {
{"BitBTC", "StandardBridge", common.HexToAddress("0x0b651A42F32069d62d5ECf4f2a7e5Bd3E9438746")},
{"USX", "StandardBridge", common.HexToAddress("0x40E862341b2416345F02c41Ac70df08525150dC7")},
{"DAI", "StandardBridge", common.HexToAddress("0xb415e822C4983ecD6B1c1596e8a5f976cf6CD9e3")},
{"wstETH", "StandardBridge", common.HexToAddress("0x65321bf24210b81500230dCEce14Faa70a9f50a7")},
},
}
func BridgesByChainID(chainID *big.Int, client bind.ContractBackend, addrs services.AddressManager) (map[string]Bridge, error) {
l1SBAddr, _ := addrs.L1StandardBridge()
allCfgs := []*implConfig{
{"Standard", "StandardBridge", l1SBAddr},
{"ETH", "ETHBridge", l1SBAddr},
}
allCfgs = append(allCfgs, customBridgeCfgs[chainID.Uint64()]...)
bridges := make(map[string]Bridge)
for _, bridge := range allCfgs {
switch bridge.impl {
case "StandardBridge":
l1SB, err := bindings.NewL1StandardBridge(bridge.addr, client)
if err != nil {
return nil, err
}
standardBridge := &StandardBridge{
name: bridge.name,
address: bridge.addr,
contract: l1SB,
}
bridges[bridge.name] = standardBridge
case "ETHBridge":
l1SB, err := bindings.NewL1StandardBridge(bridge.addr, client)
if err != nil {
return nil, err
}
ethBridge := &EthBridge{
name: bridge.name,
address: bridge.addr,
contract: l1SB,
}
bridges[bridge.name] = ethBridge
default:
return nil, errors.New("unsupported bridge")
}
}
return bridges, nil
}
func StateCommitmentChainScanner(client bind.ContractFilterer, addrs services.AddressManager) (*scc.StateCommitmentChainFilterer, error) {
sccAddr, _ := addrs.StateCommitmentChain()
filter, err := scc.NewStateCommitmentChainFilterer(sccAddr, client)
if err != nil {
return nil, err
}
return filter, nil
}
...@@ -5,33 +5,40 @@ import ( ...@@ -5,33 +5,40 @@ import (
"github.com/ethereum-optimism/optimism/indexer/db" "github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-service/backoff"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
type EthBridge struct { type EthBridge struct {
name string name string
ctx context.Context
address common.Address address common.Address
client bind.ContractFilterer contract *bindings.L1StandardBridge
filterer *bindings.L1StandardBridgeFilterer
} }
func (e *EthBridge) Address() common.Address { func (e *EthBridge) Address() common.Address {
return e.address return e.address
} }
func (e *EthBridge) GetDepositsByBlockRange(start, end uint64) (DepositsMap, error) { func (e *EthBridge) GetDepositsByBlockRange(ctx context.Context, start, end uint64) (DepositsMap, error) {
depositsByBlockhash := make(DepositsMap) depositsByBlockhash := make(DepositsMap)
opts := &bind.FilterOpts{
Context: ctx,
Start: start,
End: &end,
}
iter, err := FilterETHDepositInitiatedWithRetry(e.ctx, e.filterer, &bind.FilterOpts{ var iter *bindings.L1StandardBridgeETHDepositInitiatedIterator
Start: start, err := backoff.Do(3, backoff.Exponential(), func() error {
End: &end, var err error
iter, err = e.contract.FilterETHDepositInitiated(opts, nil, nil)
return err
}) })
if err != nil { if err != nil {
logger.Error("Error fetching filter", "err", err) return nil, err
} }
defer iter.Close()
for iter.Next() { for iter.Next() {
depositsByBlockhash[iter.Event.Raw.BlockHash] = append( depositsByBlockhash[iter.Event.Raw.BlockHash] = append(
depositsByBlockhash[iter.Event.Raw.BlockHash], db.Deposit{ depositsByBlockhash[iter.Event.Raw.BlockHash], db.Deposit{
...@@ -43,41 +50,8 @@ func (e *EthBridge) GetDepositsByBlockRange(start, end uint64) (DepositsMap, err ...@@ -43,41 +50,8 @@ func (e *EthBridge) GetDepositsByBlockRange(start, end uint64) (DepositsMap, err
LogIndex: iter.Event.Raw.Index, LogIndex: iter.Event.Raw.Index,
}) })
} }
if err := iter.Error(); err != nil {
return nil, err
}
return depositsByBlockhash, nil
}
func (s *EthBridge) GetWithdrawalsByBlockRange(start, end uint64) (WithdrawalsMap, error) {
withdrawalsByBlockHash := make(WithdrawalsMap)
iter, err := FilterETHWithdrawalFinalizedWithRetry(s.ctx, s.filterer, &bind.FilterOpts{
Start: start,
End: &end,
})
if err != nil {
logger.Error("Error fetching filter", "err", err)
}
for iter.Next() {
withdrawalsByBlockHash[iter.Event.Raw.BlockHash] = append(
withdrawalsByBlockHash[iter.Event.Raw.BlockHash], db.Withdrawal{
TxHash: iter.Event.Raw.TxHash,
FromAddress: iter.Event.From,
ToAddress: iter.Event.To,
Amount: iter.Event.Amount,
Data: iter.Event.ExtraData,
LogIndex: iter.Event.Raw.Index,
})
}
if err := iter.Error(); err != nil {
return nil, err
}
return withdrawalsByBlockHash, nil return depositsByBlockhash, iter.Error()
} }
func (e *EthBridge) String() string { func (e *EthBridge) String() string {
......
...@@ -4,7 +4,7 @@ import ( ...@@ -4,7 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/indexer/bindings/legacy/scc"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
) )
...@@ -12,61 +12,13 @@ import ( ...@@ -12,61 +12,13 @@ import (
// calls. // calls.
var clientRetryInterval = 5 * time.Second var clientRetryInterval = 5 * time.Second
// FilterETHDepositInitiatedWithRetry retries the given func until it succeeds, // FilterStateBatchAppendedWithRetry retries the given func until it succeeds,
// waiting for clientRetryInterval duration after every call. // waiting for clientRetryInterval duration after every call.
func FilterETHDepositInitiatedWithRetry(ctx context.Context, filterer *bindings.L1StandardBridgeFilterer, opts *bind.FilterOpts) (*bindings.L1StandardBridgeETHDepositInitiatedIterator, error) { func FilterStateBatchAppendedWithRetry(ctx context.Context, filterer *scc.StateCommitmentChainFilterer, opts *bind.FilterOpts) (*scc.StateCommitmentChainStateBatchAppendedIterator, error) {
for { for {
ctxt, cancel := context.WithTimeout(ctx, DefaultConnectionTimeout) ctxt, cancel := context.WithTimeout(ctx, DefaultConnectionTimeout)
opts.Context = ctxt opts.Context = ctxt
res, err := filterer.FilterETHDepositInitiated(opts, nil, nil) res, err := filterer.FilterStateBatchAppended(opts, nil)
cancel()
if err == nil {
return res, nil
}
logger.Error("Error fetching filter", "err", err)
time.Sleep(clientRetryInterval)
}
}
// FilterERC20DepositInitiatedWithRetry retries the given func until it succeeds,
// waiting for clientRetryInterval duration after every call.
func FilterERC20DepositInitiatedWithRetry(ctx context.Context, filterer *bindings.L1StandardBridgeFilterer, opts *bind.FilterOpts) (*bindings.L1StandardBridgeERC20DepositInitiatedIterator, error) {
for {
ctxt, cancel := context.WithTimeout(ctx, DefaultConnectionTimeout)
opts.Context = ctxt
res, err := filterer.FilterERC20DepositInitiated(opts, nil, nil, nil)
cancel()
if err == nil {
return res, nil
}
logger.Error("Error fetching filter", "err", err)
time.Sleep(clientRetryInterval)
}
}
// FilterETHWithdrawalFinalizedWithRetry retries the given func until it succeeds,
// waiting for clientRetryInterval duration after every call.
func FilterETHWithdrawalFinalizedWithRetry(ctx context.Context, filterer *bindings.L1StandardBridgeFilterer, opts *bind.FilterOpts) (*bindings.L1StandardBridgeETHWithdrawalFinalizedIterator, error) {
for {
ctxt, cancel := context.WithTimeout(ctx, DefaultConnectionTimeout)
opts.Context = ctxt
res, err := filterer.FilterETHWithdrawalFinalized(opts, nil, nil)
cancel()
if err == nil {
return res, nil
}
logger.Error("Error fetching filter", "err", err)
time.Sleep(clientRetryInterval)
}
}
// FilterERC20WithdrawalFinalizedWithRetry retries the given func until it succeeds,
// waiting for clientRetryInterval duration after every call.
func FilterERC20WithdrawalFinalizedWithRetry(ctx context.Context, filterer *bindings.L1StandardBridgeFilterer, opts *bind.FilterOpts) (*bindings.L1StandardBridgeERC20WithdrawalFinalizedIterator, error) {
for {
ctxt, cancel := context.WithTimeout(ctx, DefaultConnectionTimeout)
opts.Context = ctxt
res, err := filterer.FilterERC20WithdrawalFinalized(opts, nil, nil, nil)
cancel() cancel()
if err == nil { if err == nil {
return res, nil return res, nil
......
package bridge
import (
"context"
"github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/indexer/services"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-service/backoff"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)
type Portal struct {
address common.Address
contract *bindings.OptimismPortal
}
func NewPortal(addrs services.AddressManager) *Portal {
address, contract := addrs.OptimismPortal()
return &Portal{
address: address,
contract: contract,
}
}
func (p *Portal) Address() common.Address {
return p.address
}
func (p *Portal) GetFinalizedWithdrawalsByBlockRange(ctx context.Context, start, end uint64) (FinalizedWithdrawalsMap, error) {
wdsByBlockHash := make(FinalizedWithdrawalsMap)
opts := &bind.FilterOpts{
Context: ctx,
Start: start,
End: &end,
}
var iter *bindings.OptimismPortalWithdrawalFinalizedIterator
err := backoff.Do(3, backoff.Exponential(), func() error {
var err error
iter, err = p.contract.FilterWithdrawalFinalized(opts, nil)
return err
})
if err != nil {
return nil, err
}
defer iter.Close()
for iter.Next() {
wdsByBlockHash[iter.Event.Raw.BlockHash] = append(
wdsByBlockHash[iter.Event.Raw.BlockHash], db.FinalizedWithdrawal{
TxHash: iter.Event.Raw.TxHash,
WithdrawalHash: iter.Event.WithdrawalHash,
Success: iter.Event.Success,
LogIndex: iter.Event.Raw.Index,
},
)
}
return wdsByBlockHash, iter.Error()
}
...@@ -5,33 +5,40 @@ import ( ...@@ -5,33 +5,40 @@ import (
"github.com/ethereum-optimism/optimism/indexer/db" "github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-service/backoff"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
type StandardBridge struct { type StandardBridge struct {
name string name string
ctx context.Context
address common.Address address common.Address
client bind.ContractFilterer contract *bindings.L1StandardBridge
filterer *bindings.L1StandardBridgeFilterer
} }
func (s *StandardBridge) Address() common.Address { func (s *StandardBridge) Address() common.Address {
return s.address return s.address
} }
func (s *StandardBridge) GetDepositsByBlockRange(start, end uint64) (DepositsMap, error) { func (s *StandardBridge) GetDepositsByBlockRange(ctx context.Context, start, end uint64) (DepositsMap, error) {
depositsByBlockhash := make(DepositsMap) depositsByBlockhash := make(DepositsMap)
opts := &bind.FilterOpts{
Context: ctx,
Start: start,
End: &end,
}
iter, err := FilterERC20DepositInitiatedWithRetry(s.ctx, s.filterer, &bind.FilterOpts{ var iter *bindings.L1StandardBridgeERC20DepositInitiatedIterator
Start: start, err := backoff.Do(3, backoff.Exponential(), func() error {
End: &end, var err error
iter, err = s.contract.FilterERC20DepositInitiated(opts, nil, nil, nil)
return err
}) })
if err != nil { if err != nil {
logger.Error("Error fetching filter", "err", err) return nil, err
} }
defer iter.Close()
for iter.Next() { for iter.Next() {
depositsByBlockhash[iter.Event.Raw.BlockHash] = append( depositsByBlockhash[iter.Event.Raw.BlockHash] = append(
depositsByBlockhash[iter.Event.Raw.BlockHash], db.Deposit{ depositsByBlockhash[iter.Event.Raw.BlockHash], db.Deposit{
...@@ -45,43 +52,8 @@ func (s *StandardBridge) GetDepositsByBlockRange(start, end uint64) (DepositsMap ...@@ -45,43 +52,8 @@ func (s *StandardBridge) GetDepositsByBlockRange(start, end uint64) (DepositsMap
LogIndex: iter.Event.Raw.Index, LogIndex: iter.Event.Raw.Index,
}) })
} }
if err := iter.Error(); err != nil {
return nil, err
}
return depositsByBlockhash, nil
}
func (s *StandardBridge) GetWithdrawalsByBlockRange(start, end uint64) (WithdrawalsMap, error) {
withdrawalsByBlockHash := make(WithdrawalsMap)
iter, err := FilterERC20WithdrawalFinalizedWithRetry(s.ctx, s.filterer, &bind.FilterOpts{
Start: start,
End: &end,
})
if err != nil {
logger.Error("Error fetching filter", "err", err)
}
for iter.Next() {
withdrawalsByBlockHash[iter.Event.Raw.BlockHash] = append(
withdrawalsByBlockHash[iter.Event.Raw.BlockHash], db.Withdrawal{
TxHash: iter.Event.Raw.TxHash,
L1Token: iter.Event.L1Token,
L2Token: iter.Event.L2Token,
FromAddress: iter.Event.From,
ToAddress: iter.Event.To,
Amount: iter.Event.Amount,
Data: iter.Event.ExtraData,
LogIndex: iter.Event.Raw.Index,
})
}
if err := iter.Error(); err != nil {
return nil, err
}
return withdrawalsByBlockHash, nil return depositsByBlockhash, iter.Error()
} }
func (s *StandardBridge) String() string { func (s *StandardBridge) String() string {
......
...@@ -17,9 +17,8 @@ import ( ...@@ -17,9 +17,8 @@ import (
) )
const ( const (
DefaultConnectionTimeout = 30 * time.Second DefaultConnectionTimeout = 30 * time.Second
DefaultConfDepth uint64 = 20 DefaultMaxBatchSize = 100
DefaultMaxBatchSize = 100
) )
type NewHeader struct { type NewHeader struct {
......
package l1 package l1
import ( import (
"github.com/ethereum/go-ethereum/ethclient" "context"
"github.com/ethereum-optimism/optimism/indexer/bindings/legacy/scc"
"github.com/ethereum-optimism/optimism/indexer/db" "github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/indexer/services/l1/bridge"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
func QueryERC20(address common.Address, client *ethclient.Client) (*db.Token, error) { func QueryStateBatches(filterer *scc.StateCommitmentChainFilterer, startHeight, endHeight uint64, ctx context.Context) (map[common.Hash][]db.StateBatch, error) {
contract, err := bindings.NewERC20(address, client) batches := make(map[common.Hash][]db.StateBatch)
if err != nil {
return nil, err
}
name, err := contract.Name(&bind.CallOpts{})
if err != nil {
return nil, err
}
symbol, err := contract.Symbol(&bind.CallOpts{}) iter, err := bridge.FilterStateBatchAppendedWithRetry(ctx, filterer, &bind.FilterOpts{
Start: startHeight,
End: &endHeight,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
decimals, err := contract.Decimals(&bind.CallOpts{}) defer iter.Close()
if err != nil { for iter.Next() {
return nil, err batches[iter.Event.Raw.BlockHash] = append(
batches[iter.Event.Raw.BlockHash], db.StateBatch{
Index: iter.Event.BatchIndex,
Root: iter.Event.BatchRoot,
Size: iter.Event.BatchSize,
PrevTotal: iter.Event.PrevTotalElements,
ExtraData: iter.Event.ExtraData,
BlockHash: iter.Event.Raw.BlockHash,
})
} }
return batches, iter.Error()
return &db.Token{
Name: name,
Symbol: symbol,
Decimals: decimals,
}, nil
} }
This diff is collapsed.
...@@ -7,75 +7,76 @@ import ( ...@@ -7,75 +7,76 @@ import (
"github.com/ethereum-optimism/optimism/indexer/db" "github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
type DepositsMap map[common.Hash][]db.Deposit // Finalizations
type WithdrawalsMap map[common.Hash][]db.Withdrawal type WithdrawalsMap map[common.Hash][]db.Withdrawal
type Bridge interface { type Bridge interface {
Address() common.Address Address() common.Address
GetDepositsByBlockRange(uint64, uint64) (DepositsMap, error) GetWithdrawalsByBlockRange(context.Context, uint64, uint64) (WithdrawalsMap, error)
GetWithdrawalsByBlockRange(uint64, uint64) (WithdrawalsMap, error)
String() string String() string
} }
type implConfig struct { type implConfig struct {
name string name string
impl string impl string
addr string addr common.Address
} }
var defaultBridgeCfgs = map[uint64][]*implConfig{ var defaultBridgeCfgs = []*implConfig{
// Devnet {"Standard", "StandardBridge", predeploys.L2StandardBridgeAddr},
901: {
{"Standard", "StandardBridge", L2StandardBridgeAddr},
},
// Goerli Alpha Testnet
28528: {
{"Standard", "StandardBridge", L2StandardBridgeAddr},
},
} }
var customBridgeCfgs = map[uint64][]*implConfig{ var customBridgeCfgs = map[uint64][]*implConfig{
// Mainnet // Mainnet
10: { 10: {
{"BitBTC", StandardBridgeImpl, "0x158F513096923fF2d3aab2BcF4478536de6725e2"}, {"BitBTC", StandardBridgeImpl, common.HexToAddress("0x158F513096923fF2d3aab2BcF4478536de6725e2")},
//{"DAI", "DAIBridge", "0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65"}, //{"DAI", "DAIBridge", "0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65"},
{"wstETH", StandardBridgeImpl, common.HexToAddress("0x8E01013243a96601a86eb3153F0d9Fa4fbFb6957")},
}, },
// Kovan // Kovan
69: { 69: {
{"BitBTC", StandardBridgeImpl, "0x0CFb46528a7002a7D8877a5F7a69b9AaF1A9058e"}, {"BitBTC", StandardBridgeImpl, common.HexToAddress("0x0CFb46528a7002a7D8877a5F7a69b9AaF1A9058e")},
{"USX", StandardBridgeImpl, "0xB4d37826b14Cd3CB7257A2A5094507d701fe715f"}, {"USX", StandardBridgeImpl, common.HexToAddress("0xB4d37826b14Cd3CB7257A2A5094507d701fe715f")},
{"wstETH", StandardBridgeImpl, common.HexToAddress("0x2E34e7d705AfaC3C4665b6feF31Aa394A1c81c92")},
//{"DAI", " DAIBridge", "0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65"}, //{"DAI", " DAIBridge", "0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65"},
}, },
} }
func BridgesByChainID(chainID *big.Int, client bind.ContractFilterer, ctx context.Context) (map[string]Bridge, error) { func BridgesByChainID(chainID *big.Int, client *ethclient.Client, isBedrock bool) (map[string]Bridge, error) {
allCfgs := make([]*implConfig, 0) allCfgs := make([]*implConfig, 0)
allCfgs = append(allCfgs, defaultBridgeCfgs[chainID.Uint64()]...) allCfgs = append(allCfgs, defaultBridgeCfgs...)
allCfgs = append(allCfgs, customBridgeCfgs[chainID.Uint64()]...) allCfgs = append(allCfgs, customBridgeCfgs[chainID.Uint64()]...)
var l2L1MP *bindings.L2ToL1MessagePasser
var err error
if isBedrock {
l2L1MP, err = bindings.NewL2ToL1MessagePasser(predeploys.L2ToL1MessagePasserAddr, client)
if err != nil {
return nil, err
}
}
bridges := make(map[string]Bridge) bridges := make(map[string]Bridge)
for _, bridge := range allCfgs { for _, bridge := range allCfgs {
switch bridge.impl { switch bridge.impl {
case "StandardBridge": case "StandardBridge":
l2StandardBridgeAddress := common.HexToAddress(bridge.addr) l2SB, err := bindings.NewL2StandardBridge(bridge.addr, client)
l2StandardBridgeFilter, err := bindings.NewL2StandardBridgeFilterer(l2StandardBridgeAddress, client)
if err != nil { if err != nil {
return nil, err return nil, err
} }
bridges[bridge.name] = &StandardBridge{
standardBridge := &StandardBridge{ name: bridge.name,
name: bridge.name, address: bridge.addr,
ctx: ctx, client: client,
address: l2StandardBridgeAddress, l2SB: l2SB,
client: client, l2L1MP: l2L1MP,
filterer: l2StandardBridgeFilter, isBedrock: isBedrock,
} }
bridges[bridge.name] = standardBridge
default: default:
return nil, errors.New("unsupported bridge") return nil, errors.New("unsupported bridge")
} }
......
package bridge
import (
"context"
"time"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
)
// clientRetryInterval is the interval to wait between retrying client API
// calls.
var clientRetryInterval = 5 * time.Second
// FilterWithdrawalInitiatedWithRetry retries the given func until it succeeds,
// waiting for clientRetryInterval duration after every call.
func FilterWithdrawalInitiatedWithRetry(ctx context.Context, filterer *bindings.L2StandardBridgeFilterer, opts *bind.FilterOpts) (*bindings.L2StandardBridgeWithdrawalInitiatedIterator, error) {
for {
ctxt, cancel := context.WithTimeout(ctx, DefaultConnectionTimeout)
opts.Context = ctxt
res, err := filterer.FilterWithdrawalInitiated(opts, nil, nil, nil)
cancel()
if err == nil {
return res, nil
}
logger.Error("Error fetching filter", "err", err)
time.Sleep(clientRetryInterval)
}
}
// FilterDepositFinalizedWithRetry retries the given func until it succeeds,
// waiting for clientRetryInterval duration after every call.
func FilterDepositFinalizedWithRetry(ctx context.Context, filterer *bindings.L2StandardBridgeFilterer, opts *bind.FilterOpts) (*bindings.L2StandardBridgeDepositFinalizedIterator, error) {
for {
ctxt, cancel := context.WithTimeout(ctx, DefaultConnectionTimeout)
opts.Context = ctxt
res, err := filterer.FilterDepositFinalized(opts, nil, nil, nil)
cancel()
if err == nil {
return res, nil
}
logger.Error("Error fetching filter", "err", err)
time.Sleep(clientRetryInterval)
}
}
...@@ -5,83 +5,112 @@ import ( ...@@ -5,83 +5,112 @@ import (
"github.com/ethereum-optimism/optimism/indexer/db" "github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
"github.com/ethereum-optimism/optimism/op-service/backoff"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
type StandardBridge struct { type StandardBridge struct {
name string name string
ctx context.Context address common.Address
address common.Address client *ethclient.Client
client bind.ContractFilterer l2SB *bindings.L2StandardBridge
filterer *bindings.L2StandardBridgeFilterer l2L1MP *bindings.L2ToL1MessagePasser
isBedrock bool
} }
func (s *StandardBridge) Address() common.Address { func (s *StandardBridge) Address() common.Address {
return s.address return s.address
} }
func (s *StandardBridge) GetDepositsByBlockRange(start, end uint64) (DepositsMap, error) { func (s *StandardBridge) GetWithdrawalsByBlockRange(ctx context.Context, start, end uint64) (WithdrawalsMap, error) {
depositsByBlockhash := make(DepositsMap) withdrawalsByBlockhash := make(map[common.Hash][]db.Withdrawal)
opts := &bind.FilterOpts{
Context: ctx,
Start: start,
End: &end,
}
iter, err := FilterDepositFinalizedWithRetry(s.ctx, s.filterer, &bind.FilterOpts{ var iter *bindings.L2StandardBridgeWithdrawalInitiatedIterator
Start: start, err := backoff.Do(3, backoff.Exponential(), func() error {
End: &end, var err error
iter, err = s.l2SB.FilterWithdrawalInitiated(opts, nil, nil, nil)
return err
}) })
if err != nil { if err != nil {
logger.Error("Error fetching filter", "err", err) return nil, err
} }
receipts := make(map[common.Hash]*types.Receipt)
defer iter.Close()
for iter.Next() { for iter.Next() {
depositsByBlockhash[iter.Event.Raw.BlockHash] = append( ev := iter.Event
depositsByBlockhash[iter.Event.Raw.BlockHash], db.Deposit{ if s.isBedrock {
TxHash: iter.Event.Raw.TxHash, receipt := receipts[ev.Raw.TxHash]
L1Token: iter.Event.L1Token, if receipt == nil {
L2Token: iter.Event.L2Token, receipt, err = s.client.TransactionReceipt(ctx, ev.Raw.TxHash)
FromAddress: iter.Event.From, if err != nil {
ToAddress: iter.Event.To, return nil, err
Amount: iter.Event.Amount, }
Data: iter.Event.ExtraData, receipts[ev.Raw.TxHash] = receipt
LogIndex: iter.Event.Raw.Index, }
})
}
if err := iter.Error(); err != nil {
return nil, err
}
return depositsByBlockhash, nil var withdrawalInitiated *bindings.L2ToL1MessagePasserMessagePassed
} for _, eLog := range receipt.Logs {
if len(eLog.Topics) == 0 || eLog.Topics[0] != withdrawals.MessagePassedTopic {
continue
}
func (s *StandardBridge) GetWithdrawalsByBlockRange(start, end uint64) (WithdrawalsMap, error) { if withdrawalInitiated != nil {
withdrawalsByBlockhash := make(map[common.Hash][]db.Withdrawal) logger.Warn("detected multiple withdrawal initiated events! ignoring", "tx_hash", ev.Raw.TxHash)
continue
}
iter, err := FilterWithdrawalInitiatedWithRetry(s.ctx, s.filterer, &bind.FilterOpts{ withdrawalInitiated, err = s.l2L1MP.ParseMessagePassed(*eLog)
Start: start, if err != nil {
End: &end, return nil, err
}) }
if err != nil { }
logger.Error("Error fetching filter", "err", err)
}
for iter.Next() { hash, err := withdrawals.WithdrawalHash(withdrawalInitiated)
withdrawalsByBlockhash[iter.Event.Raw.BlockHash] = append( if err != nil {
withdrawalsByBlockhash[iter.Event.Raw.BlockHash], db.Withdrawal{ return nil, err
TxHash: iter.Event.Raw.TxHash, }
L1Token: iter.Event.L1Token,
L2Token: iter.Event.L2Token, withdrawalsByBlockhash[ev.Raw.BlockHash] = append(
FromAddress: iter.Event.From, withdrawalsByBlockhash[ev.Raw.BlockHash], db.Withdrawal{
ToAddress: iter.Event.To, TxHash: ev.Raw.TxHash,
Amount: iter.Event.Amount, L1Token: ev.L1Token,
Data: iter.Event.ExtraData, L2Token: ev.L2Token,
LogIndex: iter.Event.Raw.Index, FromAddress: ev.From,
}) ToAddress: ev.To,
} Amount: ev.Amount,
if err := iter.Error(); err != nil { Data: ev.ExtraData,
return nil, err LogIndex: ev.Raw.Index,
BedrockHash: &hash,
},
)
} else {
withdrawalsByBlockhash[ev.Raw.BlockHash] = append(
withdrawalsByBlockhash[ev.Raw.BlockHash], db.Withdrawal{
TxHash: ev.Raw.TxHash,
L1Token: ev.L1Token,
L2Token: ev.L2Token,
FromAddress: ev.From,
ToAddress: ev.To,
Amount: ev.Amount,
Data: ev.ExtraData,
LogIndex: ev.Raw.Index,
},
)
}
} }
return withdrawalsByBlockhash, nil return withdrawalsByBlockhash, iter.Error()
} }
func (s *StandardBridge) String() string { func (s *StandardBridge) String() string {
......
...@@ -147,8 +147,7 @@ func (f *ConfirmedHeaderSelector) NewHead( ...@@ -147,8 +147,7 @@ func (f *ConfirmedHeaderSelector) NewHead(
return headers, nil return headers, nil
} }
func NewConfirmedHeaderSelector(cfg HeaderSelectorConfig) (*ConfirmedHeaderSelector, func NewConfirmedHeaderSelector(cfg HeaderSelectorConfig) (*ConfirmedHeaderSelector, error) {
error) {
if cfg.ConfDepth == 0 { if cfg.ConfDepth == 0 {
return nil, errors.New("ConfDepth must be greater than zero") return nil, errors.New("ConfDepth must be greater than zero")
} }
......
This diff is collapsed.
package l2 package query
import ( import (
"github.com/ethereum-optimism/optimism/indexer/db" "github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
) )
func QueryERC20(address common.Address, client *ethclient.Client) (*db.Token, error) { func NewERC20(address common.Address, client *ethclient.Client) (*db.Token, error) {
contract, err := bindings.NewERC20(address, client) contract, err := bindings.NewERC20(address, client)
if err != nil { if err != nil {
return nil, err return nil, err
......
package query
import (
"context"
"github.com/ethereum-optimism/optimism/op-service/backoff"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
)
// HeaderByNumberWithRetry retries getting headers.
func HeaderByNumberWithRetry(ctx context.Context, client *ethclient.Client) (*types.Header, error) {
var res *types.Header
err := backoff.DoCtx(ctx, 3, backoff.Exponential(), func() error {
var err error
res, err = client.HeaderByNumber(ctx, nil)
return err
})
return res, err
}
# @eth-optimism/integration-tests # @eth-optimism/integration-tests
## 0.5.21
### Patch Changes
- a3242d4f: Fix erc721 factory to match erc21 factory
## 0.5.20 ## 0.5.20
### Patch Changes ### Patch Changes
......
{ {
"private": true, "private": true,
"name": "@eth-optimism/integration-tests", "name": "@eth-optimism/integration-tests",
"version": "0.5.20", "version": "0.5.21",
"description": "[Optimism] Integration tests", "description": "[Optimism] Integration tests",
"scripts": { "scripts": {
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.5.4", "@babel/eslint-parser": "^7.5.4",
"@eth-optimism/contracts": "^0.5.37", "@eth-optimism/contracts": "^0.5.37",
"@eth-optimism/contracts-periphery": "^1.0.1", "@eth-optimism/contracts-periphery": "^1.0.2",
"@eth-optimism/core-utils": "0.10.1", "@eth-optimism/core-utils": "0.10.1",
"@eth-optimism/sdk": "1.6.6", "@eth-optimism/sdk": "1.6.7",
"@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-provider": "^5.7.0",
"@ethersproject/providers": "^5.7.0", "@ethersproject/providers": "^5.7.0",
"@ethersproject/transactions": "^5.7.0", "@ethersproject/transactions": "^5.7.0",
......
# Changelog # Changelog
## 0.5.25
### Patch Changes
- 89f1abfa: add --rpc.evmtimeout flag to configure timeout for eth_call
## 0.5.24 ## 0.5.24
### Patch Changes ### Patch Changes
......
{ {
"name": "@eth-optimism/l2geth", "name": "@eth-optimism/l2geth",
"version": "0.5.24", "version": "0.5.25",
"private": true, "private": true,
"devDependencies": {} "devDependencies": {}
} }
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const DeployerWhitelistStorageLayoutJSON = "{\"storage\":[{\"astId\":2853,\"contract\":\"contracts/legacy/DeployerWhitelist.sol:DeployerWhitelist\",\"label\":\"owner\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"},{\"astId\":2858,\"contract\":\"contracts/legacy/DeployerWhitelist.sol:DeployerWhitelist\",\"label\":\"whitelist\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_address,t_bool)\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"}}}" const DeployerWhitelistStorageLayoutJSON = "{\"storage\":[{\"astId\":2850,\"contract\":\"contracts/legacy/DeployerWhitelist.sol:DeployerWhitelist\",\"label\":\"owner\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"},{\"astId\":2855,\"contract\":\"contracts/legacy/DeployerWhitelist.sol:DeployerWhitelist\",\"label\":\"whitelist\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_address,t_bool)\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"}}}"
var DeployerWhitelistStorageLayout = new(solc.StorageLayout) var DeployerWhitelistStorageLayout = new(solc.StorageLayout)
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const GasPriceOracleStorageLayoutJSON = "{\"storage\":[{\"astId\":27829,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"},{\"astId\":1754,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"spacer_1_0_32\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_uint256\"},{\"astId\":1757,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"spacer_2_0_32\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_uint256\"},{\"astId\":1760,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"overhead\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_uint256\"},{\"astId\":1763,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"scalar\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_uint256\"},{\"astId\":1766,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"decimals\",\"offset\":0,\"slot\":\"5\",\"type\":\"t_uint256\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}" const GasPriceOracleStorageLayoutJSON = "{\"storage\":[{\"astId\":27823,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"},{\"astId\":1751,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"spacer_1_0_32\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_uint256\"},{\"astId\":1754,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"spacer_2_0_32\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_uint256\"},{\"astId\":1757,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"overhead\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_uint256\"},{\"astId\":1760,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"scalar\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_uint256\"},{\"astId\":1763,\"contract\":\"contracts/L2/GasPriceOracle.sol:GasPriceOracle\",\"label\":\"decimals\",\"offset\":0,\"slot\":\"5\",\"type\":\"t_uint256\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}"
var GasPriceOracleStorageLayout = new(solc.StorageLayout) var GasPriceOracleStorageLayout = new(solc.StorageLayout)
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const GovernanceTokenStorageLayoutJSON = "{\"storage\":[{\"astId\":28179,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_balances\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":28185,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_allowances\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_address,t_mapping(t_address,t_uint256))\"},{\"astId\":28187,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_totalSupply\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_uint256\"},{\"astId\":28189,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_name\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_string_storage\"},{\"astId\":28191,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_symbol\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_string_storage\"},{\"astId\":29556,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_nonces\",\"offset\":0,\"slot\":\"5\",\"type\":\"t_mapping(t_address,t_struct(Counter)30345_storage)\"},{\"astId\":29564,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_PERMIT_TYPEHASH_DEPRECATED_SLOT\",\"offset\":0,\"slot\":\"6\",\"type\":\"t_bytes32\"},{\"astId\":28897,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_delegates\",\"offset\":0,\"slot\":\"7\",\"type\":\"t_mapping(t_address,t_address)\"},{\"astId\":28903,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_checkpoints\",\"offset\":0,\"slot\":\"8\",\"type\":\"t_mapping(t_address,t_array(t_struct(Checkpoint)28888_storage)dyn_storage)\"},{\"astId\":28907,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_totalSupplyCheckpoints\",\"offset\":0,\"slot\":\"9\",\"type\":\"t_array(t_struct(Checkpoint)28888_storage)dyn_storage\"},{\"astId\":27829,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"10\",\"type\":\"t_address\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_struct(Checkpoint)28888_storage)dyn_storage\":{\"encoding\":\"dynamic_array\",\"label\":\"struct ERC20Votes.Checkpoint[]\",\"numberOfBytes\":\"32\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_address)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e address)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_address\"},\"t_mapping(t_address,t_array(t_struct(Checkpoint)28888_storage)dyn_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e struct ERC20Votes.Checkpoint[])\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_array(t_struct(Checkpoint)28888_storage)dyn_storage\"},\"t_mapping(t_address,t_mapping(t_address,t_uint256))\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e mapping(address =\u003e uint256))\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_mapping(t_address,t_uint256)\"},\"t_mapping(t_address,t_struct(Counter)30345_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e struct Counters.Counter)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_struct(Counter)30345_storage\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_string_storage\":{\"encoding\":\"bytes\",\"label\":\"string\",\"numberOfBytes\":\"32\"},\"t_struct(Checkpoint)28888_storage\":{\"encoding\":\"inplace\",\"label\":\"struct ERC20Votes.Checkpoint\",\"numberOfBytes\":\"32\"},\"t_struct(Counter)30345_storage\":{\"encoding\":\"inplace\",\"label\":\"struct Counters.Counter\",\"numberOfBytes\":\"32\"},\"t_uint224\":{\"encoding\":\"inplace\",\"label\":\"uint224\",\"numberOfBytes\":\"28\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint32\":{\"encoding\":\"inplace\",\"label\":\"uint32\",\"numberOfBytes\":\"4\"}}}" const GovernanceTokenStorageLayoutJSON = "{\"storage\":[{\"astId\":28173,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_balances\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":28179,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_allowances\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_address,t_mapping(t_address,t_uint256))\"},{\"astId\":28181,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_totalSupply\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_uint256\"},{\"astId\":28183,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_name\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_string_storage\"},{\"astId\":28185,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_symbol\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_string_storage\"},{\"astId\":29550,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_nonces\",\"offset\":0,\"slot\":\"5\",\"type\":\"t_mapping(t_address,t_struct(Counter)30339_storage)\"},{\"astId\":29558,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_PERMIT_TYPEHASH_DEPRECATED_SLOT\",\"offset\":0,\"slot\":\"6\",\"type\":\"t_bytes32\"},{\"astId\":28891,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_delegates\",\"offset\":0,\"slot\":\"7\",\"type\":\"t_mapping(t_address,t_address)\"},{\"astId\":28897,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_checkpoints\",\"offset\":0,\"slot\":\"8\",\"type\":\"t_mapping(t_address,t_array(t_struct(Checkpoint)28882_storage)dyn_storage)\"},{\"astId\":28901,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_totalSupplyCheckpoints\",\"offset\":0,\"slot\":\"9\",\"type\":\"t_array(t_struct(Checkpoint)28882_storage)dyn_storage\"},{\"astId\":27823,\"contract\":\"contracts/L2/GovernanceToken.sol:GovernanceToken\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"10\",\"type\":\"t_address\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_struct(Checkpoint)28882_storage)dyn_storage\":{\"encoding\":\"dynamic_array\",\"label\":\"struct ERC20Votes.Checkpoint[]\",\"numberOfBytes\":\"32\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_address)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e address)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_address\"},\"t_mapping(t_address,t_array(t_struct(Checkpoint)28882_storage)dyn_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e struct ERC20Votes.Checkpoint[])\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_array(t_struct(Checkpoint)28882_storage)dyn_storage\"},\"t_mapping(t_address,t_mapping(t_address,t_uint256))\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e mapping(address =\u003e uint256))\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_mapping(t_address,t_uint256)\"},\"t_mapping(t_address,t_struct(Counter)30339_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e struct Counters.Counter)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_struct(Counter)30339_storage\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_string_storage\":{\"encoding\":\"bytes\",\"label\":\"string\",\"numberOfBytes\":\"32\"},\"t_struct(Checkpoint)28882_storage\":{\"encoding\":\"inplace\",\"label\":\"struct ERC20Votes.Checkpoint\",\"numberOfBytes\":\"32\"},\"t_struct(Counter)30339_storage\":{\"encoding\":\"inplace\",\"label\":\"struct Counters.Counter\",\"numberOfBytes\":\"32\"},\"t_uint224\":{\"encoding\":\"inplace\",\"label\":\"uint224\",\"numberOfBytes\":\"28\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint32\":{\"encoding\":\"inplace\",\"label\":\"uint32\",\"numberOfBytes\":\"4\"}}}"
var GovernanceTokenStorageLayout = new(solc.StorageLayout) var GovernanceTokenStorageLayout = new(solc.StorageLayout)
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const L1BlockStorageLayoutJSON = "{\"storage\":[{\"astId\":2101,\"contract\":\"contracts/L2/L1Block.sol:L1Block\",\"label\":\"number\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint64\"},{\"astId\":2104,\"contract\":\"contracts/L2/L1Block.sol:L1Block\",\"label\":\"timestamp\",\"offset\":8,\"slot\":\"0\",\"type\":\"t_uint64\"},{\"astId\":2107,\"contract\":\"contracts/L2/L1Block.sol:L1Block\",\"label\":\"basefee\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_uint256\"},{\"astId\":2110,\"contract\":\"contracts/L2/L1Block.sol:L1Block\",\"label\":\"hash\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_bytes32\"},{\"astId\":2113,\"contract\":\"contracts/L2/L1Block.sol:L1Block\",\"label\":\"sequenceNumber\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_uint64\"}],\"types\":{\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"}}}" const L1BlockStorageLayoutJSON = "{\"storage\":[{\"astId\":2098,\"contract\":\"contracts/L2/L1Block.sol:L1Block\",\"label\":\"number\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint64\"},{\"astId\":2101,\"contract\":\"contracts/L2/L1Block.sol:L1Block\",\"label\":\"timestamp\",\"offset\":8,\"slot\":\"0\",\"type\":\"t_uint64\"},{\"astId\":2104,\"contract\":\"contracts/L2/L1Block.sol:L1Block\",\"label\":\"basefee\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_uint256\"},{\"astId\":2107,\"contract\":\"contracts/L2/L1Block.sol:L1Block\",\"label\":\"hash\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_bytes32\"},{\"astId\":2110,\"contract\":\"contracts/L2/L1Block.sol:L1Block\",\"label\":\"sequenceNumber\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_uint64\"}],\"types\":{\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"}}}"
var L1BlockStorageLayout = new(solc.StorageLayout) var L1BlockStorageLayout = new(solc.StorageLayout)
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const L1CrossDomainMessengerStorageLayoutJSON = "{\"storage\":[{\"astId\":24817,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"spacer_0_0_20\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"},{\"astId\":27206,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"_initialized\",\"offset\":20,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":27209,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"_initializing\",\"offset\":21,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":27820,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)50_storage\"},{\"astId\":27078,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":27198,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":27371,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":27476,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":27491,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"_status\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_uint256\"},{\"astId\":27535,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":24869,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"spacer_201_0_32\",\"offset\":0,\"slot\":\"201\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24874,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"spacer_202_0_32\",\"offset\":0,\"slot\":\"202\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24879,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"successfulMessages\",\"offset\":0,\"slot\":\"203\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24882,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"xDomainMsgSender\",\"offset\":0,\"slot\":\"204\",\"type\":\"t_address\"},{\"astId\":24885,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"msgNonce\",\"offset\":0,\"slot\":\"205\",\"type\":\"t_uint240\"},{\"astId\":24890,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"receivedMessages\",\"offset\":0,\"slot\":\"206\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24895,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"207\",\"type\":\"t_array(t_uint256)42_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)42_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[42]\",\"numberOfBytes\":\"1344\"},\"t_array(t_uint256)49_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)50_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_uint240\":{\"encoding\":\"inplace\",\"label\":\"uint240\",\"numberOfBytes\":\"30\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" const L1CrossDomainMessengerStorageLayoutJSON = "{\"storage\":[{\"astId\":24811,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"spacer_0_0_20\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"},{\"astId\":27200,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"_initialized\",\"offset\":20,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":27203,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"_initializing\",\"offset\":21,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":27814,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)50_storage\"},{\"astId\":27072,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":27192,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":27365,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":27470,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":27485,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"_status\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_uint256\"},{\"astId\":27529,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":24863,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"spacer_201_0_32\",\"offset\":0,\"slot\":\"201\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24868,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"spacer_202_0_32\",\"offset\":0,\"slot\":\"202\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24873,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"successfulMessages\",\"offset\":0,\"slot\":\"203\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24876,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"xDomainMsgSender\",\"offset\":0,\"slot\":\"204\",\"type\":\"t_address\"},{\"astId\":24879,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"msgNonce\",\"offset\":0,\"slot\":\"205\",\"type\":\"t_uint240\"},{\"astId\":24884,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"receivedMessages\",\"offset\":0,\"slot\":\"206\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24889,\"contract\":\"contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"207\",\"type\":\"t_array(t_uint256)42_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)42_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[42]\",\"numberOfBytes\":\"1344\"},\"t_array(t_uint256)49_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)50_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_uint240\":{\"encoding\":\"inplace\",\"label\":\"uint240\",\"numberOfBytes\":\"30\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}"
var L1CrossDomainMessengerStorageLayout = new(solc.StorageLayout) var L1CrossDomainMessengerStorageLayout = new(solc.StorageLayout)
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const L2CrossDomainMessengerStorageLayoutJSON = "{\"storage\":[{\"astId\":24817,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"spacer_0_0_20\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"},{\"astId\":27206,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"_initialized\",\"offset\":20,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":27209,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"_initializing\",\"offset\":21,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":27820,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)50_storage\"},{\"astId\":27078,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":27198,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":27371,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":27476,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":27491,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"_status\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_uint256\"},{\"astId\":27535,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":24869,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"spacer_201_0_32\",\"offset\":0,\"slot\":\"201\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24874,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"spacer_202_0_32\",\"offset\":0,\"slot\":\"202\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24879,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"successfulMessages\",\"offset\":0,\"slot\":\"203\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24882,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"xDomainMsgSender\",\"offset\":0,\"slot\":\"204\",\"type\":\"t_address\"},{\"astId\":24885,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"msgNonce\",\"offset\":0,\"slot\":\"205\",\"type\":\"t_uint240\"},{\"astId\":24890,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"receivedMessages\",\"offset\":0,\"slot\":\"206\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24895,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"207\",\"type\":\"t_array(t_uint256)42_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)42_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[42]\",\"numberOfBytes\":\"1344\"},\"t_array(t_uint256)49_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)50_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_uint240\":{\"encoding\":\"inplace\",\"label\":\"uint240\",\"numberOfBytes\":\"30\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" const L2CrossDomainMessengerStorageLayoutJSON = "{\"storage\":[{\"astId\":24811,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"spacer_0_0_20\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"},{\"astId\":27200,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"_initialized\",\"offset\":20,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":27203,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"_initializing\",\"offset\":21,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":27814,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)50_storage\"},{\"astId\":27072,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":27192,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":27365,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":27470,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":27485,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"_status\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_uint256\"},{\"astId\":27529,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_array(t_uint256)49_storage\"},{\"astId\":24863,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"spacer_201_0_32\",\"offset\":0,\"slot\":\"201\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24868,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"spacer_202_0_32\",\"offset\":0,\"slot\":\"202\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24873,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"successfulMessages\",\"offset\":0,\"slot\":\"203\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24876,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"xDomainMsgSender\",\"offset\":0,\"slot\":\"204\",\"type\":\"t_address\"},{\"astId\":24879,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"msgNonce\",\"offset\":0,\"slot\":\"205\",\"type\":\"t_uint240\"},{\"astId\":24884,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"receivedMessages\",\"offset\":0,\"slot\":\"206\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":24889,\"contract\":\"contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"207\",\"type\":\"t_array(t_uint256)42_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)42_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[42]\",\"numberOfBytes\":\"1344\"},\"t_array(t_uint256)49_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)50_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_uint240\":{\"encoding\":\"inplace\",\"label\":\"uint240\",\"numberOfBytes\":\"30\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}"
var L2CrossDomainMessengerStorageLayout = new(solc.StorageLayout) var L2CrossDomainMessengerStorageLayout = new(solc.StorageLayout)
......
This diff is collapsed.
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const L2StandardBridgeStorageLayoutJSON = "{\"storage\":[{\"astId\":26379,\"contract\":\"contracts/L2/L2StandardBridge.sol:L2StandardBridge\",\"label\":\"spacer_0_0_20\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"},{\"astId\":26382,\"contract\":\"contracts/L2/L2StandardBridge.sol:L2StandardBridge\",\"label\":\"spacer_1_0_20\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_address\"},{\"astId\":26389,\"contract\":\"contracts/L2/L2StandardBridge.sol:L2StandardBridge\",\"label\":\"deposits\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_mapping(t_address,t_mapping(t_address,t_uint256))\"},{\"astId\":26394,\"contract\":\"contracts/L2/L2StandardBridge.sol:L2StandardBridge\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_array(t_uint256)47_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)47_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[47]\",\"numberOfBytes\":\"1504\"},\"t_mapping(t_address,t_mapping(t_address,t_uint256))\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e mapping(address =\u003e uint256))\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_mapping(t_address,t_uint256)\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}" const L2StandardBridgeStorageLayoutJSON = "{\"storage\":[{\"astId\":26373,\"contract\":\"contracts/L2/L2StandardBridge.sol:L2StandardBridge\",\"label\":\"spacer_0_0_20\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"},{\"astId\":26376,\"contract\":\"contracts/L2/L2StandardBridge.sol:L2StandardBridge\",\"label\":\"spacer_1_0_20\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_address\"},{\"astId\":26383,\"contract\":\"contracts/L2/L2StandardBridge.sol:L2StandardBridge\",\"label\":\"deposits\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_mapping(t_address,t_mapping(t_address,t_uint256))\"},{\"astId\":26388,\"contract\":\"contracts/L2/L2StandardBridge.sol:L2StandardBridge\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_array(t_uint256)47_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)47_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[47]\",\"numberOfBytes\":\"1504\"},\"t_mapping(t_address,t_mapping(t_address,t_uint256))\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e mapping(address =\u003e uint256))\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_mapping(t_address,t_uint256)\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}"
var L2StandardBridgeStorageLayout = new(solc.StorageLayout) var L2StandardBridgeStorageLayout = new(solc.StorageLayout)
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const L2ToL1MessagePasserStorageLayoutJSON = "{\"storage\":[{\"astId\":2546,\"contract\":\"contracts/L2/L2ToL1MessagePasser.sol:L2ToL1MessagePasser\",\"label\":\"sentMessages\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":2549,\"contract\":\"contracts/L2/L2ToL1MessagePasser.sol:L2ToL1MessagePasser\",\"label\":\"nonce\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_uint256\"}],\"types\":{\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}" const L2ToL1MessagePasserStorageLayoutJSON = "{\"storage\":[{\"astId\":2543,\"contract\":\"contracts/L2/L2ToL1MessagePasser.sol:L2ToL1MessagePasser\",\"label\":\"sentMessages\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":2546,\"contract\":\"contracts/L2/L2ToL1MessagePasser.sol:L2ToL1MessagePasser\",\"label\":\"nonce\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_uint256\"}],\"types\":{\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}"
var L2ToL1MessagePasserStorageLayout = new(solc.StorageLayout) var L2ToL1MessagePasserStorageLayout = new(solc.StorageLayout)
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const LegacyERC20ETHStorageLayoutJSON = "{\"storage\":[{\"astId\":28179,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"_balances\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":28185,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"_allowances\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_address,t_mapping(t_address,t_uint256))\"},{\"astId\":28187,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"_totalSupply\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_uint256\"},{\"astId\":28189,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"_name\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_string_storage\"},{\"astId\":28191,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"_symbol\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_string_storage\"},{\"astId\":25292,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"remoteToken\",\"offset\":0,\"slot\":\"5\",\"type\":\"t_address\"},{\"astId\":25295,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"bridge\",\"offset\":0,\"slot\":\"6\",\"type\":\"t_address\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_mapping(t_address,t_mapping(t_address,t_uint256))\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e mapping(address =\u003e uint256))\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_mapping(t_address,t_uint256)\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_string_storage\":{\"encoding\":\"bytes\",\"label\":\"string\",\"numberOfBytes\":\"32\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}" const LegacyERC20ETHStorageLayoutJSON = "{\"storage\":[{\"astId\":28173,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"_balances\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":28179,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"_allowances\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_address,t_mapping(t_address,t_uint256))\"},{\"astId\":28181,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"_totalSupply\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_uint256\"},{\"astId\":28183,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"_name\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_string_storage\"},{\"astId\":28185,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"_symbol\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_string_storage\"},{\"astId\":25286,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"remoteToken\",\"offset\":0,\"slot\":\"5\",\"type\":\"t_address\"},{\"astId\":25289,\"contract\":\"contracts/legacy/LegacyERC20ETH.sol:LegacyERC20ETH\",\"label\":\"bridge\",\"offset\":0,\"slot\":\"6\",\"type\":\"t_address\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_mapping(t_address,t_mapping(t_address,t_uint256))\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e mapping(address =\u003e uint256))\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_mapping(t_address,t_uint256)\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_string_storage\":{\"encoding\":\"bytes\",\"label\":\"string\",\"numberOfBytes\":\"32\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}"
var LegacyERC20ETHStorageLayout = new(solc.StorageLayout) var LegacyERC20ETHStorageLayout = new(solc.StorageLayout)
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const LegacyMessagePasserStorageLayoutJSON = "{\"storage\":[{\"astId\":3496,\"contract\":\"contracts/legacy/LegacyMessagePasser.sol:LegacyMessagePasser\",\"label\":\"sentMessages\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_bytes32,t_bool)\"}],\"types\":{\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"}}}" const LegacyMessagePasserStorageLayoutJSON = "{\"storage\":[{\"astId\":3493,\"contract\":\"contracts/legacy/LegacyMessagePasser.sol:LegacyMessagePasser\",\"label\":\"sentMessages\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_bytes32,t_bool)\"}],\"types\":{\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"}}}"
var LegacyMessagePasserStorageLayout = new(solc.StorageLayout) var LegacyMessagePasserStorageLayout = new(solc.StorageLayout)
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const OptimismPortalStorageLayoutJSON = "{\"storage\":[{\"astId\":28019,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":28022,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1404,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"params\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_struct(ResourceParams)1374_storage\"},{\"astId\":1409,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_array(t_uint256)48_storage\"},{\"astId\":982,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"l2Sender\",\"offset\":0,\"slot\":\"50\",\"type\":\"t_address\"},{\"astId\":995,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"finalizedWithdrawals\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_mapping(t_bytes32,t_bool)\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)48_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[48]\",\"numberOfBytes\":\"1536\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_struct(ResourceParams)1374_storage\":{\"encoding\":\"inplace\",\"label\":\"struct ResourceMetering.ResourceParams\",\"numberOfBytes\":\"32\"},\"t_uint128\":{\"encoding\":\"inplace\",\"label\":\"uint128\",\"numberOfBytes\":\"16\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" const OptimismPortalStorageLayoutJSON = "{\"storage\":[{\"astId\":28013,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":28016,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1401,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"params\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_struct(ResourceParams)1371_storage\"},{\"astId\":1406,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_array(t_uint256)48_storage\"},{\"astId\":979,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"l2Sender\",\"offset\":0,\"slot\":\"50\",\"type\":\"t_address\"},{\"astId\":992,\"contract\":\"contracts/L1/OptimismPortal.sol:OptimismPortal\",\"label\":\"finalizedWithdrawals\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_mapping(t_bytes32,t_bool)\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)48_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[48]\",\"numberOfBytes\":\"1536\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_struct(ResourceParams)1371_storage\":{\"encoding\":\"inplace\",\"label\":\"struct ResourceMetering.ResourceParams\",\"numberOfBytes\":\"32\"},\"t_uint128\":{\"encoding\":\"inplace\",\"label\":\"uint128\",\"numberOfBytes\":\"16\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}"
var OptimismPortalStorageLayout = new(solc.StorageLayout) var OptimismPortalStorageLayout = new(solc.StorageLayout)
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const SequencerFeeVaultStorageLayoutJSON = "{\"storage\":[{\"astId\":2694,\"contract\":\"contracts/L2/SequencerFeeVault.sol:SequencerFeeVault\",\"label\":\"l1FeeWallet\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"}}}" const SequencerFeeVaultStorageLayoutJSON = "{\"storage\":[{\"astId\":2691,\"contract\":\"contracts/L2/SequencerFeeVault.sol:SequencerFeeVault\",\"label\":\"l1FeeWallet\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_address\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"}}}"
var SequencerFeeVaultStorageLayout = new(solc.StorageLayout) var SequencerFeeVaultStorageLayout = new(solc.StorageLayout)
......
...@@ -10,6 +10,7 @@ const ( ...@@ -10,6 +10,7 @@ const (
DevOptimismMintableERC20Factory = "0x6900000000000000000000000000000000000004" DevOptimismMintableERC20Factory = "0x6900000000000000000000000000000000000004"
DevAddressManager = "0x6900000000000000000000000000000000000005" DevAddressManager = "0x6900000000000000000000000000000000000005"
DevProxyAdmin = "0x6900000000000000000000000000000000000006" DevProxyAdmin = "0x6900000000000000000000000000000000000006"
DevWETH9 = "0x6900000000000000000000000000000000000007"
) )
var ( var (
...@@ -20,6 +21,7 @@ var ( ...@@ -20,6 +21,7 @@ var (
DevOptimismMintableERC20FactoryAddr = common.HexToAddress(DevOptimismMintableERC20Factory) DevOptimismMintableERC20FactoryAddr = common.HexToAddress(DevOptimismMintableERC20Factory)
DevAddressManagerAddr = common.HexToAddress(DevAddressManager) DevAddressManagerAddr = common.HexToAddress(DevAddressManager)
DevProxyAdminAddr = common.HexToAddress(DevProxyAdmin) DevProxyAdminAddr = common.HexToAddress(DevProxyAdmin)
DevWETH9Addr = common.HexToAddress(DevWETH9)
DevPredeploys = make(map[string]*common.Address) DevPredeploys = make(map[string]*common.Address)
) )
...@@ -32,4 +34,5 @@ func init() { ...@@ -32,4 +34,5 @@ func init() {
DevPredeploys["OptimismMintableERC20Factory"] = &DevOptimismMintableERC20FactoryAddr DevPredeploys["OptimismMintableERC20Factory"] = &DevOptimismMintableERC20FactoryAddr
DevPredeploys["AddressManager"] = &DevAddressManagerAddr DevPredeploys["AddressManager"] = &DevAddressManagerAddr
DevPredeploys["Admin"] = &DevProxyAdminAddr DevPredeploys["Admin"] = &DevProxyAdminAddr
DevPredeploys["WETH9"] = &DevWETH9Addr
} }
...@@ -73,7 +73,6 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) { ...@@ -73,7 +73,6 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) {
data, err := l2ooABI.Pack( data, err := l2ooABI.Pack(
"initialize", "initialize",
config.L2OutputOracleGenesisL2Output, config.L2OutputOracleGenesisL2Output,
big.NewInt(0),
config.L2OutputOracleProposer, config.L2OutputOracleProposer,
config.L2OutputOracleOwner, config.L2OutputOracleOwner,
) )
...@@ -166,6 +165,16 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) { ...@@ -166,6 +165,16 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) {
for name, proxyAddr := range predeploys.DevPredeploys { for name, proxyAddr := range predeploys.DevPredeploys {
memDB.SetState(*proxyAddr, ImplementationSlot, depsByName[name].Address.Hash()) memDB.SetState(*proxyAddr, ImplementationSlot, depsByName[name].Address.Hash())
// Special case for WETH since it was not designed to be behind a proxy
if name == "WETH9" {
name, _ := state.EncodeStringValue("Wrapped Ether", 0)
symbol, _ := state.EncodeStringValue("WETH", 0)
decimals, _ := state.EncodeUintValue(18, 0)
memDB.SetState(*proxyAddr, common.Hash{}, name)
memDB.SetState(*proxyAddr, common.Hash{31: 0x01}, symbol)
memDB.SetState(*proxyAddr, common.Hash{31: 0x02}, decimals)
}
} }
stateDB, err := backend.Blockchain().State() stateDB, err := backend.Blockchain().State()
...@@ -184,6 +193,7 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) { ...@@ -184,6 +193,7 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) {
memDB.CreateAccount(depAddr) memDB.CreateAccount(depAddr)
memDB.SetCode(depAddr, dep.Bytecode) memDB.SetCode(depAddr, dep.Bytecode)
for iter.Next() { for iter.Next() {
_, data, _, err := rlp.Split(iter.Value) _, data, _, err := rlp.Split(iter.Value)
if err != nil { if err != nil {
...@@ -251,6 +261,9 @@ func deployL1Contracts(config *DeployConfig, backend *backends.SimulatedBackend) ...@@ -251,6 +261,9 @@ func deployL1Contracts(config *DeployConfig, backend *backends.SimulatedBackend)
common.Address{19: 0x01}, common.Address{19: 0x01},
}, },
}, },
{
Name: "WETH9",
},
}...) }...)
return deployer.Deploy(backend, constructors, l1Deployer) return deployer.Deploy(backend, constructors, l1Deployer)
} }
...@@ -309,6 +322,11 @@ func l1Deployer(backend *backends.SimulatedBackend, opts *bind.TransactOpts, dep ...@@ -309,6 +322,11 @@ func l1Deployer(backend *backends.SimulatedBackend, opts *bind.TransactOpts, dep
backend, backend,
common.Address{}, common.Address{},
) )
case "WETH9":
_, tx, _, err = bindings.DeployWETH9(
opts,
backend,
)
default: default:
if strings.HasSuffix(deployment.Name, "Proxy") { if strings.HasSuffix(deployment.Name, "Proxy") {
_, tx, _, err = bindings.DeployProxy(opts, backend, deployer.TestAddress) _, tx, _, err = bindings.DeployProxy(opts, backend, deployer.TestAddress)
......
...@@ -92,6 +92,18 @@ func TestBuildL1DeveloperGenesis(t *testing.T) { ...@@ -92,6 +92,18 @@ func TestBuildL1DeveloperGenesis(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, predeploys.DevL1StandardBridgeAddr, bridgeAddr) require.Equal(t, predeploys.DevL1StandardBridgeAddr, bridgeAddr)
weth9, err := bindings.NewWETH9(predeploys.DevWETH9Addr, sim)
require.NoError(t, err)
decimals, err := weth9.Decimals(callOpts)
require.NoError(t, err)
require.Equal(t, uint8(18), decimals)
symbol, err := weth9.Symbol(callOpts)
require.NoError(t, err)
require.Equal(t, "WETH", symbol)
name, err := weth9.Name(callOpts)
require.NoError(t, err)
require.Equal(t, "Wrapped Ether", name)
// test that we can do deposits, etc. // test that we can do deposits, etc.
priv, err := crypto.HexToECDSA("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") priv, err := crypto.HexToECDSA("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")
require.NoError(t, err) require.NoError(t, err)
......
...@@ -106,6 +106,7 @@ func (s *L1Miner) ActL1IncludeTx(from common.Address) Action { ...@@ -106,6 +106,7 @@ func (s *L1Miner) ActL1IncludeTx(from common.Address) Action {
return return
} }
s.pendingIndices[from] = i + 1 // won't retry the tx s.pendingIndices[from] = i + 1 // won't retry the tx
s.l1BuildingState.Prepare(tx.Hash(), len(s.l1Transactions))
receipt, err := core.ApplyTransaction(s.l1Cfg.Config, s.l1Chain, &s.l1BuildingHeader.Coinbase, receipt, err := core.ApplyTransaction(s.l1Cfg.Config, s.l1Chain, &s.l1BuildingHeader.Coinbase,
s.l1GasPool, s.l1BuildingState, s.l1BuildingHeader, tx, &s.l1BuildingHeader.GasUsed, *s.l1Chain.GetVMConfig()) s.l1GasPool, s.l1BuildingState, s.l1BuildingHeader, tx, &s.l1BuildingHeader.GasUsed, *s.l1Chain.GetVMConfig())
if err != nil { if err != nil {
......
package actions
import (
"bytes"
"context"
"crypto/ecdsa"
"io"
"math/big"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
type SyncStatusAPI interface {
SyncStatus(ctx context.Context) (*eth.SyncStatus, error)
}
type BlocksAPI interface {
BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error)
}
type L1TxAPI interface {
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
SendTransaction(ctx context.Context, tx *types.Transaction) error
}
type BatcherCfg struct {
// Limit the size of txs
MinL1TxSize uint64
MaxL1TxSize uint64
BatcherKey *ecdsa.PrivateKey
}
// L2Batcher buffers and submits L2 batches to L1.
//
// TODO: note the batcher shares little logic/state with actual op-batcher,
// tests should only use this actor to build batch contents for rollup node actors to consume,
// until the op-batcher is refactored and can be covered better.
type L2Batcher struct {
log log.Logger
rollupCfg *rollup.Config
syncStatusAPI SyncStatusAPI
l2 BlocksAPI
l1 L1TxAPI
l1Signer types.Signer
l2ChannelOut *derive.ChannelOut
l2Submitting bool // when the channel out is being submitted, and not safe to write to without resetting
l2BufferedBlock eth.BlockID
l2SubmittedBlock eth.BlockID
l2BatcherCfg *BatcherCfg
}
func NewL2Batcher(log log.Logger, rollupCfg *rollup.Config, batcherCfg *BatcherCfg, api SyncStatusAPI, l1 L1TxAPI, l2 BlocksAPI) *L2Batcher {
return &L2Batcher{
log: log,
rollupCfg: rollupCfg,
syncStatusAPI: api,
l1: l1,
l2: l2,
l2BatcherCfg: batcherCfg,
l1Signer: types.LatestSignerForChainID(rollupCfg.L1ChainID),
}
}
// SubmittingData indicates if the actor is submitting buffer data.
// All data must be submitted before it can safely continue buffering more L2 blocks.
func (s *L2Batcher) SubmittingData() bool {
return s.l2Submitting
}
// ActL2BatchBuffer adds the next L2 block to the batch buffer.
// If the buffer is being submitted, the buffer is wiped.
func (s *L2Batcher) ActL2BatchBuffer(t Testing) {
if s.l2Submitting { // break ongoing submitting work if necessary
s.l2ChannelOut = nil
s.l2Submitting = false
}
syncStatus, err := s.syncStatusAPI.SyncStatus(t.Ctx())
require.NoError(t, err, "no sync status error")
// If we just started, start at safe-head
if s.l2SubmittedBlock == (eth.BlockID{}) {
s.log.Info("Starting batch-submitter work at safe-head", "safe", syncStatus.SafeL2)
s.l2SubmittedBlock = syncStatus.SafeL2.ID()
s.l2BufferedBlock = syncStatus.SafeL2.ID()
s.l2ChannelOut = nil
}
// If it's lagging behind, catch it up.
if s.l2SubmittedBlock.Number < syncStatus.SafeL2.Number {
s.log.Warn("last submitted block lagged behind L2 safe head: batch submission will continue from the safe head now", "last", s.l2SubmittedBlock, "safe", syncStatus.SafeL2)
s.l2SubmittedBlock = syncStatus.SafeL2.ID()
s.l2BufferedBlock = syncStatus.SafeL2.ID()
s.l2ChannelOut = nil
}
// Create channel if we don't have one yet
if s.l2ChannelOut == nil {
ch, err := derive.NewChannelOut()
require.NoError(t, err, "failed to create channel")
s.l2ChannelOut = ch
}
// Add the next unsafe block to the channel
if s.l2BufferedBlock.Number >= syncStatus.UnsafeL2.Number {
return
}
block, err := s.l2.BlockByNumber(t.Ctx(), big.NewInt(int64(s.l2BufferedBlock.Number+1)))
require.NoError(t, err, "need l2 block %d from sync status", s.l2SubmittedBlock.Number+1)
if block.ParentHash() != s.l2BufferedBlock.Hash {
s.log.Error("detected a reorg in L2 chain vs previous submitted information, resetting to safe head now", "safe_head", syncStatus.SafeL2)
s.l2SubmittedBlock = syncStatus.SafeL2.ID()
s.l2BufferedBlock = syncStatus.SafeL2.ID()
s.l2ChannelOut = nil
}
if err := s.l2ChannelOut.AddBlock(block); err != nil { // should always succeed
t.Fatalf("failed to add block to channel: %v", err)
}
}
func (s *L2Batcher) ActL2ChannelClose(t Testing) {
// Don't run this action if there's no data to submit
if s.l2ChannelOut == nil {
t.InvalidAction("need to buffer data first, cannot batch submit with empty buffer")
return
}
require.NoError(t, s.l2ChannelOut.Close(), "must close channel before submitting it")
}
// ActL2BatchSubmit constructs a batch tx from previous buffered L2 blocks, and submits it to L1
func (s *L2Batcher) ActL2BatchSubmit(t Testing) {
// Don't run this action if there's no data to submit
if s.l2ChannelOut == nil {
t.InvalidAction("need to buffer data first, cannot batch submit with empty buffer")
return
}
// Collect the output frame
data := new(bytes.Buffer)
data.WriteByte(derive.DerivationVersion0)
// subtract one, to account for the version byte
if err := s.l2ChannelOut.OutputFrame(data, s.l2BatcherCfg.MaxL1TxSize-1); err == io.EOF {
s.l2Submitting = false
// there may still be some data to submit
} else if err != nil {
s.l2Submitting = false
t.Fatalf("failed to output channel data to frame: %v", err)
}
nonce, err := s.l1.PendingNonceAt(t.Ctx(), s.rollupCfg.BatchSenderAddress)
require.NoError(t, err, "need batcher nonce")
gasTipCap := big.NewInt(2 * params.GWei)
pendingHeader, err := s.l1.HeaderByNumber(t.Ctx(), big.NewInt(-1))
require.NoError(t, err, "need l1 pending header for gas price estimation")
gasFeeCap := new(big.Int).Add(gasTipCap, new(big.Int).Mul(pendingHeader.BaseFee, big.NewInt(2)))
rawTx := &types.DynamicFeeTx{
ChainID: s.rollupCfg.L1ChainID,
Nonce: nonce,
To: &s.rollupCfg.BatchInboxAddress,
GasTipCap: gasTipCap,
GasFeeCap: gasFeeCap,
Data: data.Bytes(),
}
gas, err := core.IntrinsicGas(rawTx.Data, nil, false, true, true)
require.NoError(t, err, "need to compute intrinsic gas")
rawTx.Gas = gas
tx, err := types.SignNewTx(s.l2BatcherCfg.BatcherKey, s.l1Signer, rawTx)
require.NoError(t, err, "need to sign tx")
err = s.l1.SendTransaction(t.Ctx(), tx)
require.NoError(t, err, "need to send tx")
}
package actions
import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
func TestBatcher(gt *testing.T) {
t := NewDefaultTesting(gt)
p := &e2eutils.TestParams{
MaxSequencerDrift: 20, // larger than L1 block time we simulate in this test (12)
SequencerWindowSize: 24,
ChannelTimeout: 20,
}
dp := e2eutils.MakeDeployParams(t, p)
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlDebug)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg))
rollupSeqCl := sequencer.RollupClient()
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient())
// Alice makes a L2 tx
cl := seqEngine.EthClient()
n, err := cl.PendingNonceAt(t.Ctx(), dp.Addresses.Alice)
require.NoError(t, err)
signer := types.LatestSigner(sd.L2Cfg.Config)
tx := types.MustSignNewTx(dp.Secrets.Alice, signer, &types.DynamicFeeTx{
ChainID: sd.L2Cfg.Config.ChainID,
Nonce: n,
GasTipCap: big.NewInt(2 * params.GWei),
GasFeeCap: new(big.Int).Add(miner.l1Chain.CurrentBlock().BaseFee(), big.NewInt(2*params.GWei)),
Gas: params.TxGas,
To: &dp.Addresses.Bob,
Value: e2eutils.Ether(2),
})
require.NoError(gt, cl.SendTransaction(t.Ctx(), tx))
sequencer.ActL2PipelineFull(t)
verifier.ActL2PipelineFull(t)
// Make L2 block
sequencer.ActL2StartBlock(t)
seqEngine.ActL2IncludeTx(dp.Addresses.Alice)(t)
sequencer.ActL2EndBlock(t)
// batch submit to L1
batcher.ActL2BatchBuffer(t)
batcher.ActL2ChannelClose(t)
batcher.ActL2BatchSubmit(t)
// confirm batch on L1
miner.ActL1StartBlock(12)(t)
miner.ActL1IncludeTx(dp.Addresses.Batcher)(t)
miner.ActL1EndBlock(t)
bl := miner.l1Chain.CurrentBlock()
log.Info("bl", "txs", len(bl.Transactions()))
// Now make enough L1 blocks that the verifier will have to derive a L2 block
for i := uint64(1); i < sd.RollupCfg.SeqWindowSize; i++ {
miner.ActL1StartBlock(12)(t)
miner.ActL1EndBlock(t)
}
// sync verifier from L1 batch in otherwise empty sequence window
verifier.ActL1HeadSignal(t)
verifier.ActL2PipelineFull(t)
require.Equal(t, uint64(1), verifier.SyncStatus().SafeL2.L1Origin.Number)
// check that the tx from alice made it into the L2 chain
verifCl := verifEngine.EthClient()
vTx, isPending, err := verifCl.TransactionByHash(t.Ctx(), tx.Hash())
require.NoError(t, err)
require.False(t, isPending)
require.NotNil(t, vTx)
}
...@@ -174,6 +174,7 @@ func (e *L2Engine) ActL2IncludeTx(from common.Address) Action { ...@@ -174,6 +174,7 @@ func (e *L2Engine) ActL2IncludeTx(from common.Address) Action {
return return
} }
e.pendingIndices[from] = i + 1 // won't retry the tx e.pendingIndices[from] = i + 1 // won't retry the tx
e.l2BuildingState.Prepare(tx.Hash(), len(e.l2Transactions))
receipt, err := core.ApplyTransaction(e.l2Cfg.Config, e.l2Chain, &e.l2BuildingHeader.Coinbase, receipt, err := core.ApplyTransaction(e.l2Cfg.Config, e.l2Chain, &e.l2BuildingHeader.Coinbase,
e.l2GasPool, e.l2BuildingState, e.l2BuildingHeader, tx, &e.l2BuildingHeader.GasUsed, *e.l2Chain.GetVMConfig()) e.l2GasPool, e.l2BuildingState, e.l2BuildingHeader, tx, &e.l2BuildingHeader.GasUsed, *e.l2Chain.GetVMConfig())
if err != nil { if err != nil {
......
This diff is collapsed.
package actions
import (
"math/rand"
"testing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
)
func TestCrossLayerUser(gt *testing.T) {
t := NewDefaultTesting(gt)
dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams)
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlDebug)
miner, seqEngine, seq := setupSequencerTest(t, sd, log)
// need to start derivation before we can make L2 blocks
seq.ActL2PipelineFull(t)
l1Cl := miner.EthClient()
l2Cl := seqEngine.EthClient()
withdrawalsCl := &withdrawals.Client{} // TODO: need a rollup node actor to wrap for output root proof RPC
addresses := e2eutils.CollectAddresses(sd, dp)
l1UserEnv := &BasicUserEnv[*L1Bindings]{
EthCl: l1Cl,
Signer: types.LatestSigner(sd.L1Cfg.Config),
AddressCorpora: addresses,
Bindings: NewL1Bindings(t, l1Cl, &sd.DeploymentsL1),
}
l2UserEnv := &BasicUserEnv[*L2Bindings]{
EthCl: l2Cl,
Signer: types.LatestSigner(sd.L2Cfg.Config),
AddressCorpora: addresses,
Bindings: NewL2Bindings(t, l2Cl, withdrawalsCl),
}
alice := NewCrossLayerUser(log, dp.Secrets.Alice, rand.New(rand.NewSource(1234)))
alice.L1.SetUserEnv(l1UserEnv)
alice.L2.SetUserEnv(l2UserEnv)
// regular L2 tx, in new L2 block
alice.L2.ActResetTxOpts(t)
alice.L2.ActSetTxToAddr(&dp.Addresses.Bob)(t)
alice.L2.ActMakeTx(t)
seq.ActL2StartBlock(t)
seqEngine.ActL2IncludeTx(alice.Address())(t)
seq.ActL2EndBlock(t)
alice.L2.ActCheckReceiptStatusOfLastTx(true)(t)
// regular L1 tx, in new L1 block
alice.L1.ActResetTxOpts(t)
alice.L1.ActSetTxToAddr(&dp.Addresses.Bob)(t)
alice.L1.ActMakeTx(t)
miner.ActL1StartBlock(12)(t)
miner.ActL1IncludeTx(alice.Address())(t)
miner.ActL1EndBlock(t)
alice.L1.ActCheckReceiptStatusOfLastTx(true)(t)
// regular Deposit, in new L1 block
alice.ActDeposit(t)
miner.ActL1StartBlock(12)(t)
miner.ActL1IncludeTx(alice.Address())(t)
miner.ActL1EndBlock(t)
seq.ActL1HeadSignal(t)
// sync sequencer build enough blocks to adopt latest L1 origin
for seq.SyncStatus().UnsafeL2.L1Origin.Number < miner.l1Chain.CurrentBlock().NumberU64() {
seq.ActL2StartBlock(t)
seq.ActL2EndBlock(t)
}
// Now that the L2 chain adopted the latest L1 block, check that we processed the deposit
alice.ActCheckDepositStatus(true, true)(t)
}
...@@ -43,7 +43,7 @@ func NewRPC(ctx context.Context, lgr log.Logger, addr string, opts ...rpc.Client ...@@ -43,7 +43,7 @@ func NewRPC(ctx context.Context, lgr log.Logger, addr string, opts ...rpc.Client
func DialRPCClientWithBackoff(ctx context.Context, log log.Logger, addr string, opts ...rpc.ClientOption) (*rpc.Client, error) { func DialRPCClientWithBackoff(ctx context.Context, log log.Logger, addr string, opts ...rpc.ClientOption) (*rpc.Client, error) {
bOff := backoff.Exponential() bOff := backoff.Exponential()
var ret *rpc.Client var ret *rpc.Client
err := backoff.Do(10, bOff, func() error { err := backoff.DoCtx(ctx, 10, bOff, func() error {
client, err := rpc.DialOptions(ctx, addr, opts...) client, err := rpc.DialOptions(ctx, addr, opts...)
if err != nil { if err != nil {
if client == nil { if client == nil {
......
...@@ -4,8 +4,11 @@ import ( ...@@ -4,8 +4,11 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
) )
var _ BlockInfo = (&types.Block{})
type BlockInfo interface { type BlockInfo interface {
Hash() common.Hash Hash() common.Hash
ParentHash() common.Hash ParentHash() common.Hash
...@@ -16,7 +19,6 @@ type BlockInfo interface { ...@@ -16,7 +19,6 @@ type BlockInfo interface {
// MixDigest field, reused for randomness after The Merge (Bellatrix hardfork) // MixDigest field, reused for randomness after The Merge (Bellatrix hardfork)
MixDigest() common.Hash MixDigest() common.Hash
BaseFee() *big.Int BaseFee() *big.Int
ID() BlockID
ReceiptHash() common.Hash ReceiptHash() common.Hash
} }
...@@ -28,3 +30,15 @@ func InfoToL1BlockRef(info BlockInfo) L1BlockRef { ...@@ -28,3 +30,15 @@ func InfoToL1BlockRef(info BlockInfo) L1BlockRef {
Time: info.Time(), Time: info.Time(),
} }
} }
type NumberAndHash interface {
Hash() common.Hash
NumberU64() uint64
}
func ToBlockID(b NumberAndHash) BlockID {
return BlockID{
Hash: b.Hash(),
Number: b.NumberU64(),
}
}
...@@ -10,6 +10,8 @@ import ( ...@@ -10,6 +10,8 @@ import (
"strconv" "strconv"
"time" "time"
libp2pmetrics "github.com/libp2p/go-libp2p-core/metrics"
pb "github.com/libp2p/go-libp2p-pubsub/pb"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/collectors"
"github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promauto"
...@@ -30,6 +32,32 @@ const ( ...@@ -30,6 +32,32 @@ const (
BatchMethod = "<batch>" BatchMethod = "<batch>"
) )
type Metricer interface {
RecordInfo(version string)
RecordUp()
RecordRPCServerRequest(method string) func()
RecordRPCClientRequest(method string) func(err error)
RecordRPCClientResponse(method string, err error)
SetDerivationIdle(status bool)
RecordPipelineReset()
RecordSequencingError()
RecordPublishingError()
RecordDerivationError()
RecordReceivedUnsafePayload(payload *eth.ExecutionPayload)
recordRef(layer string, name string, num uint64, timestamp uint64, h common.Hash)
RecordL1Ref(name string, ref eth.L1BlockRef)
RecordL2Ref(name string, ref eth.L2BlockRef)
RecordUnsafePayloadsBuffer(length uint64, memSize uint64, next eth.BlockID)
CountSequencedTxs(count int)
RecordL1ReorgDepth(d uint64)
RecordGossipEvent(evType int32)
IncPeerCount()
DecPeerCount()
IncStreamCount()
DecStreamCount()
RecordBandwidth(ctx context.Context, bwc *libp2pmetrics.BandwidthCounter)
}
type Metrics struct { type Metrics struct {
Info *prometheus.GaugeVec Info *prometheus.GaugeVec
Up prometheus.Gauge Up prometheus.Gauge
...@@ -67,6 +95,12 @@ type Metrics struct { ...@@ -67,6 +95,12 @@ type Metrics struct {
TransactionsSequencedTotal prometheus.Counter TransactionsSequencedTotal prometheus.Counter
// P2P Metrics
PeerCount prometheus.Gauge
StreamCount prometheus.Gauge
GossipEventsTotal *prometheus.CounterVec
BandwidthTotal *prometheus.GaugeVec
registry *prometheus.Registry registry *prometheus.Registry
} }
...@@ -217,6 +251,35 @@ func NewMetrics(procName string) *Metrics { ...@@ -217,6 +251,35 @@ func NewMetrics(procName string) *Metrics {
Help: "Count of total transactions sequenced", Help: "Count of total transactions sequenced",
}), }),
PeerCount: promauto.With(registry).NewGauge(prometheus.GaugeOpts{
Namespace: ns,
Subsystem: "p2p",
Name: "peer_count",
Help: "Count of currently connected p2p peers",
}),
StreamCount: promauto.With(registry).NewGauge(prometheus.GaugeOpts{
Namespace: ns,
Subsystem: "p2p",
Name: "stream_count",
Help: "Count of currently connected p2p streams",
}),
GossipEventsTotal: promauto.With(registry).NewCounterVec(prometheus.CounterOpts{
Namespace: ns,
Subsystem: "p2p",
Name: "gossip_events_total",
Help: "Count of gossip events by type",
}, []string{
"type",
}),
BandwidthTotal: promauto.With(registry).NewGaugeVec(prometheus.GaugeOpts{
Namespace: ns,
Subsystem: "p2p",
Name: "bandwidth_bytes_total",
Help: "P2P bandwidth by direction",
}, []string{
"direction",
}),
registry: registry, registry: registry,
} }
} }
...@@ -348,6 +411,42 @@ func (m *Metrics) RecordL1ReorgDepth(d uint64) { ...@@ -348,6 +411,42 @@ func (m *Metrics) RecordL1ReorgDepth(d uint64) {
m.L1ReorgDepth.Observe(float64(d)) m.L1ReorgDepth.Observe(float64(d))
} }
func (m *Metrics) RecordGossipEvent(evType int32) {
m.GossipEventsTotal.WithLabelValues(pb.TraceEvent_Type_name[evType]).Inc()
}
func (m *Metrics) IncPeerCount() {
m.PeerCount.Inc()
}
func (m *Metrics) DecPeerCount() {
m.PeerCount.Dec()
}
func (m *Metrics) IncStreamCount() {
m.StreamCount.Inc()
}
func (m *Metrics) DecStreamCount() {
m.StreamCount.Dec()
}
func (m *Metrics) RecordBandwidth(ctx context.Context, bwc *libp2pmetrics.BandwidthCounter) {
tick := time.NewTicker(10 * time.Second)
defer tick.Stop()
for {
select {
case <-tick.C:
bwTotals := bwc.GetBandwidthTotals()
m.BandwidthTotal.WithLabelValues("in").Set(float64(bwTotals.TotalIn))
m.BandwidthTotal.WithLabelValues("out").Set(float64(bwTotals.TotalOut))
case <-ctx.Done():
return
}
}
}
// Serve starts the metrics server on the given hostname and port. // Serve starts the metrics server on the given hostname and port.
// The server will be closed when the passed-in context is cancelled. // The server will be closed when the passed-in context is cancelled.
func (m *Metrics) Serve(ctx context.Context, hostname string, port int) error { func (m *Metrics) Serve(ctx context.Context, hostname string, port int) error {
...@@ -364,3 +463,78 @@ func (m *Metrics) Serve(ctx context.Context, hostname string, port int) error { ...@@ -364,3 +463,78 @@ func (m *Metrics) Serve(ctx context.Context, hostname string, port int) error {
}() }()
return server.ListenAndServe() return server.ListenAndServe()
} }
type noopMetricer struct{}
var NoopMetrics = new(noopMetricer)
func (n *noopMetricer) RecordInfo(version string) {
}
func (n *noopMetricer) RecordUp() {
}
func (n *noopMetricer) RecordRPCServerRequest(method string) func() {
return func() {}
}
func (n *noopMetricer) RecordRPCClientRequest(method string) func(err error) {
return func(err error) {}
}
func (n *noopMetricer) RecordRPCClientResponse(method string, err error) {
}
func (n *noopMetricer) SetDerivationIdle(status bool) {
}
func (n *noopMetricer) RecordPipelineReset() {
}
func (n *noopMetricer) RecordSequencingError() {
}
func (n *noopMetricer) RecordPublishingError() {
}
func (n *noopMetricer) RecordDerivationError() {
}
func (n *noopMetricer) RecordReceivedUnsafePayload(payload *eth.ExecutionPayload) {
}
func (n *noopMetricer) recordRef(layer string, name string, num uint64, timestamp uint64, h common.Hash) {
}
func (n *noopMetricer) RecordL1Ref(name string, ref eth.L1BlockRef) {
}
func (n *noopMetricer) RecordL2Ref(name string, ref eth.L2BlockRef) {
}
func (n *noopMetricer) RecordUnsafePayloadsBuffer(length uint64, memSize uint64, next eth.BlockID) {
}
func (n *noopMetricer) CountSequencedTxs(count int) {
}
func (n *noopMetricer) RecordL1ReorgDepth(d uint64) {
}
func (n *noopMetricer) RecordGossipEvent(evType int32) {
}
func (n *noopMetricer) IncPeerCount() {
}
func (n *noopMetricer) DecPeerCount() {
}
func (n *noopMetricer) IncStreamCount() {
}
func (n *noopMetricer) DecStreamCount() {
}
func (n *noopMetricer) RecordBandwidth(ctx context.Context, bwc *libp2pmetrics.BandwidthCounter) {
}
...@@ -44,7 +44,7 @@ func (cfg *LogConfig) Check() error { ...@@ -44,7 +44,7 @@ func (cfg *LogConfig) Check() error {
func (cfg *LogConfig) NewLogger() log.Logger { func (cfg *LogConfig) NewLogger() log.Logger {
handler := log.StreamHandler(os.Stdout, format(cfg.Format, cfg.Color)) handler := log.StreamHandler(os.Stdout, format(cfg.Format, cfg.Color))
handler = log.SyncHandler(handler) handler = log.SyncHandler(handler)
log.LvlFilterHandler(level(cfg.Level), handler) handler = log.LvlFilterHandler(level(cfg.Level), handler)
logger := log.New() logger := log.New()
logger.SetHandler(handler) logger.SetHandler(handler)
return logger return logger
......
...@@ -196,7 +196,7 @@ func (n *OpNode) initMetricsServer(ctx context.Context, cfg *Config) error { ...@@ -196,7 +196,7 @@ func (n *OpNode) initMetricsServer(ctx context.Context, cfg *Config) error {
func (n *OpNode) initP2P(ctx context.Context, cfg *Config) error { func (n *OpNode) initP2P(ctx context.Context, cfg *Config) error {
if cfg.P2P != nil { if cfg.P2P != nil {
p2pNode, err := p2p.NewNodeP2P(n.resourcesCtx, &cfg.Rollup, n.log, cfg.P2P, n) p2pNode, err := p2p.NewNodeP2P(n.resourcesCtx, &cfg.Rollup, n.log, cfg.P2P, n, n.metrics)
if err != nil || p2pNode == nil { if err != nil || p2pNode == nil {
return err return err
} }
......
...@@ -41,7 +41,7 @@ import ( ...@@ -41,7 +41,7 @@ import (
type SetupP2P interface { type SetupP2P interface {
Check() error Check() error
// Host creates a libp2p host service. Returns nil, nil if p2p is disabled. // Host creates a libp2p host service. Returns nil, nil if p2p is disabled.
Host(log log.Logger) (host.Host, error) Host(log log.Logger, reporter metrics.Reporter) (host.Host, error)
// Discovery creates a disc-v5 service. Returns nil, nil, nil if discovery is disabled. // Discovery creates a disc-v5 service. Returns nil, nil, nil if discovery is disabled.
Discovery(log log.Logger, rollupCfg *rollup.Config, tcpPort uint16) (*enode.LocalNode, *discover.UDPv5, error) Discovery(log log.Logger, rollupCfg *rollup.Config, tcpPort uint16) (*enode.LocalNode, *discover.UDPv5, error)
TargetPeers() uint TargetPeers() uint
...@@ -91,8 +91,6 @@ type Config struct { ...@@ -91,8 +91,6 @@ type Config struct {
ConnGater func(conf *Config) (connmgr.ConnectionGater, error) ConnGater func(conf *Config) (connmgr.ConnectionGater, error)
ConnMngr func(conf *Config) (connmgr.ConnManager, error) ConnMngr func(conf *Config) (connmgr.ConnManager, error)
// nil to disable bandwidth metrics
BandwidthMetrics metrics.Reporter
} }
type ConnectionGater interface { type ConnectionGater interface {
......
...@@ -46,6 +46,10 @@ var MessageDomainValidSnappy = [4]byte{1, 0, 0, 0} ...@@ -46,6 +46,10 @@ var MessageDomainValidSnappy = [4]byte{1, 0, 0, 0}
const MaxGossipSize = 1 << 20 const MaxGossipSize = 1 << 20
type GossipMetricer interface {
RecordGossipEvent(evType int32)
}
func blocksTopicV1(cfg *rollup.Config) string { func blocksTopicV1(cfg *rollup.Config) string {
return fmt.Sprintf("/optimism/%s/0/blocks", cfg.L2ChainID.String()) return fmt.Sprintf("/optimism/%s/0/blocks", cfg.L2ChainID.String())
} }
...@@ -115,7 +119,7 @@ func BuildGlobalGossipParams(cfg *rollup.Config) pubsub.GossipSubParams { ...@@ -115,7 +119,7 @@ func BuildGlobalGossipParams(cfg *rollup.Config) pubsub.GossipSubParams {
return params return params
} }
func NewGossipSub(p2pCtx context.Context, h host.Host, cfg *rollup.Config) (*pubsub.PubSub, error) { func NewGossipSub(p2pCtx context.Context, h host.Host, cfg *rollup.Config, m GossipMetricer) (*pubsub.PubSub, error) {
denyList, err := pubsub.NewTimeCachedBlacklist(30 * time.Second) denyList, err := pubsub.NewTimeCachedBlacklist(30 * time.Second)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -132,6 +136,7 @@ func NewGossipSub(p2pCtx context.Context, h host.Host, cfg *rollup.Config) (*pub ...@@ -132,6 +136,7 @@ func NewGossipSub(p2pCtx context.Context, h host.Host, cfg *rollup.Config) (*pub
pubsub.WithPeerExchange(false), pubsub.WithPeerExchange(false),
pubsub.WithBlacklist(denyList), pubsub.WithBlacklist(denyList),
pubsub.WithGossipSubParams(BuildGlobalGossipParams(cfg)), pubsub.WithGossipSubParams(BuildGlobalGossipParams(cfg)),
pubsub.WithEventTracer(&gossipTracer{m: m}),
) )
// TODO: pubsub.WithPeerScoreInspect(inspect, InspectInterval) to update peerstore scores with gossip scores // TODO: pubsub.WithPeerScoreInspect(inspect, InspectInterval) to update peerstore scores with gossip scores
} }
...@@ -441,3 +446,13 @@ func LogTopicEvents(ctx context.Context, log log.Logger, evHandler *pubsub.Topic ...@@ -441,3 +446,13 @@ func LogTopicEvents(ctx context.Context, log log.Logger, evHandler *pubsub.Topic
} }
} }
} }
type gossipTracer struct {
m GossipMetricer
}
func (g *gossipTracer) Trace(evt *pb.TraceEvent) {
if g.m != nil {
g.m.RecordGossipEvent(int32(*evt.Type))
}
}
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/libp2p/go-libp2p-core/connmgr" "github.com/libp2p/go-libp2p-core/connmgr"
"github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/metrics"
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-peerstore/pstoreds" "github.com/libp2p/go-libp2p-peerstore/pstoreds"
lconf "github.com/libp2p/go-libp2p/config" lconf "github.com/libp2p/go-libp2p/config"
...@@ -41,7 +42,7 @@ func (e *extraHost) ConnectionManager() connmgr.ConnManager { ...@@ -41,7 +42,7 @@ func (e *extraHost) ConnectionManager() connmgr.ConnManager {
var _ ExtraHostFeatures = (*extraHost)(nil) var _ ExtraHostFeatures = (*extraHost)(nil)
func (conf *Config) Host(log log.Logger) (host.Host, error) { func (conf *Config) Host(log log.Logger, reporter metrics.Reporter) (host.Host, error) {
if conf.DisableP2P { if conf.DisableP2P {
return nil, nil return nil, nil
} }
...@@ -115,7 +116,7 @@ func (conf *Config) Host(log log.Logger) (host.Host, error) { ...@@ -115,7 +116,7 @@ func (conf *Config) Host(log log.Logger) (host.Host, error) {
ResourceManager: nil, // TODO use resource manager interface to manage resources per peer better. ResourceManager: nil, // TODO use resource manager interface to manage resources per peer better.
NATManager: nat, NATManager: nat,
Peerstore: ps, Peerstore: ps,
Reporter: conf.BandwidthMetrics, // may be nil if disabled Reporter: reporter, // may be nil if disabled
MultiaddrResolver: madns.DefaultResolver, MultiaddrResolver: madns.DefaultResolver,
// Ping is a small built-in libp2p protocol that helps us check/debug latency between peers. // Ping is a small built-in libp2p protocol that helps us check/debug latency between peers.
DisablePing: false, DisablePing: false,
......
...@@ -21,7 +21,6 @@ import ( ...@@ -21,7 +21,6 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/metrics"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -65,10 +64,10 @@ func TestingConfig(t *testing.T) *Config { ...@@ -65,10 +64,10 @@ func TestingConfig(t *testing.T) *Config {
func TestP2PSimple(t *testing.T) { func TestP2PSimple(t *testing.T) {
confA := TestingConfig(t) confA := TestingConfig(t)
confB := TestingConfig(t) confB := TestingConfig(t)
hostA, err := confA.Host(testlog.Logger(t, log.LvlError).New("host", "A")) hostA, err := confA.Host(testlog.Logger(t, log.LvlError).New("host", "A"), nil)
require.NoError(t, err, "failed to launch host A") require.NoError(t, err, "failed to launch host A")
defer hostA.Close() defer hostA.Close()
hostB, err := confB.Host(testlog.Logger(t, log.LvlError).New("host", "B")) hostB, err := confB.Host(testlog.Logger(t, log.LvlError).New("host", "B"), nil)
require.NoError(t, err, "failed to launch host B") require.NoError(t, err, "failed to launch host B")
defer hostB.Close() defer hostB.Close()
err = hostA.Connect(context.Background(), peer.AddrInfo{ID: hostB.ID(), Addrs: hostB.Addrs()}) err = hostA.Connect(context.Background(), peer.AddrInfo{ID: hostB.ID(), Addrs: hostB.Addrs()})
...@@ -132,7 +131,7 @@ func TestP2PFull(t *testing.T) { ...@@ -132,7 +131,7 @@ func TestP2PFull(t *testing.T) {
// TODO: maybe swap the order of sec/mux preferences, to test that negotiation works // TODO: maybe swap the order of sec/mux preferences, to test that negotiation works
logA := testlog.Logger(t, log.LvlError).New("host", "A") logA := testlog.Logger(t, log.LvlError).New("host", "A")
nodeA, err := NewNodeP2P(context.Background(), &rollup.Config{}, logA, &confA, &mockGossipIn{}) nodeA, err := NewNodeP2P(context.Background(), &rollup.Config{}, logA, &confA, &mockGossipIn{}, nil)
require.NoError(t, err) require.NoError(t, err)
defer nodeA.Close() defer nodeA.Close()
...@@ -143,7 +142,7 @@ func TestP2PFull(t *testing.T) { ...@@ -143,7 +142,7 @@ func TestP2PFull(t *testing.T) {
conns <- conn conns <- conn
}}) }})
backend := NewP2PAPIBackend(nodeA, logA, metrics.NewMetrics("")) backend := NewP2PAPIBackend(nodeA, logA, nil)
srv := rpc.NewServer() srv := rpc.NewServer()
require.NoError(t, srv.RegisterName("opp2p", backend)) require.NoError(t, srv.RegisterName("opp2p", backend))
client := rpc.DialInProc(srv) client := rpc.DialInProc(srv)
...@@ -155,7 +154,7 @@ func TestP2PFull(t *testing.T) { ...@@ -155,7 +154,7 @@ func TestP2PFull(t *testing.T) {
logB := testlog.Logger(t, log.LvlError).New("host", "B") logB := testlog.Logger(t, log.LvlError).New("host", "B")
nodeB, err := NewNodeP2P(context.Background(), &rollup.Config{}, logB, &confB, &mockGossipIn{}) nodeB, err := NewNodeP2P(context.Background(), &rollup.Config{}, logB, &confB, &mockGossipIn{}, nil)
require.NoError(t, err) require.NoError(t, err)
defer nodeB.Close() defer nodeB.Close()
hostB := nodeB.Host() hostB := nodeB.Host()
...@@ -289,7 +288,7 @@ func TestDiscovery(t *testing.T) { ...@@ -289,7 +288,7 @@ func TestDiscovery(t *testing.T) {
resourcesCtx, resourcesCancel := context.WithCancel(context.Background()) resourcesCtx, resourcesCancel := context.WithCancel(context.Background())
defer resourcesCancel() defer resourcesCancel()
nodeA, err := NewNodeP2P(context.Background(), rollupCfg, logA, &confA, &mockGossipIn{}) nodeA, err := NewNodeP2P(context.Background(), rollupCfg, logA, &confA, &mockGossipIn{}, nil)
require.NoError(t, err) require.NoError(t, err)
defer nodeA.Close() defer nodeA.Close()
hostA := nodeA.Host() hostA := nodeA.Host()
...@@ -304,7 +303,7 @@ func TestDiscovery(t *testing.T) { ...@@ -304,7 +303,7 @@ func TestDiscovery(t *testing.T) {
confB.DiscoveryDB = discDBC confB.DiscoveryDB = discDBC
// Start B // Start B
nodeB, err := NewNodeP2P(context.Background(), rollupCfg, logB, &confB, &mockGossipIn{}) nodeB, err := NewNodeP2P(context.Background(), rollupCfg, logB, &confB, &mockGossipIn{}, nil)
require.NoError(t, err) require.NoError(t, err)
defer nodeB.Close() defer nodeB.Close()
hostB := nodeB.Host() hostB := nodeB.Host()
...@@ -319,7 +318,7 @@ func TestDiscovery(t *testing.T) { ...@@ -319,7 +318,7 @@ func TestDiscovery(t *testing.T) {
}}) }})
// Start C // Start C
nodeC, err := NewNodeP2P(context.Background(), rollupCfg, logC, &confC, &mockGossipIn{}) nodeC, err := NewNodeP2P(context.Background(), rollupCfg, logC, &confC, &mockGossipIn{}, nil)
require.NoError(t, err) require.NoError(t, err)
defer nodeC.Close() defer nodeC.Close()
hostC := nodeC.Host() hostC := nodeC.Host()
......
...@@ -6,9 +6,11 @@ import ( ...@@ -6,9 +6,11 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"github.com/ethereum-optimism/optimism/op-node/metrics"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/libp2p/go-libp2p-core/connmgr" "github.com/libp2p/go-libp2p-core/connmgr"
"github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/host"
p2pmetrics "github.com/libp2p/go-libp2p-core/metrics"
pubsub "github.com/libp2p/go-libp2p-pubsub" pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/p2p/protocol/identify" "github.com/libp2p/go-libp2p/p2p/protocol/identify"
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
...@@ -30,12 +32,12 @@ type NodeP2P struct { ...@@ -30,12 +32,12 @@ type NodeP2P struct {
gsOut GossipOut // p2p gossip application interface for publishing gsOut GossipOut // p2p gossip application interface for publishing
} }
func NewNodeP2P(resourcesCtx context.Context, rollupCfg *rollup.Config, log log.Logger, setup SetupP2P, gossipIn GossipIn) (*NodeP2P, error) { func NewNodeP2P(resourcesCtx context.Context, rollupCfg *rollup.Config, log log.Logger, setup SetupP2P, gossipIn GossipIn, metrics metrics.Metricer) (*NodeP2P, error) {
if setup == nil { if setup == nil {
return nil, errors.New("p2p node cannot be created without setup") return nil, errors.New("p2p node cannot be created without setup")
} }
var n NodeP2P var n NodeP2P
if err := n.init(resourcesCtx, rollupCfg, log, setup, gossipIn); err != nil { if err := n.init(resourcesCtx, rollupCfg, log, setup, gossipIn, metrics); err != nil {
closeErr := n.Close() closeErr := n.Close()
if closeErr != nil { if closeErr != nil {
log.Error("failed to close p2p after starting with err", "closeErr", closeErr, "err", err) log.Error("failed to close p2p after starting with err", "closeErr", closeErr, "err", err)
...@@ -48,10 +50,12 @@ func NewNodeP2P(resourcesCtx context.Context, rollupCfg *rollup.Config, log log. ...@@ -48,10 +50,12 @@ func NewNodeP2P(resourcesCtx context.Context, rollupCfg *rollup.Config, log log.
return &n, nil return &n, nil
} }
func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, log log.Logger, setup SetupP2P, gossipIn GossipIn) error { func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, log log.Logger, setup SetupP2P, gossipIn GossipIn, metrics metrics.Metricer) error {
bwc := p2pmetrics.NewBandwidthCounter()
var err error var err error
// nil if disabled. // nil if disabled.
n.host, err = setup.Host(log) n.host, err = setup.Host(log, bwc)
if err != nil { if err != nil {
if n.dv5Udp != nil { if n.dv5Udp != nil {
n.dv5Udp.Close() n.dv5Udp.Close()
...@@ -66,10 +70,10 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l ...@@ -66,10 +70,10 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l
n.connMgr = extra.ConnectionManager() n.connMgr = extra.ConnectionManager()
} }
// notify of any new connections/streams/etc. // notify of any new connections/streams/etc.
n.host.Network().Notify(NewNetworkNotifier(log)) n.host.Network().Notify(NewNetworkNotifier(log, metrics))
// unregister identify-push handler. Only identifying on dial is fine, and more robust against spam // unregister identify-push handler. Only identifying on dial is fine, and more robust against spam
n.host.RemoveStreamHandler(identify.IDDelta) n.host.RemoveStreamHandler(identify.IDDelta)
n.gs, err = NewGossipSub(resourcesCtx, n.host, rollupCfg) n.gs, err = NewGossipSub(resourcesCtx, n.host, rollupCfg, metrics)
if err != nil { if err != nil {
return fmt.Errorf("failed to start gossipsub router: %w", err) return fmt.Errorf("failed to start gossipsub router: %w", err)
} }
...@@ -90,6 +94,10 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l ...@@ -90,6 +94,10 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l
if err != nil { if err != nil {
return fmt.Errorf("failed to start discv5: %w", err) return fmt.Errorf("failed to start discv5: %w", err)
} }
if metrics != nil {
go metrics.RecordBandwidth(resourcesCtx, bwc)
}
} }
return nil return nil
} }
......
package p2p package p2p
import ( import (
"github.com/ethereum-optimism/optimism/op-node/metrics"
"github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/network"
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
// TODO: add metrics here as well type NotificationsMetricer interface {
IncPeerCount()
DecPeerCount()
IncStreamCount()
DecStreamCount()
}
type notifications struct { type notifications struct {
log log.Logger log log.Logger
m NotificationsMetricer
} }
func (notif *notifications) Listen(n network.Network, a ma.Multiaddr) { func (notif *notifications) Listen(n network.Network, a ma.Multiaddr) {
...@@ -20,20 +27,27 @@ func (notif *notifications) ListenClose(n network.Network, a ma.Multiaddr) { ...@@ -20,20 +27,27 @@ func (notif *notifications) ListenClose(n network.Network, a ma.Multiaddr) {
notif.log.Info("stopped listening network address", "addr", a) notif.log.Info("stopped listening network address", "addr", a)
} }
func (notif *notifications) Connected(n network.Network, v network.Conn) { func (notif *notifications) Connected(n network.Network, v network.Conn) {
notif.m.IncPeerCount()
notif.log.Info("connected to peer", "peer", v.RemotePeer(), "addr", v.RemoteMultiaddr()) notif.log.Info("connected to peer", "peer", v.RemotePeer(), "addr", v.RemoteMultiaddr())
} }
func (notif *notifications) Disconnected(n network.Network, v network.Conn) { func (notif *notifications) Disconnected(n network.Network, v network.Conn) {
notif.m.DecPeerCount()
notif.log.Info("disconnected from peer", "peer", v.RemotePeer(), "addr", v.RemoteMultiaddr()) notif.log.Info("disconnected from peer", "peer", v.RemotePeer(), "addr", v.RemoteMultiaddr())
} }
func (notif *notifications) OpenedStream(n network.Network, v network.Stream) { func (notif *notifications) OpenedStream(n network.Network, v network.Stream) {
notif.m.IncStreamCount()
c := v.Conn() c := v.Conn()
notif.log.Trace("opened stream", "protocol", v.Protocol(), "peer", c.RemotePeer(), "addr", c.RemoteMultiaddr()) notif.log.Trace("opened stream", "protocol", v.Protocol(), "peer", c.RemotePeer(), "addr", c.RemoteMultiaddr())
} }
func (notif *notifications) ClosedStream(n network.Network, v network.Stream) { func (notif *notifications) ClosedStream(n network.Network, v network.Stream) {
notif.m.DecStreamCount()
c := v.Conn() c := v.Conn()
notif.log.Trace("opened stream", "protocol", v.Protocol(), "peer", c.RemotePeer(), "addr", c.RemoteMultiaddr()) notif.log.Trace("opened stream", "protocol", v.Protocol(), "peer", c.RemotePeer(), "addr", c.RemoteMultiaddr())
} }
func NewNetworkNotifier(log log.Logger) network.Notifiee { func NewNetworkNotifier(log log.Logger, m metrics.Metricer) network.Notifiee {
return &notifications{log: log} if m == nil {
m = metrics.NoopMetrics
}
return &notifications{log: log, m: m}
} }
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/metrics"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -38,7 +39,7 @@ func (p *Prepared) Check() error { ...@@ -38,7 +39,7 @@ func (p *Prepared) Check() error {
} }
// Host creates a libp2p host service. Returns nil, nil if p2p is disabled. // Host creates a libp2p host service. Returns nil, nil if p2p is disabled.
func (p *Prepared) Host(log log.Logger) (host.Host, error) { func (p *Prepared) Host(log log.Logger, reporter metrics.Reporter) (host.Host, error) {
return p.HostP2P, nil return p.HostP2P, nil
} }
......
...@@ -54,12 +54,16 @@ type Node interface { ...@@ -54,12 +54,16 @@ type Node interface {
type APIBackend struct { type APIBackend struct {
node Node node Node
log log.Logger log log.Logger
m *metrics.Metrics m metrics.Metricer
} }
var _ API = (*APIBackend)(nil) var _ API = (*APIBackend)(nil)
func NewP2PAPIBackend(node Node, log log.Logger, m *metrics.Metrics) *APIBackend { func NewP2PAPIBackend(node Node, log log.Logger, m metrics.Metricer) *APIBackend {
if m == nil {
m = metrics.NoopMetrics
}
return &APIBackend{ return &APIBackend{
node: node, node: node,
log: log, log: log,
......
...@@ -59,7 +59,11 @@ func (bq *BatchQueue) Origin() eth.L1BlockRef { ...@@ -59,7 +59,11 @@ func (bq *BatchQueue) Origin() eth.L1BlockRef {
} }
func (bq *BatchQueue) NextBatch(ctx context.Context, safeL2Head eth.L2BlockRef) (*BatchData, error) { func (bq *BatchQueue) NextBatch(ctx context.Context, safeL2Head eth.L2BlockRef) (*BatchData, error) {
originBehind := bq.origin.Number < safeL2Head.L1Origin.Number // Note: We use the origin that we will have to determine if it's behind. This is important
// because it's the future origin that gets saved into the l1Blocks array.
// We always update the origin of this stage if it is not the same so after the update code
// runs, this is consistent.
originBehind := bq.prev.Origin().Number < safeL2Head.L1Origin.Number
// Advance origin if needed // Advance origin if needed
// Note: The entire pipeline has the same origin // Note: The entire pipeline has the same origin
...@@ -148,7 +152,7 @@ func (bq *BatchQueue) deriveNextBatch(ctx context.Context, outOfData bool, l2Saf ...@@ -148,7 +152,7 @@ func (bq *BatchQueue) deriveNextBatch(ctx context.Context, outOfData bool, l2Saf
epoch := bq.l1Blocks[0] epoch := bq.l1Blocks[0]
if l2SafeHead.L1Origin != epoch.ID() { if l2SafeHead.L1Origin != epoch.ID() {
return nil, NewResetError(fmt.Errorf("buffered L1 chain epoch %s in batch queue does not match safe head %s", epoch, l2SafeHead)) return nil, NewResetError(fmt.Errorf("buffered L1 chain epoch %s in batch queue does not match safe head origin %s", epoch, l2SafeHead.L1Origin))
} }
// Find the first-seen batch that matches all validity conditions. // Find the first-seen batch that matches all validity conditions.
......
...@@ -405,7 +405,7 @@ func (eq *EngineQueue) forceNextSafeAttributes(ctx context.Context) error { ...@@ -405,7 +405,7 @@ func (eq *EngineQueue) forceNextSafeAttributes(ctx context.Context) error {
// ResetStep Walks the L2 chain backwards until it finds an L2 block whose L1 origin is canonical. // ResetStep Walks the L2 chain backwards until it finds an L2 block whose L1 origin is canonical.
// The unsafe head is set to the head of the L2 chain, unless the existing safe head is not canonical. // The unsafe head is set to the head of the L2 chain, unless the existing safe head is not canonical.
func (eq *EngineQueue) Reset(ctx context.Context, _ eth.L1BlockRef) error { func (eq *EngineQueue) Reset(ctx context.Context, _ eth.L1BlockRef) error {
result, err := sync.FindL2Heads(ctx, eq.cfg, eq.l1Fetcher, eq.engine) result, err := sync.FindL2Heads(ctx, eq.cfg, eq.l1Fetcher, eq.engine, eq.log)
if err != nil { if err != nil {
return NewTemporaryError(fmt.Errorf("failed to find the L2 Heads to start from: %w", err)) return NewTemporaryError(fmt.Errorf("failed to find the L2 Heads to start from: %w", err))
} }
......
...@@ -91,6 +91,7 @@ func (d *Sequencer) CompleteBuildingBlock(ctx context.Context) (*eth.ExecutionPa ...@@ -91,6 +91,7 @@ func (d *Sequencer) CompleteBuildingBlock(ctx context.Context) (*eth.ExecutionPa
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to complete building on top of L2 chain %s, error (%d): %w", d.buildingOnto.HeadBlockHash, errTyp, err) return nil, fmt.Errorf("failed to complete building on top of L2 chain %s, error (%d): %w", d.buildingOnto.HeadBlockHash, errTyp, err)
} }
d.buildingID = eth.PayloadID{}
return payload, nil return payload, nil
} }
...@@ -103,7 +104,6 @@ func (d *Sequencer) CreateNewBlock(ctx context.Context, l2Head eth.L2BlockRef, l ...@@ -103,7 +104,6 @@ func (d *Sequencer) CreateNewBlock(ctx context.Context, l2Head eth.L2BlockRef, l
if err != nil { if err != nil {
return l2Head, nil, err return l2Head, nil, err
} }
d.buildingID = eth.PayloadID{}
// Generate an L2 block ref from the payload. // Generate an L2 block ref from the payload.
ref, err := derive.PayloadToBlockRef(payload, &d.config.Genesis) ref, err := derive.PayloadToBlockRef(payload, &d.config.Genesis)
......
...@@ -266,7 +266,7 @@ func (s *Driver) eventLoop() { ...@@ -266,7 +266,7 @@ func (s *Driver) eventLoop() {
s.log.Warn("not creating block, node is deriving new l2 data", "head_l1", l1Head) s.log.Warn("not creating block, node is deriving new l2 data", "head_l1", l1Head)
break break
} }
ctx, cancel := context.WithTimeout(ctx, 10*time.Second) ctx, cancel := context.WithTimeout(ctx, 20*time.Minute)
err := s.createNewL2Block(ctx) err := s.createNewL2Block(ctx)
cancel() cancel()
if err != nil { if err != nil {
...@@ -309,9 +309,7 @@ func (s *Driver) eventLoop() { ...@@ -309,9 +309,7 @@ func (s *Driver) eventLoop() {
s.metrics.SetDerivationIdle(false) s.metrics.SetDerivationIdle(false)
s.idleDerivation = false s.idleDerivation = false
s.log.Debug("Derivation process step", "onto_origin", s.derivation.Origin(), "attempts", stepAttempts) s.log.Debug("Derivation process step", "onto_origin", s.derivation.Origin(), "attempts", stepAttempts)
stepCtx, cancel := context.WithTimeout(ctx, time.Second*10) // TODO pick a timeout for executing a single step err := s.derivation.Step(context.Background())
err := s.derivation.Step(stepCtx)
cancel()
stepAttempts += 1 // count as attempt by default. We reset to 0 if we are making healthy progress. stepAttempts += 1 // count as attempt by default. We reset to 0 if we are making healthy progress.
if err == io.EOF { if err == io.EOF {
s.log.Debug("Derivation process went idle", "progress", s.derivation.Origin()) s.log.Debug("Derivation process went idle", "progress", s.derivation.Origin())
......
...@@ -32,6 +32,7 @@ import ( ...@@ -32,6 +32,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
) )
type L1Chain interface { type L1Chain interface {
...@@ -101,7 +102,7 @@ func currentHeads(ctx context.Context, cfg *rollup.Config, l2 L2Chain) (*FindHea ...@@ -101,7 +102,7 @@ func currentHeads(ctx context.Context, cfg *rollup.Config, l2 L2Chain) (*FindHea
// Plausible: meaning that the blockhash of the L2 block's L1 origin // Plausible: meaning that the blockhash of the L2 block's L1 origin
// (as reported in the L1 Attributes deposit within the L2 block) is not canonical at another height in the L1 chain, // (as reported in the L1 Attributes deposit within the L2 block) is not canonical at another height in the L1 chain,
// and the same holds for all its ancestors. // and the same holds for all its ancestors.
func FindL2Heads(ctx context.Context, cfg *rollup.Config, l1 L1Chain, l2 L2Chain) (result *FindHeadsResult, err error) { func FindL2Heads(ctx context.Context, cfg *rollup.Config, l1 L1Chain, l2 L2Chain, lgr log.Logger) (result *FindHeadsResult, err error) {
// Fetch current L2 forkchoice state // Fetch current L2 forkchoice state
result, err = currentHeads(ctx, cfg, l2) result, err = currentHeads(ctx, cfg, l2)
if err != nil { if err != nil {
...@@ -137,6 +138,8 @@ func FindL2Heads(ctx context.Context, cfg *rollup.Config, l1 L1Chain, l2 L2Chain ...@@ -137,6 +138,8 @@ func FindL2Heads(ctx context.Context, cfg *rollup.Config, l1 L1Chain, l2 L2Chain
ahead = notFound ahead = notFound
} }
lgr.Trace("walking sync start", "number", n.Number)
// Don't walk past genesis. If we were at the L2 genesis, but could not find its L1 origin, // Don't walk past genesis. If we were at the L2 genesis, but could not find its L1 origin,
// the L2 chain is building on the wrong L1 branch. // the L2 chain is building on the wrong L1 branch.
if n.Number == cfg.Genesis.L2.Number { if n.Number == cfg.Genesis.L2.Number {
......
...@@ -73,7 +73,9 @@ func (c *syncStartTestCase) Run(t *testing.T) { ...@@ -73,7 +73,9 @@ func (c *syncStartTestCase) Run(t *testing.T) {
Genesis: genesis, Genesis: genesis,
SeqWindowSize: c.SeqWindowSize, SeqWindowSize: c.SeqWindowSize,
} }
result, err := FindL2Heads(context.Background(), cfg, chain, chain) lgr := log.New()
lgr.SetHandler(log.DiscardHandler())
result, err := FindL2Heads(context.Background(), cfg, chain, chain, lgr)
if c.ExpectedErr != nil { if c.ExpectedErr != nil {
require.ErrorIs(t, err, c.ExpectedErr, "expected error") require.ErrorIs(t, err, c.ExpectedErr, "expected error")
return return
......
...@@ -251,7 +251,7 @@ func (s *EthClient) FetchReceipts(ctx context.Context, blockHash common.Hash) (e ...@@ -251,7 +251,7 @@ func (s *EthClient) FetchReceipts(ctx context.Context, blockHash common.Hash) (e
for i := 0; i < len(txs); i++ { for i := 0; i < len(txs); i++ {
txHashes[i] = txs[i].Hash() txHashes[i] = txs[i].Hash()
} }
fetcher = NewReceiptsFetcher(info.ID(), info.ReceiptHash(), txHashes, s.client.BatchCallContext, s.maxBatchSize) fetcher = NewReceiptsFetcher(eth.ToBlockID(info), info.ReceiptHash(), txHashes, s.client.BatchCallContext, s.maxBatchSize)
s.receiptsCache.Add(blockHash, fetcher) s.receiptsCache.Add(blockHash, fetcher)
} }
// Fetch all receipts // Fetch all receipts
......
# @eth-optimism/ci-builder # @eth-optimism/ci-builder
## 0.3.3
### Patch Changes
- 3f485627: Pin slither version to 0.9.0
## 0.3.2 ## 0.3.2
### Patch Changes ### Patch Changes
......
{ {
"name": "@eth-optimism/ci-builder", "name": "@eth-optimism/ci-builder",
"version": "0.3.2", "version": "0.3.3",
"scripts": {}, "scripts": {},
"license": "MIT", "license": "MIT",
"dependencies": {} "dependencies": {}
......
# @eth-optimism/actor-tests # @eth-optimism/actor-tests
## 0.0.9
### Patch Changes
- Updated dependencies [35a7bb5e]
- Updated dependencies [b40913b1]
- Updated dependencies [a5e715c3]
- Updated dependencies [d18b8aa3]
- @eth-optimism/contracts-bedrock@0.8.1
- @eth-optimism/sdk@1.6.7
## 0.0.8 ## 0.0.8
### Patch Changes ### Patch Changes
......
{ {
"name": "@eth-optimism/actor-tests", "name": "@eth-optimism/actor-tests",
"version": "0.0.8", "version": "0.0.9",
"description": "A library and suite of tests to stress test Optimism Bedrock.", "description": "A library and suite of tests to stress test Optimism Bedrock.",
"license": "MIT", "license": "MIT",
"author": "", "author": "",
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
"test:coverage": "yarn test" "test:coverage": "yarn test"
}, },
"dependencies": { "dependencies": {
"@eth-optimism/contracts-bedrock": "0.8.0", "@eth-optimism/contracts-bedrock": "0.8.1",
"@eth-optimism/core-utils": "^0.10.1", "@eth-optimism/core-utils": "^0.10.1",
"@eth-optimism/sdk": "^1.6.6", "@eth-optimism/sdk": "^1.6.7",
"@types/chai": "^4.2.18", "@types/chai": "^4.2.18",
"@types/chai-as-promised": "^7.1.4", "@types/chai-as-promised": "^7.1.4",
"async-mutex": "^0.3.2", "async-mutex": "^0.3.2",
......
...@@ -6,7 +6,7 @@ GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 1122 ...@@ -6,7 +6,7 @@ GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 1122
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 348094) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 348094)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 112225) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 112225)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 40569) GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 40569)
GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 68671) GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 68693)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 74964) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 74964)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 35777) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 35777)
CrossDomainMessenger_Test:testFuzz_baseGas(uint32) (runs: 256, μ: 20263, ~: 20263) CrossDomainMessenger_Test:testFuzz_baseGas(uint32) (runs: 256, μ: 20263, ~: 20263)
...@@ -97,29 +97,29 @@ L2CrossDomainMessenger_Test:test_L2MessengerSendMessage() (gas: 120648) ...@@ -97,29 +97,29 @@ L2CrossDomainMessenger_Test:test_L2MessengerSendMessage() (gas: 120648)
L2CrossDomainMessenger_Test:test_L2MessengerTwiceSendMessage() (gas: 136338) L2CrossDomainMessenger_Test:test_L2MessengerTwiceSendMessage() (gas: 136338)
L2CrossDomainMessenger_Test:test_L2MessengerXDomainSenderReverts() (gas: 10576) L2CrossDomainMessenger_Test:test_L2MessengerXDomainSenderReverts() (gas: 10576)
L2CrossDomainMessenger_Test:test_L2MessengerxDomainMessageSenderResets() (gas: 50459) L2CrossDomainMessenger_Test:test_L2MessengerxDomainMessageSenderResets() (gas: 50459)
L2OutputOracleTest:testCannot_ProposeWithUnmatchedBlockhash() (gas: 26829) L2OutputOracleTest:testCannot_ProposeWithUnmatchedBlockhash() (gas: 26828)
L2OutputOracleTest:testCannot_constructWithBadTimestamp() (gas: 52842) L2OutputOracleTest:testCannot_constructWithBadTimestamp() (gas: 52850)
L2OutputOracleTest:testCannot_deleteL2Output_ifNotOwner() (gas: 25123) L2OutputOracleTest:testCannot_deleteL2Output_ifNotOwner() (gas: 25145)
L2OutputOracleTest:testCannot_deleteL2Output_withWrongRoot() (gas: 91467) L2OutputOracleTest:testCannot_deleteL2Output_withWrongRoot() (gas: 91488)
L2OutputOracleTest:testCannot_deleteL2Output_withWrongTime() (gas: 87450) L2OutputOracleTest:testCannot_deleteL2Output_withWrongTime() (gas: 87471)
L2OutputOracleTest:testCannot_proposeEmptyOutput() (gas: 24150) L2OutputOracleTest:testCannot_proposeEmptyOutput() (gas: 24149)
L2OutputOracleTest:testCannot_proposeFutureTimetamp() (gas: 26074) L2OutputOracleTest:testCannot_proposeFutureTimetamp() (gas: 26073)
L2OutputOracleTest:testCannot_proposeL2OutputIfNotProposer() (gas: 23564) L2OutputOracleTest:testCannot_proposeL2OutputIfNotProposer() (gas: 23563)
L2OutputOracleTest:testCannot_proposeOnWrongFork() (gas: 26381) L2OutputOracleTest:testCannot_proposeOnWrongFork() (gas: 26380)
L2OutputOracleTest:testCannot_proposeUnexpectedBlockNumber() (gas: 26005) L2OutputOracleTest:testCannot_proposeUnexpectedBlockNumber() (gas: 26004)
L2OutputOracleTest:test_changeProposer() (gas: 56127) L2OutputOracleTest:test_changeProposer() (gas: 56149)
L2OutputOracleTest:test_computeL2Timestamp() (gas: 30284) L2OutputOracleTest:test_computeL2Timestamp() (gas: 30192)
L2OutputOracleTest:test_constructor() (gas: 49046) L2OutputOracleTest:test_constructor() (gas: 49090)
L2OutputOracleTest:test_deleteOutput() (gas: 77260) L2OutputOracleTest:test_deleteOutput() (gas: 77312)
L2OutputOracleTest:test_getL2Output() (gas: 88523) L2OutputOracleTest:test_getL2Output() (gas: 88610)
L2OutputOracleTest:test_latestBlockNumber() (gas: 76242) L2OutputOracleTest:test_latestBlockNumber() (gas: 76241)
L2OutputOracleTest:test_nextBlockNumber() (gas: 15254) L2OutputOracleTest:test_nextBlockNumber() (gas: 15254)
L2OutputOracleTest:test_proposeWithBlockhashAndHeight() (gas: 75046) L2OutputOracleTest:test_proposeWithBlockhashAndHeight() (gas: 75045)
L2OutputOracleTest:test_proposingAnotherOutput() (gas: 76903) L2OutputOracleTest:test_proposingAnotherOutput() (gas: 76902)
L2OutputOracleTest:test_updateOwner() (gas: 46095) L2OutputOracleTest:test_updateOwner() (gas: 46161)
L2OutputOracleUpgradeable_Test:test_cannotInitImpl() (gas: 19555) L2OutputOracleUpgradeable_Test:test_cannotInitImpl() (gas: 17381)
L2OutputOracleUpgradeable_Test:test_cannotInitProxy() (gas: 24554) L2OutputOracleUpgradeable_Test:test_cannotInitProxy() (gas: 22377)
L2OutputOracleUpgradeable_Test:test_initValuesOnProxy() (gas: 39086) L2OutputOracleUpgradeable_Test:test_initValuesOnProxy() (gas: 39108)
L2OutputOracleUpgradeable_Test:test_upgrading() (gas: 180632) L2OutputOracleUpgradeable_Test:test_upgrading() (gas: 180632)
L2StandardBridge_Test:test_cannotWithdrawEthWithoutSendingIt() (gas: 21816) L2StandardBridge_Test:test_cannotWithdrawEthWithoutSendingIt() (gas: 21816)
L2StandardBridge_Test:test_finalizeBridgeETH_incorrectValueReverts() (gas: 23835) L2StandardBridge_Test:test_finalizeBridgeETH_incorrectValueReverts() (gas: 23835)
...@@ -162,16 +162,16 @@ OptimismPortalUpgradeable_Test:test_cannotInitImpl() (gas: 10813) ...@@ -162,16 +162,16 @@ OptimismPortalUpgradeable_Test:test_cannotInitImpl() (gas: 10813)
OptimismPortalUpgradeable_Test:test_cannotInitProxy() (gas: 15789) OptimismPortalUpgradeable_Test:test_cannotInitProxy() (gas: 15789)
OptimismPortalUpgradeable_Test:test_initValuesOnProxy() (gas: 15967) OptimismPortalUpgradeable_Test:test_initValuesOnProxy() (gas: 15967)
OptimismPortalUpgradeable_Test:test_upgrading() (gas: 180632) OptimismPortalUpgradeable_Test:test_upgrading() (gas: 180632)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_differential(address,address,uint256,uint256,bytes) (runs: 256, μ: 258471, ~: 259036) OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_differential(address,address,uint256,uint256,bytes) (runs: 256, μ: 258442, ~: 259036)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnInsufficientGas() (gas: 158312) OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnInsufficientGas() (gas: 158312)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnInvalidOutputRootProof() (gas: 81265) OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnInvalidOutputRootProof() (gas: 81287)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnRecentWithdrawal() (gas: 50525) OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnRecentWithdrawal() (gas: 50525)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnReentrancy() (gas: 202902) OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnReentrancy() (gas: 202902)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnReplay() (gas: 278777) OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnReplay() (gas: 278821)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnSelfCall() (gas: 50563) OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOnSelfCall() (gas: 50563)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOninvalidWithdrawalProof() (gas: 148586) OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_revertsOninvalidWithdrawalProof() (gas: 148608)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_succeeds() (gas: 186825) OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_succeeds() (gas: 186847)
OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_targetFails() (gas: 289474) OptimismPortal_FinalizeWithdrawal_Test:test_finalizeWithdrawalTransaction_targetFails() (gas: 289496)
OptimismPortal_Test:test_OptimismPortalConstructor() (gas: 17341) OptimismPortal_Test:test_OptimismPortalConstructor() (gas: 17341)
OptimismPortal_Test:test_OptimismPortalContractCreationReverts() (gas: 14199) OptimismPortal_Test:test_OptimismPortalContractCreationReverts() (gas: 14199)
OptimismPortal_Test:test_OptimismPortalReceiveEth() (gas: 127534) OptimismPortal_Test:test_OptimismPortalReceiveEth() (gas: 127534)
...@@ -183,7 +183,7 @@ OptimismPortal_Test:test_depositTransaction_withEthValueAndContractContractCreat ...@@ -183,7 +183,7 @@ OptimismPortal_Test:test_depositTransaction_withEthValueAndContractContractCreat
OptimismPortal_Test:test_depositTransaction_withEthValueAndEOAContractCreation() (gas: 75881) OptimismPortal_Test:test_depositTransaction_withEthValueAndEOAContractCreation() (gas: 75881)
OptimismPortal_Test:test_depositTransaction_withEthValueFromContract() (gas: 83333) OptimismPortal_Test:test_depositTransaction_withEthValueFromContract() (gas: 83333)
OptimismPortal_Test:test_depositTransaction_withEthValueFromEOA() (gas: 83993) OptimismPortal_Test:test_depositTransaction_withEthValueFromEOA() (gas: 83993)
OptimismPortal_Test:test_isBlockFinalized() (gas: 113744) OptimismPortal_Test:test_isBlockFinalized() (gas: 113897)
OptimismPortal_Test:test_simple_isBlockFinalized() (gas: 24130) OptimismPortal_Test:test_simple_isBlockFinalized() (gas: 24130)
Proxy_Test:test_clashingFunctionSignatures() (gas: 101427) Proxy_Test:test_clashingFunctionSignatures() (gas: 101427)
Proxy_Test:test_implementationKey() (gas: 20942) Proxy_Test:test_implementationKey() (gas: 20942)
......
# @eth-optimism/contracts-bedrock # @eth-optimism/contracts-bedrock
## 0.8.1
### Patch Changes
- 35a7bb5e: Use uint64 for arithmetic in XDM's baseGas
- a5e715c3: Rename the event emitted in the L2ToL1MessagePasser
- d18b8aa3: Removes an unnecessary initializer parameter in the L200
## 0.8.0 ## 0.8.0
### Minor Changes ### Minor Changes
......
...@@ -138,7 +138,27 @@ contract L2OutputOracle is OwnableUpgradeable, Semver { ...@@ -138,7 +138,27 @@ contract L2OutputOracle is OwnableUpgradeable, Semver {
STARTING_TIMESTAMP = _startingTimestamp; STARTING_TIMESTAMP = _startingTimestamp;
L2_BLOCK_TIME = _l2BlockTime; L2_BLOCK_TIME = _l2BlockTime;
initialize(_genesisL2Output, _startingBlockNumber, _proposer, _owner); initialize(_genesisL2Output, _proposer, _owner);
}
/**
* @notice Initializer.
*
* @param _genesisL2Output The initial L2 output of the L2 chain.
* @param _proposer The address of the proposer.
* @param _owner The address of the owner.
*/
function initialize(
bytes32 _genesisL2Output,
address _proposer,
address _owner
) public initializer {
require(_proposer != _owner, "L2OutputOracle: proposer cannot be the same as the owner");
l2Outputs[STARTING_BLOCK_NUMBER] = Types.OutputProposal(_genesisL2Output, block.timestamp);
latestBlockNumber = STARTING_BLOCK_NUMBER;
__Ownable_init();
changeProposer(_proposer);
_transferOwnership(_owner);
} }
/** /**
...@@ -257,28 +277,6 @@ contract L2OutputOracle is OwnableUpgradeable, Semver { ...@@ -257,28 +277,6 @@ contract L2OutputOracle is OwnableUpgradeable, Semver {
return output; return output;
} }
/**
* @notice Initializer.
*
* @param _genesisL2Output The initial L2 output of the L2 chain.
* @param _startingBlockNumber The timestamp to start L2 block at.
* @param _proposer The address of the proposer.
* @param _owner The address of the owner.
*/
function initialize(
bytes32 _genesisL2Output,
uint256 _startingBlockNumber,
address _proposer,
address _owner
) public initializer {
require(_proposer != _owner, "L2OutputOracle: proposer cannot be the same as the owner");
l2Outputs[_startingBlockNumber] = Types.OutputProposal(_genesisL2Output, block.timestamp);
latestBlockNumber = _startingBlockNumber;
__Ownable_init();
changeProposer(_proposer);
_transferOwnership(_owner);
}
/** /**
* @notice Overrides the standard implementation of transferOwnership * @notice Overrides the standard implementation of transferOwnership
* to add the requirement that the owner and proposer are distinct. * to add the requirement that the owner and proposer are distinct.
......
...@@ -130,12 +130,13 @@ contract L2OutputOracle_Initializer is CommonTest { ...@@ -130,12 +130,13 @@ contract L2OutputOracle_Initializer is CommonTest {
vm.prank(multisig); vm.prank(multisig);
proxy.upgradeToAndCall( proxy.upgradeToAndCall(
address(oracleImpl), address(oracleImpl),
abi.encodeWithSelector( abi.encodeCall(
L2OutputOracle.initialize.selector, L2OutputOracle.initialize,
genesisL2Output, (
startingBlockNumber, genesisL2Output,
proposer, proposer,
owner owner
)
) )
); );
oracle = L2OutputOracle(address(proxy)); oracle = L2OutputOracle(address(proxy));
......
...@@ -384,7 +384,6 @@ contract L2OutputOracleUpgradeable_Test is L2OutputOracle_Initializer { ...@@ -384,7 +384,6 @@ contract L2OutputOracleUpgradeable_Test is L2OutputOracle_Initializer {
vm.expectRevert("Initializable: contract is already initialized"); vm.expectRevert("Initializable: contract is already initialized");
L2OutputOracle(payable(proxy)).initialize( L2OutputOracle(payable(proxy)).initialize(
genesisL2Output, genesisL2Output,
startingBlockNumber,
proposer, proposer,
owner owner
); );
...@@ -394,7 +393,6 @@ contract L2OutputOracleUpgradeable_Test is L2OutputOracle_Initializer { ...@@ -394,7 +393,6 @@ contract L2OutputOracleUpgradeable_Test is L2OutputOracle_Initializer {
vm.expectRevert("Initializable: contract is already initialized"); vm.expectRevert("Initializable: contract is already initialized");
L2OutputOracle(oracleImpl).initialize( L2OutputOracle(oracleImpl).initialize(
genesisL2Output, genesisL2Output,
startingBlockNumber,
proposer, proposer,
owner owner
); );
......
...@@ -7,10 +7,9 @@ import '@eth-optimism/hardhat-deploy-config' ...@@ -7,10 +7,9 @@ import '@eth-optimism/hardhat-deploy-config'
const upgradeABIs = { const upgradeABIs = {
L2OutputOracleProxy: async (deployConfig) => [ L2OutputOracleProxy: async (deployConfig) => [
'initialize(bytes32,uint256,address,address)', 'initialize(bytes32,uint256,address)',
[ [
deployConfig.l2OutputOracleGenesisL2Output, deployConfig.l2OutputOracleGenesisL2Output,
deployConfig.l2OutputOracleStartingBlockNumber,
deployConfig.l2OutputOracleProposer, deployConfig.l2OutputOracleProposer,
deployConfig.l2OutputOracleOwner, deployConfig.l2OutputOracleOwner,
], ],
......
{ {
"name": "@eth-optimism/contracts-bedrock", "name": "@eth-optimism/contracts-bedrock",
"version": "0.8.0", "version": "0.8.1",
"description": "Contracts for Optimism Specs", "description": "Contracts for Optimism Specs",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment