Commit 9b3cbbd8 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into feat/fix-nonce-wipe

parents 9fbeebda 117e5746
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
/op-chain-ops @ethereum-optimism/go-reviewers /op-chain-ops @ethereum-optimism/go-reviewers
/op-e2e @ethereum-optimism/go-reviewers /op-e2e @ethereum-optimism/go-reviewers
/op-node @ethereum-optimism/go-reviewers /op-node @ethereum-optimism/go-reviewers
/op-node/rollup @protolambda @trianglesphere
/op-proposer @ethereum-optimism/go-reviewers /op-proposer @ethereum-optimism/go-reviewers
/op-service @ethereum-optimism/go-reviewers /op-service @ethereum-optimism/go-reviewers
......
...@@ -163,7 +163,7 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF ...@@ -163,7 +163,7 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF
done: make(chan struct{}), done: make(chan struct{}),
log: l, log: l,
state: NewChannelManager(l, cfg.ChannelTimeout), state: NewChannelManager(l, cfg.ChannelTimeout),
// TODO: this context only exists because the even loop doesn't reach done // 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. // if the tx manager is blocking forever due to e.g. insufficient balance.
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
......
This diff is collapsed.
This diff is collapsed.
...@@ -170,3 +170,17 @@ func (w *LegacyWithdrawal) Value() (*big.Int, error) { ...@@ -170,3 +170,17 @@ func (w *LegacyWithdrawal) Value() (*big.Int, error) {
return value, nil return value, nil
} }
// CrossDomainMessage turns the LegacyWithdrawal into
// a CrossDomainMessage. LegacyWithdrawals do not have
// the concept of value or gaslimit, so set them to 0.
func (w *LegacyWithdrawal) CrossDomainMessage() *CrossDomainMessage {
return &CrossDomainMessage{
Nonce: w.Nonce,
Sender: w.Sender,
Target: w.Target,
Value: new(big.Int),
GasLimit: new(big.Int),
Data: []byte(w.Data),
}
}
...@@ -26,9 +26,10 @@ type L2Sequencer struct { ...@@ -26,9 +26,10 @@ type L2Sequencer struct {
func NewL2Sequencer(t Testing, log log.Logger, l1 derive.L1Fetcher, eng L2API, cfg *rollup.Config, seqConfDepth uint64) *L2Sequencer { 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) ver := NewL2Verifier(t, log, l1, eng, cfg)
attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, eng)
return &L2Sequencer{ return &L2Sequencer{
L2Verifier: *ver, L2Verifier: *ver,
sequencer: driver.NewSequencer(log, cfg, l1, eng, ver.derivation, metrics.NoopMetrics), sequencer: driver.NewSequencer(log, cfg, eng, ver.derivation, attrBuilder, metrics.NoopMetrics),
l1OriginSelector: driver.NewL1OriginSelector(log, cfg, l1, seqConfDepth), l1OriginSelector: driver.NewL1OriginSelector(log, cfg, l1, seqConfDepth),
seqOldOrigin: false, seqOldOrigin: false,
failL2GossipUnsafeBlock: nil, failL2GossipUnsafeBlock: nil,
......
...@@ -113,6 +113,14 @@ func (s *l2VerifierBackend) ResetDerivationPipeline(ctx context.Context) error { ...@@ -113,6 +113,14 @@ func (s *l2VerifierBackend) ResetDerivationPipeline(ctx context.Context) error {
return nil return nil
} }
func (s *l2VerifierBackend) StartSequencer(ctx context.Context, blockHash common.Hash) error {
return nil
}
func (s *l2VerifierBackend) StopSequencer(ctx context.Context) (common.Hash, error) {
return common.Hash{}, errors.New("stopping the L2Verifier sequencer is not supported")
}
func (s *L2Verifier) L2Finalized() eth.L2BlockRef { func (s *L2Verifier) L2Finalized() eth.L2BlockRef {
return s.derivation.Finalized() return s.derivation.Finalized()
} }
......
...@@ -1129,6 +1129,58 @@ func TestFees(t *testing.T) { ...@@ -1129,6 +1129,58 @@ func TestFees(t *testing.T) {
require.Equal(t, balanceDiff, totalFee, "balances should add up") require.Equal(t, balanceDiff, totalFee, "balances should add up")
} }
func TestStopStartSequencer(t *testing.T) {
parallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
require.Nil(t, err, "Error starting up system")
defer sys.Close()
l2Seq := sys.Clients["sequencer"]
rollupNode := sys.RollupNodes["sequencer"]
nodeRPC, err := rpc.DialContext(context.Background(), rollupNode.HTTPEndpoint())
require.Nil(t, err, "Error dialing node")
blockBefore := latestBlock(t, l2Seq)
time.Sleep(time.Duration(cfg.DeployConfig.L2BlockTime+1) * time.Second)
blockAfter := latestBlock(t, l2Seq)
require.Greaterf(t, blockAfter, blockBefore, "Chain did not advance")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
blockHash := common.Hash{}
err = nodeRPC.CallContext(ctx, &blockHash, "admin_stopSequencer")
require.Nil(t, err, "Error stopping sequencer")
blockBefore = latestBlock(t, l2Seq)
time.Sleep(time.Duration(cfg.DeployConfig.L2BlockTime+1) * time.Second)
blockAfter = latestBlock(t, l2Seq)
require.Equal(t, blockAfter, blockBefore, "Chain advanced after stopping sequencer")
ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err = nodeRPC.CallContext(ctx, nil, "admin_startSequencer", blockHash)
require.Nil(t, err, "Error starting sequencer")
blockBefore = latestBlock(t, l2Seq)
time.Sleep(time.Duration(cfg.DeployConfig.L2BlockTime+1) * time.Second)
blockAfter = latestBlock(t, l2Seq)
require.Greater(t, blockAfter, blockBefore, "Chain did not advance after starting sequencer")
}
func safeAddBig(a *big.Int, b *big.Int) *big.Int { func safeAddBig(a *big.Int, b *big.Int) *big.Int {
return new(big.Int).Add(a, b) return new(big.Int).Add(a, b)
} }
func latestBlock(t *testing.T, client *ethclient.Client) uint64 {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
blockAfter, err := client.BlockNumber(ctx)
require.Nil(t, err, "Error getting latest block")
return blockAfter
}
...@@ -3,16 +3,17 @@ package main ...@@ -3,16 +3,17 @@ package main
import ( import (
"context" "context"
"net" "net"
"net/http"
"os" "os"
"os/signal" "os/signal"
"strconv"
"syscall" "syscall"
"time"
"github.com/ethereum-optimism/optimism/op-node/cmd/doc" "github.com/ethereum-optimism/optimism/op-node/cmd/doc"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/ethereum/go-ethereum/log"
opnode "github.com/ethereum-optimism/optimism/op-node" opnode "github.com/ethereum-optimism/optimism/op-node"
"github.com/ethereum-optimism/optimism/op-node/cmd/genesis" "github.com/ethereum-optimism/optimism/op-node/cmd/genesis"
"github.com/ethereum-optimism/optimism/op-node/cmd/p2p" "github.com/ethereum-optimism/optimism/op-node/cmd/p2p"
...@@ -21,7 +22,7 @@ import ( ...@@ -21,7 +22,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/metrics" "github.com/ethereum-optimism/optimism/op-node/metrics"
"github.com/ethereum-optimism/optimism/op-node/node" "github.com/ethereum-optimism/optimism/op-node/node"
"github.com/ethereum-optimism/optimism/op-node/version" "github.com/ethereum-optimism/optimism/op-node/version"
"github.com/ethereum/go-ethereum/log" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
) )
var ( var (
...@@ -145,24 +146,14 @@ func RollupNodeMain(ctx *cli.Context) error { ...@@ -145,24 +146,14 @@ func RollupNodeMain(ctx *cli.Context) error {
} }
if cfg.Pprof.Enabled { if cfg.Pprof.Enabled {
var srv http.Server pprofCtx, pprofCancel := context.WithCancel(context.Background())
srv.Addr = net.JoinHostPort(cfg.Pprof.ListenAddr, cfg.Pprof.ListenPort)
// Start pprof server + register it's shutdown
go func() { go func() {
log.Info("pprof server started", "addr", srv.Addr) log.Info("pprof server started", "addr", net.JoinHostPort(cfg.Pprof.ListenAddr, strconv.Itoa(cfg.Pprof.ListenPort)))
if err := srv.ListenAndServe(); err != http.ErrServerClosed { if err := oppprof.ListenAndServe(pprofCtx, cfg.Pprof.ListenAddr, cfg.Pprof.ListenPort); err != nil {
log.Error("error in pprof server", "err", err) log.Error("error starting pprof", "err", err)
} else {
log.Info("pprof server shutting down")
} }
}()
defer func() {
shutCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err := srv.Shutdown(shutCtx)
log.Info("pprof server shut down", "err", err)
}() }()
defer pprofCancel()
} }
interruptChannel := make(chan os.Signal, 1) interruptChannel := make(chan os.Signal, 1)
......
...@@ -94,6 +94,11 @@ var ( ...@@ -94,6 +94,11 @@ var (
Usage: "Enable sequencing of new L2 blocks. A separate batch submitter has to be deployed to publish the data for verifiers.", Usage: "Enable sequencing of new L2 blocks. A separate batch submitter has to be deployed to publish the data for verifiers.",
EnvVar: prefixEnvVar("SEQUENCER_ENABLED"), EnvVar: prefixEnvVar("SEQUENCER_ENABLED"),
} }
SequencerStoppedFlag = cli.BoolFlag{
Name: "sequencer.stopped",
Usage: "Initialize the sequencer in a stopped state. The sequencer can be started using the admin_startSequencer RPC",
EnvVar: prefixEnvVar("SEQUENCER_STOPPED"),
}
SequencerL1Confs = cli.Uint64Flag{ SequencerL1Confs = cli.Uint64Flag{
Name: "sequencer.l1-confs", Name: "sequencer.l1-confs",
Usage: "Number of L1 blocks to keep distance from the L1 head as a sequencer for picking an L1 origin.", Usage: "Number of L1 blocks to keep distance from the L1 head as a sequencer for picking an L1 origin.",
...@@ -197,6 +202,7 @@ var optionalFlags = append([]cli.Flag{ ...@@ -197,6 +202,7 @@ var optionalFlags = append([]cli.Flag{
L2EngineJWTSecret, L2EngineJWTSecret,
VerifierL1Confs, VerifierL1Confs,
SequencerEnabledFlag, SequencerEnabledFlag,
SequencerStoppedFlag,
SequencerL1Confs, SequencerL1Confs,
L1EpochPollIntervalFlag, L1EpochPollIntervalFlag,
LogLevelFlag, LogLevelFlag,
......
...@@ -26,6 +26,8 @@ type driverClient interface { ...@@ -26,6 +26,8 @@ type driverClient interface {
SyncStatus(ctx context.Context) (*eth.SyncStatus, error) SyncStatus(ctx context.Context) (*eth.SyncStatus, error)
BlockRefWithStatus(ctx context.Context, num uint64) (eth.L2BlockRef, *eth.SyncStatus, error) BlockRefWithStatus(ctx context.Context, num uint64) (eth.L2BlockRef, *eth.SyncStatus, error)
ResetDerivationPipeline(context.Context) error ResetDerivationPipeline(context.Context) error
StartSequencer(ctx context.Context, blockHash common.Hash) error
StopSequencer(context.Context) (common.Hash, error)
} }
type rpcMetrics interface { type rpcMetrics interface {
...@@ -51,6 +53,18 @@ func (n *adminAPI) ResetDerivationPipeline(ctx context.Context) error { ...@@ -51,6 +53,18 @@ func (n *adminAPI) ResetDerivationPipeline(ctx context.Context) error {
return n.dr.ResetDerivationPipeline(ctx) return n.dr.ResetDerivationPipeline(ctx)
} }
func (n *adminAPI) StartSequencer(ctx context.Context, blockHash common.Hash) error {
recordDur := n.m.RecordRPCServerRequest("admin_startSequencer")
defer recordDur()
return n.dr.StartSequencer(ctx, blockHash)
}
func (n *adminAPI) StopSequencer(ctx context.Context) (common.Hash, error) {
recordDur := n.m.RecordRPCServerRequest("admin_stopSequencer")
defer recordDur()
return n.dr.StopSequencer(ctx)
}
type nodeAPI struct { type nodeAPI struct {
config *rollup.Config config *rollup.Config
client l2EthClient client l2EthClient
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/p2p" "github.com/ethereum-optimism/optimism/op-node/p2p"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/driver" "github.com/ethereum-optimism/optimism/op-node/rollup/driver"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
) )
type Config struct { type Config struct {
...@@ -29,7 +30,7 @@ type Config struct { ...@@ -29,7 +30,7 @@ type Config struct {
Metrics MetricsConfig Metrics MetricsConfig
Pprof PprofConfig Pprof oppprof.CLIConfig
// Used to poll the L1 for new finalized or safe blocks // Used to poll the L1 for new finalized or safe blocks
L1EpochPollInterval time.Duration L1EpochPollInterval time.Duration
...@@ -67,16 +68,6 @@ func (m MetricsConfig) Check() error { ...@@ -67,16 +68,6 @@ func (m MetricsConfig) Check() error {
return nil return nil
} }
type PprofConfig struct {
Enabled bool
ListenAddr string
ListenPort string
}
func (p PprofConfig) Check() error {
return nil
}
type HeartbeatConfig struct { type HeartbeatConfig struct {
Enabled bool Enabled bool
Moniker string Moniker string
......
...@@ -218,3 +218,11 @@ func (c *mockDriverClient) SyncStatus(ctx context.Context) (*eth.SyncStatus, err ...@@ -218,3 +218,11 @@ func (c *mockDriverClient) SyncStatus(ctx context.Context) (*eth.SyncStatus, err
func (c *mockDriverClient) ResetDerivationPipeline(ctx context.Context) error { func (c *mockDriverClient) ResetDerivationPipeline(ctx context.Context) error {
return c.Mock.MethodCalled("ResetDerivationPipeline").Get(0).(error) return c.Mock.MethodCalled("ResetDerivationPipeline").Get(0).(error)
} }
func (c *mockDriverClient) StartSequencer(ctx context.Context, blockHash common.Hash) error {
return c.Mock.MethodCalled("StartSequencer").Get(0).(error)
}
func (c *mockDriverClient) StopSequencer(ctx context.Context) (common.Hash, error) {
return c.Mock.MethodCalled("StopSequencer").Get(0).(common.Hash), nil
}
...@@ -23,17 +23,32 @@ type SystemConfigL2Fetcher interface { ...@@ -23,17 +23,32 @@ type SystemConfigL2Fetcher interface {
SystemConfigByL2Hash(ctx context.Context, hash common.Hash) (eth.SystemConfig, error) SystemConfigByL2Hash(ctx context.Context, hash common.Hash) (eth.SystemConfig, error)
} }
// FetchingAttributesBuilder fetches inputs for the building of L2 payload attributes on the fly.
type FetchingAttributesBuilder struct {
cfg *rollup.Config
l1 L1ReceiptsFetcher
l2 SystemConfigL2Fetcher
}
func NewFetchingAttributesBuilder(cfg *rollup.Config, l1 L1ReceiptsFetcher, l2 SystemConfigL2Fetcher) *FetchingAttributesBuilder {
return &FetchingAttributesBuilder{
cfg: cfg,
l1: l1,
l2: l2,
}
}
// PreparePayloadAttributes prepares a PayloadAttributes template that is ready to build a L2 block with deposits only, on top of the given l2Parent, with the given epoch as L1 origin. // PreparePayloadAttributes prepares a PayloadAttributes template that is ready to build a L2 block with deposits only, on top of the given l2Parent, with the given epoch as L1 origin.
// The template defaults to NoTxPool=true, and no sequencer transactions: the caller has to modify the template to add transactions, // The template defaults to NoTxPool=true, and no sequencer transactions: the caller has to modify the template to add transactions,
// by setting NoTxPool=false as sequencer, or by appending batch transactions as verifier. // by setting NoTxPool=false as sequencer, or by appending batch transactions as verifier.
// The severity of the error is returned; a crit=false error means there was a temporary issue, like a failed RPC or time-out. // The severity of the error is returned; a crit=false error means there was a temporary issue, like a failed RPC or time-out.
// A crit=true error means the input arguments are inconsistent or invalid. // A crit=true error means the input arguments are inconsistent or invalid.
func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1ReceiptsFetcher, l2 SystemConfigL2Fetcher, l2Parent eth.L2BlockRef, timestamp uint64, epoch eth.BlockID) (attrs *eth.PayloadAttributes, err error) { func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Context, l2Parent eth.L2BlockRef, epoch eth.BlockID) (attrs *eth.PayloadAttributes, err error) {
var l1Info eth.BlockInfo var l1Info eth.BlockInfo
var depositTxs []hexutil.Bytes var depositTxs []hexutil.Bytes
var seqNumber uint64 var seqNumber uint64
sysConfig, err := l2.SystemConfigByL2Hash(ctx, l2Parent.Hash) sysConfig, err := ba.l2.SystemConfigByL2Hash(ctx, l2Parent.Hash)
if err != nil { if err != nil {
return nil, NewTemporaryError(fmt.Errorf("failed to retrieve L2 parent block: %w", err)) return nil, NewTemporaryError(fmt.Errorf("failed to retrieve L2 parent block: %w", err))
} }
...@@ -42,7 +57,7 @@ func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1Rece ...@@ -42,7 +57,7 @@ func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1Rece
// case we need to fetch all transaction receipts from the L1 origin block so we can scan for // case we need to fetch all transaction receipts from the L1 origin block so we can scan for
// user deposits. // user deposits.
if l2Parent.L1Origin.Number != epoch.Number { if l2Parent.L1Origin.Number != epoch.Number {
info, receipts, err := dl.FetchReceipts(ctx, epoch.Hash) info, receipts, err := ba.l1.FetchReceipts(ctx, epoch.Hash)
if err != nil { if err != nil {
return nil, NewTemporaryError(fmt.Errorf("failed to fetch L1 block info and receipts: %w", err)) return nil, NewTemporaryError(fmt.Errorf("failed to fetch L1 block info and receipts: %w", err))
} }
...@@ -52,13 +67,13 @@ func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1Rece ...@@ -52,13 +67,13 @@ func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1Rece
epoch, info.ParentHash(), l2Parent.L1Origin)) epoch, info.ParentHash(), l2Parent.L1Origin))
} }
deposits, err := DeriveDeposits(receipts, cfg.DepositContractAddress) deposits, err := DeriveDeposits(receipts, ba.cfg.DepositContractAddress)
if err != nil { if err != nil {
// deposits may never be ignored. Failing to process them is a critical error. // deposits may never be ignored. Failing to process them is a critical error.
return nil, NewCriticalError(fmt.Errorf("failed to derive some deposits: %w", err)) return nil, NewCriticalError(fmt.Errorf("failed to derive some deposits: %w", err))
} }
// apply sysCfg changes // apply sysCfg changes
if err := UpdateSystemConfigWithL1Receipts(&sysConfig, receipts, cfg); err != nil { if err := UpdateSystemConfigWithL1Receipts(&sysConfig, receipts, ba.cfg); err != nil {
return nil, NewCriticalError(fmt.Errorf("failed to apply derived L1 sysCfg updates: %w", err)) return nil, NewCriticalError(fmt.Errorf("failed to apply derived L1 sysCfg updates: %w", err))
} }
...@@ -69,7 +84,7 @@ func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1Rece ...@@ -69,7 +84,7 @@ func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1Rece
if l2Parent.L1Origin.Hash != epoch.Hash { if l2Parent.L1Origin.Hash != epoch.Hash {
return nil, NewResetError(fmt.Errorf("cannot create new block with L1 origin %s in conflict with L1 origin %s", epoch, l2Parent.L1Origin)) return nil, NewResetError(fmt.Errorf("cannot create new block with L1 origin %s in conflict with L1 origin %s", epoch, l2Parent.L1Origin))
} }
info, err := dl.InfoByHash(ctx, epoch.Hash) info, err := ba.l1.InfoByHash(ctx, epoch.Hash)
if err != nil { if err != nil {
return nil, NewTemporaryError(fmt.Errorf("failed to fetch L1 block info: %w", err)) return nil, NewTemporaryError(fmt.Errorf("failed to fetch L1 block info: %w", err))
} }
...@@ -78,6 +93,13 @@ func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1Rece ...@@ -78,6 +93,13 @@ func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1Rece
seqNumber = l2Parent.SequenceNumber + 1 seqNumber = l2Parent.SequenceNumber + 1
} }
// Sanity check the L1 origin was correctly selected to maintain the time invariant between L1 and L2
nextL2Time := l2Parent.Time + ba.cfg.BlockTime
if nextL2Time < l1Info.Time() {
return nil, NewResetError(fmt.Errorf("cannot build L2 block on top %s for time %d before L1 origin %s at time %d",
l2Parent, nextL2Time, eth.ToBlockID(l1Info), l1Info.Time()))
}
l1InfoTx, err := L1InfoDepositBytes(seqNumber, l1Info, sysConfig) l1InfoTx, err := L1InfoDepositBytes(seqNumber, l1Info, sysConfig)
if err != nil { if err != nil {
return nil, NewCriticalError(fmt.Errorf("failed to create l1InfoTx: %w", err)) return nil, NewCriticalError(fmt.Errorf("failed to create l1InfoTx: %w", err))
...@@ -88,7 +110,7 @@ func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1Rece ...@@ -88,7 +110,7 @@ func PreparePayloadAttributes(ctx context.Context, cfg *rollup.Config, dl L1Rece
txs = append(txs, depositTxs...) txs = append(txs, depositTxs...)
return &eth.PayloadAttributes{ return &eth.PayloadAttributes{
Timestamp: hexutil.Uint64(timestamp), Timestamp: hexutil.Uint64(nextL2Time),
PrevRandao: eth.Bytes32(l1Info.MixDigest()), PrevRandao: eth.Bytes32(l1Info.MixDigest()),
SuggestedFeeRecipient: predeploys.SequencerFeeVaultAddr, SuggestedFeeRecipient: predeploys.SequencerFeeVaultAddr,
Transactions: txs, Transactions: txs,
......
...@@ -23,22 +23,24 @@ import ( ...@@ -23,22 +23,24 @@ import (
// This stage can be reset by clearing it's batch buffer. // This stage can be reset by clearing it's batch buffer.
// This stage does not need to retain any references to L1 blocks. // This stage does not need to retain any references to L1 blocks.
type AttributesBuilder interface {
PreparePayloadAttributes(ctx context.Context, l2Parent eth.L2BlockRef, epoch eth.BlockID) (attrs *eth.PayloadAttributes, err error)
}
type AttributesQueue struct { type AttributesQueue struct {
log log.Logger log log.Logger
config *rollup.Config config *rollup.Config
dl L1ReceiptsFetcher builder AttributesBuilder
eng SystemConfigL2Fetcher prev *BatchQueue
prev *BatchQueue batch *BatchData
batch *BatchData
} }
func NewAttributesQueue(log log.Logger, cfg *rollup.Config, l1Fetcher L1ReceiptsFetcher, eng SystemConfigL2Fetcher, prev *BatchQueue) *AttributesQueue { func NewAttributesQueue(log log.Logger, cfg *rollup.Config, builder AttributesBuilder, prev *BatchQueue) *AttributesQueue {
return &AttributesQueue{ return &AttributesQueue{
log: log, log: log,
config: cfg, config: cfg,
dl: l1Fetcher, builder: builder,
eng: eng, prev: prev,
prev: prev,
} }
} }
...@@ -74,9 +76,13 @@ func (aq *AttributesQueue) createNextAttributes(ctx context.Context, batch *Batc ...@@ -74,9 +76,13 @@ func (aq *AttributesQueue) createNextAttributes(ctx context.Context, batch *Batc
if batch.ParentHash != l2SafeHead.Hash { if batch.ParentHash != l2SafeHead.Hash {
return nil, NewResetError(fmt.Errorf("valid batch has bad parent hash %s, expected %s", batch.ParentHash, l2SafeHead.Hash)) return nil, NewResetError(fmt.Errorf("valid batch has bad parent hash %s, expected %s", batch.ParentHash, l2SafeHead.Hash))
} }
// sanity check timestamp
if expected := l2SafeHead.Time + aq.config.BlockTime; expected != batch.Timestamp {
return nil, NewResetError(fmt.Errorf("valid batch has bad timestamp %d, expected %d", batch.Timestamp, expected))
}
fetchCtx, cancel := context.WithTimeout(ctx, 20*time.Second) fetchCtx, cancel := context.WithTimeout(ctx, 20*time.Second)
defer cancel() defer cancel()
attrs, err := PreparePayloadAttributes(fetchCtx, aq.config, aq.dl, aq.eng, l2SafeHead, batch.Timestamp, batch.Epoch()) attrs, err := aq.builder.PreparePayloadAttributes(fetchCtx, l2SafeHead, batch.Epoch())
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -40,6 +40,7 @@ func TestAttributesQueue(t *testing.T) { ...@@ -40,6 +40,7 @@ func TestAttributesQueue(t *testing.T) {
safeHead := testutils.RandomL2BlockRef(rng) safeHead := testutils.RandomL2BlockRef(rng)
safeHead.L1Origin = l1Info.ID() safeHead.L1Origin = l1Info.ID()
safeHead.Time = l1Info.InfoTime
batch := &BatchData{BatchV1{ batch := &BatchData{BatchV1{
ParentHash: safeHead.Hash, ParentHash: safeHead.Hash,
...@@ -75,11 +76,12 @@ func TestAttributesQueue(t *testing.T) { ...@@ -75,11 +76,12 @@ func TestAttributesQueue(t *testing.T) {
NoTxPool: true, NoTxPool: true,
GasLimit: (*eth.Uint64Quantity)(&expectedL1Cfg.GasLimit), GasLimit: (*eth.Uint64Quantity)(&expectedL1Cfg.GasLimit),
} }
attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l2Fetcher)
aq := NewAttributesQueue(testlog.Logger(t, log.LvlError), cfg, l1Fetcher, l2Fetcher, nil) aq := NewAttributesQueue(testlog.Logger(t, log.LvlError), cfg, attrBuilder, nil)
actual, err := aq.createNextAttributes(context.Background(), batch, safeHead) actual, err := aq.createNextAttributes(context.Background(), batch, safeHead)
require.Nil(t, err) require.NoError(t, err)
require.Equal(t, attrs, *actual) require.Equal(t, attrs, *actual)
} }
...@@ -43,12 +43,12 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -43,12 +43,12 @@ func TestPreparePayloadAttributes(t *testing.T) {
l1CfgFetcher := &testutils.MockL2Client{} l1CfgFetcher := &testutils.MockL2Client{}
l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil) l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil)
defer l1CfgFetcher.AssertExpectations(t) defer l1CfgFetcher.AssertExpectations(t)
l2Time := l2Parent.Time + cfg.BlockTime
l1Info := testutils.RandomBlockInfo(rng) l1Info := testutils.RandomBlockInfo(rng)
l1Info.InfoNum = l2Parent.L1Origin.Number + 1 l1Info.InfoNum = l2Parent.L1Origin.Number + 1
epoch := l1Info.ID() epoch := l1Info.ID()
l1Fetcher.ExpectFetchReceipts(epoch.Hash, l1Info, nil, nil) l1Fetcher.ExpectFetchReceipts(epoch.Hash, l1Info, nil, nil)
_, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l1CfgFetcher, l2Parent, l2Time, epoch) attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher)
_, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch)
require.NotNil(t, err, "inconsistent L1 origin error expected") require.NotNil(t, err, "inconsistent L1 origin error expected")
require.ErrorIs(t, err, ErrReset, "inconsistent L1 origin transition must be handled like a critical error with reorg") require.ErrorIs(t, err, ErrReset, "inconsistent L1 origin transition must be handled like a critical error with reorg")
}) })
...@@ -60,11 +60,11 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -60,11 +60,11 @@ func TestPreparePayloadAttributes(t *testing.T) {
l1CfgFetcher := &testutils.MockL2Client{} l1CfgFetcher := &testutils.MockL2Client{}
l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil) l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil)
defer l1CfgFetcher.AssertExpectations(t) defer l1CfgFetcher.AssertExpectations(t)
l2Time := l2Parent.Time + cfg.BlockTime
l1Info := testutils.RandomBlockInfo(rng) l1Info := testutils.RandomBlockInfo(rng)
l1Info.InfoNum = l2Parent.L1Origin.Number l1Info.InfoNum = l2Parent.L1Origin.Number
epoch := l1Info.ID() epoch := l1Info.ID()
_, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l1CfgFetcher, l2Parent, l2Time, epoch) attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher)
_, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch)
require.NotNil(t, err, "inconsistent L1 origin error expected") require.NotNil(t, err, "inconsistent L1 origin error expected")
require.ErrorIs(t, err, ErrReset, "inconsistent L1 origin transition must be handled like a critical error with reorg") require.ErrorIs(t, err, ErrReset, "inconsistent L1 origin transition must be handled like a critical error with reorg")
}) })
...@@ -76,12 +76,12 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -76,12 +76,12 @@ func TestPreparePayloadAttributes(t *testing.T) {
l1CfgFetcher := &testutils.MockL2Client{} l1CfgFetcher := &testutils.MockL2Client{}
l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil) l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil)
defer l1CfgFetcher.AssertExpectations(t) defer l1CfgFetcher.AssertExpectations(t)
l2Time := l2Parent.Time + cfg.BlockTime
epoch := l2Parent.L1Origin epoch := l2Parent.L1Origin
epoch.Number += 1 epoch.Number += 1
mockRPCErr := errors.New("mock rpc error") mockRPCErr := errors.New("mock rpc error")
l1Fetcher.ExpectFetchReceipts(epoch.Hash, nil, nil, mockRPCErr) l1Fetcher.ExpectFetchReceipts(epoch.Hash, nil, nil, mockRPCErr)
_, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l1CfgFetcher, l2Parent, l2Time, epoch) attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher)
_, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch)
require.ErrorIs(t, err, mockRPCErr, "mock rpc error expected") require.ErrorIs(t, err, mockRPCErr, "mock rpc error expected")
require.ErrorIs(t, err, ErrTemporary, "rpc errors should not be critical, it is not necessary to reorg") require.ErrorIs(t, err, ErrTemporary, "rpc errors should not be critical, it is not necessary to reorg")
}) })
...@@ -93,11 +93,11 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -93,11 +93,11 @@ func TestPreparePayloadAttributes(t *testing.T) {
l1CfgFetcher := &testutils.MockL2Client{} l1CfgFetcher := &testutils.MockL2Client{}
l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil) l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil)
defer l1CfgFetcher.AssertExpectations(t) defer l1CfgFetcher.AssertExpectations(t)
l2Time := l2Parent.Time + cfg.BlockTime
epoch := l2Parent.L1Origin epoch := l2Parent.L1Origin
mockRPCErr := errors.New("mock rpc error") mockRPCErr := errors.New("mock rpc error")
l1Fetcher.ExpectInfoByHash(epoch.Hash, nil, mockRPCErr) l1Fetcher.ExpectInfoByHash(epoch.Hash, nil, mockRPCErr)
_, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l1CfgFetcher, l2Parent, l2Time, epoch) attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher)
_, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch)
require.ErrorIs(t, err, mockRPCErr, "mock rpc error expected") require.ErrorIs(t, err, mockRPCErr, "mock rpc error expected")
require.ErrorIs(t, err, ErrTemporary, "rpc errors should not be critical, it is not necessary to reorg") require.ErrorIs(t, err, ErrTemporary, "rpc errors should not be critical, it is not necessary to reorg")
}) })
...@@ -109,7 +109,6 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -109,7 +109,6 @@ func TestPreparePayloadAttributes(t *testing.T) {
l1CfgFetcher := &testutils.MockL2Client{} l1CfgFetcher := &testutils.MockL2Client{}
l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil) l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil)
defer l1CfgFetcher.AssertExpectations(t) defer l1CfgFetcher.AssertExpectations(t)
l2Time := l2Parent.Time + cfg.BlockTime
l1Info := testutils.RandomBlockInfo(rng) l1Info := testutils.RandomBlockInfo(rng)
l1Info.InfoParentHash = l2Parent.L1Origin.Hash l1Info.InfoParentHash = l2Parent.L1Origin.Hash
l1Info.InfoNum = l2Parent.L1Origin.Number + 1 l1Info.InfoNum = l2Parent.L1Origin.Number + 1
...@@ -117,7 +116,8 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -117,7 +116,8 @@ func TestPreparePayloadAttributes(t *testing.T) {
l1InfoTx, err := L1InfoDepositBytes(0, l1Info, testSysCfg) l1InfoTx, err := L1InfoDepositBytes(0, l1Info, testSysCfg)
require.NoError(t, err) require.NoError(t, err)
l1Fetcher.ExpectFetchReceipts(epoch.Hash, l1Info, nil, nil) l1Fetcher.ExpectFetchReceipts(epoch.Hash, l1Info, nil, nil)
attrs, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l1CfgFetcher, l2Parent, l2Time, epoch) attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher)
attrs, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, attrs) require.NotNil(t, attrs)
require.Equal(t, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp)) require.Equal(t, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp))
...@@ -135,7 +135,6 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -135,7 +135,6 @@ func TestPreparePayloadAttributes(t *testing.T) {
l1CfgFetcher := &testutils.MockL2Client{} l1CfgFetcher := &testutils.MockL2Client{}
l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil) l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil)
defer l1CfgFetcher.AssertExpectations(t) defer l1CfgFetcher.AssertExpectations(t)
l2Time := l2Parent.Time + cfg.BlockTime
l1Info := testutils.RandomBlockInfo(rng) l1Info := testutils.RandomBlockInfo(rng)
l1Info.InfoParentHash = l2Parent.L1Origin.Hash l1Info.InfoParentHash = l2Parent.L1Origin.Hash
l1Info.InfoNum = l2Parent.L1Origin.Number + 1 l1Info.InfoNum = l2Parent.L1Origin.Number + 1
...@@ -157,7 +156,8 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -157,7 +156,8 @@ func TestPreparePayloadAttributes(t *testing.T) {
l2Txs := append(append(make([]eth.Data, 0), l1InfoTx), usedDepositTxs...) l2Txs := append(append(make([]eth.Data, 0), l1InfoTx), usedDepositTxs...)
l1Fetcher.ExpectFetchReceipts(epoch.Hash, l1Info, receipts, nil) l1Fetcher.ExpectFetchReceipts(epoch.Hash, l1Info, receipts, nil)
attrs, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l1CfgFetcher, l2Parent, l2Time, epoch) attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher)
attrs, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, attrs) require.NotNil(t, attrs)
require.Equal(t, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp)) require.Equal(t, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp))
...@@ -175,7 +175,6 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -175,7 +175,6 @@ func TestPreparePayloadAttributes(t *testing.T) {
l1CfgFetcher := &testutils.MockL2Client{} l1CfgFetcher := &testutils.MockL2Client{}
l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil) l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil)
defer l1CfgFetcher.AssertExpectations(t) defer l1CfgFetcher.AssertExpectations(t)
l2Time := l2Parent.Time + cfg.BlockTime
l1Info := testutils.RandomBlockInfo(rng) l1Info := testutils.RandomBlockInfo(rng)
l1Info.InfoHash = l2Parent.L1Origin.Hash l1Info.InfoHash = l2Parent.L1Origin.Hash
l1Info.InfoNum = l2Parent.L1Origin.Number l1Info.InfoNum = l2Parent.L1Origin.Number
...@@ -185,7 +184,8 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -185,7 +184,8 @@ func TestPreparePayloadAttributes(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
l1Fetcher.ExpectInfoByHash(epoch.Hash, l1Info, nil) l1Fetcher.ExpectInfoByHash(epoch.Hash, l1Info, nil)
attrs, err := PreparePayloadAttributes(context.Background(), cfg, l1Fetcher, l1CfgFetcher, l2Parent, l2Time, epoch) attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher)
attrs, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, attrs) require.NotNil(t, attrs)
require.Equal(t, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp)) require.Equal(t, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp))
......
...@@ -74,7 +74,8 @@ func NewDerivationPipeline(log log.Logger, cfg *rollup.Config, l1Fetcher L1Fetch ...@@ -74,7 +74,8 @@ func NewDerivationPipeline(log log.Logger, cfg *rollup.Config, l1Fetcher L1Fetch
bank := NewChannelBank(log, cfg, frameQueue, l1Fetcher) bank := NewChannelBank(log, cfg, frameQueue, l1Fetcher)
chInReader := NewChannelInReader(log, bank) chInReader := NewChannelInReader(log, bank)
batchQueue := NewBatchQueue(log, cfg, chInReader) batchQueue := NewBatchQueue(log, cfg, chInReader)
attributesQueue := NewAttributesQueue(log, cfg, l1Fetcher, engine, batchQueue) attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, engine)
attributesQueue := NewAttributesQueue(log, cfg, attrBuilder, batchQueue)
// Step stages // Step stages
eng := NewEngineQueue(log, cfg, engine, metrics, attributesQueue, l1Fetcher) eng := NewEngineQueue(log, cfg, engine, metrics, attributesQueue, l1Fetcher)
......
...@@ -13,4 +13,7 @@ type Config struct { ...@@ -13,4 +13,7 @@ type Config struct {
// SequencerEnabled is true when the driver should sequence new blocks. // SequencerEnabled is true when the driver should sequence new blocks.
SequencerEnabled bool `json:"sequencer_enabled"` SequencerEnabled bool `json:"sequencer_enabled"`
// SequencerStopped is false when the driver should sequence new blocks.
SequencerStopped bool `json:"sequencer_stopped"`
} }
...@@ -89,14 +89,16 @@ func NewDriver(driverCfg *Config, cfg *rollup.Config, l2 L2Chain, l1 L1Chain, ne ...@@ -89,14 +89,16 @@ func NewDriver(driverCfg *Config, cfg *rollup.Config, l2 L2Chain, l1 L1Chain, ne
findL1Origin := NewL1OriginSelector(log, cfg, l1, driverCfg.SequencerConfDepth) findL1Origin := NewL1OriginSelector(log, cfg, l1, driverCfg.SequencerConfDepth)
verifConfDepth := NewConfDepth(driverCfg.VerifierConfDepth, l1State.L1Head, l1) verifConfDepth := NewConfDepth(driverCfg.VerifierConfDepth, l1State.L1Head, l1)
derivationPipeline := derive.NewDerivationPipeline(log, cfg, verifConfDepth, l2, metrics) derivationPipeline := derive.NewDerivationPipeline(log, cfg, verifConfDepth, l2, metrics)
sequencer := NewSequencer(log, cfg, l1, l2, derivationPipeline, metrics) attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, l2)
sequencer := NewSequencer(log, cfg, l2, derivationPipeline, attrBuilder, metrics)
return &Driver{ return &Driver{
l1State: l1State, l1State: l1State,
derivation: derivationPipeline, derivation: derivationPipeline,
idleDerivation: false, idleDerivation: false,
stateReq: make(chan chan struct{}), stateReq: make(chan chan struct{}),
forceReset: make(chan chan struct{}, 10), forceReset: make(chan chan struct{}, 10),
startSequencer: make(chan hashAndErrorChannel, 10),
stopSequencer: make(chan chan hashAndError, 10),
config: cfg, config: cfg,
driverConfig: driverCfg, driverConfig: driverCfg,
done: make(chan struct{}), done: make(chan struct{}),
......
...@@ -37,10 +37,10 @@ type Sequencer struct { ...@@ -37,10 +37,10 @@ type Sequencer struct {
log log.Logger log log.Logger
config *rollup.Config config *rollup.Config
l1 Downloader
l2 derive.Engine l2 derive.Engine
engineState EngineState engineState EngineState
attrBuilder derive.AttributesBuilder
buildingOnto eth.L2BlockRef buildingOnto eth.L2BlockRef
buildingID eth.PayloadID buildingID eth.PayloadID
buildingStartTime time.Time buildingStartTime time.Time
...@@ -48,14 +48,14 @@ type Sequencer struct { ...@@ -48,14 +48,14 @@ type Sequencer struct {
metrics SequencerMetrics metrics SequencerMetrics
} }
func NewSequencer(log log.Logger, cfg *rollup.Config, l1 Downloader, l2 derive.Engine, engineState EngineState, metrics SequencerMetrics) *Sequencer { func NewSequencer(log log.Logger, cfg *rollup.Config, l2 derive.Engine, engineState EngineState, attributesBuilder derive.AttributesBuilder, metrics SequencerMetrics) *Sequencer {
return &Sequencer{ return &Sequencer{
log: log, log: log,
config: cfg, config: cfg,
l1: l1,
l2: l2, l2: l2,
metrics: metrics, metrics: metrics,
engineState: engineState, engineState: engineState,
attrBuilder: attributesBuilder,
} }
} }
...@@ -75,7 +75,7 @@ func (d *Sequencer) StartBuildingBlock(ctx context.Context, l1Origin eth.L1Block ...@@ -75,7 +75,7 @@ func (d *Sequencer) StartBuildingBlock(ctx context.Context, l1Origin eth.L1Block
fetchCtx, cancel := context.WithTimeout(ctx, time.Second*20) fetchCtx, cancel := context.WithTimeout(ctx, time.Second*20)
defer cancel() defer cancel()
attrs, err := derive.PreparePayloadAttributes(fetchCtx, d.config, d.l1, d.l2, l2Head, l2Head.Time+d.config.BlockTime, l1Origin.ID()) attrs, err := d.attrBuilder.PreparePayloadAttributes(fetchCtx, l2Head, l1Origin.ID())
if err != nil { if err != nil {
return err return err
} }
......
package driver package driver
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
...@@ -9,6 +10,7 @@ import ( ...@@ -9,6 +10,7 @@ import (
gosync "sync" gosync "sync"
"time" "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
...@@ -42,6 +44,14 @@ type Driver struct { ...@@ -42,6 +44,14 @@ type Driver struct {
// It tells the caller that the reset occurred by closing the passed in channel. // It tells the caller that the reset occurred by closing the passed in channel.
forceReset chan chan struct{} forceReset chan chan struct{}
// Upon receiving a hash in this channel, the sequencer is started at the given hash.
// It tells the caller that the sequencer started by closing the passed in channel (or returning an error).
startSequencer chan hashAndErrorChannel
// Upon receiving a channel in this channel, the sequencer is stopped.
// It tells the caller that the sequencer stopped by returning the latest sequenced L2 block hash.
stopSequencer chan chan hashAndError
// Rollup config: rollup chain configuration // Rollup config: rollup chain configuration
config *rollup.Config config *rollup.Config
...@@ -274,7 +284,7 @@ func (s *Driver) eventLoop() { ...@@ -274,7 +284,7 @@ func (s *Driver) eventLoop() {
for { for {
// If we are sequencing, update the trigger for the next sequencer action. // If we are sequencing, update the trigger for the next sequencer action.
// This may adjust at any time based on fork-choice changes or previous errors. // This may adjust at any time based on fork-choice changes or previous errors.
if s.driverConfig.SequencerEnabled { if s.driverConfig.SequencerEnabled && !s.driverConfig.SequencerStopped {
// update sequencer time if the head changed // update sequencer time if the head changed
if sequencingPlannedOnto != s.derivation.UnsafeL2Head().ID() { if sequencingPlannedOnto != s.derivation.UnsafeL2Head().ID() {
planSequencerAction() planSequencerAction()
...@@ -367,6 +377,26 @@ func (s *Driver) eventLoop() { ...@@ -367,6 +377,26 @@ func (s *Driver) eventLoop() {
s.derivation.Reset() s.derivation.Reset()
s.metrics.RecordPipelineReset() s.metrics.RecordPipelineReset()
close(respCh) close(respCh)
case resp := <-s.startSequencer:
unsafeHead := s.derivation.UnsafeL2Head().Hash
if !s.driverConfig.SequencerStopped {
resp.err <- errors.New("sequencer already running")
} else if !bytes.Equal(unsafeHead[:], resp.hash[:]) {
resp.err <- fmt.Errorf("block hash does not match: head %s, received %s", unsafeHead.String(), resp.hash.String())
} else {
s.log.Info("Sequencer has been started")
s.driverConfig.SequencerStopped = false
sequencingPlannedOnto = eth.BlockID{}
close(resp.err)
}
case respCh := <-s.stopSequencer:
if s.driverConfig.SequencerStopped {
respCh <- hashAndError{err: errors.New("sequencer not running")}
} else {
s.log.Warn("Sequencer has been stopped")
s.driverConfig.SequencerStopped = true
respCh <- hashAndError{hash: s.derivation.UnsafeL2Head().Hash}
}
case <-s.done: case <-s.done:
return return
} }
...@@ -391,6 +421,45 @@ func (s *Driver) ResetDerivationPipeline(ctx context.Context) error { ...@@ -391,6 +421,45 @@ func (s *Driver) ResetDerivationPipeline(ctx context.Context) error {
} }
} }
func (s *Driver) StartSequencer(ctx context.Context, blockHash common.Hash) error {
if !s.driverConfig.SequencerEnabled {
return errors.New("sequencer is not enabled")
}
h := hashAndErrorChannel{
hash: blockHash,
err: make(chan error, 1),
}
select {
case <-ctx.Done():
return ctx.Err()
case s.startSequencer <- h:
select {
case <-ctx.Done():
return ctx.Err()
case e := <-h.err:
return e
}
}
}
func (s *Driver) StopSequencer(ctx context.Context) (common.Hash, error) {
if !s.driverConfig.SequencerEnabled {
return common.Hash{}, errors.New("sequencer is not enabled")
}
respCh := make(chan hashAndError, 1)
select {
case <-ctx.Done():
return common.Hash{}, ctx.Err()
case s.stopSequencer <- respCh:
select {
case <-ctx.Done():
return common.Hash{}, ctx.Err()
case he := <-respCh:
return he.hash, he.err
}
}
}
// syncStatus returns the current sync status, and should only be called synchronously with // syncStatus returns the current sync status, and should only be called synchronously with
// the driver event loop to avoid retrieval of an inconsistent status. // the driver event loop to avoid retrieval of an inconsistent status.
func (s *Driver) syncStatus() *eth.SyncStatus { func (s *Driver) syncStatus() *eth.SyncStatus {
...@@ -455,3 +524,13 @@ func (s *Driver) snapshot(event string) { ...@@ -455,3 +524,13 @@ func (s *Driver) snapshot(event string) {
"l2Safe", deferJSONString{s.derivation.SafeL2Head()}, "l2Safe", deferJSONString{s.derivation.SafeL2Head()},
"l2FinalizedHead", deferJSONString{s.derivation.Finalized()}) "l2FinalizedHead", deferJSONString{s.derivation.Finalized()})
} }
type hashAndError struct {
hash common.Hash
err error
}
type hashAndErrorChannel struct {
hash common.Hash
err chan error
}
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/sources" "github.com/ethereum-optimism/optimism/op-node/sources"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/urfave/cli" "github.com/urfave/cli"
...@@ -75,10 +76,10 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) { ...@@ -75,10 +76,10 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) {
ListenAddr: ctx.GlobalString(flags.MetricsAddrFlag.Name), ListenAddr: ctx.GlobalString(flags.MetricsAddrFlag.Name),
ListenPort: ctx.GlobalInt(flags.MetricsPortFlag.Name), ListenPort: ctx.GlobalInt(flags.MetricsPortFlag.Name),
}, },
Pprof: node.PprofConfig{ Pprof: oppprof.CLIConfig{
Enabled: ctx.GlobalBool(flags.PprofEnabledFlag.Name), Enabled: ctx.GlobalBool(flags.PprofEnabledFlag.Name),
ListenAddr: ctx.GlobalString(flags.PprofAddrFlag.Name), ListenAddr: ctx.GlobalString(flags.PprofAddrFlag.Name),
ListenPort: ctx.GlobalString(flags.PprofPortFlag.Name), ListenPort: ctx.GlobalInt(flags.PprofPortFlag.Name),
}, },
P2P: p2pConfig, P2P: p2pConfig,
P2PSigner: p2pSignerSetup, P2PSigner: p2pSignerSetup,
...@@ -138,6 +139,7 @@ func NewDriverConfig(ctx *cli.Context) (*driver.Config, error) { ...@@ -138,6 +139,7 @@ func NewDriverConfig(ctx *cli.Context) (*driver.Config, error) {
VerifierConfDepth: ctx.GlobalUint64(flags.VerifierL1Confs.Name), VerifierConfDepth: ctx.GlobalUint64(flags.VerifierL1Confs.Name),
SequencerConfDepth: ctx.GlobalUint64(flags.SequencerL1Confs.Name), SequencerConfDepth: ctx.GlobalUint64(flags.SequencerL1Confs.Name),
SequencerEnabled: ctx.GlobalBool(flags.SequencerEnabledFlag.Name), SequencerEnabled: ctx.GlobalBool(flags.SequencerEnabledFlag.Name),
SequencerStopped: ctx.GlobalBool(flags.SequencerStoppedFlag.Name),
}, nil }, nil
} }
......
...@@ -65,6 +65,7 @@ services: ...@@ -65,6 +65,7 @@ services:
--metrics.addr=0.0.0.0 --metrics.addr=0.0.0.0
--metrics.port=7300 --metrics.port=7300
--pprof.enabled --pprof.enabled
--rpc.enable-admin
ports: ports:
- "7545:8545" - "7545:8545"
- "9003:9003" - "9003:9003"
......
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 261344) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 261344)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 75851) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 75851)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 348151) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 348207)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 112583) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 112639)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 348173) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 348229)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 112604) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 112660)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 40502) GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 40502)
GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 88513) GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 88513)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 74998) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 74998)
...@@ -17,7 +17,7 @@ Bytes_Test:test_toNibbles_expectedResult128Bytes_works() (gas: 129885) ...@@ -17,7 +17,7 @@ Bytes_Test:test_toNibbles_expectedResult128Bytes_works() (gas: 129885)
Bytes_Test:test_toNibbles_expectedResult5Bytes_works() (gas: 6132) Bytes_Test:test_toNibbles_expectedResult5Bytes_works() (gas: 6132)
Bytes_Test:test_toNibbles_zeroLengthInput_works() (gas: 966) Bytes_Test:test_toNibbles_zeroLengthInput_works() (gas: 966)
CrossDomainMessenger_BaseGas_Test:test_baseGas_succeeds() (gas: 20120) CrossDomainMessenger_BaseGas_Test:test_baseGas_succeeds() (gas: 20120)
CrossDomainOwnableThroughPortal_Test:test_depositTransaction_crossDomainOwner_succeeds() (gas: 61876) CrossDomainOwnableThroughPortal_Test:test_depositTransaction_crossDomainOwner_succeeds() (gas: 61882)
CrossDomainOwnable_Test:test_onlyOwner_notOwner_reverts() (gas: 10530) CrossDomainOwnable_Test:test_onlyOwner_notOwner_reverts() (gas: 10530)
CrossDomainOwnable_Test:test_onlyOwner_succeeds() (gas: 34861) CrossDomainOwnable_Test:test_onlyOwner_succeeds() (gas: 34861)
CrossDomainOwnable2_Test:test_onlyOwner_notMessenger_reverts() (gas: 8416) CrossDomainOwnable2_Test:test_onlyOwner_notMessenger_reverts() (gas: 8416)
...@@ -92,11 +92,11 @@ L1ERC721Bridge_Test:test_finalizeBridgeERC721_notFromRemoteMessenger_reverts() ( ...@@ -92,11 +92,11 @@ L1ERC721Bridge_Test:test_finalizeBridgeERC721_notFromRemoteMessenger_reverts() (
L1ERC721Bridge_Test:test_finalizeBridgeERC721_notViaLocalMessenger_reverts() (gas: 16093) L1ERC721Bridge_Test:test_finalizeBridgeERC721_notViaLocalMessenger_reverts() (gas: 16093)
L1ERC721Bridge_Test:test_finalizeBridgeERC721_selfToken_reverts() (gas: 17593) L1ERC721Bridge_Test:test_finalizeBridgeERC721_selfToken_reverts() (gas: 17593)
L1ERC721Bridge_Test:test_finalizeBridgeERC721_succeeds() (gas: 323814) L1ERC721Bridge_Test:test_finalizeBridgeERC721_succeeds() (gas: 323814)
L1StandardBridge_DepositERC20To_Test:test_depositERC20To_succeeds() (gas: 575959) L1StandardBridge_DepositERC20To_Test:test_depositERC20To_succeeds() (gas: 576276)
L1StandardBridge_DepositERC20_Test:test_depositERC20_succeeds() (gas: 573786) L1StandardBridge_DepositERC20_Test:test_depositERC20_succeeds() (gas: 574103)
L1StandardBridge_DepositERC20_TestFail:test_depositERC20_notEoa_reverts() (gas: 22320) L1StandardBridge_DepositERC20_TestFail:test_depositERC20_notEoa_reverts() (gas: 22320)
L1StandardBridge_DepositETHTo_Test:test_depositETHTo_succeeds() (gas: 324712) L1StandardBridge_DepositETHTo_Test:test_depositETHTo_succeeds() (gas: 324839)
L1StandardBridge_DepositETH_Test:test_depositETH_succeeds() (gas: 367539) L1StandardBridge_DepositETH_Test:test_depositETH_succeeds() (gas: 367666)
L1StandardBridge_DepositETH_TestFail:test_depositETH_notEoa_reverts() (gas: 40780) L1StandardBridge_DepositETH_TestFail:test_depositETH_notEoa_reverts() (gas: 40780)
L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_incorrectValue_reverts() (gas: 34207) L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_incorrectValue_reverts() (gas: 34207)
L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_sendToMessenger_reverts() (gas: 34288) L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_sendToMessenger_reverts() (gas: 34288)
...@@ -105,9 +105,9 @@ L1StandardBridge_FinalizeERC20Withdrawal_Test:test_finalizeERC20Withdrawal_succe ...@@ -105,9 +105,9 @@ L1StandardBridge_FinalizeERC20Withdrawal_Test:test_finalizeERC20Withdrawal_succe
L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_notMessenger_reverts() (gas: 31148) L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_notMessenger_reverts() (gas: 31148)
L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_notOtherBridge_reverts() (gas: 31504) L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_notOtherBridge_reverts() (gas: 31504)
L1StandardBridge_FinalizeETHWithdrawal_Test:test_finalizeETHWithdrawal_succeeds() (gas: 58686) L1StandardBridge_FinalizeETHWithdrawal_Test:test_finalizeETHWithdrawal_succeeds() (gas: 58686)
L1StandardBridge_Getter_Test:test_getters_succeeds() (gas: 31449) L1StandardBridge_Getter_Test:test_getters_succeeds() (gas: 32151)
L1StandardBridge_Initialize_Test:test_initialize_succeeds() (gas: 22005) L1StandardBridge_Initialize_Test:test_initialize_succeeds() (gas: 22005)
L1StandardBridge_Receive_Test:test_receive_succeeds() (gas: 514475) L1StandardBridge_Receive_Test:test_receive_succeeds() (gas: 519995)
L2CrossDomainMessenger_Test:test_messageVersion_succeeds() (gas: 8389) L2CrossDomainMessenger_Test:test_messageVersion_succeeds() (gas: 8389)
L2CrossDomainMessenger_Test:test_pause_notOwner_reverts() (gas: 10837) L2CrossDomainMessenger_Test:test_pause_notOwner_reverts() (gas: 10837)
L2CrossDomainMessenger_Test:test_pause_succeeds() (gas: 31846) L2CrossDomainMessenger_Test:test_pause_succeeds() (gas: 31846)
...@@ -168,11 +168,11 @@ L2StandardBridge_Test:test_finalizeBridgeETH_sendToMessenger_reverts() (gas: 239 ...@@ -168,11 +168,11 @@ L2StandardBridge_Test:test_finalizeBridgeETH_sendToMessenger_reverts() (gas: 239
L2StandardBridge_Test:test_finalizeBridgeETH_sendToSelf_reverts() (gas: 23893) L2StandardBridge_Test:test_finalizeBridgeETH_sendToSelf_reverts() (gas: 23893)
L2StandardBridge_Test:test_finalizeDeposit_succeeds() (gas: 89473) L2StandardBridge_Test:test_finalizeDeposit_succeeds() (gas: 89473)
L2StandardBridge_Test:test_initialize_succeeds() (gas: 24270) L2StandardBridge_Test:test_initialize_succeeds() (gas: 24270)
L2StandardBridge_Test:test_receive_succeeds() (gas: 131905) L2StandardBridge_Test:test_receive_succeeds() (gas: 141940)
L2StandardBridge_Test:test_withdrawTo_succeeds() (gas: 344660) L2StandardBridge_Test:test_withdrawTo_succeeds() (gas: 344914)
L2StandardBridge_Test:test_withdraw_insufficientValue_reverts() (gas: 19630) L2StandardBridge_Test:test_withdraw_insufficientValue_reverts() (gas: 19627)
L2StandardBridge_Test:test_withdraw_notEOA_reverts() (gas: 251798) L2StandardBridge_Test:test_withdraw_notEOA_reverts() (gas: 251798)
L2StandardBridge_Test:test_withdraw_succeeds() (gas: 343975) L2StandardBridge_Test:test_withdraw_succeeds() (gas: 344228)
L2ToL1MessagePasserTest:test_burn_succeeds() (gas: 112572) L2ToL1MessagePasserTest:test_burn_succeeds() (gas: 112572)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromContract_succeeds() (gas: 70423) L2ToL1MessagePasserTest:test_initiateWithdrawal_fromContract_succeeds() (gas: 70423)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromEOA_succeeds() (gas: 75874) L2ToL1MessagePasserTest:test_initiateWithdrawal_fromEOA_succeeds() (gas: 75874)
......
This diff is collapsed.
...@@ -91,15 +91,22 @@ contract L1StandardBridge is StandardBridge, Semver { ...@@ -91,15 +91,22 @@ contract L1StandardBridge is StandardBridge, Semver {
); );
/** /**
* @custom:semver 1.0.0 * @custom:semver 1.1.0
* *
* @param _messenger Address of the L1CrossDomainMessenger. * @param _messenger Address of the L1CrossDomainMessenger.
*/ */
constructor(address payable _messenger) constructor(address payable _messenger)
Semver(1, 0, 0) Semver(1, 1, 0)
StandardBridge(_messenger, payable(Predeploys.L2_STANDARD_BRIDGE)) StandardBridge(_messenger, payable(Predeploys.L2_STANDARD_BRIDGE))
{} {}
/**
* @notice Allows EOAs to bridge ETH by sending directly to the bridge.
*/
receive() external payable override onlyEOA {
_initiateETHDeposit(msg.sender, msg.sender, RECEIVE_DEFAULT_GAS_LIMIT, bytes(""));
}
/** /**
* @custom:legacy * @custom:legacy
* @notice Finalizes a withdrawal of ERC20 tokens from L2. * @notice Finalizes a withdrawal of ERC20 tokens from L2.
...@@ -261,7 +268,7 @@ contract L1StandardBridge is StandardBridge, Semver { ...@@ -261,7 +268,7 @@ contract L1StandardBridge is StandardBridge, Semver {
address _from, address _from,
address _to, address _to,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes memory _extraData
) internal { ) internal {
emit ETHDepositInitiated(_from, _to, msg.value, _extraData); emit ETHDepositInitiated(_from, _to, msg.value, _extraData);
_initiateBridgeETH(_from, _to, msg.value, _minGasLimit, _extraData); _initiateBridgeETH(_from, _to, msg.value, _minGasLimit, _extraData);
...@@ -285,7 +292,7 @@ contract L1StandardBridge is StandardBridge, Semver { ...@@ -285,7 +292,7 @@ contract L1StandardBridge is StandardBridge, Semver {
address _to, address _to,
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes memory _extraData
) internal { ) internal {
emit ERC20DepositInitiated(_l1Token, _l2Token, _from, _to, _amount, _extraData); emit ERC20DepositInitiated(_l1Token, _l2Token, _from, _to, _amount, _extraData);
_initiateBridgeERC20(_l1Token, _l2Token, _from, _to, _amount, _minGasLimit, _extraData); _initiateBridgeERC20(_l1Token, _l2Token, _from, _to, _amount, _minGasLimit, _extraData);
......
...@@ -59,15 +59,29 @@ contract L2StandardBridge is StandardBridge, Semver { ...@@ -59,15 +59,29 @@ contract L2StandardBridge is StandardBridge, Semver {
); );
/** /**
* @custom:semver 1.0.0 * @custom:semver 1.1.0
* *
* @param _otherBridge Address of the L1StandardBridge. * @param _otherBridge Address of the L1StandardBridge.
*/ */
constructor(address payable _otherBridge) constructor(address payable _otherBridge)
Semver(1, 0, 0) Semver(1, 1, 0)
StandardBridge(payable(Predeploys.L2_CROSS_DOMAIN_MESSENGER), _otherBridge) StandardBridge(payable(Predeploys.L2_CROSS_DOMAIN_MESSENGER), _otherBridge)
{} {}
/**
* @notice Allows EOAs to bridge ETH by sending directly to the bridge.
*/
receive() external payable override onlyEOA {
_initiateWithdrawal(
Predeploys.LEGACY_ERC20_ETH,
msg.sender,
msg.sender,
msg.value,
RECEIVE_DEFAULT_GAS_LIMIT,
bytes("")
);
}
/** /**
* @custom:legacy * @custom:legacy
* @notice Initiates a withdrawal from L2 to L1. * @notice Initiates a withdrawal from L2 to L1.
...@@ -165,7 +179,7 @@ contract L2StandardBridge is StandardBridge, Semver { ...@@ -165,7 +179,7 @@ contract L2StandardBridge is StandardBridge, Semver {
address _to, address _to,
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes memory _extraData
) internal { ) internal {
address l1Token = OptimismMintableERC20(_l2Token).l1Token(); address l1Token = OptimismMintableERC20(_l2Token).l1Token();
if (_l2Token == Predeploys.LEGACY_ERC20_ETH) { if (_l2Token == Predeploys.LEGACY_ERC20_ETH) {
......
...@@ -16,7 +16,7 @@ contract L1StandardBridge_Getter_Test is Bridge_Initializer { ...@@ -16,7 +16,7 @@ contract L1StandardBridge_Getter_Test is Bridge_Initializer {
assert(L1Bridge.OTHER_BRIDGE() == L2Bridge); assert(L1Bridge.OTHER_BRIDGE() == L2Bridge);
assert(L1Bridge.messenger() == L1Messenger); assert(L1Bridge.messenger() == L1Messenger);
assert(L1Bridge.MESSENGER() == L1Messenger); assert(L1Bridge.MESSENGER() == L1Messenger);
assertEq(L1Bridge.version(), "1.0.0"); assertEq(L1Bridge.version(), "1.1.0");
} }
} }
...@@ -38,6 +38,10 @@ contract L1StandardBridge_Receive_Test is Bridge_Initializer { ...@@ -38,6 +38,10 @@ contract L1StandardBridge_Receive_Test is Bridge_Initializer {
function test_receive_succeeds() external { function test_receive_succeeds() external {
assertEq(address(op).balance, 0); assertEq(address(op).balance, 0);
// The legacy event must be emitted for backwards compatibility
vm.expectEmit(true, true, true, true);
emit ETHDepositInitiated(alice, alice, 100, hex"");
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
emit ETHBridgeInitiated(alice, alice, 100, hex""); emit ETHBridgeInitiated(alice, alice, 100, hex"");
......
...@@ -33,6 +33,9 @@ contract L2StandardBridge_Test is Bridge_Initializer { ...@@ -33,6 +33,9 @@ contract L2StandardBridge_Test is Bridge_Initializer {
// TODO: withdrawal hash should be computed correctly // TODO: withdrawal hash should be computed correctly
// TODO: events from each contract // TODO: events from each contract
vm.expectEmit(true, true, true, true);
emit WithdrawalInitiated(address(0), Predeploys.LEGACY_ERC20_ETH, alice, alice, 100, hex"");
vm.prank(alice, alice); vm.prank(alice, alice);
(bool success, ) = address(L2Bridge).call{ value: 100 }(hex""); (bool success, ) = address(L2Bridge).call{ value: 100 }(hex"");
assertEq(success, true); assertEq(success, true);
......
...@@ -164,11 +164,10 @@ abstract contract StandardBridge { ...@@ -164,11 +164,10 @@ abstract contract StandardBridge {
} }
/** /**
* @notice Allows EOAs to deposit ETH by sending directly to the bridge. * @notice Allows EOAs to bridge ETH by sending directly to the bridge.
* Must be implemented by contracts that inherit.
*/ */
receive() external payable onlyEOA { receive() external payable virtual;
_initiateBridgeETH(msg.sender, msg.sender, msg.value, RECEIVE_DEFAULT_GAS_LIMIT, bytes(""));
}
/** /**
* @custom:legacy * @custom:legacy
...@@ -401,7 +400,7 @@ abstract contract StandardBridge { ...@@ -401,7 +400,7 @@ abstract contract StandardBridge {
address _to, address _to,
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes memory _extraData
) internal { ) internal {
if (_isOptimismMintableERC20(_localToken)) { if (_isOptimismMintableERC20(_localToken)) {
require( require(
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
"contracts/**/*.sol" "contracts/**/*.sol"
], ],
"scripts": { "scripts": {
"bindings": "cd ../../op-bindings && make",
"build:forge": "forge build", "build:forge": "forge build",
"build:with-metadata": "FOUNDRY_PROFILE=echidna yarn build:forge", "build:with-metadata": "FOUNDRY_PROFILE=echidna yarn build:forge",
"build:differential": "tsc scripts/differential-testing.ts --outDir dist --moduleResolution node --esModuleInterop", "build:differential": "tsc scripts/differential-testing.ts --outDir dist --moduleResolution node --esModuleInterop",
...@@ -29,7 +30,7 @@ ...@@ -29,7 +30,7 @@
"coverage:lcov": "yarn build:differential && yarn build:fuzz && forge coverage --report lcov", "coverage:lcov": "yarn build:differential && yarn build:fuzz && forge coverage --report lcov",
"gas-snapshot": "yarn build:differential && yarn build:fuzz && forge snapshot --no-match-test 'testDiff|testFuzz|invariant'", "gas-snapshot": "yarn build:differential && yarn build:fuzz && forge snapshot --no-match-test 'testDiff|testFuzz|invariant'",
"storage-snapshot": "./scripts/storage-snapshot.sh", "storage-snapshot": "./scripts/storage-snapshot.sh",
"validate-spacers": "hardhat validate-spacers", "validate-spacers": "hardhat compile && hardhat validate-spacers",
"slither": "./scripts/slither.sh", "slither": "./scripts/slither.sh",
"clean": "rm -rf ./dist ./artifacts ./forge-artifacts ./cache ./tsconfig.tsbuildinfo ./tsconfig.build.tsbuildinfo ./src/contract-artifacts.ts ./test-case-generator/fuzz", "clean": "rm -rf ./dist ./artifacts ./forge-artifacts ./cache ./tsconfig.tsbuildinfo ./tsconfig.build.tsbuildinfo ./src/contract-artifacts.ts ./test-case-generator/fuzz",
"lint:ts:check": "eslint . --max-warnings=0", "lint:ts:check": "eslint . --max-warnings=0",
......
...@@ -56,7 +56,7 @@ interface RequiredDeployConfig { ...@@ -56,7 +56,7 @@ interface RequiredDeployConfig {
sequencerWindowSize: number sequencerWindowSize: number
/** /**
* Number of seconds (w.r.t. L1 time) that a frame can be valid when included in L1. * Number of L1 blocks that a frame stays valid when included in L1.
*/ */
channelTimeout: number channelTimeout: number
......
...@@ -328,7 +328,7 @@ const check = { ...@@ -328,7 +328,7 @@ const check = {
signer signer
) )
await assertSemver(L2StandardBridge, 'L2StandardBridge') await assertSemver(L2StandardBridge, 'L2StandardBridge', '1.1.0')
const OTHER_BRIDGE = await L2StandardBridge.OTHER_BRIDGE() const OTHER_BRIDGE = await L2StandardBridge.OTHER_BRIDGE()
assert(OTHER_BRIDGE !== hre.ethers.constants.AddressZero) assert(OTHER_BRIDGE !== hre.ethers.constants.AddressZero)
......
This diff is collapsed.
...@@ -479,7 +479,7 @@ transaction must also be signed by a recognized batch submitter account. ...@@ -479,7 +479,7 @@ transaction must also be signed by a recognized batch submitter account.
[channel-timeout]: glossary.md#channel-timeout [channel-timeout]: glossary.md#channel-timeout
The channel timeout is a duration (in seconds) during which [channel frames][channel-frame may land on L1 within The channel timeout is a duration (in L1 blocks) during which [channel frames][channel-frame] may land on L1 within
[batcher transactions][batcher-transaction]. [batcher transactions][batcher-transaction].
The acceptable time range for the frames of a [channel][channel] is `[channel_id.timestamp, channel_id.timestamp + The acceptable time range for the frames of a [channel][channel] is `[channel_id.timestamp, channel_id.timestamp +
......
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