mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
beacon/types: add BeaconBlock and payload conversion
This commit is contained in:
parent
e3029e3c05
commit
aec6b03f32
4 changed files with 273 additions and 1 deletions
110
beacon/types/beacon_block.go
Normal file
110
beacon/types/beacon_block.go
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
// Copyright 2024 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 types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||||
|
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||||
|
"github.com/protolambda/zrnt/eth2/beacon/deneb"
|
||||||
|
"github.com/protolambda/zrnt/eth2/configs"
|
||||||
|
"github.com/protolambda/ztyp/tree"
|
||||||
|
)
|
||||||
|
|
||||||
|
type blockObject interface {
|
||||||
|
HashTreeRoot(spec *zrntcommon.Spec, hFn tree.HashFn) zrntcommon.Root
|
||||||
|
Header(spec *zrntcommon.Spec) *zrntcommon.BeaconBlockHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeaconBlock represents a full block in the beacon chain.
|
||||||
|
type BeaconBlock struct {
|
||||||
|
blockObj blockObject
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockFromJSON decodes a beacon block from JSON.
|
||||||
|
func BlockFromJSON(forkName string, data []byte) (*BeaconBlock, error) {
|
||||||
|
var obj blockObject
|
||||||
|
switch forkName {
|
||||||
|
case "deneb":
|
||||||
|
obj = new(deneb.BeaconBlock)
|
||||||
|
case "capella":
|
||||||
|
obj = new(capella.BeaconBlock)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported fork: " + forkName)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, obj); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &BeaconBlock{obj}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBeaconBlock wraps a ZRNT block.
|
||||||
|
func NewBeaconBlock(obj blockObject) *BeaconBlock {
|
||||||
|
switch obj := obj.(type) {
|
||||||
|
case *capella.BeaconBlock:
|
||||||
|
return &BeaconBlock{obj}
|
||||||
|
case *deneb.BeaconBlock:
|
||||||
|
return &BeaconBlock{obj}
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported block type %T", obj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slot returns the slot number of the block.
|
||||||
|
func (b *BeaconBlock) Slot() uint64 {
|
||||||
|
switch obj := b.blockObj.(type) {
|
||||||
|
case *capella.BeaconBlock:
|
||||||
|
return uint64(obj.Slot)
|
||||||
|
case *deneb.BeaconBlock:
|
||||||
|
return uint64(obj.Slot)
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported block type %T", b.blockObj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecutionPayload parses and returns the execution payload of the block.
|
||||||
|
func (b *BeaconBlock) ExecutionPayload() (*types.Block, error) {
|
||||||
|
switch obj := b.blockObj.(type) {
|
||||||
|
case *capella.BeaconBlock:
|
||||||
|
return convertPayload(&obj.Body.ExecutionPayload)
|
||||||
|
case *deneb.BeaconBlock:
|
||||||
|
return convertPayload(&obj.Body.ExecutionPayload)
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported block type %T", b.blockObj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header returns the block's header data.
|
||||||
|
func (b *BeaconBlock) Header() Header {
|
||||||
|
switch obj := b.blockObj.(type) {
|
||||||
|
case *capella.BeaconBlock:
|
||||||
|
return headerFromZRNT(obj.Header(configs.Mainnet))
|
||||||
|
case *deneb.BeaconBlock:
|
||||||
|
return headerFromZRNT(obj.Header(configs.Mainnet))
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported block type %T", b.blockObj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash computes the hash of the block.
|
||||||
|
func (b *BeaconBlock) Hash() common.Hash {
|
||||||
|
return common.Hash(b.blockObj.HashTreeRoot(configs.Mainnet, tree.GetHashFn()))
|
||||||
|
}
|
||||||
|
|
@ -37,7 +37,7 @@ const syncCommitteeDomain = 7
|
||||||
// Fork describes a single beacon chain fork and also stores the calculated
|
// Fork describes a single beacon chain fork and also stores the calculated
|
||||||
// signature domain used after this fork.
|
// signature domain used after this fork.
|
||||||
type Fork struct {
|
type Fork struct {
|
||||||
// Name of the fork in the chain config (config.yaml) file{
|
// Name of the fork in the chain config (config.yaml) file
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Epoch when given fork version is activated
|
// Epoch when given fork version is activated
|
||||||
|
|
@ -110,6 +110,16 @@ type ChainConfig struct {
|
||||||
Forks Forks
|
Forks Forks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForkAtEpoch returns the latest active fork at the given epoch.
|
||||||
|
func (c *ChainConfig) ForkAtEpoch(epoch uint64) *Fork {
|
||||||
|
for i := len(c.Forks) - 1; i >= 0; i-- {
|
||||||
|
if c.Forks[i].Epoch <= epoch {
|
||||||
|
return c.Forks[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AddFork adds a new item to the list of forks.
|
// AddFork adds a new item to the list of forks.
|
||||||
func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig {
|
func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig {
|
||||||
fork := &Fork{
|
fork := &Fork{
|
||||||
|
|
|
||||||
141
beacon/types/exec_payload.go
Normal file
141
beacon/types/exec_payload.go
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
// Copyright 2024 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 types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
"github.com/protolambda/zrnt/eth2/beacon/capella"
|
||||||
|
zcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||||
|
"github.com/protolambda/zrnt/eth2/beacon/deneb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type payloadType interface {
|
||||||
|
*capella.ExecutionPayload | *deneb.ExecutionPayload
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertPayload converts a beacon chain execution payload to types.Block.
|
||||||
|
func convertPayload[T payloadType](payload T) (*types.Block, error) {
|
||||||
|
var (
|
||||||
|
header types.Header
|
||||||
|
transactions []*types.Transaction
|
||||||
|
withdrawals []*types.Withdrawal
|
||||||
|
expectedHash [32]byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
switch p := any(payload).(type) {
|
||||||
|
case *capella.ExecutionPayload:
|
||||||
|
convertCapellaHeader(p, &header)
|
||||||
|
transactions, err = convertTransactions(p.Transactions, &header)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
withdrawals = convertWithdrawals(p.Withdrawals, &header)
|
||||||
|
expectedHash = p.BlockHash
|
||||||
|
case *deneb.ExecutionPayload:
|
||||||
|
convertDenebHeader(p, &header)
|
||||||
|
transactions, err = convertTransactions(p.Transactions, &header)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
withdrawals = convertWithdrawals(p.Withdrawals, &header)
|
||||||
|
expectedHash = p.BlockHash
|
||||||
|
default:
|
||||||
|
panic("unsupported block type")
|
||||||
|
}
|
||||||
|
|
||||||
|
block := types.NewBlockWithHeader(&header)
|
||||||
|
block = block.WithBody(transactions, nil)
|
||||||
|
block = block.WithWithdrawals(withdrawals)
|
||||||
|
hash := block.Hash()
|
||||||
|
if hash != expectedHash {
|
||||||
|
return block, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash)
|
||||||
|
}
|
||||||
|
return block, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertCapellaHeader(payload *capella.ExecutionPayload, h *types.Header) {
|
||||||
|
h.ParentHash = common.Hash(payload.ParentHash)
|
||||||
|
h.UncleHash = types.EmptyUncleHash
|
||||||
|
h.Coinbase = common.Address(payload.FeeRecipient)
|
||||||
|
h.Root = common.Hash(payload.StateRoot)
|
||||||
|
h.ReceiptHash = common.Hash(payload.ReceiptsRoot)
|
||||||
|
h.Bloom = types.Bloom(payload.LogsBloom)
|
||||||
|
h.Difficulty = common.Big0
|
||||||
|
h.Number = new(big.Int).SetUint64(uint64(payload.BlockNumber))
|
||||||
|
h.GasLimit = uint64(payload.GasLimit)
|
||||||
|
h.GasUsed = uint64(payload.GasUsed)
|
||||||
|
h.Time = uint64(payload.Timestamp)
|
||||||
|
h.Extra = []byte(payload.ExtraData)
|
||||||
|
h.MixDigest = common.Hash(payload.PrevRandao)
|
||||||
|
h.Nonce = types.BlockNonce{}
|
||||||
|
h.BaseFee = (*uint256.Int)(&payload.BaseFeePerGas).ToBig()
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertDenebHeader(payload *deneb.ExecutionPayload, h *types.Header) {
|
||||||
|
h.ParentHash = common.Hash(payload.ParentHash)
|
||||||
|
h.UncleHash = types.EmptyUncleHash
|
||||||
|
h.Coinbase = common.Address(payload.FeeRecipient)
|
||||||
|
h.Root = common.Hash(payload.StateRoot)
|
||||||
|
h.ReceiptHash = common.Hash(payload.ReceiptsRoot)
|
||||||
|
h.Bloom = types.Bloom(payload.LogsBloom)
|
||||||
|
h.Difficulty = common.Big0
|
||||||
|
h.Number = new(big.Int).SetUint64(uint64(payload.BlockNumber))
|
||||||
|
h.GasLimit = uint64(payload.GasLimit)
|
||||||
|
h.GasUsed = uint64(payload.GasUsed)
|
||||||
|
h.Time = uint64(payload.Timestamp)
|
||||||
|
h.Extra = []byte(payload.ExtraData)
|
||||||
|
h.MixDigest = common.Hash(payload.PrevRandao)
|
||||||
|
h.Nonce = types.BlockNonce{}
|
||||||
|
h.BaseFee = (*uint256.Int)(&payload.BaseFeePerGas).ToBig()
|
||||||
|
// new in deneb
|
||||||
|
h.BlobGasUsed = (*uint64)(&payload.BlobGasUsed)
|
||||||
|
h.ExcessBlobGas = (*uint64)(&payload.ExcessBlobGas)
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertTransactions(list zcommon.PayloadTransactions, execHeader *types.Header) ([]*types.Transaction, error) {
|
||||||
|
txs := make([]*types.Transaction, len(list))
|
||||||
|
for i, opaqueTx := range list {
|
||||||
|
var tx types.Transaction
|
||||||
|
if err := tx.UnmarshalBinary(opaqueTx); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse tx %d: %v", i, err)
|
||||||
|
}
|
||||||
|
txs[i] = &tx
|
||||||
|
}
|
||||||
|
execHeader.TxHash = types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil))
|
||||||
|
return txs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertWithdrawals(list zcommon.Withdrawals, execHeader *types.Header) []*types.Withdrawal {
|
||||||
|
withdrawals := make([]*types.Withdrawal, len(list))
|
||||||
|
for i, w := range list {
|
||||||
|
withdrawals[i] = &types.Withdrawal{
|
||||||
|
Index: uint64(w.Index),
|
||||||
|
Validator: uint64(w.ValidatorIndex),
|
||||||
|
Address: common.Address(w.Address),
|
||||||
|
Amount: uint64(w.Amount),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wroot := types.DeriveSha(types.Withdrawals(withdrawals), trie.NewStackTrie(nil))
|
||||||
|
execHeader.WithdrawalsHash = &wroot
|
||||||
|
return withdrawals
|
||||||
|
}
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/beacon/merkle"
|
"github.com/ethereum/go-ethereum/beacon/merkle"
|
||||||
"github.com/ethereum/go-ethereum/beacon/params"
|
"github.com/ethereum/go-ethereum/beacon/params"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
|
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
|
||||||
|
|
@ -57,6 +58,16 @@ type Header struct {
|
||||||
BodyRoot common.Hash `gencodec:"required" json:"body_root"`
|
BodyRoot common.Hash `gencodec:"required" json:"body_root"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func headerFromZRNT(zh *zrntcommon.BeaconBlockHeader) Header {
|
||||||
|
return Header{
|
||||||
|
Slot: uint64(zh.Slot),
|
||||||
|
ProposerIndex: uint64(zh.ProposerIndex),
|
||||||
|
ParentRoot: common.Hash(zh.ParentRoot),
|
||||||
|
StateRoot: common.Hash(zh.StateRoot),
|
||||||
|
BodyRoot: common.Hash(zh.BodyRoot),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// headerMarshaling is a field type overrides for gencodec.
|
// headerMarshaling is a field type overrides for gencodec.
|
||||||
type headerMarshaling struct {
|
type headerMarshaling struct {
|
||||||
Slot common.Decimal
|
Slot common.Decimal
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue