op-geth/beacon/engine/types.go
Joshua Gutow c48b8aab5a
optimism: historical Bedrock geth rollup changes
This commit squashes the op-geth fork history into a more maintainable
diff for rebasing upon upstream geth.

reference-optimistic-geth changes (origins of op-geth in early Bedrock
development stage):
- Deposit TX Type
- Enable deposit tx in EVM/tx pool
- Change deposit nonce to not be the max nonce
- Extend PayloadAttributesV1 with a Transactions field
- Force deposits at the start of each L2 block
- Fix height check
- noTxPool flag, reproduce block in verifier mode without tx pool interference
- Fix RPC json marshalling (ref op-geth PR 4)
- Deposit txs block height check in block body validation (ref op-geth PR 5)
- core: do not try to reinject deposit txs into tx-pool (ref-op-geth PR 6)
- deposit source hash field instead of L2 block height and tx index combination
- Include invalid deposits, rewind state, but always persist mint (#10)
- Provide gas to Call/Create in deposit transactions (#12)
- Add docker builds (ref-op-geth PR 16, 17)
- Don't panic on deposit transaction signature values or chain ID (ref-op-geth PR 18)
- core: Add version to DepositTx (ref-op-geth PR 19)
- Enable Geth build/lint/test in CircleCI (ref-op-geth PR 23)
- core: Include guaranteed gas in the gas pool (ref-op-geth PR 21)
- core: handle base fee, l1 availability fee, tx fee (ref-op-geth PR 27)
- fix: deposit tx hash
- fix l1 fee cache, rpc, tracing and tx pool
- core: remove deposit-tx sub-type (a.k.a. deposit version byte)
- eth/catalyst: allow engine user to reorg own chain
- miner: restore ability to reorg deep as block builder
- params: print Optimism consensus type in banner
- core/types: remove unused protected() method, see upstream PR 23376
- core: do not mutate original balance value in tx pool l1 cost adjustment
- core: subtract deposit gas from pool, so other txs do not use the same gas. And fail tx processing if deposits reach gas limit
- core/types: deposits do not tip, avoid basefee subtraction
- Unmeter the L1 Attributes Transaction
- miner: handle force tx errors as critical, clean up diff
- ci: Switch branch
- eth,miner: return STATUS_INVALID when failing to process forced transactions in request (ref-op-geth PR 40)
- verifier: forward tx to sequencer based on flag
- txpool: add flag to disable tx gossip (ref-op-geth PR 42)
- Add op-geth version in addition to geth version (ref-op-geth PR 43)
- ci: CircleCI improvements (ref-op-geth PR 44)
- Rename to op-geth
- Build latest tag on optimism branch

op-geth changes:
- Expose cache config in simulated backend (#2)
- Add EIP-1559 parameters
- eth/catalyst: update payload id computation (#1)
- make eip1559 configurable (#4)
- post-merge network should not log warnings about missing transition information (#5)
- Make the simulator more configurable (#6)
- fix OPB-6 - IsDepositTx check instead of artificial nonce value check (#7)
- Simulated backend - enable proof of stake consensus type and fix performance issue (#8)
- accounts: simulated backend consensus engine option and immediate tx indexing
- consensus/beacon: recognize all blocks as reached TTD with 0 TTD in chain config
- Add --rollup.historicalhttp CLI flag and fix backend iface
- Flags and interfaces for historical RPC requests (#12)
- Redirect historical RPC requests (#13)
- Use the pre-existing ethereum.NotFound error (#18)
- Add historical endpoint to TraceBlockByNumber and TraceBlockByHash (#19)
- Add historical endpoint to TraceTransaction (#20)
- Add historical endpoint to TraceCall (#21)
- optimism: fee params from info txi, update l1 cost func GPO params read (#15)
- add hardcoded addresses for fee payouts (#23)
- dynamic gas limit via engine API (#22)

Co-authored-by: Matthew Slipper <me@matthewslipper.com>
Co-authored-by: Joshua Gutow <jgutow@oplabs.co>
Co-authored-by: protolambda <proto@protolambda.com>
Co-authored-by: Mark Tyneway <mark.tyneway@gmail.com>
Co-authored-by: Maurelian <maurelian@protonmail.ch>
2023-02-22 09:49:38 -06:00

249 lines
9.7 KiB
Go

// Copyright 2022 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package engine
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/trie"
)
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
// PayloadAttributes describes the environment context in which a block should
// be built.
type PayloadAttributes struct {
Timestamp uint64 `json:"timestamp" gencodec:"required"`
Random common.Hash `json:"prevRandao" gencodec:"required"`
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty" gencodec:"optional"`
// Transactions is a field for rollups: the transactions list is forced into the block
Transactions [][]byte `json:"transactions,omitempty" gencodec:"optional"`
// NoTxPool is a field for rollups: if true, the no transactions are taken out of the tx-pool,
// only transactions from the above Transactions list will be included.
NoTxPool bool `json:"noTxPool,omitempty" gencodec:"optional"`
// GasLimit is a field for rollups: if set, this sets the exact gas limit the block produced with.
GasLimit *uint64 `json:"gasLimit,omitempty" gencodec:"optional"`
}
// JSON type overrides for PayloadAttributes.
type payloadAttributesMarshaling struct {
Timestamp hexutil.Uint64
Transactions []hexutil.Bytes
GasLimit *hexutil.Uint64
}
//go:generate go run github.com/fjl/gencodec -type ExecutableData -field-override executableDataMarshaling -out gen_ed.go
// ExecutableData is the data necessary to execute an EL payload.
type ExecutableData struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
LogsBloom []byte `json:"logsBloom" gencodec:"required"`
Random common.Hash `json:"prevRandao" gencodec:"required"`
Number uint64 `json:"blockNumber" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Timestamp uint64 `json:"timestamp" gencodec:"required"`
ExtraData []byte `json:"extraData" gencodec:"required"`
BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"`
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
Transactions [][]byte `json:"transactions" gencodec:"required"`
Withdrawals []*types.Withdrawal `json:"withdrawals"`
}
// JSON type overrides for executableData.
type executableDataMarshaling struct {
Number hexutil.Uint64
GasLimit hexutil.Uint64
GasUsed hexutil.Uint64
Timestamp hexutil.Uint64
BaseFeePerGas *hexutil.Big
ExtraData hexutil.Bytes
LogsBloom hexutil.Bytes
Transactions []hexutil.Bytes
}
//go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go
type ExecutionPayloadEnvelope struct {
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
BlockValue *big.Int `json:"blockValue" gencodec:"required"`
}
// JSON type overrides for ExecutionPayloadEnvelope.
type executionPayloadEnvelopeMarshaling struct {
BlockValue *hexutil.Big
}
type PayloadStatusV1 struct {
Status string `json:"status"`
LatestValidHash *common.Hash `json:"latestValidHash"`
ValidationError *string `json:"validationError"`
}
type TransitionConfigurationV1 struct {
TerminalTotalDifficulty *hexutil.Big `json:"terminalTotalDifficulty"`
TerminalBlockHash common.Hash `json:"terminalBlockHash"`
TerminalBlockNumber hexutil.Uint64 `json:"terminalBlockNumber"`
}
// PayloadID is an identifier of the payload build process
type PayloadID [8]byte
func (b PayloadID) String() string {
return hexutil.Encode(b[:])
}
func (b PayloadID) MarshalText() ([]byte, error) {
return hexutil.Bytes(b[:]).MarshalText()
}
func (b *PayloadID) UnmarshalText(input []byte) error {
err := hexutil.UnmarshalFixedText("PayloadID", input, b[:])
if err != nil {
return fmt.Errorf("invalid payload id %q: %w", input, err)
}
return nil
}
type ForkChoiceResponse struct {
PayloadStatus PayloadStatusV1 `json:"payloadStatus"`
PayloadID *PayloadID `json:"payloadId"`
}
type ForkchoiceStateV1 struct {
HeadBlockHash common.Hash `json:"headBlockHash"`
SafeBlockHash common.Hash `json:"safeBlockHash"`
FinalizedBlockHash common.Hash `json:"finalizedBlockHash"`
}
func encodeTransactions(txs []*types.Transaction) [][]byte {
var enc = make([][]byte, len(txs))
for i, tx := range txs {
enc[i], _ = tx.MarshalBinary()
}
return enc
}
func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
var txs = make([]*types.Transaction, len(enc))
for i, encTx := range enc {
var tx types.Transaction
if err := tx.UnmarshalBinary(encTx); err != nil {
return nil, fmt.Errorf("invalid transaction %d: %v", i, err)
}
txs[i] = &tx
}
return txs, nil
}
// ExecutableDataToBlock constructs a block from executable data.
// It verifies that the following fields:
//
// len(extraData) <= 32
// uncleHash = emptyUncleHash
// difficulty = 0
//
// and that the blockhash of the constructed block matches the parameters. Nil
// Withdrawals value will propagate through the returned block. Empty
// Withdrawals value must be passed via non-nil, length 0 value in params.
func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) {
txs, err := decodeTransactions(params.Transactions)
if err != nil {
return nil, err
}
if len(params.ExtraData) > 32 {
return nil, fmt.Errorf("invalid extradata length: %v", len(params.ExtraData))
}
if len(params.LogsBloom) != 256 {
return nil, fmt.Errorf("invalid logsBloom length: %v", len(params.LogsBloom))
}
// Check that baseFeePerGas is not negative or too big
if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) {
return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas)
}
// Only set withdrawalsRoot if it is non-nil. This allows CLs to use
// ExecutableData before withdrawals are enabled by marshaling
// Withdrawals as the json null value.
var withdrawalsRoot *common.Hash
if params.Withdrawals != nil {
h := types.DeriveSha(types.Withdrawals(params.Withdrawals), trie.NewStackTrie(nil))
withdrawalsRoot = &h
}
header := &types.Header{
ParentHash: params.ParentHash,
UncleHash: types.EmptyUncleHash,
Coinbase: params.FeeRecipient,
Root: params.StateRoot,
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
ReceiptHash: params.ReceiptsRoot,
Bloom: types.BytesToBloom(params.LogsBloom),
Difficulty: common.Big0,
Number: new(big.Int).SetUint64(params.Number),
GasLimit: params.GasLimit,
GasUsed: params.GasUsed,
Time: params.Timestamp,
BaseFee: params.BaseFeePerGas,
Extra: params.ExtraData,
MixDigest: params.Random,
WithdrawalsHash: withdrawalsRoot,
}
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals)
if block.Hash() != params.BlockHash {
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash())
}
return block, nil
}
// BlockToExecutableData constructs the ExecutableData structure by filling the
// fields from the given block. It assumes the given block is post-merge block.
func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadEnvelope {
data := &ExecutableData{
BlockHash: block.Hash(),
ParentHash: block.ParentHash(),
FeeRecipient: block.Coinbase(),
StateRoot: block.Root(),
Number: block.NumberU64(),
GasLimit: block.GasLimit(),
GasUsed: block.GasUsed(),
BaseFeePerGas: block.BaseFee(),
Timestamp: block.Time(),
ReceiptsRoot: block.ReceiptHash(),
LogsBloom: block.Bloom().Bytes(),
Transactions: encodeTransactions(block.Transactions()),
Random: block.MixDigest(),
ExtraData: block.Extra(),
Withdrawals: block.Withdrawals(),
}
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees}
}
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1
type ExecutionPayloadBodyV1 struct {
TransactionData []hexutil.Bytes `json:"transactions"`
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
}