Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions op-e2e/system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@ import (

"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-node/l2"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/node"
rollupNode "github.com/ethereum-optimism/optimism/op-node/node"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
"github.com/ethereum-optimism/optimism/op-proposer/rollupclient"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
Expand Down Expand Up @@ -265,7 +264,7 @@ func TestSystemE2E(t *testing.T) {
receipt, err := waitForTransaction(tx.Hash(), l1Client, 3*time.Duration(cfg.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for deposit tx on L1")

reconstructedDep, err := derive.UnmarshalLogEvent(receipt.Logs[0])
reconstructedDep, err := derive.UnmarshalDepositLogEvent(receipt.Logs[0])
require.NoError(t, err, "Could not reconstruct L2 Deposit")
tx = types.NewTx(reconstructedDep)
receipt, err = waitForTransaction(tx.Hash(), l2Verif, 3*time.Duration(cfg.L1BlockTime)*time.Second)
Expand Down Expand Up @@ -355,7 +354,7 @@ func TestMintOnRevertedDeposit(t *testing.T) {
receipt, err := waitForTransaction(tx.Hash(), l1Client, 3*time.Duration(cfg.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for deposit tx on L1")

reconstructedDep, err := derive.UnmarshalLogEvent(receipt.Logs[0])
reconstructedDep, err := derive.UnmarshalDepositLogEvent(receipt.Logs[0])
require.NoError(t, err, "Could not reconstruct L2 Deposit")
tx = types.NewTx(reconstructedDep)
receipt, err = waitForTransaction(tx.Hash(), l2Verif, 3*time.Duration(cfg.L1BlockTime)*time.Second)
Expand Down Expand Up @@ -501,10 +500,10 @@ func TestSystemMockP2P(t *testing.T) {

var published, received []common.Hash
seqTracer, verifTracer := new(FnTracer), new(FnTracer)
seqTracer.OnPublishL2PayloadFn = func(ctx context.Context, payload *l2.ExecutionPayload) {
seqTracer.OnPublishL2PayloadFn = func(ctx context.Context, payload *eth.ExecutionPayload) {
published = append(published, payload.BlockHash)
}
verifTracer.OnUnsafeL2PayloadFn = func(ctx context.Context, from peer.ID, payload *l2.ExecutionPayload) {
verifTracer.OnUnsafeL2PayloadFn = func(ctx context.Context, from peer.ID, payload *eth.ExecutionPayload) {
received = append(received, payload.BlockHash)
}
cfg.Nodes["sequencer"].Tracer = seqTracer
Expand Down Expand Up @@ -715,7 +714,7 @@ func TestWithdrawals(t *testing.T) {
require.Nil(t, err, "binding withdrawer on L2")

// Wait for deposit to arrive
reconstructedDep, err := derive.UnmarshalLogEvent(receipt.Logs[0])
reconstructedDep, err := derive.UnmarshalDepositLogEvent(receipt.Logs[0])
require.NoError(t, err, "Could not reconstruct L2 Deposit")
tx = types.NewTx(reconstructedDep)
receipt, err = waitForTransaction(tx.Hash(), l2Verif, 3*time.Duration(cfg.L1BlockTime)*time.Second)
Expand Down
9 changes: 4 additions & 5 deletions op-e2e/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import (
"context"

"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/l2"
"github.com/ethereum-optimism/optimism/op-node/node"
"github.com/libp2p/go-libp2p-core/peer"
)

type FnTracer struct {
OnNewL1HeadFn func(ctx context.Context, sig eth.L1BlockRef)
OnUnsafeL2PayloadFn func(ctx context.Context, from peer.ID, payload *l2.ExecutionPayload)
OnPublishL2PayloadFn func(ctx context.Context, payload *l2.ExecutionPayload)
OnUnsafeL2PayloadFn func(ctx context.Context, from peer.ID, payload *eth.ExecutionPayload)
OnPublishL2PayloadFn func(ctx context.Context, payload *eth.ExecutionPayload)
}

func (n *FnTracer) OnNewL1Head(ctx context.Context, sig eth.L1BlockRef) {
Expand All @@ -21,13 +20,13 @@ func (n *FnTracer) OnNewL1Head(ctx context.Context, sig eth.L1BlockRef) {
}
}

func (n *FnTracer) OnUnsafeL2Payload(ctx context.Context, from peer.ID, payload *l2.ExecutionPayload) {
func (n *FnTracer) OnUnsafeL2Payload(ctx context.Context, from peer.ID, payload *eth.ExecutionPayload) {
if n.OnUnsafeL2PayloadFn != nil {
n.OnUnsafeL2PayloadFn(ctx, from, payload)
}
}

func (n *FnTracer) OnPublishL2Payload(ctx context.Context, payload *l2.ExecutionPayload) {
func (n *FnTracer) OnPublishL2Payload(ctx context.Context, payload *eth.ExecutionPayload) {
if n.OnPublishL2PayloadFn != nil {
n.OnPublishL2PayloadFn(ctx, payload)
}
Expand Down
2 changes: 1 addition & 1 deletion op-node/l2/ssz.go → op-node/eth/ssz.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package l2
package eth

import (
"encoding/binary"
Expand Down
2 changes: 1 addition & 1 deletion op-node/l2/ssz_test.go → op-node/eth/ssz_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package l2
package eth

import (
"bytes"
Expand Down
13 changes: 5 additions & 8 deletions op-node/l2/api.go → op-node/eth/types.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Package l2 connects to the L2 execution engine over the Engine API.
package l2
package eth

import (
"bytes"
Expand All @@ -9,8 +8,6 @@ import (

"github.com/ethereum/go-ethereum/trie"

"github.com/ethereum-optimism/optimism/op-node/eth"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/beacon"
Expand Down Expand Up @@ -111,16 +108,16 @@ type ExecutionPayload struct {
Transactions []Data `json:"transactions"`
}

func (payload *ExecutionPayload) ID() eth.BlockID {
return eth.BlockID{Hash: payload.BlockHash, Number: uint64(payload.BlockNumber)}
func (payload *ExecutionPayload) ID() BlockID {
return BlockID{Hash: payload.BlockHash, Number: uint64(payload.BlockNumber)}
}

func (payload *ExecutionPayload) ParentID() eth.BlockID {
func (payload *ExecutionPayload) ParentID() BlockID {
n := uint64(payload.BlockNumber)
if n > 0 {
n -= 1
}
return eth.BlockID{Hash: payload.ParentHash, Number: n}
return BlockID{Hash: payload.ParentHash, Number: n}
}

type rawTransactions []Data
Expand Down
86 changes: 23 additions & 63 deletions op-node/l2/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,26 @@ func (s *Source) Close() {
s.rpc.Close()
}

func (s *Source) PayloadByHash(ctx context.Context, hash common.Hash) (*ExecutionPayload, error) {
func (s *Source) PayloadByHash(ctx context.Context, hash common.Hash) (*eth.ExecutionPayload, error) {
// TODO: we really do not need to parse every single tx and block detail, keeping transactions encoded is faster.
block, err := s.client.BlockByHash(ctx, hash)
if err != nil {
return nil, fmt.Errorf("failed to retrieve L2 block by hash: %v", err)
}
payload, err := BlockAsPayload(block)
payload, err := eth.BlockAsPayload(block)
if err != nil {
return nil, fmt.Errorf("failed to read L2 block as payload: %w", err)
}
return payload, nil
}

func (s *Source) PayloadByNumber(ctx context.Context, number *big.Int) (*ExecutionPayload, error) {
func (s *Source) PayloadByNumber(ctx context.Context, number *big.Int) (*eth.ExecutionPayload, error) {
// TODO: we really do not need to parse every single tx and block detail, keeping transactions encoded is faster.
block, err := s.client.BlockByNumber(ctx, number)
if err != nil {
return nil, fmt.Errorf("failed to retrieve L2 block by number: %v", err)
}
payload, err := BlockAsPayload(block)
payload, err := eth.BlockAsPayload(block)
if err != nil {
return nil, fmt.Errorf("failed to read L2 block as payload: %w", err)
}
Expand All @@ -67,12 +67,12 @@ func (s *Source) PayloadByNumber(ctx context.Context, number *big.Int) (*Executi
// ForkchoiceUpdate updates the forkchoice on the execution client. If attributes is not nil, the engine client will also begin building a block
// based on attributes after the new head block and return the payload ID.
// May return an error in ForkChoiceResult, but the error is marshalled into the error return
func (s *Source) ForkchoiceUpdate(ctx context.Context, fc *ForkchoiceState, attributes *PayloadAttributes) (*ForkchoiceUpdatedResult, error) {
func (s *Source) ForkchoiceUpdate(ctx context.Context, fc *eth.ForkchoiceState, attributes *eth.PayloadAttributes) (*eth.ForkchoiceUpdatedResult, error) {
e := s.log.New("state", fc, "attr", attributes)
e.Debug("Sharing forkchoice-updated signal")
fcCtx, cancel := context.WithTimeout(ctx, time.Second*5)
defer cancel()
var result ForkchoiceUpdatedResult
var result eth.ForkchoiceUpdatedResult
err := s.rpc.CallContext(fcCtx, &result, "engine_forkchoiceUpdatedV1", fc, attributes)
if err == nil {
e.Debug("Shared forkchoice-updated signal")
Expand All @@ -82,35 +82,35 @@ func (s *Source) ForkchoiceUpdate(ctx context.Context, fc *ForkchoiceState, attr
} else {
e = e.New("err", err)
if rpcErr, ok := err.(rpc.Error); ok {
code := ErrorCode(rpcErr.ErrorCode())
code := eth.ErrorCode(rpcErr.ErrorCode())
e.Warn("Unexpected error code in forkchoice-updated response", "code", code)
} else {
e.Error("Failed to share forkchoice-updated signal")
}
}
switch result.PayloadStatus.Status {
case ExecutionSyncing:
case eth.ExecutionSyncing:
return nil, fmt.Errorf("updated forkchoice, but node is syncing: %v", err)
case ExecutionAccepted, ExecutionInvalidTerminalBlock, ExecutionInvalidBlockHash:
case eth.ExecutionAccepted, eth.ExecutionInvalidTerminalBlock, eth.ExecutionInvalidBlockHash:
// ACCEPTED, INVALID_TERMINAL_BLOCK, INVALID_BLOCK_HASH are only for execution
return nil, fmt.Errorf("unexpected %s status, could not update forkchoice: %v", result.PayloadStatus.Status, err)
case ExecutionInvalid:
case eth.ExecutionInvalid:
return nil, fmt.Errorf("cannot update forkchoice, block is invalid: %v", err)
case ExecutionValid:
case eth.ExecutionValid:
return &result, nil
default:
return nil, fmt.Errorf("unknown forkchoice status on %s: %q, ", fc.SafeBlockHash, string(result.PayloadStatus.Status))
}
}

// ExecutePayload executes a built block on the execution engine and returns an error if it was not successful.
func (s *Source) NewPayload(ctx context.Context, payload *ExecutionPayload) error {
func (s *Source) NewPayload(ctx context.Context, payload *eth.ExecutionPayload) error {
e := s.log.New("block_hash", payload.BlockHash)
e.Debug("sending payload for execution")

execCtx, cancel := context.WithTimeout(ctx, time.Second*5)
defer cancel()
var result PayloadStatusV1
var result eth.PayloadStatusV1
err := s.rpc.CallContext(execCtx, &result, "engine_newPayloadV1", payload)
e.Debug("Received payload execution result", "status", result.Status, "latestValidHash", result.LatestValidHash, "message", result.ValidationError)
if err != nil {
Expand All @@ -119,34 +119,34 @@ func (s *Source) NewPayload(ctx context.Context, payload *ExecutionPayload) erro
}

switch result.Status {
case ExecutionValid:
case eth.ExecutionValid:
return nil
case ExecutionSyncing:
case eth.ExecutionSyncing:
return fmt.Errorf("failed to execute payload %s, node is syncing", payload.ID())
case ExecutionInvalid:
case eth.ExecutionInvalid:
return fmt.Errorf("execution payload %s was INVALID! Latest valid hash is %s, ignoring bad block: %q", payload.ID(), result.LatestValidHash, result.ValidationError)
case ExecutionInvalidBlockHash:
case eth.ExecutionInvalidBlockHash:
return fmt.Errorf("execution payload %s has INVALID BLOCKHASH! %v", payload.BlockHash, result.ValidationError)
case ExecutionInvalidTerminalBlock:
case eth.ExecutionInvalidTerminalBlock:
return fmt.Errorf("engine is misconfigured. Received invalid-terminal-block error while engine API should be active at genesis. err: %v", result.ValidationError)
case ExecutionAccepted:
case eth.ExecutionAccepted:
return fmt.Errorf("execution payload cannot be validated yet, latest valid hash is %s", result.LatestValidHash)
default:
return fmt.Errorf("unknown execution status on %s: %q, ", payload.ID(), string(result.Status))
}
}

// GetPayload gets the execution payload associated with the PayloadId
func (s *Source) GetPayload(ctx context.Context, payloadId PayloadID) (*ExecutionPayload, error) {
func (s *Source) GetPayload(ctx context.Context, payloadId eth.PayloadID) (*eth.ExecutionPayload, error) {
e := s.log.New("payload_id", payloadId)
e.Debug("getting payload")
var result ExecutionPayload
var result eth.ExecutionPayload
err := s.rpc.CallContext(ctx, &result, "engine_getPayloadV1", payloadId)
if err != nil {
e = e.New("payload_id", payloadId, "err", err)
if rpcErr, ok := err.(rpc.Error); ok {
code := ErrorCode(rpcErr.ErrorCode())
if code != UnavailablePayload {
code := eth.ErrorCode(rpcErr.ErrorCode())
if code != eth.UnavailablePayload {
e.Warn("unexpected error code in get-payload response", "code", code)
} else {
e.Warn("unavailable payload in get-payload request")
Expand Down Expand Up @@ -217,46 +217,6 @@ func blockToBlockRef(block *types.Block, genesis *rollup.Genesis) (eth.L2BlockRe
}, nil
}

// PayloadToBlockRef extracts the essential L2BlockRef information from an execution payload,
// falling back to genesis information if necessary.
func PayloadToBlockRef(payload *ExecutionPayload, genesis *rollup.Genesis) (eth.L2BlockRef, error) {
var l1Origin eth.BlockID
var sequenceNumber uint64
if uint64(payload.BlockNumber) == genesis.L2.Number {
if payload.BlockHash != genesis.L2.Hash {
return eth.L2BlockRef{}, fmt.Errorf("expected L2 genesis hash to match L2 block at genesis block number %d: %s <> %s", genesis.L2.Number, payload.BlockHash, genesis.L2.Hash)
}
l1Origin = genesis.L1
sequenceNumber = 0
} else {
if len(payload.Transactions) == 0 {
return eth.L2BlockRef{}, fmt.Errorf("l2 block is missing L1 info deposit tx, block hash: %s", payload.BlockHash)
}
var tx types.Transaction
if err := tx.UnmarshalBinary(payload.Transactions[0]); err != nil {
return eth.L2BlockRef{}, fmt.Errorf("failed to decode first tx to read l1 info from: %v", err)
}
if tx.Type() != types.DepositTxType {
return eth.L2BlockRef{}, fmt.Errorf("first payload tx has unexpected tx type: %d", tx.Type())
}
info, err := derive.L1InfoDepositTxData(tx.Data())
if err != nil {
return eth.L2BlockRef{}, fmt.Errorf("failed to parse L1 info deposit tx from L2 block: %v", err)
}
l1Origin = eth.BlockID{Hash: info.BlockHash, Number: info.Number}
sequenceNumber = info.SequenceNumber
}

return eth.L2BlockRef{
Hash: payload.BlockHash,
Number: uint64(payload.BlockNumber),
ParentHash: payload.ParentHash,
Time: uint64(payload.Timestamp),
L1Origin: l1Origin,
SequenceNumber: sequenceNumber,
}, nil
}

type ReadOnlySource struct {
rpc *rpc.Client // raw RPC client. Used for methods that do not already have bindings
client *ethclient.Client // go-ethereum's wrapper around the rpc client for the eth namespace
Expand Down
6 changes: 4 additions & 2 deletions op-node/l2/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"fmt"
"math/big"

"github.com/ethereum-optimism/optimism/op-node/eth"

"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/core/types"
Expand All @@ -20,13 +22,13 @@ import (
"github.com/ethereum/go-ethereum/trie"
)

func ComputeL2OutputRoot(l2OutputRootVersion Bytes32, blockHash common.Hash, blockRoot common.Hash, storageRoot common.Hash) Bytes32 {
func ComputeL2OutputRoot(l2OutputRootVersion eth.Bytes32, blockHash common.Hash, blockRoot common.Hash, storageRoot common.Hash) eth.Bytes32 {
var buf bytes.Buffer
buf.Write(l2OutputRootVersion[:])
buf.Write(blockRoot.Bytes())
buf.Write(storageRoot[:])
buf.Write(blockHash.Bytes())
return Bytes32(crypto.Keccak256Hash(buf.Bytes()))
return eth.Bytes32(crypto.Keccak256Hash(buf.Bytes()))
}

type AccountResult struct {
Expand Down
6 changes: 3 additions & 3 deletions op-node/node/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func newNodeAPI(config *rollup.Config, l2Client l2EthClient, log log.Logger) *no
}
}

func (n *nodeAPI) OutputAtBlock(ctx context.Context, number rpc.BlockNumber) ([]l2.Bytes32, error) {
func (n *nodeAPI) OutputAtBlock(ctx context.Context, number rpc.BlockNumber) ([]eth.Bytes32, error) {
// TODO: rpc.BlockNumber doesn't support the "safe" tag. Need a new type

head, err := n.client.GetBlockHeader(ctx, toBlockNumArg(number))
Expand All @@ -76,10 +76,10 @@ func (n *nodeAPI) OutputAtBlock(ctx context.Context, number rpc.BlockNumber) ([]
return nil, fmt.Errorf("invalid withdrawal root hash")
}

var l2OutputRootVersion l2.Bytes32 // it's zero for now
var l2OutputRootVersion eth.Bytes32 // it's zero for now
l2OutputRoot := l2.ComputeL2OutputRoot(l2OutputRootVersion, head.Hash(), head.Root, proof.StorageHash)

return []l2.Bytes32{l2OutputRootVersion, l2OutputRoot}, nil
return []eth.Bytes32{l2OutputRootVersion, l2OutputRoot}, nil
}

func (n *nodeAPI) Version(ctx context.Context) (string, error) {
Expand Down
9 changes: 4 additions & 5 deletions op-node/node/comms.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,23 @@ import (
"context"

"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/l2"
"github.com/libp2p/go-libp2p-core/peer"
)

// Tracer configures the OpNode to share events
type Tracer interface {
OnNewL1Head(ctx context.Context, sig eth.L1BlockRef)
OnUnsafeL2Payload(ctx context.Context, from peer.ID, payload *l2.ExecutionPayload)
OnPublishL2Payload(ctx context.Context, payload *l2.ExecutionPayload)
OnUnsafeL2Payload(ctx context.Context, from peer.ID, payload *eth.ExecutionPayload)
OnPublishL2Payload(ctx context.Context, payload *eth.ExecutionPayload)
}

type noOpTracer struct{}

func (n noOpTracer) OnNewL1Head(ctx context.Context, sig eth.L1BlockRef) {}

func (n noOpTracer) OnUnsafeL2Payload(ctx context.Context, from peer.ID, payload *l2.ExecutionPayload) {
func (n noOpTracer) OnUnsafeL2Payload(ctx context.Context, from peer.ID, payload *eth.ExecutionPayload) {
}

func (n noOpTracer) OnPublishL2Payload(ctx context.Context, payload *l2.ExecutionPayload) {}
func (n noOpTracer) OnPublishL2Payload(ctx context.Context, payload *eth.ExecutionPayload) {}

var _ Tracer = (*noOpTracer)(nil)
Loading