payload_util.go 4.04 KB
Newer Older
1 2 3
package derive

import (
4
	"encoding/binary"
5 6
	"fmt"

7
	"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
8 9
	"github.com/ethereum/go-ethereum/core/types"

10
	"github.com/ethereum-optimism/optimism/op-node/rollup"
11
	"github.com/ethereum-optimism/optimism/op-service/eth"
12 13 14 15
)

// PayloadToBlockRef extracts the essential L2BlockRef information from an execution payload,
// falling back to genesis information if necessary.
16 17
func PayloadToBlockRef(rollupCfg *rollup.Config, payload *eth.ExecutionPayload) (eth.L2BlockRef, error) {
	genesis := &rollupCfg.Genesis
18 19 20 21 22 23 24 25 26 27 28 29 30 31
	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 {
32
			return eth.L2BlockRef{}, fmt.Errorf("failed to decode first tx to read l1 info from: %w", err)
33 34 35 36
		}
		if tx.Type() != types.DepositTxType {
			return eth.L2BlockRef{}, fmt.Errorf("first payload tx has unexpected tx type: %d", tx.Type())
		}
37
		info, err := L1BlockInfoFromBytes(rollupCfg, uint64(payload.Timestamp), tx.Data())
38
		if err != nil {
39
			return eth.L2BlockRef{}, fmt.Errorf("failed to parse L1 info deposit tx from L2 block: %w", err)
40 41 42 43 44 45 46 47 48 49 50 51 52 53
		}
		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
}
54

55 56 57 58 59 60
func PayloadToSystemConfig(rollupCfg *rollup.Config, payload *eth.ExecutionPayload) (eth.SystemConfig, error) {
	if uint64(payload.BlockNumber) == rollupCfg.Genesis.L2.Number {
		if payload.BlockHash != rollupCfg.Genesis.L2.Hash {
			return eth.SystemConfig{}, fmt.Errorf(
				"expected L2 genesis hash to match L2 block at genesis block number %d: %s <> %s",
				rollupCfg.Genesis.L2.Number, payload.BlockHash, rollupCfg.Genesis.L2.Hash)
61
		}
62
		return rollupCfg.Genesis.SystemConfig, nil
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
	}

	if len(payload.Transactions) == 0 {
		return eth.SystemConfig{}, 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.SystemConfig{}, fmt.Errorf("failed to decode first tx to read l1 info from: %w", err)
	}
	if tx.Type() != types.DepositTxType {
		return eth.SystemConfig{}, fmt.Errorf("first payload tx has unexpected tx type: %d", tx.Type())
	}
	info, err := L1BlockInfoFromBytes(rollupCfg, uint64(payload.Timestamp), tx.Data())
	if err != nil {
		return eth.SystemConfig{}, fmt.Errorf("failed to parse L1 info deposit tx from L2 block: %w", err)
	}
	if isEcotoneButNotFirstBlock(rollupCfg, uint64(payload.Timestamp)) {
		// Translate Ecotone values back into encoded scalar if needed.
		// We do not know if it was derived from a v0 or v1 scalar,
		// but v1 is fine, a 0 blob base fee has the same effect.
		info.L1FeeScalar[0] = 1
		binary.BigEndian.PutUint32(info.L1FeeScalar[24:28], info.BlobBaseFeeScalar)
		binary.BigEndian.PutUint32(info.L1FeeScalar[28:32], info.BaseFeeScalar)
	}
	r := eth.SystemConfig{
		BatcherAddr: info.BatcherAddr,
		Overhead:    info.L1FeeOverhead,
		Scalar:      info.L1FeeScalar,
		GasLimit:    uint64(payload.GasLimit),
	}
	if rollupCfg.IsHolocene(uint64(payload.Timestamp)) {
		if err := eip1559.ValidateHoloceneExtraData(payload.ExtraData); err != nil {
			return eth.SystemConfig{}, err
96
		}
97 98
		d, e := eip1559.DecodeHoloceneExtraData(payload.ExtraData)
		copy(r.EIP1559Params[:], eip1559.EncodeHolocene1559Params(d, e))
99
	}
100
	return r, nil
101
}