Skip to content

Commit

Permalink
Merge branch 'develop' into jg/metrics_docs
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Apr 13, 2023
2 parents 40e13ed + aae815b commit 2c56f51
Show file tree
Hide file tree
Showing 37 changed files with 1,080 additions and 218 deletions.
23 changes: 19 additions & 4 deletions op-chain-ops/cmd/withdrawals/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ func main() {
Name: "evm-messages",
Usage: "Path to evm-messages.json",
},
&cli.StringFlag{
Name: "witness-file",
Usage: "Path to l2geth witness file",
},
&cli.StringFlag{
Name: "private-key",
Usage: "Key to sign transactions with",
Expand Down Expand Up @@ -702,8 +706,9 @@ func newContracts(ctx *cli.Context, l1Backend, l2Backend bind.ContractBackend) (
func newWithdrawals(ctx *cli.Context, l1ChainID *big.Int) ([]*crossdomain.LegacyWithdrawal, error) {
ovmMsgs := ctx.String("ovm-messages")
evmMsgs := ctx.String("evm-messages")
witnessFile := ctx.String("witness-file")

log.Debug("Migration data", "ovm-path", ovmMsgs, "evm-messages", evmMsgs)
log.Debug("Migration data", "ovm-path", ovmMsgs, "evm-messages", evmMsgs, "witness-file", witnessFile)
ovmMessages, err := crossdomain.NewSentMessageFromJSON(ovmMsgs)
if err != nil {
return nil, err
Expand All @@ -716,9 +721,19 @@ func newWithdrawals(ctx *cli.Context, l1ChainID *big.Int) ([]*crossdomain.Legacy
ovmMessages = []*crossdomain.SentMessage{}
}

evmMessages, err := crossdomain.NewSentMessageFromJSON(evmMsgs)
if err != nil {
return nil, err
var evmMessages []*crossdomain.SentMessage
if witnessFile != "" {
evmMessages, _, err = crossdomain.ReadWitnessData(witnessFile)
if err != nil {
return nil, err
}
} else if evmMsgs != "" {
evmMessages, err = crossdomain.NewSentMessageFromJSON(evmMsgs)
if err != nil {
return nil, err
}
} else {
return nil, errors.New("must provide either witness file or evm messages")
}

migrationData := crossdomain.MigrationData{
Expand Down
6 changes: 3 additions & 3 deletions op-e2e/actions/blocktime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@ func TestBatchInLastPossibleBlocks(gt *testing.T) {

signer := types.LatestSigner(sd.L2Cfg.Config)
cl := sequencerEngine.EthClient()
aliceNonce := uint64(0) // manual nonce management to avoid geth pending-tx nonce non-determinism flakiness
aliceTx := func() {
n, err := cl.PendingNonceAt(t.Ctx(), dp.Addresses.Alice)
require.NoError(t, err)
tx := types.MustSignNewTx(dp.Secrets.Alice, signer, &types.DynamicFeeTx{
ChainID: sd.L2Cfg.Config.ChainID,
Nonce: n,
Nonce: aliceNonce,
GasTipCap: big.NewInt(2 * params.GWei),
GasFeeCap: new(big.Int).Add(miner.l1Chain.CurrentBlock().BaseFee, big.NewInt(2*params.GWei)),
Gas: params.TxGas,
To: &dp.Addresses.Bob,
Value: e2eutils.Ether(2),
})
require.NoError(gt, cl.SendTransaction(t.Ctx(), tx))
aliceNonce += 1
}
makeL2BlockWithAliceTx := func() {
aliceTx()
Expand Down
8 changes: 1 addition & 7 deletions op-node/node/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log"

"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup"
Expand Down Expand Up @@ -115,12 +114,7 @@ func (n *nodeAPI) OutputAtBlock(ctx context.Context, number hexutil.Uint64) (*et
}

var l2OutputRootVersion eth.Bytes32 // it's zero for now
l2OutputRoot, err := rollup.ComputeL2OutputRoot(&bindings.TypesOutputRootProof{
Version: l2OutputRootVersion,
StateRoot: head.Root(),
MessagePasserStorageRoot: proof.StorageHash,
LatestBlockhash: head.Hash(),
})
l2OutputRoot, err := rollup.ComputeL2OutputRootV0(head, proof.StorageHash)
if err != nil {
n.log.Error("Error computing L2 output root, nil ptr passed to hashing function")
return nil, err
Expand Down
43 changes: 27 additions & 16 deletions op-node/rollup/derive/engine_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ import (
"github.com/ethereum-optimism/optimism/op-node/rollup/sync"
)

type attributesWithParent struct {
attributes *eth.PayloadAttributes
parent eth.L2BlockRef
}

type NextAttributesProvider interface {
Origin() eth.L1BlockRef
NextAttributes(context.Context, eth.L2BlockRef) (*eth.PayloadAttributes, error)
Expand Down Expand Up @@ -114,9 +119,8 @@ type EngineQueue struct {
triedFinalizeAt eth.L1BlockRef

// The queued-up attributes
safeAttributesParent eth.L2BlockRef
safeAttributes *eth.PayloadAttributes
unsafePayloads *PayloadsQueue // queue of unsafe payloads, ordered by ascending block number, may have gaps and duplicates
safeAttributes *attributesWithParent
unsafePayloads *PayloadsQueue // queue of unsafe payloads, ordered by ascending block number, may have gaps and duplicates

// Tracks which L2 blocks where last derived from which L1 block. At most finalityLookback large.
finalityData []FinalityData
Expand Down Expand Up @@ -241,9 +245,11 @@ func (eq *EngineQueue) Step(ctx context.Context) error {
} else if err != nil {
return err
} else {
eq.safeAttributes = next
eq.safeAttributesParent = eq.safeHead
eq.log.Debug("Adding next safe attributes", "safe_head", eq.safeHead, "next", eq.safeAttributes)
eq.safeAttributes = &attributesWithParent{
attributes: next,
parent: eq.safeHead,
}
eq.log.Debug("Adding next safe attributes", "safe_head", eq.safeHead, "next", next)
return NotEnoughData
}

Expand Down Expand Up @@ -482,15 +488,19 @@ func (eq *EngineQueue) tryNextSafeAttributes(ctx context.Context) error {
return nil
}
// validate the safe attributes before processing them. The engine may have completed processing them through other means.
if eq.safeHead != eq.safeAttributesParent {
if eq.safeHead.ParentHash != eq.safeAttributesParent.Hash {
return NewResetError(fmt.Errorf("safe head changed to %s with parent %s, conflicting with queued safe attributes on top of %s",
eq.safeHead, eq.safeHead.ParentID(), eq.safeAttributesParent))
if eq.safeHead != eq.safeAttributes.parent {
// Previously the attribute's parent was the safe head. If the safe head advances so safe head's parent is the same as the
// attribute's parent then we need to cancel the attributes.
if eq.safeHead.ParentHash == eq.safeAttributes.parent.Hash {
eq.log.Warn("queued safe attributes are stale, safehead progressed",
"safe_head", eq.safeHead, "safe_head_parent", eq.safeHead.ParentID(), "attributes_parent", eq.safeAttributes.parent)
eq.safeAttributes = nil
return nil
}
eq.log.Warn("queued safe attributes are stale, safe-head progressed",
"safe_head", eq.safeHead, "safe_head_parent", eq.safeHead.ParentID(), "attributes_parent", eq.safeAttributesParent)
eq.safeAttributes = nil
return nil
// If something other than a simple advance occurred, perform a full reset
return NewResetError(fmt.Errorf("safe head changed to %s with parent %s, conflicting with queued safe attributes on top of %s",
eq.safeHead, eq.safeHead.ParentID(), eq.safeAttributes.parent))

}
if eq.safeHead.Number < eq.unsafeHead.Number {
return eq.consolidateNextSafeAttributes(ctx)
Expand Down Expand Up @@ -520,7 +530,7 @@ func (eq *EngineQueue) consolidateNextSafeAttributes(ctx context.Context) error
}
return NewTemporaryError(fmt.Errorf("failed to get existing unsafe payload to compare against derived attributes from L1: %w", err))
}
if err := AttributesMatchBlock(eq.safeAttributes, eq.safeHead.Hash, payload, eq.log); err != nil {
if err := AttributesMatchBlock(eq.safeAttributes.attributes, eq.safeHead.Hash, payload, eq.log); err != nil {
eq.log.Warn("L2 reorg: existing unsafe block does not match derived attributes from L1", "err", err, "unsafe", eq.unsafeHead, "safe", eq.safeHead)
// geth cannot wind back a chain without reorging to a new, previously non-canonical, block
return eq.forceNextSafeAttributes(ctx)
Expand All @@ -545,7 +555,7 @@ func (eq *EngineQueue) forceNextSafeAttributes(ctx context.Context) error {
if eq.safeAttributes == nil {
return nil
}
attrs := eq.safeAttributes
attrs := eq.safeAttributes.attributes
errType, err := eq.StartPayload(ctx, eq.safeHead, attrs, true)
if err == nil {
_, errType, err = eq.ConfirmPayload(ctx)
Expand Down Expand Up @@ -716,6 +726,7 @@ func (eq *EngineQueue) Reset(ctx context.Context, _ eth.L1BlockRef, _ eth.System
eq.log.Debug("Reset engine queue", "safeHead", safe, "unsafe", unsafe, "safe_timestamp", safe.Time, "unsafe_timestamp", unsafe.Time, "l1Origin", l1Origin)
eq.unsafeHead = unsafe
eq.safeHead = safe
eq.safeAttributes = nil
eq.finalized = finalized
eq.resetBuildingState()
eq.needForkchoiceUpdate = true
Expand Down
100 changes: 100 additions & 0 deletions op-node/rollup/derive/engine_queue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/ethereum/go-ethereum/log"

"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/testlog"
"github.com/ethereum-optimism/optimism/op-node/testutils"
Expand Down Expand Up @@ -1007,3 +1008,102 @@ func TestBlockBuildingRace(t *testing.T) {
l1F.AssertExpectations(t)
eng.AssertExpectations(t)
}

func TestResetLoop(t *testing.T) {
logger := testlog.Logger(t, log.LvlInfo)
eng := &testutils.MockEngine{}
l1F := &testutils.MockL1Source{}

rng := rand.New(rand.NewSource(1234))

refA := testutils.RandomBlockRef(rng)
refA0 := eth.L2BlockRef{
Hash: testutils.RandomHash(rng),
Number: 0,
ParentHash: common.Hash{},
Time: refA.Time,
L1Origin: refA.ID(),
SequenceNumber: 0,
}
gasLimit := eth.Uint64Quantity(20_000_000)
cfg := &rollup.Config{
Genesis: rollup.Genesis{
L1: refA.ID(),
L2: refA0.ID(),
L2Time: refA0.Time,
SystemConfig: eth.SystemConfig{
BatcherAddr: common.Address{42},
Overhead: [32]byte{123},
Scalar: [32]byte{42},
GasLimit: 20_000_000,
},
},
BlockTime: 1,
SeqWindowSize: 2,
}
refA1 := eth.L2BlockRef{
Hash: testutils.RandomHash(rng),
Number: refA0.Number + 1,
ParentHash: refA0.Hash,
Time: refA0.Time + cfg.BlockTime,
L1Origin: refA.ID(),
SequenceNumber: 1,
}
refA2 := eth.L2BlockRef{
Hash: testutils.RandomHash(rng),
Number: refA1.Number + 1,
ParentHash: refA1.Hash,
Time: refA1.Time + cfg.BlockTime,
L1Origin: refA.ID(),
SequenceNumber: 2,
}

attrs := &eth.PayloadAttributes{
Timestamp: eth.Uint64Quantity(refA2.Time),
PrevRandao: eth.Bytes32{},
SuggestedFeeRecipient: common.Address{},
Transactions: nil,
NoTxPool: false,
GasLimit: &gasLimit,
}

eng.ExpectL2BlockRefByLabel(eth.Finalized, refA0, nil)
eng.ExpectL2BlockRefByLabel(eth.Safe, refA1, nil)
eng.ExpectL2BlockRefByLabel(eth.Unsafe, refA2, nil)
eng.ExpectL2BlockRefByHash(refA1.Hash, refA1, nil)
eng.ExpectL2BlockRefByHash(refA0.Hash, refA0, nil)
eng.ExpectSystemConfigByL2Hash(refA0.Hash, cfg.Genesis.SystemConfig, nil)
l1F.ExpectL1BlockRefByNumber(refA.Number, refA, nil)
l1F.ExpectL1BlockRefByHash(refA.Hash, refA, nil)
l1F.ExpectL1BlockRefByHash(refA.Hash, refA, nil)

prev := &fakeAttributesQueue{origin: refA, attrs: attrs}

eq := NewEngineQueue(logger, cfg, eng, metrics.NoopMetrics, prev, l1F)
eq.unsafeHead = refA2
eq.safeHead = refA1
eq.finalized = refA0

// Qeueue up the safe attributes
require.Nil(t, eq.safeAttributes)
require.ErrorIs(t, eq.Step(context.Background()), NotEnoughData)
require.NotNil(t, eq.safeAttributes)

// Peform the reset
require.ErrorIs(t, eq.Reset(context.Background(), eth.L1BlockRef{}, eth.SystemConfig{}), io.EOF)

// Expect a FCU after the reset
preFc := &eth.ForkchoiceState{
HeadBlockHash: refA2.Hash,
SafeBlockHash: refA0.Hash,
FinalizedBlockHash: refA0.Hash,
}
eng.ExpectForkchoiceUpdate(preFc, nil, nil, nil)
require.NoError(t, eq.Step(context.Background()), "clean forkchoice state after reset")

// Crux of the test. Should be in a valid state after the reset.
require.ErrorIs(t, eq.Step(context.Background()), NotEnoughData, "Should be able to step after a reset")

l1F.AssertExpectations(t)
eng.AssertExpectations(t)
}
10 changes: 10 additions & 0 deletions op-node/rollup/output_root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,13 @@ func ComputeL2OutputRoot(proofElements *bindings.TypesOutputRootProof) (eth.Byte
)
return eth.Bytes32(digest), nil
}

func ComputeL2OutputRootV0(block eth.BlockInfo, storageRoot [32]byte) (eth.Bytes32, error) {
var l2OutputRootVersion eth.Bytes32 // it's zero for now
return ComputeL2OutputRoot(&bindings.TypesOutputRootProof{
Version: l2OutputRootVersion,
StateRoot: block.Root(),
MessagePasserStorageRoot: storageRoot,
LatestBlockhash: block.Hash(),
})
}
28 changes: 24 additions & 4 deletions op-node/sources/batching.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type IterativeBatchCall[K any, V any] struct {

makeRequest func(K) (V, rpc.BatchElem)
getBatch BatchCallContextFn
getSingle CallContextFn

requestsValues []V
scheduled chan rpc.BatchElem
Expand All @@ -35,6 +36,7 @@ func NewIterativeBatchCall[K any, V any](
requestsKeys []K,
makeRequest func(K) (V, rpc.BatchElem),
getBatch BatchCallContextFn,
getSingle CallContextFn,
batchSize int) *IterativeBatchCall[K, V] {

if len(requestsKeys) < batchSize {
Expand All @@ -47,6 +49,7 @@ func NewIterativeBatchCall[K any, V any](
out := &IterativeBatchCall[K, V]{
completed: 0,
getBatch: getBatch,
getSingle: getSingle,
requestsKeys: requestsKeys,
batchSize: batchSize,
makeRequest: makeRequest,
Expand Down Expand Up @@ -84,6 +87,11 @@ func (ibc *IterativeBatchCall[K, V]) Fetch(ctx context.Context) error {
ibc.resetLock.RLock()
defer ibc.resetLock.RUnlock()

// return early if context is Done
if ctx.Err() != nil {
return ctx.Err()
}

// collect a batch from the requests channel
batch := make([]rpc.BatchElem, 0, ibc.batchSize)
// wait for first element
Expand Down Expand Up @@ -119,11 +127,23 @@ func (ibc *IterativeBatchCall[K, V]) Fetch(ctx context.Context) error {
break
}

if err := ibc.getBatch(ctx, batch); err != nil {
for _, r := range batch {
ibc.scheduled <- r
if len(batch) == 0 {
return nil
}

if ibc.batchSize == 1 {
first := batch[0]
if err := ibc.getSingle(ctx, &first.Result, first.Method, first.Args...); err != nil {
ibc.scheduled <- first
return err
}
} else {
if err := ibc.getBatch(ctx, batch); err != nil {
for _, r := range batch {
ibc.scheduled <- r
}
return fmt.Errorf("failed batch-retrieval: %w", err)
}
return fmt.Errorf("failed batch-retrieval: %w", err)
}
var result error
for _, elem := range batch {
Expand Down
Loading

0 comments on commit 2c56f51

Please sign in to comment.