mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 10:50:44 +00:00
cmd/evm/internal/t8ntool: add execution witness as t8n output
Signed-off-by: jsign <jsign.uy@gmail.com>
This commit is contained in:
parent
9700b5b10e
commit
8b93e43ecc
4 changed files with 346 additions and 68 deletions
|
|
@ -17,12 +17,15 @@
|
|||
package t8ntool
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
stdmath "math"
|
||||
"math/big"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
|
|
@ -33,6 +36,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||
|
|
@ -77,12 +81,20 @@ type ExecutionResult struct {
|
|||
RequestsHash *common.Hash `json:"requestsHash,omitempty"`
|
||||
Requests [][]byte `json:"requests"`
|
||||
|
||||
BlockAccessList hexutil.Bytes `json:"blockAccessList,omitempty"`
|
||||
BlockAccessListHash *common.Hash `json:"blockAccessListHash,omitempty"`
|
||||
BlockAccessList hexutil.Bytes `json:"blockAccessList,omitempty"`
|
||||
BlockAccessListHash *common.Hash `json:"blockAccessListHash,omitempty"`
|
||||
ExecutionWitness *executionWitness `json:"executionWitness,omitempty"`
|
||||
}
|
||||
|
||||
type executionResultMarshaling struct {
|
||||
Requests []hexutil.Bytes `json:"requests"`
|
||||
Requests []hexutil.Bytes `json:"requests"`
|
||||
BlockAccessList hexutil.Bytes `json:"blockAccessList,omitempty"`
|
||||
}
|
||||
|
||||
type executionWitness struct {
|
||||
State []hexutil.Bytes `json:"state"`
|
||||
Codes []hexutil.Bytes `json:"codes"`
|
||||
Headers []hexutil.Bytes `json:"headers"`
|
||||
}
|
||||
|
||||
type ommer struct {
|
||||
|
|
@ -92,27 +104,28 @@ type ommer struct {
|
|||
|
||||
//go:generate go run github.com/fjl/gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go
|
||||
type stEnv struct {
|
||||
Coinbase common.Address `json:"currentCoinbase" gencodec:"required"`
|
||||
Difficulty *big.Int `json:"currentDifficulty"`
|
||||
Random *big.Int `json:"currentRandom"`
|
||||
ParentDifficulty *big.Int `json:"parentDifficulty"`
|
||||
ParentBaseFee *big.Int `json:"parentBaseFee,omitempty"`
|
||||
ParentGasUsed uint64 `json:"parentGasUsed,omitempty"`
|
||||
ParentGasLimit uint64 `json:"parentGasLimit,omitempty"`
|
||||
GasLimit uint64 `json:"currentGasLimit" gencodec:"required"`
|
||||
Number uint64 `json:"currentNumber" gencodec:"required"`
|
||||
Timestamp uint64 `json:"currentTimestamp" gencodec:"required"`
|
||||
ParentTimestamp uint64 `json:"parentTimestamp,omitempty"`
|
||||
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
||||
Ommers []ommer `json:"ommers,omitempty"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
|
||||
BaseFee *big.Int `json:"currentBaseFee,omitempty"`
|
||||
ParentUncleHash common.Hash `json:"parentUncleHash"`
|
||||
ExcessBlobGas *uint64 `json:"currentExcessBlobGas,omitempty"`
|
||||
ParentExcessBlobGas *uint64 `json:"parentExcessBlobGas,omitempty"`
|
||||
ParentBlobGasUsed *uint64 `json:"parentBlobGasUsed,omitempty"`
|
||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||
SlotNumber *uint64 `json:"slotNumber"`
|
||||
Coinbase common.Address `json:"currentCoinbase" gencodec:"required"`
|
||||
Difficulty *big.Int `json:"currentDifficulty"`
|
||||
Random *big.Int `json:"currentRandom"`
|
||||
ParentDifficulty *big.Int `json:"parentDifficulty"`
|
||||
ParentBaseFee *big.Int `json:"parentBaseFee,omitempty"`
|
||||
ParentGasUsed uint64 `json:"parentGasUsed,omitempty"`
|
||||
ParentGasLimit uint64 `json:"parentGasLimit,omitempty"`
|
||||
GasLimit uint64 `json:"currentGasLimit" gencodec:"required"`
|
||||
Number uint64 `json:"currentNumber" gencodec:"required"`
|
||||
Timestamp uint64 `json:"currentTimestamp" gencodec:"required"`
|
||||
ParentTimestamp uint64 `json:"parentTimestamp,omitempty"`
|
||||
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
||||
Ommers []ommer `json:"ommers,omitempty"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
|
||||
BaseFee *big.Int `json:"currentBaseFee,omitempty"`
|
||||
ParentUncleHash common.Hash `json:"parentUncleHash"`
|
||||
ExcessBlobGas *uint64 `json:"currentExcessBlobGas,omitempty"`
|
||||
ParentExcessBlobGas *uint64 `json:"parentExcessBlobGas,omitempty"`
|
||||
ParentBlobGasUsed *uint64 `json:"parentBlobGasUsed,omitempty"`
|
||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||
SlotNumber *uint64 `json:"slotNumber"`
|
||||
BlockHeaders map[math.HexOrDecimal64]hexutil.Bytes `json:"blockHeaders,omitempty"`
|
||||
}
|
||||
|
||||
type stEnvMarshaling struct {
|
||||
|
|
@ -132,6 +145,7 @@ type stEnvMarshaling struct {
|
|||
ParentExcessBlobGas *math.HexOrDecimal64
|
||||
ParentBlobGasUsed *math.HexOrDecimal64
|
||||
SlotNumber *math.HexOrDecimal64
|
||||
BlockHeaders map[math.HexOrDecimal64]hexutil.Bytes
|
||||
}
|
||||
|
||||
type rejectedTx struct {
|
||||
|
|
@ -139,6 +153,105 @@ type rejectedTx struct {
|
|||
Err string `json:"error"`
|
||||
}
|
||||
|
||||
type t8nHeaderReader struct {
|
||||
headers map[uint64]*types.Header
|
||||
err error
|
||||
}
|
||||
|
||||
func newT8nHeaderReader(raw map[math.HexOrDecimal64]hexutil.Bytes) (*t8nHeaderReader, error) {
|
||||
reader := &t8nHeaderReader{headers: make(map[uint64]*types.Header)}
|
||||
for rawNumber, encoded := range raw {
|
||||
number := uint64(rawNumber)
|
||||
var header types.Header
|
||||
if err := rlp.DecodeBytes(encoded, &header); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode blockHeaders[%d]: %w", number, err)
|
||||
}
|
||||
if header.Number == nil || !header.Number.IsUint64() || header.Number.Uint64() != number {
|
||||
return nil, fmt.Errorf("blockHeaders[%d] decodes to header number %v", number, header.Number)
|
||||
}
|
||||
reader.headers[number] = &header
|
||||
}
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
func (reader *t8nHeaderReader) GetHeader(hash common.Hash, number uint64) *types.Header {
|
||||
header, ok := reader.headers[number]
|
||||
if !ok {
|
||||
reader.setErr(fmt.Errorf("missing blockHeaders[%d] for hash %s", number, hash))
|
||||
return nil
|
||||
}
|
||||
if got := header.Hash(); got != hash {
|
||||
reader.setErr(fmt.Errorf("blockHeaders[%d] hash mismatch: have %s, want %s", number, got, hash))
|
||||
return nil
|
||||
}
|
||||
return header
|
||||
}
|
||||
|
||||
func (reader *t8nHeaderReader) setErr(err error) {
|
||||
if reader.err == nil {
|
||||
reader.err = err
|
||||
}
|
||||
}
|
||||
|
||||
func (reader *t8nHeaderReader) Err() error {
|
||||
if reader == nil {
|
||||
return nil
|
||||
}
|
||||
return reader.err
|
||||
}
|
||||
|
||||
func (pre *Prestate) witnessContextHeader() (*types.Header, error) {
|
||||
if pre.Env.Number == 0 {
|
||||
return nil, errors.New("cannot build execution witness for block 0")
|
||||
}
|
||||
if pre.Env.BlockHashes == nil {
|
||||
return nil, fmt.Errorf("missing blockHashes[%d] for execution witness parent", pre.Env.Number-1)
|
||||
}
|
||||
parentNumber := math.HexOrDecimal64(pre.Env.Number - 1)
|
||||
parentHash, ok := pre.Env.BlockHashes[parentNumber]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing blockHashes[%d] for execution witness parent", pre.Env.Number-1)
|
||||
}
|
||||
return &types.Header{
|
||||
ParentHash: parentHash,
|
||||
Number: new(big.Int).SetUint64(pre.Env.Number),
|
||||
Time: pre.Env.Timestamp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func convertExecutionWitness(witness *stateless.Witness) (*executionWitness, error) {
|
||||
ext := witness.ToExtWitness()
|
||||
sort.Slice(ext.State, func(i, j int) bool {
|
||||
return bytes.Compare(ext.State[i], ext.State[j]) < 0
|
||||
})
|
||||
sort.Slice(ext.Codes, func(i, j int) bool {
|
||||
return bytes.Compare(ext.Codes[i], ext.Codes[j]) < 0
|
||||
})
|
||||
|
||||
result := &executionWitness{
|
||||
State: make([]hexutil.Bytes, len(ext.State)),
|
||||
Codes: make([]hexutil.Bytes, len(ext.Codes)),
|
||||
Headers: make([]hexutil.Bytes, len(ext.Headers)),
|
||||
}
|
||||
for i, state := range ext.State {
|
||||
result.State[i] = state
|
||||
}
|
||||
for i, code := range ext.Codes {
|
||||
result.Codes[i] = code
|
||||
}
|
||||
for i, header := range ext.Headers {
|
||||
if header == nil {
|
||||
return nil, errors.New("execution witness contains a nil header")
|
||||
}
|
||||
encoded, err := rlp.EncodeToBytes(header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Headers[i] = encoded
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Apply applies a set of transactions to a pre-state
|
||||
func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txIt txIterator, miningReward int64) (*state.StateDB, *ExecutionResult, []byte, error) {
|
||||
// Capture errors for BLOCKHASH operation, if we haven't been supplied the
|
||||
|
|
@ -243,6 +356,29 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
misc.ApplyDAOHardFork(statedb)
|
||||
}
|
||||
evm := vm.NewEVM(vmContext, statedb, chainConfig, vmConfig)
|
||||
var (
|
||||
witness *stateless.Witness
|
||||
headerReader *t8nHeaderReader
|
||||
)
|
||||
if isAmsterdam {
|
||||
var err error
|
||||
headerReader, err = newT8nHeaderReader(pre.Env.BlockHeaders)
|
||||
if err != nil {
|
||||
return nil, nil, nil, NewError(ErrorMissingBlockhash, err)
|
||||
}
|
||||
contextHeader, err := pre.witnessContextHeader()
|
||||
if err != nil {
|
||||
return nil, nil, nil, NewError(ErrorMissingBlockhash, err)
|
||||
}
|
||||
witness, err = stateless.NewWitness(contextHeader, headerReader, false)
|
||||
if err != nil {
|
||||
if headerErr := headerReader.Err(); headerErr != nil {
|
||||
err = headerErr
|
||||
}
|
||||
return nil, nil, nil, NewError(ErrorMissingBlockhash, err)
|
||||
}
|
||||
statedb.StartPrefetcher("t8n", witness)
|
||||
}
|
||||
if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil {
|
||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, blockAccessList)
|
||||
}
|
||||
|
|
@ -304,13 +440,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
if hashError != nil {
|
||||
return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError)
|
||||
}
|
||||
if err := headerReader.Err(); err != nil {
|
||||
return nil, nil, nil, NewError(ErrorMissingBlockhash, err)
|
||||
}
|
||||
blobGasUsed += txBlobGas
|
||||
receipts = append(receipts, receipt)
|
||||
blockAccessList.Merge(bal)
|
||||
}
|
||||
statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber))
|
||||
|
||||
// TODO(rjl493456442) call engine.Finalize() instead
|
||||
// Add mining reward? (-1 means rewards are disabled)
|
||||
if miningReward >= 0 {
|
||||
// Add mining reward. The mining reward may be `0`, which only makes a difference in the cases
|
||||
|
|
@ -367,6 +504,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("failed to process post-execution: %v", err))
|
||||
}
|
||||
blockAccessList.Merge(bal)
|
||||
if err := headerReader.Err(); err != nil {
|
||||
return nil, nil, nil, NewError(ErrorMissingBlockhash, err)
|
||||
}
|
||||
|
||||
// Commit block
|
||||
root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber), chainConfig.IsCancun(vmContext.BlockNumber, vmContext.Time))
|
||||
|
|
@ -408,6 +548,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
balHash := encoded.Hash()
|
||||
execRs.BlockAccessListHash = &balHash
|
||||
execRs.BlockAccessList = balRLP
|
||||
|
||||
executionWitness, err := convertExecutionWitness(witness)
|
||||
if err != nil {
|
||||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not encode execution witness: %v", err))
|
||||
}
|
||||
execRs.ExecutionWitness = executionWitness
|
||||
}
|
||||
|
||||
// Re-create statedb instance with new root for MPT mode
|
||||
|
|
|
|||
119
cmd/evm/internal/t8ntool/execution_test.go
Normal file
119
cmd/evm/internal/t8ntool/execution_test.go
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright 2026 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package t8ntool
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
gethmath "github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
func mustEncodeHeader(t *testing.T, header *types.Header) []byte {
|
||||
t.Helper()
|
||||
|
||||
encoded, err := rlp.EncodeToBytes(header)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return encoded
|
||||
}
|
||||
|
||||
func TestConvertExecutionWitnessOrdersForEEST(t *testing.T) {
|
||||
parent := &types.Header{Number: big.NewInt(2)}
|
||||
grandparent := &types.Header{Number: big.NewInt(1)}
|
||||
witness := &stateless.Witness{
|
||||
Headers: []*types.Header{parent, grandparent},
|
||||
Codes: map[string]struct{}{
|
||||
string([]byte{0x02}): {},
|
||||
string([]byte{0x01}): {},
|
||||
},
|
||||
State: map[string]struct{}{
|
||||
string([]byte{0x20}): {},
|
||||
string([]byte{0x10}): {},
|
||||
},
|
||||
}
|
||||
|
||||
got, err := convertExecutionWitness(witness)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(got.State[0], []byte{0x10}) || !bytes.Equal(got.State[1], []byte{0x20}) {
|
||||
t.Fatalf("state not sorted lexicographically: %#x", got.State)
|
||||
}
|
||||
if !bytes.Equal(got.Codes[0], []byte{0x01}) || !bytes.Equal(got.Codes[1], []byte{0x02}) {
|
||||
t.Fatalf("codes not sorted lexicographically: %#x", got.Codes)
|
||||
}
|
||||
wantHeaders := [][]byte{
|
||||
mustEncodeHeader(t, grandparent),
|
||||
mustEncodeHeader(t, parent),
|
||||
}
|
||||
for i, want := range wantHeaders {
|
||||
if !bytes.Equal(got.Headers[i], want) {
|
||||
t.Fatalf("header %d mismatch: have %#x want %#x", i, got.Headers[i], want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestT8NHeaderReaderValidatesHash(t *testing.T) {
|
||||
header := &types.Header{Number: big.NewInt(7)}
|
||||
reader, err := newT8nHeaderReader(map[gethmath.HexOrDecimal64]hexutil.Bytes{
|
||||
7: mustEncodeHeader(t, header),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := reader.GetHeader(header.Hash(), 7); got == nil || got.Hash() != header.Hash() {
|
||||
t.Fatalf("failed to retrieve known header: %v", got)
|
||||
}
|
||||
if got := reader.GetHeader(common.Hash{0x01}, 7); got != nil {
|
||||
t.Fatalf("retrieved header for mismatched hash: %v", got)
|
||||
}
|
||||
if err := reader.Err(); err == nil || !strings.Contains(err.Error(), "hash mismatch") {
|
||||
t.Fatalf("unexpected reader error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestT8NHeaderReaderReportsMissingAncestor(t *testing.T) {
|
||||
reader, err := newT8nHeaderReader(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := reader.GetHeader(common.Hash{}, 1); got != nil {
|
||||
t.Fatalf("retrieved missing header: %v", got)
|
||||
}
|
||||
if err := reader.Err(); err == nil || !strings.Contains(err.Error(), "missing blockHeaders[1]") {
|
||||
t.Fatalf("unexpected reader error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestT8NHeaderReaderRejectsNumberMismatch(t *testing.T) {
|
||||
header := &types.Header{Number: big.NewInt(2)}
|
||||
_, err := newT8nHeaderReader(map[gethmath.HexOrDecimal64]hexutil.Bytes{
|
||||
1: mustEncodeHeader(t, header),
|
||||
})
|
||||
if err == nil || !strings.Contains(err.Error(), "decodes to header number") {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@ func (e ExecutionResult) MarshalJSON() ([]byte, error) {
|
|||
Requests []hexutil.Bytes `json:"requests"`
|
||||
BlockAccessList hexutil.Bytes `json:"blockAccessList,omitempty"`
|
||||
BlockAccessListHash *common.Hash `json:"blockAccessListHash,omitempty"`
|
||||
ExecutionWitness *executionWitness `json:"executionWitness,omitempty"`
|
||||
}
|
||||
var enc ExecutionResult
|
||||
enc.StateRoot = e.StateRoot
|
||||
|
|
@ -58,6 +59,7 @@ func (e ExecutionResult) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
enc.BlockAccessList = e.BlockAccessList
|
||||
enc.BlockAccessListHash = e.BlockAccessListHash
|
||||
enc.ExecutionWitness = e.ExecutionWitness
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +83,7 @@ func (e *ExecutionResult) UnmarshalJSON(input []byte) error {
|
|||
Requests []hexutil.Bytes `json:"requests"`
|
||||
BlockAccessList *hexutil.Bytes `json:"blockAccessList,omitempty"`
|
||||
BlockAccessListHash *common.Hash `json:"blockAccessListHash,omitempty"`
|
||||
ExecutionWitness *executionWitness `json:"executionWitness,omitempty"`
|
||||
}
|
||||
var dec ExecutionResult
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
|
|
@ -142,5 +145,8 @@ func (e *ExecutionResult) UnmarshalJSON(input []byte) error {
|
|||
if dec.BlockAccessListHash != nil {
|
||||
e.BlockAccessListHash = dec.BlockAccessListHash
|
||||
}
|
||||
if dec.ExecutionWitness != nil {
|
||||
e.ExecutionWitness = dec.ExecutionWitness
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
|
@ -17,27 +18,28 @@ var _ = (*stEnvMarshaling)(nil)
|
|||
// MarshalJSON marshals as JSON.
|
||||
func (s stEnv) MarshalJSON() ([]byte, error) {
|
||||
type stEnv struct {
|
||||
Coinbase common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"`
|
||||
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"`
|
||||
Random *math.HexOrDecimal256 `json:"currentRandom"`
|
||||
ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"`
|
||||
ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"`
|
||||
ParentGasUsed math.HexOrDecimal64 `json:"parentGasUsed,omitempty"`
|
||||
ParentGasLimit math.HexOrDecimal64 `json:"parentGasLimit,omitempty"`
|
||||
GasLimit math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"`
|
||||
Number math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"`
|
||||
Timestamp math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
|
||||
ParentTimestamp math.HexOrDecimal64 `json:"parentTimestamp,omitempty"`
|
||||
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
||||
Ommers []ommer `json:"ommers,omitempty"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
|
||||
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
|
||||
ParentUncleHash common.Hash `json:"parentUncleHash"`
|
||||
ExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
|
||||
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
||||
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||
SlotNumber *math.HexOrDecimal64 `json:"slotNumber"`
|
||||
Coinbase common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"`
|
||||
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"`
|
||||
Random *math.HexOrDecimal256 `json:"currentRandom"`
|
||||
ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"`
|
||||
ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"`
|
||||
ParentGasUsed math.HexOrDecimal64 `json:"parentGasUsed,omitempty"`
|
||||
ParentGasLimit math.HexOrDecimal64 `json:"parentGasLimit,omitempty"`
|
||||
GasLimit math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"`
|
||||
Number math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"`
|
||||
Timestamp math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
|
||||
ParentTimestamp math.HexOrDecimal64 `json:"parentTimestamp,omitempty"`
|
||||
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
||||
Ommers []ommer `json:"ommers,omitempty"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
|
||||
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
|
||||
ParentUncleHash common.Hash `json:"parentUncleHash"`
|
||||
ExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
|
||||
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
||||
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||
SlotNumber *math.HexOrDecimal64 `json:"slotNumber"`
|
||||
BlockHeaders map[math.HexOrDecimal64]hexutil.Bytes `json:"blockHeaders,omitempty"`
|
||||
}
|
||||
var enc stEnv
|
||||
enc.Coinbase = common.UnprefixedAddress(s.Coinbase)
|
||||
|
|
@ -61,33 +63,35 @@ func (s stEnv) MarshalJSON() ([]byte, error) {
|
|||
enc.ParentBlobGasUsed = (*math.HexOrDecimal64)(s.ParentBlobGasUsed)
|
||||
enc.ParentBeaconBlockRoot = s.ParentBeaconBlockRoot
|
||||
enc.SlotNumber = (*math.HexOrDecimal64)(s.SlotNumber)
|
||||
enc.BlockHeaders = s.BlockHeaders
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (s *stEnv) UnmarshalJSON(input []byte) error {
|
||||
type stEnv struct {
|
||||
Coinbase *common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"`
|
||||
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"`
|
||||
Random *math.HexOrDecimal256 `json:"currentRandom"`
|
||||
ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"`
|
||||
ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"`
|
||||
ParentGasUsed *math.HexOrDecimal64 `json:"parentGasUsed,omitempty"`
|
||||
ParentGasLimit *math.HexOrDecimal64 `json:"parentGasLimit,omitempty"`
|
||||
GasLimit *math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"`
|
||||
Number *math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"`
|
||||
Timestamp *math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
|
||||
ParentTimestamp *math.HexOrDecimal64 `json:"parentTimestamp,omitempty"`
|
||||
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
||||
Ommers []ommer `json:"ommers,omitempty"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
|
||||
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
|
||||
ParentUncleHash *common.Hash `json:"parentUncleHash"`
|
||||
ExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
|
||||
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
||||
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||
SlotNumber *math.HexOrDecimal64 `json:"slotNumber"`
|
||||
Coinbase *common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"`
|
||||
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"`
|
||||
Random *math.HexOrDecimal256 `json:"currentRandom"`
|
||||
ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"`
|
||||
ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"`
|
||||
ParentGasUsed *math.HexOrDecimal64 `json:"parentGasUsed,omitempty"`
|
||||
ParentGasLimit *math.HexOrDecimal64 `json:"parentGasLimit,omitempty"`
|
||||
GasLimit *math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"`
|
||||
Number *math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"`
|
||||
Timestamp *math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
|
||||
ParentTimestamp *math.HexOrDecimal64 `json:"parentTimestamp,omitempty"`
|
||||
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
||||
Ommers []ommer `json:"ommers,omitempty"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
|
||||
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
|
||||
ParentUncleHash *common.Hash `json:"parentUncleHash"`
|
||||
ExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
|
||||
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
||||
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||
SlotNumber *math.HexOrDecimal64 `json:"slotNumber"`
|
||||
BlockHeaders map[math.HexOrDecimal64]hexutil.Bytes `json:"blockHeaders,omitempty"`
|
||||
}
|
||||
var dec stEnv
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
|
|
@ -160,5 +164,8 @@ func (s *stEnv) UnmarshalJSON(input []byte) error {
|
|||
if dec.SlotNumber != nil {
|
||||
s.SlotNumber = (*uint64)(dec.SlotNumber)
|
||||
}
|
||||
if dec.BlockHeaders != nil {
|
||||
s.BlockHeaders = dec.BlockHeaders
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue