github.com/ethereum-optimism/optimism@v1.7.2/op-node/rollup/derive/l1_block_info.go (about)

     1  package derive
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"math/big"
     9  
    10  	"github.com/ethereum/go-ethereum/common"
    11  	"github.com/ethereum/go-ethereum/core/types"
    12  	"github.com/ethereum/go-ethereum/crypto"
    13  
    14  	"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
    15  	"github.com/ethereum-optimism/optimism/op-node/rollup"
    16  	"github.com/ethereum-optimism/optimism/op-service/eth"
    17  	"github.com/ethereum-optimism/optimism/op-service/solabi"
    18  )
    19  
    20  const (
    21  	L1InfoFuncBedrockSignature = "setL1BlockValues(uint64,uint64,uint256,bytes32,uint64,bytes32,uint256,uint256)"
    22  	L1InfoFuncEcotoneSignature = "setL1BlockValuesEcotone()"
    23  	L1InfoArguments            = 8
    24  	L1InfoBedrockLen           = 4 + 32*L1InfoArguments
    25  	L1InfoEcotoneLen           = 4 + 32*5 // after Ecotone upgrade, args are packed into 5 32-byte slots
    26  )
    27  
    28  var (
    29  	L1InfoFuncBedrockBytes4 = crypto.Keccak256([]byte(L1InfoFuncBedrockSignature))[:4]
    30  	L1InfoFuncEcotoneBytes4 = crypto.Keccak256([]byte(L1InfoFuncEcotoneSignature))[:4]
    31  	L1InfoDepositerAddress  = common.HexToAddress("0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001")
    32  	L1BlockAddress          = predeploys.L1BlockAddr
    33  )
    34  
    35  const (
    36  	RegolithSystemTxGas = 1_000_000
    37  )
    38  
    39  // L1BlockInfo presents the information stored in a L1Block.setL1BlockValues call
    40  type L1BlockInfo struct {
    41  	Number    uint64
    42  	Time      uint64
    43  	BaseFee   *big.Int
    44  	BlockHash common.Hash
    45  	// Not strictly a piece of L1 information. Represents the number of L2 blocks since the start of the epoch,
    46  	// i.e. when the actual L1 info was first introduced.
    47  	SequenceNumber uint64
    48  	// BatcherHash version 0 is just the address with 0 padding to the left.
    49  	BatcherAddr common.Address
    50  
    51  	L1FeeOverhead eth.Bytes32 // ignored after Ecotone upgrade
    52  	L1FeeScalar   eth.Bytes32 // ignored after Ecotone upgrade
    53  
    54  	BlobBaseFee       *big.Int // added by Ecotone upgrade
    55  	BaseFeeScalar     uint32   // added by Ecotone upgrade
    56  	BlobBaseFeeScalar uint32   // added by Ecotone upgrade
    57  }
    58  
    59  // Bedrock Binary Format
    60  // +---------+--------------------------+
    61  // | Bytes   | Field                    |
    62  // +---------+--------------------------+
    63  // | 4       | Function signature       |
    64  // | 32      | Number                   |
    65  // | 32      | Time                     |
    66  // | 32      | BaseFee                  |
    67  // | 32      | BlockHash                |
    68  // | 32      | SequenceNumber           |
    69  // | 32      | BatcherHash              |
    70  // | 32      | L1FeeOverhead            |
    71  // | 32      | L1FeeScalar              |
    72  // +---------+--------------------------+
    73  
    74  func (info *L1BlockInfo) marshalBinaryBedrock() ([]byte, error) {
    75  	w := bytes.NewBuffer(make([]byte, 0, L1InfoBedrockLen))
    76  	if err := solabi.WriteSignature(w, L1InfoFuncBedrockBytes4); err != nil {
    77  		return nil, err
    78  	}
    79  	if err := solabi.WriteUint64(w, info.Number); err != nil {
    80  		return nil, err
    81  	}
    82  	if err := solabi.WriteUint64(w, info.Time); err != nil {
    83  		return nil, err
    84  	}
    85  	if err := solabi.WriteUint256(w, info.BaseFee); err != nil {
    86  		return nil, err
    87  	}
    88  	if err := solabi.WriteHash(w, info.BlockHash); err != nil {
    89  		return nil, err
    90  	}
    91  	if err := solabi.WriteUint64(w, info.SequenceNumber); err != nil {
    92  		return nil, err
    93  	}
    94  	if err := solabi.WriteAddress(w, info.BatcherAddr); err != nil {
    95  		return nil, err
    96  	}
    97  	if err := solabi.WriteEthBytes32(w, info.L1FeeOverhead); err != nil {
    98  		return nil, err
    99  	}
   100  	if err := solabi.WriteEthBytes32(w, info.L1FeeScalar); err != nil {
   101  		return nil, err
   102  	}
   103  	return w.Bytes(), nil
   104  }
   105  
   106  func (info *L1BlockInfo) unmarshalBinaryBedrock(data []byte) error {
   107  	if len(data) != L1InfoBedrockLen {
   108  		return fmt.Errorf("data is unexpected length: %d", len(data))
   109  	}
   110  	reader := bytes.NewReader(data)
   111  
   112  	var err error
   113  	if _, err := solabi.ReadAndValidateSignature(reader, L1InfoFuncBedrockBytes4); err != nil {
   114  		return err
   115  	}
   116  	if info.Number, err = solabi.ReadUint64(reader); err != nil {
   117  		return err
   118  	}
   119  	if info.Time, err = solabi.ReadUint64(reader); err != nil {
   120  		return err
   121  	}
   122  	if info.BaseFee, err = solabi.ReadUint256(reader); err != nil {
   123  		return err
   124  	}
   125  	if info.BlockHash, err = solabi.ReadHash(reader); err != nil {
   126  		return err
   127  	}
   128  	if info.SequenceNumber, err = solabi.ReadUint64(reader); err != nil {
   129  		return err
   130  	}
   131  	if info.BatcherAddr, err = solabi.ReadAddress(reader); err != nil {
   132  		return err
   133  	}
   134  	if info.L1FeeOverhead, err = solabi.ReadEthBytes32(reader); err != nil {
   135  		return err
   136  	}
   137  	if info.L1FeeScalar, err = solabi.ReadEthBytes32(reader); err != nil {
   138  		return err
   139  	}
   140  	if !solabi.EmptyReader(reader) {
   141  		return errors.New("too many bytes")
   142  	}
   143  	return nil
   144  }
   145  
   146  // Ecotone Binary Format
   147  // +---------+--------------------------+
   148  // | Bytes   | Field                    |
   149  // +---------+--------------------------+
   150  // | 4       | Function signature       |
   151  // | 4       | BaseFeeScalar            |
   152  // | 4       | BlobBaseFeeScalar        |
   153  // | 8       | SequenceNumber           |
   154  // | 8       | Timestamp                |
   155  // | 8       | L1BlockNumber            |
   156  // | 32      | BaseFee                  |
   157  // | 32      | BlobBaseFee              |
   158  // | 32      | BlockHash                |
   159  // | 32      | BatcherHash              |
   160  // +---------+--------------------------+
   161  
   162  func (info *L1BlockInfo) marshalBinaryEcotone() ([]byte, error) {
   163  	w := bytes.NewBuffer(make([]byte, 0, L1InfoEcotoneLen))
   164  	if err := solabi.WriteSignature(w, L1InfoFuncEcotoneBytes4); err != nil {
   165  		return nil, err
   166  	}
   167  	if err := binary.Write(w, binary.BigEndian, info.BaseFeeScalar); err != nil {
   168  		return nil, err
   169  	}
   170  	if err := binary.Write(w, binary.BigEndian, info.BlobBaseFeeScalar); err != nil {
   171  		return nil, err
   172  	}
   173  	if err := binary.Write(w, binary.BigEndian, info.SequenceNumber); err != nil {
   174  		return nil, err
   175  	}
   176  	if err := binary.Write(w, binary.BigEndian, info.Time); err != nil {
   177  		return nil, err
   178  	}
   179  	if err := binary.Write(w, binary.BigEndian, info.Number); err != nil {
   180  		return nil, err
   181  	}
   182  	if err := solabi.WriteUint256(w, info.BaseFee); err != nil {
   183  		return nil, err
   184  	}
   185  	blobBasefee := info.BlobBaseFee
   186  	if blobBasefee == nil {
   187  		blobBasefee = big.NewInt(1) // set to 1, to match the min blob basefee as defined in EIP-4844
   188  	}
   189  	if err := solabi.WriteUint256(w, blobBasefee); err != nil {
   190  		return nil, err
   191  	}
   192  	if err := solabi.WriteHash(w, info.BlockHash); err != nil {
   193  		return nil, err
   194  	}
   195  	// ABI encoding will perform the left-padding with zeroes to 32 bytes, matching the "batcherHash" SystemConfig format and version 0 byte.
   196  	if err := solabi.WriteAddress(w, info.BatcherAddr); err != nil {
   197  		return nil, err
   198  	}
   199  	return w.Bytes(), nil
   200  }
   201  
   202  func (info *L1BlockInfo) unmarshalBinaryEcotone(data []byte) error {
   203  	if len(data) != L1InfoEcotoneLen {
   204  		return fmt.Errorf("data is unexpected length: %d", len(data))
   205  	}
   206  	r := bytes.NewReader(data)
   207  
   208  	var err error
   209  	if _, err := solabi.ReadAndValidateSignature(r, L1InfoFuncEcotoneBytes4); err != nil {
   210  		return err
   211  	}
   212  	if err := binary.Read(r, binary.BigEndian, &info.BaseFeeScalar); err != nil {
   213  		return fmt.Errorf("invalid ecotone l1 block info format")
   214  	}
   215  	if err := binary.Read(r, binary.BigEndian, &info.BlobBaseFeeScalar); err != nil {
   216  		return fmt.Errorf("invalid ecotone l1 block info format")
   217  	}
   218  	if err := binary.Read(r, binary.BigEndian, &info.SequenceNumber); err != nil {
   219  		return fmt.Errorf("invalid ecotone l1 block info format")
   220  	}
   221  	if err := binary.Read(r, binary.BigEndian, &info.Time); err != nil {
   222  		return fmt.Errorf("invalid ecotone l1 block info format")
   223  	}
   224  	if err := binary.Read(r, binary.BigEndian, &info.Number); err != nil {
   225  		return fmt.Errorf("invalid ecotone l1 block info format")
   226  	}
   227  	if info.BaseFee, err = solabi.ReadUint256(r); err != nil {
   228  		return err
   229  	}
   230  	if info.BlobBaseFee, err = solabi.ReadUint256(r); err != nil {
   231  		return err
   232  	}
   233  	if info.BlockHash, err = solabi.ReadHash(r); err != nil {
   234  		return err
   235  	}
   236  	// The "batcherHash" will be correctly parsed as address, since the version 0 and left-padding matches the ABI encoding format.
   237  	if info.BatcherAddr, err = solabi.ReadAddress(r); err != nil {
   238  		return err
   239  	}
   240  	if !solabi.EmptyReader(r) {
   241  		return errors.New("too many bytes")
   242  	}
   243  	return nil
   244  }
   245  
   246  // isEcotoneButNotFirstBlock returns whether the specified block is subject to the Ecotone upgrade,
   247  // but is not the actiation block itself.
   248  func isEcotoneButNotFirstBlock(rollupCfg *rollup.Config, l2BlockTime uint64) bool {
   249  	return rollupCfg.IsEcotone(l2BlockTime) && !rollupCfg.IsEcotoneActivationBlock(l2BlockTime)
   250  }
   251  
   252  // L1BlockInfoFromBytes is the inverse of L1InfoDeposit, to see where the L2 chain is derived from
   253  func L1BlockInfoFromBytes(rollupCfg *rollup.Config, l2BlockTime uint64, data []byte) (*L1BlockInfo, error) {
   254  	var info L1BlockInfo
   255  	if isEcotoneButNotFirstBlock(rollupCfg, l2BlockTime) {
   256  		return &info, info.unmarshalBinaryEcotone(data)
   257  	}
   258  	return &info, info.unmarshalBinaryBedrock(data)
   259  }
   260  
   261  // L1InfoDeposit creates a L1 Info deposit transaction based on the L1 block,
   262  // and the L2 block-height difference with the start of the epoch.
   263  func L1InfoDeposit(rollupCfg *rollup.Config, sysCfg eth.SystemConfig, seqNumber uint64, block eth.BlockInfo, l2BlockTime uint64) (*types.DepositTx, error) {
   264  	l1BlockInfo := L1BlockInfo{
   265  		Number:         block.NumberU64(),
   266  		Time:           block.Time(),
   267  		BaseFee:        block.BaseFee(),
   268  		BlockHash:      block.Hash(),
   269  		SequenceNumber: seqNumber,
   270  		BatcherAddr:    sysCfg.BatcherAddr,
   271  	}
   272  	var data []byte
   273  	if isEcotoneButNotFirstBlock(rollupCfg, l2BlockTime) {
   274  		l1BlockInfo.BlobBaseFee = block.BlobBaseFee()
   275  		if l1BlockInfo.BlobBaseFee == nil {
   276  			// The L2 spec states to use the MIN_BLOB_GASPRICE from EIP-4844 if not yet active on L1.
   277  			l1BlockInfo.BlobBaseFee = big.NewInt(1)
   278  		}
   279  		blobBaseFeeScalar, baseFeeScalar, err := sysCfg.EcotoneScalars()
   280  		if err != nil {
   281  			return nil, err
   282  		}
   283  		l1BlockInfo.BlobBaseFeeScalar = blobBaseFeeScalar
   284  		l1BlockInfo.BaseFeeScalar = baseFeeScalar
   285  		out, err := l1BlockInfo.marshalBinaryEcotone()
   286  		if err != nil {
   287  			return nil, fmt.Errorf("failed to marshal Ecotone l1 block info: %w", err)
   288  		}
   289  		data = out
   290  	} else {
   291  		l1BlockInfo.L1FeeOverhead = sysCfg.Overhead
   292  		l1BlockInfo.L1FeeScalar = sysCfg.Scalar
   293  		out, err := l1BlockInfo.marshalBinaryBedrock()
   294  		if err != nil {
   295  			return nil, fmt.Errorf("failed to marshal Bedrock l1 block info: %w", err)
   296  		}
   297  		data = out
   298  	}
   299  
   300  	source := L1InfoDepositSource{
   301  		L1BlockHash: block.Hash(),
   302  		SeqNumber:   seqNumber,
   303  	}
   304  	// Set a very large gas limit with `IsSystemTransaction` to ensure
   305  	// that the L1 Attributes Transaction does not run out of gas.
   306  	out := &types.DepositTx{
   307  		SourceHash:          source.SourceHash(),
   308  		From:                L1InfoDepositerAddress,
   309  		To:                  &L1BlockAddress,
   310  		Mint:                nil,
   311  		Value:               big.NewInt(0),
   312  		Gas:                 150_000_000,
   313  		IsSystemTransaction: true,
   314  		Data:                data,
   315  	}
   316  	// With the regolith fork we disable the IsSystemTx functionality, and allocate real gas
   317  	if rollupCfg.IsRegolith(l2BlockTime) {
   318  		out.IsSystemTransaction = false
   319  		out.Gas = RegolithSystemTxGas
   320  	}
   321  	return out, nil
   322  }
   323  
   324  // L1InfoDepositBytes returns a serialized L1-info attributes transaction.
   325  func L1InfoDepositBytes(rollupCfg *rollup.Config, sysCfg eth.SystemConfig, seqNumber uint64, l1Info eth.BlockInfo, l2BlockTime uint64) ([]byte, error) {
   326  	dep, err := L1InfoDeposit(rollupCfg, sysCfg, seqNumber, l1Info, l2BlockTime)
   327  	if err != nil {
   328  		return nil, fmt.Errorf("failed to create L1 info tx: %w", err)
   329  	}
   330  	l1Tx := types.NewTx(dep)
   331  	opaqueL1Tx, err := l1Tx.MarshalBinary()
   332  	if err != nil {
   333  		return nil, fmt.Errorf("failed to encode L1 info tx: %w", err)
   334  	}
   335  	return opaqueL1Tx, nil
   336  }