mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-03 16:37:39 +00:00
cb02a6897d
* proto+ssz * refactor GetBlindedBlockSSZ (cherry picked from commit 97483c339f99b0d96bd81846a979383ffd2b0cda) # Conflicts: # beacon-chain/rpc/eth/beacon/blocks.go (cherry picked from commit 9e4e82d2c55e09be7568b28eaa33cdd1141445f4) # Conflicts: # beacon-chain/rpc/eth/beacon/blocks.go * add Capella version (cherry picked from commit 5d6fd0bbe663e5dd16df5b2e773f68982bbcd24e) (cherry picked from commit 82f6ddb693ac9e8b4336b30fae724e478b9e8ec0) * support SSZ lol (cherry picked from commit 52bc2c8d617ac3e1254c493fa053cdce4a1ebd63) (cherry picked from commit d7d70bc25b3ee8acbea10aaf77d26cd1f8c5f26f) * update withdrawals proto * refactor and test GetBlockV2 (cherry picked from commit c1d4eaa79d4df04bd284ec65cf261b6f5f260a97) # Conflicts: # beacon-chain/rpc/eth/beacon/blocks.go * refactor and test GetSSZBlockV2 (cherry picked from commit fbc4e73d31c2f68d55d1e2bb8e7f2d8c7458c0a0) # Conflicts: # beacon-chain/rpc/eth/beacon/blocks.go * test other functions (cherry picked from commit 31d4a4cd1165b882d823696e5983ac6635262ec2) * move stuff to blinded_blocks.go (cherry picked from commit 0a9e1658ddb28f45ae5c1cb9fc2703cbb8c6708d) # Conflicts: # beacon-chain/rpc/eth/beacon/blocks.go * fix migration code * add Capella to SubmitBlock * custom hooks * missing structs * fix tests * fix tests * review * fix build issues * replace ioutil with io Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
470 lines
14 KiB
Go
470 lines
14 KiB
Go
package enginev1
|
|
|
|
import (
|
|
"encoding/json"
|
|
"math/big"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
gethtypes "github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/pkg/errors"
|
|
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
|
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
|
)
|
|
|
|
// PayloadIDBytes defines a custom type for Payload IDs used by the engine API
|
|
// client with proper JSON Marshal and Unmarshal methods to hex.
|
|
type PayloadIDBytes [8]byte
|
|
|
|
// MarshalJSON --
|
|
func (b PayloadIDBytes) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(hexutil.Bytes(b[:]))
|
|
}
|
|
|
|
// ExecutionBlock is the response kind received by the eth_getBlockByHash and
|
|
// eth_getBlockByNumber endpoints via JSON-RPC.
|
|
type ExecutionBlock struct {
|
|
Version int
|
|
gethtypes.Header
|
|
Hash common.Hash `json:"hash"`
|
|
Transactions []*gethtypes.Transaction `json:"transactions"`
|
|
TotalDifficulty string `json:"totalDifficulty"`
|
|
Withdrawals []*Withdrawal `json:"withdrawals"`
|
|
}
|
|
|
|
func (e *ExecutionBlock) MarshalJSON() ([]byte, error) {
|
|
decoded := make(map[string]interface{})
|
|
encodedHeader, err := e.Header.MarshalJSON()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := json.Unmarshal(encodedHeader, &decoded); err != nil {
|
|
return nil, err
|
|
}
|
|
decoded["hash"] = e.Hash.String()
|
|
decoded["transactions"] = e.Transactions
|
|
decoded["totalDifficulty"] = e.TotalDifficulty
|
|
|
|
if e.Version == version.Capella {
|
|
decoded["withdrawals"] = e.Withdrawals
|
|
}
|
|
|
|
return json.Marshal(decoded)
|
|
}
|
|
|
|
func (e *ExecutionBlock) UnmarshalJSON(enc []byte) error {
|
|
type transactionsJson struct {
|
|
Transactions []*gethtypes.Transaction `json:"transactions"`
|
|
}
|
|
type withdrawalsJson struct {
|
|
Withdrawals []*withdrawalJSON `json:"withdrawals"`
|
|
}
|
|
|
|
if err := e.Header.UnmarshalJSON(enc); err != nil {
|
|
return err
|
|
}
|
|
decoded := make(map[string]interface{})
|
|
if err := json.Unmarshal(enc, &decoded); err != nil {
|
|
return err
|
|
}
|
|
blockHashStr, ok := decoded["hash"].(string)
|
|
if !ok {
|
|
return errors.New("expected `hash` field in JSON response")
|
|
}
|
|
decodedHash, err := hexutil.Decode(blockHashStr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
e.Hash = common.BytesToHash(decodedHash)
|
|
e.TotalDifficulty, ok = decoded["totalDifficulty"].(string)
|
|
if !ok {
|
|
return errors.New("expected `totalDifficulty` field in JSON response")
|
|
}
|
|
|
|
rawWithdrawals, ok := decoded["withdrawals"]
|
|
if !ok || rawWithdrawals == nil {
|
|
e.Version = version.Bellatrix
|
|
} else {
|
|
e.Version = version.Capella
|
|
j := &withdrawalsJson{}
|
|
if err := json.Unmarshal(enc, j); err != nil {
|
|
return err
|
|
}
|
|
ws := make([]*Withdrawal, len(j.Withdrawals))
|
|
for i, wj := range j.Withdrawals {
|
|
ws[i], err = wj.ToWithdrawal()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
e.Withdrawals = ws
|
|
}
|
|
|
|
rawTxList, ok := decoded["transactions"]
|
|
if !ok || rawTxList == nil {
|
|
// Exit early if there are no transactions stored in the json payload.
|
|
return nil
|
|
}
|
|
txsList, ok := rawTxList.([]interface{})
|
|
if !ok {
|
|
return errors.Errorf("expected transaction list to be of a slice interface type.")
|
|
}
|
|
for _, tx := range txsList {
|
|
// If the transaction is just a hex string, do not attempt to
|
|
// unmarshal into a full transaction object.
|
|
if txItem, ok := tx.(string); ok && strings.HasPrefix(txItem, "0x") {
|
|
return nil
|
|
}
|
|
}
|
|
// If the block contains a list of transactions, we JSON unmarshal
|
|
// them into a list of geth transaction objects.
|
|
txJson := &transactionsJson{}
|
|
if err := json.Unmarshal(enc, txJson); err != nil {
|
|
return err
|
|
}
|
|
e.Transactions = txJson.Transactions
|
|
return nil
|
|
}
|
|
|
|
// UnmarshalJSON --
|
|
func (b *PayloadIDBytes) UnmarshalJSON(enc []byte) error {
|
|
res := [8]byte{}
|
|
if err := hexutil.UnmarshalFixedJSON(reflect.TypeOf(b), enc, res[:]); err != nil {
|
|
return err
|
|
}
|
|
*b = res
|
|
return nil
|
|
}
|
|
|
|
type withdrawalJSON struct {
|
|
Index *hexutil.Uint64 `json:"index"`
|
|
Validator *hexutil.Uint64 `json:"validatorIndex"`
|
|
Address *common.Address `json:"address"`
|
|
Amount string `json:"amount"`
|
|
}
|
|
|
|
func (j *withdrawalJSON) ToWithdrawal() (*Withdrawal, error) {
|
|
w := &Withdrawal{}
|
|
b, err := json.Marshal(j)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := w.UnmarshalJSON(b); err != nil {
|
|
return nil, err
|
|
}
|
|
return w, nil
|
|
}
|
|
|
|
func (w *Withdrawal) MarshalJSON() ([]byte, error) {
|
|
index := hexutil.Uint64(w.Index)
|
|
validatorIndex := hexutil.Uint64(w.ValidatorIndex)
|
|
address := common.BytesToAddress(w.Address)
|
|
wei := new(big.Int).SetUint64(1000000000)
|
|
amountWei := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), wei)
|
|
return json.Marshal(withdrawalJSON{
|
|
Index: &index,
|
|
Validator: &validatorIndex,
|
|
Address: &address,
|
|
Amount: hexutil.EncodeBig(amountWei),
|
|
})
|
|
}
|
|
|
|
func (w *Withdrawal) UnmarshalJSON(enc []byte) error {
|
|
dec := withdrawalJSON{}
|
|
if err := json.Unmarshal(enc, &dec); err != nil {
|
|
return err
|
|
}
|
|
if dec.Index == nil {
|
|
return errors.New("missing withdrawal index")
|
|
}
|
|
if dec.Validator == nil {
|
|
return errors.New("missing validator index")
|
|
}
|
|
if dec.Address == nil {
|
|
return errors.New("missing execution address")
|
|
}
|
|
*w = Withdrawal{}
|
|
w.Index = uint64(*dec.Index)
|
|
w.ValidatorIndex = types.ValidatorIndex(*dec.Validator)
|
|
w.Address = dec.Address.Bytes()
|
|
wei := new(big.Int).SetUint64(1000000000)
|
|
amountWei, err := hexutil.DecodeBig(dec.Amount)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
amount := new(big.Int).Div(amountWei, wei)
|
|
if !amount.IsUint64() {
|
|
return errors.New("withdrawal amount overflow")
|
|
}
|
|
w.Amount = amount.Uint64()
|
|
return nil
|
|
}
|
|
|
|
type executionPayloadJSON struct {
|
|
ParentHash *common.Hash `json:"parentHash"`
|
|
FeeRecipient *common.Address `json:"feeRecipient"`
|
|
StateRoot *common.Hash `json:"stateRoot"`
|
|
ReceiptsRoot *common.Hash `json:"receiptsRoot"`
|
|
LogsBloom *hexutil.Bytes `json:"logsBloom"`
|
|
PrevRandao *common.Hash `json:"prevRandao"`
|
|
BlockNumber *hexutil.Uint64 `json:"blockNumber"`
|
|
GasLimit *hexutil.Uint64 `json:"gasLimit"`
|
|
GasUsed *hexutil.Uint64 `json:"gasUsed"`
|
|
Timestamp *hexutil.Uint64 `json:"timestamp"`
|
|
ExtraData hexutil.Bytes `json:"extraData"`
|
|
BaseFeePerGas string `json:"baseFeePerGas"`
|
|
BlockHash *common.Hash `json:"blockHash"`
|
|
Transactions []hexutil.Bytes `json:"transactions"`
|
|
}
|
|
|
|
// MarshalJSON --
|
|
func (e *ExecutionPayload) MarshalJSON() ([]byte, error) {
|
|
transactions := make([]hexutil.Bytes, len(e.Transactions))
|
|
for i, tx := range e.Transactions {
|
|
transactions[i] = tx
|
|
}
|
|
baseFee := bytesutil.LittleEndianBytesToBigInt(e.BaseFeePerGas)
|
|
baseFeeHex := hexutil.EncodeBig(baseFee)
|
|
pHash := common.BytesToHash(e.ParentHash)
|
|
sRoot := common.BytesToHash(e.StateRoot)
|
|
recRoot := common.BytesToHash(e.ReceiptsRoot)
|
|
prevRan := common.BytesToHash(e.PrevRandao)
|
|
bHash := common.BytesToHash(e.BlockHash)
|
|
blockNum := hexutil.Uint64(e.BlockNumber)
|
|
gasLimit := hexutil.Uint64(e.GasLimit)
|
|
gasUsed := hexutil.Uint64(e.GasUsed)
|
|
timeStamp := hexutil.Uint64(e.Timestamp)
|
|
recipient := common.BytesToAddress(e.FeeRecipient)
|
|
logsBloom := hexutil.Bytes(e.LogsBloom)
|
|
return json.Marshal(executionPayloadJSON{
|
|
ParentHash: &pHash,
|
|
FeeRecipient: &recipient,
|
|
StateRoot: &sRoot,
|
|
ReceiptsRoot: &recRoot,
|
|
LogsBloom: &logsBloom,
|
|
PrevRandao: &prevRan,
|
|
BlockNumber: &blockNum,
|
|
GasLimit: &gasLimit,
|
|
GasUsed: &gasUsed,
|
|
Timestamp: &timeStamp,
|
|
ExtraData: e.ExtraData,
|
|
BaseFeePerGas: baseFeeHex,
|
|
BlockHash: &bHash,
|
|
Transactions: transactions,
|
|
})
|
|
}
|
|
|
|
// UnmarshalJSON --
|
|
func (e *ExecutionPayload) UnmarshalJSON(enc []byte) error {
|
|
dec := executionPayloadJSON{}
|
|
if err := json.Unmarshal(enc, &dec); err != nil {
|
|
return err
|
|
}
|
|
|
|
if dec.ParentHash == nil {
|
|
return errors.New("missing required field 'parentHash' for ExecutionPayload")
|
|
}
|
|
if dec.FeeRecipient == nil {
|
|
return errors.New("missing required field 'feeRecipient' for ExecutionPayload")
|
|
}
|
|
if dec.StateRoot == nil {
|
|
return errors.New("missing required field 'stateRoot' for ExecutionPayload")
|
|
}
|
|
if dec.ReceiptsRoot == nil {
|
|
return errors.New("missing required field 'receiptsRoot' for ExecutableDataV1")
|
|
}
|
|
|
|
if dec.LogsBloom == nil {
|
|
return errors.New("missing required field 'logsBloom' for ExecutionPayload")
|
|
}
|
|
if dec.PrevRandao == nil {
|
|
return errors.New("missing required field 'prevRandao' for ExecutionPayload")
|
|
}
|
|
if dec.ExtraData == nil {
|
|
return errors.New("missing required field 'extraData' for ExecutionPayload")
|
|
}
|
|
if dec.BlockHash == nil {
|
|
return errors.New("missing required field 'blockHash' for ExecutionPayload")
|
|
}
|
|
if dec.Transactions == nil {
|
|
return errors.New("missing required field 'transactions' for ExecutionPayload")
|
|
}
|
|
if dec.BlockNumber == nil {
|
|
return errors.New("missing required field 'blockNumber' for ExecutionPayload")
|
|
}
|
|
if dec.Timestamp == nil {
|
|
return errors.New("missing required field 'timestamp' for ExecutionPayload")
|
|
}
|
|
if dec.GasUsed == nil {
|
|
return errors.New("missing required field 'gasUsed' for ExecutionPayload")
|
|
}
|
|
if dec.GasLimit == nil {
|
|
return errors.New("missing required field 'gasLimit' for ExecutionPayload")
|
|
}
|
|
*e = ExecutionPayload{}
|
|
e.ParentHash = dec.ParentHash.Bytes()
|
|
e.FeeRecipient = dec.FeeRecipient.Bytes()
|
|
e.StateRoot = dec.StateRoot.Bytes()
|
|
e.ReceiptsRoot = dec.ReceiptsRoot.Bytes()
|
|
e.LogsBloom = *dec.LogsBloom
|
|
e.PrevRandao = dec.PrevRandao.Bytes()
|
|
e.BlockNumber = uint64(*dec.BlockNumber)
|
|
e.GasLimit = uint64(*dec.GasLimit)
|
|
e.GasUsed = uint64(*dec.GasUsed)
|
|
e.Timestamp = uint64(*dec.Timestamp)
|
|
e.ExtraData = dec.ExtraData
|
|
baseFee, err := hexutil.DecodeBig(dec.BaseFeePerGas)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
e.BaseFeePerGas = bytesutil.PadTo(bytesutil.ReverseByteOrder(baseFee.Bytes()), fieldparams.RootLength)
|
|
e.BlockHash = dec.BlockHash.Bytes()
|
|
transactions := make([][]byte, len(dec.Transactions))
|
|
for i, tx := range dec.Transactions {
|
|
transactions[i] = tx
|
|
}
|
|
e.Transactions = transactions
|
|
return nil
|
|
}
|
|
|
|
type payloadAttributesJSON struct {
|
|
Timestamp hexutil.Uint64 `json:"timestamp"`
|
|
PrevRandao hexutil.Bytes `json:"prevRandao"`
|
|
SuggestedFeeRecipient hexutil.Bytes `json:"suggestedFeeRecipient"`
|
|
}
|
|
|
|
// MarshalJSON --
|
|
func (p *PayloadAttributes) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(payloadAttributesJSON{
|
|
Timestamp: hexutil.Uint64(p.Timestamp),
|
|
PrevRandao: p.PrevRandao,
|
|
SuggestedFeeRecipient: p.SuggestedFeeRecipient,
|
|
})
|
|
}
|
|
|
|
// UnmarshalJSON --
|
|
func (p *PayloadAttributes) UnmarshalJSON(enc []byte) error {
|
|
dec := payloadAttributesJSON{}
|
|
if err := json.Unmarshal(enc, &dec); err != nil {
|
|
return err
|
|
}
|
|
*p = PayloadAttributes{}
|
|
p.Timestamp = uint64(dec.Timestamp)
|
|
p.PrevRandao = dec.PrevRandao
|
|
p.SuggestedFeeRecipient = dec.SuggestedFeeRecipient
|
|
return nil
|
|
}
|
|
|
|
type payloadStatusJSON struct {
|
|
LatestValidHash *common.Hash `json:"latestValidHash"`
|
|
Status string `json:"status"`
|
|
ValidationError *string `json:"validationError"`
|
|
}
|
|
|
|
// MarshalJSON --
|
|
func (p *PayloadStatus) MarshalJSON() ([]byte, error) {
|
|
var latestHash *common.Hash
|
|
if p.LatestValidHash != nil {
|
|
hash := common.Hash(bytesutil.ToBytes32(p.LatestValidHash))
|
|
latestHash = &hash
|
|
}
|
|
return json.Marshal(payloadStatusJSON{
|
|
LatestValidHash: latestHash,
|
|
Status: p.Status.String(),
|
|
ValidationError: &p.ValidationError,
|
|
})
|
|
}
|
|
|
|
// UnmarshalJSON --
|
|
func (p *PayloadStatus) UnmarshalJSON(enc []byte) error {
|
|
dec := payloadStatusJSON{}
|
|
if err := json.Unmarshal(enc, &dec); err != nil {
|
|
return err
|
|
}
|
|
*p = PayloadStatus{}
|
|
if dec.LatestValidHash != nil {
|
|
p.LatestValidHash = dec.LatestValidHash[:]
|
|
}
|
|
p.Status = PayloadStatus_Status(PayloadStatus_Status_value[dec.Status])
|
|
if dec.ValidationError != nil {
|
|
p.ValidationError = *dec.ValidationError
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type transitionConfigurationJSON struct {
|
|
TerminalTotalDifficulty *hexutil.Big `json:"terminalTotalDifficulty"`
|
|
TerminalBlockHash common.Hash `json:"terminalBlockHash"`
|
|
TerminalBlockNumber hexutil.Uint64 `json:"terminalBlockNumber"`
|
|
}
|
|
|
|
// MarshalJSON --
|
|
func (t *TransitionConfiguration) MarshalJSON() ([]byte, error) {
|
|
num := new(big.Int).SetBytes(t.TerminalBlockNumber)
|
|
var hexNum *hexutil.Big
|
|
if t.TerminalTotalDifficulty != "" {
|
|
ttdNum, err := hexutil.DecodeBig(t.TerminalTotalDifficulty)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bHex := hexutil.Big(*ttdNum)
|
|
hexNum = &bHex
|
|
}
|
|
if len(t.TerminalBlockHash) != fieldparams.RootLength {
|
|
return nil, errors.Errorf("terminal block hash is of the wrong length: %d", len(t.TerminalBlockHash))
|
|
}
|
|
return json.Marshal(transitionConfigurationJSON{
|
|
TerminalTotalDifficulty: hexNum,
|
|
TerminalBlockHash: *(*[32]byte)(t.TerminalBlockHash),
|
|
TerminalBlockNumber: hexutil.Uint64(num.Uint64()),
|
|
})
|
|
}
|
|
|
|
// UnmarshalJSON --
|
|
func (t *TransitionConfiguration) UnmarshalJSON(enc []byte) error {
|
|
dec := transitionConfigurationJSON{}
|
|
if err := json.Unmarshal(enc, &dec); err != nil {
|
|
return err
|
|
}
|
|
*t = TransitionConfiguration{}
|
|
num := big.NewInt(int64(dec.TerminalBlockNumber))
|
|
if dec.TerminalTotalDifficulty != nil {
|
|
t.TerminalTotalDifficulty = dec.TerminalTotalDifficulty.String()
|
|
}
|
|
t.TerminalBlockHash = dec.TerminalBlockHash[:]
|
|
t.TerminalBlockNumber = num.Bytes()
|
|
return nil
|
|
}
|
|
|
|
type forkchoiceStateJSON struct {
|
|
HeadBlockHash hexutil.Bytes `json:"headBlockHash"`
|
|
SafeBlockHash hexutil.Bytes `json:"safeBlockHash"`
|
|
FinalizedBlockHash hexutil.Bytes `json:"finalizedBlockHash"`
|
|
}
|
|
|
|
// MarshalJSON --
|
|
func (f *ForkchoiceState) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(forkchoiceStateJSON{
|
|
HeadBlockHash: f.HeadBlockHash,
|
|
SafeBlockHash: f.SafeBlockHash,
|
|
FinalizedBlockHash: f.FinalizedBlockHash,
|
|
})
|
|
}
|
|
|
|
// UnmarshalJSON --
|
|
func (f *ForkchoiceState) UnmarshalJSON(enc []byte) error {
|
|
dec := forkchoiceStateJSON{}
|
|
if err := json.Unmarshal(enc, &dec); err != nil {
|
|
return err
|
|
}
|
|
*f = ForkchoiceState{}
|
|
f.HeadBlockHash = dec.HeadBlockHash
|
|
f.SafeBlockHash = dec.SafeBlockHash
|
|
f.FinalizedBlockHash = dec.FinalizedBlockHash
|
|
return nil
|
|
}
|