github.com/ethereum/go-ethereum@v1.16.1/beacon/types/beacon_block.go (about)

     1  // Copyright 2024 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package types
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"fmt"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  	zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common"
    27  	"github.com/protolambda/zrnt/eth2/configs"
    28  	"github.com/protolambda/ztyp/codec"
    29  	"github.com/protolambda/ztyp/tree"
    30  
    31  	// beacon forks
    32  	"github.com/protolambda/zrnt/eth2/beacon/capella"
    33  	"github.com/protolambda/zrnt/eth2/beacon/deneb"
    34  	"github.com/protolambda/zrnt/eth2/beacon/electra"
    35  )
    36  
    37  type blockObject interface {
    38  	HashTreeRoot(spec *zrntcommon.Spec, hFn tree.HashFn) zrntcommon.Root
    39  	Header(spec *zrntcommon.Spec) *zrntcommon.BeaconBlockHeader
    40  }
    41  
    42  // BeaconBlock represents a full block in the beacon chain.
    43  type BeaconBlock struct {
    44  	blockObj blockObject
    45  }
    46  
    47  // BlockFromJSON decodes a beacon block from JSON.
    48  func BlockFromJSON(forkName string, data []byte) (*BeaconBlock, error) {
    49  	var obj blockObject
    50  	switch forkName {
    51  	case "capella":
    52  		obj = new(capella.BeaconBlock)
    53  	case "deneb":
    54  		obj = new(deneb.BeaconBlock)
    55  	case "electra":
    56  		obj = new(electra.BeaconBlock)
    57  	default:
    58  		return nil, fmt.Errorf("unsupported fork: %s", forkName)
    59  	}
    60  	if err := json.Unmarshal(data, obj); err != nil {
    61  		return nil, err
    62  	}
    63  	return &BeaconBlock{obj}, nil
    64  }
    65  
    66  // NewBeaconBlock wraps a ZRNT block.
    67  func NewBeaconBlock(obj blockObject) *BeaconBlock {
    68  	switch obj := obj.(type) {
    69  	case *capella.BeaconBlock:
    70  		return &BeaconBlock{obj}
    71  	case *deneb.BeaconBlock:
    72  		return &BeaconBlock{obj}
    73  	case *electra.BeaconBlock:
    74  		return &BeaconBlock{obj}
    75  	default:
    76  		panic(fmt.Errorf("unsupported block type %T", obj))
    77  	}
    78  }
    79  
    80  // Slot returns the slot number of the block.
    81  func (b *BeaconBlock) Slot() uint64 {
    82  	switch obj := b.blockObj.(type) {
    83  	case *capella.BeaconBlock:
    84  		return uint64(obj.Slot)
    85  	case *deneb.BeaconBlock:
    86  		return uint64(obj.Slot)
    87  	case *electra.BeaconBlock:
    88  		return uint64(obj.Slot)
    89  	default:
    90  		panic(fmt.Errorf("unsupported block type %T", b.blockObj))
    91  	}
    92  }
    93  
    94  // ExecutionPayload parses and returns the execution payload of the block.
    95  func (b *BeaconBlock) ExecutionPayload() (*types.Block, error) {
    96  	switch obj := b.blockObj.(type) {
    97  	case *capella.BeaconBlock:
    98  		return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot, nil)
    99  	case *deneb.BeaconBlock:
   100  		return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot, nil)
   101  	case *electra.BeaconBlock:
   102  		requests := b.ExecutionRequestsList()
   103  		return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot, requests)
   104  	default:
   105  		panic(fmt.Errorf("unsupported block type %T", b.blockObj))
   106  	}
   107  }
   108  
   109  // Header returns the block's header data.
   110  func (b *BeaconBlock) Header() Header {
   111  	switch obj := b.blockObj.(type) {
   112  	case *capella.BeaconBlock:
   113  		return headerFromZRNT(obj.Header(configs.Mainnet))
   114  	case *deneb.BeaconBlock:
   115  		return headerFromZRNT(obj.Header(configs.Mainnet))
   116  	case *electra.BeaconBlock:
   117  		return headerFromZRNT(obj.Header(configs.Mainnet))
   118  	default:
   119  		panic(fmt.Errorf("unsupported block type %T", b.blockObj))
   120  	}
   121  }
   122  
   123  // Root computes the SSZ root hash of the block.
   124  func (b *BeaconBlock) Root() common.Hash {
   125  	return common.Hash(b.blockObj.HashTreeRoot(configs.Mainnet, tree.GetHashFn()))
   126  }
   127  
   128  // ExecutionRequestsList returns the execution layer requests of the block.
   129  func (b *BeaconBlock) ExecutionRequestsList() [][]byte {
   130  	switch obj := b.blockObj.(type) {
   131  	case *capella.BeaconBlock, *deneb.BeaconBlock:
   132  		return nil
   133  	case *electra.BeaconBlock:
   134  		r := obj.Body.ExecutionRequests
   135  		return marshalRequests(configs.Mainnet,
   136  			&r.Deposits,
   137  			&r.Withdrawals,
   138  			&r.Consolidations,
   139  		)
   140  	default:
   141  		panic(fmt.Errorf("unsupported block type %T", b.blockObj))
   142  	}
   143  }
   144  
   145  func marshalRequests(spec *zrntcommon.Spec, items ...zrntcommon.SpecObj) (list [][]byte) {
   146  	var buf bytes.Buffer
   147  	list = [][]byte{}
   148  	for typ, data := range items {
   149  		buf.Reset()
   150  		buf.WriteByte(byte(typ))
   151  		w := codec.NewEncodingWriter(&buf)
   152  		if err := data.Serialize(spec, w); err != nil {
   153  			panic(err)
   154  		}
   155  		if buf.Len() == 1 {
   156  			continue // skip empty requests
   157  		}
   158  		list = append(list, bytes.Clone(buf.Bytes()))
   159  	}
   160  	return list
   161  }