Commit 870a59be authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into jm/test-new-bridge-iface

parents 1825982a dd4dce86
---
'@eth-optimism/proxyd': patch
---
proxyd: Add req_id to log
---
'@eth-optimism/proxyd': minor
---
Include nonce in sender rate limit
---
'@eth-optimism/common-ts': minor
---
Add option to configure body parser
---
'@eth-optimism/l2geth': patch
---
Has l2geth return a NonceToHigh response if the txn nonce is greater than the expected nonce.
......@@ -846,9 +846,9 @@ workflows:
requires:
- yarn-monorepo
- js-lint-test:
name: drippie-mon-tests
coverage_flag: drippie-mon-tests
package_name: drippie-mon
name: chain-mon-tests
coverage_flag: chain-mon-tests
package_name: chain-mon
dependencies: "(common-ts|contracts-periphery|core-utils|sdk)"
requires:
- yarn-monorepo
......
.github
.vscode
node_modules
**/node_modules
.env
**/.env
......
......@@ -12,7 +12,7 @@
/packages/contracts-periphery @ethereum-optimism/contract-reviewers
/packages/core-utils @ethereum-optimism/legacy-reviewers
/packages/data-transport-layer @ethereum-optimism/legacy-reviewers
/packages/drippie-mon @smartcontracts
/packages/chain-mon @smartcontracts
/packages/fault-detector @ethereum-optimism/legacy-reviewers
/packages/hardhat-deploy-config @ethereum-optimism/legacy-reviewers
/packages/message-relayer @ethereum-optimism/legacy-reviewers
......
......@@ -25,7 +25,7 @@
"changeProcessCWD": true
},
{
"directory": "packages/drippie-mon",
"directory": "packages/chain-mon",
"changeProcessCWD": true
},
{
......
......@@ -57,7 +57,7 @@ Refer to the Directory Structure section below to understand which packages are
│ ├── <a href="./packages/contracts-periphery">contracts-periphery</a>: Peripheral contracts for Optimism
│ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier
│ ├── <a href="./packages/data-transport-layer">data-transport-layer</a>: Service for indexing Optimism-related L1 data
│ ├── <a href="./packages/drippie-mon">drippie-mon</a>: Service for monitoring Drippie instances
│ ├── <a href="./packages/chain-mon">chain-mon</a>: Chain monitoring services
│ ├── <a href="./packages/fault-detector">fault-detector</a>: Service for detecting Sequencer faults
│ ├── <a href="./packages/message-relayer">message-relayer</a>: Tool for automatically relaying L1<>L2 messages in development
│ ├── <a href="./packages/replica-healthcheck">replica-healthcheck</a>: Service for monitoring the health of a replica node
......
......@@ -37,7 +37,7 @@ flag_management:
- name: actor-tests-tests
- name: contracts-periphery-tests
- name: dtl-tests
- name: drippie-mon-tests
- name: chain-mon-tests
- name: fault-detector-tests
- name: message-relayer-tests
- name: replica-healthcheck-tests
......
......@@ -555,8 +555,10 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
}
// Ensure the transaction adheres to nonce ordering
if rcfg.UsingOVM {
if pool.currentState.GetNonce(from) != tx.Nonce() {
if pool.currentState.GetNonce(from) > tx.Nonce() {
return ErrNonceTooLow
} else if pool.currentState.GetNonce(from) < tx.Nonce() {
return ErrNonceTooHigh
}
} else {
if pool.currentState.GetNonce(from) > tx.Nonce() {
......
......@@ -3,21 +3,18 @@ package batcher
import (
"context"
"fmt"
"math/big"
_ "net/http/pprof"
"os"
"os/signal"
"syscall"
"time"
"github.com/urfave/cli"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
opsigner "github.com/ethereum-optimism/optimism/op-signer/client"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/urfave/cli"
)
const (
......@@ -30,8 +27,7 @@ const (
// 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(version string) func(cliCtx *cli.Context) error {
return func(cliCtx *cli.Context) error {
func Main(version string, cliCtx *cli.Context) error {
cfg := NewConfig(cliCtx)
if err := cfg.Check(); err != nil {
return fmt.Errorf("invalid CLI flags: %w", err)
......@@ -40,33 +36,11 @@ func Main(version string) func(cliCtx *cli.Context) error {
l := oplog.NewLogger(cfg.LogConfig)
l.Info("Initializing Batch Submitter")
var batchSubmitter *BatchSubmitter
if !cfg.SignerConfig.Enabled() {
bs, err := NewBatchSubmitter(cfg, l)
batchSubmitter, err := NewBatchSubmitterFromCLIConfig(cfg, l)
if err != nil {
l.Error("Unable to create Batch Submitter", "error", err)
return err
}
batchSubmitter = bs
} else {
signerClient, err := opsigner.NewSignerClientFromConfig(l, cfg.SignerConfig)
if err != nil {
l.Error("Unable to create Signer Client", "error", err)
return err
}
signer := func(chainID *big.Int) SignerFn {
return func(ctx context.Context, rawTx types.TxData) (*types.Transaction, error) {
tx := types.NewTx(rawTx)
return signerClient.SignTransaction(ctx, chainID, tx)
}
}
bs, err := NewBatchSubmitterWithSigner(cfg, common.HexToAddress(cfg.SignerConfig.Address), signer, l)
if err != nil {
l.Error("Unable to create Batch Submitter with signer", "error", err)
return err
}
batchSubmitter = bs
}
l.Info("Starting Batch Submitter")
......@@ -98,7 +72,7 @@ func Main(version string) func(cliCtx *cli.Context) error {
l.Error("error starting metrics server", err)
}
}()
opmetrics.LaunchBalanceMetrics(ctx, l, registry, "", batchSubmitter.cfg.L1Client, batchSubmitter.addr)
opmetrics.LaunchBalanceMetrics(ctx, l, registry, "", batchSubmitter.L1Client, batchSubmitter.From)
}
rpcCfg := cfg.RPCConfig
......@@ -123,5 +97,5 @@ func Main(version string) func(cliCtx *cli.Context) error {
cancel()
_ = server.Stop()
return nil
}
}
package batcher
import (
"bytes"
"errors"
"fmt"
"io"
"math"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/core/types"
)
type (
// channelBuilder uses a ChannelOut to create a channel with output frame
// size approximation.
channelBuilder struct {
cfg ChannelConfig
// marked as full if a) max RLP input bytes, b) max num frames or c) max
// allowed frame index (uint16) has been reached
fullErr error
// current channel
co *derive.ChannelOut
// list of blocks in the channel. Saved in case the channel must be rebuilt
blocks []*types.Block
// frames data queue, to be send as txs
frames []taggedData
}
ChannelConfig struct {
// ChannelTimeout is the maximum duration, in seconds, to attempt completing
// an opened channel. The batcher can decide to set it shorter than the
// actual timeout, since submitting continued channel data to L1 is not
// instantaneous. It's not worth it to work with nearly timed-out channels.
ChannelTimeout uint64
// The maximum byte-size a frame can have.
MaxFrameSize uint64
// The target number of frames to create per channel. Note that if the
// realized compression ratio is worse than the approximate, more frames may
// actually be created. This also depends on how close TargetFrameSize is to
// MaxFrameSize.
TargetFrameSize uint64
// The target number of frames to create in this channel. If the realized
// compression ratio is worse than approxComprRatio, additional leftover
// frame(s) might get created.
TargetNumFrames int
// Approximated compression ratio to assume. Should be slightly smaller than
// average from experiments to avoid the chances of creating a small
// additional leftover frame.
ApproxComprRatio float64
}
ChannelFullError struct {
Err error
}
)
func (e *ChannelFullError) Error() string {
return "channel full: " + e.Err.Error()
}
func (e *ChannelFullError) Unwrap() error {
return e.Err
}
var (
ErrInputTargetReached = errors.New("target amount of input data reached")
ErrMaxFrameIndex = errors.New("max frame index reached (uint16)")
)
// InputThreshold calculates the input data threshold in bytes from the given
// parameters.
func (c ChannelConfig) InputThreshold() uint64 {
return uint64(float64(c.TargetNumFrames) * float64(c.TargetFrameSize) / c.ApproxComprRatio)
}
func newChannelBuilder(cfg ChannelConfig) (*channelBuilder, error) {
co, err := derive.NewChannelOut()
if err != nil {
return nil, err
}
return &channelBuilder{
cfg: cfg,
co: co,
}, nil
}
func (c *channelBuilder) ID() derive.ChannelID {
return c.co.ID()
}
// InputBytes returns to total amount of input bytes added to the channel.
func (c *channelBuilder) InputBytes() int {
return c.co.InputBytes()
}
// Blocks returns a backup list of all blocks that were added to the channel. It
// can be used in case the channel needs to be rebuilt.
func (c *channelBuilder) Blocks() []*types.Block {
return c.blocks
}
// Reset resets the internal state of the channel builder so that it can be
// reused. Note that a new channel id is also generated by Reset.
func (c *channelBuilder) Reset() error {
c.blocks = c.blocks[:0]
c.frames = c.frames[:0]
return c.co.Reset()
}
// AddBlock adds a block to the channel compression pipeline. IsFull should be
// called aftewards to test whether the channel is full. If full, a new channel
// must be started.
//
// AddBlock returns a ChannelFullError if called even though the channel is
// already full. See description of FullErr for details.
//
// Call OutputFrames() afterwards to create frames.
func (c *channelBuilder) AddBlock(block *types.Block) error {
if c.IsFull() {
return c.FullErr()
}
_, err := c.co.AddBlock(block)
if errors.Is(err, derive.ErrTooManyRLPBytes) {
c.setFullErr(err)
return c.FullErr()
} else if err != nil {
return fmt.Errorf("adding block to channel out: %w", err)
}
c.blocks = append(c.blocks, block)
if c.InputTargetReached() {
c.setFullErr(ErrInputTargetReached)
// Adding this block still worked, so don't return error, just mark as full
}
return nil
}
// InputTargetReached says whether the target amount of input data has been
// reached in this channel builder. No more blocks can be added afterwards.
func (c *channelBuilder) InputTargetReached() bool {
return uint64(c.co.InputBytes()) >= c.cfg.InputThreshold()
}
// IsFull returns whether the channel is full.
// FullErr returns the reason for the channel being full.
func (c *channelBuilder) IsFull() bool {
return c.fullErr != nil
}
// FullErr returns the reason why the channel is full. If not full yet, it
// returns nil.
//
// It returns a ChannelFullError wrapping one of three possible reasons for the
// channel being full:
// - ErrInputTargetReached if the target amount of input data has been reached,
// - derive.MaxRLPBytesPerChannel if the general maximum amount of input data
// would have been exceeded by the latest AddBlock call,
// - ErrMaxFrameIndex if the maximum number of frames has been generated (uint16)
func (c *channelBuilder) FullErr() error {
return c.fullErr
}
func (c *channelBuilder) setFullErr(err error) {
c.fullErr = &ChannelFullError{Err: err}
}
// OutputFrames creates new frames with the channel out. It should be called
// after AddBlock and before iterating over available frames with HasFrame and
// NextFrame.
//
// If the input data target hasn't been reached yet, it will conservatively only
// pull readily available frames from the compression output.
// If the target has been reached, the channel is closed and all remaining
// frames will be created, possibly with a small leftover frame.
func (c *channelBuilder) OutputFrames() error {
if c.IsFull() {
return c.closeAndOutputAllFrames()
}
return c.outputReadyFrames()
}
// outputReadyFrames creates new frames as long as there's enough data ready in
// the channel out compression pipeline.
//
// This is part of an optimization to already generate frames and send them off
// as txs while still collecting blocks in the channel builder.
func (c *channelBuilder) outputReadyFrames() error {
// TODO: Decide whether we want to fill frames to max size and use target
// only for estimation, or use target size.
for c.co.ReadyBytes() >= int(c.cfg.MaxFrameSize) {
if err := c.outputFrame(); err == io.EOF {
return nil
} else if err != nil {
return err
}
}
return nil
}
func (c *channelBuilder) closeAndOutputAllFrames() error {
if err := c.co.Close(); err != nil {
return fmt.Errorf("closing channel out: %w", err)
}
for {
if err := c.outputFrame(); err == io.EOF {
return nil
} else if err != nil {
return err
}
}
}
// outputFrame creates one new frame and adds it to the frames queue.
// Note that compressed output data must be available on the underlying
// ChannelOut, or an empty frame will be produced.
func (c *channelBuilder) outputFrame() error {
var buf bytes.Buffer
fn, err := c.co.OutputFrame(&buf, c.cfg.MaxFrameSize)
if err != io.EOF && err != nil {
return fmt.Errorf("writing frame[%d]: %w", fn, err)
}
// Mark as full if max index reached
// TODO: If there's still data in the compression pipeline of the channel out,
// we would miss it and the whole channel would be broken because the last
// frames would never be generated...
// Hitting the max index is impossible with current parameters, so ignore for
// now. Note that in order to properly catch this, we'd need to call Flush
// after every block addition to estimate how many more frames are coming.
if fn == math.MaxUint16 {
c.setFullErr(ErrMaxFrameIndex)
}
frame := taggedData{
id: txID{chID: c.co.ID(), frameNumber: fn},
data: buf.Bytes(),
}
c.frames = append(c.frames, frame)
return err // possibly io.EOF (last frame)
}
// HasFrame returns whether there's any available frame. If true, it can be
// popped using NextFrame().
//
// Call OutputFrames before to create new frames from the channel out
// compression pipeline.
func (c *channelBuilder) HasFrame() bool {
return len(c.frames) > 0
}
func (c *channelBuilder) NumFrames() int {
return len(c.frames)
}
// NextFrame returns the next available frame.
// HasFrame must be called prior to check if there's a next frame available.
// Panics if called when there's no next frame.
func (c *channelBuilder) NextFrame() (txID, []byte) {
if len(c.frames) == 0 {
panic("no next frame")
}
f := c.frames[0]
c.frames = c.frames[1:]
return f.id, f.data
}
// PushFrame adds the frame back to the internal frames queue. Panics if not of
// the same channel.
func (c *channelBuilder) PushFrame(id txID, frame []byte) {
if id.chID != c.ID() {
panic("wrong channel")
}
c.frames = append(c.frames, taggedData{id: id, data: frame})
}
This diff is collapsed.
package batcher
import (
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli"
"github.com/ethereum-optimism/optimism/op-batcher/flags"
"github.com/ethereum-optimism/optimism/op-node/sources"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
opsigner "github.com/ethereum-optimism/optimism/op-signer/client"
)
type Config struct {
log log.Logger
L1Client *ethclient.Client
L2Client *ethclient.Client
RollupNode *sources.RollupClient
PollInterval time.Duration
TxManagerConfig txmgr.Config
From common.Address
SignerFnFactory opcrypto.SignerFactory
ChainID *big.Int
// Where to send the batch txs to.
BatchInboxAddress common.Address
// Channel creation parameters
Channel ChannelConfig
}
type CLIConfig struct {
/* Required Params */
// L1EthRpc is the HTTP provider URL for L1.
......@@ -25,12 +50,6 @@ type Config struct {
// RollupRpc is the HTTP provider URL for the L2 rollup node.
RollupRpc string
// MinL1TxSize is the minimum size of a batch tx submitted to L1.
MinL1TxSize uint64
// MaxL1TxSize is the maximum size of a batch tx submitted to L1.
MaxL1TxSize uint64
// ChannelTimeout is the maximum amount of time to attempt completing an opened channel,
// as opposed to submitting missing blocks in new channels
ChannelTimeout uint64
......@@ -72,6 +91,19 @@ type Config struct {
/* Optional Params */
// MaxL1TxSize is the maximum size of a batch tx submitted to L1.
MaxL1TxSize uint64
// TargetL1TxSize is the target size of a batch tx submitted to L1.
TargetL1TxSize uint64
// TargetNumFrames is the target number of frames per channel.
TargetNumFrames int
// ApproxComprRatio is the approximate compression ratio (<= 1.0) of the used
// compression algorithm.
ApproxComprRatio float64
LogConfig oplog.CLIConfig
MetricsConfig opmetrics.CLIConfig
......@@ -82,7 +114,7 @@ type Config struct {
SignerConfig opsigner.CLIConfig
}
func (c Config) Check() error {
func (c CLIConfig) Check() error {
if err := c.RPCConfig.Check(); err != nil {
return err
}
......@@ -102,19 +134,23 @@ func (c Config) Check() error {
}
// NewConfig parses the Config from the provided flags or environment variables.
func NewConfig(ctx *cli.Context) Config {
return Config{
func NewConfig(ctx *cli.Context) CLIConfig {
return CLIConfig{
/* Required Flags */
L1EthRpc: ctx.GlobalString(flags.L1EthRpcFlag.Name),
L2EthRpc: ctx.GlobalString(flags.L2EthRpcFlag.Name),
RollupRpc: ctx.GlobalString(flags.RollupRpcFlag.Name),
MinL1TxSize: ctx.GlobalUint64(flags.MinL1TxSizeBytesFlag.Name),
MaxL1TxSize: ctx.GlobalUint64(flags.MaxL1TxSizeBytesFlag.Name),
ChannelTimeout: ctx.GlobalUint64(flags.ChannelTimeoutFlag.Name),
PollInterval: ctx.GlobalDuration(flags.PollIntervalFlag.Name),
NumConfirmations: ctx.GlobalUint64(flags.NumConfirmationsFlag.Name),
SafeAbortNonceTooLowCount: ctx.GlobalUint64(flags.SafeAbortNonceTooLowCountFlag.Name),
ResubmissionTimeout: ctx.GlobalDuration(flags.ResubmissionTimeoutFlag.Name),
/* Optional Flags */
MaxL1TxSize: ctx.GlobalUint64(flags.MaxL1TxSizeBytesFlag.Name),
TargetL1TxSize: ctx.GlobalUint64(flags.TargetL1TxSizeBytesFlag.Name),
TargetNumFrames: ctx.GlobalInt(flags.TargetNumFramesFlag.Name),
ApproxComprRatio: ctx.GlobalFloat64(flags.ApproxComprRatioFlag.Name),
Mnemonic: ctx.GlobalString(flags.MnemonicFlag.Name),
SequencerHDPath: ctx.GlobalString(flags.SequencerHDPathFlag.Name),
PrivateKey: ctx.GlobalString(flags.PrivateKeyFlag.Name),
......
......@@ -2,34 +2,28 @@ package batcher
import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"io"
"math/big"
"strings"
_ "net/http/pprof"
"sync"
"time"
hdwallet "github.com/ethereum-optimism/go-ethereum-hdwallet"
"github.com/ethereum-optimism/optimism/op-node/eth"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
)
// BatchSubmitter encapsulates a service responsible for submitting L2 tx
// batches to L1 for availability.
type BatchSubmitter struct {
Config // directly embed the config + sources
txMgr *TransactionManager
addr common.Address
cfg DriverConfig
wg sync.WaitGroup
done chan struct{}
log log.Logger
ctx context.Context
cancel context.CancelFunc
......@@ -40,62 +34,15 @@ type BatchSubmitter struct {
state *channelManager
}
// NewBatchSubmitter initializes the BatchSubmitter, gathering any resources
// NewBatchSubmitterFromCLIConfig initializes the BatchSubmitter, gathering any resources
// that will be needed during operation.
func NewBatchSubmitter(cfg Config, l log.Logger) (*BatchSubmitter, error) {
var err error
var sequencerPrivKey *ecdsa.PrivateKey
var addr common.Address
if cfg.PrivateKey != "" && cfg.Mnemonic != "" {
return nil, errors.New("cannot specify both a private key and a mnemonic")
}
if cfg.PrivateKey == "" {
// Parse wallet private key that will be used to submit L2 txs to the batch
// inbox address.
wallet, err := hdwallet.NewFromMnemonic(cfg.Mnemonic)
if err != nil {
return nil, err
}
acc := accounts.Account{
URL: accounts.URL{
Path: cfg.SequencerHDPath,
},
}
addr, err = wallet.Address(acc)
if err != nil {
return nil, err
}
func NewBatchSubmitterFromCLIConfig(cfg CLIConfig, l log.Logger) (*BatchSubmitter, error) {
ctx := context.Background()
sequencerPrivKey, err = wallet.PrivateKey(acc)
signer, fromAddress, err := opcrypto.SignerFactoryFromConfig(l, cfg.PrivateKey, cfg.Mnemonic, cfg.SequencerHDPath, cfg.SignerConfig)
if err != nil {
return nil, err
}
} else {
sequencerPrivKey, err = crypto.HexToECDSA(strings.TrimPrefix(cfg.PrivateKey, "0x"))
if err != nil {
return nil, err
}
addr = crypto.PubkeyToAddress(sequencerPrivKey.PublicKey)
}
signer := func(chainID *big.Int) SignerFn {
s := types.LatestSignerForChainID(chainID)
return func(_ context.Context, rawTx types.TxData) (*types.Transaction, error) {
return types.SignNewTx(sequencerPrivKey, s, rawTx)
}
}
return NewBatchSubmitterWithSigner(cfg, addr, signer, l)
}
type SignerFactory func(chainID *big.Int) SignerFn
func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerFactory, l log.Logger) (*BatchSubmitter, error) {
ctx := context.Background()
batchInboxAddress, err := parseAddress(cfg.SequencerBatchInboxAddress)
if err != nil {
......@@ -124,13 +71,6 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF
return nil, err
}
sequencerBalance, err := l1Client.BalanceAt(ctx, addr, nil)
if err != nil {
return nil, err
}
log.Info("starting batch submitter", "submitter_addr", addr, "submitter_bal", sequencerBalance)
txManagerConfig := txmgr.Config{
Log: l,
Name: "Batch Submitter",
......@@ -140,34 +80,53 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF
SafeAbortNonceTooLowCount: cfg.SafeAbortNonceTooLowCount,
}
batcherCfg := DriverConfig{
Log: l,
Name: "Batch Submitter",
batcherCfg := Config{
L1Client: l1Client,
L2Client: l2Client,
RollupNode: rollupClient,
MinL1TxSize: cfg.MinL1TxSize,
MaxL1TxSize: cfg.MaxL1TxSize,
BatchInboxAddress: batchInboxAddress,
ChannelTimeout: cfg.ChannelTimeout,
ChainID: chainID,
PollInterval: cfg.PollInterval,
TxManagerConfig: txManagerConfig,
From: fromAddress,
SignerFnFactory: signer,
BatchInboxAddress: batchInboxAddress,
Channel: ChannelConfig{
ChannelTimeout: cfg.ChannelTimeout,
MaxFrameSize: cfg.MaxL1TxSize - 1, // subtract 1 byte for version
TargetFrameSize: cfg.TargetL1TxSize - 1, // subtract 1 byte for version
TargetNumFrames: cfg.TargetNumFrames,
ApproxComprRatio: cfg.ApproxComprRatio,
},
}
return NewBatchSubmitter(batcherCfg, l)
}
// NewBatchSubmitter initializes the BatchSubmitter, gathering any resources
// that will be needed during operation.
func NewBatchSubmitter(cfg Config, l log.Logger) (*BatchSubmitter, error) {
ctx, cancel := context.WithCancel(context.Background())
balance, err := cfg.L1Client.BalanceAt(ctx, cfg.From, nil)
if err != nil {
cancel()
return nil, err
}
cfg.log = l
cfg.log.Info("creating batch submitter", "submitter_addr", cfg.From, "submitter_bal", balance)
return &BatchSubmitter{
cfg: batcherCfg,
addr: addr,
txMgr: NewTransactionManager(l, txManagerConfig, batchInboxAddress, chainID, addr, l1Client, signer(chainID)),
Config: cfg,
txMgr: NewTransactionManager(l, cfg.TxManagerConfig, cfg.BatchInboxAddress, cfg.ChainID, cfg.From, cfg.L1Client, cfg.SignerFnFactory(cfg.ChainID)),
done: make(chan struct{}),
log: l,
state: NewChannelManager(l, cfg.ChannelTimeout),
// TODO: this context only exists because the event loop doesn't reach done
// if the tx manager is blocking forever due to e.g. insufficient balance.
ctx: ctx,
cancel: cancel,
state: NewChannelManager(l, cfg.Channel),
}, nil
}
func (l *BatchSubmitter) Start() error {
......@@ -214,7 +173,7 @@ func (l *BatchSubmitter) loadBlocksIntoState(ctx context.Context) {
// loadBlockIntoState fetches & stores a single block into `state`. It returns the block it loaded.
func (l *BatchSubmitter) loadBlockIntoState(ctx context.Context, blockNumber uint64) (eth.BlockID, error) {
ctx, cancel := context.WithTimeout(ctx, networkTimeout)
block, err := l.cfg.L2Client.BlockByNumber(ctx, new(big.Int).SetUint64(blockNumber))
block, err := l.L2Client.BlockByNumber(ctx, new(big.Int).SetUint64(blockNumber))
cancel()
if err != nil {
return eth.BlockID{}, err
......@@ -232,7 +191,7 @@ func (l *BatchSubmitter) loadBlockIntoState(ctx context.Context, blockNumber uin
func (l *BatchSubmitter) calculateL2BlockRangeToStore(ctx context.Context) (eth.BlockID, eth.BlockID, error) {
childCtx, cancel := context.WithTimeout(ctx, networkTimeout)
defer cancel()
syncStatus, err := l.cfg.RollupNode.SyncStatus(childCtx)
syncStatus, err := l.RollupNode.SyncStatus(childCtx)
// Ensure that we have the sync status
if err != nil {
return eth.BlockID{}, eth.BlockID{}, fmt.Errorf("failed to get sync status: %w", err)
......@@ -273,7 +232,7 @@ func (l *BatchSubmitter) calculateL2BlockRangeToStore(ctx context.Context) (eth.
func (l *BatchSubmitter) loop() {
defer l.wg.Done()
ticker := time.NewTicker(l.cfg.PollInterval)
ticker := time.NewTicker(l.PollInterval)
defer ticker.Stop()
for {
select {
......
package batcher
import (
"math/big"
"time"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
)
type DriverConfig struct {
Log log.Logger
Name string
// API to submit txs to
L1Client *ethclient.Client
// API to hit for batch data
L2Client *ethclient.Client
RollupNode *sources.RollupClient
// Limit the size of txs
MinL1TxSize uint64
MaxL1TxSize uint64
// Where to send the batch txs to.
BatchInboxAddress common.Address
// The batcher can decide to set it shorter than the actual timeout,
// since submitting continued channel data to L1 is not instantaneous.
// It's not worth it to work with nearly timed-out channels.
ChannelTimeout uint64
// Chain ID of the L1 chain to submit txs to.
ChainID *big.Int
PollInterval time.Duration
}
......@@ -12,12 +12,13 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
)
const networkTimeout = 2 * time.Second // How long a single network request can take. TODO: put in a config somewhere
type SignerFn func(ctx context.Context, rawTx types.TxData) (*types.Transaction, error)
// TransactionManager wraps the simple txmgr package to make it easy to send & wait for transactions
type TransactionManager struct {
// Config
......@@ -27,11 +28,11 @@ type TransactionManager struct {
// Outside world
txMgr txmgr.TxManager
l1Client *ethclient.Client
signerFn SignerFn
signerFn opcrypto.SignerFn
log log.Logger
}
func NewTransactionManager(log log.Logger, txMgrConfg txmgr.Config, batchInboxAddress common.Address, chainID *big.Int, senderAddress common.Address, l1Client *ethclient.Client, signerFn SignerFn) *TransactionManager {
func NewTransactionManager(log log.Logger, txMgrConfg txmgr.Config, batchInboxAddress common.Address, chainID *big.Int, senderAddress common.Address, l1Client *ethclient.Client, signerFn opcrypto.SignerFn) *TransactionManager {
t := &TransactionManager{
batchInboxAddress: batchInboxAddress,
senderAddress: senderAddress,
......@@ -78,12 +79,20 @@ func (t *TransactionManager) calcGasTipAndFeeCap(ctx context.Context) (gasTipCap
return nil, nil, fmt.Errorf("failed to get suggested gas tip cap: %w", err)
}
if gasTipCap == nil {
t.log.Warn("unexpected unset gasTipCap, using default 2 gwei")
gasTipCap = new(big.Int).SetUint64(params.GWei * 2)
}
childCtx, cancel = context.WithTimeout(ctx, networkTimeout)
head, err := t.l1Client.HeaderByNumber(childCtx, nil)
cancel()
if err != nil {
if err != nil || head == nil {
return nil, nil, fmt.Errorf("failed to get L1 head block for fee cap: %w", err)
}
if head.BaseFee == nil {
return nil, nil, fmt.Errorf("failed to get L1 basefee in block %d for fee cap", head.Number)
}
gasFeeCap = txmgr.CalcGasFeeCap(head.BaseFee, gasTipCap)
return gasTipCap, gasFeeCap, nil
......@@ -123,7 +132,8 @@ func (t *TransactionManager) CraftTx(ctx context.Context, data []byte) (*types.T
ctx, cancel = context.WithTimeout(ctx, networkTimeout)
defer cancel()
return t.signerFn(ctx, rawTx)
tx := types.NewTx(rawTx)
return t.signerFn(ctx, t.senderAddress, tx)
}
// UpdateGasPrice signs an otherwise identical txn to the one provided but with
......@@ -148,5 +158,6 @@ func (t *TransactionManager) UpdateGasPrice(ctx context.Context, tx *types.Trans
// Only log the new tip/fee cap because the updateGasPrice closure reuses the same initial transaction
t.log.Trace("updating gas price", "tip_cap", gasTipCap, "fee_cap", gasFeeCap)
return t.signerFn(ctx, rawTx)
finalTx := types.NewTx(rawTx)
return t.signerFn(ctx, t.senderAddress, finalTx)
}
......@@ -13,7 +13,7 @@ import (
)
var (
Version = "v0.10.11"
Version = "v0.10.12"
GitCommit = ""
GitDate = ""
)
......@@ -29,9 +29,17 @@ func main() {
app.Description = "Service for generating and submitting L2 tx batches " +
"to L1"
app.Action = batcher.Main(Version)
app.Action = curryMain(Version)
err := app.Run(os.Args)
if err != nil {
log.Crit("Application failed", "message", err)
}
}
// curryMain transforms the batcher.Main function into an app.Action
// This is done to capture the Version of the batcher.
func curryMain(version string) func(ctx *cli.Context) error {
return func(ctx *cli.Context) error {
return batcher.Main(version, ctx)
}
}
......@@ -14,7 +14,7 @@ import (
const envVarPrefix = "OP_BATCHER"
var (
/* Required Flags */
/* Required flags */
L1EthRpcFlag = cli.StringFlag{
Name: "l1-eth-rpc",
......@@ -34,21 +34,9 @@ var (
Required: true,
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "ROLLUP_RPC"),
}
MinL1TxSizeBytesFlag = cli.Uint64Flag{
Name: "min-l1-tx-size-bytes",
Usage: "The minimum size of a batch tx submitted to L1.",
Required: true,
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "MIN_L1_TX_SIZE_BYTES"),
}
MaxL1TxSizeBytesFlag = cli.Uint64Flag{
Name: "max-l1-tx-size-bytes",
Usage: "The maximum size of a batch tx submitted to L1.",
Required: true,
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "MAX_L1_TX_SIZE_BYTES"),
}
ChannelTimeoutFlag = cli.Uint64Flag{
Name: "channel-timeout",
Usage: "The maximum amount of time to attempt completing an opened channel, as opposed to submitting L2 blocks into a new channel.",
Usage: "The maximum duration (in seconds) to attempt completing an opened channel, as opposed to submitting L2 blocks into a new channel.",
Required: true,
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "CHANNEL_TIMEOUT"),
}
......@@ -81,6 +69,39 @@ var (
Required: true,
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "RESUBMISSION_TIMEOUT"),
}
SequencerBatchInboxAddressFlag = cli.StringFlag{
Name: "sequencer-batch-inbox-address",
Usage: "L1 Address to receive batch transactions",
Required: true,
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "SEQUENCER_BATCH_INBOX_ADDRESS"),
}
/* Optional flags */
MaxL1TxSizeBytesFlag = cli.Uint64Flag{
Name: "max-l1-tx-size-bytes",
Usage: "The maximum size of a batch tx submitted to L1.",
Value: 120_000,
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "MAX_L1_TX_SIZE_BYTES"),
}
TargetL1TxSizeBytesFlag = cli.Uint64Flag{
Name: "target-l1-tx-size-bytes",
Usage: "The target size of a batch tx submitted to L1.",
Value: 100_000,
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "TARGET_L1_TX_SIZE_BYTES"),
}
TargetNumFramesFlag = cli.IntFlag{
Name: "target-num-frames",
Usage: "The target number of frames to create per channel",
Value: 1,
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "TARGET_NUM_FRAMES"),
}
ApproxComprRatioFlag = cli.Float64Flag{
Name: "approx-compr-ratio",
Usage: "The approximate compression ratio (<= 1.0)",
Value: 1.0,
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "APPROX_COMPR_RATIO"),
}
MnemonicFlag = cli.StringFlag{
Name: "mnemonic",
Usage: "The mnemonic used to derive the wallets for either the " +
......@@ -98,20 +119,12 @@ var (
Usage: "The private key to use with the l2output wallet. Must not be used with mnemonic.",
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "PRIVATE_KEY"),
}
SequencerBatchInboxAddressFlag = cli.StringFlag{
Name: "sequencer-batch-inbox-address",
Usage: "L1 Address to receive batch transactions",
Required: true,
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "SEQUENCER_BATCH_INBOX_ADDRESS"),
}
)
var requiredFlags = []cli.Flag{
L1EthRpcFlag,
L2EthRpcFlag,
RollupRpcFlag,
MinL1TxSizeBytesFlag,
MaxL1TxSizeBytesFlag,
ChannelTimeoutFlag,
PollIntervalFlag,
NumConfirmationsFlag,
......@@ -121,6 +134,10 @@ var requiredFlags = []cli.Flag{
}
var optionalFlags = []cli.Flag{
MaxL1TxSizeBytesFlag,
TargetL1TxSizeBytesFlag,
TargetNumFramesFlag,
ApproxComprRatioFlag,
MnemonicFlag,
SequencerHDPathFlag,
PrivateKeyFlag,
......
......@@ -3,9 +3,8 @@ module github.com/ethereum-optimism/optimism/op-batcher
go 1.18
require (
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3
github.com/ethereum-optimism/optimism/op-node v0.10.11
github.com/ethereum-optimism/optimism/op-service v0.10.11
github.com/ethereum-optimism/optimism/op-node v0.10.12
github.com/ethereum-optimism/optimism/op-service v0.10.12
github.com/ethereum-optimism/optimism/op-signer v0.1.0
github.com/ethereum/go-ethereum v1.10.26
github.com/urfave/cli v1.22.9
......@@ -24,7 +23,8 @@ require (
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/dyson/certman v0.3.0 // indirect
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 // indirect
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 // indirect
github.com/ethereum-optimism/optimism/op-bindings v0.10.12 // indirect
github.com/fjl/memsize v0.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
......
......@@ -109,12 +109,12 @@ github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 h1:RDiRyHo0G/UuxHZQdMJyqIuHtWvpionuFNfczNaWCcM=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-node v0.10.11 h1:ED72b68ainzcXr5/cLOYRwv+LdE4hRDnkq3SmNRY1+Q=
github.com/ethereum-optimism/optimism/op-node v0.10.11/go.mod h1:/CDpkMxc3mDklZ1nqz2lmxfeUyAUz7yC/OLmX8egAUw=
github.com/ethereum-optimism/optimism/op-service v0.10.11 h1:o+SazhFXlE3EM9Re5KIPEQklZ9uTI8rNkjl0h5OwRtU=
github.com/ethereum-optimism/optimism/op-service v0.10.11/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c=
github.com/ethereum-optimism/optimism/op-bindings v0.10.12 h1:/B1gaCLwZYy9Rja3MiceV3R642bygp937kZjnYwRxA0=
github.com/ethereum-optimism/optimism/op-bindings v0.10.12/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-node v0.10.12 h1:yOxMThwwz1rEDDM0xTjS+6jqJwgKRtrYM6h4Pdf0zno=
github.com/ethereum-optimism/optimism/op-node v0.10.12/go.mod h1:z+DiFb82Vnn5zM3VEwc2OXK2V/JBg6MLg7ejTbsxye8=
github.com/ethereum-optimism/optimism/op-service v0.10.12 h1:Y7pR3/b8eeHYkmo2V5z7sj8jaraYqm2Azyph5lbiIxo=
github.com/ethereum-optimism/optimism/op-service v0.10.12/go.mod h1:Ibbun+aic0rjQBV8yBf9kohqIj6mQ8nSTWbZjHv+Q7Q=
github.com/ethereum-optimism/optimism/op-signer v0.1.0 h1:wH44Deai43YQWO0pEd44pDm3BahdAtSmrOHKiPvTB8Y=
github.com/ethereum-optimism/optimism/op-signer v0.1.0/go.mod h1:u8sN6X/c20pP9F1Ey7jH3fi19D08Y+T9ep3PGJfdyi8=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
......@@ -391,7 +391,7 @@ github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg=
github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d h1:vmirMegf1vqPJ+lDBxLQ0MAt3tz+JL57UPxu44JBOjA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
......
package main
import (
"errors"
"os"
"github.com/mattn/go-isatty"
"github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/op-chain-ops/eof"
"github.com/ethereum/go-ethereum/log"
)
func main() {
log.Root().SetHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(isatty.IsTerminal(os.Stderr.Fd()))))
app := &cli.App{
Name: "eof-crawler",
Usage: "Scan a Geth database for EOF-prefixed contracts",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "db-path",
Usage: "Path to the geth LevelDB",
},
&cli.StringFlag{
Name: "out",
Value: "eof-contracts.json",
Usage: "Path to the output file",
},
},
Action: func(ctx *cli.Context) error {
dbPath := ctx.String("db-path")
if len(dbPath) == 0 {
return errors.New("Must specify a db-path")
}
out := ctx.String("out")
return eof.IndexEOFContracts(dbPath, out)
},
}
if err := app.Run(os.Args); err != nil {
log.Crit("error indexing state", "err", err)
}
}
This diff is collapsed.
......@@ -10,6 +10,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
......@@ -17,7 +18,7 @@ import (
type LegacyWithdrawal struct {
Target *common.Address `json:"target"`
Sender *common.Address `json:"sender"`
Data []byte `json:"data"`
Data hexutil.Bytes `json:"data"`
Nonce *big.Int `json:"nonce"`
}
......@@ -38,7 +39,7 @@ func NewLegacyWithdrawal(target, sender *common.Address, data []byte, nonce *big
// through the standard optimism cross domain messaging system by hashing in
// the L2CrossDomainMessenger address.
func (w *LegacyWithdrawal) Encode() ([]byte, error) {
enc, err := EncodeCrossDomainMessageV0(w.Target, w.Sender, w.Data, w.Nonce)
enc, err := EncodeCrossDomainMessageV0(w.Target, w.Sender, []byte(w.Data), w.Nonce)
if err != nil {
return nil, fmt.Errorf("cannot encode LegacyWithdrawal: %w", err)
}
......@@ -98,7 +99,7 @@ func (w *LegacyWithdrawal) Decode(data []byte) error {
w.Target = &target
w.Sender = &sender
w.Data = msgData
w.Data = hexutil.Bytes(msgData)
w.Nonce = nonce
return nil
}
......
......@@ -72,6 +72,12 @@ func (c *CrossDomainMessage) Hash() (common.Hash, error) {
}
}
// HashV1 forces using the V1 hash even if its a legacy hash. This is used
// for the migration process.
func (c *CrossDomainMessage) HashV1() (common.Hash, error) {
return HashCrossDomainMessageV1(c.Nonce, c.Sender, c.Target, c.Value, c.GasLimit, c.Data)
}
// ToWithdrawal will turn a CrossDomainMessage into a Withdrawal.
// This only works for version 0 CrossDomainMessages as not all of
// the data is present for version 1 CrossDomainMessages to be turned
......
......@@ -273,6 +273,6 @@ func TestGetPendingWithdrawals(t *testing.T) {
withdrawal := withdrawals[i]
require.Equal(t, msg.Target, *withdrawal.Target)
require.Equal(t, msg.Message, withdrawal.Data)
require.Equal(t, msg.Message, []byte(withdrawal.Data))
}
}
# `eof-crawler`
Simple CLI tool to scan all accounts in a geth LevelDB for contracts that begin with the EOF prefix.
## Usage
1. Pass the directory of the Geth DB into the tool
```sh
go run ./cmd/eof-crawler/main.go --db-path <db_path> [--out <out_file>]
```
2. Once the indexing has completed, an array of all EOF-prefixed contracts will be written to `eof_contracts.json` or the designated output file.
package eof
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"log"
"os"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
)
// Account represents an account in the state.
type Account struct {
Balance string `json:"balance"`
Nonce uint64 `json:"nonce"`
Root hexutil.Bytes `json:"root"`
CodeHash hexutil.Bytes `json:"codeHash"`
Code hexutil.Bytes `json:"code,omitempty"`
Address common.Address `json:"address,omitempty"`
SecureKey hexutil.Bytes `json:"key,omitempty"`
}
// emptyCodeHash is the known hash of an account with no code.
var emptyCodeHash = crypto.Keccak256(nil)
// IndexEOFContracts indexes all the EOF contracts in the state trie of the head block
// for the given db and writes them to a JSON file.
func IndexEOFContracts(dbPath string, out string) error {
// Open an existing Ethereum database
db, err := rawdb.NewLevelDBDatabase(dbPath, 16, 16, "", true)
if err != nil {
return fmt.Errorf("Failed to open database: %w", err)
}
stateDB := state.NewDatabase(db)
// Retrieve the head block
hash := rawdb.ReadHeadBlockHash(db)
number := rawdb.ReadHeaderNumber(db, hash)
if number == nil {
return errors.New("Failed to retrieve head block number")
}
head := rawdb.ReadBlock(db, hash, *number)
if head == nil {
return errors.New("Failed to retrieve head block")
}
// Retrieve the state belonging to the head block
st, err := trie.New(trie.StateTrieID(head.Root()), trie.NewDatabase(db))
if err != nil {
return fmt.Errorf("Failed to retrieve state trie: %w", err)
}
log.Printf("Indexing state trie at head block #%d [0x%x]", *number, hash)
// Iterate over the entire account trie to search for EOF-prefixed contracts
start := time.Now()
missingPreimages := uint64(0)
eoas := uint64(0)
nonEofContracts := uint64(0)
eofContracts := make([]Account, 0)
it := trie.NewIterator(st.NodeIterator(nil))
for it.Next() {
// Decode the state account
var data types.StateAccount
err := rlp.DecodeBytes(it.Value, &data)
if err != nil {
return fmt.Errorf("Failed to decode state account: %w", err)
}
// Check to see if the account has any code associated with it before performing
// more reads from the trie & db.
if bytes.Equal(data.CodeHash, emptyCodeHash) {
eoas++
continue
}
// Create a serializable `Account` object
account := Account{
Balance: data.Balance.String(),
Nonce: data.Nonce,
Root: data.Root[:],
CodeHash: data.CodeHash,
SecureKey: it.Key,
}
// Attempt to get the address of the account from the trie
addrBytes := st.Get(it.Key)
if addrBytes == nil {
// Preimage missing! Cannot continue.
missingPreimages++
continue
}
addr := common.BytesToAddress(addrBytes)
// Attempt to get the code of the account from the trie
code, err := stateDB.ContractCode(crypto.Keccak256Hash(addrBytes), common.BytesToHash(data.CodeHash))
if err != nil {
return fmt.Errorf("Could not load code for account %x: %w", addr, err)
}
// Check if the contract's runtime bytecode starts with the EOF prefix.
if len(code) >= 1 && code[0] == 0xEF {
// Append the account to the list of EOF contracts
account.Address = addr
account.Code = code
eofContracts = append(eofContracts, account)
} else {
nonEofContracts++
}
}
// Print finishing status
log.Printf("Indexing done in %v, found %d EOF contracts", time.Since(start), len(eofContracts))
log.Printf("Num missing preimages: %d", missingPreimages)
log.Printf("Non-EOF-prefixed contracts: %d", nonEofContracts)
log.Printf("Accounts with no code (EOAs): %d", eoas)
// Write the EOF contracts to a file
file, err := json.MarshalIndent(eofContracts, "", " ")
if err != nil {
return fmt.Errorf("Cannot marshal EOF contracts: %w", err)
}
err = os.WriteFile(out, file, 0644)
if err != nil {
return fmt.Errorf("Failed to write EOF contracts array to file: %w", err)
}
log.Printf("Wrote list of EOF contracts to `%v`", out)
return nil
}
......@@ -3,7 +3,7 @@ module github.com/ethereum-optimism/optimism/op-chain-ops
go 1.18
require (
github.com/ethereum-optimism/optimism/op-bindings v0.10.11
github.com/ethereum-optimism/optimism/op-bindings v0.10.12
github.com/ethereum-optimism/optimism/op-node v0.10.1
github.com/ethereum/go-ethereum v1.10.26
github.com/holiman/uint256 v1.2.0
......@@ -23,7 +23,8 @@ require (
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/ethereum-optimism/optimism/op-service v0.10.11 // indirect
github.com/ethereum-optimism/optimism/op-service v0.10.12 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/go-kit/kit v0.10.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect
......@@ -35,6 +36,8 @@ require (
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/huin/goupnp v1.0.3 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
......@@ -46,12 +49,16 @@ require (
github.com/rogpeppe/go-internal v1.8.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.5.0 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
......
......@@ -79,21 +79,22 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 h1:RDiRyHo0G/UuxHZQdMJyqIuHtWvpionuFNfczNaWCcM=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-bindings v0.10.12 h1:/B1gaCLwZYy9Rja3MiceV3R642bygp937kZjnYwRxA0=
github.com/ethereum-optimism/optimism/op-bindings v0.10.12/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-node v0.10.1 h1:kVBaOEOYLV22XEHRhB7dfdmoXepO0kx/RsZQK+Bpk1Y=
github.com/ethereum-optimism/optimism/op-node v0.10.1/go.mod h1:pup7wiiUs9g8cZKwXeB5tEGCqwUUwFVmej9MmSIm6S8=
github.com/ethereum-optimism/optimism/op-service v0.10.11 h1:o+SazhFXlE3EM9Re5KIPEQklZ9uTI8rNkjl0h5OwRtU=
github.com/ethereum-optimism/optimism/op-service v0.10.11/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c=
github.com/ethereum-optimism/optimism/op-service v0.10.12 h1:Y7pR3/b8eeHYkmo2V5z7sj8jaraYqm2Azyph5lbiIxo=
github.com/ethereum-optimism/optimism/op-service v0.10.12/go.mod h1:Ibbun+aic0rjQBV8yBf9kohqIj6mQ8nSTWbZjHv+Q7Q=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
......@@ -196,11 +197,14 @@ github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
......@@ -373,7 +377,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg=
github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d h1:vmirMegf1vqPJ+lDBxLQ0MAt3tz+JL57UPxu44JBOjA=
github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d/go.mod h1:97vT0Rym0wCnK4B++hNA3nCetr0Mh1KXaVxzSt1arjg=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
......@@ -400,6 +405,7 @@ github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+
github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw=
......@@ -473,7 +479,9 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
......
......@@ -54,11 +54,11 @@ type Writer interface {
type ChannelOutIface interface {
ID() derive.ChannelID
Reset() error
AddBlock(block *types.Block) error
AddBlock(block *types.Block) (uint64, error)
ReadyBytes() int
Flush() error
Close() error
OutputFrame(w *bytes.Buffer, maxSize uint64) error
OutputFrame(w *bytes.Buffer, maxSize uint64) (uint16, error)
}
// Compile-time check for ChannelOutIface interface implementation for the ChannelOut type.
......@@ -135,19 +135,19 @@ func (co *GarbageChannelOut) Reset() error {
// error that it returns is ErrTooManyRLPBytes. If this error
// is returned, the channel should be closed and a new one
// should be made.
func (co *GarbageChannelOut) AddBlock(block *types.Block) error {
func (co *GarbageChannelOut) AddBlock(block *types.Block) (uint64, error) {
if co.closed {
return errors.New("already closed")
return 0, errors.New("already closed")
}
batch, err := blockToBatch(block)
if err != nil {
return err
return 0, err
}
// We encode to a temporary buffer to determine the encoded length to
// ensure that the total size of all RLP elements is less than or equal to MAX_RLP_BYTES_PER_CHANNEL
var buf bytes.Buffer
if err := rlp.Encode(&buf, batch); err != nil {
return err
return 0, err
}
if co.cfg.malformRLP {
// Malform the RLP by incrementing the length prefix by 1.
......@@ -157,13 +157,13 @@ func (co *GarbageChannelOut) AddBlock(block *types.Block) error {
buf.Write(bufBytes)
}
if co.rlpLength+buf.Len() > derive.MaxRLPBytesPerChannel {
return fmt.Errorf("could not add %d bytes to channel of %d bytes, max is %d. err: %w",
return 0, fmt.Errorf("could not add %d bytes to channel of %d bytes, max is %d. err: %w",
buf.Len(), co.rlpLength, derive.MaxRLPBytesPerChannel, derive.ErrTooManyRLPBytes)
}
co.rlpLength += buf.Len()
_, err = io.Copy(co.compress, &buf)
return err
written, err := io.Copy(co.compress, &buf)
return uint64(written), err
}
// ReadyBytes returns the number of bytes that the channel out can immediately output into a frame.
......@@ -192,11 +192,12 @@ func (co *GarbageChannelOut) Close() error {
// Returns io.EOF when the channel is closed & there are no more frames
// Returns nil if there is still more buffered data.
// Returns and error if it ran into an error during processing.
func (co *GarbageChannelOut) OutputFrame(w *bytes.Buffer, maxSize uint64) error {
func (co *GarbageChannelOut) OutputFrame(w *bytes.Buffer, maxSize uint64) (uint16, error) {
f := derive.Frame{
ID: co.id,
FrameNumber: uint16(co.frame),
}
fn := f.FrameNumber
// Copy data from the local buffer into the frame data buffer
// Don't go past the maxSize with the fixed frame overhead.
......@@ -214,18 +215,18 @@ func (co *GarbageChannelOut) OutputFrame(w *bytes.Buffer, maxSize uint64) error
f.Data = make([]byte, maxDataSize)
if _, err := io.ReadFull(&co.buf, f.Data); err != nil {
return err
return fn, err
}
if err := f.MarshalBinary(w); err != nil {
return err
return fn, err
}
co.frame += 1
if f.IsLast {
return io.EOF
return fn, io.EOF
} else {
return nil
return fn, nil
}
}
......
......@@ -142,7 +142,7 @@ func (s *L2Batcher) ActL2BatchBuffer(t Testing) {
s.l2BufferedBlock = syncStatus.SafeL2.ID()
s.l2ChannelOut = nil
}
if err := s.l2ChannelOut.AddBlock(block); err != nil { // should always succeed
if _, err := s.l2ChannelOut.AddBlock(block); err != nil { // should always succeed
t.Fatalf("failed to add block to channel: %v", err)
}
s.l2BufferedBlock = eth.ToBlockID(block)
......@@ -168,7 +168,7 @@ func (s *L2Batcher) ActL2BatchSubmit(t Testing) {
data := new(bytes.Buffer)
data.WriteByte(derive.DerivationVersion0)
// subtract one, to account for the version byte
if err := s.l2ChannelOut.OutputFrame(data, s.l2BatcherCfg.MaxL1TxSize-1); err == io.EOF {
if _, err := s.l2ChannelOut.OutputFrame(data, s.l2BatcherCfg.MaxL1TxSize-1); err == io.EOF {
s.l2ChannelOut = nil
s.l2Submitting = false
} else if err != nil {
......@@ -218,7 +218,7 @@ func (s *L2Batcher) ActL2BatchSubmitGarbage(t Testing, kind GarbageKind) {
data.WriteByte(derive.DerivationVersion0)
// subtract one, to account for the version byte
if err := s.l2ChannelOut.OutputFrame(data, s.l2BatcherCfg.MaxL1TxSize-1); err == io.EOF {
if _, err := s.l2ChannelOut.OutputFrame(data, s.l2BatcherCfg.MaxL1TxSize-1); err == io.EOF {
s.l2ChannelOut = nil
s.l2Submitting = false
} else if err != nil {
......
package actions
import (
"context"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/metrics"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/rollup/driver"
)
// MockL1OriginSelector is a shim to override the origin as sequencer, so we can force it to stay on an older origin.
type MockL1OriginSelector struct {
actual *driver.L1OriginSelector
originOverride eth.L1BlockRef // override which origin gets picked
}
func (m *MockL1OriginSelector) FindL1Origin(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) {
if m.originOverride != (eth.L1BlockRef{}) {
return m.originOverride, nil
}
return m.actual.FindL1Origin(ctx, l2Head)
}
// L2Sequencer is an actor that functions like a rollup node,
// without the full P2P/API/Node stack, but just the derivation state, and simplified driver with sequencing ability.
type L2Sequencer struct {
L2Verifier
sequencer *driver.Sequencer
l1OriginSelector *driver.L1OriginSelector
seqOldOrigin bool // stay on current L1 origin when sequencing a block, unless forced to adopt the next origin
failL2GossipUnsafeBlock error // mock error
mockL1OriginSelector *MockL1OriginSelector
}
func NewL2Sequencer(t Testing, log log.Logger, l1 derive.L1Fetcher, eng L2API, cfg *rollup.Config, seqConfDepth uint64) *L2Sequencer {
ver := NewL2Verifier(t, log, l1, eng, cfg)
attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, eng)
seqConfDepthL1 := driver.NewConfDepth(seqConfDepth, ver.l1State.L1Head, l1)
l1OriginSelector := &MockL1OriginSelector{
actual: driver.NewL1OriginSelector(log, cfg, seqConfDepthL1),
}
return &L2Sequencer{
L2Verifier: *ver,
sequencer: driver.NewSequencer(log, cfg, eng, ver.derivation, attrBuilder, metrics.NoopMetrics),
l1OriginSelector: driver.NewL1OriginSelector(log, cfg, l1, seqConfDepth),
seqOldOrigin: false,
sequencer: driver.NewSequencer(log, cfg, ver.derivation, attrBuilder, l1OriginSelector),
mockL1OriginSelector: l1OriginSelector,
failL2GossipUnsafeBlock: nil,
}
}
......@@ -47,22 +63,7 @@ func (s *L2Sequencer) ActL2StartBlock(t Testing) {
return
}
parent := s.derivation.UnsafeL2Head()
var origin eth.L1BlockRef
if s.seqOldOrigin {
// force old origin, for testing purposes
oldOrigin, err := s.l1.L1BlockRefByHash(t.Ctx(), parent.L1Origin.Hash)
require.NoError(t, err, "failed to get current origin: %s", parent.L1Origin)
origin = oldOrigin
s.seqOldOrigin = false // don't repeat this
} else {
// select origin the real way
l1Origin, err := s.l1OriginSelector.FindL1Origin(t.Ctx(), s.l1State.L1Head(), parent)
require.NoError(t, err)
origin = l1Origin
}
err := s.sequencer.StartBuildingBlock(t.Ctx(), origin)
err := s.sequencer.StartBuildingBlock(t.Ctx())
require.NoError(t, err, "failed to start block building")
s.l2Building = true
......@@ -76,24 +77,21 @@ func (s *L2Sequencer) ActL2EndBlock(t Testing) {
}
s.l2Building = false
payload, err := s.sequencer.CompleteBuildingBlock(t.Ctx())
_, err := s.sequencer.CompleteBuildingBlock(t.Ctx())
// TODO: there may be legitimate temporary errors here, if we mock engine API RPC-failure.
// For advanced tests we can catch those and print a warning instead.
require.NoError(t, err)
ref, err := derive.PayloadToBlockRef(payload, &s.rollupCfg.Genesis)
require.NoError(t, err, "payload must convert to block ref")
s.derivation.SetUnsafeHead(ref)
// TODO: action-test publishing of payload on p2p
}
// ActL2KeepL1Origin makes the sequencer use the current L1 origin, even if the next origin is available.
func (s *L2Sequencer) ActL2KeepL1Origin(t Testing) {
if s.seqOldOrigin { // don't do this twice
t.InvalidAction("already decided to keep old L1 origin")
return
}
s.seqOldOrigin = true
parent := s.derivation.UnsafeL2Head()
// force old origin, for testing purposes
oldOrigin, err := s.l1.L1BlockRefByHash(t.Ctx(), parent.L1Origin.Hash)
require.NoError(t, err, "failed to get current origin: %s", parent.L1Origin)
s.mockL1OriginSelector.originOverride = oldOrigin
}
// ActBuildToL1Head builds empty blocks until (incl.) the L1 head becomes the L2 origin
......@@ -109,7 +107,7 @@ func (s *L2Sequencer) ActBuildToL1Head(t Testing) {
func (s *L2Sequencer) ActBuildToL1HeadExcl(t Testing) {
for {
s.ActL2PipelineFull(t)
nextOrigin, err := s.l1OriginSelector.FindL1Origin(t.Ctx(), s.l1State.L1Head(), s.derivation.UnsafeL2Head())
nextOrigin, err := s.mockL1OriginSelector.FindL1Origin(t.Ctx(), s.derivation.UnsafeL2Head())
require.NoError(t, err)
if nextOrigin.Number >= s.l1State.L1Head().Number {
break
......
......@@ -10,12 +10,12 @@ require (
github.com/docker/docker v20.10.21+incompatible
github.com/docker/go-connections v0.4.0
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3
github.com/ethereum-optimism/optimism/op-batcher v0.10.11
github.com/ethereum-optimism/optimism/op-bindings v0.10.11
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11
github.com/ethereum-optimism/optimism/op-node v0.10.11
github.com/ethereum-optimism/optimism/op-proposer v0.10.11
github.com/ethereum-optimism/optimism/op-service v0.10.11
github.com/ethereum-optimism/optimism/op-batcher v0.10.12
github.com/ethereum-optimism/optimism/op-bindings v0.10.12
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12
github.com/ethereum-optimism/optimism/op-node v0.10.12
github.com/ethereum-optimism/optimism/op-proposer v0.10.12
github.com/ethereum-optimism/optimism/op-service v0.10.12
github.com/ethereum/go-ethereum v1.10.26
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8
github.com/libp2p/go-libp2p v0.23.3
......
......@@ -161,18 +161,18 @@ github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-batcher v0.10.11 h1:aqTOE3UnTrX/rngXruT815CyRhcKi9kvZ4xJllW9l6I=
github.com/ethereum-optimism/optimism/op-batcher v0.10.11/go.mod h1:HIsxM0YihXGGImsUuPdI0T+L1LuS8UXgZnaZweXUGug=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 h1:RDiRyHo0G/UuxHZQdMJyqIuHtWvpionuFNfczNaWCcM=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11 h1:6ihrVPJYN1HvD4KG0Fk1zIJCM4ZB109kCu9fq81jznQ=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11/go.mod h1:6mub7Tx1cC4gDrfX9o9n+kA4R2qLlYvfWkG8es21EQI=
github.com/ethereum-optimism/optimism/op-node v0.10.11 h1:ED72b68ainzcXr5/cLOYRwv+LdE4hRDnkq3SmNRY1+Q=
github.com/ethereum-optimism/optimism/op-node v0.10.11/go.mod h1:/CDpkMxc3mDklZ1nqz2lmxfeUyAUz7yC/OLmX8egAUw=
github.com/ethereum-optimism/optimism/op-proposer v0.10.11 h1:uG+CXcac1LVRAnivv+3q7qJZDTgdKLv0D3mbu2o7nKI=
github.com/ethereum-optimism/optimism/op-proposer v0.10.11/go.mod h1:O/BolDMRNanlblBQKwq2UGwnl7hTdKrnVlmXfijG7vw=
github.com/ethereum-optimism/optimism/op-service v0.10.11 h1:o+SazhFXlE3EM9Re5KIPEQklZ9uTI8rNkjl0h5OwRtU=
github.com/ethereum-optimism/optimism/op-service v0.10.11/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c=
github.com/ethereum-optimism/optimism/op-batcher v0.10.12 h1:Vyb2oEujqokXiybaC64l+T5e0NpEMOC6rhXqIFIN8Oo=
github.com/ethereum-optimism/optimism/op-batcher v0.10.12/go.mod h1:ai4nZjD0aOOHWhLZj7R8KFttG9+EFsdxiELDuqwzrO4=
github.com/ethereum-optimism/optimism/op-bindings v0.10.12 h1:/B1gaCLwZYy9Rja3MiceV3R642bygp937kZjnYwRxA0=
github.com/ethereum-optimism/optimism/op-bindings v0.10.12/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12 h1:gRX5oIk0hboTOZ65y5MpEdM5+nmaad87QZP1donrHXo=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12/go.mod h1:x98mGAxXIhyYM4WsnbgziJCAk+qA4JX0wvaE+azBg48=
github.com/ethereum-optimism/optimism/op-node v0.10.12 h1:yOxMThwwz1rEDDM0xTjS+6jqJwgKRtrYM6h4Pdf0zno=
github.com/ethereum-optimism/optimism/op-node v0.10.12/go.mod h1:z+DiFb82Vnn5zM3VEwc2OXK2V/JBg6MLg7ejTbsxye8=
github.com/ethereum-optimism/optimism/op-proposer v0.10.12 h1:4K61QLg1mF38zwsaTQKOJnDqc65DKKsO33X20cLrhmk=
github.com/ethereum-optimism/optimism/op-proposer v0.10.12/go.mod h1:JBB9oVfhx9VjrBgcE5KIxCdQPnr7ma/xLBLYg2EFo9I=
github.com/ethereum-optimism/optimism/op-service v0.10.12 h1:Y7pR3/b8eeHYkmo2V5z7sj8jaraYqm2Azyph5lbiIxo=
github.com/ethereum-optimism/optimism/op-service v0.10.12/go.mod h1:Ibbun+aic0rjQBV8yBf9kohqIj6mQ8nSTWbZjHv+Q7Q=
github.com/ethereum-optimism/optimism/op-signer v0.1.0 h1:wH44Deai43YQWO0pEd44pDm3BahdAtSmrOHKiPvTB8Y=
github.com/ethereum-optimism/optimism/op-signer v0.1.0/go.mod h1:u8sN6X/c20pP9F1Ey7jH3fi19D08Y+T9ep3PGJfdyi8=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
......
......@@ -319,12 +319,14 @@ func TestMigration(t *testing.T) {
require.NoError(t, rollupNode.Close())
})
batcher, err := bss.NewBatchSubmitter(bss.Config{
batcher, err := bss.NewBatchSubmitterFromCLIConfig(bss.CLIConfig{
L1EthRpc: forkedL1URL,
L2EthRpc: gethNode.WSEndpoint(),
RollupRpc: rollupNode.HTTPEndpoint(),
MinL1TxSize: 1,
MaxL1TxSize: 120000,
MaxL1TxSize: 120_000,
TargetL1TxSize: 1,
TargetNumFrames: 1,
ApproxComprRatio: 1.0,
ChannelTimeout: deployCfg.ChannelTimeout,
PollInterval: 50 * time.Millisecond,
NumConfirmations: 1,
......
......@@ -522,12 +522,14 @@ func (cfg SystemConfig) Start() (*System, error) {
}
// Batch Submitter
sys.BatchSubmitter, err = bss.NewBatchSubmitter(bss.Config{
sys.BatchSubmitter, err = bss.NewBatchSubmitterFromCLIConfig(bss.CLIConfig{
L1EthRpc: sys.Nodes["l1"].WSEndpoint(),
L2EthRpc: sys.Nodes["sequencer"].WSEndpoint(),
RollupRpc: sys.RollupNodes["sequencer"].HTTPEndpoint(),
MinL1TxSize: 1,
MaxL1TxSize: 120000,
MaxL1TxSize: 120_000,
TargetL1TxSize: 1,
TargetNumFrames: 1,
ApproxComprRatio: 1.0,
ChannelTimeout: cfg.DeployConfig.ChannelTimeout,
PollInterval: 50 * time.Millisecond,
NumConfirmations: 1,
......
......@@ -883,7 +883,7 @@ func TestWithdrawals(t *testing.T) {
require.Nil(t, err)
// Get l2BlockNumber for proof generation
ctx, cancel = context.WithTimeout(context.Background(), 20*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
ctx, cancel = context.WithTimeout(context.Background(), 30*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel()
blockNumber, err := withdrawals.WaitForFinalizationPeriod(ctx, l1Client, predeploys.DevOptimismPortalAddr, receipt.BlockNumber)
require.Nil(t, err)
......@@ -933,7 +933,7 @@ func TestWithdrawals(t *testing.T) {
require.Equal(t, types.ReceiptStatusSuccessful, proveReceipt.Status)
// Wait for finalization and then create the Finalized Withdrawal Transaction
ctx, cancel = context.WithTimeout(context.Background(), 20*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
ctx, cancel = context.WithTimeout(context.Background(), 30*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel()
_, err = withdrawals.WaitForFinalizationPeriod(ctx, l1Client, predeploys.DevOptimismPortalAddr, header.Number)
require.Nil(t, err)
......@@ -1052,10 +1052,10 @@ func TestFees(t *testing.T) {
err = l2Seq.SendTransaction(context.Background(), tx)
require.Nil(t, err, "Sending L2 tx to sequencer")
_, err = waitForTransaction(tx.Hash(), l2Seq, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
_, err = waitForTransaction(tx.Hash(), l2Seq, 4*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on sequencer")
receipt, err := waitForTransaction(tx.Hash(), l2Verif, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
receipt, err := waitForTransaction(tx.Hash(), l2Verif, 4*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on verifier")
require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status, "TX should have succeeded")
......
......@@ -123,7 +123,7 @@ func RollupNodeMain(ctx *cli.Context) error {
if cfg.Heartbeat.Enabled {
var peerID string
if cfg.P2P == nil {
if cfg.P2P.Disabled() {
peerID = "disabled"
} else {
peerID = n.P2P().Host().ID().String()
......
......@@ -15,7 +15,7 @@ import (
type StorageProofEntry struct {
Key common.Hash `json:"key"`
Value hexutil.Bytes `json:"value"`
Value hexutil.Big `json:"value"`
Proof []hexutil.Bytes `json:"proof"`
}
......
......@@ -6,9 +6,9 @@ require (
github.com/btcsuite/btcd v0.23.3
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0
github.com/ethereum-optimism/optimism/op-bindings v0.10.11
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11
github.com/ethereum-optimism/optimism/op-service v0.10.11
github.com/ethereum-optimism/optimism/op-bindings v0.10.12
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12
github.com/ethereum-optimism/optimism/op-service v0.10.12
github.com/ethereum/go-ethereum v1.10.26
github.com/golang/snappy v0.0.4
github.com/google/go-cmp v0.5.8
......@@ -52,8 +52,7 @@ require (
github.com/fjl/memsize v0.0.1 // indirect
github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
......@@ -137,7 +136,6 @@ require (
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.5.0 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa // indirect
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
......@@ -151,7 +149,6 @@ require (
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
golang.org/x/tools v0.1.12 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
......
......@@ -145,12 +145,12 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 h1:RDiRyHo0G/UuxHZQdMJyqIuHtWvpionuFNfczNaWCcM=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11 h1:6ihrVPJYN1HvD4KG0Fk1zIJCM4ZB109kCu9fq81jznQ=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11/go.mod h1:6mub7Tx1cC4gDrfX9o9n+kA4R2qLlYvfWkG8es21EQI=
github.com/ethereum-optimism/optimism/op-service v0.10.11 h1:o+SazhFXlE3EM9Re5KIPEQklZ9uTI8rNkjl0h5OwRtU=
github.com/ethereum-optimism/optimism/op-service v0.10.11/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c=
github.com/ethereum-optimism/optimism/op-bindings v0.10.12 h1:/B1gaCLwZYy9Rja3MiceV3R642bygp937kZjnYwRxA0=
github.com/ethereum-optimism/optimism/op-bindings v0.10.12/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12 h1:gRX5oIk0hboTOZ65y5MpEdM5+nmaad87QZP1donrHXo=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12/go.mod h1:x98mGAxXIhyYM4WsnbgziJCAk+qA4JX0wvaE+azBg48=
github.com/ethereum-optimism/optimism/op-service v0.10.12 h1:Y7pR3/b8eeHYkmo2V5z7sj8jaraYqm2Azyph5lbiIxo=
github.com/ethereum-optimism/optimism/op-service v0.10.12/go.mod h1:Ibbun+aic0rjQBV8yBf9kohqIj6mQ8nSTWbZjHv+Q7Q=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
......@@ -160,10 +160,10 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
......@@ -587,7 +587,7 @@ github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg=
github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d h1:vmirMegf1vqPJ+lDBxLQ0MAt3tz+JL57UPxu44JBOjA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
......@@ -613,7 +613,6 @@ github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hM
github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+A=
github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw=
github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
......@@ -846,6 +845,7 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
......@@ -865,7 +865,6 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
......
......@@ -33,6 +33,7 @@ var DefaultBootnodes = []*enode.Node{
// SetupP2P provides a host and discovery service for usage in the rollup node.
type SetupP2P interface {
Check() error
Disabled() bool
// Host creates a libp2p host service. Returns nil, nil if p2p is disabled.
Host(log log.Logger, reporter metrics.Reporter) (host.Host, error)
// Discovery creates a disc-v5 service. Returns nil, nil, nil if discovery is disabled.
......@@ -134,6 +135,10 @@ func (conf *Config) TargetPeers() uint {
return conf.PeersLo
}
func (conf *Config) Disabled() bool {
return conf.DisableP2P
}
const maxMeshParam = 1000
func (conf *Config) Check() error {
......
......@@ -63,3 +63,7 @@ func (p *Prepared) Discovery(log log.Logger, rollupCfg *rollup.Config, tcpPort u
func (p *Prepared) ConfigureGossip(params *pubsub.GossipSubParams) []pubsub.Option {
return nil
}
func (p *Prepared) Disabled() bool {
return false
}
......@@ -64,39 +64,40 @@ func (co *ChannelOut) Reset() error {
co.compress.Reset(&co.buf)
co.closed = false
_, err := rand.Read(co.id[:])
if err != nil {
return err
}
return nil
}
// AddBlock adds a block to the channel. It returns an error
// if there is a problem adding the block. The only sentinel
// error that it returns is ErrTooManyRLPBytes. If this error
// is returned, the channel should be closed and a new one
// should be made.
func (co *ChannelOut) AddBlock(block *types.Block) error {
// AddBlock adds a block to the channel. It returns the RLP encoded byte size
// and an error if there is a problem adding the block. The only sentinel error
// that it returns is ErrTooManyRLPBytes. If this error is returned, the channel
// should be closed and a new one should be made.
func (co *ChannelOut) AddBlock(block *types.Block) (uint64, error) {
if co.closed {
return errors.New("already closed")
return 0, errors.New("already closed")
}
batch, err := blockToBatch(block)
if err != nil {
return err
return 0, err
}
// We encode to a temporary buffer to determine the encoded length to
// ensure that the total size of all RLP elements is less than or equal to MAX_RLP_BYTES_PER_CHANNEL
var buf bytes.Buffer
if err := rlp.Encode(&buf, batch); err != nil {
return err
return 0, err
}
if co.rlpLength+buf.Len() > MaxRLPBytesPerChannel {
return fmt.Errorf("could not add %d bytes to channel of %d bytes, max is %d. err: %w",
return 0, fmt.Errorf("could not add %d bytes to channel of %d bytes, max is %d. err: %w",
buf.Len(), co.rlpLength, MaxRLPBytesPerChannel, ErrTooManyRLPBytes)
}
co.rlpLength += buf.Len()
_, err = io.Copy(co.compress, &buf)
return err
written, err := io.Copy(co.compress, &buf)
return uint64(written), err
}
// InputBytes returns the total amount of RLP-encoded input bytes.
func (co *ChannelOut) InputBytes() int {
return co.rlpLength
}
// ReadyBytes returns the number of bytes that the channel out can immediately output into a frame.
......@@ -120,12 +121,13 @@ func (co *ChannelOut) Close() error {
return co.compress.Close()
}
// OutputFrame writes a frame to w with a given max size
// OutputFrame writes a frame to w with a given max size and returns the frame
// number.
// Use `ReadyBytes`, `Flush`, and `Close` to modify the ready buffer.
// Returns io.EOF when the channel is closed & there are no more frames
// Returns nil if there is still more buffered data.
// Returns and error if it ran into an error during processing.
func (co *ChannelOut) OutputFrame(w *bytes.Buffer, maxSize uint64) error {
func (co *ChannelOut) OutputFrame(w *bytes.Buffer, maxSize uint64) (uint16, error) {
f := Frame{
ID: co.id,
FrameNumber: uint16(co.frame),
......@@ -133,9 +135,8 @@ func (co *ChannelOut) OutputFrame(w *bytes.Buffer, maxSize uint64) error {
// Copy data from the local buffer into the frame data buffer
// Don't go past the maxSize with the fixed frame overhead.
// Fixed overhead: 32 + 8 + 2 + 4 + 1 = 47 bytes.
// Add one extra byte for the version byte (for the entire L1 tx though)
maxDataSize := maxSize - 47 - 1
// Fixed overhead: 16 + 2 + 4 + 1 = 23 bytes.
maxDataSize := maxSize - 23
if maxDataSize > uint64(co.buf.Len()) {
maxDataSize = uint64(co.buf.Len())
// If we are closed & will not spill past the current frame
......@@ -147,18 +148,19 @@ func (co *ChannelOut) OutputFrame(w *bytes.Buffer, maxSize uint64) error {
f.Data = make([]byte, maxDataSize)
if _, err := io.ReadFull(&co.buf, f.Data); err != nil {
return err
return 0, err
}
if err := f.MarshalBinary(w); err != nil {
return err
return 0, err
}
co.frame += 1
fn := f.FrameNumber
if f.IsLast {
return io.EOF
return fn, io.EOF
} else {
return nil
return fn, nil
}
}
......
......@@ -22,7 +22,7 @@ func TestChannelOutAddBlock(t *testing.T) {
},
nil,
)
err := cout.AddBlock(block)
_, err := cout.AddBlock(block)
require.Error(t, err)
require.Equal(t, ErrNotDepositTx, err)
})
......
......@@ -33,6 +33,31 @@ type Engine interface {
SystemConfigL2Fetcher
}
// EngineState provides a read-only interface of the forkchoice state properties of the L2 Engine.
type EngineState interface {
Finalized() eth.L2BlockRef
UnsafeL2Head() eth.L2BlockRef
SafeL2Head() eth.L2BlockRef
}
// EngineControl enables other components to build blocks with the Engine,
// while keeping the forkchoice state and payload-id management internal to
// avoid state inconsistencies between different users of the EngineControl.
type EngineControl interface {
EngineState
// StartPayload requests the engine to start building a block with the given attributes.
// If updateSafe, the resulting block will be marked as a safe block.
StartPayload(ctx context.Context, parent eth.L2BlockRef, attrs *eth.PayloadAttributes, updateSafe bool) (errType BlockInsertionErrType, err error)
// ConfirmPayload requests the engine to complete the current block. If no block is being built, or if it fails, an error is returned.
ConfirmPayload(ctx context.Context) (out *eth.ExecutionPayload, errTyp BlockInsertionErrType, err error)
// CancelPayload requests the engine to stop building the current block without making it canonical.
// This is optional, as the engine expires building jobs that are left uncompleted, but can still save resources.
CancelPayload(ctx context.Context, force bool) error
// BuildingPayload indicates if a payload is being built, and onto which block it is being built, and whether or not it is a safe payload.
BuildingPayload() (onto eth.L2BlockRef, id eth.PayloadID, safe bool)
}
// Max memory used for buffering unsafe payloads
const maxUnsafePayloadsMemory = 500 * 1024 * 1024
......@@ -68,6 +93,10 @@ type EngineQueue struct {
safeHead eth.L2BlockRef
unsafeHead eth.L2BlockRef
buildingOnto eth.L2BlockRef
buildingID eth.PayloadID
buildingSafe bool
// Track when the rollup node changes the forkchoice without engine action,
// e.g. on a reset after a reorg, or after consolidating a block.
// This update may repeat if the engine returns a temporary error.
......@@ -91,6 +120,8 @@ type EngineQueue struct {
l1Fetcher L1Fetcher
}
var _ EngineControl = (*EngineQueue)(nil)
// NewEngineQueue creates a new EngineQueue, which should be Reset(origin) before use.
func NewEngineQueue(log log.Logger, cfg *rollup.Config, engine Engine, metrics Metrics, prev NextAttributesProvider, l1Fetcher L1Fetcher) *EngineQueue {
return &EngineQueue{
......@@ -416,13 +447,11 @@ func (eq *EngineQueue) forceNextSafeAttributes(ctx context.Context) error {
if len(eq.safeAttributes) == 0 {
return nil
}
fc := eth.ForkchoiceState{
HeadBlockHash: eq.safeHead.Hash,
SafeBlockHash: eq.safeHead.Hash,
FinalizedBlockHash: eq.finalized.Hash,
}
attrs := eq.safeAttributes[0]
payload, errType, err := InsertHeadBlock(ctx, eq.log, eq.engine, fc, attrs, true)
errType, err := eq.StartPayload(ctx, eq.safeHead, attrs, true)
if err == nil {
_, errType, err = eq.ConfirmPayload(ctx)
}
if err != nil {
switch errType {
case BlockInsertTemporaryErr:
......@@ -457,21 +486,89 @@ func (eq *EngineQueue) forceNextSafeAttributes(ctx context.Context) error {
return NewCriticalError(fmt.Errorf("unknown InsertHeadBlock error type %d: %w", errType, err))
}
}
eq.safeAttributes = eq.safeAttributes[1:]
eq.logSyncProgress("processed safe block derived from L1")
return nil
}
func (eq *EngineQueue) StartPayload(ctx context.Context, parent eth.L2BlockRef, attrs *eth.PayloadAttributes, updateSafe bool) (errType BlockInsertionErrType, err error) {
if eq.buildingID != (eth.PayloadID{}) {
eq.log.Warn("did not finish previous block building, starting new building now", "prev_onto", eq.buildingOnto, "prev_payload_id", eq.buildingID, "new_onto", parent)
// TODO: maybe worth it to force-cancel the old payload ID here.
}
fc := eth.ForkchoiceState{
HeadBlockHash: parent.Hash,
SafeBlockHash: eq.safeHead.Hash,
FinalizedBlockHash: eq.finalized.Hash,
}
id, errTyp, err := StartPayload(ctx, eq.engine, fc, attrs)
if err != nil {
return errTyp, err
}
eq.buildingID = id
eq.buildingSafe = updateSafe
eq.buildingOnto = parent
return BlockInsertOK, nil
}
func (eq *EngineQueue) ConfirmPayload(ctx context.Context) (out *eth.ExecutionPayload, errTyp BlockInsertionErrType, err error) {
if eq.buildingID == (eth.PayloadID{}) {
return nil, BlockInsertPrestateErr, fmt.Errorf("cannot complete payload building: not currently building a payload")
}
if eq.buildingOnto.Hash != eq.unsafeHead.Hash { // E.g. when safe-attributes consolidation fails, it will drop the existing work.
eq.log.Warn("engine is building block that reorgs previous usafe head", "onto", eq.buildingOnto, "unsafe", eq.unsafeHead)
}
fc := eth.ForkchoiceState{
HeadBlockHash: common.Hash{}, // gets overridden
SafeBlockHash: eq.safeHead.Hash,
FinalizedBlockHash: eq.finalized.Hash,
}
payload, errTyp, err := ConfirmPayload(ctx, eq.log, eq.engine, fc, eq.buildingID, eq.buildingSafe)
if err != nil {
return nil, errTyp, fmt.Errorf("failed to complete building on top of L2 chain %s, id: %s, error (%d): %w", eq.buildingOnto, eq.buildingID, errTyp, err)
}
ref, err := PayloadToBlockRef(payload, &eq.cfg.Genesis)
if err != nil {
return NewTemporaryError(fmt.Errorf("failed to decode L2 block ref from payload: %w", err))
return nil, BlockInsertPayloadErr, NewResetError(fmt.Errorf("failed to decode L2 block ref from payload: %w", err))
}
eq.safeHead = ref
eq.unsafeHead = ref
eq.metrics.RecordL2Ref("l2_safe", ref)
eq.metrics.RecordL2Ref("l2_unsafe", ref)
eq.safeAttributes = eq.safeAttributes[1:]
if eq.buildingSafe {
eq.safeHead = ref
eq.postProcessSafeL2()
eq.logSyncProgress("processed safe block derived from L1")
eq.metrics.RecordL2Ref("l2_safe", ref)
}
eq.resetBuildingState()
return payload, BlockInsertOK, nil
}
func (eq *EngineQueue) CancelPayload(ctx context.Context, force bool) error {
// the building job gets wrapped up as soon as the payload is retrieved, there's no explicit cancel in the Engine API
eq.log.Error("cancelling old block sealing job", "payload", eq.buildingID)
_, err := eq.engine.GetPayload(ctx, eq.buildingID)
if err != nil {
eq.log.Error("failed to cancel block building job", "payload", eq.buildingID, "err", err)
if !force {
return err
}
}
eq.resetBuildingState()
return nil
}
func (eq *EngineQueue) BuildingPayload() (onto eth.L2BlockRef, id eth.PayloadID, safe bool) {
return eq.buildingOnto, eq.buildingID, eq.buildingSafe
}
func (eq *EngineQueue) resetBuildingState() {
eq.buildingID = eth.PayloadID{}
eq.buildingOnto = eth.L2BlockRef{}
eq.buildingSafe = false
}
// ResetStep Walks the L2 chain backwards until it finds an L2 block whose L1 origin is canonical.
// The unsafe head is set to the head of the L2 chain, unless the existing safe head is not canonical.
func (eq *EngineQueue) Reset(ctx context.Context, _ eth.L1BlockRef, _ eth.SystemConfig) error {
......@@ -517,6 +614,7 @@ func (eq *EngineQueue) Reset(ctx context.Context, _ eth.L1BlockRef, _ eth.System
eq.unsafeHead = unsafe
eq.safeHead = safe
eq.finalized = finalized
eq.resetBuildingState()
eq.needForkchoiceUpdate = true
eq.finalityData = eq.finalityData[:0]
// note: we do not clear the unsafe payloads queue; if the payloads are not applicable anymore the parent hash checks will clear out the old payloads.
......
......@@ -79,19 +79,6 @@ const (
BlockInsertPayloadErr
)
// InsertHeadBlock creates, executes, and inserts the specified block as the head block.
// It first uses the given FC to start the block creation process and then after the payload is executed,
// sets the FC to the same safe and finalized hashes, but updates the head hash to the new block.
// If updateSafe is true, the head block is considered to be the safe head as well as the head.
// It returns the payload, an RPC error (if the payload might still be valid), and a payload error (if the payload was not valid)
func InsertHeadBlock(ctx context.Context, log log.Logger, eng Engine, fc eth.ForkchoiceState, attrs *eth.PayloadAttributes, updateSafe bool) (out *eth.ExecutionPayload, errTyp BlockInsertionErrType, err error) {
id, errTyp, err := StartPayload(ctx, eng, fc, attrs)
if err != nil {
return nil, errTyp, err
}
return ConfirmPayload(ctx, log, eng, fc, id, updateSafe)
}
// StartPayload starts an execution payload building process in the provided Engine, with the given attributes.
// The severity of the error is distinguished to determine whether the same payload attributes may be re-attempted later.
func StartPayload(ctx context.Context, eng Engine, fc eth.ForkchoiceState, attrs *eth.PayloadAttributes) (id eth.PayloadID, errType BlockInsertionErrType, err error) {
......
......@@ -31,6 +31,8 @@ type ResetableStage interface {
}
type EngineQueueStage interface {
EngineControl
FinalizedL1() eth.L1BlockRef
Finalized() eth.L2BlockRef
UnsafeL2Head() eth.L2BlockRef
......@@ -130,8 +132,20 @@ func (dp *DerivationPipeline) UnsafeL2Head() eth.L2BlockRef {
return dp.eng.UnsafeL2Head()
}
func (dp *DerivationPipeline) SetUnsafeHead(head eth.L2BlockRef) {
dp.eng.SetUnsafeHead(head)
func (dp *DerivationPipeline) StartPayload(ctx context.Context, parent eth.L2BlockRef, attrs *eth.PayloadAttributes, updateSafe bool) (errType BlockInsertionErrType, err error) {
return dp.eng.StartPayload(ctx, parent, attrs, updateSafe)
}
func (dp *DerivationPipeline) ConfirmPayload(ctx context.Context) (out *eth.ExecutionPayload, errTyp BlockInsertionErrType, err error) {
return dp.eng.ConfirmPayload(ctx)
}
func (dp *DerivationPipeline) CancelPayload(ctx context.Context, force bool) error {
return dp.eng.CancelPayload(ctx, force)
}
func (dp *DerivationPipeline) BuildingPayload() (onto eth.L2BlockRef, id eth.PayloadID, safe bool) {
return dp.eng.BuildingPayload()
}
// AddUnsafePayload schedules an execution payload to be processed, ahead of deriving it from L1
......
......@@ -14,7 +14,6 @@ import (
type Metrics interface {
RecordPipelineReset()
RecordSequencingError()
RecordPublishingError()
RecordDerivationError()
......@@ -28,9 +27,8 @@ type Metrics interface {
SetDerivationIdle(idle bool)
RecordL1ReorgDepth(d uint64)
CountSequencedTxs(count int)
SequencerMetrics
EngineMetrics
}
type L1Chain interface {
......@@ -48,7 +46,6 @@ type L2Chain interface {
type DerivationPipeline interface {
Reset()
Step(ctx context.Context) error
SetUnsafeHead(head eth.L2BlockRef)
AddUnsafePayload(payload *eth.ExecutionPayload)
Finalize(ref eth.L1BlockRef)
FinalizedL1() eth.L1BlockRef
......@@ -68,14 +65,12 @@ type L1StateIface interface {
L1Finalized() eth.L1BlockRef
}
type L1OriginSelectorIface interface {
FindL1Origin(ctx context.Context, l1Head eth.L1BlockRef, l2Head eth.L2BlockRef) (eth.L1BlockRef, error)
}
type SequencerIface interface {
StartBuildingBlock(ctx context.Context, l1Origin eth.L1BlockRef) error
StartBuildingBlock(ctx context.Context) error
CompleteBuildingBlock(ctx context.Context) (*eth.ExecutionPayload, error)
PlanNextSequencerAction(sequenceErr error) (delay time.Duration, seal bool, onto eth.BlockID)
PlanNextSequencerAction() time.Duration
RunNextSequencerAction(ctx context.Context) *eth.ExecutionPayload
BuildingOnto() eth.L2BlockRef
}
type Network interface {
......@@ -86,11 +81,15 @@ type Network interface {
// NewDriver composes an events handler that tracks L1 state, triggers L2 derivation, and optionally sequences new L2 blocks.
func NewDriver(driverCfg *Config, cfg *rollup.Config, l2 L2Chain, l1 L1Chain, network Network, log log.Logger, snapshotLog log.Logger, metrics Metrics) *Driver {
l1State := NewL1State(log, metrics)
findL1Origin := NewL1OriginSelector(log, cfg, l1, driverCfg.SequencerConfDepth)
sequencerConfDepth := NewConfDepth(driverCfg.SequencerConfDepth, l1State.L1Head, l1)
findL1Origin := NewL1OriginSelector(log, cfg, sequencerConfDepth)
verifConfDepth := NewConfDepth(driverCfg.VerifierConfDepth, l1State.L1Head, l1)
derivationPipeline := derive.NewDerivationPipeline(log, cfg, verifConfDepth, l2, metrics)
attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, l2)
sequencer := NewSequencer(log, cfg, l2, derivationPipeline, attrBuilder, metrics)
engine := derivationPipeline
meteredEngine := NewMeteredEngine(cfg, engine, metrics, log)
sequencer := NewSequencer(log, cfg, meteredEngine, attrBuilder, findL1Origin)
return &Driver{
l1State: l1State,
derivation: derivationPipeline,
......@@ -106,7 +105,6 @@ func NewDriver(driverCfg *Config, cfg *rollup.Config, l2 L2Chain, l1 L1Chain, ne
snapshotLog: snapshotLog,
l1: l1,
l2: l2,
l1OriginSelector: findL1Origin,
sequencer: sequencer,
network: network,
metrics: metrics,
......
package driver
import (
"context"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
)
type EngineMetrics interface {
RecordSequencingError()
CountSequencedTxs(count int)
RecordSequencerBuildingDiffTime(duration time.Duration)
RecordSequencerSealingTime(duration time.Duration)
}
// MeteredEngine wraps an EngineControl and adds metrics such as block building time diff and sealing time
type MeteredEngine struct {
inner derive.EngineControl
cfg *rollup.Config
metrics EngineMetrics
log log.Logger
buildingStartTime time.Time
}
// MeteredEngine implements derive.EngineControl
var _ derive.EngineControl = (*MeteredEngine)(nil)
func NewMeteredEngine(cfg *rollup.Config, inner derive.EngineControl, metrics EngineMetrics, log log.Logger) *MeteredEngine {
return &MeteredEngine{
inner: inner,
cfg: cfg,
metrics: metrics,
log: log,
}
}
func (m *MeteredEngine) Finalized() eth.L2BlockRef {
return m.inner.Finalized()
}
func (m *MeteredEngine) UnsafeL2Head() eth.L2BlockRef {
return m.inner.UnsafeL2Head()
}
func (m *MeteredEngine) SafeL2Head() eth.L2BlockRef {
return m.inner.SafeL2Head()
}
func (m *MeteredEngine) StartPayload(ctx context.Context, parent eth.L2BlockRef, attrs *eth.PayloadAttributes, updateSafe bool) (errType derive.BlockInsertionErrType, err error) {
m.buildingStartTime = time.Now()
errType, err = m.inner.StartPayload(ctx, parent, attrs, updateSafe)
if err != nil {
m.metrics.RecordSequencingError()
}
return errType, err
}
func (m *MeteredEngine) ConfirmPayload(ctx context.Context) (out *eth.ExecutionPayload, errTyp derive.BlockInsertionErrType, err error) {
sealingStart := time.Now()
// Actually execute the block and add it to the head of the chain.
payload, errType, err := m.inner.ConfirmPayload(ctx)
if err != nil {
m.metrics.RecordSequencingError()
return payload, errType, err
}
now := time.Now()
sealTime := now.Sub(sealingStart)
buildTime := now.Sub(m.buildingStartTime)
m.metrics.RecordSequencerSealingTime(sealTime)
m.metrics.RecordSequencerBuildingDiffTime(buildTime - time.Duration(m.cfg.BlockTime)*time.Second)
m.metrics.CountSequencedTxs(len(payload.Transactions))
ref := m.inner.UnsafeL2Head()
m.log.Debug("Processed new L2 block", "l2_unsafe", ref, "l1_origin", ref.L1Origin,
"txs", len(payload.Transactions), "time", ref.Time, "seal_time", sealTime, "build_time", buildTime)
return payload, errType, err
}
func (m *MeteredEngine) CancelPayload(ctx context.Context, force bool) error {
return m.inner.CancelPayload(ctx, force)
}
func (m *MeteredEngine) BuildingPayload() (onto eth.L2BlockRef, id eth.PayloadID, safe bool) {
return m.inner.BuildingPayload()
}
......@@ -2,7 +2,10 @@ package driver
import (
"context"
"errors"
"fmt"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-node/eth"
......@@ -20,62 +23,48 @@ type L1OriginSelector struct {
cfg *rollup.Config
l1 L1Blocks
sequencingConfDepth uint64
}
func NewL1OriginSelector(log log.Logger, cfg *rollup.Config, l1 L1Blocks, sequencingConfDepth uint64) *L1OriginSelector {
func NewL1OriginSelector(log log.Logger, cfg *rollup.Config, l1 L1Blocks) *L1OriginSelector {
return &L1OriginSelector{
log: log,
cfg: cfg,
l1: l1,
sequencingConfDepth: sequencingConfDepth,
}
}
// FindL1Origin determines what the next L1 Origin should be.
// The L1 Origin is either the L2 Head's Origin, or the following L1 block
// if the next L2 block's time is greater than or equal to the L2 Head's Origin.
func (los *L1OriginSelector) FindL1Origin(ctx context.Context, l1Head eth.L1BlockRef, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) {
// If we are at the head block, don't do a lookup.
if l2Head.L1Origin.Hash == l1Head.Hash {
return l1Head, nil
}
// Grab a reference to the current L1 origin block.
func (los *L1OriginSelector) FindL1Origin(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) {
// Grab a reference to the current L1 origin block. This call is by hash and thus easily cached.
currentOrigin, err := los.l1.L1BlockRefByHash(ctx, l2Head.L1Origin.Hash)
if err != nil {
return eth.L1BlockRef{}, err
}
log := los.log.New("current", currentOrigin, "current_time", currentOrigin.Time,
"l2_head", l2Head, "l2_head_time", l2Head.Time)
// If we are past the sequencer depth, we may want to advance the origin, but need to still
// check the time of the next origin.
pastSeqDrift := l2Head.Time+los.cfg.BlockTime > currentOrigin.Time+los.cfg.MaxSequencerDrift
if pastSeqDrift {
log.Info("Next L2 block time is past the sequencer drift + current origin time",
"current", currentOrigin, "current_time", currentOrigin.Time,
"l1_head", l1Head, "l1_head_time", l1Head.Time,
"l2_head", l2Head, "l2_head_time", l2Head.Time,
"depth", los.sequencingConfDepth)
}
if !pastSeqDrift && currentOrigin.Number+1+los.sequencingConfDepth > l1Head.Number {
// TODO: we can decide to ignore confirmation depth if we would be forced
// to make an empty block (only deposits) by staying on the current origin.
log.Info("sequencing with old origin to preserve conf depth",
"current", currentOrigin, "current_time", currentOrigin.Time,
"l1_head", l1Head, "l1_head_time", l1Head.Time,
"l2_head", l2Head, "l2_head_time", l2Head.Time,
"depth", los.sequencingConfDepth)
return currentOrigin, nil
log.Warn("Next L2 block time is past the sequencer drift + current origin time")
}
// Attempt to find the next L1 origin block, where the next origin is the immediate child of
// the current origin block.
// The L1 source can be shimmed to hide new L1 blocks and enforce a sequencer confirmation distance.
nextOrigin, err := los.l1.L1BlockRefByNumber(ctx, currentOrigin.Number+1)
if err != nil {
// TODO: this could result in a bad origin being selected if we are past the seq
// drift & should instead advance to the next origin.
if pastSeqDrift {
return eth.L1BlockRef{}, fmt.Errorf("cannot build next L2 block past current L1 origin %s by more than sequencer time drift, and failed to find next L1 origin: %w", currentOrigin, err)
}
if errors.Is(err, ethereum.NotFound) {
log.Debug("No next L1 block found, repeating current origin")
} else {
log.Error("Failed to get next origin. Falling back to current origin", "err", err)
}
return currentOrigin, nil
}
......
......@@ -27,6 +27,7 @@ func TestOriginSelectorAdvances(t *testing.T) {
BlockTime: 2,
}
l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{
Hash: common.Hash{'a'},
Number: 10,
......@@ -46,9 +47,8 @@ func TestOriginSelectorAdvances(t *testing.T) {
l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil)
s := NewL1OriginSelector(log, cfg, l1, 0)
next, err := s.FindL1Origin(context.Background(), b, l2Head)
s := NewL1OriginSelector(log, cfg, l1)
next, err := s.FindL1Origin(context.Background(), l2Head)
require.Nil(t, err)
require.Equal(t, b, next)
}
......@@ -68,6 +68,7 @@ func TestOriginSelectorRespectsOriginTiming(t *testing.T) {
BlockTime: 2,
}
l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{
Hash: common.Hash{'a'},
Number: 10,
......@@ -87,15 +88,14 @@ func TestOriginSelectorRespectsOriginTiming(t *testing.T) {
l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil)
s := NewL1OriginSelector(log, cfg, l1, 0)
next, err := s.FindL1Origin(context.Background(), b, l2Head)
s := NewL1OriginSelector(log, cfg, l1)
next, err := s.FindL1Origin(context.Background(), l2Head)
require.Nil(t, err)
require.Equal(t, a, next)
}
// TestOriginSelectorRespectsConfDepth ensures that the origin selector
// will respects the confirmation depth requirement
// will respect the confirmation depth requirement
//
// There are 2 L1 blocks at time 20 & 25. The L2 Head is at time 27.
// The next L2 time is 29 which enough to normally select block `b`
......@@ -108,6 +108,7 @@ func TestOriginSelectorRespectsConfDepth(t *testing.T) {
BlockTime: 2,
}
l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{
Hash: common.Hash{'a'},
Number: 10,
......@@ -125,33 +126,32 @@ func TestOriginSelectorRespectsConfDepth(t *testing.T) {
}
l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil)
s := NewL1OriginSelector(log, cfg, l1, 10)
confDepthL1 := NewConfDepth(10, func() eth.L1BlockRef { return b }, l1)
s := NewL1OriginSelector(log, cfg, confDepthL1)
next, err := s.FindL1Origin(context.Background(), b, l2Head)
next, err := s.FindL1Origin(context.Background(), l2Head)
require.Nil(t, err)
require.Equal(t, a, next)
}
// TestOriginSelectorRespectsMaxSeqDrift ensures that the origin selector
// will advance if the time delta between the current L1 origin and the next
// L2 block is greater than the sequencer drift. This needs to occur even
// if conf depth needs to be ignored
// TestOriginSelectorStrictConfDepth ensures that the origin selector will maintain the sequencer conf depth,
// even while the time delta between the current L1 origin and the next
// L2 block is greater than the sequencer drift.
// It's more important to maintain safety with an empty block than to maintain liveness with poor conf depth.
//
// There are 2 L1 blocks at time 20 & 25. The L2 Head is at time 27.
// The next L2 time is 29. The sequencer drift is 8 so the L2 head is
// valid with origin `a`, but the next L2 block is not valid with origin `b.`
// This is because 29 (next L2 time) > 20 (origin) + 8 (seq drift) => invalid block.
// Even though the LOS would normally refuse to advance because block `b` does not
// have enough confirmations, it should in this instance.
func TestOriginSelectorRespectsMaxSeqDrift(t *testing.T) {
// We maintain confirmation distance, even though we would shift to the next origin if we could.
func TestOriginSelectorStrictConfDepth(t *testing.T) {
log := testlog.Logger(t, log.LvlCrit)
cfg := &rollup.Config{
MaxSequencerDrift: 8,
BlockTime: 2,
}
l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{
Hash: common.Hash{'a'},
Number: 10,
......@@ -169,13 +169,11 @@ func TestOriginSelectorRespectsMaxSeqDrift(t *testing.T) {
}
l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil)
s := NewL1OriginSelector(log, cfg, l1, 10)
confDepthL1 := NewConfDepth(10, func() eth.L1BlockRef { return b }, l1)
s := NewL1OriginSelector(log, cfg, confDepthL1)
next, err := s.FindL1Origin(context.Background(), b, l2Head)
require.Nil(t, err)
require.Equal(t, b, next)
_, err := s.FindL1Origin(context.Background(), l2Head)
require.ErrorContains(t, err, "sequencer time drift")
}
// TestOriginSelectorSeqDriftRespectsNextOriginTime
......@@ -191,6 +189,7 @@ func TestOriginSelectorSeqDriftRespectsNextOriginTime(t *testing.T) {
BlockTime: 2,
}
l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{
Hash: common.Hash{'a'},
Number: 10,
......@@ -210,9 +209,76 @@ func TestOriginSelectorSeqDriftRespectsNextOriginTime(t *testing.T) {
l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil)
s := NewL1OriginSelector(log, cfg, l1, 10)
next, err := s.FindL1Origin(context.Background(), b, l2Head)
s := NewL1OriginSelector(log, cfg, l1)
next, err := s.FindL1Origin(context.Background(), l2Head)
require.Nil(t, err)
require.Equal(t, a, next)
}
// TestOriginSelectorHandlesLateL1Blocks tests the forced repeat of the previous origin,
// but with a conf depth that first prevents it from learning about the need to repeat.
//
// There are 2 L1 blocks at time 20 & 100. The L2 Head is at time 27.
// The next L2 time is 29. Even though the next L2 time is past the seq
// drift, the origin should remain on block `a` because the next origin's
// time is greater than the next L2 time.
// Due to a conf depth of 2, block `b` is not immediately visible,
// and the origin selection should fail until it is visible, by waiting for block `c`.
func TestOriginSelectorHandlesLateL1Blocks(t *testing.T) {
log := testlog.Logger(t, log.LvlCrit)
cfg := &rollup.Config{
MaxSequencerDrift: 8,
BlockTime: 2,
}
l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{
Hash: common.Hash{'a'},
Number: 10,
Time: 20,
}
b := eth.L1BlockRef{
Hash: common.Hash{'b'},
Number: 11,
Time: 100,
ParentHash: a.Hash,
}
c := eth.L1BlockRef{
Hash: common.Hash{'c'},
Number: 12,
Time: 150,
ParentHash: b.Hash,
}
d := eth.L1BlockRef{
Hash: common.Hash{'d'},
Number: 13,
Time: 200,
ParentHash: c.Hash,
}
l2Head := eth.L2BlockRef{
L1Origin: a.ID(),
Time: 27,
}
// l2 head does not change, so we start at the same origin again and again until we meet the conf depth
l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil)
l1Head := b
confDepthL1 := NewConfDepth(2, func() eth.L1BlockRef { return l1Head }, l1)
s := NewL1OriginSelector(log, cfg, confDepthL1)
_, err := s.FindL1Origin(context.Background(), l2Head)
require.ErrorContains(t, err, "sequencer time drift")
l1Head = c
_, err = s.FindL1Origin(context.Background(), l2Head)
require.ErrorContains(t, err, "sequencer time drift")
l1Head = d
next, err := s.FindL1Origin(context.Background(), l2Head)
require.Nil(t, err)
require.Equal(t, a, next, "must stay on a because the L1 time may not be higher than the L2 time")
}
This diff is collapsed.
This diff is collapsed.
......@@ -25,8 +25,6 @@ type SyncStatus = eth.SyncStatus
// sealingDuration defines the expected time it takes to seal the block
const sealingDuration = time.Millisecond * 50
var UninitializedL1StateErr = errors.New("the L1 Head in L1 State is not initialized yet")
type Driver struct {
l1State L1StateIface
......@@ -73,7 +71,6 @@ type Driver struct {
l1 L1Chain
l2 L2Chain
l1OriginSelector L1OriginSelectorIface
sequencer SequencerIface
network Network // may be nil, network for is optional
......@@ -142,75 +139,6 @@ func (s *Driver) OnUnsafeL2Payload(ctx context.Context, payload *eth.ExecutionPa
}
}
// startNewL2Block starts sequencing a new L2 block on top of the unsafe L2 Head.
func (s *Driver) startNewL2Block(ctx context.Context) error {
l2Head := s.derivation.UnsafeL2Head()
l1Head := s.l1State.L1Head()
if l1Head == (eth.L1BlockRef{}) {
return UninitializedL1StateErr
}
// Figure out which L1 origin block we're going to be building on top of.
l1Origin, err := s.l1OriginSelector.FindL1Origin(ctx, l1Head, l2Head)
if err != nil {
s.log.Error("Error finding next L1 Origin", "err", err)
return err
}
// Rollup is configured to not start producing blocks until a specific L1 block has been
// reached. Don't produce any blocks until we're at that genesis block.
if l1Origin.Number < s.config.Genesis.L1.Number {
s.log.Info("Skipping block production because the next L1 Origin is behind the L1 genesis", "next", l1Origin.ID(), "genesis", s.config.Genesis.L1)
return fmt.Errorf("the L1 origin %s cannot be before genesis at %s", l1Origin, s.config.Genesis.L1)
}
// Should never happen. Sequencer will halt if we get into this situation somehow.
nextL2Time := l2Head.Time + s.config.BlockTime
if nextL2Time < l1Origin.Time {
s.log.Error("Cannot build L2 block for time before L1 origin",
"l2Unsafe", l2Head, "nextL2Time", nextL2Time, "l1Origin", l1Origin, "l1OriginTime", l1Origin.Time)
return fmt.Errorf("cannot build L2 block on top %s for time %d before L1 origin %s at time %d",
l2Head, nextL2Time, l1Origin, l1Origin.Time)
}
// Start creating the new block.
return s.sequencer.StartBuildingBlock(ctx, l1Origin)
}
// completeNewBlock completes a previously started L2 block sequencing job.
func (s *Driver) completeNewBlock(ctx context.Context) error {
payload, err := s.sequencer.CompleteBuildingBlock(ctx)
if err != nil {
s.metrics.RecordSequencingError()
s.log.Error("Failed to seal block as sequencer", "err", err)
return err
}
// Generate an L2 block ref from the payload.
newUnsafeL2Head, err := derive.PayloadToBlockRef(payload, &s.config.Genesis)
if err != nil {
s.metrics.RecordSequencingError()
s.log.Error("Sequenced payload cannot be transformed into valid L2 block reference", "err", err)
return fmt.Errorf("sequenced payload cannot be transformed into valid L2 block reference: %w", err)
}
// Update our L2 head block based on the new unsafe block we just generated.
s.derivation.SetUnsafeHead(newUnsafeL2Head)
s.log.Info("Sequenced new l2 block", "l2_unsafe", newUnsafeL2Head, "l1_origin", newUnsafeL2Head.L1Origin, "txs", len(payload.Transactions), "time", newUnsafeL2Head.Time)
s.metrics.CountSequencedTxs(len(payload.Transactions))
if s.network != nil {
if err := s.network.PublishL2Payload(ctx, payload); err != nil {
s.log.Warn("failed to publish newly created block", "id", payload.ID(), "err", err)
s.metrics.RecordPublishingError()
// publishing of unsafe data via p2p is optional. Errors are not severe enough to change/halt sequencing but should be logged and metered.
}
}
return nil
}
// the eventLoop responds to L1 changes and internal timers to produce L2 blocks.
func (s *Driver) eventLoop() {
defer s.wg.Done()
......@@ -259,34 +187,23 @@ func (s *Driver) eventLoop() {
// L1 chain that we need to handle.
reqStep()
blockTime := time.Duration(s.config.BlockTime) * time.Second
var sequenceErr error
var sequenceErrTime time.Time
sequencerTimer := time.NewTimer(0)
var sequencerCh <-chan time.Time
var sequencingPlannedOnto eth.BlockID
var sequencerSealNext bool
planSequencerAction := func() {
delay, seal, onto := s.sequencer.PlanNextSequencerAction(sequenceErr)
if sequenceErr != nil && time.Since(sequenceErrTime) > delay {
sequenceErr = nil
}
delay := s.sequencer.PlanNextSequencerAction()
sequencerCh = sequencerTimer.C
if len(sequencerCh) > 0 { // empty if not already drained before resetting
<-sequencerCh
}
sequencerTimer.Reset(delay)
sequencingPlannedOnto = onto
sequencerSealNext = seal
}
for {
// If we are sequencing, update the trigger for the next sequencer action.
// If we are sequencing, and the L1 state is ready, update the trigger for the next sequencer action.
// This may adjust at any time based on fork-choice changes or previous errors.
if s.driverConfig.SequencerEnabled && !s.driverConfig.SequencerStopped {
if s.driverConfig.SequencerEnabled && !s.driverConfig.SequencerStopped && s.l1State.L1Head() != (eth.L1BlockRef{}) {
// update sequencer time if the head changed
if sequencingPlannedOnto != s.derivation.UnsafeL2Head().ID() {
if s.sequencer.BuildingOnto().ID() != s.derivation.UnsafeL2Head().ID() {
planSequencerAction()
}
} else {
......@@ -295,22 +212,14 @@ func (s *Driver) eventLoop() {
select {
case <-sequencerCh:
s.log.Info("sequencing now!", "seal", sequencerSealNext, "idle_derivation", s.idleDerivation)
if sequencerSealNext {
// try to seal the current block task, and allow it to take up to 3 block times.
// If this fails we will simply start a new block building job.
ctx, cancel := context.WithTimeout(ctx, 3*blockTime)
sequenceErr = s.completeNewBlock(ctx)
cancel()
} else {
// Start the block building, don't allow the starting of sequencing to get stuck for more the time of 1 block.
ctx, cancel := context.WithTimeout(ctx, blockTime)
sequenceErr = s.startNewL2Block(ctx)
cancel()
payload := s.sequencer.RunNextSequencerAction(ctx)
if s.network != nil && payload != nil {
// Publishing of unsafe data via p2p is optional.
// Errors are not severe enough to change/halt sequencing but should be logged and metered.
if err := s.network.PublishL2Payload(ctx, payload); err != nil {
s.log.Warn("failed to publish newly created block", "id", payload.ID(), "err", err)
s.metrics.RecordPublishingError()
}
if sequenceErr != nil {
s.log.Error("sequencing error", "err", sequenceErr)
sequenceErrTime = time.Now()
}
planSequencerAction() // schedule the next sequencer action to keep the sequencing looping
case payload := <-s.unsafeL2Payloads:
......@@ -386,8 +295,8 @@ func (s *Driver) eventLoop() {
} else {
s.log.Info("Sequencer has been started")
s.driverConfig.SequencerStopped = false
sequencingPlannedOnto = eth.BlockID{}
close(resp.err)
planSequencerAction() // resume sequencing
}
case respCh := <-s.stopSequencer:
if s.driverConfig.SequencerStopped {
......
This diff is collapsed.
......@@ -359,7 +359,8 @@ func (s *EthClient) ReadStorageAt(ctx context.Context, address common.Address, s
if err := result.Verify(block.Root()); err != nil {
return common.Hash{}, fmt.Errorf("failed to verify retrieved proof against state root: %w", err)
}
return common.BytesToHash(result.StorageProof[0].Value), nil
value := result.StorageProof[0].Value.ToInt()
return common.BytesToHash(value.Bytes()), nil
}
func (s *EthClient) Close() {
......
package version
var (
Version = "v0.10.11"
Version = "v0.10.12"
Meta = "dev"
)
......@@ -13,7 +13,7 @@ import (
)
var (
Version = "v0.10.11"
Version = "v0.10.12"
GitCommit = ""
GitDate = ""
)
......
......@@ -3,9 +3,9 @@ module github.com/ethereum-optimism/optimism/op-proposer
go 1.18
require (
github.com/ethereum-optimism/optimism/op-bindings v0.10.11
github.com/ethereum-optimism/optimism/op-node v0.10.11
github.com/ethereum-optimism/optimism/op-service v0.10.11
github.com/ethereum-optimism/optimism/op-bindings v0.10.12
github.com/ethereum-optimism/optimism/op-node v0.10.12
github.com/ethereum-optimism/optimism/op-service v0.10.12
github.com/ethereum-optimism/optimism/op-signer v0.1.0
github.com/ethereum/go-ethereum v1.10.26
github.com/urfave/cli v1.22.9
......@@ -15,12 +15,16 @@ require (
github.com/VictoriaMetrics/fastcache v1.10.0 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/btcsuite/btcd v0.23.3 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/btcsuite/btcd/btcutil v1.1.0 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/dyson/certman v0.3.0 // indirect
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 // indirect
github.com/fjl/memsize v0.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
......@@ -80,6 +84,7 @@ require (
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.5.0 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
......
This diff is collapsed.
......@@ -119,8 +119,10 @@ services:
OP_BATCHER_L1_ETH_RPC: http://l1:8545
OP_BATCHER_L2_ETH_RPC: http://l2:8545
OP_BATCHER_ROLLUP_RPC: http://op-node:8545
OP_BATCHER_MIN_L1_TX_SIZE_BYTES: 1
OP_BATCHER_MAX_L1_TX_SIZE_BYTES: 120000
OP_BATCHER_TARGET_L1_TX_SIZE_BYTES: 624
OP_BATCHER_TARGET_NUM_FRAMES: 1
OP_BATCHER_APPROX_COMPR_RATIO: 1.0
OP_BATCHER_CHANNEL_TIMEOUT: 40
OP_BATCHER_POLL_INTERVAL: 1s
OP_BATCHER_NUM_CONFIRMATIONS: 1
......
......@@ -46,7 +46,7 @@ COPY packages/hardhat-deploy-config/package.json ./packages/hardhat-deploy-confi
COPY packages/message-relayer/package.json ./packages/message-relayer/package.json
COPY packages/fault-detector/package.json ./packages/fault-detector/package.json
COPY packages/replica-healthcheck/package.json ./packages/replica-healthcheck/package.json
COPY packages/drippie-mon/package.json ./packages/drippie-mon/package.json
COPY packages/chain-mon/package.json ./packages/chain-mon/package.json
COPY packages/balance-monitor/package.json ./packages/balance-monitor/package.json
COPY packages/two-step-monitor/package.json ./packages/two-step-monitor/package.json
COPY integration-tests/package.json ./integration-tests/package.json
......@@ -106,8 +106,8 @@ WORKDIR /opt/optimism/packages/replica-healthcheck
ENTRYPOINT ["npm", "run", "start"]
FROM base as drippie-mon
WORKDIR /opt/optimism/packages/drippie-mon
ENTRYPOINT ["npm", "run", "start"]
WORKDIR /opt/optimism/packages/chain-mon
ENTRYPOINT ["npm", "run", "start:drippie-mon"]
FROM base as balance-monitor
WORKDIR /opt/optimism/packages/balance-monitor
......
###############################################################################
# ↓ drippie-mon ↓ #
###############################################################################
# RPC pointing to network where Drippie is deployed
DRIPPIE_MON__RPC=
......
......@@ -9,7 +9,7 @@ import { Provider } from '@ethersproject/abstract-provider'
import { ethers } from 'ethers'
import * as DrippieArtifact from '@eth-optimism/contracts-periphery/artifacts/contracts/universal/drippie/Drippie.sol/Drippie.json'
import { version } from '../package.json'
import { version } from '../../package.json'
type DrippieMonOptions = {
rpc: Provider
......
export * from './drippie-mon/service'
......@@ -124,6 +124,7 @@ export abstract class BaseServiceV2<
metricsSpec: MetricsSpec<TMetrics>
options?: Partial<TOptions & StandardOptions>
loop?: boolean
bodyParserParams?: bodyParser.OptionsJson
}
) {
this.loop = params.loop !== undefined ? params.loop : true
......@@ -330,6 +331,7 @@ export abstract class BaseServiceV2<
verify: (req, res, buf, encoding) => {
;(req as any).rawBody = buf?.toString(encoding || 'utf8') || ''
},
...(this.params.bodyParserParams ?? {}),
})
)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment