Commit 5dbe50d6 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into move-eth-pkg

parents d1e26cc9 9a7381db
......@@ -524,7 +524,7 @@ jobs:
op-bindings-build:
docker:
- image: us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest
resource_class: medium
resource_class: large
steps:
- checkout
- run:
......@@ -897,6 +897,7 @@ jobs:
docker:
- image: us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest
- image: cimg/postgres:14.1
resource_class: large
steps:
- checkout
- check-changed:
......@@ -923,7 +924,7 @@ jobs:
name: Test
command: |
mkdir -p /test-results
DB_USER=postgres gotestsum --junitfile /test-results/tests.xml
DB_USER=postgres gotestsum --junitfile /test-results/tests.xml -- -parallel=4 ./...
working_directory: indexer
- run:
name: Build
......
......@@ -20,49 +20,10 @@ updates:
directory: "/"
schedule:
interval: daily
time: "16:30"
timezone: "America/New_York"
open-pull-requests-limit: 10
labels:
- dependabot
- package-ecosystem: npm
directory: "/packages/chain-mon"
schedule:
interval: daily
open-pull-requests-limit: 10
labels:
- dependabot
- package-ecosystem: npm
directory: "/packages/core-utils"
schedule:
interval: daily
open-pull-requests-limit: 10
labels:
- dependabot
- package-ecosystem: npm
directory: "/packages/contracts-ts"
schedule:
interval: daily
open-pull-requests-limit: 10
labels:
- dependabot
- package-ecosystem: npm
directory: "/packages/sdk"
schedule:
interval: daily
open-pull-requests-limit: 10
labels:
- dependabot
- package-ecosystem: npm
directory: "/packages/fee-estimation"
schedule:
interval: daily
open-pull-requests-limit: 10
labels:
- dependabot
- package-ecosystem: npm
directory: "/packages/common-ts"
schedule:
interval: daily
open-pull-requests-limit: 10
versioning-strategy: auto
labels:
- dependabot
......
......@@ -112,9 +112,17 @@ func NewEVMEnv(contracts *Contracts, addrs *Addresses) (*vm.EVM, *state.StateDB)
env := vm.NewEVM(blockContext, vm.TxContext{}, state, chainCfg, vmCfg)
// pre-deploy the contracts
env.StateDB.SetCode(addrs.MIPS, contracts.MIPS.DeployedBytecode.Object)
env.StateDB.SetCode(addrs.Oracle, contracts.Oracle.DeployedBytecode.Object)
env.StateDB.SetState(addrs.MIPS, common.Hash{}, addrs.Oracle.Hash())
var mipsCtorArgs [32]byte
copy(mipsCtorArgs[12:], addrs.Oracle[:])
mipsDeploy := append(hexutil.MustDecode(bindings.MIPSMetaData.Bin), mipsCtorArgs[:]...)
startingGas := uint64(30_000_000)
_, deployedMipsAddr, leftOverGas, err := env.Create(vm.AccountRef(addrs.Sender), mipsDeploy, startingGas, big.NewInt(0))
if err != nil {
panic(fmt.Errorf("failed to deploy MIPS contract: %w. took %d gas", err, startingGas-leftOverGas))
}
addrs.MIPS = deployedMipsAddr
rules := env.ChainConfig().Rules(header.Number, true, header.Time)
env.StateDB.Prepare(rules, addrs.Sender, addrs.FeeRecipient, &addrs.MIPS, vm.ActivePrecompiles(rules), nil)
......
docker-compose.dev.yml
.env
indexer
indexer-refresh
......@@ -8,11 +8,8 @@ LDFLAGS := -ldflags "$(LDFLAGSSTRING)"
indexer:
env GO111MODULE=on go build -v $(LDFLAGS) ./cmd/indexer
indexer-refresh:
env GO111MODULE=on go build -v $(LDFLAGS) ./cmd/indexer-refresh
clean:
rm indexer && rm indexer-refresh
rm indexer
test:
go test -v ./...
......@@ -22,7 +19,6 @@ lint:
.PHONY: \
indexer \
indexer-refresh \
bindings \
bindings-scc \
clean \
......
......@@ -72,15 +72,6 @@ var (
Usage: "path to config file",
EnvVars: []string{"INDEXER_CONFIG"},
}
// Not used yet. Use this flag to run legacy app instead
// Remove me after indexer is released
IndexerRefreshFlag = &cli.BoolFlag{
Name: "indexer-refresh",
Value: false,
Aliases: []string{"i"},
Usage: "run new unreleased indexer by passing in flag",
EnvVars: []string{"INDEXER_REFRESH"},
}
)
// make a instance method on Cli called Run that runs cli
......
# indexer/cmd/indexer-refresh
Entrypoint for the new WIP indexer. After project is deployed and stable we will delete the [indexer/main.go](../indexer/main.go) file and move [indexer-refresh/main.go](./main.go) in it's place.
package main
import (
"os"
"github.com/ethereum-optimism/optimism/indexer/cli"
"github.com/ethereum/go-ethereum/log"
)
var (
GitVersion = ""
GitCommit = ""
GitDate = ""
)
func main() {
app := cli.NewCli(GitVersion, GitCommit, GitDate)
if err := app.Run(os.Args); err != nil {
log.Crit("Application failed", "message", err)
}
}
package main
import (
"fmt"
"os"
"github.com/ethereum-optimism/optimism/indexer/cli"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/urfave/cli"
"github.com/ethereum-optimism/optimism/indexer/flags"
"github.com/ethereum-optimism/optimism/indexer/legacy"
)
var (
......@@ -19,26 +14,9 @@ var (
)
func main() {
// Set up logger with a default INFO level in case we fail to parse flags.
// Otherwise the final crtiical log won't show what the parsing error was.
log.Root().SetHandler(
log.LvlFilterHandler(
log.LvlInfo,
log.StreamHandler(os.Stdout, log.TerminalFormat(true)),
),
)
app := cli.NewApp()
app.Flags = flags.Flags
app.Version = fmt.Sprintf("%s-%s", GitVersion, params.VersionWithCommit(GitCommit, GitDate))
app.Name = "indexer"
app.Usage = "Indexer Service"
app.Description = "Service for indexing deposits and withdrawals " +
"by account on L1 and L2"
app := cli.NewCli(GitVersion, GitCommit, GitDate)
app.Action = legacy.Main(GitVersion)
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Crit("Application failed", "message", err)
}
}
......@@ -26,6 +26,7 @@ func TestLoadConfig(t *testing.T) {
port = 5432
user = "postgres"
password = "postgres"
name = "indexer"
[api]
host = "127.0.0.1"
......@@ -54,6 +55,7 @@ func TestLoadConfig(t *testing.T) {
require.Equal(t, conf.DB.Port, 5432)
require.Equal(t, conf.DB.User, "postgres")
require.Equal(t, conf.DB.Password, "postgres")
require.Equal(t, conf.DB.Name, "indexer")
require.Equal(t, conf.API.Host, "127.0.0.1")
require.Equal(t, conf.API.Port, 8080)
require.Equal(t, conf.Metrics.Host, "127.0.0.1")
......
package indexer
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
)
// ParseAddress parses a ETH address from a hex string. This method will
// fail if the address is not a valid hexadecimal address.
func ParseAddress(address string) (common.Address, error) {
if common.IsHexAddress(address) {
return common.HexToAddress(address), nil
}
return common.Address{}, fmt.Errorf("invalid address: %v", address)
}
package indexer_test
import (
"bytes"
"errors"
"testing"
indexer "github.com/ethereum-optimism/optimism/indexer"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
// TestParseAddress asserts that ParseAddress correctly parses
// 40-characater hexadecimal strings with optional 0x prefix into valid 20-byte
// addresses
func TestParseAddress(t *testing.T) {
tests := []struct {
name string
addr string
expErr error
expAddr common.Address
}{
{
name: "empty address",
addr: "",
expErr: errors.New("invalid address: "),
},
{
name: "only 0x",
addr: "0x",
expErr: errors.New("invalid address: 0x"),
},
{
name: "non hex character",
addr: "0xaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
expErr: errors.New("invalid address: 0xaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
},
{
name: "valid address",
addr: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
expErr: nil,
expAddr: common.BytesToAddress(bytes.Repeat([]byte{170}, 20)),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
addr, err := indexer.ParseAddress(test.addr)
require.Equal(t, err, test.expErr)
if test.expErr != nil {
return
}
require.Equal(t, addr, test.expAddr)
})
}
}
package db
type Airdrop struct {
Address string `json:"address"`
VoterAmount string `json:"voterAmount"`
MultisigSignerAmount string `json:"multisigSignerAmount"`
GitcoinAmount string `json:"gitcoinAmount"`
ActiveBridgedAmount string `json:"activeBridgedAmount"`
OpUserAmount string `json:"opUserAmount"`
OpRepeatUserAmount string `json:"opRepeatUserAmount"`
BonusAmount string `json:"bonusAmount"`
TotalAmount string `json:"totalAmount"`
}
package db
import (
"database/sql"
"errors"
"fmt"
"strings"
"github.com/ethereum/go-ethereum/common"
// NOTE: Only postgresql backend is supported at the moment.
_ "github.com/lib/pq"
)
// Database contains the database instance and the connection string.
type Database struct {
db *sql.DB
config string
}
// NewDatabase returns the database for the given connection string.
func NewDatabase(config string) (*Database, error) {
db, err := sql.Open("postgres", config)
if err != nil {
return nil, err
}
err = db.Ping()
if err != nil {
return nil, err
}
for _, migration := range schema {
_, err = db.Exec(migration)
if err != nil {
return nil, err
}
}
return &Database{
db: db,
config: config,
}, nil
}
// Close closes the database.
// NOTE: "It is rarely necessary to close a DB."
// See: https://pkg.go.dev/database/sql#Open
func (d *Database) Close() error {
return d.db.Close()
}
// Config returns the db connection string.
func (d *Database) Config() string {
return d.config
}
// GetL1TokenByAddress returns the ERC20 Token corresponding to the given
// address on L1.
func (d *Database) GetL1TokenByAddress(address string) (*Token, error) {
const selectL1TokenStatement = `
SELECT name, symbol, decimals FROM l1_tokens WHERE address = $1;
`
var token *Token
err := txn(d.db, func(tx *sql.Tx) error {
row := tx.QueryRow(selectL1TokenStatement, address)
if row.Err() != nil {
return row.Err()
}
var name string
var symbol string
var decimals uint8
err := row.Scan(&name, &symbol, &decimals)
if errors.Is(err, sql.ErrNoRows) {
return nil
}
if err != nil {
return err
}
token = &Token{
Name: name,
Symbol: symbol,
Decimals: decimals,
}
return nil
})
if err != nil {
return nil, err
}
return token, nil
}
// GetL2TokenByAddress returns the ERC20 Token corresponding to the given
// address on L2.
func (d *Database) GetL2TokenByAddress(address string) (*Token, error) {
const selectL2TokenStatement = `
SELECT name, symbol, decimals FROM l2_tokens WHERE address = $1;
`
var token *Token
err := txn(d.db, func(tx *sql.Tx) error {
row := tx.QueryRow(selectL2TokenStatement, address)
if row.Err() != nil {
return row.Err()
}
var name string
var symbol string
var decimals uint8
err := row.Scan(&name, &symbol, &decimals)
if errors.Is(err, sql.ErrNoRows) {
return nil
}
if err != nil {
return err
}
token = &Token{
Name: name,
Symbol: symbol,
Decimals: decimals,
}
return nil
})
if err != nil {
return nil, err
}
return token, nil
}
// AddL1Token inserts the Token details for the given address into the known L1
// tokens database.
// NOTE: a Token MUST have a unique address
func (d *Database) AddL1Token(address string, token *Token) error {
const insertTokenStatement = `
INSERT INTO l1_tokens
(address, name, symbol, decimals)
VALUES
($1, $2, $3, $4)
`
return txn(d.db, func(tx *sql.Tx) error {
_, err := tx.Exec(
insertTokenStatement,
address,
token.Name,
token.Symbol,
token.Decimals,
)
return err
})
}
// AddL2Token inserts the Token details for the given address into the known L2
// tokens database.
// NOTE: a Token MUST have a unique address
func (d *Database) AddL2Token(address string, token *Token) error {
const insertTokenStatement = `
INSERT INTO l2_tokens
(address, name, symbol, decimals)
VALUES
($1, $2, $3, $4)
`
return txn(d.db, func(tx *sql.Tx) error {
_, err := tx.Exec(
insertTokenStatement,
address,
token.Name,
token.Symbol,
token.Decimals,
)
return err
})
}
// AddIndexedL1Block inserts the indexed block i.e. the L1 block containing all
// scanned Deposits into the known deposits database.
// NOTE: the block hash MUST be unique
func (d *Database) AddIndexedL1Block(block *IndexedL1Block) error {
const insertBlockStatement = `
INSERT INTO l1_blocks
(hash, parent_hash, number, timestamp)
VALUES
($1, $2, $3, $4)
`
const insertDepositStatement = `
INSERT INTO deposits
(guid, from_address, to_address, l1_token, l2_token, amount, tx_hash, log_index, block_hash, data)
VALUES
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
`
const updateProvenWithdrawalStatement = `
UPDATE withdrawals SET (br_withdrawal_proven_tx_hash, br_withdrawal_proven_log_index) = ($1, $2)
WHERE br_withdrawal_hash = $3
`
const updateFinalizedWithdrawalStatement = `
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 {
_, err := tx.Exec(
insertBlockStatement,
block.Hash.String(),
block.ParentHash.String(),
block.Number,
block.Timestamp,
)
if err != nil {
return err
}
if len(block.Deposits) > 0 {
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
}
}
}
if len(block.ProvenWithdrawals) > 0 {
for _, wd := range block.ProvenWithdrawals {
_, err = tx.Exec(
updateProvenWithdrawalStatement,
wd.TxHash.String(),
wd.LogIndex,
wd.WithdrawalHash.String(),
)
if err != nil {
return err
}
}
}
if len(block.FinalizedWithdrawals) > 0 {
for _, wd := range block.FinalizedWithdrawals {
_, err = tx.Exec(
updateFinalizedWithdrawalStatement,
wd.TxHash.String(),
wd.LogIndex,
wd.Success,
wd.WithdrawalHash.String(),
)
if err != nil {
return err
}
}
}
return nil
})
}
// AddIndexedL2Block inserts the indexed block i.e. the L2 block containing all
// scanned Withdrawals into the known withdrawals database.
// NOTE: the block hash MUST be unique
func (d *Database) AddIndexedL2Block(block *IndexedL2Block) error {
const insertBlockStatement = `
INSERT INTO l2_blocks
(hash, parent_hash, number, timestamp)
VALUES
($1, $2, $3, $4)
`
const insertWithdrawalStatement = `
INSERT INTO withdrawals
(guid, from_address, to_address, l1_token, l2_token, amount, tx_hash, log_index, block_hash, data, br_withdrawal_hash)
VALUES
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
`
return txn(d.db, func(tx *sql.Tx) error {
_, err := tx.Exec(
insertBlockStatement,
block.Hash.String(),
block.ParentHash.String(),
block.Number,
block.Timestamp,
)
if err != nil {
return err
}
if len(block.Withdrawals) == 0 {
return nil
}
for _, withdrawal := range block.Withdrawals {
_, err = tx.Exec(
insertWithdrawalStatement,
NewGUID(),
withdrawal.FromAddress.String(),
withdrawal.ToAddress.String(),
withdrawal.L1Token.String(),
withdrawal.L2Token.String(),
withdrawal.Amount.String(),
withdrawal.TxHash.String(),
withdrawal.LogIndex,
block.Hash.String(),
withdrawal.Data,
nullableHash(withdrawal.BedrockHash),
)
if err != nil {
return err
}
}
return nil
})
}
// AddStateBatch inserts the state batches into the known state batches
// database.
func (d *Database) AddStateBatch(batches []StateBatch) error {
const insertStateBatchStatement = `
INSERT INTO state_batches
(index, root, size, prev_total, extra_data, block_hash)
VALUES
($1, $2, $3, $4, $5, $6)
`
return txn(d.db, func(tx *sql.Tx) error {
for _, sb := range batches {
_, err := tx.Exec(
insertStateBatchStatement,
sb.Index.Uint64(),
sb.Root.String(),
sb.Size.Uint64(),
sb.PrevTotal.Uint64(),
sb.ExtraData,
sb.BlockHash.String(),
)
if err != nil {
return err
}
}
return nil
})
}
// GetDepositsByAddress returns the list of Deposits indexed for the given
// address paginated by the given params.
func (d *Database) GetDepositsByAddress(address common.Address, page PaginationParam) (*PaginatedDeposits, error) {
const selectDepositsStatement = `
SELECT
deposits.guid, deposits.from_address, deposits.to_address,
deposits.amount, deposits.tx_hash, deposits.data,
deposits.l1_token, deposits.l2_token,
l1_tokens.name, l1_tokens.symbol, l1_tokens.decimals,
l1_blocks.number, l1_blocks.timestamp
FROM deposits
INNER JOIN l1_blocks ON deposits.block_hash=l1_blocks.hash
INNER JOIN l1_tokens ON deposits.l1_token=l1_tokens.address
WHERE deposits.from_address = $1 ORDER BY l1_blocks.timestamp LIMIT $2 OFFSET $3;
`
var deposits []DepositJSON
err := txn(d.db, func(tx *sql.Tx) error {
rows, err := tx.Query(selectDepositsStatement, address.String(), page.Limit, page.Offset)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var deposit DepositJSON
var l1Token Token
if err := rows.Scan(
&deposit.GUID, &deposit.FromAddress, &deposit.ToAddress,
&deposit.Amount, &deposit.TxHash, &deposit.Data,
&l1Token.Address, &deposit.L2Token,
&l1Token.Name, &l1Token.Symbol, &l1Token.Decimals,
&deposit.BlockNumber, &deposit.BlockTimestamp,
); err != nil {
return err
}
deposit.L1Token = &l1Token
deposits = append(deposits, deposit)
}
return rows.Err()
})
if err != nil {
return nil, err
}
const selectDepositCountStatement = `
SELECT
count(*)
FROM deposits
INNER JOIN l1_blocks ON deposits.block_hash=l1_blocks.hash
INNER JOIN l1_tokens ON deposits.l1_token=l1_tokens.address
WHERE deposits.from_address = $1;
`
var count uint64
err = txn(d.db, func(tx *sql.Tx) error {
row := tx.QueryRow(selectDepositCountStatement, address.String())
if err != nil {
return err
}
return row.Scan(&count)
})
if err != nil {
return nil, err
}
page.Total = count
return &PaginatedDeposits{
&page,
deposits,
}, nil
}
// GetWithdrawalBatch returns the StateBatch corresponding to the given
// withdrawal transaction hash.
func (d *Database) GetWithdrawalBatch(hash common.Hash) (*StateBatchJSON, error) {
const selectWithdrawalBatchStatement = `
SELECT
state_batches.index, state_batches.root, state_batches.size, state_batches.prev_total, state_batches.extra_data, state_batches.block_hash,
l1_blocks.number, l1_blocks.timestamp
FROM state_batches
INNER JOIN l1_blocks ON state_batches.block_hash = l1_blocks.hash
WHERE size + prev_total >= (
SELECT
number
FROM
withdrawals
INNER JOIN l2_blocks ON withdrawals.block_hash = l2_blocks.hash where tx_hash=$1
) ORDER BY "index" LIMIT 1;
`
var batch *StateBatchJSON
err := txn(d.db, func(tx *sql.Tx) error {
row := tx.QueryRow(selectWithdrawalBatchStatement, hash.String())
if row.Err() != nil {
return row.Err()
}
var index, size, prevTotal, blockNumber, blockTimestamp uint64
var root, blockHash string
var extraData []byte
err := row.Scan(&index, &root, &size, &prevTotal, &extraData, &blockHash,
&blockNumber, &blockTimestamp)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
batch = nil
return nil
}
return err
}
batch = &StateBatchJSON{
Index: index,
Root: root,
Size: size,
PrevTotal: prevTotal,
ExtraData: extraData,
BlockHash: blockHash,
BlockNumber: blockNumber,
BlockTimestamp: blockTimestamp,
}
return nil
})
if err != nil {
return nil, err
}
return batch, nil
}
// GetWithdrawalsByAddress returns the list of Withdrawals indexed for the given
// address paginated by the given params.
func (d *Database) GetWithdrawalsByAddress(address common.Address, page PaginationParam, state FinalizationState) (*PaginatedWithdrawals, error) {
selectWithdrawalsStatement := fmt.Sprintf(`
SELECT
withdrawals.guid, withdrawals.from_address, withdrawals.to_address,
withdrawals.amount, withdrawals.tx_hash, withdrawals.data,
withdrawals.l1_token, withdrawals.l2_token,
l2_tokens.name, l2_tokens.symbol, l2_tokens.decimals,
l2_blocks.number, l2_blocks.timestamp, withdrawals.br_withdrawal_hash,
withdrawals.br_withdrawal_proven_tx_hash, withdrawals.br_withdrawal_proven_log_index,
withdrawals.br_withdrawal_finalized_tx_hash, withdrawals.br_withdrawal_finalized_log_index,
withdrawals.br_withdrawal_finalized_success
FROM withdrawals
INNER JOIN l2_blocks ON withdrawals.block_hash=l2_blocks.hash
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;
`, state.SQL())
var withdrawals []WithdrawalJSON
err := txn(d.db, func(tx *sql.Tx) error {
rows, err := tx.Query(selectWithdrawalsStatement, address.String(), page.Limit, page.Offset)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var withdrawal WithdrawalJSON
var l2Token Token
var wdHash sql.NullString
var proveTxHash sql.NullString
var proveLogIndex sql.NullInt32
var finTxHash sql.NullString
var finLogIndex sql.NullInt32
var finSuccess sql.NullBool
if err := rows.Scan(
&withdrawal.GUID, &withdrawal.FromAddress, &withdrawal.ToAddress,
&withdrawal.Amount, &withdrawal.TxHash, &withdrawal.Data,
&withdrawal.L1Token, &l2Token.Address,
&l2Token.Name, &l2Token.Symbol, &l2Token.Decimals,
&withdrawal.BlockNumber, &withdrawal.BlockTimestamp,
&wdHash, &proveTxHash, &proveLogIndex,
&finTxHash, &finLogIndex, &finSuccess,
); err != nil {
return err
}
withdrawal.L2Token = &l2Token
if wdHash.Valid {
withdrawal.BedrockWithdrawalHash = &wdHash.String
}
if proveTxHash.Valid {
withdrawal.BedrockProvenTxHash = &proveTxHash.String
}
if proveLogIndex.Valid {
idx := int(proveLogIndex.Int32)
withdrawal.BedrockProvenLogIndex = &idx
}
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)
}
return rows.Err()
})
if err != nil {
return nil, err
}
for i := range withdrawals {
batch, _ := d.GetWithdrawalBatch(common.HexToHash(withdrawals[i].TxHash))
withdrawals[i].Batch = batch
}
const selectWithdrawalCountStatement = `
SELECT
count(*)
FROM withdrawals
INNER JOIN l2_blocks ON withdrawals.block_hash=l2_blocks.hash
INNER JOIN l2_tokens ON withdrawals.l2_token=l2_tokens.address
WHERE withdrawals.from_address = $1;
`
var count uint64
err = txn(d.db, func(tx *sql.Tx) error {
row := tx.QueryRow(selectWithdrawalCountStatement, address.String())
if err != nil {
return err
}
return row.Scan(&count)
})
if err != nil {
return nil, err
}
page.Total = count
return &PaginatedWithdrawals{
&page,
withdrawals,
}, nil
}
// GetHighestL1Block returns the highest known L1 block.
func (d *Database) GetHighestL1Block() (*BlockLocator, error) {
const selectHighestBlockStatement = `
SELECT number, hash FROM l1_blocks ORDER BY number DESC LIMIT 1
`
var highestBlock *BlockLocator
err := txn(d.db, func(tx *sql.Tx) error {
row := tx.QueryRow(selectHighestBlockStatement)
if row.Err() != nil {
return row.Err()
}
var number uint64
var hash string
err := row.Scan(&number, &hash)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
highestBlock = nil
return nil
}
return err
}
highestBlock = &BlockLocator{
Number: number,
Hash: common.HexToHash(hash),
}
return nil
})
if err != nil {
return nil, err
}
return highestBlock, nil
}
// GetHighestL2Block returns the highest known L2 block.
func (d *Database) GetHighestL2Block() (*BlockLocator, error) {
const selectHighestBlockStatement = `
SELECT number, hash FROM l2_blocks ORDER BY number DESC LIMIT 1
`
var highestBlock *BlockLocator
err := txn(d.db, func(tx *sql.Tx) error {
row := tx.QueryRow(selectHighestBlockStatement)
if row.Err() != nil {
return row.Err()
}
var number uint64
var hash string
err := row.Scan(&number, &hash)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
highestBlock = nil
return nil
}
return err
}
highestBlock = &BlockLocator{
Number: number,
Hash: common.HexToHash(hash),
}
return nil
})
if err != nil {
return nil, err
}
return highestBlock, nil
}
// GetIndexedL1BlockByHash returns the L1 block by it's hash.
func (d *Database) GetIndexedL1BlockByHash(hash common.Hash) (*IndexedL1Block, error) {
const selectBlockByHashStatement = `
SELECT
hash, parent_hash, number, timestamp
FROM l1_blocks
WHERE hash = $1
`
var block *IndexedL1Block
err := txn(d.db, func(tx *sql.Tx) error {
row := tx.QueryRow(selectBlockByHashStatement, hash.String())
if row.Err() != nil {
return row.Err()
}
var hash string
var parentHash string
var number uint64
var timestamp uint64
err := row.Scan(&hash, &parentHash, &number, &timestamp)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil
}
return err
}
block = &IndexedL1Block{
Hash: common.HexToHash(hash),
ParentHash: common.HexToHash(parentHash),
Number: number,
Timestamp: timestamp,
Deposits: nil,
}
return nil
})
if err != nil {
return nil, err
}
return block, nil
}
const getAirdropQuery = `
SELECT
address, voter_amount, multisig_signer_amount, gitcoin_amount,
active_bridged_amount, op_user_amount, op_repeat_user_amount,
bonus_amount, total_amount
FROM airdrops
WHERE address = $1
`
func (d *Database) GetAirdrop(address common.Address) (*Airdrop, error) {
row := d.db.QueryRow(getAirdropQuery, strings.ToLower(address.String()))
if row.Err() != nil {
return nil, fmt.Errorf("error getting airdrop: %w", row.Err())
}
airdrop := new(Airdrop)
err := row.Scan(
&airdrop.Address,
&airdrop.VoterAmount,
&airdrop.MultisigSignerAmount,
&airdrop.GitcoinAmount,
&airdrop.ActiveBridgedAmount,
&airdrop.OpUserAmount,
&airdrop.OpRepeatUserAmount,
&airdrop.BonusAmount,
&airdrop.TotalAmount,
)
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("error scanning airdrop: %w", err)
}
return airdrop, nil
}
func nullableHash(in *common.Hash) *string {
if in == nil {
return nil
}
out := in.String()
return &out
}
package db
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
)
// Deposit contains transaction data for deposits made via the L1 to L2 bridge.
type Deposit struct {
GUID string
TxHash common.Hash
L1Token common.Address
L2Token common.Address
FromAddress common.Address
ToAddress common.Address
Amount *big.Int
Data []byte
LogIndex uint
}
// String returns the tx hash for the deposit.
func (d Deposit) String() string {
return d.TxHash.String()
}
// DepositJSON contains Deposit data suitable for JSON serialization.
type DepositJSON struct {
GUID string `json:"guid"`
FromAddress string `json:"from"`
ToAddress string `json:"to"`
L1Token *Token `json:"l1Token"`
L2Token string `json:"l2Token"`
Amount string `json:"amount"`
Data []byte `json:"data"`
LogIndex uint64 `json:"logIndex"`
BlockNumber uint64 `json:"blockNumber"`
BlockTimestamp string `json:"blockTimestamp"`
TxHash string `json:"transactionHash"`
}
package db
import (
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/common"
)
var ETHL1Address common.Address
// ETHL1Token is a placeholder token for differentiating ETH transactions from
// ERC20 transactions on L1.
var ETHL1Token = &Token{
Address: ETHL1Address.String(),
Name: "Ethereum",
Symbol: "ETH",
Decimals: 18,
}
// ETHL2Token is a placeholder token for differentiating ETH transactions from
// ERC20 transactions on L2.
var ETHL2Token = &Token{
Address: predeploys.LegacyERC20ETH,
Name: "Ethereum",
Symbol: "ETH",
Decimals: 18,
}
package db
import "github.com/google/uuid"
// NewGUID returns a new guid.
func NewGUID() string {
return uuid.New().String()
}
package db
import (
"github.com/ethereum/go-ethereum/common"
)
// IndexedL1Block contains the L1 block including the deposits in it.
type IndexedL1Block struct {
Hash common.Hash
ParentHash common.Hash
Number uint64
Timestamp uint64
Deposits []Deposit
ProvenWithdrawals []ProvenWithdrawal
FinalizedWithdrawals []FinalizedWithdrawal
}
// String returns the block hash for the indexed l1 block.
func (b IndexedL1Block) String() string {
return b.Hash.String()
}
// IndexedL2Block contains the L2 block including the withdrawals in it.
type IndexedL2Block struct {
Hash common.Hash
ParentHash common.Hash
Number uint64
Timestamp uint64
Withdrawals []Withdrawal
}
// String returns the block hash for the indexed l2 block.
func (b IndexedL2Block) String() string {
return b.Hash.String()
}
package db
import (
"github.com/ethereum/go-ethereum/common"
)
// BlockLocator contains the block number and hash. It can
// uniquely identify an Ethereum block
type BlockLocator struct {
Number uint64 `json:"number"`
Hash common.Hash `json:"hash"`
}
package db
// PaginationParam holds the pagination fields passed through by the REST
// middleware and queried by the database to page through deposits and
// withdrawals.
type PaginationParam struct {
Limit uint64 `json:"limit"`
Offset uint64 `json:"offset"`
Total uint64 `json:"total"`
}
type PaginatedDeposits struct {
Param *PaginationParam `json:"pagination"`
Deposits []DepositJSON `json:"items"`
}
type PaginatedWithdrawals struct {
Param *PaginationParam `json:"pagination"`
Withdrawals []WithdrawalJSON `json:"items"`
}
package db
const createL1BlocksTable = `
CREATE TABLE IF NOT EXISTS l1_blocks (
hash VARCHAR NOT NULL PRIMARY KEY,
parent_hash VARCHAR NOT NULL,
number INTEGER NOT NULL,
timestamp INTEGER NOT NULL
)
`
const createL2BlocksTable = `
CREATE TABLE IF NOT EXISTS l2_blocks (
hash VARCHAR NOT NULL PRIMARY KEY,
parent_hash VARCHAR NOT NULL,
number INTEGER NOT NULL,
timestamp INTEGER NOT NULL
)
`
const createDepositsTable = `
CREATE TABLE IF NOT EXISTS deposits (
guid VARCHAR PRIMARY KEY NOT NULL,
from_address VARCHAR NOT NULL,
to_address VARCHAR NOT NULL,
l1_token VARCHAR NOT NULL REFERENCES l1_tokens(address),
l2_token VARCHAR NOT NULL,
amount VARCHAR NOT NULL,
data BYTEA NOT NULL,
log_index INTEGER NOT NULL,
block_hash VARCHAR NOT NULL REFERENCES l1_blocks(hash),
tx_hash VARCHAR NOT NULL
)
`
const createL1TokensTable = `
CREATE TABLE IF NOT EXISTS l1_tokens (
address VARCHAR NOT NULL PRIMARY KEY,
name VARCHAR NOT NULL,
symbol VARCHAR NOT NULL,
decimals INTEGER NOT NULL
)
`
const createL2TokensTable = `
CREATE TABLE IF NOT EXISTS l2_tokens (
address TEXT NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
symbol TEXT NOT NULL,
decimals INTEGER NOT NULL
)
`
const createStateBatchesTable = `
CREATE TABLE IF NOT EXISTS state_batches (
index INTEGER NOT NULL PRIMARY KEY,
root VARCHAR NOT NULL,
size INTEGER NOT NULL,
prev_total INTEGER NOT NULL,
extra_data BYTEA NOT NULL,
block_hash VARCHAR NOT NULL REFERENCES l1_blocks(hash)
);
CREATE INDEX IF NOT EXISTS state_batches_block_hash ON state_batches(block_hash);
CREATE INDEX IF NOT EXISTS state_batches_size ON state_batches(size);
CREATE INDEX IF NOT EXISTS state_batches_prev_total ON state_batches(prev_total);
`
const createWithdrawalsTable = `
CREATE TABLE IF NOT EXISTS withdrawals (
guid VARCHAR PRIMARY KEY NOT NULL,
from_address VARCHAR NOT NULL,
to_address VARCHAR NOT NULL,
l1_token VARCHAR NOT NULL,
l2_token VARCHAR NOT NULL REFERENCES l2_tokens(address),
amount VARCHAR NOT NULL,
data BYTEA NOT NULL,
log_index INTEGER NOT NULL,
block_hash VARCHAR NOT NULL REFERENCES l2_blocks(hash),
tx_hash VARCHAR NOT NULL,
state_batch INTEGER REFERENCES state_batches(index)
)
`
const insertETHL1Token = `
INSERT INTO l1_tokens
(address, name, symbol, decimals)
VALUES ('0x0000000000000000000000000000000000000000', 'Ethereum', 'ETH', 18)
ON CONFLICT (address) DO NOTHING;
`
// earlier transactions used 0x0000000000000000000000000000000000000000 as
// address of ETH so insert both that and
// 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000
const insertETHL2Token = `
INSERT INTO l2_tokens
(address, name, symbol, decimals)
VALUES ('0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000', 'Ethereum', 'ETH', 18)
ON CONFLICT (address) DO NOTHING;
INSERT INTO l2_tokens
(address, name, symbol, decimals)
VALUES ('0x0000000000000000000000000000000000000000', 'Ethereum', 'ETH', 18)
ON CONFLICT (address) DO NOTHING;
`
const createL1L2NumberIndex = `
CREATE UNIQUE INDEX IF NOT EXISTS l1_blocks_number ON l1_blocks(number);
CREATE UNIQUE INDEX IF NOT EXISTS l2_blocks_number ON l2_blocks(number);
`
const createAirdropsTable = `
CREATE TABLE IF NOT EXISTS airdrops (
address VARCHAR(42) PRIMARY KEY,
voter_amount VARCHAR NOT NULL DEFAULT '0' CHECK(voter_amount ~ '^\d+$') ,
multisig_signer_amount VARCHAR NOT NULL DEFAULT '0' CHECK(multisig_signer_amount ~ '^\d+$'),
gitcoin_amount VARCHAR NOT NULL DEFAULT '0' CHECK(gitcoin_amount ~ '^\d+$'),
active_bridged_amount VARCHAR NOT NULL DEFAULT '0' CHECK(active_bridged_amount ~ '^\d+$'),
op_user_amount VARCHAR NOT NULL DEFAULT '0' CHECK(op_user_amount ~ '^\d+$'),
op_repeat_user_amount VARCHAR NOT NULL DEFAULT '0' CHECK(op_user_amount ~ '^\d+$'),
op_og_amount VARCHAR NOT NULL DEFAULT '0' CHECK(op_og_amount ~ '^\d+$'),
bonus_amount VARCHAR NOT NULL DEFAULT '0' CHECK(bonus_amount ~ '^\d+$'),
total_amount VARCHAR NOT NULL CHECK(voter_amount ~ '^\d+$')
)
`
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_proven_tx_hash VARCHAR NULL;
ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_proven_log_index INTEGER 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 INTEGER 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);
`
var schema = []string{
createL1BlocksTable,
createL2BlocksTable,
createL1TokensTable,
createL2TokensTable,
createStateBatchesTable,
insertETHL1Token,
insertETHL2Token,
createDepositsTable,
createWithdrawalsTable,
createL1L2NumberIndex,
createAirdropsTable,
updateWithdrawalsTable,
}
package db
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
)
// StateBatch is the state batch containing merkle root of the withdrawals
// periodically written to L1.
type StateBatch struct {
Index *big.Int
Root common.Hash
Size *big.Int
PrevTotal *big.Int
ExtraData []byte
BlockHash common.Hash
}
// StateBatchJSON contains StateBatch data suitable for JSON serialization.
type StateBatchJSON struct {
Index uint64 `json:"index"`
Root string `json:"root"`
Size uint64 `json:"size"`
PrevTotal uint64 `json:"prevTotal"`
ExtraData []byte `json:"extraData"`
BlockHash string `json:"blockHash"`
BlockNumber uint64 `json:"blockNumber"`
BlockTimestamp uint64 `json:"blockTimestamp"`
}
package db
// Token contains the token details of the ERC20 contract at the given address.
// NOTE: The Token address will almost definitely be different on L1 and L2, so
// we need to track it on both chains when handling transactions.
type Token struct {
Address string `json:"address"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals uint8 `json:"decimals"`
}
package db
import "database/sql"
func txn(db *sql.DB, apply func(*sql.Tx) error) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer func() {
if p := recover(); p != nil {
// Ignore since we're panicking anyway
_ = tx.Rollback()
panic(p)
}
}()
err = apply(tx)
if err != nil {
// Don't swallow application error
_ = tx.Rollback()
return err
}
return tx.Commit()
}
package db
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
)
// Withdrawal contains transaction data for withdrawals made via the L2 to L1 bridge.
type Withdrawal struct {
GUID string
TxHash common.Hash
L1Token common.Address
L2Token common.Address
FromAddress common.Address
ToAddress common.Address
Amount *big.Int
Data []byte
LogIndex uint
BedrockHash *common.Hash
}
// String returns the tx hash for the withdrawal.
func (w Withdrawal) String() string {
return w.TxHash.String()
}
// WithdrawalJSON contains Withdrawal data suitable for JSON serialization.
type WithdrawalJSON struct {
GUID string `json:"guid"`
FromAddress string `json:"from"`
ToAddress string `json:"to"`
L1Token string `json:"l1Token"`
L2Token *Token `json:"l2Token"`
Amount string `json:"amount"`
Data []byte `json:"data"`
LogIndex uint64 `json:"logIndex"`
BlockNumber uint64 `json:"blockNumber"`
BlockTimestamp string `json:"blockTimestamp"`
TxHash string `json:"transactionHash"`
Batch *StateBatchJSON `json:"batch"`
BedrockWithdrawalHash *string `json:"bedrockWithdrawalHash"`
BedrockProvenTxHash *string `json:"bedrockProvenTxHash"`
BedrockProvenLogIndex *int `json:"bedrockProvenLogIndex"`
BedrockFinalizedTxHash *string `json:"bedrockFinalizedTxHash"`
BedrockFinalizedLogIndex *int `json:"bedrockFinalizedLogIndex"`
BedrockFinalizedSuccess *bool `json:"bedrockFinalizedSuccess"`
}
type FinalizationState int
const (
FinalizationStateAny FinalizationState = iota
FinalizationStateFinalized
FinalizationStateUnfinalized
)
func ParseFinalizationState(in string) FinalizationState {
switch in {
case "true":
return FinalizationStateFinalized
case "false":
return FinalizationStateUnfinalized
default:
return FinalizationStateAny
}
}
func (f FinalizationState) SQL() string {
switch f {
case FinalizationStateFinalized:
return "AND withdrawals.br_withdrawal_finalized_tx_hash IS NOT NULL"
case FinalizationStateUnfinalized:
return "AND withdrawals.br_withdrawal_finalized_tx_hash IS NULL"
}
return ""
}
type ProvenWithdrawal struct {
From common.Address
To common.Address
WithdrawalHash common.Hash
TxHash common.Hash
LogIndex uint
}
type FinalizedWithdrawal struct {
WithdrawalHash common.Hash
TxHash common.Hash
Success bool
LogIndex uint
}
......@@ -2,8 +2,5 @@
INDEXER_L1_ETH_RPC=FILL_ME_IN
INDEXER_L2_ETH_RPC=FILL_ME_IN
# temporary env variable to enable to new indexer
INDEXER_REFRESH=1
# Fill in to use prisma studio ui with a db other than the default
# DATABASE_URL=FILL_ME_IN
package flags
import (
"time"
"github.com/urfave/cli"
)
const envVarPrefix = "INDEXER_"
func prefixEnvVar(name string) string {
return envVarPrefix + name
}
var (
/* Required Flags */
BuildEnvFlag = cli.StringFlag{
Name: "build-env",
Usage: "Build environment for which the binary is produced, " +
"e.g. production or development",
Required: true,
EnvVar: prefixEnvVar("BUILD_ENV"),
}
ChainIDFlag = cli.StringFlag{
Name: "chain-id",
Usage: "Ethereum chain ID",
Required: true,
EnvVar: prefixEnvVar("CHAIN_ID"),
}
L1EthRPCFlag = cli.StringFlag{
Name: "l1-eth-rpc",
Usage: "HTTP provider URL for L1",
Required: true,
EnvVar: prefixEnvVar("L1_ETH_RPC"),
}
L2EthRPCFlag = cli.StringFlag{
Name: "l2-eth-rpc",
Usage: "HTTP provider URL for L2",
Required: true,
EnvVar: prefixEnvVar("L2_ETH_RPC"),
}
L1AddressManagerAddressFlag = cli.StringFlag{
Name: "l1-address-manager-address",
Usage: "Address of the L1 address manager",
Required: true,
EnvVar: prefixEnvVar("L1_ADDRESS_MANAGER_ADDRESS"),
}
DBHostFlag = cli.StringFlag{
Name: "db-host",
Usage: "Hostname of the database connection",
Required: true,
EnvVar: prefixEnvVar("DB_HOST"),
}
DBPortFlag = cli.Uint64Flag{
Name: "db-port",
Usage: "Port of the database connection",
Required: true,
EnvVar: prefixEnvVar("DB_PORT"),
}
DBUserFlag = cli.StringFlag{
Name: "db-user",
Usage: "Username of the database connection",
Required: true,
EnvVar: prefixEnvVar("DB_USER"),
}
DBPasswordFlag = cli.StringFlag{
Name: "db-password",
Usage: "Password of the database connection",
Required: true,
EnvVar: prefixEnvVar("DB_PASSWORD"),
}
DBNameFlag = cli.StringFlag{
Name: "db-name",
Usage: "Database name of the database connection",
Required: true,
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.StringFlag{
Name: "bedrock.l1-standard-bridge-address",
Usage: "Address of the L1 standard bridge",
EnvVar: prefixEnvVar("BEDROCK_L1_STANDARD_BRIDGE"),
}
BedrockOptimismPortalAddress = cli.StringFlag{
Name: "bedrock.portal-address",
Usage: "Address of the portal",
EnvVar: prefixEnvVar("BEDROCK_OPTIMISM_PORTAL"),
}
/* Optional Flags */
DisableIndexer = cli.BoolFlag{
Name: "disable-indexer",
Usage: "Whether or not to enable the indexer on this instance",
Required: false,
EnvVar: prefixEnvVar("DISABLE_INDEXER"),
}
LogLevelFlag = cli.StringFlag{
Name: "log-level",
Usage: "The lowest log level that will be output",
Value: "info",
EnvVar: prefixEnvVar("LOG_LEVEL"),
}
LogTerminalFlag = cli.BoolFlag{
Name: "log-terminal",
Usage: "If true, outputs logs in terminal format, otherwise prints " +
"in JSON format. If SENTRY_ENABLE is set to true, this flag is " +
"ignored and logs are printed using JSON",
EnvVar: prefixEnvVar("LOG_TERMINAL"),
}
SentryEnableFlag = cli.BoolFlag{
Name: "sentry-enable",
Usage: "Whether or not to enable Sentry. If true, sentry-dsn must also be set",
EnvVar: prefixEnvVar("SENTRY_ENABLE"),
}
SentryDsnFlag = cli.StringFlag{
Name: "sentry-dsn",
Usage: "Sentry data source name",
EnvVar: prefixEnvVar("SENTRY_DSN"),
}
SentryTraceRateFlag = cli.DurationFlag{
Name: "sentry-trace-rate",
Usage: "Sentry trace rate",
Value: 50 * time.Millisecond,
EnvVar: prefixEnvVar("SENTRY_TRACE_RATE"),
}
L1StartBlockNumberFlag = cli.Uint64Flag{
Name: "start-block-number",
Usage: "The block number to start indexing from. Must be use together with start block hash",
Value: 0,
EnvVar: prefixEnvVar("START_BLOCK_NUMBER"),
}
L1ConfDepthFlag = cli.Uint64Flag{
Name: "l1-conf-depth",
Usage: "The number of confirmations after which headers are considered confirmed on L1",
Value: 20,
EnvVar: prefixEnvVar("L1_CONF_DEPTH"),
}
L2ConfDepthFlag = cli.Uint64Flag{
Name: "l2-conf-depth",
Usage: "The number of confirmations after which headers are considered confirmed on L1",
Value: 24,
EnvVar: prefixEnvVar("L2_CONF_DEPTH"),
}
MaxHeaderBatchSizeFlag = cli.Uint64Flag{
Name: "max-header-batch-size",
Usage: "The maximum number of headers to request as a batch",
Value: 2000,
EnvVar: prefixEnvVar("MAX_HEADER_BATCH_SIZE"),
}
RESTHostnameFlag = cli.StringFlag{
Name: "rest-hostname",
Usage: "The hostname of the REST server",
Value: "127.0.0.1",
EnvVar: prefixEnvVar("REST_HOSTNAME"),
}
RESTPortFlag = cli.Uint64Flag{
Name: "rest-port",
Usage: "The port of the REST server",
Value: 8080,
EnvVar: prefixEnvVar("REST_PORT"),
}
MetricsServerEnableFlag = cli.BoolFlag{
Name: "metrics-server-enable",
Usage: "Whether or not to run the embedded metrics server",
EnvVar: prefixEnvVar("METRICS_SERVER_ENABLE"),
}
MetricsHostnameFlag = cli.StringFlag{
Name: "metrics-hostname",
Usage: "The hostname of the metrics server",
Value: "127.0.0.1",
EnvVar: prefixEnvVar("METRICS_HOSTNAME"),
}
MetricsPortFlag = cli.Uint64Flag{
Name: "metrics-port",
Usage: "The port of the metrics server",
Value: 7300,
EnvVar: prefixEnvVar("METRICS_PORT"),
}
)
var requiredFlags = []cli.Flag{
BuildEnvFlag,
ChainIDFlag,
L1EthRPCFlag,
L2EthRPCFlag,
L1AddressManagerAddressFlag,
DBHostFlag,
DBPortFlag,
DBUserFlag,
DBPasswordFlag,
DBNameFlag,
}
var optionalFlags = []cli.Flag{
BedrockFlag,
BedrockL1StandardBridgeAddress,
BedrockOptimismPortalAddress,
DisableIndexer,
LogLevelFlag,
LogTerminalFlag,
SentryEnableFlag,
SentryDsnFlag,
SentryTraceRateFlag,
L1ConfDepthFlag,
L2ConfDepthFlag,
MaxHeaderBatchSizeFlag,
L1StartBlockNumberFlag,
RESTHostnameFlag,
RESTPortFlag,
MetricsServerEnableFlag,
MetricsHostnameFlag,
MetricsPortFlag,
}
// Flags contains the list of configuration options available to the binary.
var Flags = append(requiredFlags, optionalFlags...)
package flags
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/urfave/cli"
)
// TestRequiredFlagsSetRequired asserts that all flags deemed required properly
// have the Required field set to true.
func TestRequiredFlagsSetRequired(t *testing.T) {
for _, flag := range requiredFlags {
reqFlag, ok := flag.(cli.RequiredFlag)
require.True(t, ok)
require.True(t, reqFlag.IsRequired())
}
}
// TestOptionalFlagsDontSetRequired asserts that all flags deemed optional set
// the Required field to false.
func TestOptionalFlagsDontSetRequired(t *testing.T) {
for _, flag := range optionalFlags {
reqFlag, ok := flag.(cli.RequiredFlag)
require.True(t, ok)
require.False(t, reqFlag.IsRequired())
}
}
......@@ -10,6 +10,7 @@ host = "127.0.0.1"
port = 5432
user = "postgres"
password = "postgres"
name = "indexer"
[api]
host = "127.0.0.1"
......
package integration_tests
import (
"database/sql"
"encoding/json"
"fmt"
"math/big"
"net/http"
"os"
"testing"
"time"
"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/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/indexer/legacy"
"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/config"
"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-optimism/optimism/op-service/client/utils"
_ "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, utils.WaitBlock(e2eutils.TimeoutCtx(t, 30*time.Second), l2Client, 10))
l1SB, err := bindings.NewL1StandardBridge(cfg.L1Deployments.L1StandardBridgeProxy, l1Client)
require.NoError(t, err)
l2SB, err := bindings.NewL2StandardBridge(predeploys.L2StandardBridgeAddr, l2Client)
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 := legacy.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,
L1ConfDepth: 1,
L2ConfDepth: 1,
MaxHeaderBatchSize: 2,
RESTHostname: "127.0.0.1",
RESTPort: 7980,
DisableIndexer: false,
Bedrock: true,
BedrockL1StandardBridgeAddress: cfg.DeployConfig.L1StandardBridgeProxy,
BedrockOptimismPortalAddress: cfg.DeployConfig.OptimismPortalProxy,
}
idxr, err := legacy.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 := utils.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 = utils.WaitReceiptOK(e2eutils.TimeoutCtx(t, 15*time.Second), l2Client, l2Hash)
require.NoError(t, err)
// Poll for indexer deposit
var depPage *db.PaginatedDeposits
require.NoError(t, utils.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 := utils.WaitReceiptOK(e2eutils.TimeoutCtx(t, 30*time.Second), l2Client, wdTx.Hash())
require.NoError(t, err)
var wdPage *db.PaginatedWithdrawals
require.NoError(t, utils.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.BedrockProvenTxHash)
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)
// Prove our withdrawal
wdParams, proveReceipt := op_e2e.ProveWithdrawal(t, cfg, l1Client, sys.Nodes["sequencer"], cfg.Secrets.Alice, wdReceipt)
wdPage = nil
require.NoError(t, utils.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].BedrockProvenTxHash == nil {
return false, nil
}
wdPage = res
return true, nil
}))
wd := wdPage.Withdrawals[0]
require.Equal(t, proveReceipt.TxHash.String(), *wd.BedrockProvenTxHash)
require.Nil(t, wd.BedrockFinalizedTxHash)
// Finalize withdrawal
err = withdrawals.WaitForFinalizationPeriod(e2eutils.TimeoutCtx(t, 30*time.Second), l1Client, proveReceipt.BlockNumber, config.L1Deployments.L2OutputOracleProxy)
require.Nil(t, err)
finReceipt := op_e2e.FinalizeWithdrawal(t, cfg, l1Client, cfg.Secrets.Alice, wdReceipt, wdParams)
wdPage = nil
require.NoError(t, utils.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, proveReceipt.TxHash.String(), *wd.BedrockProvenTxHash)
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)
}
package legacy
import (
"errors"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli"
"github.com/ethereum-optimism/optimism/indexer/flags"
)
var (
// ErrSentryDSNNotSet signals that not Data Source Name was provided
// with which to configure Sentry logging.
ErrSentryDSNNotSet = errors.New("sentry-dsn must be set if use-sentry " +
"is true")
)
type Config struct {
/* Required Params */
// ChainID identifies the chain being indexed.
ChainID uint64
// L1EthRpc is the HTTP provider URL for L1.
L1EthRpc string
// L2EthRpc is the HTTP provider URL for L1.
L2EthRpc string
// L1AddressManagerAddress is the address of the address manager for L1.
L1AddressManagerAddress string
// PollInterval is the delay between querying L2 for more transaction
// and creating a new batch.
PollInterval time.Duration
// Hostname of the database connection.
DBHost string
// Port of the database connection.
DBPort uint64
// Username of the database connection.
DBUser string
// Password of the database connection.
DBPassword string
// Database name of the database connection.
DBName string
/* Optional Params */
// LogLevel is the lowest log level that will be output.
LogLevel string
// LogTerminal if true, prints to stdout in terminal format, otherwise
// prints using JSON. If SentryEnable is true this flag is ignored, and logs
// are printed using JSON.
LogTerminal bool
// L1StartBlockNumber is the block number to start indexing L1 from.
L1StartBlockNumber uint64
// L1ConfDepth is the number of confirmations after which headers are
// considered confirmed on L1.
L1ConfDepth uint64
// L2ConfDepth is the number of confirmations after which headers are
// considered confirmed on L2.
L2ConfDepth uint64
// MaxHeaderBatchSize is the maximum number of headers to request as a
// batch.
MaxHeaderBatchSize uint64
// RESTHostname is the hostname at which the REST server is running.
RESTHostname string
// RESTPort is the port at which the REST server is running.
RESTPort uint64
// MetricsServerEnable if true, will create a metrics client and log to
// Prometheus.
MetricsServerEnable bool
// MetricsHostname is the hostname at which the metrics server is running.
MetricsHostname string
// MetricsPort is the port at which the metrics server is running.
MetricsPort uint64
// DisableIndexer enables/disables the indexer.
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.
// This method fails if ValidateConfig deems the configuration to be malformed.
func NewConfig(ctx *cli.Context) (Config, error) {
cfg := Config{
/* Required Flags */
ChainID: ctx.GlobalUint64(flags.ChainIDFlag.Name),
L1EthRpc: ctx.GlobalString(flags.L1EthRPCFlag.Name),
L2EthRpc: ctx.GlobalString(flags.L2EthRPCFlag.Name),
L1AddressManagerAddress: ctx.GlobalString(flags.L1AddressManagerAddressFlag.Name),
DBHost: ctx.GlobalString(flags.DBHostFlag.Name),
DBPort: ctx.GlobalUint64(flags.DBPortFlag.Name),
DBUser: ctx.GlobalString(flags.DBUserFlag.Name),
DBPassword: ctx.GlobalString(flags.DBPasswordFlag.Name),
DBName: ctx.GlobalString(flags.DBNameFlag.Name),
/* Optional Flags */
Bedrock: ctx.GlobalBool(flags.BedrockFlag.Name),
BedrockL1StandardBridgeAddress: common.HexToAddress(ctx.GlobalString(flags.BedrockL1StandardBridgeAddress.Name)),
BedrockOptimismPortalAddress: common.HexToAddress(ctx.GlobalString(flags.BedrockOptimismPortalAddress.Name)),
DisableIndexer: ctx.GlobalBool(flags.DisableIndexer.Name),
LogLevel: ctx.GlobalString(flags.LogLevelFlag.Name),
LogTerminal: ctx.GlobalBool(flags.LogTerminalFlag.Name),
L1StartBlockNumber: ctx.GlobalUint64(flags.L1StartBlockNumberFlag.Name),
L1ConfDepth: ctx.GlobalUint64(flags.L1ConfDepthFlag.Name),
L2ConfDepth: ctx.GlobalUint64(flags.L2ConfDepthFlag.Name),
MaxHeaderBatchSize: ctx.GlobalUint64(flags.MaxHeaderBatchSizeFlag.Name),
MetricsServerEnable: ctx.GlobalBool(flags.MetricsServerEnableFlag.Name),
RESTHostname: ctx.GlobalString(flags.RESTHostnameFlag.Name),
RESTPort: ctx.GlobalUint64(flags.RESTPortFlag.Name),
MetricsHostname: ctx.GlobalString(flags.MetricsHostnameFlag.Name),
MetricsPort: ctx.GlobalUint64(flags.MetricsPortFlag.Name),
}
err := ValidateConfig(&cfg)
if err != nil {
return Config{}, err
}
return cfg, nil
}
// ValidateConfig ensures additional constraints on the parsed configuration to
// ensure that it is well-formed.
func ValidateConfig(cfg *Config) error {
// Sanity check log level.
if cfg.LogLevel == "" {
cfg.LogLevel = "debug"
}
_, err := log.LvlFromString(cfg.LogLevel)
if err != nil {
return err
}
if cfg.Bedrock && (cfg.BedrockL1StandardBridgeAddress == common.Address{} || cfg.BedrockOptimismPortalAddress == common.Address{}) {
return errors.New("must specify l1 standard bridge and optimism portal addresses in bedrock mode")
}
return nil
}
package legacy_test
import (
"fmt"
"testing"
legacy "github.com/ethereum-optimism/optimism/indexer/legacy"
"github.com/stretchr/testify/require"
)
var validateConfigTests = []struct {
name string
cfg legacy.Config
expErr error
}{
{
name: "bad log level",
cfg: legacy.Config{
LogLevel: "unknown",
},
expErr: fmt.Errorf("unknown level: unknown"),
},
}
// TestValidateConfig asserts the behavior of ValidateConfig by testing expected
// error and success configurations.
func TestValidateConfig(t *testing.T) {
for _, test := range validateConfigTests {
t.Run(test.name, func(t *testing.T) {
err := legacy.ValidateConfig(&test.cfg)
require.Equal(t, err, test.expErr)
})
}
}
package legacy
import (
"context"
"fmt"
"math/big"
"net"
"net/http"
"os"
"strconv"
"time"
"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/server"
"github.com/rs/cors"
database "github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/indexer/services/l1"
"github.com/ethereum-optimism/optimism/indexer/services/l2"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
"github.com/gorilla/mux"
"github.com/urfave/cli"
)
const (
// defaultDialTimeout is default duration the service will wait on
// startup to make a connection to either the L1 or L2 backends.
defaultDialTimeout = 5 * time.Second
)
// Main is the entrypoint into the indexer service. This method returns
// a closure that executes the service and blocks until the service exits. The
// use of a closure allows the parameters bound to the top-level main package,
// e.g. GitVersion, to be captured and used once the function is executed.
func Main(gitVersion string) func(ctx *cli.Context) error {
return func(ctx *cli.Context) error {
cfg, err := NewConfig(ctx)
if err != nil {
return err
}
log.Info("Initializing indexer")
indexer, err := NewIndexer(cfg)
if err != nil {
log.Error("Unable to create indexer", "error", err)
return err
}
log.Info("Starting indexer")
if err := indexer.Start(); err != nil {
return err
}
defer indexer.Stop()
log.Info("Indexer started")
<-(chan struct{})(nil)
return nil
}
}
// Indexer is a service that configures the necessary resources for
// running the Sync and BlockHandler sub-services.
type Indexer struct {
ctx context.Context
cfg Config
l1Client *ethclient.Client
l2Client *ethclient.Client
l1IndexingService *l1.Service
l2IndexingService *l2.Service
airdropService *services.Airdrop
router *mux.Router
metrics *metrics.Metrics
db *database.Database
server *http.Server
}
// NewIndexer initializes the Indexer, gathering any resources
// that will be needed by the TxIndexer and StateIndexer
// sub-services.
func NewIndexer(cfg Config) (*Indexer, error) {
ctx := context.Background()
var logHandler log.Handler
if cfg.LogTerminal {
logHandler = log.StreamHandler(os.Stdout, log.TerminalFormat(true))
} else {
logHandler = log.StreamHandler(os.Stdout, log.JSONFormat())
}
logLevel, err := log.LvlFromString(cfg.LogLevel)
if err != nil {
return nil, err
}
log.Root().SetHandler(log.LvlFilterHandler(logLevel, logHandler))
// Connect to L1 and L2 providers. Perform these last since they are the
// most expensive.
l1Client, rawl1Client, err := dialEthClientWithTimeout(ctx, cfg.L1EthRpc)
if err != nil {
return nil, err
}
l2Client, l2RPC, err := dialEthClientWithTimeout(ctx, cfg.L2EthRpc)
if err != nil {
return nil, err
}
m := metrics.NewMetrics(nil)
if cfg.MetricsServerEnable {
go func() {
_, err := m.Serve(cfg.MetricsHostname, cfg.MetricsPort)
if err != nil {
log.Error("metrics server failed to start", "err", err)
}
}()
log.Info("metrics server enabled", "host", cfg.MetricsHostname, "port", cfg.MetricsPort)
}
dsn := fmt.Sprintf("host=%s port=%d dbname=%s sslmode=disable",
cfg.DBHost, cfg.DBPort, cfg.DBName)
if cfg.DBUser != "" {
dsn += fmt.Sprintf(" user=%s", cfg.DBUser)
}
if cfg.DBPassword != "" {
dsn += fmt.Sprintf(" password=%s", cfg.DBPassword)
}
db, err := database.NewDatabase(dsn)
if err != nil {
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{
Context: ctx,
Metrics: m,
L1Client: l1Client,
RawL1Client: rawl1Client,
ChainID: new(big.Int).SetUint64(cfg.ChainID),
AddressManager: addrManager,
DB: db,
ConfDepth: cfg.L1ConfDepth,
MaxHeaderBatchSize: cfg.MaxHeaderBatchSize,
StartBlockNumber: cfg.L1StartBlockNumber,
Bedrock: cfg.Bedrock,
})
if err != nil {
return nil, err
}
l2IndexingService, err := l2.NewService(l2.ServiceConfig{
Context: ctx,
Metrics: m,
L2RPC: l2RPC,
L2Client: l2Client,
DB: db,
ConfDepth: cfg.L2ConfDepth,
MaxHeaderBatchSize: cfg.MaxHeaderBatchSize,
StartBlockNumber: uint64(0),
Bedrock: cfg.Bedrock,
})
if err != nil {
return nil, err
}
return &Indexer{
ctx: ctx,
cfg: cfg,
l1Client: l1Client,
l2Client: l2Client,
l1IndexingService: l1IndexingService,
l2IndexingService: l2IndexingService,
airdropService: services.NewAirdrop(db, m),
router: mux.NewRouter(),
metrics: m,
db: db,
}, nil
}
// Serve spins up a REST API server at the given hostname and port.
func (b *Indexer) Serve() error {
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
})
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/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.GetWithdrawalBatch).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("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
_, err := w.Write([]byte("OK"))
if err != nil {
log.Error("Error handling /healthz", "error", err)
}
})
middleware := server.LoggingMiddleware(b.metrics, log.New("service", "server"))
port := strconv.FormatUint(b.cfg.RESTPort, 10)
addr := net.JoinHostPort(b.cfg.RESTHostname, port)
b.server = &http.Server{
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
// starts the REST server.
func (b *Indexer) Start() error {
if b.cfg.DisableIndexer {
log.Info("indexer disabled, only serving data")
} else {
err := b.l1IndexingService.Start()
if err != nil {
return err
}
err = b.l2IndexingService.Start()
if err != nil {
return err
}
}
return b.Serve()
}
// Stop stops the indexing service on L1 and L2 chains.
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 {
b.l1IndexingService.Stop()
b.l2IndexingService.Stop()
}
}
// dialL1EthClientWithTimeout attempts to dial the L1 provider using the
// provided URL. If the dial doesn't complete within defaultDialTimeout seconds,
// this method will return an error.
func dialEthClientWithTimeout(ctx context.Context, url string) (
*ethclient.Client, *rpc.Client, error) {
ctxt, cancel := context.WithTimeout(ctx, defaultDialTimeout)
defer cancel()
c, err := rpc.DialContext(ctxt, url)
if err != nil {
return nil, nil, err
}
return ethclient.NewClient(c), c, nil
}
package metrics
import (
"net"
"net/http"
"strconv"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
const metricsNamespace = "indexer"
type Metrics struct {
SyncHeight *prometheus.GaugeVec
DepositsCount *prometheus.CounterVec
WithdrawalsCount *prometheus.CounterVec
StateBatchesCount prometheus.Counter
L1CatchingUp prometheus.Gauge
L2CatchingUp prometheus.Gauge
SyncPercent *prometheus.GaugeVec
UpdateDuration *prometheus.SummaryVec
CachedTokensCount *prometheus.CounterVec
HTTPRequestsCount prometheus.Counter
HTTPResponsesCount *prometheus.CounterVec
HTTPRequestDurationSecs prometheus.Summary
tokenAddrs map[string]string
}
func NewMetrics(monitoredTokens map[string]string) *Metrics {
mts := make(map[string]string)
mts["0x0000000000000000000000000000000000000000"] = "ETH"
for addr, symbol := range monitoredTokens {
mts[addr] = symbol
}
return &Metrics{
SyncHeight: promauto.NewGaugeVec(prometheus.GaugeOpts{
Name: "sync_height",
Help: "The max height of the indexer's last batch of L1/L1 blocks.",
Namespace: metricsNamespace,
}, []string{
"chain",
}),
DepositsCount: promauto.NewCounterVec(prometheus.CounterOpts{
Name: "deposits_count",
Help: "The number of deposits indexed.",
Namespace: metricsNamespace,
}, []string{
"symbol",
}),
WithdrawalsCount: promauto.NewCounterVec(prometheus.CounterOpts{
Name: "withdrawals_count",
Help: "The number of withdrawals indexed.",
Namespace: metricsNamespace,
}, []string{
"symbol",
}),
StateBatchesCount: promauto.NewCounter(prometheus.CounterOpts{
Name: "state_batches_count",
Help: "The number of state batches indexed.",
Namespace: metricsNamespace,
}),
L1CatchingUp: promauto.NewGauge(prometheus.GaugeOpts{
Name: "l1_catching_up",
Help: "Whether or not L1 is far behind the chain tip.",
Namespace: metricsNamespace,
}),
L2CatchingUp: promauto.NewGauge(prometheus.GaugeOpts{
Name: "l2_catching_up",
Help: "Whether or not L2 is far behind the chain tip.",
Namespace: metricsNamespace,
}),
SyncPercent: promauto.NewGaugeVec(prometheus.GaugeOpts{
Name: "sync_percent",
Help: "Sync percentage for each chain.",
Namespace: metricsNamespace,
}, []string{
"chain",
}),
UpdateDuration: promauto.NewSummaryVec(prometheus.SummaryOpts{
Name: "update_duration_seconds",
Help: "How long each update took.",
Namespace: metricsNamespace,
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.95: 0.005, 0.99: 0.001},
}, []string{
"chain",
}),
CachedTokensCount: promauto.NewCounterVec(prometheus.CounterOpts{
Name: "cached_tokens_count",
Help: "How many tokens are in the cache",
Namespace: metricsNamespace,
}, []string{
"chain",
}),
HTTPRequestsCount: promauto.NewCounter(prometheus.CounterOpts{
Name: "http_requests_count",
Help: "How many HTTP requests this instance has seen",
Namespace: metricsNamespace,
}),
HTTPResponsesCount: promauto.NewCounterVec(prometheus.CounterOpts{
Name: "http_responses_count",
Help: "How many HTTP responses this instance has served",
Namespace: metricsNamespace,
}, []string{
"status_code",
}),
HTTPRequestDurationSecs: promauto.NewSummary(prometheus.SummaryOpts{
Name: "http_request_duration_secs",
Help: "How long each HTTP request took",
Namespace: metricsNamespace,
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.95: 0.005, 0.99: 0.001},
}),
tokenAddrs: mts,
}
}
func (m *Metrics) SetL1SyncHeight(height uint64) {
m.SyncHeight.WithLabelValues("l1").Set(float64(height))
}
func (m *Metrics) SetL2SyncHeight(height uint64) {
m.SyncHeight.WithLabelValues("l2").Set(float64(height))
}
func (m *Metrics) RecordDeposit(addr common.Address) {
sym := m.tokenAddrs[addr.String()]
if sym == "" {
sym = "UNKNOWN"
}
m.DepositsCount.WithLabelValues(sym).Inc()
}
func (m *Metrics) RecordWithdrawal(addr common.Address) {
sym := m.tokenAddrs[addr.String()]
if sym == "" {
sym = "UNKNOWN"
}
m.WithdrawalsCount.WithLabelValues(sym).Inc()
}
func (m *Metrics) RecordStateBatches(count int) {
m.StateBatchesCount.Add(float64(count))
}
func (m *Metrics) SetL1CatchingUp(state bool) {
var catchingUp float64
if state {
catchingUp = 1
}
m.L1CatchingUp.Set(catchingUp)
}
func (m *Metrics) SetL2CatchingUp(state bool) {
var catchingUp float64
if state {
catchingUp = 1
}
m.L2CatchingUp.Set(catchingUp)
}
func (m *Metrics) SetL1SyncPercent(height uint64, head uint64) {
m.SyncPercent.WithLabelValues("l1").Set(float64(height) / float64(head))
}
func (m *Metrics) SetL2SyncPercent(height uint64, head uint64) {
m.SyncPercent.WithLabelValues("l2").Set(float64(height) / float64(head))
}
func (m *Metrics) IncL1CachedTokensCount() {
m.CachedTokensCount.WithLabelValues("l1").Inc()
}
func (m *Metrics) IncL2CachedTokensCount() {
m.CachedTokensCount.WithLabelValues("l2").Inc()
}
func (m *Metrics) RecordHTTPRequest() {
m.HTTPRequestsCount.Inc()
}
func (m *Metrics) RecordHTTPResponse(code int, dur time.Duration) {
m.HTTPResponsesCount.WithLabelValues(strconv.Itoa(code)).Inc()
m.HTTPRequestDurationSecs.Observe(float64(dur) / float64(time.Second))
}
func (m *Metrics) Serve(hostname string, port uint64) (*http.Server, error) {
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
srv := new(http.Server)
srv.Addr = net.JoinHostPort(hostname, strconv.FormatUint(port, 10))
srv.Handler = mux
err := srv.ListenAndServe()
return srv, err
}
package server
import (
"encoding/json"
"net/http"
"runtime/debug"
"time"
"github.com/ethereum-optimism/optimism/indexer/metrics"
"github.com/ethereum/go-ethereum/log"
)
// RespondWithError writes the given error code and message to the writer.
func RespondWithError(w http.ResponseWriter, code int, message string) {
RespondWithJSON(w, code, map[string]string{"error": message})
}
// RespondWithJSON writes the given payload marshalled as JSON to the writer.
func RespondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
response, _ := json.Marshal(payload)
w.WriteHeader(code)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(response)
}
// responseWriter is a minimal wrapper for http.ResponseWriter that allows the
// written HTTP status code to be captured for logging.
type responseWriter struct {
http.ResponseWriter
status int
wroteHeader bool
}
func wrapResponseWriter(w http.ResponseWriter) *responseWriter {
return &responseWriter{ResponseWriter: w}
}
func (rw *responseWriter) Status() int {
return rw.status
}
func (rw *responseWriter) WriteHeader(code int) {
if rw.wroteHeader {
return
}
rw.status = code
rw.ResponseWriter.WriteHeader(code)
rw.wroteHeader = true
}
// LoggingMiddleware logs the incoming HTTP request & its duration.
func LoggingMiddleware(metrics *metrics.Metrics, logger log.Logger) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
w.WriteHeader(http.StatusInternalServerError)
logger.Error(
"server panicked",
"err", err,
"trace", debug.Stack(),
)
}
}()
metrics.RecordHTTPRequest()
start := time.Now()
wrapped := wrapResponseWriter(w)
next.ServeHTTP(wrapped, r)
dur := time.Since(start)
logger.Info(
"served request",
"status", wrapped.status,
"method", r.Method,
"path", r.URL.EscapedPath(),
"duration", dur,
)
metrics.RecordHTTPResponse(wrapped.status, dur)
}
return http.HandlerFunc(fn)
}
}
package services
import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
legacy_bindings "github.com/ethereum-optimism/optimism/op-bindings/legacy-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, *legacy_bindings.StateCommitmentChain)
OptimismPortal() (common.Address, *bindings.OptimismPortal)
}
type LegacyAddresses struct {
l1SB *bindings.L1StandardBridge
l1SBAddr common.Address
scc *legacy_bindings.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 := legacy_bindings.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, *legacy_bindings.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, *legacy_bindings.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
}
package services
import (
"net/http"
"github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/indexer/metrics"
"github.com/ethereum-optimism/optimism/indexer/server"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/gorilla/mux"
)
var airdropLogger = log.New("service", "airdrop")
type Airdrop struct {
db *db.Database
metrics *metrics.Metrics
}
func NewAirdrop(db *db.Database, metrics *metrics.Metrics) *Airdrop {
return &Airdrop{
db: db,
metrics: metrics,
}
}
func (a *Airdrop) GetAirdrop(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
address := vars["address"]
airdrop, err := a.db.GetAirdrop(common.HexToAddress(address))
if err != nil {
airdropLogger.Error("db error getting airdrop", "err", err)
server.RespondWithError(w, http.StatusInternalServerError, "database error")
return
}
if airdrop == nil {
server.RespondWithError(w, http.StatusNotFound, "airdrop not found")
return
}
server.RespondWithJSON(w, http.StatusOK, airdrop)
}
package bridge
import (
"context"
"errors"
"math/big"
"github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/indexer/services"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
legacy_bindings "github.com/ethereum-optimism/optimism/op-bindings/legacy-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
// WithdrawalsMap is a collection of withdrawal objects keyed
// on block hashes.
type InitiatedWithdrawalMap map[common.Hash][]db.Withdrawal
// ProvenWithdrawalsMap is a collection of proven withdrawal
// objects keyed on block hashses
type ProvenWithdrawalsMap map[common.Hash][]db.ProvenWithdrawal
// FinalizedWithdrawalsMap is a collection of finalized withdrawal
// objects keyed on block hashes.
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")},
},
}
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) (*legacy_bindings.StateCommitmentChainFilterer, error) {
sccAddr, _ := addrs.StateCommitmentChain()
filter, err := legacy_bindings.NewStateCommitmentChainFilterer(sccAddr, client)
if err != nil {
return nil, err
}
return filter, nil
}
package bridge
import "time"
const (
DefaultConnectionTimeout = 60 * time.Second
)
package bridge
import (
"context"
"github.com/ethereum-optimism/optimism/indexer/db"
"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 EthBridge struct {
name string
address common.Address
contract *bindings.L1StandardBridge
}
func (e *EthBridge) Address() common.Address {
return e.address
}
func (e *EthBridge) GetDepositsByBlockRange(ctx context.Context, start, end uint64) (DepositsMap, error) {
depositsByBlockhash := make(DepositsMap)
opts := &bind.FilterOpts{
Context: ctx,
Start: start,
End: &end,
}
iter, err := backoff.Do(ctx, 3, backoff.Exponential(), func() (*bindings.L1StandardBridgeETHDepositInitiatedIterator, error) {
return e.contract.FilterETHDepositInitiated(opts, nil, nil)
})
if err != nil {
return nil, err
}
defer iter.Close()
for iter.Next() {
depositsByBlockhash[iter.Event.Raw.BlockHash] = append(
depositsByBlockhash[iter.Event.Raw.BlockHash], db.Deposit{
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,
})
}
return depositsByBlockhash, iter.Error()
}
func (e *EthBridge) String() string {
return e.name
}
package bridge
import (
"context"
"time"
legacy_bindings "github.com/ethereum-optimism/optimism/op-bindings/legacy-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
// FilterStateBatchAppendedWithRetry retries the given func until it succeeds,
// waiting for clientRetryInterval duration after every call.
func FilterStateBatchAppendedWithRetry(ctx context.Context, filterer *legacy_bindings.StateCommitmentChainFilterer, opts *bind.FilterOpts) (*legacy_bindings.StateCommitmentChainStateBatchAppendedIterator, error) {
for {
ctxt, cancel := context.WithTimeout(ctx, DefaultConnectionTimeout)
opts.Context = ctxt
res, err := filterer.FilterStateBatchAppended(opts, nil)
cancel()
if err == nil {
return res, nil
}
logger.Error("Error fetching filter", "err", err)
time.Sleep(clientRetryInterval)
}
}
package bridge
import "github.com/ethereum/go-ethereum/log"
var logger = log.New("service", "l1-bridge")
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) GetProvenWithdrawalsByBlockRange(ctx context.Context, start, end uint64) (ProvenWithdrawalsMap, error) {
wdsByBlockHash := make(ProvenWithdrawalsMap)
opts := &bind.FilterOpts{
Context: ctx,
Start: start,
End: &end,
}
iter, err := backoff.Do(ctx, 3, backoff.Exponential(), func() (*bindings.OptimismPortalWithdrawalProvenIterator, error) {
return p.contract.FilterWithdrawalProven(opts, nil, nil, nil)
})
if err != nil {
return nil, err
}
defer iter.Close()
for iter.Next() {
wdsByBlockHash[iter.Event.Raw.BlockHash] = append(
wdsByBlockHash[iter.Event.Raw.BlockHash], db.ProvenWithdrawal{
WithdrawalHash: iter.Event.WithdrawalHash,
From: iter.Event.From,
To: iter.Event.To,
TxHash: iter.Event.Raw.TxHash,
LogIndex: iter.Event.Raw.Index,
},
)
}
return wdsByBlockHash, iter.Error()
}
func (p *Portal) GetFinalizedWithdrawalsByBlockRange(ctx context.Context, start, end uint64) (FinalizedWithdrawalsMap, error) {
wdsByBlockHash := make(FinalizedWithdrawalsMap)
opts := &bind.FilterOpts{
Context: ctx,
Start: start,
End: &end,
}
iter, err := backoff.Do(ctx, 3, backoff.Exponential(), func() (*bindings.OptimismPortalWithdrawalFinalizedIterator, error) {
return p.contract.FilterWithdrawalFinalized(opts, nil)
})
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()
}
package bridge
import (
"context"
"github.com/ethereum-optimism/optimism/indexer/db"
"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 StandardBridge struct {
name string
address common.Address
contract *bindings.L1StandardBridge
}
func (s *StandardBridge) Address() common.Address {
return s.address
}
func (s *StandardBridge) GetDepositsByBlockRange(ctx context.Context, start, end uint64) (DepositsMap, error) {
depositsByBlockhash := make(DepositsMap)
opts := &bind.FilterOpts{
Context: ctx,
Start: start,
End: &end,
}
iter, err := backoff.Do(ctx, 3, backoff.Exponential(), func() (*bindings.L1StandardBridgeERC20DepositInitiatedIterator, error) {
return s.contract.FilterERC20DepositInitiated(opts, nil, nil, nil)
})
if err != nil {
return nil, err
}
defer iter.Close()
for iter.Next() {
depositsByBlockhash[iter.Event.Raw.BlockHash] = append(
depositsByBlockhash[iter.Event.Raw.BlockHash], db.Deposit{
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,
})
}
return depositsByBlockhash, iter.Error()
}
func (s *StandardBridge) String() string {
return s.name
}
package l1
import (
"context"
"encoding/json"
"errors"
"math/big"
"time"
"github.com/ethereum-optimism/optimism/indexer/services/util"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
)
const (
DefaultConnectionTimeout = 30 * time.Second
DefaultMaxBatchSize = 100
)
type NewHeader struct {
types.Header
Hash common.Hash
}
func (h *NewHeader) UnmarshalJSON(input []byte) error {
type NewHeader struct {
Hash *common.Hash `json:"hash" gencodec:"required"`
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"`
Coinbase *common.Address `json:"miner" gencodec:"required"`
Root *common.Hash `json:"stateRoot" gencodec:"required"`
TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"`
Bloom *types.Bloom `json:"logsBloom" gencodec:"required"`
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
Number *hexutil.Big `json:"number" gencodec:"required"`
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
Extra *hexutil.Bytes `json:"extraData" gencodec:"required"`
MixDigest *common.Hash `json:"mixHash"`
Nonce *types.BlockNonce `json:"nonce"`
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
}
var dec NewHeader
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Hash == nil {
return errors.New("missing required field 'hash' for Header")
}
h.Hash = *dec.Hash
if dec.ParentHash == nil {
return errors.New("missing required field 'parentHash' for Header")
}
h.ParentHash = *dec.ParentHash
if dec.UncleHash == nil {
return errors.New("missing required field 'sha3Uncles' for Header")
}
h.UncleHash = *dec.UncleHash
if dec.Coinbase == nil {
return errors.New("missing required field 'miner' for Header")
}
h.Coinbase = *dec.Coinbase
if dec.Root == nil {
return errors.New("missing required field 'stateRoot' for Header")
}
h.Root = *dec.Root
if dec.TxHash == nil {
return errors.New("missing required field 'transactionsRoot' for Header")
}
h.TxHash = *dec.TxHash
if dec.ReceiptHash == nil {
return errors.New("missing required field 'receiptsRoot' for Header")
}
h.ReceiptHash = *dec.ReceiptHash
if dec.Bloom == nil {
return errors.New("missing required field 'logsBloom' for Header")
}
h.Bloom = *dec.Bloom
if dec.Difficulty == nil {
return errors.New("missing required field 'difficulty' for Header")
}
h.Difficulty = (*big.Int)(dec.Difficulty)
if dec.Number == nil {
return errors.New("missing required field 'number' for Header")
}
h.Number = (*big.Int)(dec.Number)
if dec.GasLimit == nil {
return errors.New("missing required field 'gasLimit' for Header")
}
h.GasLimit = uint64(*dec.GasLimit)
if dec.GasUsed == nil {
return errors.New("missing required field 'gasUsed' for Header")
}
h.GasUsed = uint64(*dec.GasUsed)
if dec.Time == nil {
return errors.New("missing required field 'timestamp' for Header")
}
h.Time = uint64(*dec.Time)
if dec.Extra == nil {
return errors.New("missing required field 'extraData' for Header")
}
h.Extra = *dec.Extra
if dec.MixDigest != nil {
h.MixDigest = *dec.MixDigest
}
if dec.Nonce != nil {
h.Nonce = *dec.Nonce
}
if dec.BaseFee != nil {
h.BaseFee = (*big.Int)(dec.BaseFee)
}
return nil
}
type HeaderSelectorConfig struct {
ConfDepth uint64
MaxBatchSize uint64
}
type ConfirmedHeaderSelector struct {
cfg HeaderSelectorConfig
}
func HeadersByRange(ctx context.Context, client *rpc.Client, startHeight uint64, count int) ([]*NewHeader, error) {
height := startHeight
batchElems := make([]rpc.BatchElem, count)
for i := 0; i < count; i++ {
batchElems[i] = rpc.BatchElem{
Method: "eth_getBlockByNumber",
Args: []interface{}{
util.ToBlockNumArg(new(big.Int).SetUint64(height + uint64(i))),
false,
},
Result: new(NewHeader),
Error: nil,
}
}
if err := client.BatchCallContext(ctx, batchElems); err != nil {
return nil, err
}
out := make([]*NewHeader, count)
for i := 0; i < len(batchElems); i++ {
if batchElems[i].Error != nil {
return nil, batchElems[i].Error
}
out[i] = batchElems[i].Result.(*NewHeader)
}
return out, nil
}
func (f *ConfirmedHeaderSelector) NewHead(
ctx context.Context,
lowest uint64,
header *types.Header,
client *rpc.Client,
) ([]*NewHeader, error) {
number := header.Number.Uint64()
blockHash := header.Hash
logger.Info("New block", "block", number, "hash", blockHash)
if number < f.cfg.ConfDepth {
return nil, nil
}
endHeight := number - f.cfg.ConfDepth + 1
minNextHeight := lowest + f.cfg.ConfDepth
if minNextHeight > number {
log.Info("Fork block ", "block", number, "hash", blockHash)
return nil, nil
}
startHeight := lowest + 1
// Clamp to max batch size
if startHeight+f.cfg.MaxBatchSize < endHeight+1 {
endHeight = startHeight + f.cfg.MaxBatchSize - 1
}
nHeaders := int(endHeight - startHeight + 1)
if nHeaders > 1 {
logger.Info("Loading blocks",
"startHeight", startHeight, "endHeight", endHeight)
}
headers := make([]*NewHeader, 0)
height := startHeight
left := nHeaders - len(headers)
for left > 0 {
count := DefaultMaxBatchSize
if count > left {
count = left
}
logger.Info("Loading block batch",
"height", height, "count", count)
ctxt, cancel := context.WithTimeout(ctx, DefaultConnectionTimeout)
fetched, err := HeadersByRange(ctxt, client, height, count)
cancel()
if err != nil {
return nil, err
}
headers = append(headers, fetched...)
left = nHeaders - len(headers)
height += uint64(count)
}
logger.Debug("Verifying block range ",
"startHeight", startHeight, "endHeight", endHeight)
for i, header := range headers {
// Trim the returned headers if any of the lookups failed.
if header == nil {
headers = headers[:i]
break
}
// Assert that each header builds on the parent before it, trim if there
// are any discontinuities.
if i > 0 {
prevHeader := headers[i-1]
if prevHeader.Hash != header.ParentHash {
log.Error("Parent hash does not connect to ",
"block", header.Number.Uint64(), "hash", header.Hash,
"prev", prevHeader.Number.Uint64(), "hash", prevHeader.Hash)
headers = headers[:i]
break
}
}
log.Debug("Confirmed block ",
"block", header.Number.Uint64(), "hash", header.Hash)
}
return headers, nil
}
func NewConfirmedHeaderSelector(cfg HeaderSelectorConfig) (*ConfirmedHeaderSelector,
error) {
if cfg.ConfDepth == 0 {
return nil, errors.New("ConfDepth must be greater than zero")
}
if cfg.MaxBatchSize == 0 {
return nil, errors.New("MaxBatchSize must be greater than zero")
}
return &ConfirmedHeaderSelector{
cfg: cfg,
}, nil
}
package l1
import (
"context"
"github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/indexer/services/l1/bridge"
legacy_bindings "github.com/ethereum-optimism/optimism/op-bindings/legacy-bindings"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)
func QueryStateBatches(filterer *legacy_bindings.StateCommitmentChainFilterer, startHeight, endHeight uint64, ctx context.Context) (map[common.Hash][]db.StateBatch, error) {
batches := make(map[common.Hash][]db.StateBatch)
iter, err := bridge.FilterStateBatchAppendedWithRetry(ctx, filterer, &bind.FilterOpts{
Start: startHeight,
End: &endHeight,
})
if err != nil {
return nil, err
}
defer iter.Close()
for iter.Next() {
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()
}
package l1
import (
"context"
"errors"
"fmt"
"math/big"
"net/http"
"strconv"
"sync"
"sync/atomic"
"time"
"github.com/ethereum-optimism/optimism/indexer/metrics"
"github.com/ethereum-optimism/optimism/indexer/services"
"github.com/ethereum-optimism/optimism/indexer/services/query"
legacy_bindings "github.com/ethereum-optimism/optimism/op-bindings/legacy-bindings"
"github.com/prometheus/client_golang/prometheus"
"github.com/ethereum-optimism/optimism/indexer/server"
"github.com/ethereum-optimism/optimism/indexer/services/l1/bridge"
_ "github.com/lib/pq"
"github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
"github.com/gorilla/mux"
)
var logger = log.New("service", "l1")
// errNoChainID represents the error when the chain id is not provided
// and it cannot be remotely fetched
var errNoChainID = errors.New("no chain id provided")
var errNoNewBlocks = errors.New("no new blocks")
var ZeroAddress common.Address
// Driver is an interface for indexing deposits from l1.
type Driver interface {
// Name is an identifier used to prefix logs for a particular service.
Name() string
}
type ServiceConfig struct {
Context context.Context
Metrics *metrics.Metrics
L1Client *ethclient.Client
RawL1Client *rpc.Client
ChainID *big.Int
AddressManager services.AddressManager
ConfDepth uint64
MaxHeaderBatchSize uint64
StartBlockNumber uint64
DB *db.Database
Bedrock bool
}
type Service struct {
cfg ServiceConfig
ctx context.Context
cancel func()
bridges map[string]bridge.Bridge
portal *bridge.Portal
batchScanner *legacy_bindings.StateCommitmentChainFilterer
latestHeader uint64
headerSelector *ConfirmedHeaderSelector
l1Client *ethclient.Client
metrics *metrics.Metrics
tokenCache map[common.Address]*db.Token
isBedrock bool
wg sync.WaitGroup
}
type IndexerStatus struct {
Synced float64 `json:"synced"`
Highest db.BlockLocator `json:"highest_block"`
}
func NewService(cfg ServiceConfig) (*Service, error) {
ctx, cancel := context.WithCancel(cfg.Context)
// Handle restart logic
logger.Info("Creating L1 Indexer")
chainID, err := cfg.L1Client.ChainID(context.Background())
if err != nil {
cancel()
return nil, err
}
if cfg.ChainID.Cmp(chainID) != 0 {
cancel()
return nil, fmt.Errorf("chain ID configured with %d but got %d", cfg.ChainID, chainID)
}
bridges, err := bridge.BridgesByChainID(cfg.ChainID, cfg.L1Client, cfg.AddressManager)
if err != nil {
cancel()
return nil, err
}
var portal *bridge.Portal
var batchScanner *legacy_bindings.StateCommitmentChainFilterer
if cfg.Bedrock {
portal = bridge.NewPortal(cfg.AddressManager)
} else {
batchScanner, err = bridge.StateCommitmentChainScanner(cfg.L1Client, cfg.AddressManager)
if err != nil {
cancel()
return nil, err
}
}
logger.Info("Scanning bridges for deposits", "bridges", bridges)
confirmedHeaderSelector, err := NewConfirmedHeaderSelector(HeaderSelectorConfig{
ConfDepth: cfg.ConfDepth,
MaxBatchSize: cfg.MaxHeaderBatchSize,
})
if err != nil {
cancel()
return nil, err
}
service := &Service{
cfg: cfg,
ctx: ctx,
cancel: cancel,
portal: portal,
bridges: bridges,
batchScanner: batchScanner,
headerSelector: confirmedHeaderSelector,
metrics: cfg.Metrics,
tokenCache: map[common.Address]*db.Token{
ZeroAddress: db.ETHL1Token,
},
isBedrock: cfg.Bedrock,
l1Client: cfg.L1Client,
}
service.wg.Add(1)
return service, nil
}
func (s *Service) loop() {
defer s.wg.Done()
for {
err := s.catchUp()
if err == nil {
break
}
if err == context.Canceled {
return
}
logger.Error("error catching up to tip, trying again in a bit", "err", err)
time.Sleep(10 * time.Second)
continue
}
newHeads := make(chan *types.Header, 1000)
tick := time.NewTicker(5 * time.Second)
defer tick.Stop()
for {
select {
case <-tick.C:
header, err := query.HeaderByNumberWithRetry(s.ctx, s.cfg.L1Client)
if err != nil {
logger.Error("error fetching header by number", "err", err)
continue
}
newHeads <- header
case header := <-newHeads:
if header == nil {
break
}
logger.Info("Received new header", "header", header.Hash)
atomic.StoreUint64(&s.latestHeader, header.Number.Uint64())
for {
err := s.Update(header)
if err != nil {
if err != errNoNewBlocks {
logger.Error("Unable to update indexer ", "err", err)
}
break
}
}
case <-s.ctx.Done():
logger.Info("service stopped")
return
}
}
}
func (s *Service) Update(newHeader *types.Header) error {
var lowest db.BlockLocator
highestConfirmed, err := s.cfg.DB.GetHighestL1Block()
if err != nil {
return err
}
if highestConfirmed == nil {
startHeader, err := s.l1Client.HeaderByNumber(s.ctx, new(big.Int).SetUint64(s.cfg.StartBlockNumber))
if err != nil {
return fmt.Errorf("error fetching header by number: %w", err)
}
highestConfirmed = &db.BlockLocator{
Number: s.cfg.StartBlockNumber,
Hash: startHeader.Hash(),
}
}
lowest = *highestConfirmed
headers, err := s.headerSelector.NewHead(s.ctx, lowest.Number, newHeader, s.cfg.RawL1Client)
if err != nil {
return err
}
if len(headers) == 0 {
return errNoNewBlocks
}
if lowest.Number+1 != headers[0].Number.Uint64() {
logger.Error("Block number does not immediately follow ",
"block", headers[0].Number.Uint64(), "hash", headers[0].Hash,
"lowest_block", lowest.Number, "hash", lowest.Hash)
return nil
}
if lowest.Number > 0 && lowest.Hash != headers[0].ParentHash {
logger.Error("Parent hash does not connect to ",
"block", headers[0].Number.Uint64(), "hash", headers[0].Hash,
"lowest_block", lowest.Number, "hash", lowest.Hash)
return nil
}
startHeight := headers[0].Number.Uint64()
endHeight := headers[len(headers)-1].Number.Uint64()
depositsByBlockHash := make(map[common.Hash][]db.Deposit)
start := prometheus.NewTimer(s.metrics.UpdateDuration.WithLabelValues("l1"))
defer func() {
dur := start.ObserveDuration()
logger.Info("updated index", "start_height", startHeight, "end_height", endHeight, "duration", dur)
}()
bridgeDepositsCh := make(chan bridge.DepositsMap, len(s.bridges))
provenWithdrawalsCh := make(chan bridge.ProvenWithdrawalsMap, 1)
finalizedWithdrawalsCh := make(chan bridge.FinalizedWithdrawalsMap, 1)
errCh := make(chan error, len(s.bridges)+1)
for _, bridgeImpl := range s.bridges {
go func(b bridge.Bridge) {
deposits, err := b.GetDepositsByBlockRange(s.ctx, startHeight, endHeight)
if err != nil {
errCh <- err
return
}
bridgeDepositsCh <- deposits
}(bridgeImpl)
}
if s.isBedrock {
go func() {
provenWithdrawals, err := s.portal.GetProvenWithdrawalsByBlockRange(s.ctx, startHeight, endHeight)
if err != nil {
errCh <- err
return
}
provenWithdrawalsCh <- provenWithdrawals
}()
go func() {
finalizedWithdrawals, err := s.portal.GetFinalizedWithdrawalsByBlockRange(s.ctx, startHeight, endHeight)
if err != nil {
errCh <- err
return
}
finalizedWithdrawalsCh <- finalizedWithdrawals
}()
} else {
provenWithdrawalsCh <- make(bridge.ProvenWithdrawalsMap)
finalizedWithdrawalsCh <- make(bridge.FinalizedWithdrawalsMap)
}
var receives int
for {
select {
case bridgeDeposits := <-bridgeDepositsCh:
for blockHash, deposits := range bridgeDeposits {
for _, deposit := range deposits {
if err := s.cacheToken(deposit); err != nil {
logger.Warn("error caching token", "err", err)
}
}
depositsByBlockHash[blockHash] = append(depositsByBlockHash[blockHash], deposits...)
}
case err := <-errCh:
return err
}
receives++
if receives == len(s.bridges) {
break
}
}
provenWithdrawalsByBlockHash := <-provenWithdrawalsCh
finalizedWithdrawalsByBlockHash := <-finalizedWithdrawalsCh
var stateBatches map[common.Hash][]db.StateBatch
if !s.isBedrock {
stateBatches, err = QueryStateBatches(s.batchScanner, startHeight, endHeight, s.ctx)
if err != nil {
logger.Error("Error querying state batches", "err", err)
return err
}
}
for i, header := range headers {
blockHash := header.Hash
number := header.Number.Uint64()
deposits := depositsByBlockHash[blockHash]
batches := stateBatches[blockHash]
provenWds := provenWithdrawalsByBlockHash[blockHash]
finalizedWds := finalizedWithdrawalsByBlockHash[blockHash]
// Always record block data in the last block
// in the list of headers
if len(deposits) == 0 && len(batches) == 0 && len(provenWds) == 0 && len(finalizedWds) == 0 && i != len(headers)-1 {
continue
}
block := &db.IndexedL1Block{
Hash: blockHash,
ParentHash: header.ParentHash,
Number: number,
Timestamp: header.Time,
Deposits: deposits,
ProvenWithdrawals: provenWds,
FinalizedWithdrawals: finalizedWds,
}
err := s.cfg.DB.AddIndexedL1Block(block)
if err != nil {
logger.Error(
"Unable to import ",
"block", number,
"hash", blockHash, "err", err,
"block", block,
)
return err
}
err = s.cfg.DB.AddStateBatch(batches)
if err != nil {
logger.Error(
"Unable to import state append batch",
"block", number,
"hash", blockHash, "err", err,
"block", block,
)
return err
}
s.metrics.RecordStateBatches(len(batches))
logger.Debug("Imported ",
"block", number, "hash", blockHash, "deposits", len(block.Deposits))
for _, deposit := range block.Deposits {
token := s.tokenCache[deposit.L1Token]
logger.Info(
"indexed deposit",
"tx_hash", deposit.TxHash,
"symbol", token.Symbol,
"amount", deposit.Amount,
)
s.metrics.RecordDeposit(deposit.L1Token)
}
}
newHeaderNumber := newHeader.Number.Uint64()
s.metrics.SetL1SyncHeight(endHeight)
s.metrics.SetL1SyncPercent(endHeight, newHeaderNumber)
latestHeaderNumber := headers[len(headers)-1].Number.Uint64()
if latestHeaderNumber+s.cfg.ConfDepth-1 == newHeaderNumber {
return errNoNewBlocks
}
return nil
}
func (s *Service) GetIndexerStatus(w http.ResponseWriter, r *http.Request) {
highestBlock, err := s.cfg.DB.GetHighestL1Block()
if err != nil {
server.RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}
var synced float64
if s.latestHeader != 0 {
synced = float64(highestBlock.Number) / float64(s.latestHeader)
}
status := &IndexerStatus{
Synced: synced,
Highest: *highestBlock,
}
server.RespondWithJSON(w, http.StatusOK, status)
}
func (s *Service) GetDeposits(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
limitStr := r.URL.Query().Get("limit")
limit, err := strconv.ParseUint(limitStr, 10, 64)
if err != nil && limitStr != "" {
server.RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}
if limit == 0 {
limit = 10
}
offsetStr := r.URL.Query().Get("offset")
offset, err := strconv.ParseUint(offsetStr, 10, 64)
if err != nil && offsetStr != "" {
server.RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}
page := db.PaginationParam{
Limit: limit,
Offset: offset,
}
deposits, err := s.cfg.DB.GetDepositsByAddress(common.HexToAddress(vars["address"]), page)
if err != nil {
server.RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}
server.RespondWithJSON(w, http.StatusOK, deposits)
}
func (s *Service) catchUp() error {
realHead, err := query.HeaderByNumberWithRetry(s.ctx, s.cfg.L1Client)
if err != nil {
return err
}
realHeadNum := realHead.Number.Uint64()
currHead, err := s.cfg.DB.GetHighestL1Block()
if err != nil {
return err
}
var currHeadNum uint64
if currHead != nil {
currHeadNum = currHead.Number
}
if realHeadNum-s.cfg.ConfDepth <= currHeadNum+s.cfg.MaxHeaderBatchSize {
return nil
}
logger.Info("chain is far behind head, resyncing")
s.metrics.SetL1CatchingUp(true)
for realHeadNum-s.cfg.ConfDepth > currHeadNum+s.cfg.MaxHeaderBatchSize {
select {
case <-s.ctx.Done():
return s.ctx.Err()
default:
if err := s.Update(realHead); err != nil && err != errNoNewBlocks {
return err
}
currHead, err := s.cfg.DB.GetHighestL1Block()
if err != nil {
return err
}
currHeadNum = currHead.Number
}
}
logger.Info("indexer is close enough to tip, starting regular loop")
s.metrics.SetL1CatchingUp(false)
return nil
}
func (s *Service) cacheToken(deposit db.Deposit) error {
if s.tokenCache[deposit.L1Token] != nil {
return nil
}
token, err := s.cfg.DB.GetL1TokenByAddress(deposit.L1Token.String())
if err != nil {
return err
}
if token != nil {
s.metrics.IncL1CachedTokensCount()
s.tokenCache[deposit.L1Token] = token
return nil
}
token, err = query.NewERC20(deposit.L1Token, s.cfg.L1Client)
if err != nil {
logger.Error("Error querying ERC20 token details",
"l1_token", deposit.L1Token.String(), "err", err)
token = &db.Token{
Address: deposit.L1Token.String(),
}
}
if err := s.cfg.DB.AddL1Token(deposit.L1Token.String(), token); err != nil {
return err
}
s.tokenCache[deposit.L1Token] = token
s.metrics.IncL1CachedTokensCount()
return nil
}
func (s *Service) Start() error {
if s.cfg.ChainID == nil {
return errNoChainID
}
go s.loop()
return nil
}
func (s *Service) Stop() {
s.cancel()
s.wg.Wait()
}
package bridge
import (
"context"
"errors"
"math/big"
"github.com/ethereum-optimism/optimism/indexer/db"
"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/common"
)
type WithdrawalsMap map[common.Hash][]db.Withdrawal
type Bridge interface {
Address() common.Address
GetWithdrawalsByBlockRange(context.Context, uint64, uint64) (WithdrawalsMap, error)
String() string
}
type implConfig struct {
name string
impl string
addr common.Address
}
var defaultBridgeCfgs = []*implConfig{
{"Standard", "StandardBridge", predeploys.L2StandardBridgeAddr},
}
var customBridgeCfgs = map[uint64][]*implConfig{
// Mainnet
10: {
{"BitBTC", StandardBridgeImpl, common.HexToAddress("0x158F513096923fF2d3aab2BcF4478536de6725e2")},
{"DAI", StandardBridgeImpl, common.HexToAddress("0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65")},
{"wstETH", StandardBridgeImpl, common.HexToAddress("0x8E01013243a96601a86eb3153F0d9Fa4fbFb6957")},
},
}
func BridgesByChainID(chainID *big.Int, client *ethclient.Client, isBedrock bool) (map[string]Bridge, error) {
allCfgs := make([]*implConfig, 0)
allCfgs = append(allCfgs, defaultBridgeCfgs...)
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)
for _, bridge := range allCfgs {
switch bridge.impl {
case "StandardBridge":
l2SB, err := bindings.NewL2StandardBridge(bridge.addr, client)
if err != nil {
return nil, err
}
bridges[bridge.name] = &StandardBridge{
name: bridge.name,
address: bridge.addr,
client: client,
l2SB: l2SB,
l2L1MP: l2L1MP,
isBedrock: isBedrock,
}
default:
return nil, errors.New("unsupported bridge")
}
}
return bridges, nil
}
package bridge
import "time"
const (
DefaultConnectionTimeout = 60 * time.Second
L2StandardBridgeAddr = "0x4200000000000000000000000000000000000010"
StandardBridgeImpl = "StandardBridge"
)
package bridge
import "github.com/ethereum/go-ethereum/log"
var logger = log.New("service", "l2-bridge")
package bridge
import (
"context"
"github.com/ethereum-optimism/optimism/indexer/db"
"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/common"
)
type StandardBridge struct {
name string
address common.Address
client *ethclient.Client
l2SB *bindings.L2StandardBridge
l2L1MP *bindings.L2ToL1MessagePasser
isBedrock bool
}
func (s *StandardBridge) Address() common.Address {
return s.address
}
func (s *StandardBridge) GetWithdrawalsByBlockRange(ctx context.Context, start, end uint64) (WithdrawalsMap, error) {
withdrawalsByBlockhash := make(map[common.Hash][]db.Withdrawal)
opts := &bind.FilterOpts{
Context: ctx,
Start: start,
End: &end,
}
iter, err := backoff.Do(ctx, 3, backoff.Exponential(), func() (*bindings.L2StandardBridgeWithdrawalInitiatedIterator, error) {
return s.l2SB.FilterWithdrawalInitiated(opts, nil, nil, nil)
})
if err != nil {
return nil, err
}
receipts := make(map[common.Hash]*types.Receipt)
defer iter.Close()
for iter.Next() {
ev := iter.Event
if s.isBedrock {
receipt := receipts[ev.Raw.TxHash]
if receipt == nil {
receipt, err = s.client.TransactionReceipt(ctx, ev.Raw.TxHash)
if err != nil {
return nil, err
}
receipts[ev.Raw.TxHash] = receipt
}
var withdrawalInitiated *bindings.L2ToL1MessagePasserMessagePassed
for _, eLog := range receipt.Logs {
if len(eLog.Topics) == 0 || eLog.Topics[0] != withdrawals.MessagePassedTopic {
continue
}
if withdrawalInitiated != nil {
logger.Warn("detected multiple withdrawal initiated events! ignoring", "tx_hash", ev.Raw.TxHash)
continue
}
withdrawalInitiated, err = s.l2L1MP.ParseMessagePassed(*eLog)
if err != nil {
return nil, err
}
}
hash, err := withdrawals.WithdrawalHash(withdrawalInitiated)
if err != nil {
return nil, err
}
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,
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, iter.Error()
}
func (s *StandardBridge) String() string {
return s.name
}
package l2
import (
"context"
"errors"
"math/big"
"time"
"github.com/ethereum-optimism/optimism/indexer/services/util"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
)
const (
DefaultConnectionTimeout = 20 * time.Second
DefaultConfDepth uint64 = 20
DefaultMaxBatchSize = 50
)
type HeaderSelectorConfig struct {
ConfDepth uint64
MaxBatchSize uint64
}
type ConfirmedHeaderSelector struct {
cfg HeaderSelectorConfig
}
func HeadersByRange(ctx context.Context, client *rpc.Client, startHeight uint64, count int) ([]*types.Header, error) {
height := startHeight
batchElems := make([]rpc.BatchElem, count)
for i := 0; i < count; i++ {
batchElems[i] = rpc.BatchElem{
Method: "eth_getBlockByNumber",
Args: []interface{}{
util.ToBlockNumArg(new(big.Int).SetUint64(height + uint64(i))),
false,
},
Result: new(types.Header),
Error: nil,
}
}
if err := client.BatchCallContext(ctx, batchElems); err != nil {
return nil, err
}
out := make([]*types.Header, count)
for i := 0; i < len(batchElems); i++ {
if batchElems[i].Error != nil {
return nil, batchElems[i].Error
}
out[i] = batchElems[i].Result.(*types.Header)
}
return out, nil
}
func (f *ConfirmedHeaderSelector) NewHead(
ctx context.Context,
lowest uint64,
header *types.Header,
client *rpc.Client,
) ([]*types.Header, error) {
number := header.Number.Uint64()
blockHash := header.Hash()
logger.Info("New block", "block", number, "hash", blockHash)
if number < f.cfg.ConfDepth {
return nil, nil
}
endHeight := number - f.cfg.ConfDepth + 1
minNextHeight := lowest + f.cfg.ConfDepth
if minNextHeight > number {
log.Info("Fork block=%d hash=%s", number, blockHash)
return nil, nil
}
startHeight := lowest + 1
// Clamp to max batch size
if startHeight+f.cfg.MaxBatchSize < endHeight+1 {
endHeight = startHeight + f.cfg.MaxBatchSize - 1
}
nHeaders := int(endHeight - startHeight + 1)
if nHeaders > 1 {
logger.Info("Loading blocks",
"startHeight", startHeight, "endHeight", endHeight)
}
headers := make([]*types.Header, 0)
height := startHeight
left := nHeaders - len(headers)
for left > 0 {
count := DefaultMaxBatchSize
if count > left {
count = left
}
logger.Info("Loading block batch",
"height", height, "count", count)
ctxt, cancel := context.WithTimeout(ctx, DefaultConnectionTimeout)
fetched, err := HeadersByRange(ctxt, client, height, count)
cancel()
if err != nil {
return nil, err
}
headers = append(headers, fetched...)
left = nHeaders - len(headers)
height += uint64(count)
}
logger.Debug("Verifying block range ",
"startHeight", startHeight, "endHeight", endHeight)
for i, header := range headers {
// Trim the returned headers if any of the lookups failed.
if header == nil {
headers = headers[:i]
break
}
// Assert that each header builds on the parent before it, trim if there
// are any discontinuities.
if i > 0 {
prevHeader := headers[i-1]
if prevHeader.Hash() != header.ParentHash {
log.Error("Parent hash does not connect to ",
"block", header.Number.Uint64(), "hash", header.Hash(),
"prev", prevHeader.Number.Uint64(), "hash", prevHeader.Hash())
headers = headers[:i]
break
}
}
log.Debug("Confirmed block ",
"block", header.Number.Uint64(), "hash", header.Hash())
}
return headers, nil
}
func NewConfirmedHeaderSelector(cfg HeaderSelectorConfig) (*ConfirmedHeaderSelector, error) {
if cfg.ConfDepth == 0 {
return nil, errors.New("ConfDepth must be greater than zero")
}
if cfg.MaxBatchSize == 0 {
return nil, errors.New("MaxBatchSize must be greater than zero")
}
return &ConfirmedHeaderSelector{
cfg: cfg,
}, nil
}
package l2
import (
"context"
"errors"
"fmt"
"math/big"
"net/http"
"strconv"
"sync"
"time"
"github.com/ethereum-optimism/optimism/indexer/metrics"
"github.com/ethereum-optimism/optimism/indexer/server"
"github.com/ethereum-optimism/optimism/indexer/services/query"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/prometheus/client_golang/prometheus"
"github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/indexer/services/l2/bridge"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/gorilla/mux"
)
var logger = log.New("service", "l2")
// errNoChainID represents the error when the chain id is not provided
// and it cannot be remotely fetched
var errNoChainID = errors.New("no chain id provided")
// errWrongChainID represents the error when the configured chain id is not
// correct
var errWrongChainID = errors.New("wrong chain id provided")
var errNoNewBlocks = errors.New("no new blocks")
type ServiceConfig struct {
Context context.Context
Metrics *metrics.Metrics
L2RPC *rpc.Client
L2Client *ethclient.Client
ChainID *big.Int
ConfDepth uint64
MaxHeaderBatchSize uint64
StartBlockNumber uint64
DB *db.Database
Bedrock bool
}
type Service struct {
cfg ServiceConfig
ctx context.Context
cancel func()
bridges map[string]bridge.Bridge
latestHeader uint64
headerSelector *ConfirmedHeaderSelector
metrics *metrics.Metrics
tokenCache map[common.Address]*db.Token
wg sync.WaitGroup
}
type IndexerStatus struct {
Synced float64 `json:"synced"`
Highest db.BlockLocator `json:"highest_block"`
}
func NewService(cfg ServiceConfig) (*Service, error) {
ctx, cancel := context.WithCancel(cfg.Context)
// Handle restart logic
logger.Info("Creating L2 Indexer")
chainID, err := cfg.L2Client.ChainID(context.Background())
if err != nil {
cancel()
return nil, err
}
if cfg.ChainID != nil {
if cfg.ChainID.Cmp(chainID) != 0 {
cancel()
return nil, fmt.Errorf("%w: configured with %d and got %d",
errWrongChainID, cfg.ChainID, chainID)
}
} else {
cfg.ChainID = chainID
}
bridges, err := bridge.BridgesByChainID(cfg.ChainID, cfg.L2Client, cfg.Bedrock)
if err != nil {
cancel()
return nil, err
}
logger.Info("Scanning bridges for withdrawals", "bridges", bridges)
confirmedHeaderSelector, err := NewConfirmedHeaderSelector(HeaderSelectorConfig{
ConfDepth: cfg.ConfDepth,
MaxBatchSize: cfg.MaxHeaderBatchSize,
})
if err != nil {
cancel()
return nil, err
}
service := &Service{
cfg: cfg,
ctx: ctx,
cancel: cancel,
bridges: bridges,
headerSelector: confirmedHeaderSelector,
metrics: cfg.Metrics,
tokenCache: map[common.Address]*db.Token{
predeploys.LegacyERC20ETHAddr: db.ETHL1Token,
},
}
service.wg.Add(1)
return service, nil
}
func (s *Service) loop() {
defer s.wg.Done()
for {
err := s.catchUp()
if err == nil {
break
}
if err == context.Canceled {
return
}
logger.Error("error catching up to tip, trying again in a bit", "err", err)
time.Sleep(10 * time.Second)
continue
}
newHeads := make(chan *types.Header, 1000)
tick := time.NewTicker(5 * time.Second)
defer tick.Stop()
for {
select {
case <-tick.C:
header, err := query.HeaderByNumberWithRetry(s.ctx, s.cfg.L2Client)
if err != nil {
logger.Error("error fetching header by number", "err", err)
continue
}
newHeads <- header
case header := <-newHeads:
logger.Info("Received new header", "header", header.Hash)
for {
err := s.Update(header)
if err != nil {
if err != errNoNewBlocks {
logger.Error("Unable to update indexer ", "err", err)
}
break
}
}
case <-s.ctx.Done():
logger.Info("service stopped")
return
}
}
}
func (s *Service) Update(newHeader *types.Header) error {
var lowest = db.BlockLocator{
Number: s.cfg.StartBlockNumber,
}
highestConfirmed, err := s.cfg.DB.GetHighestL2Block()
if err != nil {
return err
}
if highestConfirmed != nil {
lowest = *highestConfirmed
}
headers, err := s.headerSelector.NewHead(s.ctx, lowest.Number, newHeader, s.cfg.L2RPC)
if err != nil {
return err
}
if len(headers) == 0 {
return errNoNewBlocks
}
if lowest.Number+1 != headers[0].Number.Uint64() {
logger.Error("Block number does not immediately follow ",
"block", headers[0].Number.Uint64(), "hash", headers[0].Hash(),
"lowest_block", lowest.Number, "hash", lowest.Hash)
return nil
}
if lowest.Number > 0 && lowest.Hash != headers[0].ParentHash {
logger.Error("Parent hash does not connect to ",
"block", headers[0].Number.Uint64(), "hash", headers[0].Hash(),
"lowest_block", lowest.Number, "hash", lowest.Hash)
return nil
}
startHeight := headers[0].Number.Uint64()
endHeight := headers[len(headers)-1].Number.Uint64()
withdrawalsByBlockHash := make(map[common.Hash][]db.Withdrawal)
start := prometheus.NewTimer(s.metrics.UpdateDuration.WithLabelValues("l2"))
defer func() {
dur := start.ObserveDuration()
logger.Info("updated index", "start_height", startHeight, "end_height", endHeight, "duration", dur)
}()
bridgeWdsCh := make(chan bridge.WithdrawalsMap)
errCh := make(chan error, len(s.bridges))
for _, bridgeImpl := range s.bridges {
go func(b bridge.Bridge) {
wds, err := b.GetWithdrawalsByBlockRange(s.ctx, startHeight, endHeight)
if err != nil {
errCh <- err
return
}
bridgeWdsCh <- wds
}(bridgeImpl)
}
var receives int
for {
select {
case bridgeWds := <-bridgeWdsCh:
for blockHash, withdrawals := range bridgeWds {
for _, wd := range withdrawals {
if err := s.cacheToken(wd); err != nil {
logger.Warn("error caching token", "err", err)
}
}
withdrawalsByBlockHash[blockHash] = append(withdrawalsByBlockHash[blockHash], withdrawals...)
}
case err := <-errCh:
return err
}
receives++
if receives == len(s.bridges) {
break
}
}
for i, header := range headers {
blockHash := header.Hash()
number := header.Number.Uint64()
withdrawals := withdrawalsByBlockHash[blockHash]
if len(withdrawals) == 0 && i != len(headers)-1 {
continue
}
block := &db.IndexedL2Block{
Hash: blockHash,
ParentHash: header.ParentHash,
Number: number,
Timestamp: header.Time,
Withdrawals: withdrawals,
}
err := s.cfg.DB.AddIndexedL2Block(block)
if err != nil {
logger.Error(
"Unable to import ",
"block", number,
"hash", blockHash,
"err", err,
"block", block,
)
return err
}
logger.Debug("Imported ",
"block", number, "hash", blockHash, "withdrawals", len(block.Withdrawals))
for _, withdrawal := range block.Withdrawals {
token := s.tokenCache[withdrawal.L2Token]
logger.Info(
"indexed withdrawal ",
"tx_hash", withdrawal.TxHash,
"symbol", token.Symbol,
"amount", withdrawal.Amount,
)
s.metrics.RecordWithdrawal(withdrawal.L2Token)
}
}
newHeaderNumber := newHeader.Number.Uint64()
s.metrics.SetL2SyncHeight(endHeight)
s.metrics.SetL2SyncPercent(endHeight, newHeaderNumber)
latestHeaderNumber := headers[len(headers)-1].Number.Uint64()
if latestHeaderNumber+s.cfg.ConfDepth-1 == newHeaderNumber {
return errNoNewBlocks
}
return nil
}
func (s *Service) GetIndexerStatus(w http.ResponseWriter, r *http.Request) {
highestBlock, err := s.cfg.DB.GetHighestL2Block()
if err != nil {
server.RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}
var synced float64
if s.latestHeader != 0 {
synced = float64(highestBlock.Number) / float64(s.latestHeader)
}
status := &IndexerStatus{
Synced: synced,
Highest: *highestBlock,
}
server.RespondWithJSON(w, http.StatusOK, status)
}
func (s *Service) GetWithdrawalBatch(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
hash := vars["hash"]
if hash == "" {
server.RespondWithError(w, http.StatusBadRequest, "must specify a hash")
return
}
batch, err := s.cfg.DB.GetWithdrawalBatch(common.HexToHash(vars["hash"]))
if err != nil {
server.RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}
server.RespondWithJSON(w, http.StatusOK, batch)
}
func (s *Service) GetWithdrawals(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
limitStr := r.URL.Query().Get("limit")
limit, err := strconv.ParseUint(limitStr, 10, 64)
if err != nil && limitStr != "" {
server.RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}
if limit == 0 {
limit = 10
}
offsetStr := r.URL.Query().Get("offset")
offset, err := strconv.ParseUint(offsetStr, 10, 64)
if err != nil && offsetStr != "" {
server.RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}
finalizationState := db.ParseFinalizationState(r.URL.Query().Get("finalized"))
page := db.PaginationParam{
Limit: limit,
Offset: offset,
}
withdrawals, err := s.cfg.DB.GetWithdrawalsByAddress(common.HexToAddress(vars["address"]), page, finalizationState)
if err != nil {
server.RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}
server.RespondWithJSON(w, http.StatusOK, withdrawals)
}
func (s *Service) catchUp() error {
realHead, err := query.HeaderByNumberWithRetry(s.ctx, s.cfg.L2Client)
if err != nil {
return err
}
realHeadNum := realHead.Number.Uint64()
currHead, err := s.cfg.DB.GetHighestL2Block()
if err != nil {
return err
}
var currHeadNum uint64
if currHead != nil {
currHeadNum = currHead.Number
}
if realHeadNum-s.cfg.ConfDepth <= currHeadNum+s.cfg.MaxHeaderBatchSize {
return nil
}
logger.Info("chain is far behind head, resyncing")
s.metrics.SetL2CatchingUp(true)
for realHeadNum-s.cfg.ConfDepth > currHeadNum+s.cfg.MaxHeaderBatchSize {
select {
case <-s.ctx.Done():
return s.ctx.Err()
default:
if err := s.Update(realHead); err != nil && err != errNoNewBlocks {
return err
}
currHead, err := s.cfg.DB.GetHighestL2Block()
if err != nil {
return err
}
currHeadNum = currHead.Number
}
}
logger.Info("indexer is close enough to tip, starting regular loop")
s.metrics.SetL2CatchingUp(false)
return nil
}
func (s *Service) cacheToken(withdrawal db.Withdrawal) error {
if s.tokenCache[withdrawal.L2Token] != nil {
return nil
}
token, err := s.cfg.DB.GetL2TokenByAddress(withdrawal.L2Token.String())
if err != nil {
return err
}
if token != nil {
s.metrics.IncL2CachedTokensCount()
s.tokenCache[withdrawal.L2Token] = token
return nil
}
token, err = query.NewERC20(withdrawal.L2Token, s.cfg.L2Client)
if err != nil {
logger.Error("Error querying ERC20 token details",
"l2_token", withdrawal.L2Token.String(), "err", err)
token = &db.Token{
Address: withdrawal.L2Token.String(),
}
}
if err := s.cfg.DB.AddL2Token(withdrawal.L2Token.String(), token); err != nil {
return err
}
s.tokenCache[withdrawal.L2Token] = token
s.metrics.IncL2CachedTokensCount()
return nil
}
func (s *Service) Start() error {
if s.cfg.ChainID == nil {
return errNoChainID
}
go s.loop()
return nil
}
func (s *Service) Stop() {
s.cancel()
s.wg.Wait()
}
package query
import (
"github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
func NewERC20(address common.Address, client *ethclient.Client) (*db.Token, error) {
contract, err := bindings.NewERC20(address, client)
if err != nil {
return nil, err
}
name, err := contract.Name(&bind.CallOpts{})
if err != nil {
return nil, err
}
symbol, err := contract.Symbol(&bind.CallOpts{})
if err != nil {
return nil, err
}
decimals, err := contract.Decimals(&bind.CallOpts{})
if err != nil {
return nil, err
}
return &db.Token{
Name: name,
Symbol: symbol,
Decimals: decimals,
}, nil
}
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) {
return backoff.Do(ctx, 3, backoff.Exponential(), func() (*types.Header, error) {
return client.HeaderByNumber(ctx, nil)
})
}
package util
import (
"math/big"
"github.com/ethereum/go-ethereum/common/hexutil"
)
func ToBlockNumArg(number *big.Int) string {
if number == nil {
return "latest"
}
pending := big.NewInt(-1)
if number.Cmp(pending) == 0 {
return "pending"
}
return hexutil.EncodeBig(number)
}
......@@ -30,8 +30,8 @@ var (
// MIPSMetaData contains all meta data concerning the MIPS contract.
var MIPSMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"contractIPreimageOracle\",\"name\":\"_oracle\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BRK_START\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracle\",\"outputs\":[{\"internalType\":\"contractIPreimageOracle\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"stateData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"step\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
Bin: "0x608060405234801561001057600080fd5b50604051611d38380380611d3883398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b611ca5806100936000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006b578063f8e0cb96146100b0575b600080fd5b610051634000000081565b60405163ffffffff90911681526020015b60405180910390f35b60005461008b9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610062565b6100c36100be366004611baa565b6100d1565b604051908152602001610062565b60006100db611ad7565b608081146100e857600080fd5b604051610600146100f857600080fd5b6064861461010557600080fd5b610184841461011357600080fd5b8535608052602086013560a052604086013560e090811c60c09081526044880135821c82526048880135821c61010052604c880135821c610120526050880135821c61014052605488013590911c61016052605887013560f890811c610180526059880135901c6101a052605a870135901c6101c0526102006101e0819052606287019060005b60208110156101be57823560e01c825260049092019160209091019060010161019a565b505050806101200151156101dc576101d4610612565b91505061060a565b6101408101805160010167ffffffffffffffff169052606081015160009061020490826106ba565b9050603f601a82901c16600281148061022357508063ffffffff166003145b15610270576102668163ffffffff1660021461024057601f610243565b60005b60ff166002610259856303ffffff16601a610776565b63ffffffff16901b6107e9565b935050505061060a565b6101608301516000908190601f601086901c81169190601587901c166020811061029c5761029c611c16565b602002015192508063ffffffff851615806102bd57508463ffffffff16601c145b156102f4578661016001518263ffffffff16602081106102df576102df611c16565b6020020151925050601f600b86901c166103b0565b60208563ffffffff161015610356578463ffffffff16600c148061031e57508463ffffffff16600d145b8061032f57508463ffffffff16600e145b15610340578561ffff1692506103b0565b61034f8661ffff166010610776565b92506103b0565b60288563ffffffff1610158061037257508463ffffffff166022145b8061038357508463ffffffff166026145b156103b0578661016001518263ffffffff16602081106103a5576103a5611c16565b602002015192508190505b60048563ffffffff16101580156103cd575060088563ffffffff16105b806103de57508463ffffffff166001145b156103fd576103ef858784876108e3565b97505050505050505061060a565b63ffffffff60006020878316106104625761041d8861ffff166010610776565b9095019463fffffffc86166104338160016106ba565b915060288863ffffffff161015801561045357508763ffffffff16603014155b1561046057809250600093505b505b600061047089888885610af3565b63ffffffff9081169150603f8a16908916158015610495575060088163ffffffff1610155b80156104a75750601c8163ffffffff16105b15610583578063ffffffff16600814806104c757508063ffffffff166009145b156104fe576104ec8163ffffffff166008146104e357856104e6565b60005b896107e9565b9b50505050505050505050505061060a565b8063ffffffff16600a0361051e576104ec858963ffffffff8a1615611196565b8063ffffffff16600b0361053f576104ec858963ffffffff8a161515611196565b8063ffffffff16600c03610555576104ec61127c565b60108163ffffffff16101580156105725750601c8163ffffffff16105b15610583576104ec81898988611790565b8863ffffffff16603814801561059e575063ffffffff861615155b156105d35760018b61016001518763ffffffff16602081106105c2576105c2611c16565b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146105f0576105f08460018461198a565b6105fc85836001611196565b9b5050505050505050505050505b949350505050565b60408051608051815260a051602082015260dc519181019190915260fc51604482015261011c51604882015261013c51604c82015261015c51605082015261017c51605482015261019f5160588201526101bf5160598201526101d851605a8201526000906102009060628101835b60208110156106a557601c8401518252602090930192600490910190600101610681565b506000815281810382a0819003902092915050565b6000806106c683611a2e565b905060038416156106d657600080fd5b6020810190358460051c8160005b601b81101561073c5760208501943583821c600116801561070c576001811461072157610732565b60008481526020839052604090209350610732565b600082815260208590526040902093505b50506001016106e4565b50608051915081811461075757630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b01826107d35760006107d5565b815b90861663ffffffff16179250505092915050565b60006107f3611ad7565b60809050806060015160040163ffffffff16816080015163ffffffff161461087c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6a756d7020696e2064656c617920736c6f74000000000000000000000000000060448201526064015b60405180910390fd5b60608101805160808301805163ffffffff9081169093528583169052908516156108d257806008018261016001518663ffffffff16602081106108c1576108c1611c16565b63ffffffff90921660209290920201525b6108da610612565b95945050505050565b60006108ed611ad7565b608090506000816060015160040163ffffffff16826080015163ffffffff1614610973576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6272616e636820696e2064656c617920736c6f740000000000000000000000006044820152606401610873565b8663ffffffff166004148061098e57508663ffffffff166005145b15610a0a5760008261016001518663ffffffff16602081106109b2576109b2611c16565b602002015190508063ffffffff168563ffffffff161480156109da57508763ffffffff166004145b80610a0257508063ffffffff168563ffffffff1614158015610a0257508763ffffffff166005145b915050610a87565b8663ffffffff16600603610a275760008460030b13159050610a87565b8663ffffffff16600703610a435760008460030b139050610a87565b8663ffffffff16600103610a8757601f601087901c166000819003610a6c5760008560030b1291505b8063ffffffff16600103610a855760008560030b121591505b505b606082018051608084015163ffffffff169091528115610acd576002610ab28861ffff166010610776565b63ffffffff90811690911b8201600401166080840152610adf565b60808301805160040163ffffffff1690525b610ae7610612565b98975050505050505050565b6000603f601a86901c81169086166020821015610eb75760088263ffffffff1610158015610b275750600f8263ffffffff16105b15610bc7578163ffffffff16600803610b4257506020610bc2565b8163ffffffff16600903610b5857506021610bc2565b8163ffffffff16600a03610b6e5750602a610bc2565b8163ffffffff16600b03610b845750602b610bc2565b8163ffffffff16600c03610b9a57506024610bc2565b8163ffffffff16600d03610bb057506025610bc2565b8163ffffffff16600e03610bc2575060265b600091505b8163ffffffff16600003610e0b57601f600688901c16602063ffffffff83161015610ce55760088263ffffffff1610610c055786935050505061060a565b8163ffffffff16600003610c285763ffffffff86811691161b925061060a915050565b8163ffffffff16600203610c4b5763ffffffff86811691161c925061060a915050565b8163ffffffff16600303610c75576102668163ffffffff168763ffffffff16901c82602003610776565b8163ffffffff16600403610c98575050505063ffffffff8216601f84161b61060a565b8163ffffffff16600603610cbb575050505063ffffffff8216601f84161c61060a565b8163ffffffff16600703610ce5576102668763ffffffff168763ffffffff16901c88602003610776565b8163ffffffff1660201480610d0057508163ffffffff166021145b15610d1257858701935050505061060a565b8163ffffffff1660221480610d2d57508163ffffffff166023145b15610d3f57858703935050505061060a565b8163ffffffff16602403610d5a57858716935050505061060a565b8163ffffffff16602503610d7557858717935050505061060a565b8163ffffffff16602603610d9057858718935050505061060a565b8163ffffffff16602703610dab57505050508282171961060a565b8163ffffffff16602a03610ddd578560030b8760030b12610dcd576000610dd0565b60015b60ff16935050505061060a565b8163ffffffff16602b03610e05578563ffffffff168763ffffffff1610610dcd576000610dd0565b50611134565b8163ffffffff16600f03610e2d5760108563ffffffff16901b9250505061060a565b8163ffffffff16601c03610eb2578063ffffffff16600203610e545750505082820261060a565b8063ffffffff1660201480610e6f57508063ffffffff166021145b15610eb2578063ffffffff16602003610e86579419945b60005b6380000000871615610ea8576401fffffffe600197881b169601610e89565b925061060a915050565b611134565b60288263ffffffff16101561101a578163ffffffff16602003610f0357610efa8660031660080260180363ffffffff168563ffffffff16901c60ff166008610776565b9250505061060a565b8163ffffffff16602103610f3857610efa8660021660080260100363ffffffff168563ffffffff16901c61ffff166010610776565b8163ffffffff16602203610f685750505063ffffffff60086003851602811681811b198416918316901b1761060a565b8163ffffffff16602303610f8057839250505061060a565b8163ffffffff16602403610fb3578560031660080260180363ffffffff168463ffffffff16901c60ff169250505061060a565b8163ffffffff16602503610fe7578560021660080260100363ffffffff168463ffffffff16901c61ffff169250505061060a565b8163ffffffff16602603610eb25750505063ffffffff60086003851602601803811681811c198416918316901c1761060a565b8163ffffffff166028036110515750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b1761060a565b8163ffffffff166029036110895750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b1761060a565b8163ffffffff16602a036110b95750505063ffffffff60086003851602811681811c198316918416901c1761060a565b8163ffffffff16602b036110d157849250505061060a565b8163ffffffff16602e036111045750505063ffffffff60086003851602601803811681811b198316918416901b1761060a565b8163ffffffff1660300361111c57839250505061060a565b8163ffffffff1660380361113457849250505061060a565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e000000000000000000000000006044820152606401610873565b60006111a0611ad7565b506080602063ffffffff861610611213576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c69642072656769737465720000000000000000000000000000000000006044820152606401610873565b63ffffffff8516158015906112255750825b1561125957838161016001518663ffffffff166020811061124857611248611c16565b63ffffffff90921660209290920201525b60808101805163ffffffff808216606085015260049091011690526108da610612565b6000611286611ad7565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa036113005781610fff8116156112cf57610fff811661100003015b8363ffffffff166000036112f65760e08801805163ffffffff8382011690915295506112fa565b8395505b5061174f565b8563ffffffff16610fcd0361131b576340000000945061174f565b8563ffffffff1661101803611333576001945061174f565b8563ffffffff166110960361136857600161012088015260ff831661010088015261135c610612565b97505050505050505090565b8563ffffffff16610fa3036115b25763ffffffff83161561174f577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb63ffffffff84160161156c5760006113c38363fffffffc1660016106ba565b60208901519091508060001a6001036114305761142d81600090815233602052604090207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b90505b6000805460408b81015190517fe03110e10000000000000000000000000000000000000000000000000000000081526004810185905263ffffffff9091166024820152829173ffffffffffffffffffffffffffffffffffffffff169063e03110e1906044016040805180830381865afa1580156114b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d59190611c45565b915091506003861680600403828110156114ed578092505b50818610156114fa578591505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119871617955050506115518663fffffffc1660018661198a565b60408b018051820163ffffffff16905297506115ad92505050565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd63ffffffff8416016115a15780945061174f565b63ffffffff9450600993505b61174f565b8563ffffffff16610fa4036116a35763ffffffff8316600114806115dc575063ffffffff83166002145b806115ed575063ffffffff83166004145b156115fa5780945061174f565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa63ffffffff8416016115a157600061163a8363fffffffc1660016106ba565b60208901519091506003841660040383811015611655578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b1760208801526000604088015293508361174f565b8563ffffffff16610fd70361174f578163ffffffff166003036117435763ffffffff831615806116d9575063ffffffff83166005145b806116ea575063ffffffff83166003145b156116f8576000945061174f565b63ffffffff831660011480611713575063ffffffff83166002145b80611724575063ffffffff83166006145b80611735575063ffffffff83166004145b156115a1576001945061174f565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b0152600401909116905261135c610612565b600061179a611ad7565b506080600063ffffffff87166010036117b8575060c0810151611921565b8663ffffffff166011036117d75763ffffffff861660c0830152611921565b8663ffffffff166012036117f0575060a0810151611921565b8663ffffffff1660130361180f5763ffffffff861660a0830152611921565b8663ffffffff166018036118435763ffffffff600387810b9087900b02602081901c821660c08501521660a0830152611921565b8663ffffffff166019036118745763ffffffff86811681871602602081901c821660c08501521660a0830152611921565b8663ffffffff16601a036118ca578460030b8660030b8161189757611897611c69565b0763ffffffff1660c0830152600385810b9087900b816118b9576118b9611c69565b0563ffffffff1660a0830152611921565b8663ffffffff16601b03611921578463ffffffff168663ffffffff16816118f3576118f3611c69565b0663ffffffff90811660c08401528581169087168161191457611914611c69565b0463ffffffff1660a08301525b63ffffffff84161561195c57808261016001518563ffffffff166020811061194b5761194b611c16565b63ffffffff90921660209290920201525b60808201805163ffffffff8082166060860152600490910116905261197f610612565b979650505050505050565b600061199583611a2e565b905060038416156119a557600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b811015611a235760208401933582821c60011680156119f35760018114611a0857611a19565b60008581526020839052604090209450611a19565b600082815260208690526040902094505b50506001016119cb565b505060805250505050565b60ff811661038002610184810190369061050401811015611ad1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f636865636b207468617420746865726520697320656e6f7567682063616c6c6460448201527f61746100000000000000000000000000000000000000000000000000000000006064820152608401610873565b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611b3d611b42565b905290565b6040518061040001604052806020906020820280368337509192915050565b60008083601f840112611b7357600080fd5b50813567ffffffffffffffff811115611b8b57600080fd5b602083019150836020828501011115611ba357600080fd5b9250929050565b60008060008060408587031215611bc057600080fd5b843567ffffffffffffffff80821115611bd857600080fd5b611be488838901611b61565b90965094506020870135915080821115611bfd57600080fd5b50611c0a87828801611b61565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008060408385031215611c5857600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea164736f6c634300080f000a",
ABI: "[{\"inputs\":[{\"internalType\":\"contractIPreimageOracle\",\"name\":\"_oracle\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BRK_START\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracle\",\"outputs\":[{\"internalType\":\"contractIPreimageOracle\",\"name\":\"oracle_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"stateData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"step\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
Bin: "0x60a060405234801561001057600080fd5b50604051611d55380380611d5583398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051611cc4610091600039600081816085015261148a0152611cc46000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006b578063f8e0cb96146100af575b600080fd5b610051634000000081565b60405163ffffffff90911681526020015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610062565b6100c26100bd366004611bc9565b6100d0565b604051908152602001610062565b60006100da611af6565b608081146100e757600080fd5b604051610600146100f757600080fd5b6064861461010457600080fd5b610184841461011257600080fd5b8535608052602086013560a052604086013560e090811c60c09081526044880135821c82526048880135821c61010052604c880135821c610120526050880135821c61014052605488013590911c61016052605887013560f890811c610180526059880135901c6101a052605a870135901c6101c0526102006101e0819052606287019060005b60208110156101bd57823560e01c8252600490920191602090910190600101610199565b505050806101200151156101db576101d3610611565b915050610609565b6101408101805160010167ffffffffffffffff169052606081015160009061020390826106b9565b9050603f601a82901c16600281148061022257508063ffffffff166003145b1561026f576102658163ffffffff1660021461023f57601f610242565b60005b60ff166002610258856303ffffff16601a610775565b63ffffffff16901b6107e8565b9350505050610609565b6101608301516000908190601f601086901c81169190601587901c166020811061029b5761029b611c35565b602002015192508063ffffffff851615806102bc57508463ffffffff16601c145b156102f3578661016001518263ffffffff16602081106102de576102de611c35565b6020020151925050601f600b86901c166103af565b60208563ffffffff161015610355578463ffffffff16600c148061031d57508463ffffffff16600d145b8061032e57508463ffffffff16600e145b1561033f578561ffff1692506103af565b61034e8661ffff166010610775565b92506103af565b60288563ffffffff1610158061037157508463ffffffff166022145b8061038257508463ffffffff166026145b156103af578661016001518263ffffffff16602081106103a4576103a4611c35565b602002015192508190505b60048563ffffffff16101580156103cc575060088563ffffffff16105b806103dd57508463ffffffff166001145b156103fc576103ee858784876108e2565b975050505050505050610609565b63ffffffff60006020878316106104615761041c8861ffff166010610775565b9095019463fffffffc86166104328160016106b9565b915060288863ffffffff161015801561045257508763ffffffff16603014155b1561045f57809250600093505b505b600061046f89888885610af2565b63ffffffff9081169150603f8a16908916158015610494575060088163ffffffff1610155b80156104a65750601c8163ffffffff16105b15610582578063ffffffff16600814806104c657508063ffffffff166009145b156104fd576104eb8163ffffffff166008146104e257856104e5565b60005b896107e8565b9b505050505050505050505050610609565b8063ffffffff16600a0361051d576104eb858963ffffffff8a1615611195565b8063ffffffff16600b0361053e576104eb858963ffffffff8a161515611195565b8063ffffffff16600c03610554576104eb61127b565b60108163ffffffff16101580156105715750601c8163ffffffff16105b15610582576104eb818989886117af565b8863ffffffff16603814801561059d575063ffffffff861615155b156105d25760018b61016001518763ffffffff16602081106105c1576105c1611c35565b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146105ef576105ef846001846119a9565b6105fb85836001611195565b9b5050505050505050505050505b949350505050565b60408051608051815260a051602082015260dc519181019190915260fc51604482015261011c51604882015261013c51604c82015261015c51605082015261017c51605482015261019f5160588201526101bf5160598201526101d851605a8201526000906102009060628101835b60208110156106a457601c8401518252602090930192600490910190600101610680565b506000815281810382a0819003902092915050565b6000806106c583611a4d565b905060038416156106d557600080fd5b6020810190358460051c8160005b601b81101561073b5760208501943583821c600116801561070b576001811461072057610731565b60008481526020839052604090209350610731565b600082815260208590526040902093505b50506001016106e3565b50608051915081811461075657630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b01826107d25760006107d4565b815b90861663ffffffff16179250505092915050565b60006107f2611af6565b60809050806060015160040163ffffffff16816080015163ffffffff161461087b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6a756d7020696e2064656c617920736c6f74000000000000000000000000000060448201526064015b60405180910390fd5b60608101805160808301805163ffffffff9081169093528583169052908516156108d157806008018261016001518663ffffffff16602081106108c0576108c0611c35565b63ffffffff90921660209290920201525b6108d9610611565b95945050505050565b60006108ec611af6565b608090506000816060015160040163ffffffff16826080015163ffffffff1614610972576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6272616e636820696e2064656c617920736c6f740000000000000000000000006044820152606401610872565b8663ffffffff166004148061098d57508663ffffffff166005145b15610a095760008261016001518663ffffffff16602081106109b1576109b1611c35565b602002015190508063ffffffff168563ffffffff161480156109d957508763ffffffff166004145b80610a0157508063ffffffff168563ffffffff1614158015610a0157508763ffffffff166005145b915050610a86565b8663ffffffff16600603610a265760008460030b13159050610a86565b8663ffffffff16600703610a425760008460030b139050610a86565b8663ffffffff16600103610a8657601f601087901c166000819003610a6b5760008560030b1291505b8063ffffffff16600103610a845760008560030b121591505b505b606082018051608084015163ffffffff169091528115610acc576002610ab18861ffff166010610775565b63ffffffff90811690911b8201600401166080840152610ade565b60808301805160040163ffffffff1690525b610ae6610611565b98975050505050505050565b6000603f601a86901c81169086166020821015610eb65760088263ffffffff1610158015610b265750600f8263ffffffff16105b15610bc6578163ffffffff16600803610b4157506020610bc1565b8163ffffffff16600903610b5757506021610bc1565b8163ffffffff16600a03610b6d5750602a610bc1565b8163ffffffff16600b03610b835750602b610bc1565b8163ffffffff16600c03610b9957506024610bc1565b8163ffffffff16600d03610baf57506025610bc1565b8163ffffffff16600e03610bc1575060265b600091505b8163ffffffff16600003610e0a57601f600688901c16602063ffffffff83161015610ce45760088263ffffffff1610610c0457869350505050610609565b8163ffffffff16600003610c275763ffffffff86811691161b9250610609915050565b8163ffffffff16600203610c4a5763ffffffff86811691161c9250610609915050565b8163ffffffff16600303610c74576102658163ffffffff168763ffffffff16901c82602003610775565b8163ffffffff16600403610c97575050505063ffffffff8216601f84161b610609565b8163ffffffff16600603610cba575050505063ffffffff8216601f84161c610609565b8163ffffffff16600703610ce4576102658763ffffffff168763ffffffff16901c88602003610775565b8163ffffffff1660201480610cff57508163ffffffff166021145b15610d11578587019350505050610609565b8163ffffffff1660221480610d2c57508163ffffffff166023145b15610d3e578587039350505050610609565b8163ffffffff16602403610d59578587169350505050610609565b8163ffffffff16602503610d74578587179350505050610609565b8163ffffffff16602603610d8f578587189350505050610609565b8163ffffffff16602703610daa575050505082821719610609565b8163ffffffff16602a03610ddc578560030b8760030b12610dcc576000610dcf565b60015b60ff169350505050610609565b8163ffffffff16602b03610e04578563ffffffff168763ffffffff1610610dcc576000610dcf565b50611133565b8163ffffffff16600f03610e2c5760108563ffffffff16901b92505050610609565b8163ffffffff16601c03610eb1578063ffffffff16600203610e5357505050828202610609565b8063ffffffff1660201480610e6e57508063ffffffff166021145b15610eb1578063ffffffff16602003610e85579419945b60005b6380000000871615610ea7576401fffffffe600197881b169601610e88565b9250610609915050565b611133565b60288263ffffffff161015611019578163ffffffff16602003610f0257610ef98660031660080260180363ffffffff168563ffffffff16901c60ff166008610775565b92505050610609565b8163ffffffff16602103610f3757610ef98660021660080260100363ffffffff168563ffffffff16901c61ffff166010610775565b8163ffffffff16602203610f675750505063ffffffff60086003851602811681811b198416918316901b17610609565b8163ffffffff16602303610f7f578392505050610609565b8163ffffffff16602403610fb2578560031660080260180363ffffffff168463ffffffff16901c60ff1692505050610609565b8163ffffffff16602503610fe6578560021660080260100363ffffffff168463ffffffff16901c61ffff1692505050610609565b8163ffffffff16602603610eb15750505063ffffffff60086003851602601803811681811c198416918316901c17610609565b8163ffffffff166028036110505750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610609565b8163ffffffff166029036110885750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610609565b8163ffffffff16602a036110b85750505063ffffffff60086003851602811681811c198316918416901c17610609565b8163ffffffff16602b036110d0578492505050610609565b8163ffffffff16602e036111035750505063ffffffff60086003851602601803811681811b198316918416901b17610609565b8163ffffffff1660300361111b578392505050610609565b8163ffffffff16603803611133578492505050610609565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e000000000000000000000000006044820152606401610872565b600061119f611af6565b506080602063ffffffff861610611212576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c69642072656769737465720000000000000000000000000000000000006044820152606401610872565b63ffffffff8516158015906112245750825b1561125857838161016001518663ffffffff166020811061124757611247611c35565b63ffffffff90921660209290920201525b60808101805163ffffffff808216606085015260049091011690526108d9610611565b6000611285611af6565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa036112ff5781610fff8116156112ce57610fff811661100003015b8363ffffffff166000036112f55760e08801805163ffffffff8382011690915295506112f9565b8395505b5061176e565b8563ffffffff16610fcd0361131a576340000000945061176e565b8563ffffffff1661101803611332576001945061176e565b8563ffffffff166110960361136757600161012088015260ff831661010088015261135b610611565b97505050505050505090565b8563ffffffff16610fa3036115d15763ffffffff83161561176e577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb63ffffffff84160161158b5760006113c28363fffffffc1660016106b9565b60208901519091508060001a60010361142f5761142c81600090815233602052604090207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b90505b6040808a015190517fe03110e10000000000000000000000000000000000000000000000000000000081526004810183905263ffffffff9091166024820152600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063e03110e1906044016040805180830381865afa1580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190611c64565b9150915060038616806004038281101561150c578092505b5081861015611519578591505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119871617955050506115708663fffffffc166001866119a9565b60408b018051820163ffffffff16905297506115cc92505050565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd63ffffffff8416016115c05780945061176e565b63ffffffff9450600993505b61176e565b8563ffffffff16610fa4036116c25763ffffffff8316600114806115fb575063ffffffff83166002145b8061160c575063ffffffff83166004145b156116195780945061176e565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa63ffffffff8416016115c05760006116598363fffffffc1660016106b9565b60208901519091506003841660040383811015611674578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b1760208801526000604088015293508361176e565b8563ffffffff16610fd70361176e578163ffffffff166003036117625763ffffffff831615806116f8575063ffffffff83166005145b80611709575063ffffffff83166003145b15611717576000945061176e565b63ffffffff831660011480611732575063ffffffff83166002145b80611743575063ffffffff83166006145b80611754575063ffffffff83166004145b156115c0576001945061176e565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b0152600401909116905261135b610611565b60006117b9611af6565b506080600063ffffffff87166010036117d7575060c0810151611940565b8663ffffffff166011036117f65763ffffffff861660c0830152611940565b8663ffffffff1660120361180f575060a0810151611940565b8663ffffffff1660130361182e5763ffffffff861660a0830152611940565b8663ffffffff166018036118625763ffffffff600387810b9087900b02602081901c821660c08501521660a0830152611940565b8663ffffffff166019036118935763ffffffff86811681871602602081901c821660c08501521660a0830152611940565b8663ffffffff16601a036118e9578460030b8660030b816118b6576118b6611c88565b0763ffffffff1660c0830152600385810b9087900b816118d8576118d8611c88565b0563ffffffff1660a0830152611940565b8663ffffffff16601b03611940578463ffffffff168663ffffffff168161191257611912611c88565b0663ffffffff90811660c08401528581169087168161193357611933611c88565b0463ffffffff1660a08301525b63ffffffff84161561197b57808261016001518563ffffffff166020811061196a5761196a611c35565b63ffffffff90921660209290920201525b60808201805163ffffffff8082166060860152600490910116905261199e610611565b979650505050505050565b60006119b483611a4d565b905060038416156119c457600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b811015611a425760208401933582821c6001168015611a125760018114611a2757611a38565b60008581526020839052604090209450611a38565b600082815260208690526040902094505b50506001016119ea565b505060805250505050565b60ff811661038002610184810190369061050401811015611af0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f636865636b207468617420746865726520697320656e6f7567682063616c6c6460448201527f61746100000000000000000000000000000000000000000000000000000000006064820152608401610872565b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611b5c611b61565b905290565b6040518061040001604052806020906020820280368337509192915050565b60008083601f840112611b9257600080fd5b50813567ffffffffffffffff811115611baa57600080fd5b602083019150836020828501011115611bc257600080fd5b9250929050565b60008060008060408587031215611bdf57600080fd5b843567ffffffffffffffff80821115611bf757600080fd5b611c0388838901611b80565b90965094506020870135915080821115611c1c57600080fd5b50611c2987828801611b80565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008060408385031215611c7757600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea164736f6c634300080f000a",
}
// MIPSABI is the input ABI used to generate the binding from.
......@@ -234,7 +234,7 @@ func (_MIPS *MIPSCallerSession) BRKSTART() (uint32, error) {
// Oracle is a free data retrieval call binding the contract method 0x7dc0d1d0.
//
// Solidity: function oracle() view returns(address)
// Solidity: function oracle() view returns(address oracle_)
func (_MIPS *MIPSCaller) Oracle(opts *bind.CallOpts) (common.Address, error) {
var out []interface{}
err := _MIPS.contract.Call(opts, &out, "oracle")
......@@ -251,14 +251,14 @@ func (_MIPS *MIPSCaller) Oracle(opts *bind.CallOpts) (common.Address, error) {
// Oracle is a free data retrieval call binding the contract method 0x7dc0d1d0.
//
// Solidity: function oracle() view returns(address)
// Solidity: function oracle() view returns(address oracle_)
func (_MIPS *MIPSSession) Oracle() (common.Address, error) {
return _MIPS.Contract.Oracle(&_MIPS.CallOpts)
}
// Oracle is a free data retrieval call binding the contract method 0x7dc0d1d0.
//
// Solidity: function oracle() view returns(address)
// Solidity: function oracle() view returns(address oracle_)
func (_MIPS *MIPSCallerSession) Oracle() (common.Address, error) {
return _MIPS.Contract.Oracle(&_MIPS.CallOpts)
}
......
......@@ -9,13 +9,13 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc"
)
const MIPSStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"src/cannon/MIPS.sol:MIPS\",\"label\":\"oracle\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_contract(IPreimageOracle)1001\"}],\"types\":{\"t_contract(IPreimageOracle)1001\":{\"encoding\":\"inplace\",\"label\":\"contract IPreimageOracle\",\"numberOfBytes\":\"20\"}}}"
const MIPSStorageLayoutJSON = "{\"storage\":null,\"types\":{}}"
var MIPSStorageLayout = new(solc.StorageLayout)
var MIPSDeployedBin = "0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006b578063f8e0cb96146100b0575b600080fd5b610051634000000081565b60405163ffffffff90911681526020015b60405180910390f35b60005461008b9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610062565b6100c36100be366004611baa565b6100d1565b604051908152602001610062565b60006100db611ad7565b608081146100e857600080fd5b604051610600146100f857600080fd5b6064861461010557600080fd5b610184841461011357600080fd5b8535608052602086013560a052604086013560e090811c60c09081526044880135821c82526048880135821c61010052604c880135821c610120526050880135821c61014052605488013590911c61016052605887013560f890811c610180526059880135901c6101a052605a870135901c6101c0526102006101e0819052606287019060005b60208110156101be57823560e01c825260049092019160209091019060010161019a565b505050806101200151156101dc576101d4610612565b91505061060a565b6101408101805160010167ffffffffffffffff169052606081015160009061020490826106ba565b9050603f601a82901c16600281148061022357508063ffffffff166003145b15610270576102668163ffffffff1660021461024057601f610243565b60005b60ff166002610259856303ffffff16601a610776565b63ffffffff16901b6107e9565b935050505061060a565b6101608301516000908190601f601086901c81169190601587901c166020811061029c5761029c611c16565b602002015192508063ffffffff851615806102bd57508463ffffffff16601c145b156102f4578661016001518263ffffffff16602081106102df576102df611c16565b6020020151925050601f600b86901c166103b0565b60208563ffffffff161015610356578463ffffffff16600c148061031e57508463ffffffff16600d145b8061032f57508463ffffffff16600e145b15610340578561ffff1692506103b0565b61034f8661ffff166010610776565b92506103b0565b60288563ffffffff1610158061037257508463ffffffff166022145b8061038357508463ffffffff166026145b156103b0578661016001518263ffffffff16602081106103a5576103a5611c16565b602002015192508190505b60048563ffffffff16101580156103cd575060088563ffffffff16105b806103de57508463ffffffff166001145b156103fd576103ef858784876108e3565b97505050505050505061060a565b63ffffffff60006020878316106104625761041d8861ffff166010610776565b9095019463fffffffc86166104338160016106ba565b915060288863ffffffff161015801561045357508763ffffffff16603014155b1561046057809250600093505b505b600061047089888885610af3565b63ffffffff9081169150603f8a16908916158015610495575060088163ffffffff1610155b80156104a75750601c8163ffffffff16105b15610583578063ffffffff16600814806104c757508063ffffffff166009145b156104fe576104ec8163ffffffff166008146104e357856104e6565b60005b896107e9565b9b50505050505050505050505061060a565b8063ffffffff16600a0361051e576104ec858963ffffffff8a1615611196565b8063ffffffff16600b0361053f576104ec858963ffffffff8a161515611196565b8063ffffffff16600c03610555576104ec61127c565b60108163ffffffff16101580156105725750601c8163ffffffff16105b15610583576104ec81898988611790565b8863ffffffff16603814801561059e575063ffffffff861615155b156105d35760018b61016001518763ffffffff16602081106105c2576105c2611c16565b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146105f0576105f08460018461198a565b6105fc85836001611196565b9b5050505050505050505050505b949350505050565b60408051608051815260a051602082015260dc519181019190915260fc51604482015261011c51604882015261013c51604c82015261015c51605082015261017c51605482015261019f5160588201526101bf5160598201526101d851605a8201526000906102009060628101835b60208110156106a557601c8401518252602090930192600490910190600101610681565b506000815281810382a0819003902092915050565b6000806106c683611a2e565b905060038416156106d657600080fd5b6020810190358460051c8160005b601b81101561073c5760208501943583821c600116801561070c576001811461072157610732565b60008481526020839052604090209350610732565b600082815260208590526040902093505b50506001016106e4565b50608051915081811461075757630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b01826107d35760006107d5565b815b90861663ffffffff16179250505092915050565b60006107f3611ad7565b60809050806060015160040163ffffffff16816080015163ffffffff161461087c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6a756d7020696e2064656c617920736c6f74000000000000000000000000000060448201526064015b60405180910390fd5b60608101805160808301805163ffffffff9081169093528583169052908516156108d257806008018261016001518663ffffffff16602081106108c1576108c1611c16565b63ffffffff90921660209290920201525b6108da610612565b95945050505050565b60006108ed611ad7565b608090506000816060015160040163ffffffff16826080015163ffffffff1614610973576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6272616e636820696e2064656c617920736c6f740000000000000000000000006044820152606401610873565b8663ffffffff166004148061098e57508663ffffffff166005145b15610a0a5760008261016001518663ffffffff16602081106109b2576109b2611c16565b602002015190508063ffffffff168563ffffffff161480156109da57508763ffffffff166004145b80610a0257508063ffffffff168563ffffffff1614158015610a0257508763ffffffff166005145b915050610a87565b8663ffffffff16600603610a275760008460030b13159050610a87565b8663ffffffff16600703610a435760008460030b139050610a87565b8663ffffffff16600103610a8757601f601087901c166000819003610a6c5760008560030b1291505b8063ffffffff16600103610a855760008560030b121591505b505b606082018051608084015163ffffffff169091528115610acd576002610ab28861ffff166010610776565b63ffffffff90811690911b8201600401166080840152610adf565b60808301805160040163ffffffff1690525b610ae7610612565b98975050505050505050565b6000603f601a86901c81169086166020821015610eb75760088263ffffffff1610158015610b275750600f8263ffffffff16105b15610bc7578163ffffffff16600803610b4257506020610bc2565b8163ffffffff16600903610b5857506021610bc2565b8163ffffffff16600a03610b6e5750602a610bc2565b8163ffffffff16600b03610b845750602b610bc2565b8163ffffffff16600c03610b9a57506024610bc2565b8163ffffffff16600d03610bb057506025610bc2565b8163ffffffff16600e03610bc2575060265b600091505b8163ffffffff16600003610e0b57601f600688901c16602063ffffffff83161015610ce55760088263ffffffff1610610c055786935050505061060a565b8163ffffffff16600003610c285763ffffffff86811691161b925061060a915050565b8163ffffffff16600203610c4b5763ffffffff86811691161c925061060a915050565b8163ffffffff16600303610c75576102668163ffffffff168763ffffffff16901c82602003610776565b8163ffffffff16600403610c98575050505063ffffffff8216601f84161b61060a565b8163ffffffff16600603610cbb575050505063ffffffff8216601f84161c61060a565b8163ffffffff16600703610ce5576102668763ffffffff168763ffffffff16901c88602003610776565b8163ffffffff1660201480610d0057508163ffffffff166021145b15610d1257858701935050505061060a565b8163ffffffff1660221480610d2d57508163ffffffff166023145b15610d3f57858703935050505061060a565b8163ffffffff16602403610d5a57858716935050505061060a565b8163ffffffff16602503610d7557858717935050505061060a565b8163ffffffff16602603610d9057858718935050505061060a565b8163ffffffff16602703610dab57505050508282171961060a565b8163ffffffff16602a03610ddd578560030b8760030b12610dcd576000610dd0565b60015b60ff16935050505061060a565b8163ffffffff16602b03610e05578563ffffffff168763ffffffff1610610dcd576000610dd0565b50611134565b8163ffffffff16600f03610e2d5760108563ffffffff16901b9250505061060a565b8163ffffffff16601c03610eb2578063ffffffff16600203610e545750505082820261060a565b8063ffffffff1660201480610e6f57508063ffffffff166021145b15610eb2578063ffffffff16602003610e86579419945b60005b6380000000871615610ea8576401fffffffe600197881b169601610e89565b925061060a915050565b611134565b60288263ffffffff16101561101a578163ffffffff16602003610f0357610efa8660031660080260180363ffffffff168563ffffffff16901c60ff166008610776565b9250505061060a565b8163ffffffff16602103610f3857610efa8660021660080260100363ffffffff168563ffffffff16901c61ffff166010610776565b8163ffffffff16602203610f685750505063ffffffff60086003851602811681811b198416918316901b1761060a565b8163ffffffff16602303610f8057839250505061060a565b8163ffffffff16602403610fb3578560031660080260180363ffffffff168463ffffffff16901c60ff169250505061060a565b8163ffffffff16602503610fe7578560021660080260100363ffffffff168463ffffffff16901c61ffff169250505061060a565b8163ffffffff16602603610eb25750505063ffffffff60086003851602601803811681811c198416918316901c1761060a565b8163ffffffff166028036110515750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b1761060a565b8163ffffffff166029036110895750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b1761060a565b8163ffffffff16602a036110b95750505063ffffffff60086003851602811681811c198316918416901c1761060a565b8163ffffffff16602b036110d157849250505061060a565b8163ffffffff16602e036111045750505063ffffffff60086003851602601803811681811b198316918416901b1761060a565b8163ffffffff1660300361111c57839250505061060a565b8163ffffffff1660380361113457849250505061060a565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e000000000000000000000000006044820152606401610873565b60006111a0611ad7565b506080602063ffffffff861610611213576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c69642072656769737465720000000000000000000000000000000000006044820152606401610873565b63ffffffff8516158015906112255750825b1561125957838161016001518663ffffffff166020811061124857611248611c16565b63ffffffff90921660209290920201525b60808101805163ffffffff808216606085015260049091011690526108da610612565b6000611286611ad7565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa036113005781610fff8116156112cf57610fff811661100003015b8363ffffffff166000036112f65760e08801805163ffffffff8382011690915295506112fa565b8395505b5061174f565b8563ffffffff16610fcd0361131b576340000000945061174f565b8563ffffffff1661101803611333576001945061174f565b8563ffffffff166110960361136857600161012088015260ff831661010088015261135c610612565b97505050505050505090565b8563ffffffff16610fa3036115b25763ffffffff83161561174f577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb63ffffffff84160161156c5760006113c38363fffffffc1660016106ba565b60208901519091508060001a6001036114305761142d81600090815233602052604090207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b90505b6000805460408b81015190517fe03110e10000000000000000000000000000000000000000000000000000000081526004810185905263ffffffff9091166024820152829173ffffffffffffffffffffffffffffffffffffffff169063e03110e1906044016040805180830381865afa1580156114b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d59190611c45565b915091506003861680600403828110156114ed578092505b50818610156114fa578591505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119871617955050506115518663fffffffc1660018661198a565b60408b018051820163ffffffff16905297506115ad92505050565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd63ffffffff8416016115a15780945061174f565b63ffffffff9450600993505b61174f565b8563ffffffff16610fa4036116a35763ffffffff8316600114806115dc575063ffffffff83166002145b806115ed575063ffffffff83166004145b156115fa5780945061174f565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa63ffffffff8416016115a157600061163a8363fffffffc1660016106ba565b60208901519091506003841660040383811015611655578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b1760208801526000604088015293508361174f565b8563ffffffff16610fd70361174f578163ffffffff166003036117435763ffffffff831615806116d9575063ffffffff83166005145b806116ea575063ffffffff83166003145b156116f8576000945061174f565b63ffffffff831660011480611713575063ffffffff83166002145b80611724575063ffffffff83166006145b80611735575063ffffffff83166004145b156115a1576001945061174f565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b0152600401909116905261135c610612565b600061179a611ad7565b506080600063ffffffff87166010036117b8575060c0810151611921565b8663ffffffff166011036117d75763ffffffff861660c0830152611921565b8663ffffffff166012036117f0575060a0810151611921565b8663ffffffff1660130361180f5763ffffffff861660a0830152611921565b8663ffffffff166018036118435763ffffffff600387810b9087900b02602081901c821660c08501521660a0830152611921565b8663ffffffff166019036118745763ffffffff86811681871602602081901c821660c08501521660a0830152611921565b8663ffffffff16601a036118ca578460030b8660030b8161189757611897611c69565b0763ffffffff1660c0830152600385810b9087900b816118b9576118b9611c69565b0563ffffffff1660a0830152611921565b8663ffffffff16601b03611921578463ffffffff168663ffffffff16816118f3576118f3611c69565b0663ffffffff90811660c08401528581169087168161191457611914611c69565b0463ffffffff1660a08301525b63ffffffff84161561195c57808261016001518563ffffffff166020811061194b5761194b611c16565b63ffffffff90921660209290920201525b60808201805163ffffffff8082166060860152600490910116905261197f610612565b979650505050505050565b600061199583611a2e565b905060038416156119a557600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b811015611a235760208401933582821c60011680156119f35760018114611a0857611a19565b60008581526020839052604090209450611a19565b600082815260208690526040902094505b50506001016119cb565b505060805250505050565b60ff811661038002610184810190369061050401811015611ad1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f636865636b207468617420746865726520697320656e6f7567682063616c6c6460448201527f61746100000000000000000000000000000000000000000000000000000000006064820152608401610873565b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611b3d611b42565b905290565b6040518061040001604052806020906020820280368337509192915050565b60008083601f840112611b7357600080fd5b50813567ffffffffffffffff811115611b8b57600080fd5b602083019150836020828501011115611ba357600080fd5b9250929050565b60008060008060408587031215611bc057600080fd5b843567ffffffffffffffff80821115611bd857600080fd5b611be488838901611b61565b90965094506020870135915080821115611bfd57600080fd5b50611c0a87828801611b61565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008060408385031215611c5857600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea164736f6c634300080f000a"
var MIPSDeployedBin = "0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006b578063f8e0cb96146100af575b600080fd5b610051634000000081565b60405163ffffffff90911681526020015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610062565b6100c26100bd366004611bc9565b6100d0565b604051908152602001610062565b60006100da611af6565b608081146100e757600080fd5b604051610600146100f757600080fd5b6064861461010457600080fd5b610184841461011257600080fd5b8535608052602086013560a052604086013560e090811c60c09081526044880135821c82526048880135821c61010052604c880135821c610120526050880135821c61014052605488013590911c61016052605887013560f890811c610180526059880135901c6101a052605a870135901c6101c0526102006101e0819052606287019060005b60208110156101bd57823560e01c8252600490920191602090910190600101610199565b505050806101200151156101db576101d3610611565b915050610609565b6101408101805160010167ffffffffffffffff169052606081015160009061020390826106b9565b9050603f601a82901c16600281148061022257508063ffffffff166003145b1561026f576102658163ffffffff1660021461023f57601f610242565b60005b60ff166002610258856303ffffff16601a610775565b63ffffffff16901b6107e8565b9350505050610609565b6101608301516000908190601f601086901c81169190601587901c166020811061029b5761029b611c35565b602002015192508063ffffffff851615806102bc57508463ffffffff16601c145b156102f3578661016001518263ffffffff16602081106102de576102de611c35565b6020020151925050601f600b86901c166103af565b60208563ffffffff161015610355578463ffffffff16600c148061031d57508463ffffffff16600d145b8061032e57508463ffffffff16600e145b1561033f578561ffff1692506103af565b61034e8661ffff166010610775565b92506103af565b60288563ffffffff1610158061037157508463ffffffff166022145b8061038257508463ffffffff166026145b156103af578661016001518263ffffffff16602081106103a4576103a4611c35565b602002015192508190505b60048563ffffffff16101580156103cc575060088563ffffffff16105b806103dd57508463ffffffff166001145b156103fc576103ee858784876108e2565b975050505050505050610609565b63ffffffff60006020878316106104615761041c8861ffff166010610775565b9095019463fffffffc86166104328160016106b9565b915060288863ffffffff161015801561045257508763ffffffff16603014155b1561045f57809250600093505b505b600061046f89888885610af2565b63ffffffff9081169150603f8a16908916158015610494575060088163ffffffff1610155b80156104a65750601c8163ffffffff16105b15610582578063ffffffff16600814806104c657508063ffffffff166009145b156104fd576104eb8163ffffffff166008146104e257856104e5565b60005b896107e8565b9b505050505050505050505050610609565b8063ffffffff16600a0361051d576104eb858963ffffffff8a1615611195565b8063ffffffff16600b0361053e576104eb858963ffffffff8a161515611195565b8063ffffffff16600c03610554576104eb61127b565b60108163ffffffff16101580156105715750601c8163ffffffff16105b15610582576104eb818989886117af565b8863ffffffff16603814801561059d575063ffffffff861615155b156105d25760018b61016001518763ffffffff16602081106105c1576105c1611c35565b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146105ef576105ef846001846119a9565b6105fb85836001611195565b9b5050505050505050505050505b949350505050565b60408051608051815260a051602082015260dc519181019190915260fc51604482015261011c51604882015261013c51604c82015261015c51605082015261017c51605482015261019f5160588201526101bf5160598201526101d851605a8201526000906102009060628101835b60208110156106a457601c8401518252602090930192600490910190600101610680565b506000815281810382a0819003902092915050565b6000806106c583611a4d565b905060038416156106d557600080fd5b6020810190358460051c8160005b601b81101561073b5760208501943583821c600116801561070b576001811461072057610731565b60008481526020839052604090209350610731565b600082815260208590526040902093505b50506001016106e3565b50608051915081811461075657630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b01826107d25760006107d4565b815b90861663ffffffff16179250505092915050565b60006107f2611af6565b60809050806060015160040163ffffffff16816080015163ffffffff161461087b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6a756d7020696e2064656c617920736c6f74000000000000000000000000000060448201526064015b60405180910390fd5b60608101805160808301805163ffffffff9081169093528583169052908516156108d157806008018261016001518663ffffffff16602081106108c0576108c0611c35565b63ffffffff90921660209290920201525b6108d9610611565b95945050505050565b60006108ec611af6565b608090506000816060015160040163ffffffff16826080015163ffffffff1614610972576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6272616e636820696e2064656c617920736c6f740000000000000000000000006044820152606401610872565b8663ffffffff166004148061098d57508663ffffffff166005145b15610a095760008261016001518663ffffffff16602081106109b1576109b1611c35565b602002015190508063ffffffff168563ffffffff161480156109d957508763ffffffff166004145b80610a0157508063ffffffff168563ffffffff1614158015610a0157508763ffffffff166005145b915050610a86565b8663ffffffff16600603610a265760008460030b13159050610a86565b8663ffffffff16600703610a425760008460030b139050610a86565b8663ffffffff16600103610a8657601f601087901c166000819003610a6b5760008560030b1291505b8063ffffffff16600103610a845760008560030b121591505b505b606082018051608084015163ffffffff169091528115610acc576002610ab18861ffff166010610775565b63ffffffff90811690911b8201600401166080840152610ade565b60808301805160040163ffffffff1690525b610ae6610611565b98975050505050505050565b6000603f601a86901c81169086166020821015610eb65760088263ffffffff1610158015610b265750600f8263ffffffff16105b15610bc6578163ffffffff16600803610b4157506020610bc1565b8163ffffffff16600903610b5757506021610bc1565b8163ffffffff16600a03610b6d5750602a610bc1565b8163ffffffff16600b03610b835750602b610bc1565b8163ffffffff16600c03610b9957506024610bc1565b8163ffffffff16600d03610baf57506025610bc1565b8163ffffffff16600e03610bc1575060265b600091505b8163ffffffff16600003610e0a57601f600688901c16602063ffffffff83161015610ce45760088263ffffffff1610610c0457869350505050610609565b8163ffffffff16600003610c275763ffffffff86811691161b9250610609915050565b8163ffffffff16600203610c4a5763ffffffff86811691161c9250610609915050565b8163ffffffff16600303610c74576102658163ffffffff168763ffffffff16901c82602003610775565b8163ffffffff16600403610c97575050505063ffffffff8216601f84161b610609565b8163ffffffff16600603610cba575050505063ffffffff8216601f84161c610609565b8163ffffffff16600703610ce4576102658763ffffffff168763ffffffff16901c88602003610775565b8163ffffffff1660201480610cff57508163ffffffff166021145b15610d11578587019350505050610609565b8163ffffffff1660221480610d2c57508163ffffffff166023145b15610d3e578587039350505050610609565b8163ffffffff16602403610d59578587169350505050610609565b8163ffffffff16602503610d74578587179350505050610609565b8163ffffffff16602603610d8f578587189350505050610609565b8163ffffffff16602703610daa575050505082821719610609565b8163ffffffff16602a03610ddc578560030b8760030b12610dcc576000610dcf565b60015b60ff169350505050610609565b8163ffffffff16602b03610e04578563ffffffff168763ffffffff1610610dcc576000610dcf565b50611133565b8163ffffffff16600f03610e2c5760108563ffffffff16901b92505050610609565b8163ffffffff16601c03610eb1578063ffffffff16600203610e5357505050828202610609565b8063ffffffff1660201480610e6e57508063ffffffff166021145b15610eb1578063ffffffff16602003610e85579419945b60005b6380000000871615610ea7576401fffffffe600197881b169601610e88565b9250610609915050565b611133565b60288263ffffffff161015611019578163ffffffff16602003610f0257610ef98660031660080260180363ffffffff168563ffffffff16901c60ff166008610775565b92505050610609565b8163ffffffff16602103610f3757610ef98660021660080260100363ffffffff168563ffffffff16901c61ffff166010610775565b8163ffffffff16602203610f675750505063ffffffff60086003851602811681811b198416918316901b17610609565b8163ffffffff16602303610f7f578392505050610609565b8163ffffffff16602403610fb2578560031660080260180363ffffffff168463ffffffff16901c60ff1692505050610609565b8163ffffffff16602503610fe6578560021660080260100363ffffffff168463ffffffff16901c61ffff1692505050610609565b8163ffffffff16602603610eb15750505063ffffffff60086003851602601803811681811c198416918316901c17610609565b8163ffffffff166028036110505750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610609565b8163ffffffff166029036110885750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610609565b8163ffffffff16602a036110b85750505063ffffffff60086003851602811681811c198316918416901c17610609565b8163ffffffff16602b036110d0578492505050610609565b8163ffffffff16602e036111035750505063ffffffff60086003851602601803811681811b198316918416901b17610609565b8163ffffffff1660300361111b578392505050610609565b8163ffffffff16603803611133578492505050610609565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e000000000000000000000000006044820152606401610872565b600061119f611af6565b506080602063ffffffff861610611212576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c69642072656769737465720000000000000000000000000000000000006044820152606401610872565b63ffffffff8516158015906112245750825b1561125857838161016001518663ffffffff166020811061124757611247611c35565b63ffffffff90921660209290920201525b60808101805163ffffffff808216606085015260049091011690526108d9610611565b6000611285611af6565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa036112ff5781610fff8116156112ce57610fff811661100003015b8363ffffffff166000036112f55760e08801805163ffffffff8382011690915295506112f9565b8395505b5061176e565b8563ffffffff16610fcd0361131a576340000000945061176e565b8563ffffffff1661101803611332576001945061176e565b8563ffffffff166110960361136757600161012088015260ff831661010088015261135b610611565b97505050505050505090565b8563ffffffff16610fa3036115d15763ffffffff83161561176e577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb63ffffffff84160161158b5760006113c28363fffffffc1660016106b9565b60208901519091508060001a60010361142f5761142c81600090815233602052604090207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b90505b6040808a015190517fe03110e10000000000000000000000000000000000000000000000000000000081526004810183905263ffffffff9091166024820152600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063e03110e1906044016040805180830381865afa1580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190611c64565b9150915060038616806004038281101561150c578092505b5081861015611519578591505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119871617955050506115708663fffffffc166001866119a9565b60408b018051820163ffffffff16905297506115cc92505050565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd63ffffffff8416016115c05780945061176e565b63ffffffff9450600993505b61176e565b8563ffffffff16610fa4036116c25763ffffffff8316600114806115fb575063ffffffff83166002145b8061160c575063ffffffff83166004145b156116195780945061176e565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa63ffffffff8416016115c05760006116598363fffffffc1660016106b9565b60208901519091506003841660040383811015611674578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b1760208801526000604088015293508361176e565b8563ffffffff16610fd70361176e578163ffffffff166003036117625763ffffffff831615806116f8575063ffffffff83166005145b80611709575063ffffffff83166003145b15611717576000945061176e565b63ffffffff831660011480611732575063ffffffff83166002145b80611743575063ffffffff83166006145b80611754575063ffffffff83166004145b156115c0576001945061176e565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b0152600401909116905261135b610611565b60006117b9611af6565b506080600063ffffffff87166010036117d7575060c0810151611940565b8663ffffffff166011036117f65763ffffffff861660c0830152611940565b8663ffffffff1660120361180f575060a0810151611940565b8663ffffffff1660130361182e5763ffffffff861660a0830152611940565b8663ffffffff166018036118625763ffffffff600387810b9087900b02602081901c821660c08501521660a0830152611940565b8663ffffffff166019036118935763ffffffff86811681871602602081901c821660c08501521660a0830152611940565b8663ffffffff16601a036118e9578460030b8660030b816118b6576118b6611c88565b0763ffffffff1660c0830152600385810b9087900b816118d8576118d8611c88565b0563ffffffff1660a0830152611940565b8663ffffffff16601b03611940578463ffffffff168663ffffffff168161191257611912611c88565b0663ffffffff90811660c08401528581169087168161193357611933611c88565b0463ffffffff1660a08301525b63ffffffff84161561197b57808261016001518563ffffffff166020811061196a5761196a611c35565b63ffffffff90921660209290920201525b60808201805163ffffffff8082166060860152600490910116905261199e610611565b979650505050505050565b60006119b483611a4d565b905060038416156119c457600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b811015611a425760208401933582821c6001168015611a125760018114611a2757611a38565b60008581526020839052604090209450611a38565b600082815260208690526040902094505b50506001016119ea565b505060805250505050565b60ff811661038002610184810190369061050401811015611af0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f636865636b207468617420746865726520697320656e6f7567682063616c6c6460448201527f61746100000000000000000000000000000000000000000000000000000000006064820152608401610872565b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611b5c611b61565b905290565b6040518061040001604052806020906020820280368337509192915050565b60008083601f840112611b9257600080fd5b50813567ffffffffffffffff811115611baa57600080fd5b602083019150836020828501011115611bc257600080fd5b9250929050565b60008060008060408587031215611bdf57600080fd5b843567ffffffffffffffff80821115611bf757600080fd5b611c0388838901611b80565b90965094506020870135915080821115611c1c57600080fd5b50611c2987828801611b80565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008060408385031215611c7757600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea164736f6c634300080f000a"
var MIPSDeployedSourceMap = "1131:37218:106:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1710:45;;1745:10;1710:45;;;;;188:10:257;176:23;;;158:42;;146:2;131:18;1710:45:106;;;;;;;;2144:29;;;;;;;;;;;;412:42:257;400:55;;;382:74;;370:2;355:18;2144:29:106;211:251:257;24696:6377:106;;;;;;:::i;:::-;;:::i;:::-;;;1687:25:257;;;1675:2;1660:18;24696:6377:106;1541:177:257;24696:6377:106;24774:7;24817:18;;:::i;:::-;24964:4;24957:5;24954:15;24944:134;;25058:1;25055;25048:12;24944:134;25114:4;25108:11;25121;25105:28;25095:137;;25212:1;25209;25202:12;25095:137;25280:3;25262:16;25259:25;25249:150;;25379:1;25376;25369:12;25249:150;25443:3;25429:12;25426:21;25416:145;;25541:1;25538;25531:12;25416:145;25821:24;;26165:4;25867:20;26223:2;25925:21;;25821:24;25983:18;25867:20;25925:21;;;25821:24;25798:21;25794:52;;;25983:18;25867:20;;;25925:21;;;25821:24;25794:52;;25867:20;;25925:21;;;25821:24;25794:52;;25983:18;25867:20;25925:21;;;25821:24;25794:52;;25983:18;25867:20;25925:21;;;25821:24;25794:52;;25983:18;25867:20;25925:21;;;25821:24;25794:52;;;25983:18;25867:20;25925:21;;;25821:24;25798:21;25794:52;;;25983:18;25867:20;25925:21;;;25821:24;25794:52;;25983:18;25867:20;25925:21;;;25821:24;25794:52;;25983:18;25867:20;26841:10;25983:18;26831:21;;;25925;;;;26939:1;26924:77;26949:2;26946:1;26943:9;26924:77;;;25821:24;;25798:21;25794:52;25867:20;;26997:1;25925:21;;;;25809:2;25983:18;;;;26967:1;26960:9;26924:77;;;26928:14;;;27079:5;:12;;;27075:71;;;27118:13;:11;:13::i;:::-;27111:20;;;;;27075:71;27160:10;;;:15;;27174:1;27160:15;;;;;27245:8;;;;-1:-1:-1;;27237:20:106;;-1:-1:-1;27237:7:106;:20::i;:::-;27223:34;-1:-1:-1;27287:10:106;27295:2;27287:10;;;;27364:1;27354:11;;;:26;;;27369:6;:11;;27379:1;27369:11;27354:26;27350:348;;;27619:64;27630:6;:11;;27640:1;27630:11;:20;;27648:2;27630:20;;;27644:1;27630:20;27619:64;;27681:1;27652:25;27655:4;27662:10;27655:17;27674:2;27652;:25::i;:::-;:30;;;;27619:10;:64::i;:::-;27612:71;;;;;;;27350:348;27947:15;;;;27742:9;;;;27879:4;27873:2;27865:10;;;27864:19;;;27947:15;27972:2;27964:10;;;27963:19;27947:36;;;;;;;:::i;:::-;;;;;;-1:-1:-1;28012:5:106;28036:11;;;;;:29;;;28051:6;:14;;28061:4;28051:14;28036:29;28032:832;;;28128:5;:15;;;28144:5;28128:22;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;28191:4:106;28185:2;28177:10;;;28176:19;28032:832;;;28229:4;28220:6;:13;;;28216:648;;;28350:6;:13;;28360:3;28350:13;:30;;;;28367:6;:13;;28377:3;28367:13;28350:30;:47;;;;28384:6;:13;;28394:3;28384:13;28350:47;28346:253;;;28460:4;28467:6;28460:13;28455:18;;28216:648;;28346:253;28559:21;28562:4;28569:6;28562:13;28577:2;28559;:21::i;:::-;28554:26;;28216:648;;;28633:4;28623:6;:14;;;;:32;;;;28641:6;:14;;28651:4;28641:14;28623:32;:50;;;;28659:6;:14;;28669:4;28659:14;28623:50;28619:245;;;28743:5;:15;;;28759:5;28743:22;;;;;;;;;:::i;:::-;;;;;28738:27;;28844:5;28836:13;;28619:245;28893:1;28883:6;:11;;;;:25;;;;;28907:1;28898:6;:10;;;28883:25;28882:42;;;;28913:6;:11;;28923:1;28913:11;28882:42;28878:125;;;28951:37;28964:6;28972:4;28978:5;28985:2;28951:12;:37::i;:::-;28944:44;;;;;;;;;;;28878:125;29036:13;29017:16;29188:4;29178:14;;;;29174:446;;29257:21;29260:4;29267:6;29260:13;29275:2;29257;:21::i;:::-;29251:27;;;;29315:10;29310:15;;29349:16;29310:15;29363:1;29349:7;:16::i;:::-;29343:22;;29397:4;29387:6;:14;;;;:32;;;;;29405:6;:14;;29415:4;29405:14;;29387:32;29383:223;;;29484:4;29472:16;;29586:1;29578:9;;29383:223;29194:426;29174:446;29653:10;29666:26;29674:4;29680:2;29684;29688:3;29666:7;:26::i;:::-;29695:10;29666:39;;;;-1:-1:-1;29791:4:106;29784:11;;;29823;;;:24;;;;;29846:1;29838:4;:9;;;;29823:24;:39;;;;;29858:4;29851;:11;;;29823:39;29819:847;;;29886:4;:9;;29894:1;29886:9;:22;;;;29899:4;:9;;29907:1;29899:9;29886:22;29882:144;;;29970:37;29981:4;:9;;29989:1;29981:9;:21;;29997:5;29981:21;;;29993:1;29981:21;30004:2;29970:10;:37::i;:::-;29963:44;;;;;;;;;;;;;;;29882:144;30048:4;:11;;30056:3;30048:11;30044:121;;30118:28;30127:5;30134:2;30138:7;;;;30118:8;:28::i;30044:121::-;30186:4;:11;;30194:3;30186:11;30182:121;;30256:28;30265:5;30272:2;30276:7;;;;;30256:8;:28::i;30182:121::-;30373:4;:11;;30381:3;30373:11;30369:80;;30415:15;:13;:15::i;30369:80::-;30552:4;30544;:12;;;;:27;;;;;30567:4;30560;:11;;;30544:27;30540:112;;;30602:31;30613:4;30619:2;30623;30627:5;30602:10;:31::i;30540:112::-;30726:6;:14;;30736:4;30726:14;:28;;;;-1:-1:-1;30744:10:106;;;;;30726:28;30722:93;;;30799:1;30774:5;:15;;;30790:5;30774:22;;;;;;;;;:::i;:::-;:26;;;;:22;;;;;;:26;30722:93;30861:9;:26;;30874:13;30861:26;30857:92;;30907:27;30916:9;30927:1;30930:3;30907:8;:27::i;:::-;31030:26;31039:5;31046:3;31051:4;31030:8;:26::i;:::-;31023:33;;;;;;;;;;;;;24696:6377;;;;;;;:::o;2858:1709::-;3405:4;3399:11;;3321:4;3124:31;3113:43;;3184:13;3124:31;3523:2;3223:13;;3113:43;3130:24;3124:31;3223:13;;;3113:43;;;;3130:24;3124:31;3223:13;;;3113:43;3130:24;3124:31;3223:13;;;3113:43;3130:24;3124:31;3223:13;;;3113:43;3130:24;3124:31;3223:13;;;3113:43;3130:24;3124:31;3223:13;;;3113:43;3130:24;3124:31;3223:13;;;3113:43;3130:24;3124:31;3223:13;;;3113:43;3130:24;3124:31;3223:13;;;3113:43;2899:12;;4108:13;;3223;;;2899:12;4188:84;4213:2;4210:1;4207:9;4188:84;;;3140:13;3130:24;;3124:31;3113:43;;3144:2;3184:13;;;;4268:1;3223:13;;;;4231:1;4224:9;4188:84;;;4192:14;4335:1;4331:2;4324:13;4430:5;4426:2;4422:14;4415:5;4410:27;4536:14;;;4519:32;;;2858:1709;-1:-1:-1;;2858:1709:106:o;20751:1831::-;20824:11;20935:14;20952:24;20964:11;20952;:24::i;:::-;20935:41;;21084:1;21077:5;21073:13;21070:33;;;21099:1;21096;21089:12;21070:33;21232:2;21220:15;;;21173:20;21662:5;21659:1;21655:13;21697:4;21733:1;21718:343;21743:2;21740:1;21737:9;21718:343;;;21866:2;21854:15;;;21803:20;21901:12;;;21915:1;21897:20;21938:42;;;;22006:1;22001:42;;;;21890:153;;21938:42;21396:1;21389:12;;;21429:2;21422:13;;;21474:2;21461:16;;21947:31;;21938:42;;22001;21396:1;21389:12;;;21429:2;21422:13;;;21474:2;21461:16;;22010:31;;21890:153;-1:-1:-1;;21761:1:106;21754:9;21718:343;;;21722:14;22171:4;22165:11;22150:26;;22257:7;22251:4;22248:17;22238:124;;22299:10;22296:1;22289:21;22341:2;22338:1;22331:13;22238:124;-1:-1:-1;;22489:2:106;22478:14;;;;22466:10;22462:31;22459:1;22455:39;22523:16;;;;22541:10;22519:33;;20751:1831;-1:-1:-1;;;20751:1831:106:o;2416:334::-;2477:6;2536:18;;;;2545:8;;;;2536:18;;;;;;2535:25;;;;;2552:1;2599:2;:9;;;2593:16;;;;;2592:22;;2591:32;;;;;;;2653:9;;2652:15;2535:25;2710:21;;2730:1;2710:21;;;2721:6;2710:21;2695:11;;;;;:37;;-1:-1:-1;;;2416:334:106;;;;:::o;17861:823::-;17930:12;18017:18;;:::i;:::-;18085:4;18076:13;;18137:5;:8;;;18148:1;18137:12;18121:28;;:5;:12;;;:28;;;18117:95;;18169:28;;;;;2114:2:257;18169:28:106;;;2096:21:257;2153:2;2133:18;;;2126:30;2192:20;2172:18;;;2165:48;2230:18;;18169:28:106;;;;;;;;18117:95;18301:8;;;;;18334:12;;;;;18323:23;;;;;;;18360:20;;;;;18301:8;18492:13;;;18488:90;;18553:6;18562:1;18553:10;18525:5;:15;;;18541:8;18525:25;;;;;;;;;:::i;:::-;:38;;;;:25;;;;;;:38;18488:90;18654:13;:11;:13::i;:::-;18647:20;17861:823;-1:-1:-1;;;;;17861:823:106:o;12722:2026::-;12819:12;12905:18;;:::i;:::-;12973:4;12964:13;;13005:17;13065:5;:8;;;13076:1;13065:12;13049:28;;:5;:12;;;:28;;;13045:97;;13097:30;;;;;2461:2:257;13097:30:106;;;2443:21:257;2500:2;2480:18;;;2473:30;2539:22;2519:18;;;2512:50;2579:18;;13097:30:106;2259:344:257;13045:97:106;13212:7;:12;;13223:1;13212:12;:28;;;;13228:7;:12;;13239:1;13228:12;13212:28;13208:947;;;13260:9;13272:5;:15;;;13288:6;13272:23;;;;;;;;;:::i;:::-;;;;;13260:35;;13336:2;13329:9;;:3;:9;;;:25;;;;;13342:7;:12;;13353:1;13342:12;13329:25;13328:58;;;;13367:2;13360:9;;:3;:9;;;;:25;;;;;13373:7;:12;;13384:1;13373:12;13360:25;13313:73;;13242:159;13208:947;;;13498:7;:12;;13509:1;13498:12;13494:661;;13559:1;13551:3;13545:15;;;;13530:30;;13494:661;;;13663:7;:12;;13674:1;13663:12;13659:496;;13723:1;13716:3;13710:14;;;13695:29;;13659:496;;;13844:7;:12;;13855:1;13844:12;13840:315;;13932:4;13926:2;13917:11;;;13916:20;13902:10;13959:8;;;13955:84;;14019:1;14012:3;14006:14;;;13991:29;;13955:84;14060:3;:8;;14067:1;14060:8;14056:85;;14121:1;14113:3;14107:15;;;;14092:30;;14056:85;13858:297;13840:315;14231:8;;;;;14309:12;;;;14298:23;;;;;14465:178;;;;14556:1;14530:22;14533:5;14541:6;14533:14;14549:2;14530;:22::i;:::-;:27;;;;;;;14516:42;;14525:1;14516:42;14501:57;:12;;;:57;14465:178;;;14612:12;;;;;14627:1;14612:16;14597:31;;;;14465:178;14718:13;:11;:13::i;:::-;14711:20;12722:2026;-1:-1:-1;;;;;;;;12722:2026:106:o;31119:7228::-;31206:6;31264:10;31272:2;31264:10;;;;;;31312:11;;31424:4;31415:13;;31411:6876;;;31555:1;31545:6;:11;;;;:27;;;;;31569:3;31560:6;:12;;;31545:27;31541:537;;;31600:6;:11;;31610:1;31600:11;31596:423;;-1:-1:-1;31620:4:106;31596:423;;;31664:6;:11;;31674:1;31664:11;31660:359;;-1:-1:-1;31684:4:106;31660:359;;;31729:6;:13;;31739:3;31729:13;31725:294;;-1:-1:-1;31751:4:106;31725:294;;;31795:6;:13;;31805:3;31795:13;31791:228;;-1:-1:-1;31817:4:106;31791:228;;;31862:6;:13;;31872:3;31862:13;31858:161;;-1:-1:-1;31884:4:106;31858:161;;;31928:6;:13;;31938:3;31928:13;31924:95;;-1:-1:-1;31950:4:106;31924:95;;;31993:6;:13;;32003:3;31993:13;31989:30;;-1:-1:-1;32015:4:106;31989:30;32058:1;32049:10;;31541:537;32139:6;:11;;32149:1;32139:11;32135:3554;;32203:4;32198:1;32190:9;;;32189:18;32240:4;32190:9;32233:11;;;32229:1319;;;32332:4;32324;:12;;;32320:1206;;32375:2;32368:9;;;;;;;32320:1206;32489:4;:12;;32497:4;32489:12;32485:1041;;32540:11;;;;;;;;-1:-1:-1;32533:18:106;;-1:-1:-1;;32533:18:106;32485:1041;32664:4;:12;;32672:4;32664:12;32660:866;;32715:11;;;;;;;;-1:-1:-1;32708:18:106;;-1:-1:-1;;32708:18:106;32660:866;32842:4;:12;;32850:4;32842:12;32838:688;;32893:27;32902:5;32896:11;;:2;:11;;;;32914:5;32909:2;:10;32893:2;:27::i;32838:688::-;33042:4;:12;;33050:4;33042:12;33038:488;;-1:-1:-1;;;;33093:17:106;;;33105:4;33100:9;;33093:17;33086:24;;33038:488;33233:4;:12;;33241:4;33233:12;33229:297;;-1:-1:-1;;;;33284:17:106;;;33296:4;33291:9;;33284:17;33277:24;;33229:297;33427:4;:12;;33435:4;33427:12;33423:103;;33478:21;33487:2;33481:8;;:2;:8;;;;33496:2;33491;:7;33478:2;:21::i;33423:103::-;33708:4;:12;;33716:4;33708:12;:28;;;;33724:4;:12;;33732:4;33724:12;33708:28;33704:1151;;;33776:2;33771;:7;33764:14;;;;;;;33704:1151;33866:4;:12;;33874:4;33866:12;:28;;;;33882:4;:12;;33890:4;33882:12;33866:28;33862:993;;;33934:2;33929;:7;33922:14;;;;;;;33862:993;34016:4;:12;;34024:4;34016:12;34012:843;;34068:2;34063;:7;34056:14;;;;;;;34012:843;34149:4;:12;;34157:4;34149:12;34145:710;;34202:2;34197;:7;34189:16;;;;;;;34145:710;34285:4;:12;;34293:4;34285:12;34281:574;;34338:2;34333;:7;34325:16;;;;;;;34281:574;34421:4;:12;;34429:4;34421:12;34417:438;;-1:-1:-1;;;;34470:7:106;;;34468:10;34461:17;;34417:438;34581:4;:12;;34589:4;34581:12;34577:278;;34646:2;34628:21;;34634:2;34628:21;;;:29;;34656:1;34628:29;;;34652:1;34628:29;34621:36;;;;;;;;;34577:278;34770:4;:12;;34778:4;34770:12;34766:89;;34822:2;34817:7;;:2;:7;;;:15;;34831:1;34817:15;;34766:89;32152:2721;31411:6876;;32135:3554;34944:6;:13;;34954:3;34944:13;34940:749;;34994:2;34988;:8;;;;34981:15;;;;;;34940:749;35069:6;:14;;35079:4;35069:14;35065:624;;35138:4;:9;;35146:1;35138:9;35134:100;;-1:-1:-1;;;35189:21:106;;;35175:36;;35134:100;35286:4;:12;;35294:4;35286:12;:28;;;;35302:4;:12;;35310:4;35302:12;35286:28;35282:389;;;35346:4;:12;;35354:4;35346:12;35342:83;;35395:3;;;35342:83;35450:8;35488:127;35500:10;35495:15;;:20;35488:127;;35580:8;35547:3;35580:8;;;;;35547:3;35488:127;;;35647:1;-1:-1:-1;35640:8:106;;-1:-1:-1;;35640:8:106;35282:389;31411:6876;;;35722:4;35713:6;:13;;;35709:2578;;;35772:6;:14;;35782:4;35772:14;35768:1208;;35817:42;35835:2;35840:1;35835:6;35845:1;35834:12;35829:2;:17;35821:26;;:3;:26;;;;35851:4;35820:35;35857:1;35817:2;:42::i;:::-;35810:49;;;;;;35768:1208;35926:6;:14;;35936:4;35926:14;35922:1054;;35971:45;35989:2;35994:1;35989:6;35999:1;35988:12;35983:2;:17;35975:26;;:3;:26;;;;36005:6;35974:37;36013:2;35971;:45::i;35922:1054::-;36084:6;:14;;36094:4;36084:14;36080:896;;-1:-1:-1;;;36135:21:106;36154:1;36149;36144:6;;36143:12;36135:21;;36192:36;;;36263:5;36258:10;;36135:21;;;;;36257:18;36250:25;;36080:896;36342:6;:14;;36352:4;36342:14;36338:638;;36387:3;36380:10;;;;;;36338:638;36458:6;:14;;36468:4;36458:14;36454:522;;36518:2;36523:1;36518:6;36528:1;36517:12;36512:2;:17;36504:26;;:3;:26;;;;36534:4;36503:35;36496:42;;;;;;36454:522;36606:6;:14;;36616:4;36606:14;36602:374;;36666:2;36671:1;36666:6;36676:1;36665:12;36660:2;:17;36652:26;;:3;:26;;;;36682:6;36651:37;36644:44;;;;;;36602:374;36756:6;:14;;36766:4;36756:14;36752:224;;-1:-1:-1;;;36807:26:106;36831:1;36826;36821:6;;36820:12;36815:2;:17;36807:26;;36869:41;;;36945:5;36940:10;;36807:26;;;;;36939:18;36932:25;;35709:2578;37030:6;:14;;37040:4;37030:14;37026:1261;;-1:-1:-1;;;37083:4:106;37077:34;37109:1;37104;37099:6;;37098:12;37093:2;:17;37077:34;;37163:27;;;37143:48;;;37217:10;;37078:9;;;37077:34;;37216:18;37209:25;;37026:1261;37289:6;:14;;37299:4;37289:14;37285:1002;;-1:-1:-1;;;37342:6:106;37336:36;37370:1;37365;37360:6;;37359:12;37354:2;:17;37336:36;;37424:29;;;37404:50;;;37480:10;;37337:11;;;37336:36;;37479:18;37472:25;;37285:1002;37553:6;:14;;37563:4;37553:14;37549:738;;-1:-1:-1;;;37600:20:106;37618:1;37613;37608:6;;37607:12;37600:20;;37652:36;;;37720:5;37714:11;;37600:20;;;;;37713:19;37706:26;;37549:738;37787:6;:14;;37797:4;37787:14;37783:504;;37828:2;37821:9;;;;;;37783:504;37886:6;:14;;37896:4;37886:14;37882:405;;-1:-1:-1;;;37933:25:106;37956:1;37951;37946:6;;37945:12;37940:2;:17;37933:25;;37990:41;;;38063:5;38057:11;;37933:25;;;;;38056:19;38049:26;;37882:405;38130:6;:14;;38140:4;38130:14;38126:161;;38171:3;38164:10;;;;;;38126:161;38229:6;:14;;38239:4;38229:14;38225:62;;38270:2;38263:9;;;;;;38225:62;38301:29;;;;;2810:2:257;38301:29:106;;;2792:21:257;2849:2;2829:18;;;2822:30;2888:21;2868:18;;;2861:49;2927:18;;38301:29:106;2608:343:257;18965:782:106;19051:12;19138:18;;:::i;:::-;-1:-1:-1;19206:4:106;19313:2;19301:14;;;;19293:41;;;;;;;3158:2:257;19293:41:106;;;3140:21:257;3197:2;3177:18;;;3170:30;3236:16;3216:18;;;3209:44;3270:18;;19293:41:106;2956:338:257;19293:41:106;19430:14;;;;;;;:30;;;19448:12;19430:30;19426:102;;;19509:4;19480:5;:15;;;19496:9;19480:26;;;;;;;;;:::i;:::-;:33;;;;:26;;;;;;:33;19426:102;19583:12;;;;;19572:23;;;;:8;;;:23;19639:1;19624:16;;;19609:31;;;19717:13;:11;:13::i;4608:7728::-;4651:12;4737:18;;:::i;:::-;-1:-1:-1;4915:15:106;;:18;;;;4805:4;5075:18;;;;5119;;;;5163;;;;;4805:4;;4895:17;;;;5075:18;5119;5253;;;5267:4;5253:18;5249:6777;;5303:2;5332:4;5327:9;;:14;5323:144;;5443:4;5438:9;;5430:4;:18;5424:24;5323:144;5488:2;:7;;5494:1;5488:7;5484:161;;5524:10;;;;;5556:16;;;;;;;;5524:10;-1:-1:-1;5484:161:106;;;5624:2;5619:7;;5484:161;5273:386;5249:6777;;;5761:10;:18;;5775:4;5761:18;5757:6269;;1745:10;5799:14;;5757:6269;;;5897:10;:18;;5911:4;5897:18;5893:6133;;5940:1;5935:6;;5893:6133;;;6065:10;:18;;6079:4;6065:18;6061:5965;;6118:4;6103:12;;;:19;6140:26;;;:14;;;:26;6191:13;:11;:13::i;:::-;6184:20;;;;;;;;;4608:7728;:::o;6061:5965::-;6330:10;:18;;6344:4;6330:18;6326:5700;;6481:14;;;6477:2708;6326:5700;6477:2708;6651:22;;;;;6647:2538;;6776:10;6789:27;6797:2;6802:10;6797:15;6814:1;6789:7;:27::i;:::-;6900:17;;;;6776:40;;-1:-1:-1;6900:17:106;6878:19;7050:14;7069:1;7044:26;7040:131;;7112:36;7136:11;1277:21:107;1426:15;;;1467:8;1461:4;1454:22;1595:4;1582:18;;1602:19;1578:44;1624:11;1575:61;;1222:430;7112:36:106;7098:50;;7040:131;7193:11;7224:6;;7257:20;;;;;7224:54;;;;;;;;3472:25:257;;;3545:10;3533:23;;;3513:18;;;3506:51;7193:11:106;;7224:6;;;:19;;3445:18:257;;7224:54:106;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7192:86;;;;7505:1;7501:2;7497:10;7602:9;7599:1;7595:17;7684:6;7677:5;7674:17;7671:40;;;7704:5;7694:15;;7671:40;;7787:6;7783:2;7780:14;7777:34;;;7807:2;7797:12;;7777:34;7913:3;7908:1;7900:6;7896:14;7891:3;7887:24;7883:34;7876:41;;8013:3;8009:1;7997:9;7988:6;7985:1;7981:14;7977:30;7973:38;7969:48;7962:55;;8168:1;8164;8160;8148:9;8145:1;8141:17;8137:25;8133:33;8129:41;8295:1;8291;8287;8278:6;8266:9;8263:1;8259:17;8255:30;8251:38;8247:46;8243:54;8225:72;;8426:10;8422:15;8416:4;8412:26;8404:34;;8542:3;8534:4;8530:9;8525:3;8521:19;8518:28;8511:35;;;;8688:33;8697:2;8702:10;8697:15;8714:1;8717:3;8688:8;:33::i;:::-;8743:20;;;:38;;;;;;;;;-1:-1:-1;6647:2538:106;;-1:-1:-1;;;6647:2538:106;;8900:18;;;;;8896:289;;9070:2;9065:7;;6326:5700;;8896:289;9124:10;9119:15;;2053:3;9156:10;;8896:289;6326:5700;;;9314:10;:18;;9328:4;9314:18;9310:2716;;9468:15;;;1824:1;9468:15;;:34;;-1:-1:-1;9487:15:106;;;1859:1;9487:15;9468:34;:57;;;-1:-1:-1;9506:19:106;;;1936:1;9506:19;9468:57;9464:1593;;;9554:2;9549:7;;9310:2716;;9464:1593;9680:23;;;;;9676:1381;;9727:10;9740:27;9748:2;9753:10;9748:15;9765:1;9740:7;:27::i;:::-;9843:17;;;;9727:40;;-1:-1:-1;10086:1:106;10078:10;;10180:1;10176:17;10255:13;;;10252:32;;;10277:5;10271:11;;10252:32;10563:14;;;10369:1;10559:22;;;10555:32;;;;10452:26;10476:1;10361:10;;;10456:18;;;10452:26;10551:43;10357:20;;10659:12;10787:17;;;:23;10855:1;10832:20;;;:24;10365:2;-1:-1:-1;10365:2:106;6326:5700;;9310:2716;11259:10;:18;;11273:4;11259:18;11255:771;;11369:2;:7;;11375:1;11369:7;11365:647;;11462:14;;;;;:40;;-1:-1:-1;11480:22:106;;;1978:1;11480:22;11462:40;:62;;;-1:-1:-1;11506:18:106;;;1897:1;11506:18;11462:62;11458:404;;;11557:1;11552:6;;11365:647;;11458:404;11603:15;;;1824:1;11603:15;;:34;;-1:-1:-1;11622:15:106;;;1859:1;11622:15;11603:34;:61;;;-1:-1:-1;11641:23:106;;;2021:1;11641:23;11603:61;:84;;;-1:-1:-1;11668:19:106;;;1936:1;11668:19;11603:84;11599:263;;;11720:1;11715:6;;6326:5700;;11365:647;11913:10;11908:15;;2087:4;11945:11;;11365:647;12101:15;;;;;:23;;;;:18;;;;:23;;;;12138:15;;:23;;;:18;;;;:23;-1:-1:-1;12227:12:106;;;;12216:23;;;:8;;;:23;12283:1;12268:16;12253:31;;;;;12306:13;:11;:13::i;15089:2480::-;15183:12;15269:18;;:::i;:::-;-1:-1:-1;15337:4:106;15369:10;15477:13;;;15486:4;15477:13;15473:1705;;-1:-1:-1;15516:8:106;;;;15473:1705;;;15635:5;:13;;15644:4;15635:13;15631:1547;;15668:14;;;:8;;;:14;15631:1547;;;15798:5;:13;;15807:4;15798:13;15794:1384;;-1:-1:-1;15837:8:106;;;;15794:1384;;;15956:5;:13;;15965:4;15956:13;15952:1226;;15989:14;;;:8;;;:14;15952:1226;;;16130:5;:13;;16139:4;16130:13;16126:1052;;16257:9;16203:17;16183;;;16203;;;;16183:37;16264:2;16257:9;;;;;16239:8;;;:28;16285:22;:8;;;:22;16126:1052;;;16444:5;:13;;16453:4;16444:13;16440:738;;16511:11;16497;;;16511;;;16497:25;16566:2;16559:9;;;;;16541:8;;;:28;16587:22;:8;;;:22;16440:738;;;16768:5;:13;;16777:4;16768:13;16764:414;;16838:3;16819:23;;16825:3;16819:23;;;;;;;:::i;:::-;;16801:42;;:8;;;:42;16879:23;;;;;;;;;;;;;:::i;:::-;;16861:42;;:8;;;:42;16764:414;;;17072:5;:13;;17081:4;17072:13;17068:110;;17122:3;17116:9;;:3;:9;;;;;;;:::i;:::-;;17105:20;;;;:8;;;:20;17154:9;;;;;;;;;;;:::i;:::-;;17143:20;;:8;;;:20;17068:110;17271:14;;;;17267:85;;17334:3;17305:5;:15;;;17321:9;17305:26;;;;;;;;;:::i;:::-;:32;;;;:26;;;;;;:32;17267:85;17406:12;;;;;17395:23;;;;:8;;;:23;17462:1;17447:16;;;17432:31;;;17539:13;:11;:13::i;:::-;17532:20;15089:2480;-1:-1:-1;;;;;;;15089:2480:106:o;22918:1654::-;23094:14;23111:24;23123:11;23111;:24::i;:::-;23094:41;;23243:1;23236:5;23232:13;23229:33;;;23258:1;23255;23248:12;23229:33;23397:2;23591:15;;;23416:2;23405:14;;23393:10;23389:31;23386:1;23382:39;23547:16;;;23332:20;;23532:10;23521:22;;;23517:27;23507:38;23504:60;24033:5;24030:1;24026:13;24104:1;24089:343;24114:2;24111:1;24108:9;24089:343;;;24237:2;24225:15;;;24174:20;24272:12;;;24286:1;24268:20;24309:42;;;;24377:1;24372:42;;;;24261:153;;24309:42;21396:1;21389:12;;;21429:2;21422:13;;;21474:2;21461:16;;24318:31;;24309:42;;24372;21396:1;21389:12;;;21429:2;21422:13;;;21474:2;21461:16;;24381:31;;24261:153;-1:-1:-1;;24132:1:106;24125:9;24089:343;;;-1:-1:-1;;24531:4:106;24524:18;-1:-1:-1;;;;22918:1654:106:o;19951:586::-;20273:20;;;20297:7;20273:32;20266:3;:40;;;20379:14;;20434:17;;20428:24;;;20420:72;;;;;;;4209:2:257;20420:72:106;;;4191:21:257;4248:2;4228:18;;;4221:30;4287:34;4267:18;;;4260:62;4358:5;4338:18;;;4331:33;4381:19;;20420:72:106;4007:399:257;20420:72:106;20506:14;19951:586;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;467:347:257:-;518:8;528:6;582:3;575:4;567:6;563:17;559:27;549:55;;600:1;597;590:12;549:55;-1:-1:-1;623:20:257;;666:18;655:30;;652:50;;;698:1;695;688:12;652:50;735:4;727:6;723:17;711:29;;787:3;780:4;771:6;763;759:19;755:30;752:39;749:59;;;804:1;801;794:12;749:59;467:347;;;;;:::o;819:717::-;909:6;917;925;933;986:2;974:9;965:7;961:23;957:32;954:52;;;1002:1;999;992:12;954:52;1042:9;1029:23;1071:18;1112:2;1104:6;1101:14;1098:34;;;1128:1;1125;1118:12;1098:34;1167:58;1217:7;1208:6;1197:9;1193:22;1167:58;:::i;:::-;1244:8;;-1:-1:-1;1141:84:257;-1:-1:-1;1332:2:257;1317:18;;1304:32;;-1:-1:-1;1348:16:257;;;1345:36;;;1377:1;1374;1367:12;1345:36;;1416:60;1468:7;1457:8;1446:9;1442:24;1416:60;:::i;:::-;819:717;;;;-1:-1:-1;1495:8:257;-1:-1:-1;;;;819:717:257:o;1723:184::-;1775:77;1772:1;1765:88;1872:4;1869:1;1862:15;1896:4;1893:1;1886:15;3568:245;3647:6;3655;3708:2;3696:9;3687:7;3683:23;3679:32;3676:52;;;3724:1;3721;3714:12;3676:52;-1:-1:-1;;3747:16:257;;3803:2;3788:18;;;3782:25;3747:16;;3782:25;;-1:-1:-1;3568:245:257:o;3818:184::-;3870:77;3867:1;3860:88;3967:4;3964:1;3957:15;3991:4;3988:1;3981:15"
var MIPSDeployedSourceMap = "1131:37447:106:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1710:45;;1745:10;1710:45;;;;;188:10:257;176:23;;;158:42;;146:2;131:18;1710:45:106;;;;;;;;2448:99;;;412:42:257;2534:6:106;400:55:257;382:74;;370:2;355:18;2448:99:106;211:251:257;24925:6377:106;;;;;;:::i;:::-;;:::i;:::-;;;1687:25:257;;;1675:2;1660:18;24925:6377:106;1541:177:257;24925:6377:106;25003:7;25046:18;;:::i;:::-;25193:4;25186:5;25183:15;25173:134;;25287:1;25284;25277:12;25173:134;25343:4;25337:11;25350;25334:28;25324:137;;25441:1;25438;25431:12;25324:137;25509:3;25491:16;25488:25;25478:150;;25608:1;25605;25598:12;25478:150;25672:3;25658:12;25655:21;25645:145;;25770:1;25767;25760:12;25645:145;26050:24;;26394:4;26096:20;26452:2;26154:21;;26050:24;26212:18;26096:20;26154:21;;;26050:24;26027:21;26023:52;;;26212:18;26096:20;;;26154:21;;;26050:24;26023:52;;26096:20;;26154:21;;;26050:24;26023:52;;26212:18;26096:20;26154:21;;;26050:24;26023:52;;26212:18;26096:20;26154:21;;;26050:24;26023:52;;26212:18;26096:20;26154:21;;;26050:24;26023:52;;;26212:18;26096:20;26154:21;;;26050:24;26027:21;26023:52;;;26212:18;26096:20;26154:21;;;26050:24;26023:52;;26212:18;26096:20;26154:21;;;26050:24;26023:52;;26212:18;26096:20;27070:10;26212:18;27060:21;;;26154;;;;27168:1;27153:77;27178:2;27175:1;27172:9;27153:77;;;26050:24;;26027:21;26023:52;26096:20;;27226:1;26154:21;;;;26038:2;26212:18;;;;27196:1;27189:9;27153:77;;;27157:14;;;27308:5;:12;;;27304:71;;;27347:13;:11;:13::i;:::-;27340:20;;;;;27304:71;27389:10;;;:15;;27403:1;27389:15;;;;;27474:8;;;;-1:-1:-1;;27466:20:106;;-1:-1:-1;27466:7:106;:20::i;:::-;27452:34;-1:-1:-1;27516:10:106;27524:2;27516:10;;;;27593:1;27583:11;;;:26;;;27598:6;:11;;27608:1;27598:11;27583:26;27579:348;;;27848:64;27859:6;:11;;27869:1;27859:11;:20;;27877:2;27859:20;;;27873:1;27859:20;27848:64;;27910:1;27881:25;27884:4;27891:10;27884:17;27903:2;27881;:25::i;:::-;:30;;;;27848:10;:64::i;:::-;27841:71;;;;;;;27579:348;28176:15;;;;27971:9;;;;28108:4;28102:2;28094:10;;;28093:19;;;28176:15;28201:2;28193:10;;;28192:19;28176:36;;;;;;;:::i;:::-;;;;;;-1:-1:-1;28241:5:106;28265:11;;;;;:29;;;28280:6;:14;;28290:4;28280:14;28265:29;28261:832;;;28357:5;:15;;;28373:5;28357:22;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;28420:4:106;28414:2;28406:10;;;28405:19;28261:832;;;28458:4;28449:6;:13;;;28445:648;;;28579:6;:13;;28589:3;28579:13;:30;;;;28596:6;:13;;28606:3;28596:13;28579:30;:47;;;;28613:6;:13;;28623:3;28613:13;28579:47;28575:253;;;28689:4;28696:6;28689:13;28684:18;;28445:648;;28575:253;28788:21;28791:4;28798:6;28791:13;28806:2;28788;:21::i;:::-;28783:26;;28445:648;;;28862:4;28852:6;:14;;;;:32;;;;28870:6;:14;;28880:4;28870:14;28852:32;:50;;;;28888:6;:14;;28898:4;28888:14;28852:50;28848:245;;;28972:5;:15;;;28988:5;28972:22;;;;;;;;;:::i;:::-;;;;;28967:27;;29073:5;29065:13;;28848:245;29122:1;29112:6;:11;;;;:25;;;;;29136:1;29127:6;:10;;;29112:25;29111:42;;;;29142:6;:11;;29152:1;29142:11;29111:42;29107:125;;;29180:37;29193:6;29201:4;29207:5;29214:2;29180:12;:37::i;:::-;29173:44;;;;;;;;;;;29107:125;29265:13;29246:16;29417:4;29407:14;;;;29403:446;;29486:21;29489:4;29496:6;29489:13;29504:2;29486;:21::i;:::-;29480:27;;;;29544:10;29539:15;;29578:16;29539:15;29592:1;29578:7;:16::i;:::-;29572:22;;29626:4;29616:6;:14;;;;:32;;;;;29634:6;:14;;29644:4;29634:14;;29616:32;29612:223;;;29713:4;29701:16;;29815:1;29807:9;;29612:223;29423:426;29403:446;29882:10;29895:26;29903:4;29909:2;29913;29917:3;29895:7;:26::i;:::-;29924:10;29895:39;;;;-1:-1:-1;30020:4:106;30013:11;;;30052;;;:24;;;;;30075:1;30067:4;:9;;;;30052:24;:39;;;;;30087:4;30080;:11;;;30052:39;30048:847;;;30115:4;:9;;30123:1;30115:9;:22;;;;30128:4;:9;;30136:1;30128:9;30115:22;30111:144;;;30199:37;30210:4;:9;;30218:1;30210:9;:21;;30226:5;30210:21;;;30222:1;30210:21;30233:2;30199:10;:37::i;:::-;30192:44;;;;;;;;;;;;;;;30111:144;30277:4;:11;;30285:3;30277:11;30273:121;;30347:28;30356:5;30363:2;30367:7;;;;30347:8;:28::i;30273:121::-;30415:4;:11;;30423:3;30415:11;30411:121;;30485:28;30494:5;30501:2;30505:7;;;;;30485:8;:28::i;30411:121::-;30602:4;:11;;30610:3;30602:11;30598:80;;30644:15;:13;:15::i;30598:80::-;30781:4;30773;:12;;;;:27;;;;;30796:4;30789;:11;;;30773:27;30769:112;;;30831:31;30842:4;30848:2;30852;30856:5;30831:10;:31::i;30769:112::-;30955:6;:14;;30965:4;30955:14;:28;;;;-1:-1:-1;30973:10:106;;;;;30955:28;30951:93;;;31028:1;31003:5;:15;;;31019:5;31003:22;;;;;;;;;:::i;:::-;:26;;;;:22;;;;;;:26;30951:93;31090:9;:26;;31103:13;31090:26;31086:92;;31136:27;31145:9;31156:1;31159:3;31136:8;:27::i;:::-;31259:26;31268:5;31275:3;31280:4;31259:8;:26::i;:::-;31252:33;;;;;;;;;;;;;24925:6377;;;;;;;:::o;3087:1709::-;3634:4;3628:11;;3550:4;3353:31;3342:43;;3413:13;3353:31;3752:2;3452:13;;3342:43;3359:24;3353:31;3452:13;;;3342:43;;;;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3128:12;;4337:13;;3452;;;3128:12;4417:84;4442:2;4439:1;4436:9;4417:84;;;3369:13;3359:24;;3353:31;3342:43;;3373:2;3413:13;;;;4497:1;3452:13;;;;4460:1;4453:9;4417:84;;;4421:14;4564:1;4560:2;4553:13;4659:5;4655:2;4651:14;4644:5;4639:27;4765:14;;;4748:32;;;3087:1709;-1:-1:-1;;3087:1709:106:o;20980:1831::-;21053:11;21164:14;21181:24;21193:11;21181;:24::i;:::-;21164:41;;21313:1;21306:5;21302:13;21299:33;;;21328:1;21325;21318:12;21299:33;21461:2;21449:15;;;21402:20;21891:5;21888:1;21884:13;21926:4;21962:1;21947:343;21972:2;21969:1;21966:9;21947:343;;;22095:2;22083:15;;;22032:20;22130:12;;;22144:1;22126:20;22167:42;;;;22235:1;22230:42;;;;22119:153;;22167:42;21625:1;21618:12;;;21658:2;21651:13;;;21703:2;21690:16;;22176:31;;22167:42;;22230;21625:1;21618:12;;;21658:2;21651:13;;;21703:2;21690:16;;22239:31;;22119:153;-1:-1:-1;;21990:1:106;21983:9;21947:343;;;21951:14;22400:4;22394:11;22379:26;;22486:7;22480:4;22477:17;22467:124;;22528:10;22525:1;22518:21;22570:2;22567:1;22560:13;22467:124;-1:-1:-1;;22718:2:106;22707:14;;;;22695:10;22691:31;22688:1;22684:39;22752:16;;;;22770:10;22748:33;;20980:1831;-1:-1:-1;;;20980:1831:106:o;2645:334::-;2706:6;2765:18;;;;2774:8;;;;2765:18;;;;;;2764:25;;;;;2781:1;2828:2;:9;;;2822:16;;;;;2821:22;;2820:32;;;;;;;2882:9;;2881:15;2764:25;2939:21;;2959:1;2939:21;;;2950:6;2939:21;2924:11;;;;;:37;;-1:-1:-1;;;2645:334:106;;;;:::o;18090:823::-;18159:12;18246:18;;:::i;:::-;18314:4;18305:13;;18366:5;:8;;;18377:1;18366:12;18350:28;;:5;:12;;;:28;;;18346:95;;18398:28;;;;;2114:2:257;18398:28:106;;;2096:21:257;2153:2;2133:18;;;2126:30;2192:20;2172:18;;;2165:48;2230:18;;18398:28:106;;;;;;;;18346:95;18530:8;;;;;18563:12;;;;;18552:23;;;;;;;18589:20;;;;;18530:8;18721:13;;;18717:90;;18782:6;18791:1;18782:10;18754:5;:15;;;18770:8;18754:25;;;;;;;;;:::i;:::-;:38;;;;:25;;;;;;:38;18717:90;18883:13;:11;:13::i;:::-;18876:20;18090:823;-1:-1:-1;;;;;18090:823:106:o;12951:2026::-;13048:12;13134:18;;:::i;:::-;13202:4;13193:13;;13234:17;13294:5;:8;;;13305:1;13294:12;13278:28;;:5;:12;;;:28;;;13274:97;;13326:30;;;;;2461:2:257;13326:30:106;;;2443:21:257;2500:2;2480:18;;;2473:30;2539:22;2519:18;;;2512:50;2579:18;;13326:30:106;2259:344:257;13274:97:106;13441:7;:12;;13452:1;13441:12;:28;;;;13457:7;:12;;13468:1;13457:12;13441:28;13437:947;;;13489:9;13501:5;:15;;;13517:6;13501:23;;;;;;;;;:::i;:::-;;;;;13489:35;;13565:2;13558:9;;:3;:9;;;:25;;;;;13571:7;:12;;13582:1;13571:12;13558:25;13557:58;;;;13596:2;13589:9;;:3;:9;;;;:25;;;;;13602:7;:12;;13613:1;13602:12;13589:25;13542:73;;13471:159;13437:947;;;13727:7;:12;;13738:1;13727:12;13723:661;;13788:1;13780:3;13774:15;;;;13759:30;;13723:661;;;13892:7;:12;;13903:1;13892:12;13888:496;;13952:1;13945:3;13939:14;;;13924:29;;13888:496;;;14073:7;:12;;14084:1;14073:12;14069:315;;14161:4;14155:2;14146:11;;;14145:20;14131:10;14188:8;;;14184:84;;14248:1;14241:3;14235:14;;;14220:29;;14184:84;14289:3;:8;;14296:1;14289:8;14285:85;;14350:1;14342:3;14336:15;;;;14321:30;;14285:85;14087:297;14069:315;14460:8;;;;;14538:12;;;;14527:23;;;;;14694:178;;;;14785:1;14759:22;14762:5;14770:6;14762:14;14778:2;14759;:22::i;:::-;:27;;;;;;;14745:42;;14754:1;14745:42;14730:57;:12;;;:57;14694:178;;;14841:12;;;;;14856:1;14841:16;14826:31;;;;14694:178;14947:13;:11;:13::i;:::-;14940:20;12951:2026;-1:-1:-1;;;;;;;;12951:2026:106:o;31348:7228::-;31435:6;31493:10;31501:2;31493:10;;;;;;31541:11;;31653:4;31644:13;;31640:6876;;;31784:1;31774:6;:11;;;;:27;;;;;31798:3;31789:6;:12;;;31774:27;31770:537;;;31829:6;:11;;31839:1;31829:11;31825:423;;-1:-1:-1;31849:4:106;31825:423;;;31893:6;:11;;31903:1;31893:11;31889:359;;-1:-1:-1;31913:4:106;31889:359;;;31958:6;:13;;31968:3;31958:13;31954:294;;-1:-1:-1;31980:4:106;31954:294;;;32024:6;:13;;32034:3;32024:13;32020:228;;-1:-1:-1;32046:4:106;32020:228;;;32091:6;:13;;32101:3;32091:13;32087:161;;-1:-1:-1;32113:4:106;32087:161;;;32157:6;:13;;32167:3;32157:13;32153:95;;-1:-1:-1;32179:4:106;32153:95;;;32222:6;:13;;32232:3;32222:13;32218:30;;-1:-1:-1;32244:4:106;32218:30;32287:1;32278:10;;31770:537;32368:6;:11;;32378:1;32368:11;32364:3554;;32432:4;32427:1;32419:9;;;32418:18;32469:4;32419:9;32462:11;;;32458:1319;;;32561:4;32553;:12;;;32549:1206;;32604:2;32597:9;;;;;;;32549:1206;32718:4;:12;;32726:4;32718:12;32714:1041;;32769:11;;;;;;;;-1:-1:-1;32762:18:106;;-1:-1:-1;;32762:18:106;32714:1041;32893:4;:12;;32901:4;32893:12;32889:866;;32944:11;;;;;;;;-1:-1:-1;32937:18:106;;-1:-1:-1;;32937:18:106;32889:866;33071:4;:12;;33079:4;33071:12;33067:688;;33122:27;33131:5;33125:11;;:2;:11;;;;33143:5;33138:2;:10;33122:2;:27::i;33067:688::-;33271:4;:12;;33279:4;33271:12;33267:488;;-1:-1:-1;;;;33322:17:106;;;33334:4;33329:9;;33322:17;33315:24;;33267:488;33462:4;:12;;33470:4;33462:12;33458:297;;-1:-1:-1;;;;33513:17:106;;;33525:4;33520:9;;33513:17;33506:24;;33458:297;33656:4;:12;;33664:4;33656:12;33652:103;;33707:21;33716:2;33710:8;;:2;:8;;;;33725:2;33720;:7;33707:2;:21::i;33652:103::-;33937:4;:12;;33945:4;33937:12;:28;;;;33953:4;:12;;33961:4;33953:12;33937:28;33933:1151;;;34005:2;34000;:7;33993:14;;;;;;;33933:1151;34095:4;:12;;34103:4;34095:12;:28;;;;34111:4;:12;;34119:4;34111:12;34095:28;34091:993;;;34163:2;34158;:7;34151:14;;;;;;;34091:993;34245:4;:12;;34253:4;34245:12;34241:843;;34297:2;34292;:7;34285:14;;;;;;;34241:843;34378:4;:12;;34386:4;34378:12;34374:710;;34431:2;34426;:7;34418:16;;;;;;;34374:710;34514:4;:12;;34522:4;34514:12;34510:574;;34567:2;34562;:7;34554:16;;;;;;;34510:574;34650:4;:12;;34658:4;34650:12;34646:438;;-1:-1:-1;;;;34699:7:106;;;34697:10;34690:17;;34646:438;34810:4;:12;;34818:4;34810:12;34806:278;;34875:2;34857:21;;34863:2;34857:21;;;:29;;34885:1;34857:29;;;34881:1;34857:29;34850:36;;;;;;;;;34806:278;34999:4;:12;;35007:4;34999:12;34995:89;;35051:2;35046:7;;:2;:7;;;:15;;35060:1;35046:15;;34995:89;32381:2721;31640:6876;;32364:3554;35173:6;:13;;35183:3;35173:13;35169:749;;35223:2;35217;:8;;;;35210:15;;;;;;35169:749;35298:6;:14;;35308:4;35298:14;35294:624;;35367:4;:9;;35375:1;35367:9;35363:100;;-1:-1:-1;;;35418:21:106;;;35404:36;;35363:100;35515:4;:12;;35523:4;35515:12;:28;;;;35531:4;:12;;35539:4;35531:12;35515:28;35511:389;;;35575:4;:12;;35583:4;35575:12;35571:83;;35624:3;;;35571:83;35679:8;35717:127;35729:10;35724:15;;:20;35717:127;;35809:8;35776:3;35809:8;;;;;35776:3;35717:127;;;35876:1;-1:-1:-1;35869:8:106;;-1:-1:-1;;35869:8:106;35511:389;31640:6876;;;35951:4;35942:6;:13;;;35938:2578;;;36001:6;:14;;36011:4;36001:14;35997:1208;;36046:42;36064:2;36069:1;36064:6;36074:1;36063:12;36058:2;:17;36050:26;;:3;:26;;;;36080:4;36049:35;36086:1;36046:2;:42::i;:::-;36039:49;;;;;;35997:1208;36155:6;:14;;36165:4;36155:14;36151:1054;;36200:45;36218:2;36223:1;36218:6;36228:1;36217:12;36212:2;:17;36204:26;;:3;:26;;;;36234:6;36203:37;36242:2;36200;:45::i;36151:1054::-;36313:6;:14;;36323:4;36313:14;36309:896;;-1:-1:-1;;;36364:21:106;36383:1;36378;36373:6;;36372:12;36364:21;;36421:36;;;36492:5;36487:10;;36364:21;;;;;36486:18;36479:25;;36309:896;36571:6;:14;;36581:4;36571:14;36567:638;;36616:3;36609:10;;;;;;36567:638;36687:6;:14;;36697:4;36687:14;36683:522;;36747:2;36752:1;36747:6;36757:1;36746:12;36741:2;:17;36733:26;;:3;:26;;;;36763:4;36732:35;36725:42;;;;;;36683:522;36835:6;:14;;36845:4;36835:14;36831:374;;36895:2;36900:1;36895:6;36905:1;36894:12;36889:2;:17;36881:26;;:3;:26;;;;36911:6;36880:37;36873:44;;;;;;36831:374;36985:6;:14;;36995:4;36985:14;36981:224;;-1:-1:-1;;;37036:26:106;37060:1;37055;37050:6;;37049:12;37044:2;:17;37036:26;;37098:41;;;37174:5;37169:10;;37036:26;;;;;37168:18;37161:25;;35938:2578;37259:6;:14;;37269:4;37259:14;37255:1261;;-1:-1:-1;;;37312:4:106;37306:34;37338:1;37333;37328:6;;37327:12;37322:2;:17;37306:34;;37392:27;;;37372:48;;;37446:10;;37307:9;;;37306:34;;37445:18;37438:25;;37255:1261;37518:6;:14;;37528:4;37518:14;37514:1002;;-1:-1:-1;;;37571:6:106;37565:36;37599:1;37594;37589:6;;37588:12;37583:2;:17;37565:36;;37653:29;;;37633:50;;;37709:10;;37566:11;;;37565:36;;37708:18;37701:25;;37514:1002;37782:6;:14;;37792:4;37782:14;37778:738;;-1:-1:-1;;;37829:20:106;37847:1;37842;37837:6;;37836:12;37829:20;;37881:36;;;37949:5;37943:11;;37829:20;;;;;37942:19;37935:26;;37778:738;38016:6;:14;;38026:4;38016:14;38012:504;;38057:2;38050:9;;;;;;38012:504;38115:6;:14;;38125:4;38115:14;38111:405;;-1:-1:-1;;;38162:25:106;38185:1;38180;38175:6;;38174:12;38169:2;:17;38162:25;;38219:41;;;38292:5;38286:11;;38162:25;;;;;38285:19;38278:26;;38111:405;38359:6;:14;;38369:4;38359:14;38355:161;;38400:3;38393:10;;;;;;38355:161;38458:6;:14;;38468:4;38458:14;38454:62;;38499:2;38492:9;;;;;;38454:62;38530:29;;;;;2810:2:257;38530:29:106;;;2792:21:257;2849:2;2829:18;;;2822:30;2888:21;2868:18;;;2861:49;2927:18;;38530:29:106;2608:343:257;19194:782:106;19280:12;19367:18;;:::i;:::-;-1:-1:-1;19435:4:106;19542:2;19530:14;;;;19522:41;;;;;;;3158:2:257;19522:41:106;;;3140:21:257;3197:2;3177:18;;;3170:30;3236:16;3216:18;;;3209:44;3270:18;;19522:41:106;2956:338:257;19522:41:106;19659:14;;;;;;;:30;;;19677:12;19659:30;19655:102;;;19738:4;19709:5;:15;;;19725:9;19709:26;;;;;;;;;:::i;:::-;:33;;;;:26;;;;;;:33;19655:102;19812:12;;;;;19801:23;;;;:8;;;:23;19868:1;19853:16;;;19838:31;;;19946:13;:11;:13::i;4837:7728::-;4880:12;4966:18;;:::i;:::-;-1:-1:-1;5144:15:106;;:18;;;;5034:4;5304:18;;;;5348;;;;5392;;;;;5034:4;;5124:17;;;;5304:18;5348;5482;;;5496:4;5482:18;5478:6777;;5532:2;5561:4;5556:9;;:14;5552:144;;5672:4;5667:9;;5659:4;:18;5653:24;5552:144;5717:2;:7;;5723:1;5717:7;5713:161;;5753:10;;;;;5785:16;;;;;;;;5753:10;-1:-1:-1;5713:161:106;;;5853:2;5848:7;;5713:161;5502:386;5478:6777;;;5990:10;:18;;6004:4;5990:18;5986:6269;;1745:10;6028:14;;5986:6269;;;6126:10;:18;;6140:4;6126:18;6122:6133;;6169:1;6164:6;;6122:6133;;;6294:10;:18;;6308:4;6294:18;6290:5965;;6347:4;6332:12;;;:19;6369:26;;;:14;;;:26;6420:13;:11;:13::i;:::-;6413:20;;;;;;;;;4837:7728;:::o;6290:5965::-;6559:10;:18;;6573:4;6559:18;6555:5700;;6710:14;;;6706:2708;6555:5700;6706:2708;6880:22;;;;;6876:2538;;7005:10;7018:27;7026:2;7031:10;7026:15;7043:1;7018:7;:27::i;:::-;7129:17;;;;7005:40;;-1:-1:-1;7129:17:106;7107:19;7279:14;7298:1;7273:26;7269:131;;7341:36;7365:11;1277:21:107;1426:15;;;1467:8;1461:4;1454:22;1595:4;1582:18;;1602:19;1578:44;1624:11;1575:61;;1222:430;7341:36:106;7327:50;;7269:131;7486:20;;;;;7453:54;;;;;;;;3472:25:257;;;7453:54:106;3533:23:257;;;3513:18;;;3506:51;7422:11:106;;;;7453:19;:6;:19;;;;3445:18:257;;7453:54:106;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7421:86;;;;7734:1;7730:2;7726:10;7831:9;7828:1;7824:17;7913:6;7906:5;7903:17;7900:40;;;7933:5;7923:15;;7900:40;;8016:6;8012:2;8009:14;8006:34;;;8036:2;8026:12;;8006:34;8142:3;8137:1;8129:6;8125:14;8120:3;8116:24;8112:34;8105:41;;8242:3;8238:1;8226:9;8217:6;8214:1;8210:14;8206:30;8202:38;8198:48;8191:55;;8397:1;8393;8389;8377:9;8374:1;8370:17;8366:25;8362:33;8358:41;8524:1;8520;8516;8507:6;8495:9;8492:1;8488:17;8484:30;8480:38;8476:46;8472:54;8454:72;;8655:10;8651:15;8645:4;8641:26;8633:34;;8771:3;8763:4;8759:9;8754:3;8750:19;8747:28;8740:35;;;;8917:33;8926:2;8931:10;8926:15;8943:1;8946:3;8917:8;:33::i;:::-;8972:20;;;:38;;;;;;;;;-1:-1:-1;6876:2538:106;;-1:-1:-1;;;6876:2538:106;;9129:18;;;;;9125:289;;9299:2;9294:7;;6555:5700;;9125:289;9353:10;9348:15;;2053:3;9385:10;;9125:289;6555:5700;;;9543:10;:18;;9557:4;9543:18;9539:2716;;9697:15;;;1824:1;9697:15;;:34;;-1:-1:-1;9716:15:106;;;1859:1;9716:15;9697:34;:57;;;-1:-1:-1;9735:19:106;;;1936:1;9735:19;9697:57;9693:1593;;;9783:2;9778:7;;9539:2716;;9693:1593;9909:23;;;;;9905:1381;;9956:10;9969:27;9977:2;9982:10;9977:15;9994:1;9969:7;:27::i;:::-;10072:17;;;;9956:40;;-1:-1:-1;10315:1:106;10307:10;;10409:1;10405:17;10484:13;;;10481:32;;;10506:5;10500:11;;10481:32;10792:14;;;10598:1;10788:22;;;10784:32;;;;10681:26;10705:1;10590:10;;;10685:18;;;10681:26;10780:43;10586:20;;10888:12;11016:17;;;:23;11084:1;11061:20;;;:24;10594:2;-1:-1:-1;10594:2:106;6555:5700;;9539:2716;11488:10;:18;;11502:4;11488:18;11484:771;;11598:2;:7;;11604:1;11598:7;11594:647;;11691:14;;;;;:40;;-1:-1:-1;11709:22:106;;;1978:1;11709:22;11691:40;:62;;;-1:-1:-1;11735:18:106;;;1897:1;11735:18;11691:62;11687:404;;;11786:1;11781:6;;11594:647;;11687:404;11832:15;;;1824:1;11832:15;;:34;;-1:-1:-1;11851:15:106;;;1859:1;11851:15;11832:34;:61;;;-1:-1:-1;11870:23:106;;;2021:1;11870:23;11832:61;:84;;;-1:-1:-1;11897:19:106;;;1936:1;11897:19;11832:84;11828:263;;;11949:1;11944:6;;6555:5700;;11594:647;12142:10;12137:15;;2087:4;12174:11;;11594:647;12330:15;;;;;:23;;;;:18;;;;:23;;;;12367:15;;:23;;;:18;;;;:23;-1:-1:-1;12456:12:106;;;;12445:23;;;:8;;;:23;12512:1;12497:16;12482:31;;;;;12535:13;:11;:13::i;15318:2480::-;15412:12;15498:18;;:::i;:::-;-1:-1:-1;15566:4:106;15598:10;15706:13;;;15715:4;15706:13;15702:1705;;-1:-1:-1;15745:8:106;;;;15702:1705;;;15864:5;:13;;15873:4;15864:13;15860:1547;;15897:14;;;:8;;;:14;15860:1547;;;16027:5;:13;;16036:4;16027:13;16023:1384;;-1:-1:-1;16066:8:106;;;;16023:1384;;;16185:5;:13;;16194:4;16185:13;16181:1226;;16218:14;;;:8;;;:14;16181:1226;;;16359:5;:13;;16368:4;16359:13;16355:1052;;16486:9;16432:17;16412;;;16432;;;;16412:37;16493:2;16486:9;;;;;16468:8;;;:28;16514:22;:8;;;:22;16355:1052;;;16673:5;:13;;16682:4;16673:13;16669:738;;16740:11;16726;;;16740;;;16726:25;16795:2;16788:9;;;;;16770:8;;;:28;16816:22;:8;;;:22;16669:738;;;16997:5;:13;;17006:4;16997:13;16993:414;;17067:3;17048:23;;17054:3;17048:23;;;;;;;:::i;:::-;;17030:42;;:8;;;:42;17108:23;;;;;;;;;;;;;:::i;:::-;;17090:42;;:8;;;:42;16993:414;;;17301:5;:13;;17310:4;17301:13;17297:110;;17351:3;17345:9;;:3;:9;;;;;;;:::i;:::-;;17334:20;;;;:8;;;:20;17383:9;;;;;;;;;;;:::i;:::-;;17372:20;;:8;;;:20;17297:110;17500:14;;;;17496:85;;17563:3;17534:5;:15;;;17550:9;17534:26;;;;;;;;;:::i;:::-;:32;;;;:26;;;;;;:32;17496:85;17635:12;;;;;17624:23;;;;:8;;;:23;17691:1;17676:16;;;17661:31;;;17768:13;:11;:13::i;:::-;17761:20;15318:2480;-1:-1:-1;;;;;;;15318:2480:106:o;23147:1654::-;23323:14;23340:24;23352:11;23340;:24::i;:::-;23323:41;;23472:1;23465:5;23461:13;23458:33;;;23487:1;23484;23477:12;23458:33;23626:2;23820:15;;;23645:2;23634:14;;23622:10;23618:31;23615:1;23611:39;23776:16;;;23561:20;;23761:10;23750:22;;;23746:27;23736:38;23733:60;24262:5;24259:1;24255:13;24333:1;24318:343;24343:2;24340:1;24337:9;24318:343;;;24466:2;24454:15;;;24403:20;24501:12;;;24515:1;24497:20;24538:42;;;;24606:1;24601:42;;;;24490:153;;24538:42;21625:1;21618:12;;;21658:2;21651:13;;;21703:2;21690:16;;24547:31;;24538:42;;24601;21625:1;21618:12;;;21658:2;21651:13;;;21703:2;21690:16;;24610:31;;24490:153;-1:-1:-1;;24361:1:106;24354:9;24318:343;;;-1:-1:-1;;24760:4:106;24753:18;-1:-1:-1;;;;23147:1654:106:o;20180:586::-;20502:20;;;20526:7;20502:32;20495:3;:40;;;20608:14;;20663:17;;20657:24;;;20649:72;;;;;;;4209:2:257;20649:72:106;;;4191:21:257;4248:2;4228:18;;;4221:30;4287:34;4267:18;;;4260:62;4358:5;4338:18;;;4331:33;4381:19;;20649:72:106;4007:399:257;20649:72:106;20735:14;20180:586;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;467:347:257:-;518:8;528:6;582:3;575:4;567:6;563:17;559:27;549:55;;600:1;597;590:12;549:55;-1:-1:-1;623:20:257;;666:18;655:30;;652:50;;;698:1;695;688:12;652:50;735:4;727:6;723:17;711:29;;787:3;780:4;771:6;763;759:19;755:30;752:39;749:59;;;804:1;801;794:12;749:59;467:347;;;;;:::o;819:717::-;909:6;917;925;933;986:2;974:9;965:7;961:23;957:32;954:52;;;1002:1;999;992:12;954:52;1042:9;1029:23;1071:18;1112:2;1104:6;1101:14;1098:34;;;1128:1;1125;1118:12;1098:34;1167:58;1217:7;1208:6;1197:9;1193:22;1167:58;:::i;:::-;1244:8;;-1:-1:-1;1141:84:257;-1:-1:-1;1332:2:257;1317:18;;1304:32;;-1:-1:-1;1348:16:257;;;1345:36;;;1377:1;1374;1367:12;1345:36;;1416:60;1468:7;1457:8;1446:9;1442:24;1416:60;:::i;:::-;819:717;;;;-1:-1:-1;1495:8:257;-1:-1:-1;;;;819:717:257:o;1723:184::-;1775:77;1772:1;1765:88;1872:4;1869:1;1862:15;1896:4;1893:1;1886:15;3568:245;3647:6;3655;3708:2;3696:9;3687:7;3683:23;3679:32;3676:52;;;3724:1;3721;3714:12;3676:52;-1:-1:-1;;3747:16:257;;3803:2;3788:18;;;3782:25;3747:16;;3782:25;;-1:-1:-1;3568:245:257:o;3818:184::-;3870:77;3867:1;3860:88;3967:4;3964:1;3957:15;3991:4;3988:1;3981:15"
func init() {
if err := json.Unmarshal([]byte(MIPSStorageLayoutJSON), MIPSStorageLayout); err != nil {
......
......@@ -51,7 +51,7 @@ type SystemConfigAddresses struct {
// SystemConfigMetaData contains all meta data concerning the SystemConfig contract.
var SystemConfigMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"enumSystemConfig.UpdateType\",\"name\":\"updateType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ConfigUpdate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BATCH_INBOX_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L1_CROSS_DOMAIN_MESSENGER_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L1_ERC_721_BRIDGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L1_STANDARD_BRIDGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L2_OUTPUT_ORACLE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OPTIMISM_PORTAL_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"UNSAFE_BLOCK_SIGNER_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VERSION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchInbox\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batcherHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasLimit\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_overhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_scalar\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"_batcherHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"_gasLimit\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"_unsafeBlockSigner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxResourceLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"elasticityMultiplier\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"minimumBaseFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"systemTxMaxGas\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"maximumBaseFee\",\"type\":\"uint128\"}],\"internalType\":\"structResourceMetering.ResourceConfig\",\"name\":\"_config\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"_startBlock\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_batchInbox\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"l1CrossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1ERC721Bridge\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1StandardBridge\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2OutputOracle\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"optimismPortal\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"optimismMintableERC20Factory\",\"type\":\"address\"}],\"internalType\":\"structSystemConfig.Addresses\",\"name\":\"_addresses\",\"type\":\"tuple\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1CrossDomainMessenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC721Bridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2OutputOracle\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumGasLimit\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"optimismMintableERC20Factory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"optimismPortal\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"overhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resourceConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxResourceLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"elasticityMultiplier\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"minimumBaseFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"systemTxMaxGas\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"maximumBaseFee\",\"type\":\"uint128\"}],\"internalType\":\"structResourceMetering.ResourceConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"scalar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_batcherHash\",\"type\":\"bytes32\"}],\"name\":\"setBatcherHash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_overhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_scalar\",\"type\":\"uint256\"}],\"name\":\"setGasConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_gasLimit\",\"type\":\"uint64\"}],\"name\":\"setGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxResourceLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"elasticityMultiplier\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"minimumBaseFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"systemTxMaxGas\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"maximumBaseFee\",\"type\":\"uint128\"}],\"internalType\":\"structResourceMetering.ResourceConfig\",\"name\":\"_config\",\"type\":\"tuple\"}],\"name\":\"setResourceConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_unsafeBlockSigner\",\"type\":\"address\"}],\"name\":\"setUnsafeBlockSigner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"startBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unsafeBlockSigner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
Bin: "0x60e06040523480156200001157600080fd5b5060016080818152600460a090815260c0838152604080518083018252858152602080820187905260028284015260006060808401829052838801829052838701829052845195860185528186529185018190529284018390528301829052938201819052918101829052620000969361dead9383928392918391829081906200009c565b62000adb565b600054600290610100900460ff16158015620000bf575060005460ff8083169116105b620001285760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805461ffff191660ff83161761010017905562000146620003f1565b620001518b62000459565b60658a905560668990556067889055606880546001600160401b0319166001600160401b038916179055620001a4867f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0855565b620001d983620001d660017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc59862000a10565b55565b81516200020d90620001d660017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce958063762000a10565b60208201516200024490620001d660017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a862000a10565b60408201516200027b90620001d660017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad637762000a10565b6060820151620002b290620001d660017fe52a667f71ec761b9b381c7b76ca9b852adf7e8905da0e0ad49986a0a687181662000a10565b6080820151620002e990620001d660017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad62000a10565b60a08201516200032090620001d660017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d62000a10565b6200032b84620004d8565b620003368562000563565b62000340620008b8565b6001600160401b0316876001600160401b03161015620003a35760405162461bcd60e51b815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064016200011f565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050505050565b600054610100900460ff166200044d5760405162461bcd60e51b815260206004820152602b6024820152600080516020620029d683398151915260448201526a6e697469616c697a696e6760a81b60648201526084016200011f565b62000457620008e5565b565b620004636200094c565b6001600160a01b038116620004ca5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016200011f565b620004d581620009a8565b50565b606a5415620005505760405162461bcd60e51b815260206004820152603860248201527f53797374656d436f6e6669673a2063616e6e6f74206f7665727269646520616e60448201527f20616c72656164792073657420737461727420626c6f636b000000000000000060648201526084016200011f565b80156200055c57606a55565b43606a5550565b8060a001516001600160801b0316816060015163ffffffff161115620005f25760405162461bcd60e51b815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d61782062617365000000000000000000000060648201526084016200011f565b6001816040015160ff1611620006635760405162461bcd60e51b815260206004820152602f60248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201526e65206c6172676572207468616e203160881b60648201526084016200011f565b606854608082015182516001600160401b039092169162000685919062000a2a565b63ffffffff161115620006db5760405162461bcd60e51b815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064016200011f565b6000816020015160ff16116200074c5760405162461bcd60e51b815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201526e06965722063616e6e6f74206265203608c1b60648201526084016200011f565b8051602082015163ffffffff82169160ff909116906200076e90829062000a55565b6200077a919062000a87565b63ffffffff1614620007f55760405162461bcd60e51b815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d697400000000000000000060648201526084016200011f565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff96871664ffffffffff199095169490941764010000000060ff948516021764ffffffffff60281b191665010000000000939092169290920263ffffffff60301b19161766010000000000009185169190910217600160501b600160f01b0319166a01000000000000000000009390941692909202600160701b600160f01b03191692909217600160701b6001600160801b0390921691909102179055565b606954600090620008e09063ffffffff6a010000000000000000000082048116911662000ab6565b905090565b600054610100900460ff16620009415760405162461bcd60e51b815260206004820152602b6024820152600080516020620029d683398151915260448201526a6e697469616c697a696e6760a81b60648201526084016200011f565b6200045733620009a8565b6033546001600160a01b03163314620004575760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016200011f565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052601160045260246000fd5b60008282101562000a255762000a25620009fa565b500390565b600063ffffffff80831681851680830382111562000a4c5762000a4c620009fa565b01949350505050565b600063ffffffff8084168062000a7b57634e487b7160e01b600052601260045260246000fd5b92169190910492915050565b600063ffffffff8083168185168183048111821515161562000aad5762000aad620009fa565b02949350505050565b60006001600160401b0382811684821680830382111562000a4c5762000a4c620009fa565b60805160a05160c051611ecb62000b0b6000396000610b7d01526000610b5401526000610b2b0152611ecb6000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c8063935f029e1161012a578063cc731b02116100bd578063f45e65d81161008c578063f8c68de011610071578063f8c68de014610541578063fd32aa0f14610549578063ffa1ad741461055157600080fd5b8063f45e65d814610524578063f68016b71461052d57600080fd5b8063cc731b02146103cc578063dac6e63a14610500578063e81b2c6d14610508578063f2fde38b1461051157600080fd5b8063bc49ce5f116100f9578063bc49ce5f14610396578063c4e8ddfa1461039e578063c71973f6146103a6578063c9b26f61146103b957600080fd5b8063935f029e146103605780639b7d7f0a14610373578063a71198691461037b578063b40a817c1461038357600080fd5b80634add321d116101bd57806354fd4d501161018c57806361d157681161017157806361d1576814610332578063715018a61461033a5780638da5cb5b1461034257600080fd5b806354fd4d50146103155780635d73369c1461032a57600080fd5b80634add321d146102b25780634d9f1559146102d35780634f16540b146102db5780635228a6ac1461030257600080fd5b806318d13918116101f957806318d139181461028457806319f5cea8146102995780631fd19ee1146102a157806348cd4cb1146102a957600080fd5b806306c926571461022b578063078f29cf146102465780630a49cb03146102735780630c18c1621461027b575b600080fd5b610233610559565b6040519081526020015b60405180910390f35b61024e610587565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161023d565b61024e6105c0565b61023360655481565b61029761029236600461189c565b6105f0565b005b6102336106b4565b61024e6106df565b610233606a5481565b6102ba610709565b60405167ffffffffffffffff909116815260200161023d565b61024e61072f565b6102337f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0881565b610297610310366004611a5b565b61075f565b61031d610b24565b60405161023d9190611c0d565b610233610bc7565b610233610bf2565b610297610c1d565b60335473ffffffffffffffffffffffffffffffffffffffff1661024e565b61029761036e366004611c20565b610c31565b61024e610cca565b61024e610cfa565b610297610391366004611c42565b610d2a565b610233610e10565b61024e610e3b565b6102976103b4366004611c5d565b610e6b565b6102976103c7366004611c79565b610e7f565b6104906040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260695463ffffffff8082168352640100000000820460ff9081166020850152650100000000008304169383019390935266010000000000008104831660608301526a0100000000000000000000810490921660808201526e0100000000000000000000000000009091046fffffffffffffffffffffffffffffffff1660a082015290565b60405161023d9190600060c08201905063ffffffff80845116835260ff602085015116602084015260ff6040850151166040840152806060850151166060840152806080850151166080840152506fffffffffffffffffffffffffffffffff60a08401511660a083015292915050565b61024e610eaf565b61023360675481565b61029761051f36600461189c565b610edf565b61023360665481565b6068546102ba9067ffffffffffffffff1681565b610233610f93565b610233610fbe565b610233600081565b61058460017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d611cc1565b81565b60006105bb6105b760017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad6377611cc1565b5490565b905090565b60006105bb6105b760017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad611cc1565b6105f8610fe9565b610620817f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0855565b6040805173ffffffffffffffffffffffffffffffffffffffff8316602082015260009101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060035b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516106a89190611c0d565b60405180910390a35050565b61058460017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a8611cc1565b60006105bb7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c085490565b6069546000906105bb9063ffffffff6a0100000000000000000000820481169116611cd8565b60006105bb6105b760017fe52a667f71ec761b9b381c7b76ca9b852adf7e8905da0e0ad49986a0a6871816611cc1565b600054600290610100900460ff16158015610781575060005460ff8083169116105b610812576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff83161761010017905561084b61106a565b6108548b610edf565b60658a905560668990556067889055606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff89161790557f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c088690556108ed836108ea60017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc598611cc1565b55565b815161091e906108ea60017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce9580637611cc1565b6020820151610952906108ea60017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a8611cc1565b6040820151610986906108ea60017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad6377611cc1565b60608201516109ba906108ea60017fe52a667f71ec761b9b381c7b76ca9b852adf7e8905da0e0ad49986a0a6871816611cc1565b60808201516109ee906108ea60017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad611cc1565b60a0820151610a22906108ea60017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d611cc1565b610a2b84611109565b610a34856111ab565b610a3c610709565b67ffffffffffffffff168767ffffffffffffffff161015610ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610809565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050505050565b6060610b4f7f000000000000000000000000000000000000000000000000000000000000000061161f565b610b787f000000000000000000000000000000000000000000000000000000000000000061161f565b610ba17f000000000000000000000000000000000000000000000000000000000000000061161f565b604051602001610bb393929190611d04565b604051602081830303815290604052905090565b61058460017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce9580637611cc1565b61058460017fe52a667f71ec761b9b381c7b76ca9b852adf7e8905da0e0ad49986a0a6871816611cc1565b610c25610fe9565b610c2f600061175c565b565b610c39610fe9565b606582905560668190556040805160208101849052908101829052600090606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190529050600160007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be83604051610cbd9190611c0d565b60405180910390a3505050565b60006105bb6105b760017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d611cc1565b60006105bb6105b760017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce9580637611cc1565b610d32610fe9565b610d3a610709565b67ffffffffffffffff168167ffffffffffffffff161015610db7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610809565b606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83169081179091556040805160208082019390935281518082039093018352810190526002610677565b61058460017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc598611cc1565b60006105bb6105b760017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a8611cc1565b610e73610fe9565b610e7c816111ab565b50565b610e87610fe9565b6067819055604080516020808201849052825180830390910181529082019091526000610677565b60006105bb6105b760017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc598611cc1565b610ee7610fe9565b73ffffffffffffffffffffffffffffffffffffffff8116610f8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610809565b610e7c8161175c565b61058460017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad6377611cc1565b61058460017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad611cc1565b60335473ffffffffffffffffffffffffffffffffffffffff163314610c2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610809565b600054610100900460ff16611101576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610809565b610c2f6117d3565b606a5415611199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f53797374656d436f6e6669673a2063616e6e6f74206f7665727269646520616e60448201527f20616c72656164792073657420737461727420626c6f636b00000000000000006064820152608401610809565b80156111a457606a55565b43606a5550565b8060a001516fffffffffffffffffffffffffffffffff16816060015163ffffffff16111561125b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d6178206261736500000000000000000000006064820152608401610809565b6001816040015160ff16116112f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201527f65206c6172676572207468616e203100000000000000000000000000000000006064820152608401610809565b6068546080820151825167ffffffffffffffff909216916113139190611d7a565b63ffffffff161115611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610809565b6000816020015160ff1611611418576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201527f6965722063616e6e6f74206265203000000000000000000000000000000000006064820152608401610809565b8051602082015163ffffffff82169160ff90911690611438908290611dc8565b6114429190611deb565b63ffffffff16146114d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d69740000000000000000006064820152608401610809565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff9687167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169490941764010000000060ff94851602177fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff166501000000000093909216929092027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff1617660100000000000091851691909102177fffff0000000000000000000000000000000000000000ffffffffffffffffffff166a010000000000000000000093909416929092027fffff00000000000000000000000000000000ffffffffffffffffffffffffffff16929092176e0100000000000000000000000000006fffffffffffffffffffffffffffffffff90921691909102179055565b60608160000361166257505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561168c578061167681611e17565b91506116859050600a83611e4f565b9150611666565b60008167ffffffffffffffff8111156116a7576116a76118d6565b6040519080825280601f01601f1916602001820160405280156116d1576020820181803683370190505b5090505b8415611754576116e6600183611cc1565b91506116f3600a86611e63565b6116fe906030611e77565b60f81b81838151811061171357611713611e8f565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061174d600a86611e4f565b94506116d5565b949350505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff1661186a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610809565b610c2f3361175c565b803573ffffffffffffffffffffffffffffffffffffffff8116811461189757600080fd5b919050565b6000602082840312156118ae57600080fd5b6118b782611873565b9392505050565b803567ffffffffffffffff8116811461189757600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561194f577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405290565b803563ffffffff8116811461189757600080fd5b803560ff8116811461189757600080fd5b600060c0828403121561198c57600080fd5b60405160c0810181811067ffffffffffffffff821117156119d6577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040529050806119e583611955565b81526119f360208401611969565b6020820152611a0460408401611969565b6040820152611a1560608401611955565b6060820152611a2660808401611955565b608082015260a08301356fffffffffffffffffffffffffffffffff81168114611a4e57600080fd5b60a0919091015292915050565b6000806000806000806000806000808a8c03610280811215611a7c57600080fd5b611a858c611873565b9a5060208c0135995060408c0135985060608c01359750611aa860808d016118be565b9650611ab660a08d01611873565b9550611ac58d60c08e0161197a565b94506101808c01359350611adc6101a08d01611873565b925060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4082011215611b0e57600080fd5b50611b17611905565b611b246101c08d01611873565b8152611b336101e08d01611873565b6020820152611b456102008d01611873565b6040820152611b576102208d01611873565b6060820152611b696102408d01611873565b6080820152611b7b6102608d01611873565b60a0820152809150509295989b9194979a5092959850565b60005b83811015611bae578181015183820152602001611b96565b83811115611bbd576000848401525b50505050565b60008151808452611bdb816020860160208601611b93565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006118b76020830184611bc3565b60008060408385031215611c3357600080fd5b50508035926020909101359150565b600060208284031215611c5457600080fd5b6118b7826118be565b600060c08284031215611c6f57600080fd5b6118b7838361197a565b600060208284031215611c8b57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611cd357611cd3611c92565b500390565b600067ffffffffffffffff808316818516808303821115611cfb57611cfb611c92565b01949350505050565b60008451611d16818460208901611b93565b80830190507f2e000000000000000000000000000000000000000000000000000000000000008082528551611d52816001850160208a01611b93565b60019201918201528351611d6d816002840160208801611b93565b0160020195945050505050565b600063ffffffff808316818516808303821115611cfb57611cfb611c92565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600063ffffffff80841680611ddf57611ddf611d99565b92169190910492915050565b600063ffffffff80831681851681830481118215151615611e0e57611e0e611c92565b02949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e4857611e48611c92565b5060010190565b600082611e5e57611e5e611d99565b500490565b600082611e7257611e72611d99565b500690565b60008219821115611e8a57611e8a611c92565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c634300080f000a496e697469616c697a61626c653a20636f6e7472616374206973206e6f742069",
Bin: "0x60e06040523480156200001157600080fd5b5060016080818152600560a0908152600060c081815260408051808301825286815260208082018890526002828401526060808301869052828801869052828701869052835194850184528585529084018590529183018490529082018390529381018290529182018190526200009c9361dead9391928392839291839190600019908390620000a2565b62000ae1565b600054600290610100900460ff16158015620000c5575060005460ff8083169116105b6200012e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805461ffff191660ff8316176101001790556200014c620003f7565b620001578b6200045f565b60658a905560668990556067889055606880546001600160401b0319166001600160401b038916179055620001aa867f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0855565b620001df83620001dc60017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc59862000a16565b55565b81516200021390620001dc60017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce958063762000a16565b60208201516200024a90620001dc60017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a862000a16565b60408201516200028190620001dc60017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad637762000a16565b6060820151620002b890620001dc60017fe52a667f71ec761b9b381c7b76ca9b852adf7e8905da0e0ad49986a0a687181662000a16565b6080820151620002ef90620001dc60017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad62000a16565b60a08201516200032690620001dc60017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d62000a16565b6200033184620004de565b6200033c8562000569565b62000346620008be565b6001600160401b0316876001600160401b03161015620003a95760405162461bcd60e51b815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f7700604482015260640162000125565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050505050565b600054610100900460ff16620004535760405162461bcd60e51b815260206004820152602b6024820152600080516020620029dc83398151915260448201526a6e697469616c697a696e6760a81b606482015260840162000125565b6200045d620008eb565b565b6200046962000952565b6001600160a01b038116620004d05760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000125565b620004db81620009ae565b50565b606a5415620005565760405162461bcd60e51b815260206004820152603860248201527f53797374656d436f6e6669673a2063616e6e6f74206f7665727269646520616e60448201527f20616c72656164792073657420737461727420626c6f636b0000000000000000606482015260840162000125565b80156200056257606a55565b43606a5550565b8060a001516001600160801b0316816060015163ffffffff161115620005f85760405162461bcd60e51b815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d617820626173650000000000000000000000606482015260840162000125565b6001816040015160ff1611620006695760405162461bcd60e51b815260206004820152602f60248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201526e65206c6172676572207468616e203160881b606482015260840162000125565b606854608082015182516001600160401b03909216916200068b919062000a30565b63ffffffff161115620006e15760405162461bcd60e51b815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f7700604482015260640162000125565b6000816020015160ff1611620007525760405162461bcd60e51b815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201526e06965722063616e6e6f74206265203608c1b606482015260840162000125565b8051602082015163ffffffff82169160ff909116906200077490829062000a5b565b62000780919062000a8d565b63ffffffff1614620007fb5760405162461bcd60e51b815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d6974000000000000000000606482015260840162000125565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff96871664ffffffffff199095169490941764010000000060ff948516021764ffffffffff60281b191665010000000000939092169290920263ffffffff60301b19161766010000000000009185169190910217600160501b600160f01b0319166a01000000000000000000009390941692909202600160701b600160f01b03191692909217600160701b6001600160801b0390921691909102179055565b606954600090620008e69063ffffffff6a010000000000000000000082048116911662000abc565b905090565b600054610100900460ff16620009475760405162461bcd60e51b815260206004820152602b6024820152600080516020620029dc83398151915260448201526a6e697469616c697a696e6760a81b606482015260840162000125565b6200045d33620009ae565b6033546001600160a01b031633146200045d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000125565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052601160045260246000fd5b60008282101562000a2b5762000a2b62000a00565b500390565b600063ffffffff80831681851680830382111562000a525762000a5262000a00565b01949350505050565b600063ffffffff8084168062000a8157634e487b7160e01b600052601260045260246000fd5b92169190910492915050565b600063ffffffff8083168185168183048111821515161562000ab35762000ab362000a00565b02949350505050565b60006001600160401b0382811684821680830382111562000a525762000a5262000a00565b60805160a05160c051611ecb62000b116000396000610b7d01526000610b5401526000610b2b0152611ecb6000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c8063935f029e1161012a578063cc731b02116100bd578063f45e65d81161008c578063f8c68de011610071578063f8c68de014610541578063fd32aa0f14610549578063ffa1ad741461055157600080fd5b8063f45e65d814610524578063f68016b71461052d57600080fd5b8063cc731b02146103cc578063dac6e63a14610500578063e81b2c6d14610508578063f2fde38b1461051157600080fd5b8063bc49ce5f116100f9578063bc49ce5f14610396578063c4e8ddfa1461039e578063c71973f6146103a6578063c9b26f61146103b957600080fd5b8063935f029e146103605780639b7d7f0a14610373578063a71198691461037b578063b40a817c1461038357600080fd5b80634add321d116101bd57806354fd4d501161018c57806361d157681161017157806361d1576814610332578063715018a61461033a5780638da5cb5b1461034257600080fd5b806354fd4d50146103155780635d73369c1461032a57600080fd5b80634add321d146102b25780634d9f1559146102d35780634f16540b146102db5780635228a6ac1461030257600080fd5b806318d13918116101f957806318d139181461028457806319f5cea8146102995780631fd19ee1146102a157806348cd4cb1146102a957600080fd5b806306c926571461022b578063078f29cf146102465780630a49cb03146102735780630c18c1621461027b575b600080fd5b610233610559565b6040519081526020015b60405180910390f35b61024e610587565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161023d565b61024e6105c0565b61023360655481565b61029761029236600461189c565b6105f0565b005b6102336106b4565b61024e6106df565b610233606a5481565b6102ba610709565b60405167ffffffffffffffff909116815260200161023d565b61024e61072f565b6102337f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0881565b610297610310366004611a5b565b61075f565b61031d610b24565b60405161023d9190611c0d565b610233610bc7565b610233610bf2565b610297610c1d565b60335473ffffffffffffffffffffffffffffffffffffffff1661024e565b61029761036e366004611c20565b610c31565b61024e610cca565b61024e610cfa565b610297610391366004611c42565b610d2a565b610233610e10565b61024e610e3b565b6102976103b4366004611c5d565b610e6b565b6102976103c7366004611c79565b610e7f565b6104906040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260695463ffffffff8082168352640100000000820460ff9081166020850152650100000000008304169383019390935266010000000000008104831660608301526a0100000000000000000000810490921660808201526e0100000000000000000000000000009091046fffffffffffffffffffffffffffffffff1660a082015290565b60405161023d9190600060c08201905063ffffffff80845116835260ff602085015116602084015260ff6040850151166040840152806060850151166060840152806080850151166080840152506fffffffffffffffffffffffffffffffff60a08401511660a083015292915050565b61024e610eaf565b61023360675481565b61029761051f36600461189c565b610edf565b61023360665481565b6068546102ba9067ffffffffffffffff1681565b610233610f93565b610233610fbe565b610233600081565b61058460017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d611cc1565b81565b60006105bb6105b760017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad6377611cc1565b5490565b905090565b60006105bb6105b760017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad611cc1565b6105f8610fe9565b610620817f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0855565b6040805173ffffffffffffffffffffffffffffffffffffffff8316602082015260009101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060035b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516106a89190611c0d565b60405180910390a35050565b61058460017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a8611cc1565b60006105bb7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c085490565b6069546000906105bb9063ffffffff6a0100000000000000000000820481169116611cd8565b60006105bb6105b760017fe52a667f71ec761b9b381c7b76ca9b852adf7e8905da0e0ad49986a0a6871816611cc1565b600054600290610100900460ff16158015610781575060005460ff8083169116105b610812576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff83161761010017905561084b61106a565b6108548b610edf565b60658a905560668990556067889055606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff89161790557f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c088690556108ed836108ea60017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc598611cc1565b55565b815161091e906108ea60017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce9580637611cc1565b6020820151610952906108ea60017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a8611cc1565b6040820151610986906108ea60017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad6377611cc1565b60608201516109ba906108ea60017fe52a667f71ec761b9b381c7b76ca9b852adf7e8905da0e0ad49986a0a6871816611cc1565b60808201516109ee906108ea60017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad611cc1565b60a0820151610a22906108ea60017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d611cc1565b610a2b84611109565b610a34856111ab565b610a3c610709565b67ffffffffffffffff168767ffffffffffffffff161015610ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610809565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050505050565b6060610b4f7f000000000000000000000000000000000000000000000000000000000000000061161f565b610b787f000000000000000000000000000000000000000000000000000000000000000061161f565b610ba17f000000000000000000000000000000000000000000000000000000000000000061161f565b604051602001610bb393929190611d04565b604051602081830303815290604052905090565b61058460017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce9580637611cc1565b61058460017fe52a667f71ec761b9b381c7b76ca9b852adf7e8905da0e0ad49986a0a6871816611cc1565b610c25610fe9565b610c2f600061175c565b565b610c39610fe9565b606582905560668190556040805160208101849052908101829052600090606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190529050600160007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be83604051610cbd9190611c0d565b60405180910390a3505050565b60006105bb6105b760017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d611cc1565b60006105bb6105b760017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce9580637611cc1565b610d32610fe9565b610d3a610709565b67ffffffffffffffff168167ffffffffffffffff161015610db7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610809565b606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83169081179091556040805160208082019390935281518082039093018352810190526002610677565b61058460017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc598611cc1565b60006105bb6105b760017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a8611cc1565b610e73610fe9565b610e7c816111ab565b50565b610e87610fe9565b6067819055604080516020808201849052825180830390910181529082019091526000610677565b60006105bb6105b760017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc598611cc1565b610ee7610fe9565b73ffffffffffffffffffffffffffffffffffffffff8116610f8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610809565b610e7c8161175c565b61058460017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad6377611cc1565b61058460017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad611cc1565b60335473ffffffffffffffffffffffffffffffffffffffff163314610c2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610809565b600054610100900460ff16611101576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610809565b610c2f6117d3565b606a5415611199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f53797374656d436f6e6669673a2063616e6e6f74206f7665727269646520616e60448201527f20616c72656164792073657420737461727420626c6f636b00000000000000006064820152608401610809565b80156111a457606a55565b43606a5550565b8060a001516fffffffffffffffffffffffffffffffff16816060015163ffffffff16111561125b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d6178206261736500000000000000000000006064820152608401610809565b6001816040015160ff16116112f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201527f65206c6172676572207468616e203100000000000000000000000000000000006064820152608401610809565b6068546080820151825167ffffffffffffffff909216916113139190611d7a565b63ffffffff161115611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610809565b6000816020015160ff1611611418576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201527f6965722063616e6e6f74206265203000000000000000000000000000000000006064820152608401610809565b8051602082015163ffffffff82169160ff90911690611438908290611dc8565b6114429190611deb565b63ffffffff16146114d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d69740000000000000000006064820152608401610809565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff9687167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169490941764010000000060ff94851602177fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff166501000000000093909216929092027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff1617660100000000000091851691909102177fffff0000000000000000000000000000000000000000ffffffffffffffffffff166a010000000000000000000093909416929092027fffff00000000000000000000000000000000ffffffffffffffffffffffffffff16929092176e0100000000000000000000000000006fffffffffffffffffffffffffffffffff90921691909102179055565b60608160000361166257505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561168c578061167681611e17565b91506116859050600a83611e4f565b9150611666565b60008167ffffffffffffffff8111156116a7576116a76118d6565b6040519080825280601f01601f1916602001820160405280156116d1576020820181803683370190505b5090505b8415611754576116e6600183611cc1565b91506116f3600a86611e63565b6116fe906030611e77565b60f81b81838151811061171357611713611e8f565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061174d600a86611e4f565b94506116d5565b949350505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff1661186a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610809565b610c2f3361175c565b803573ffffffffffffffffffffffffffffffffffffffff8116811461189757600080fd5b919050565b6000602082840312156118ae57600080fd5b6118b782611873565b9392505050565b803567ffffffffffffffff8116811461189757600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561194f577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405290565b803563ffffffff8116811461189757600080fd5b803560ff8116811461189757600080fd5b600060c0828403121561198c57600080fd5b60405160c0810181811067ffffffffffffffff821117156119d6577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040529050806119e583611955565b81526119f360208401611969565b6020820152611a0460408401611969565b6040820152611a1560608401611955565b6060820152611a2660808401611955565b608082015260a08301356fffffffffffffffffffffffffffffffff81168114611a4e57600080fd5b60a0919091015292915050565b6000806000806000806000806000808a8c03610280811215611a7c57600080fd5b611a858c611873565b9a5060208c0135995060408c0135985060608c01359750611aa860808d016118be565b9650611ab660a08d01611873565b9550611ac58d60c08e0161197a565b94506101808c01359350611adc6101a08d01611873565b925060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4082011215611b0e57600080fd5b50611b17611905565b611b246101c08d01611873565b8152611b336101e08d01611873565b6020820152611b456102008d01611873565b6040820152611b576102208d01611873565b6060820152611b696102408d01611873565b6080820152611b7b6102608d01611873565b60a0820152809150509295989b9194979a5092959850565b60005b83811015611bae578181015183820152602001611b96565b83811115611bbd576000848401525b50505050565b60008151808452611bdb816020860160208601611b93565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006118b76020830184611bc3565b60008060408385031215611c3357600080fd5b50508035926020909101359150565b600060208284031215611c5457600080fd5b6118b7826118be565b600060c08284031215611c6f57600080fd5b6118b7838361197a565b600060208284031215611c8b57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611cd357611cd3611c92565b500390565b600067ffffffffffffffff808316818516808303821115611cfb57611cfb611c92565b01949350505050565b60008451611d16818460208901611b93565b80830190507f2e000000000000000000000000000000000000000000000000000000000000008082528551611d52816001850160208a01611b93565b60019201918201528351611d6d816002840160208801611b93565b0160020195945050505050565b600063ffffffff808316818516808303821115611cfb57611cfb611c92565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600063ffffffff80841680611ddf57611ddf611d99565b92169190910492915050565b600063ffffffff80831681851681830481118215151615611e0e57611e0e611c92565b02949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e4857611e48611c92565b5060010190565b600082611e5e57611e5e611d99565b500490565b600082611e7257611e72611d99565b500690565b60008219821115611e8a57611e8a611c92565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c634300080f000a496e697469616c697a61626c653a20636f6e7472616374206973206e6f742069",
}
// SystemConfigABI is the input ABI used to generate the binding from.
......
......@@ -484,7 +484,7 @@ func (s *CrossLayerUser) CompleteWithdrawal(t Testing, l2TxHash common.Hash) com
// Check if the withdrawal may be completed yet
if l2OutputBlock.Time()+finalizationPeriod.Uint64() >= l1Head.Time {
t.InvalidAction("withdrawal tx %s was included in L2 block %d (time %d) but L1 only knows of L2 proposal %d (time %d) at head %d (time %d) which has not reached output confirmation yet (period is %d)",
l2TxHash, l2WithdrawalBlock.NumberU64(), l2WithdrawalBlock.Time(), l2OutputBlock.NumberU64(), l2OutputBlock.Time(), finalizationPeriod.Uint64(), l1Head.Number.Uint64(), l1Head.Time)
l2TxHash, l2WithdrawalBlock.NumberU64(), l2WithdrawalBlock.Time(), l2OutputBlock.NumberU64(), l2OutputBlock.Time(), l1Head.Number.Uint64(), l1Head.Time, finalizationPeriod.Uint64())
return common.Hash{}
}
......
FROM ethereum/client-go:v1.12.1
FROM ethereum/client-go:v1.12.2
RUN apk add --no-cache jq
......
......@@ -347,7 +347,7 @@ MIPS_Test:test_multu_succeeds() (gas: 121698)
MIPS_Test:test_nor_succeeds() (gas: 121739)
MIPS_Test:test_or_succeeds() (gas: 121635)
MIPS_Test:test_ori_succeeds() (gas: 121865)
MIPS_Test:test_preimage_read_succeeds() (gas: 235922)
MIPS_Test:test_preimage_read_succeeds() (gas: 233825)
MIPS_Test:test_preimage_write_succeeds() (gas: 126473)
MIPS_Test:test_prestate_exited_succeeds() (gas: 112970)
MIPS_Test:test_sb_succeeds() (gas: 159993)
......
......@@ -37,5 +37,6 @@
"l2GenesisBlockBaseFeePerGas": "0x3b9aca00",
"eip1559Denominator": 50,
"eip1559Elasticity": 6,
"l2GenesisRegolithTimeOffset": "0x0"
"l2GenesisRegolithTimeOffset": "0x0",
"systemConfigStartBlock": 0
}
......@@ -27,7 +27,7 @@
"validate-spacers": "pnpm build && npx ts-node scripts/validate-spacers.ts",
"slither": "./scripts/slither.sh",
"slither:triage": "TRIAGE_MODE=1 ./scripts/slither.sh",
"clean": "rm -rf ./artifacts ./forge-artifacts ./cache ./tsconfig.tsbuildinfo ./tsconfig.build.tsbuildinfo ./test-case-generator/fuzz ./scripts/differential-testing",
"clean": "rm -rf ./artifacts ./forge-artifacts ./cache ./tsconfig.tsbuildinfo ./tsconfig.build.tsbuildinfo ./test-case-generator/fuzz ./scripts/differential-testing/differential-testing",
"preinstall": "npx only-allow pnpm",
"lint:ts:check": "eslint . --max-warnings=0",
"lint:forge-tests:check": "ts-node scripts/forge-test-names.ts",
......
......@@ -395,7 +395,6 @@ contract Deploy is Deployer {
/// @notice Deploy the SystemConfig
function deploySystemConfig() public broadcast returns (address addr_) {
SystemConfig config = new SystemConfig();
bytes32 batcherHash = bytes32(uint256(uint160(cfg.batchSenderAddress())));
require(config.owner() == address(0xdEaD));
require(config.overhead() == 0);
......@@ -418,7 +417,7 @@ contract Deploy is Deployer {
require(config.optimismPortal() == address(0));
require(config.l1CrossDomainMessenger() == address(0));
require(config.optimismMintableERC20Factory() == address(0));
require(config.startBlock() == 0);
require(config.startBlock() == type(uint256).max);
save("SystemConfig", address(config));
console.log("SystemConfig deployed at %s", address(config));
......@@ -490,6 +489,7 @@ contract Deploy is Deployer {
address systemConfig = mustGetAddress("SystemConfig");
bytes32 batcherHash = bytes32(uint256(uint160(cfg.batchSenderAddress())));
uint256 startBlock = cfg.systemConfigStartBlock();
proxyAdmin.upgradeAndCall({
_proxy: payable(systemConfigProxy),
......@@ -504,7 +504,7 @@ contract Deploy is Deployer {
uint64(cfg.l2GenesisBlockGasLimit()),
cfg.p2pSequencerAddress(),
Constants.DEFAULT_RESOURCE_CONFIG(),
cfg.systemConfigStartBlock(),
startBlock,
cfg.batchInboxAddress(),
SystemConfig.Addresses({
l1CrossDomainMessenger: mustGetAddress("L1CrossDomainMessengerProxy"),
......@@ -542,7 +542,13 @@ contract Deploy is Deployer {
require(config.l2OutputOracle() == mustGetAddress("L2OutputOracleProxy"));
require(config.optimismPortal() == mustGetAddress("OptimismPortalProxy"));
require(config.l1CrossDomainMessenger() == mustGetAddress("L1CrossDomainMessengerProxy"));
require(config.startBlock() == cfg.systemConfigStartBlock());
// A non zero start block is an override
if (startBlock != 0) {
require(config.startBlock() == startBlock);
} else {
require(config.startBlock() == block.number);
}
}
/// @notice Initialize the L1StandardBridge
......
......@@ -4,7 +4,7 @@
"src/L1/L1StandardBridge.sol": "0xbd7b303cefe46bc14bf1a2b81e5702ff45ce9c5257524e59778e11c75f7f5bdc",
"src/L1/L2OutputOracle.sol": "0x05ea17a834563ffa50cade81189b120b6f0805ba316d6a9893c8cf8b231e57e3",
"src/L1/OptimismPortal.sol": "0xeefcc16d30e14ed7ce9970f3aeaf1d5668324b3fc1ddb4790da5804cfdd78980",
"src/L1/SystemConfig.sol": "0x932c896b1bc2a32227bfe30aa66e1e6d17f057cc9a2562876bf7730858041895",
"src/L1/SystemConfig.sol": "0x29beec0a03b9602a53e3ceaec2354972d917f8b80f1b3a8f03f4fb7a67753fce",
"src/L2/BaseFeeVault.sol": "0xd8df28898799b80c370e77e9aad09f79235dfda2bf13e56daf21997cfe54200d",
"src/L2/GasPriceOracle.sol": "0xb7d8c4f3ea8db31900125e341aae42a862a2b7d3f1c1aa60c97dc2d0e022b7ba",
"src/L2/L1Block.sol": "0x38ea78a9611656a60ae4d58db75e96413a638e3ccb2e935052441f98a1fd3105",
......
......@@ -98,11 +98,11 @@ contract SystemConfig is OwnableUpgradeable, Semver {
/// @notice The block at which the op-node can start searching for logs from.
uint256 public startBlock;
/// @custom:semver 1.4.1
/// @custom:semver 1.5.0
/// @notice Constructs the SystemConfig contract. Cannot set
/// the owner to `address(0)` due to the Ownable contract's
/// implementation, so set it to `address(0xdEaD)`
constructor() Semver(1, 4, 1) {
constructor() Semver(1, 5, 0) {
initialize({
_owner: address(0xdEaD),
_overhead: 0,
......@@ -118,7 +118,7 @@ contract SystemConfig is OwnableUpgradeable, Semver {
systemTxMaxGas: 0,
maximumBaseFee: 0
}),
_startBlock: 0,
_startBlock: type(uint256).max,
_batchInbox: address(0),
_addresses: SystemConfig.Addresses({
l1CrossDomainMessenger: address(0),
......
......@@ -53,11 +53,17 @@ contract MIPS {
uint32 constant EINVAL = 0x16;
/// @notice The preimage oracle contract.
IPreimageOracle public oracle;
IPreimageOracle internal immutable ORACLE;
/// @param _oracle The address of the preimage oracle contract.
constructor(IPreimageOracle _oracle) {
oracle = _oracle;
ORACLE = _oracle;
}
/// @notice Getter for the pre-image oracle contract.
/// @return oracle_ The IPreimageOracle contract.
function oracle() external view returns (IPreimageOracle oracle_) {
oracle_ = ORACLE;
}
/// @notice Extends the value leftwards with its most significant bit (sign extension).
......@@ -179,7 +185,7 @@ contract MIPS {
if (uint8(preimageKey[0]) == 1) {
preimageKey = PreimageKeyLib.localize(preimageKey);
}
(bytes32 dat, uint256 datLen) = oracle.readPreimage(preimageKey, state.preimageOffset);
(bytes32 dat, uint256 datLen) = ORACLE.readPreimage(preimageKey, state.preimageOffset);
// Transform data for writing to memory
// We use assembly for more precise ops, and no var count limit
......
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