mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 07:58:22 -05:00
Add Capella support for Validator's REST API ProposeBeaconBlock and GetBeaconBlock endpoints (#11848)
* Add Capella support for Validator's REST API ProposeBeaconBlock and GetBeaconBlock endpoints * Fix * Fix * Add context to capella tests * Update validator/client/beacon-api/beacon_block_proto_helpers.go * Update validator/client/beacon-api/beacon_block_proto_helpers.go * Update validator/client/beacon-api/beacon_block_proto_helpers_test.go * Update validator/client/beacon-api/beacon_block_proto_helpers_test.go Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com> Co-authored-by: Radosław Kapka <radek@prysmaticlabs.com> Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
@@ -60,6 +60,7 @@ go_test(
|
||||
"genesis_test.go",
|
||||
"get_beacon_block_altair_test.go",
|
||||
"get_beacon_block_bellatrix_test.go",
|
||||
"get_beacon_block_capella_test.go",
|
||||
"get_beacon_block_phase0_test.go",
|
||||
"get_beacon_block_test.go",
|
||||
"index_test.go",
|
||||
@@ -70,6 +71,7 @@ go_test(
|
||||
"propose_beacon_block_bellatrix_test.go",
|
||||
"propose_beacon_block_blinded_bellatrix_test.go",
|
||||
"propose_beacon_block_blinded_capella_test.go",
|
||||
"propose_beacon_block_capella_test.go",
|
||||
"propose_beacon_block_phase0_test.go",
|
||||
"propose_beacon_block_test.go",
|
||||
"propose_exit_test.go",
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -170,3 +173,16 @@ func jsonifySignedAggregateAndProof(signedAggregateAndProof *ethpb.SignedAggrega
|
||||
Signature: hexutil.Encode(signedAggregateAndProof.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
func jsonifyWithdrawals(withdrawals []*enginev1.Withdrawal) []*apimiddleware.WithdrawalJson {
|
||||
jsonWithdrawals := make([]*apimiddleware.WithdrawalJson, len(withdrawals))
|
||||
for index, withdrawal := range withdrawals {
|
||||
jsonWithdrawals[index] = &apimiddleware.WithdrawalJson{
|
||||
WithdrawalIndex: strconv.FormatUint(withdrawal.Index, 10),
|
||||
ValidatorIndex: strconv.FormatUint(uint64(withdrawal.ValidatorIndex), 10),
|
||||
ExecutionAddress: hexutil.Encode(withdrawal.Address),
|
||||
Amount: strconv.FormatUint(withdrawal.Amount, 10),
|
||||
}
|
||||
}
|
||||
return jsonWithdrawals
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
)
|
||||
@@ -611,3 +612,38 @@ func TestBeaconBlockJsonHelpers_JsonifyAttestationData(t *testing.T) {
|
||||
result := jsonifyAttestationData(input)
|
||||
assert.DeepEqual(t, expectedResult, result)
|
||||
}
|
||||
|
||||
func TestBeaconBlockJsonHelpers_JsonifyWithdrawals(t *testing.T) {
|
||||
input := []*enginev1.Withdrawal{
|
||||
{
|
||||
Index: 1,
|
||||
ValidatorIndex: 2,
|
||||
Address: []byte{3},
|
||||
Amount: 4,
|
||||
},
|
||||
{
|
||||
Index: 5,
|
||||
ValidatorIndex: 6,
|
||||
Address: []byte{7},
|
||||
Amount: 8,
|
||||
},
|
||||
}
|
||||
|
||||
expectedResult := []*apimiddleware.WithdrawalJson{
|
||||
{
|
||||
WithdrawalIndex: "1",
|
||||
ValidatorIndex: "2",
|
||||
ExecutionAddress: hexutil.Encode([]byte{3}),
|
||||
Amount: "4",
|
||||
},
|
||||
{
|
||||
WithdrawalIndex: "5",
|
||||
ValidatorIndex: "6",
|
||||
ExecutionAddress: hexutil.Encode([]byte{7}),
|
||||
Amount: "8",
|
||||
},
|
||||
}
|
||||
|
||||
result := jsonifyWithdrawals(input)
|
||||
assert.DeepEqual(t, expectedResult, result)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -350,3 +351,87 @@ func convertTransactionsToProto(jsonTransactions []string) ([][]byte, error) {
|
||||
|
||||
return transactions, nil
|
||||
}
|
||||
|
||||
func convertWithdrawalsToProto(jsonWithdrawals []*apimiddleware.WithdrawalJson) ([]*enginev1.Withdrawal, error) {
|
||||
withdrawals := make([]*enginev1.Withdrawal, len(jsonWithdrawals))
|
||||
|
||||
for index, jsonWithdrawal := range jsonWithdrawals {
|
||||
if jsonWithdrawal == nil {
|
||||
return nil, errors.Errorf("withdrawal at index `%d` is nil", index)
|
||||
}
|
||||
|
||||
withdrawalIndex, err := strconv.ParseUint(jsonWithdrawal.WithdrawalIndex, 10, 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse withdrawal index `%s`", jsonWithdrawal.WithdrawalIndex)
|
||||
}
|
||||
|
||||
validatorIndex, err := strconv.ParseUint(jsonWithdrawal.ValidatorIndex, 10, 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse validator index `%s`", jsonWithdrawal.ValidatorIndex)
|
||||
}
|
||||
|
||||
executionAddress, err := hexutil.Decode(jsonWithdrawal.ExecutionAddress)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to decode execution address `%s`", jsonWithdrawal.ExecutionAddress)
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseUint(jsonWithdrawal.Amount, 10, 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse withdrawal amount `%s`", jsonWithdrawal.Amount)
|
||||
}
|
||||
|
||||
withdrawals[index] = &enginev1.Withdrawal{
|
||||
Index: withdrawalIndex,
|
||||
ValidatorIndex: types.ValidatorIndex(validatorIndex),
|
||||
Address: executionAddress,
|
||||
Amount: amount,
|
||||
}
|
||||
}
|
||||
|
||||
return withdrawals, nil
|
||||
}
|
||||
|
||||
func convertBlsToExecutionChangesToProto(jsonSignedBlsToExecutionChanges []*apimiddleware.SignedBLSToExecutionChangeJson) ([]*ethpb.SignedBLSToExecutionChange, error) {
|
||||
signedBlsToExecutionChanges := make([]*ethpb.SignedBLSToExecutionChange, len(jsonSignedBlsToExecutionChanges))
|
||||
|
||||
for index, jsonBlsToExecutionChange := range jsonSignedBlsToExecutionChanges {
|
||||
if jsonBlsToExecutionChange == nil {
|
||||
return nil, errors.Errorf("bls to execution change at index `%d` is nil", index)
|
||||
}
|
||||
|
||||
if jsonBlsToExecutionChange.Message == nil {
|
||||
return nil, errors.Errorf("bls to execution change message at index `%d` is nil", index)
|
||||
}
|
||||
|
||||
validatorIndex, err := strconv.ParseUint(jsonBlsToExecutionChange.Message.ValidatorIndex, 10, 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to decode validator index `%s`", jsonBlsToExecutionChange.Message.ValidatorIndex)
|
||||
}
|
||||
|
||||
fromBlsPubkey, err := hexutil.Decode(jsonBlsToExecutionChange.Message.FromBLSPubkey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to decode bls pubkey `%s`", jsonBlsToExecutionChange.Message.FromBLSPubkey)
|
||||
}
|
||||
|
||||
toExecutionAddress, err := hexutil.Decode(jsonBlsToExecutionChange.Message.ToExecutionAddress)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to decode execution address `%s`", jsonBlsToExecutionChange.Message.ToExecutionAddress)
|
||||
}
|
||||
|
||||
signature, err := hexutil.Decode(jsonBlsToExecutionChange.Signature)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to decode signature `%s`", jsonBlsToExecutionChange.Signature)
|
||||
}
|
||||
|
||||
signedBlsToExecutionChanges[index] = ðpb.SignedBLSToExecutionChange{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: types.ValidatorIndex(validatorIndex),
|
||||
FromBlsPubkey: fromBlsPubkey,
|
||||
ToExecutionAddress: toExecutionAddress,
|
||||
},
|
||||
Signature: signature,
|
||||
}
|
||||
}
|
||||
|
||||
return signedBlsToExecutionChanges, nil
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
@@ -917,6 +918,169 @@ func TestBeaconBlockProtoHelpers_ConvertTransactionsToProto(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeaconBlockProtoHelpers_ConvertWithdrawalsToProto(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
generateInput func() []*apimiddleware.WithdrawalJson
|
||||
expectedResult []*enginev1.Withdrawal
|
||||
expectedErrorMessage string
|
||||
}{
|
||||
{
|
||||
name: "nil withdrawal",
|
||||
expectedErrorMessage: "withdrawal at index `0` is nil",
|
||||
generateInput: func() []*apimiddleware.WithdrawalJson {
|
||||
input := generateWithdrawals()
|
||||
input[0] = nil
|
||||
return input
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad withdrawal index",
|
||||
expectedErrorMessage: "failed to parse withdrawal index `foo`",
|
||||
generateInput: func() []*apimiddleware.WithdrawalJson {
|
||||
input := generateWithdrawals()
|
||||
input[0].WithdrawalIndex = "foo"
|
||||
return input
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad validator index",
|
||||
expectedErrorMessage: "failed to parse validator index `bar`",
|
||||
generateInput: func() []*apimiddleware.WithdrawalJson {
|
||||
input := generateWithdrawals()
|
||||
input[0].ValidatorIndex = "bar"
|
||||
return input
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad execution address",
|
||||
expectedErrorMessage: "failed to decode execution address `foo`",
|
||||
generateInput: func() []*apimiddleware.WithdrawalJson {
|
||||
input := generateWithdrawals()
|
||||
input[0].ExecutionAddress = "foo"
|
||||
return input
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad amount",
|
||||
expectedErrorMessage: "failed to parse withdrawal amount `bar`",
|
||||
generateInput: func() []*apimiddleware.WithdrawalJson {
|
||||
input := generateWithdrawals()
|
||||
input[0].Amount = "bar"
|
||||
return input
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
generateInput: generateWithdrawals,
|
||||
expectedResult: []*enginev1.Withdrawal{
|
||||
{
|
||||
Index: 1,
|
||||
ValidatorIndex: 2,
|
||||
Address: []byte{3},
|
||||
Amount: 4,
|
||||
},
|
||||
{
|
||||
Index: 5,
|
||||
ValidatorIndex: 6,
|
||||
Address: []byte{7},
|
||||
Amount: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
result, err := convertWithdrawalsToProto(testCase.generateInput())
|
||||
|
||||
if testCase.expectedResult != nil {
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, testCase.expectedResult, result)
|
||||
} else if testCase.expectedErrorMessage != "" {
|
||||
assert.ErrorContains(t, testCase.expectedErrorMessage, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeaconBlockProtoHelpers_ConvertBlsToExecutionChangesToProto(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
generateInput func() []*apimiddleware.SignedBLSToExecutionChangeJson
|
||||
expectedResult []*ethpb.SignedBLSToExecutionChange
|
||||
expectedErrorMessage string
|
||||
}{
|
||||
{
|
||||
name: "nil bls to execution change",
|
||||
expectedErrorMessage: "bls to execution change at index `0` is nil",
|
||||
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
|
||||
input := generateBlsToExecutionChanges()
|
||||
input[0] = nil
|
||||
return input
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nil bls to execution change message",
|
||||
expectedErrorMessage: "bls to execution change message at index `0` is nil",
|
||||
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
|
||||
input := generateBlsToExecutionChanges()
|
||||
input[0].Message = nil
|
||||
return input
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad validator index",
|
||||
expectedErrorMessage: "failed to decode validator index `foo`",
|
||||
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
|
||||
input := generateBlsToExecutionChanges()
|
||||
input[0].Message.ValidatorIndex = "foo"
|
||||
return input
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad from bls pubkey",
|
||||
expectedErrorMessage: "failed to decode bls pubkey `bar`",
|
||||
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
|
||||
input := generateBlsToExecutionChanges()
|
||||
input[0].Message.FromBLSPubkey = "bar"
|
||||
return input
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad to execution address",
|
||||
expectedErrorMessage: "failed to decode execution address `foo`",
|
||||
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
|
||||
input := generateBlsToExecutionChanges()
|
||||
input[0].Message.ToExecutionAddress = "foo"
|
||||
return input
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad signature",
|
||||
expectedErrorMessage: "failed to decode signature `bar`",
|
||||
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
|
||||
input := generateBlsToExecutionChanges()
|
||||
input[0].Signature = "bar"
|
||||
return input
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
result, err := convertBlsToExecutionChangesToProto(testCase.generateInput())
|
||||
|
||||
if testCase.expectedResult != nil {
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, testCase.expectedResult, result)
|
||||
} else if testCase.expectedErrorMessage != "" {
|
||||
assert.ErrorContains(t, testCase.expectedErrorMessage, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func generateProposerSlashings() []*apimiddleware.ProposerSlashingJson {
|
||||
return []*apimiddleware.ProposerSlashingJson{
|
||||
{
|
||||
@@ -1185,3 +1349,41 @@ func generateSignedVoluntaryExits() []*apimiddleware.SignedVoluntaryExitJson {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func generateWithdrawals() []*apimiddleware.WithdrawalJson {
|
||||
return []*apimiddleware.WithdrawalJson{
|
||||
{
|
||||
WithdrawalIndex: "1",
|
||||
ValidatorIndex: "2",
|
||||
ExecutionAddress: hexutil.Encode([]byte{3}),
|
||||
Amount: "4",
|
||||
},
|
||||
{
|
||||
WithdrawalIndex: "5",
|
||||
ValidatorIndex: "6",
|
||||
ExecutionAddress: hexutil.Encode([]byte{7}),
|
||||
Amount: "8",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func generateBlsToExecutionChanges() []*apimiddleware.SignedBLSToExecutionChangeJson {
|
||||
return []*apimiddleware.SignedBLSToExecutionChangeJson{
|
||||
{
|
||||
Message: &apimiddleware.BLSToExecutionChangeJson{
|
||||
ValidatorIndex: "1",
|
||||
FromBLSPubkey: hexutil.Encode([]byte{2}),
|
||||
ToExecutionAddress: hexutil.Encode([]byte{3}),
|
||||
},
|
||||
Signature: hexutil.Encode([]byte{4}),
|
||||
},
|
||||
{
|
||||
Message: &apimiddleware.BLSToExecutionChangeJson{
|
||||
ValidatorIndex: "5",
|
||||
FromBLSPubkey: hexutil.Encode([]byte{6}),
|
||||
ToExecutionAddress: hexutil.Encode([]byte{7}),
|
||||
},
|
||||
Signature: hexutil.Encode([]byte{8}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,18 @@ func (c beaconApiValidatorClient) getBeaconBlock(ctx context.Context, slot types
|
||||
}
|
||||
response.Block = bellatrixBlock
|
||||
|
||||
case "capella":
|
||||
jsonCapellaBlock := apimiddleware.BeaconBlockCapellaJson{}
|
||||
if err := decoder.Decode(&jsonCapellaBlock); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to decode capella block response json")
|
||||
}
|
||||
|
||||
capellaBlock, err := convertRESTCapellaBlockToProto(&jsonCapellaBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get capella block")
|
||||
}
|
||||
response.Block = capellaBlock
|
||||
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported consensus version `%s`", produceBlockResponseJson.Version)
|
||||
}
|
||||
@@ -395,3 +407,100 @@ func convertRESTBellatrixBlockToProto(block *apimiddleware.BeaconBlockBellatrixJ
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func convertRESTCapellaBlockToProto(block *apimiddleware.BeaconBlockCapellaJson) (*ethpb.GenericBeaconBlock_Capella, error) {
|
||||
if block.Body == nil {
|
||||
return nil, errors.New("block body is nil")
|
||||
}
|
||||
|
||||
if block.Body.ExecutionPayload == nil {
|
||||
return nil, errors.New("execution payload is nil")
|
||||
}
|
||||
|
||||
// Call convertRESTBellatrixBlockToProto to set the bellatrix fields because all the error handling and the heavy
|
||||
// lifting has already been done
|
||||
bellatrixBlock, err := convertRESTBellatrixBlockToProto(&apimiddleware.BeaconBlockBellatrixJson{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: block.ParentRoot,
|
||||
StateRoot: block.StateRoot,
|
||||
Body: &apimiddleware.BeaconBlockBodyBellatrixJson{
|
||||
RandaoReveal: block.Body.RandaoReveal,
|
||||
Eth1Data: block.Body.Eth1Data,
|
||||
Graffiti: block.Body.Graffiti,
|
||||
ProposerSlashings: block.Body.ProposerSlashings,
|
||||
AttesterSlashings: block.Body.AttesterSlashings,
|
||||
Attestations: block.Body.Attestations,
|
||||
Deposits: block.Body.Deposits,
|
||||
VoluntaryExits: block.Body.VoluntaryExits,
|
||||
SyncAggregate: block.Body.SyncAggregate,
|
||||
ExecutionPayload: &apimiddleware.ExecutionPayloadJson{
|
||||
ParentHash: block.Body.ExecutionPayload.ParentHash,
|
||||
FeeRecipient: block.Body.ExecutionPayload.FeeRecipient,
|
||||
StateRoot: block.Body.ExecutionPayload.StateRoot,
|
||||
ReceiptsRoot: block.Body.ExecutionPayload.ReceiptsRoot,
|
||||
LogsBloom: block.Body.ExecutionPayload.LogsBloom,
|
||||
PrevRandao: block.Body.ExecutionPayload.PrevRandao,
|
||||
BlockNumber: block.Body.ExecutionPayload.BlockNumber,
|
||||
GasLimit: block.Body.ExecutionPayload.GasLimit,
|
||||
GasUsed: block.Body.ExecutionPayload.GasUsed,
|
||||
TimeStamp: block.Body.ExecutionPayload.TimeStamp,
|
||||
ExtraData: block.Body.ExecutionPayload.ExtraData,
|
||||
BaseFeePerGas: block.Body.ExecutionPayload.BaseFeePerGas,
|
||||
BlockHash: block.Body.ExecutionPayload.BlockHash,
|
||||
Transactions: block.Body.ExecutionPayload.Transactions,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get the bellatrix fields of the capella block")
|
||||
}
|
||||
|
||||
withdrawals, err := convertWithdrawalsToProto(block.Body.ExecutionPayload.Withdrawals)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get withdrawals")
|
||||
}
|
||||
|
||||
blsToExecutionChanges, err := convertBlsToExecutionChangesToProto(block.Body.BLSToExecutionChanges)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get bls to execution changes")
|
||||
}
|
||||
|
||||
return ðpb.GenericBeaconBlock_Capella{
|
||||
Capella: ðpb.BeaconBlockCapella{
|
||||
Slot: bellatrixBlock.Bellatrix.Slot,
|
||||
ProposerIndex: bellatrixBlock.Bellatrix.ProposerIndex,
|
||||
ParentRoot: bellatrixBlock.Bellatrix.ParentRoot,
|
||||
StateRoot: bellatrixBlock.Bellatrix.StateRoot,
|
||||
Body: ðpb.BeaconBlockBodyCapella{
|
||||
RandaoReveal: bellatrixBlock.Bellatrix.Body.RandaoReveal,
|
||||
Eth1Data: bellatrixBlock.Bellatrix.Body.Eth1Data,
|
||||
Graffiti: bellatrixBlock.Bellatrix.Body.Graffiti,
|
||||
ProposerSlashings: bellatrixBlock.Bellatrix.Body.ProposerSlashings,
|
||||
AttesterSlashings: bellatrixBlock.Bellatrix.Body.AttesterSlashings,
|
||||
Attestations: bellatrixBlock.Bellatrix.Body.Attestations,
|
||||
Deposits: bellatrixBlock.Bellatrix.Body.Deposits,
|
||||
VoluntaryExits: bellatrixBlock.Bellatrix.Body.VoluntaryExits,
|
||||
SyncAggregate: bellatrixBlock.Bellatrix.Body.SyncAggregate,
|
||||
ExecutionPayload: &enginev1.ExecutionPayloadCapella{
|
||||
ParentHash: bellatrixBlock.Bellatrix.Body.ExecutionPayload.ParentHash,
|
||||
FeeRecipient: bellatrixBlock.Bellatrix.Body.ExecutionPayload.FeeRecipient,
|
||||
StateRoot: bellatrixBlock.Bellatrix.Body.ExecutionPayload.StateRoot,
|
||||
ReceiptsRoot: bellatrixBlock.Bellatrix.Body.ExecutionPayload.ReceiptsRoot,
|
||||
LogsBloom: bellatrixBlock.Bellatrix.Body.ExecutionPayload.LogsBloom,
|
||||
PrevRandao: bellatrixBlock.Bellatrix.Body.ExecutionPayload.PrevRandao,
|
||||
BlockNumber: bellatrixBlock.Bellatrix.Body.ExecutionPayload.BlockNumber,
|
||||
GasLimit: bellatrixBlock.Bellatrix.Body.ExecutionPayload.GasLimit,
|
||||
GasUsed: bellatrixBlock.Bellatrix.Body.ExecutionPayload.GasUsed,
|
||||
Timestamp: bellatrixBlock.Bellatrix.Body.ExecutionPayload.Timestamp,
|
||||
ExtraData: bellatrixBlock.Bellatrix.Body.ExecutionPayload.ExtraData,
|
||||
BaseFeePerGas: bellatrixBlock.Bellatrix.Body.ExecutionPayload.BaseFeePerGas,
|
||||
BlockHash: bellatrixBlock.Bellatrix.Body.ExecutionPayload.BlockHash,
|
||||
Transactions: bellatrixBlock.Bellatrix.Body.ExecutionPayload.Transactions,
|
||||
Withdrawals: withdrawals,
|
||||
},
|
||||
BlsToExecutionChanges: blsToExecutionChanges,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
149
validator/client/beacon-api/get_beacon_block_capella_test.go
Normal file
149
validator/client/beacon-api/get_beacon_block_capella_test.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/mock"
|
||||
test_helpers "github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/test-helpers"
|
||||
)
|
||||
|
||||
func TestGetBeaconBlock_CapellaValid(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
capellaProtoBeaconBlock := test_helpers.GenerateProtoCapellaBeaconBlock()
|
||||
capellaBeaconBlockBytes, err := json.Marshal(test_helpers.GenerateJsonCapellaBeaconBlock())
|
||||
require.NoError(t, err)
|
||||
|
||||
const slot = types.Slot(1)
|
||||
randaoReveal := []byte{2}
|
||||
graffiti := []byte{3}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
|
||||
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
||||
ctx,
|
||||
fmt.Sprintf("/eth/v2/validator/blocks/%d?graffiti=%s&randao_reveal=%s", slot, hexutil.Encode(graffiti), hexutil.Encode(randaoReveal)),
|
||||
&abstractProduceBlockResponseJson{},
|
||||
).SetArg(
|
||||
2,
|
||||
abstractProduceBlockResponseJson{
|
||||
Version: "capella",
|
||||
Data: capellaBeaconBlockBytes,
|
||||
},
|
||||
).Return(
|
||||
nil,
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
expectedBeaconBlock := generateProtoCapellaBlock(capellaProtoBeaconBlock)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
beaconBlock, err := validatorClient.getBeaconBlock(ctx, slot, randaoReveal, graffiti)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedBeaconBlock, beaconBlock)
|
||||
}
|
||||
|
||||
func TestGetBeaconBlock_CapellaError(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
expectedErrorMessage string
|
||||
generateData func() *apimiddleware.BeaconBlockCapellaJson
|
||||
}{
|
||||
{
|
||||
name: "nil body",
|
||||
expectedErrorMessage: "block body is nil",
|
||||
generateData: func() *apimiddleware.BeaconBlockCapellaJson {
|
||||
beaconBlock := test_helpers.GenerateJsonCapellaBeaconBlock()
|
||||
beaconBlock.Body = nil
|
||||
return beaconBlock
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nil execution payload",
|
||||
expectedErrorMessage: "execution payload is nil",
|
||||
generateData: func() *apimiddleware.BeaconBlockCapellaJson {
|
||||
beaconBlock := test_helpers.GenerateJsonCapellaBeaconBlock()
|
||||
beaconBlock.Body.ExecutionPayload = nil
|
||||
return beaconBlock
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad bellatrix fields",
|
||||
expectedErrorMessage: "failed to get the bellatrix fields of the capella block",
|
||||
generateData: func() *apimiddleware.BeaconBlockCapellaJson {
|
||||
beaconBlock := test_helpers.GenerateJsonCapellaBeaconBlock()
|
||||
beaconBlock.Body.Eth1Data = nil
|
||||
return beaconBlock
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad withdrawals",
|
||||
expectedErrorMessage: "failed to get withdrawals",
|
||||
generateData: func() *apimiddleware.BeaconBlockCapellaJson {
|
||||
beaconBlock := test_helpers.GenerateJsonCapellaBeaconBlock()
|
||||
beaconBlock.Body.ExecutionPayload.Withdrawals[0] = nil
|
||||
return beaconBlock
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad bls execution changes",
|
||||
expectedErrorMessage: "failed to get bls to execution changes",
|
||||
generateData: func() *apimiddleware.BeaconBlockCapellaJson {
|
||||
beaconBlock := test_helpers.GenerateJsonCapellaBeaconBlock()
|
||||
beaconBlock.Body.BLSToExecutionChanges[0] = nil
|
||||
return beaconBlock
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
dataBytes, err := json.Marshal(testCase.generateData())
|
||||
require.NoError(t, err)
|
||||
|
||||
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
|
||||
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
||||
context.Background(),
|
||||
gomock.Any(),
|
||||
&abstractProduceBlockResponseJson{},
|
||||
).SetArg(
|
||||
2,
|
||||
abstractProduceBlockResponseJson{
|
||||
Version: "capella",
|
||||
Data: dataBytes,
|
||||
},
|
||||
).Return(
|
||||
nil,
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
_, err = validatorClient.getBeaconBlock(context.Background(), 1, []byte{1}, []byte{2})
|
||||
assert.ErrorContains(t, "failed to get capella block", err)
|
||||
assert.ErrorContains(t, testCase.expectedErrorMessage, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func generateProtoCapellaBlock(capellaProtoBeaconBlock *ethpb.BeaconBlockCapella) *ethpb.GenericBeaconBlock {
|
||||
return ðpb.GenericBeaconBlock{
|
||||
Block: ðpb.GenericBeaconBlock_Capella{
|
||||
Capella: capellaProtoBeaconBlock,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,8 @@ func TestGetBeaconBlock_Error(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
bellatrixBeaconBlockBytes, err := json.Marshal(apimiddleware.BeaconBlockBellatrixJson{})
|
||||
require.NoError(t, err)
|
||||
capellaBeaconBlockBytes, err := json.Marshal(apimiddleware.BeaconBlockCapellaJson{})
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
@@ -87,6 +89,19 @@ func TestGetBeaconBlock_Error(t *testing.T) {
|
||||
consensusVersion: "bellatrix",
|
||||
data: bellatrixBeaconBlockBytes,
|
||||
},
|
||||
{
|
||||
name: "capella block decoding failed",
|
||||
expectedErrorMessage: "failed to decode capella block response json",
|
||||
beaconBlock: "foo",
|
||||
consensusVersion: "capella",
|
||||
data: []byte{},
|
||||
},
|
||||
{
|
||||
name: "capella block conversion failed",
|
||||
expectedErrorMessage: "failed to get capella block",
|
||||
consensusVersion: "capella",
|
||||
data: capellaBeaconBlockBytes,
|
||||
},
|
||||
{
|
||||
name: "unsupported consensus version",
|
||||
expectedErrorMessage: "unsupported consensus version `foo`",
|
||||
|
||||
@@ -67,6 +67,17 @@ func (c beaconApiValidatorClient) proposeBeaconBlock(ctx context.Context, in *et
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall blinded bellatrix beacon block")
|
||||
}
|
||||
case *ethpb.GenericSignedBeaconBlock_Capella:
|
||||
consensusVersion = "capella"
|
||||
beaconBlockRoot, err = blockType.Capella.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for capella beacon block")
|
||||
}
|
||||
|
||||
marshalledSignedBeaconBlockJson, err = marshallBeaconBlockCapella(blockType.Capella)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall capella beacon block")
|
||||
}
|
||||
case *ethpb.GenericSignedBeaconBlock_BlindedCapella:
|
||||
blinded = true
|
||||
consensusVersion = "capella"
|
||||
@@ -79,8 +90,6 @@ func (c beaconApiValidatorClient) proposeBeaconBlock(ctx context.Context, in *et
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall blinded capella beacon block")
|
||||
}
|
||||
case *ethpb.GenericSignedBeaconBlock_Capella:
|
||||
return nil, errors.Errorf("Capella blocks are not supported yet")
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported block type %T", in.Block)
|
||||
}
|
||||
@@ -246,6 +255,52 @@ func marshallBeaconBlockBlindedBellatrix(block *ethpb.SignedBlindedBeaconBlockBe
|
||||
return json.Marshal(signedBeaconBlockBellatrixJson)
|
||||
}
|
||||
|
||||
func marshallBeaconBlockCapella(block *ethpb.SignedBeaconBlockCapella) ([]byte, error) {
|
||||
signedBeaconBlockCapellaJson := &apimiddleware.SignedBeaconBlockCapellaContainerJson{
|
||||
Signature: hexutil.Encode(block.Signature),
|
||||
Message: &apimiddleware.BeaconBlockCapellaJson{
|
||||
ParentRoot: hexutil.Encode(block.Block.ParentRoot),
|
||||
ProposerIndex: uint64ToString(block.Block.ProposerIndex),
|
||||
Slot: uint64ToString(block.Block.Slot),
|
||||
StateRoot: hexutil.Encode(block.Block.StateRoot),
|
||||
Body: &apimiddleware.BeaconBlockBodyCapellaJson{
|
||||
Attestations: jsonifyAttestations(block.Block.Body.Attestations),
|
||||
AttesterSlashings: jsonifyAttesterSlashings(block.Block.Body.AttesterSlashings),
|
||||
Deposits: jsonifyDeposits(block.Block.Body.Deposits),
|
||||
Eth1Data: jsonifyEth1Data(block.Block.Body.Eth1Data),
|
||||
Graffiti: hexutil.Encode(block.Block.Body.Graffiti),
|
||||
ProposerSlashings: jsonifyProposerSlashings(block.Block.Body.ProposerSlashings),
|
||||
RandaoReveal: hexutil.Encode(block.Block.Body.RandaoReveal),
|
||||
VoluntaryExits: jsonifySignedVoluntaryExits(block.Block.Body.VoluntaryExits),
|
||||
SyncAggregate: &apimiddleware.SyncAggregateJson{
|
||||
SyncCommitteeBits: hexutil.Encode(block.Block.Body.SyncAggregate.SyncCommitteeBits),
|
||||
SyncCommitteeSignature: hexutil.Encode(block.Block.Body.SyncAggregate.SyncCommitteeSignature),
|
||||
},
|
||||
ExecutionPayload: &apimiddleware.ExecutionPayloadCapellaJson{
|
||||
BaseFeePerGas: bytesutil.LittleEndianBytesToBigInt(block.Block.Body.ExecutionPayload.BaseFeePerGas).String(),
|
||||
BlockHash: hexutil.Encode(block.Block.Body.ExecutionPayload.BlockHash),
|
||||
BlockNumber: uint64ToString(block.Block.Body.ExecutionPayload.BlockNumber),
|
||||
ExtraData: hexutil.Encode(block.Block.Body.ExecutionPayload.ExtraData),
|
||||
FeeRecipient: hexutil.Encode(block.Block.Body.ExecutionPayload.FeeRecipient),
|
||||
GasLimit: uint64ToString(block.Block.Body.ExecutionPayload.GasLimit),
|
||||
GasUsed: uint64ToString(block.Block.Body.ExecutionPayload.GasUsed),
|
||||
LogsBloom: hexutil.Encode(block.Block.Body.ExecutionPayload.LogsBloom),
|
||||
ParentHash: hexutil.Encode(block.Block.Body.ExecutionPayload.ParentHash),
|
||||
PrevRandao: hexutil.Encode(block.Block.Body.ExecutionPayload.PrevRandao),
|
||||
ReceiptsRoot: hexutil.Encode(block.Block.Body.ExecutionPayload.ReceiptsRoot),
|
||||
StateRoot: hexutil.Encode(block.Block.Body.ExecutionPayload.StateRoot),
|
||||
TimeStamp: uint64ToString(block.Block.Body.ExecutionPayload.Timestamp),
|
||||
Transactions: jsonifyTransactions(block.Block.Body.ExecutionPayload.Transactions),
|
||||
Withdrawals: jsonifyWithdrawals(block.Block.Body.ExecutionPayload.Withdrawals),
|
||||
},
|
||||
BLSToExecutionChanges: jsonifyBlsToExecutionChanges(block.Block.Body.BlsToExecutionChanges),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return json.Marshal(signedBeaconBlockCapellaJson)
|
||||
}
|
||||
|
||||
func marshallBeaconBlockBlindedCapella(block *ethpb.SignedBlindedBeaconBlockCapella) ([]byte, error) {
|
||||
signedBeaconBlockCapellaJson := &apimiddleware.SignedBlindedBeaconBlockCapellaContainerJson{
|
||||
Signature: hexutil.Encode(block.Signature),
|
||||
|
||||
104
validator/client/beacon-api/propose_beacon_block_capella_test.go
Normal file
104
validator/client/beacon-api/propose_beacon_block_capella_test.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/mock"
|
||||
test_helpers "github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/test-helpers"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_Capella(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
|
||||
|
||||
capellaBlock := generateSignedCapellaBlock()
|
||||
|
||||
genericSignedBlock := ðpb.GenericSignedBeaconBlock{}
|
||||
genericSignedBlock.Block = capellaBlock
|
||||
|
||||
jsonCapellaBlock := &apimiddleware.SignedBeaconBlockCapellaContainerJson{
|
||||
Signature: hexutil.Encode(capellaBlock.Capella.Signature),
|
||||
Message: &apimiddleware.BeaconBlockCapellaJson{
|
||||
ParentRoot: hexutil.Encode(capellaBlock.Capella.Block.ParentRoot),
|
||||
ProposerIndex: uint64ToString(capellaBlock.Capella.Block.ProposerIndex),
|
||||
Slot: uint64ToString(capellaBlock.Capella.Block.Slot),
|
||||
StateRoot: hexutil.Encode(capellaBlock.Capella.Block.StateRoot),
|
||||
Body: &apimiddleware.BeaconBlockBodyCapellaJson{
|
||||
Attestations: jsonifyAttestations(capellaBlock.Capella.Block.Body.Attestations),
|
||||
AttesterSlashings: jsonifyAttesterSlashings(capellaBlock.Capella.Block.Body.AttesterSlashings),
|
||||
Deposits: jsonifyDeposits(capellaBlock.Capella.Block.Body.Deposits),
|
||||
Eth1Data: jsonifyEth1Data(capellaBlock.Capella.Block.Body.Eth1Data),
|
||||
Graffiti: hexutil.Encode(capellaBlock.Capella.Block.Body.Graffiti),
|
||||
ProposerSlashings: jsonifyProposerSlashings(capellaBlock.Capella.Block.Body.ProposerSlashings),
|
||||
RandaoReveal: hexutil.Encode(capellaBlock.Capella.Block.Body.RandaoReveal),
|
||||
VoluntaryExits: jsonifySignedVoluntaryExits(capellaBlock.Capella.Block.Body.VoluntaryExits),
|
||||
SyncAggregate: &apimiddleware.SyncAggregateJson{
|
||||
SyncCommitteeBits: hexutil.Encode(capellaBlock.Capella.Block.Body.SyncAggregate.SyncCommitteeBits),
|
||||
SyncCommitteeSignature: hexutil.Encode(capellaBlock.Capella.Block.Body.SyncAggregate.SyncCommitteeSignature),
|
||||
},
|
||||
ExecutionPayload: &apimiddleware.ExecutionPayloadCapellaJson{
|
||||
BaseFeePerGas: bytesutil.LittleEndianBytesToBigInt(capellaBlock.Capella.Block.Body.ExecutionPayload.BaseFeePerGas).String(),
|
||||
BlockHash: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.BlockHash),
|
||||
BlockNumber: uint64ToString(capellaBlock.Capella.Block.Body.ExecutionPayload.BlockNumber),
|
||||
ExtraData: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.ExtraData),
|
||||
FeeRecipient: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.FeeRecipient),
|
||||
GasLimit: uint64ToString(capellaBlock.Capella.Block.Body.ExecutionPayload.GasLimit),
|
||||
GasUsed: uint64ToString(capellaBlock.Capella.Block.Body.ExecutionPayload.GasUsed),
|
||||
LogsBloom: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.LogsBloom),
|
||||
ParentHash: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.ParentHash),
|
||||
PrevRandao: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.PrevRandao),
|
||||
ReceiptsRoot: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.ReceiptsRoot),
|
||||
StateRoot: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.StateRoot),
|
||||
TimeStamp: uint64ToString(capellaBlock.Capella.Block.Body.ExecutionPayload.Timestamp),
|
||||
Transactions: jsonifyTransactions(capellaBlock.Capella.Block.Body.ExecutionPayload.Transactions),
|
||||
Withdrawals: jsonifyWithdrawals(capellaBlock.Capella.Block.Body.ExecutionPayload.Withdrawals),
|
||||
},
|
||||
BLSToExecutionChanges: jsonifyBlsToExecutionChanges(capellaBlock.Capella.Block.Body.BlsToExecutionChanges),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
marshalledBlock, err := json.Marshal(jsonCapellaBlock)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "capella"}
|
||||
jsonRestHandler.EXPECT().PostRestJson(
|
||||
context.Background(),
|
||||
"/eth/v1/beacon/blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(marshalledBlock),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(context.Background(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := capellaBlock.Capella.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
|
||||
func generateSignedCapellaBlock() *ethpb.GenericSignedBeaconBlock_Capella {
|
||||
return ðpb.GenericSignedBeaconBlock_Capella{
|
||||
Capella: ðpb.SignedBeaconBlockCapella{
|
||||
Block: test_helpers.GenerateProtoCapellaBeaconBlock(),
|
||||
Signature: test_helpers.FillByteSlice(96, 127),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ go_library(
|
||||
srcs = [
|
||||
"altair_beacon_block_test_helpers.go",
|
||||
"bellatrix_beacon_block_test_helpers.go",
|
||||
"capella_beacon_block_test_helpers.go",
|
||||
"phase0_beacon_block_test_helpers.go",
|
||||
"test_helpers.go",
|
||||
],
|
||||
|
||||
@@ -0,0 +1,538 @@
|
||||
package test_helpers
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
func GenerateProtoCapellaBeaconBlock() *ethpb.BeaconBlockCapella {
|
||||
return ðpb.BeaconBlockCapella{
|
||||
Slot: 1,
|
||||
ProposerIndex: 2,
|
||||
ParentRoot: FillByteSlice(32, 3),
|
||||
StateRoot: FillByteSlice(32, 4),
|
||||
Body: ðpb.BeaconBlockBodyCapella{
|
||||
RandaoReveal: FillByteSlice(96, 5),
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: FillByteSlice(32, 6),
|
||||
DepositCount: 7,
|
||||
BlockHash: FillByteSlice(32, 8),
|
||||
},
|
||||
Graffiti: FillByteSlice(32, 9),
|
||||
ProposerSlashings: []*ethpb.ProposerSlashing{
|
||||
{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 10,
|
||||
ProposerIndex: 11,
|
||||
ParentRoot: FillByteSlice(32, 12),
|
||||
StateRoot: FillByteSlice(32, 13),
|
||||
BodyRoot: FillByteSlice(32, 14),
|
||||
},
|
||||
Signature: FillByteSlice(96, 15),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 16,
|
||||
ProposerIndex: 17,
|
||||
ParentRoot: FillByteSlice(32, 18),
|
||||
StateRoot: FillByteSlice(32, 19),
|
||||
BodyRoot: FillByteSlice(32, 20),
|
||||
},
|
||||
Signature: FillByteSlice(96, 21),
|
||||
},
|
||||
},
|
||||
{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 22,
|
||||
ProposerIndex: 23,
|
||||
ParentRoot: FillByteSlice(32, 24),
|
||||
StateRoot: FillByteSlice(32, 25),
|
||||
BodyRoot: FillByteSlice(32, 26),
|
||||
},
|
||||
Signature: FillByteSlice(96, 27),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 28,
|
||||
ProposerIndex: 29,
|
||||
ParentRoot: FillByteSlice(32, 30),
|
||||
StateRoot: FillByteSlice(32, 31),
|
||||
BodyRoot: FillByteSlice(32, 32),
|
||||
},
|
||||
Signature: FillByteSlice(96, 33),
|
||||
},
|
||||
},
|
||||
},
|
||||
AttesterSlashings: []*ethpb.AttesterSlashing{
|
||||
{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{34, 35},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 36,
|
||||
CommitteeIndex: 37,
|
||||
BeaconBlockRoot: FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 39,
|
||||
Root: FillByteSlice(32, 40),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 41,
|
||||
Root: FillByteSlice(32, 42),
|
||||
},
|
||||
},
|
||||
Signature: FillByteSlice(96, 43),
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{44, 45},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 46,
|
||||
CommitteeIndex: 47,
|
||||
BeaconBlockRoot: FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 49,
|
||||
Root: FillByteSlice(32, 50),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 51,
|
||||
Root: FillByteSlice(32, 52),
|
||||
},
|
||||
},
|
||||
Signature: FillByteSlice(96, 53),
|
||||
},
|
||||
},
|
||||
{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{54, 55},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 56,
|
||||
CommitteeIndex: 57,
|
||||
BeaconBlockRoot: FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 59,
|
||||
Root: FillByteSlice(32, 60),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 61,
|
||||
Root: FillByteSlice(32, 62),
|
||||
},
|
||||
},
|
||||
Signature: FillByteSlice(96, 63),
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{64, 65},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 66,
|
||||
CommitteeIndex: 67,
|
||||
BeaconBlockRoot: FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 69,
|
||||
Root: FillByteSlice(32, 70),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 71,
|
||||
Root: FillByteSlice(32, 72),
|
||||
},
|
||||
},
|
||||
Signature: FillByteSlice(96, 73),
|
||||
},
|
||||
},
|
||||
},
|
||||
Attestations: []*ethpb.Attestation{
|
||||
{
|
||||
AggregationBits: FillByteSlice(4, 74),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 75,
|
||||
CommitteeIndex: 76,
|
||||
BeaconBlockRoot: FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 78,
|
||||
Root: FillByteSlice(32, 79),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 80,
|
||||
Root: FillByteSlice(32, 81),
|
||||
},
|
||||
},
|
||||
Signature: FillByteSlice(96, 82),
|
||||
},
|
||||
{
|
||||
AggregationBits: FillByteSlice(4, 83),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 84,
|
||||
CommitteeIndex: 85,
|
||||
BeaconBlockRoot: FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 87,
|
||||
Root: FillByteSlice(32, 88),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 89,
|
||||
Root: FillByteSlice(32, 90),
|
||||
},
|
||||
},
|
||||
Signature: FillByteSlice(96, 91),
|
||||
},
|
||||
},
|
||||
Deposits: []*ethpb.Deposit{
|
||||
{
|
||||
Proof: FillByteArraySlice(33, FillByteSlice(32, 92)),
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: FillByteSlice(48, 94),
|
||||
WithdrawalCredentials: FillByteSlice(32, 95),
|
||||
Amount: 96,
|
||||
Signature: FillByteSlice(96, 97),
|
||||
},
|
||||
},
|
||||
{
|
||||
Proof: FillByteArraySlice(33, FillByteSlice(32, 98)),
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: FillByteSlice(48, 100),
|
||||
WithdrawalCredentials: FillByteSlice(32, 101),
|
||||
Amount: 102,
|
||||
Signature: FillByteSlice(96, 103),
|
||||
},
|
||||
},
|
||||
},
|
||||
VoluntaryExits: []*ethpb.SignedVoluntaryExit{
|
||||
{
|
||||
Exit: ðpb.VoluntaryExit{
|
||||
Epoch: 104,
|
||||
ValidatorIndex: 105,
|
||||
},
|
||||
Signature: FillByteSlice(96, 106),
|
||||
},
|
||||
{
|
||||
Exit: ðpb.VoluntaryExit{
|
||||
Epoch: 107,
|
||||
ValidatorIndex: 108,
|
||||
},
|
||||
Signature: FillByteSlice(96, 109),
|
||||
},
|
||||
},
|
||||
SyncAggregate: ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: FillByteSlice(64, 110),
|
||||
SyncCommitteeSignature: FillByteSlice(96, 111),
|
||||
},
|
||||
ExecutionPayload: &enginev1.ExecutionPayloadCapella{
|
||||
ParentHash: FillByteSlice(32, 112),
|
||||
FeeRecipient: FillByteSlice(20, 113),
|
||||
StateRoot: FillByteSlice(32, 114),
|
||||
ReceiptsRoot: FillByteSlice(32, 115),
|
||||
LogsBloom: FillByteSlice(256, 116),
|
||||
PrevRandao: FillByteSlice(32, 117),
|
||||
BlockNumber: 118,
|
||||
GasLimit: 119,
|
||||
GasUsed: 120,
|
||||
Timestamp: 121,
|
||||
ExtraData: FillByteSlice(32, 122),
|
||||
BaseFeePerGas: FillByteSlice(32, 123),
|
||||
BlockHash: FillByteSlice(32, 124),
|
||||
Transactions: [][]byte{
|
||||
FillByteSlice(32, 125),
|
||||
FillByteSlice(32, 126),
|
||||
},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
{
|
||||
Index: 127,
|
||||
ValidatorIndex: 128,
|
||||
Address: FillByteSlice(20, 129),
|
||||
Amount: 130,
|
||||
},
|
||||
{
|
||||
Index: 131,
|
||||
ValidatorIndex: 132,
|
||||
Address: FillByteSlice(20, 133),
|
||||
Amount: 134,
|
||||
},
|
||||
},
|
||||
},
|
||||
BlsToExecutionChanges: []*ethpb.SignedBLSToExecutionChange{
|
||||
{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 135,
|
||||
FromBlsPubkey: FillByteSlice(48, 136),
|
||||
ToExecutionAddress: FillByteSlice(20, 137),
|
||||
},
|
||||
Signature: FillByteSlice(96, 138),
|
||||
},
|
||||
{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 139,
|
||||
FromBlsPubkey: FillByteSlice(48, 140),
|
||||
ToExecutionAddress: FillByteSlice(20, 141),
|
||||
},
|
||||
Signature: FillByteSlice(96, 142),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateJsonCapellaBeaconBlock() *apimiddleware.BeaconBlockCapellaJson {
|
||||
return &apimiddleware.BeaconBlockCapellaJson{
|
||||
Slot: "1",
|
||||
ProposerIndex: "2",
|
||||
ParentRoot: FillEncodedByteSlice(32, 3),
|
||||
StateRoot: FillEncodedByteSlice(32, 4),
|
||||
Body: &apimiddleware.BeaconBlockBodyCapellaJson{
|
||||
RandaoReveal: FillEncodedByteSlice(96, 5),
|
||||
Eth1Data: &apimiddleware.Eth1DataJson{
|
||||
DepositRoot: FillEncodedByteSlice(32, 6),
|
||||
DepositCount: "7",
|
||||
BlockHash: FillEncodedByteSlice(32, 8),
|
||||
},
|
||||
Graffiti: FillEncodedByteSlice(32, 9),
|
||||
ProposerSlashings: []*apimiddleware.ProposerSlashingJson{
|
||||
{
|
||||
Header_1: &apimiddleware.SignedBeaconBlockHeaderJson{
|
||||
Header: &apimiddleware.BeaconBlockHeaderJson{
|
||||
Slot: "10",
|
||||
ProposerIndex: "11",
|
||||
ParentRoot: FillEncodedByteSlice(32, 12),
|
||||
StateRoot: FillEncodedByteSlice(32, 13),
|
||||
BodyRoot: FillEncodedByteSlice(32, 14),
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 15),
|
||||
},
|
||||
Header_2: &apimiddleware.SignedBeaconBlockHeaderJson{
|
||||
Header: &apimiddleware.BeaconBlockHeaderJson{
|
||||
Slot: "16",
|
||||
ProposerIndex: "17",
|
||||
ParentRoot: FillEncodedByteSlice(32, 18),
|
||||
StateRoot: FillEncodedByteSlice(32, 19),
|
||||
BodyRoot: FillEncodedByteSlice(32, 20),
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 21),
|
||||
},
|
||||
},
|
||||
{
|
||||
Header_1: &apimiddleware.SignedBeaconBlockHeaderJson{
|
||||
Header: &apimiddleware.BeaconBlockHeaderJson{
|
||||
Slot: "22",
|
||||
ProposerIndex: "23",
|
||||
ParentRoot: FillEncodedByteSlice(32, 24),
|
||||
StateRoot: FillEncodedByteSlice(32, 25),
|
||||
BodyRoot: FillEncodedByteSlice(32, 26),
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 27),
|
||||
},
|
||||
Header_2: &apimiddleware.SignedBeaconBlockHeaderJson{
|
||||
Header: &apimiddleware.BeaconBlockHeaderJson{
|
||||
Slot: "28",
|
||||
ProposerIndex: "29",
|
||||
ParentRoot: FillEncodedByteSlice(32, 30),
|
||||
StateRoot: FillEncodedByteSlice(32, 31),
|
||||
BodyRoot: FillEncodedByteSlice(32, 32),
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 33),
|
||||
},
|
||||
},
|
||||
},
|
||||
AttesterSlashings: []*apimiddleware.AttesterSlashingJson{
|
||||
{
|
||||
Attestation_1: &apimiddleware.IndexedAttestationJson{
|
||||
AttestingIndices: []string{"34", "35"},
|
||||
Data: &apimiddleware.AttestationDataJson{
|
||||
Slot: "36",
|
||||
CommitteeIndex: "37",
|
||||
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
|
||||
Source: &apimiddleware.CheckpointJson{
|
||||
Epoch: "39",
|
||||
Root: FillEncodedByteSlice(32, 40),
|
||||
},
|
||||
Target: &apimiddleware.CheckpointJson{
|
||||
Epoch: "41",
|
||||
Root: FillEncodedByteSlice(32, 42),
|
||||
},
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 43),
|
||||
},
|
||||
Attestation_2: &apimiddleware.IndexedAttestationJson{
|
||||
AttestingIndices: []string{"44", "45"},
|
||||
Data: &apimiddleware.AttestationDataJson{
|
||||
Slot: "46",
|
||||
CommitteeIndex: "47",
|
||||
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
|
||||
Source: &apimiddleware.CheckpointJson{
|
||||
Epoch: "49",
|
||||
Root: FillEncodedByteSlice(32, 50),
|
||||
},
|
||||
Target: &apimiddleware.CheckpointJson{
|
||||
Epoch: "51",
|
||||
Root: FillEncodedByteSlice(32, 52),
|
||||
},
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 53),
|
||||
},
|
||||
},
|
||||
{
|
||||
Attestation_1: &apimiddleware.IndexedAttestationJson{
|
||||
AttestingIndices: []string{"54", "55"},
|
||||
Data: &apimiddleware.AttestationDataJson{
|
||||
Slot: "56",
|
||||
CommitteeIndex: "57",
|
||||
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
|
||||
Source: &apimiddleware.CheckpointJson{
|
||||
Epoch: "59",
|
||||
Root: FillEncodedByteSlice(32, 60),
|
||||
},
|
||||
Target: &apimiddleware.CheckpointJson{
|
||||
Epoch: "61",
|
||||
Root: FillEncodedByteSlice(32, 62),
|
||||
},
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 63),
|
||||
},
|
||||
Attestation_2: &apimiddleware.IndexedAttestationJson{
|
||||
AttestingIndices: []string{"64", "65"},
|
||||
Data: &apimiddleware.AttestationDataJson{
|
||||
Slot: "66",
|
||||
CommitteeIndex: "67",
|
||||
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
|
||||
Source: &apimiddleware.CheckpointJson{
|
||||
Epoch: "69",
|
||||
Root: FillEncodedByteSlice(32, 70),
|
||||
},
|
||||
Target: &apimiddleware.CheckpointJson{
|
||||
Epoch: "71",
|
||||
Root: FillEncodedByteSlice(32, 72),
|
||||
},
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 73),
|
||||
},
|
||||
},
|
||||
},
|
||||
Attestations: []*apimiddleware.AttestationJson{
|
||||
{
|
||||
AggregationBits: FillEncodedByteSlice(4, 74),
|
||||
Data: &apimiddleware.AttestationDataJson{
|
||||
Slot: "75",
|
||||
CommitteeIndex: "76",
|
||||
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
|
||||
Source: &apimiddleware.CheckpointJson{
|
||||
Epoch: "78",
|
||||
Root: FillEncodedByteSlice(32, 79),
|
||||
},
|
||||
Target: &apimiddleware.CheckpointJson{
|
||||
Epoch: "80",
|
||||
Root: FillEncodedByteSlice(32, 81),
|
||||
},
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 82),
|
||||
},
|
||||
{
|
||||
AggregationBits: FillEncodedByteSlice(4, 83),
|
||||
Data: &apimiddleware.AttestationDataJson{
|
||||
Slot: "84",
|
||||
CommitteeIndex: "85",
|
||||
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
|
||||
Source: &apimiddleware.CheckpointJson{
|
||||
Epoch: "87",
|
||||
Root: FillEncodedByteSlice(32, 88),
|
||||
},
|
||||
Target: &apimiddleware.CheckpointJson{
|
||||
Epoch: "89",
|
||||
Root: FillEncodedByteSlice(32, 90),
|
||||
},
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 91),
|
||||
},
|
||||
},
|
||||
Deposits: []*apimiddleware.DepositJson{
|
||||
{
|
||||
Proof: FillEncodedByteArraySlice(33, FillEncodedByteSlice(32, 92)),
|
||||
Data: &apimiddleware.Deposit_DataJson{
|
||||
PublicKey: FillEncodedByteSlice(48, 94),
|
||||
WithdrawalCredentials: FillEncodedByteSlice(32, 95),
|
||||
Amount: "96",
|
||||
Signature: FillEncodedByteSlice(96, 97),
|
||||
},
|
||||
},
|
||||
{
|
||||
Proof: FillEncodedByteArraySlice(33, FillEncodedByteSlice(32, 98)),
|
||||
Data: &apimiddleware.Deposit_DataJson{
|
||||
PublicKey: FillEncodedByteSlice(48, 100),
|
||||
WithdrawalCredentials: FillEncodedByteSlice(32, 101),
|
||||
Amount: "102",
|
||||
Signature: FillEncodedByteSlice(96, 103),
|
||||
},
|
||||
},
|
||||
},
|
||||
VoluntaryExits: []*apimiddleware.SignedVoluntaryExitJson{
|
||||
{
|
||||
Exit: &apimiddleware.VoluntaryExitJson{
|
||||
Epoch: "104",
|
||||
ValidatorIndex: "105",
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 106),
|
||||
},
|
||||
{
|
||||
Exit: &apimiddleware.VoluntaryExitJson{
|
||||
Epoch: "107",
|
||||
ValidatorIndex: "108",
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 109),
|
||||
},
|
||||
},
|
||||
SyncAggregate: &apimiddleware.SyncAggregateJson{
|
||||
SyncCommitteeBits: FillEncodedByteSlice(64, 110),
|
||||
SyncCommitteeSignature: FillEncodedByteSlice(96, 111),
|
||||
},
|
||||
ExecutionPayload: &apimiddleware.ExecutionPayloadCapellaJson{
|
||||
ParentHash: FillEncodedByteSlice(32, 112),
|
||||
FeeRecipient: FillEncodedByteSlice(20, 113),
|
||||
StateRoot: FillEncodedByteSlice(32, 114),
|
||||
ReceiptsRoot: FillEncodedByteSlice(32, 115),
|
||||
LogsBloom: FillEncodedByteSlice(256, 116),
|
||||
PrevRandao: FillEncodedByteSlice(32, 117),
|
||||
BlockNumber: "118",
|
||||
GasLimit: "119",
|
||||
GasUsed: "120",
|
||||
TimeStamp: "121",
|
||||
ExtraData: FillEncodedByteSlice(32, 122),
|
||||
BaseFeePerGas: bytesutil.LittleEndianBytesToBigInt(FillByteSlice(32, 123)).String(),
|
||||
BlockHash: FillEncodedByteSlice(32, 124),
|
||||
Transactions: []string{
|
||||
FillEncodedByteSlice(32, 125),
|
||||
FillEncodedByteSlice(32, 126),
|
||||
},
|
||||
Withdrawals: []*apimiddleware.WithdrawalJson{
|
||||
{
|
||||
WithdrawalIndex: "127",
|
||||
ValidatorIndex: "128",
|
||||
ExecutionAddress: FillEncodedByteSlice(20, 129),
|
||||
Amount: "130",
|
||||
},
|
||||
{
|
||||
WithdrawalIndex: "131",
|
||||
ValidatorIndex: "132",
|
||||
ExecutionAddress: FillEncodedByteSlice(20, 133),
|
||||
Amount: "134",
|
||||
},
|
||||
},
|
||||
},
|
||||
BLSToExecutionChanges: []*apimiddleware.SignedBLSToExecutionChangeJson{
|
||||
{
|
||||
Message: &apimiddleware.BLSToExecutionChangeJson{
|
||||
ValidatorIndex: "135",
|
||||
FromBLSPubkey: FillEncodedByteSlice(48, 136),
|
||||
ToExecutionAddress: FillEncodedByteSlice(20, 137),
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 138),
|
||||
},
|
||||
{
|
||||
Message: &apimiddleware.BLSToExecutionChangeJson{
|
||||
ValidatorIndex: "139",
|
||||
FromBLSPubkey: FillEncodedByteSlice(48, 140),
|
||||
ToExecutionAddress: FillEncodedByteSlice(20, 141),
|
||||
},
|
||||
Signature: FillEncodedByteSlice(96, 142),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user