diff --git a/proto/prysm/v1alpha1/block/block_interfaces.go b/proto/prysm/v1alpha1/block/block_interfaces.go index 37287d790146..cc8a067612b8 100644 --- a/proto/prysm/v1alpha1/block/block_interfaces.go +++ b/proto/prysm/v1alpha1/block/block_interfaces.go @@ -17,6 +17,7 @@ type SignedBeaconBlock interface { Proto() proto.Message PbPhase0Block() (*ethpb.SignedBeaconBlock, error) PbAltairBlock() (*ethpb.SignedBeaconBlockAltair, error) + PbMergeBlock() (*ethpb.SignedBeaconBlockMerge, error) ssz.Marshaler ssz.Unmarshaler Version() int @@ -54,4 +55,5 @@ type BeaconBlockBody interface { IsNil() bool HashTreeRoot() ([32]byte, error) Proto() proto.Message + ExecutionPayload() (*ethpb.ExecutionPayload, error) } diff --git a/proto/prysm/v1alpha1/cloners.go b/proto/prysm/v1alpha1/cloners.go index f6710e7bf13e..47d597f3a18e 100644 --- a/proto/prysm/v1alpha1/cloners.go +++ b/proto/prysm/v1alpha1/cloners.go @@ -377,6 +377,74 @@ func CopySyncAggregate(a *SyncAggregate) *SyncAggregate { } } +// CopySignedBeaconBlockMerge copies the provided SignedBeaconBlockMerge. +func CopySignedBeaconBlockMerge(sigBlock *SignedBeaconBlockMerge) *SignedBeaconBlockMerge { + if sigBlock == nil { + return nil + } + return &SignedBeaconBlockMerge{ + Block: CopyBeaconBlockMerge(sigBlock.Block), + Signature: bytesutil.SafeCopyBytes(sigBlock.Signature), + } +} + +// CopyBeaconBlockMerge copies the provided BeaconBlockMerge. +func CopyBeaconBlockMerge(block *BeaconBlockMerge) *BeaconBlockMerge { + if block == nil { + return nil + } + return &BeaconBlockMerge{ + Slot: block.Slot, + ProposerIndex: block.ProposerIndex, + ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot), + StateRoot: bytesutil.SafeCopyBytes(block.StateRoot), + Body: CopyBeaconBlockBodyMerge(block.Body), + } +} + +// CopyBeaconBlockBodyMerge copies the provided BeaconBlockBodyMerge. +func CopyBeaconBlockBodyMerge(body *BeaconBlockBodyMerge) *BeaconBlockBodyMerge { + if body == nil { + return nil + } + return &BeaconBlockBodyMerge{ + RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal), + Eth1Data: CopyETH1Data(body.Eth1Data), + Graffiti: bytesutil.SafeCopyBytes(body.Graffiti), + ProposerSlashings: CopyProposerSlashings(body.ProposerSlashings), + AttesterSlashings: CopyAttesterSlashings(body.AttesterSlashings), + Attestations: CopyAttestations(body.Attestations), + Deposits: CopyDeposits(body.Deposits), + VoluntaryExits: CopySignedVoluntaryExits(body.VoluntaryExits), + SyncAggregate: CopySyncAggregate(body.SyncAggregate), + ExecutionPayload: CopyExecutionPayload(body.ExecutionPayload), + } +} + +// CopyExecutionPayload copies the provided ApplicationPayload. +func CopyExecutionPayload(payload *ExecutionPayload) *ExecutionPayload { + if payload == nil { + return nil + } + + return &ExecutionPayload{ + ParentHash: bytesutil.SafeCopyBytes(payload.ParentHash), + FeeRecipient: bytesutil.SafeCopyBytes(payload.FeeRecipient), + StateRoot: bytesutil.SafeCopyBytes(payload.StateRoot), + ReceiptRoot: bytesutil.SafeCopyBytes(payload.ReceiptRoot), + LogsBloom: bytesutil.SafeCopyBytes(payload.LogsBloom), + Random: bytesutil.SafeCopyBytes(payload.Random), + BlockNumber: payload.BlockNumber, + GasLimit: payload.GasLimit, + GasUsed: payload.GasUsed, + Timestamp: payload.Timestamp, + ExtraData: bytesutil.SafeCopyBytes(payload.ExtraData), + BaseFeePerGas: bytesutil.SafeCopyBytes(payload.BaseFeePerGas), + BlockHash: bytesutil.SafeCopyBytes(payload.BlockHash), + Transactions: bytesutil.SafeCopy2dBytes(payload.Transactions), + } +} + // CopyExecutionPayloadHeader copies the provided execution payload object. func CopyExecutionPayloadHeader(payload *ExecutionPayloadHeader) *ExecutionPayloadHeader { if payload == nil { diff --git a/proto/prysm/v1alpha1/cloners_test.go b/proto/prysm/v1alpha1/cloners_test.go index 6368036720fb..c14e0a2cbebe 100644 --- a/proto/prysm/v1alpha1/cloners_test.go +++ b/proto/prysm/v1alpha1/cloners_test.go @@ -318,6 +318,36 @@ func TestCopyPayloadHeader(t *testing.T) { assert.NotEmpty(t, got, "Copied execution payload header has empty fields") } +func TestCopySignedBeaconBlockMerge(t *testing.T) { + sbb := genSignedBeaconBlockMerge() + + got := v1alpha1.CopySignedBeaconBlockMerge(sbb) + if !reflect.DeepEqual(got, sbb) { + t.Errorf("CopySignedBeaconBlockMerge() = %v, want %v", got, sbb) + } + assert.NotEmpty(t, sbb, "Copied signed beacon block Merge has empty fields") +} + +func TestCopyBeaconBlockMerge(t *testing.T) { + b := genBeaconBlockMerge() + + got := v1alpha1.CopyBeaconBlockMerge(b) + if !reflect.DeepEqual(got, b) { + t.Errorf("CopyBeaconBlockMerge() = %v, want %v", got, b) + } + assert.NotEmpty(t, b, "Copied beacon block Merge has empty fields") +} + +func TestCopyBeaconBlockBodyMerge(t *testing.T) { + bb := genBeaconBlockBodyMerge() + + got := v1alpha1.CopyBeaconBlockBodyMerge(bb) + if !reflect.DeepEqual(got, bb) { + t.Errorf("CopyBeaconBlockBodyMerge() = %v, want %v", got, bb) + } + assert.NotEmpty(t, bb, "Copied beacon block body Merge has empty fields") +} + func bytes() []byte { b := make([]byte, 32) _, err := rand.Read(b) @@ -574,6 +604,38 @@ func genSignedBeaconBlockAltair() *v1alpha1.SignedBeaconBlockAltair { } } +func genBeaconBlockBodyMerge() *v1alpha1.BeaconBlockBodyMerge { + return &v1alpha1.BeaconBlockBodyMerge{ + RandaoReveal: bytes(), + Eth1Data: genEth1Data(), + Graffiti: bytes(), + ProposerSlashings: genProposerSlashings(5), + AttesterSlashings: genAttesterSlashings(5), + Attestations: genAttestations(10), + Deposits: genDeposits(5), + VoluntaryExits: genSignedVoluntaryExits(12), + SyncAggregate: genSyncAggregate(), + ExecutionPayload: genPayload(), + } +} + +func genBeaconBlockMerge() *v1alpha1.BeaconBlockMerge { + return &v1alpha1.BeaconBlockMerge{ + Slot: 123455, + ProposerIndex: 55433, + ParentRoot: bytes(), + StateRoot: bytes(), + Body: genBeaconBlockBodyMerge(), + } +} + +func genSignedBeaconBlockMerge() *v1alpha1.SignedBeaconBlockMerge { + return &v1alpha1.SignedBeaconBlockMerge{ + Block: genBeaconBlockMerge(), + Signature: bytes(), + } +} + func genSyncCommitteeMessage() *v1alpha1.SyncCommitteeMessage { return &v1alpha1.SyncCommitteeMessage{ Slot: 424555, @@ -583,6 +645,25 @@ func genSyncCommitteeMessage() *v1alpha1.SyncCommitteeMessage { } } +func genPayload() *v1alpha1.ExecutionPayload { + return &v1alpha1.ExecutionPayload{ + ParentHash: bytes(), + FeeRecipient: bytes(), + StateRoot: bytes(), + ReceiptRoot: bytes(), + LogsBloom: bytes(), + Random: bytes(), + BlockNumber: 1, + GasLimit: 2, + GasUsed: 3, + Timestamp: 4, + ExtraData: bytes(), + BaseFeePerGas: bytes(), + BlockHash: bytes(), + Transactions: [][]byte{{'a'}, {'b'}, {'c'}}, + } +} + func genPayloadHeader() *v1alpha1.ExecutionPayloadHeader { return &v1alpha1.ExecutionPayloadHeader{ ParentHash: bytes(), diff --git a/proto/prysm/v1alpha1/wrapper/beacon_block.go b/proto/prysm/v1alpha1/wrapper/beacon_block.go index 830bc71ce55f..384d2b745824 100644 --- a/proto/prysm/v1alpha1/wrapper/beacon_block.go +++ b/proto/prysm/v1alpha1/wrapper/beacon_block.go @@ -84,11 +84,16 @@ func (w Phase0SignedBeaconBlock) PbPhase0Block() (*eth.SignedBeaconBlock, error) return w.b, nil } -// PbAltairBlock returns the underlying protobuf object. +// PbAltairBlock is a stub. func (w Phase0SignedBeaconBlock) PbAltairBlock() (*eth.SignedBeaconBlockAltair, error) { return nil, errors.New("unsupported altair block") } +// PbMergeBlock is a stub. +func (w Phase0SignedBeaconBlock) PbMergeBlock() (*eth.SignedBeaconBlockMerge, error) { + return nil, errors.New("unsupported merge block") +} + // Version of the underlying protobuf object. func (w Phase0SignedBeaconBlock) Version() int { return version.Phase0 @@ -264,6 +269,11 @@ func (w Phase0BeaconBlockBody) Proto() proto.Message { return w.b } +// ExecutionPayload is a stub. +func (w Phase0BeaconBlockBody) ExecutionPayload() (*eth.ExecutionPayload, error) { + return nil, errors.New("ExecutionPayload is not supported in phase 0 block body") +} + var ( // ErrUnsupportedPhase0Block is returned when accessing a phase0 block from an altair wrapped // block. @@ -350,6 +360,11 @@ func (w altairSignedBeaconBlock) PbPhase0Block() (*eth.SignedBeaconBlock, error) return nil, ErrUnsupportedPhase0Block } +// PbMergeBlock is a stub. +func (w altairSignedBeaconBlock) PbMergeBlock() (*eth.SignedBeaconBlockMerge, error) { + return nil, errors.New("unsupported merge block") +} + // Version of the underlying protobuf object. func (w altairSignedBeaconBlock) Version() int { return version.Altair @@ -532,3 +547,274 @@ func (w altairBeaconBlockBody) HashTreeRoot() ([32]byte, error) { func (w altairBeaconBlockBody) Proto() proto.Message { return w.b } + +// ExecutionPayload is a stub. +func (w altairBeaconBlockBody) ExecutionPayload() (*eth.ExecutionPayload, error) { + return nil, errors.New("ExecutionPayload is not supported in altair block body") +} + +// mergeSignedBeaconBlock is a convenience wrapper around a merge beacon block +// object. This wrapper allows us to conform to a common interface so that beacon +// blocks for future forks can also be applied across prysm without issues. +type mergeSignedBeaconBlock struct { + b *eth.SignedBeaconBlockMerge +} + +// WrappedMergeSignedBeaconBlock is constructor which wraps a protobuf merge block with the block wrapper. +func WrappedMergeSignedBeaconBlock(b *eth.SignedBeaconBlockMerge) (block.SignedBeaconBlock, error) { + w := mergeSignedBeaconBlock{b: b} + if w.IsNil() { + return nil, ErrNilObjectWrapped + } + return w, nil +} + +// Signature returns the respective block signature. +func (w mergeSignedBeaconBlock) Signature() []byte { + return w.b.Signature +} + +// Block returns the underlying beacon block object. +func (w mergeSignedBeaconBlock) Block() block.BeaconBlock { + return mergeBeaconBlock{b: w.b.Block} +} + +// IsNil checks if the underlying beacon block is nil. +func (w mergeSignedBeaconBlock) IsNil() bool { + return w.b == nil || w.b.Block == nil +} + +// Copy performs a deep copy of the signed beacon block object. +func (w mergeSignedBeaconBlock) Copy() block.SignedBeaconBlock { + return mergeSignedBeaconBlock{b: eth.CopySignedBeaconBlockMerge(w.b)} +} + +// MarshalSSZ marshals the signed beacon block to its relevant ssz form. +func (w mergeSignedBeaconBlock) MarshalSSZ() ([]byte, error) { + return w.b.MarshalSSZ() +} + +// MarshalSSZTo marshals the signed beacon block to its relevant ssz +// form to the provided byte buffer. +func (w mergeSignedBeaconBlock) MarshalSSZTo(dst []byte) ([]byte, error) { + return w.b.MarshalSSZTo(dst) +} + +// SizeSSZ returns the size of serialized signed block +func (w mergeSignedBeaconBlock) SizeSSZ() int { + return w.b.SizeSSZ() +} + +// UnmarshalSSZ unmarshalls the signed beacon block from its relevant ssz +// form. +func (w mergeSignedBeaconBlock) UnmarshalSSZ(buf []byte) error { + return w.b.UnmarshalSSZ(buf) +} + +// Proto returns the block in its underlying protobuf interface. +func (w mergeSignedBeaconBlock) Proto() proto.Message { + return w.b +} + +// PbMergeBlock returns the underlying protobuf object. +func (w mergeSignedBeaconBlock) PbMergeBlock() (*eth.SignedBeaconBlockMerge, error) { + return w.b, nil +} + +// PbPhase0Block is a stub. +func (w mergeSignedBeaconBlock) PbPhase0Block() (*eth.SignedBeaconBlock, error) { + return nil, ErrUnsupportedPhase0Block +} + +// PbAltairBlock returns the underlying protobuf object. +func (w mergeSignedBeaconBlock) PbAltairBlock() (*eth.SignedBeaconBlockAltair, error) { + return nil, errors.New("unsupported altair block") +} + +// Version of the underlying protobuf object. +func (w mergeSignedBeaconBlock) Version() int { + return version.Merge +} + +func (w mergeSignedBeaconBlock) Header() (*eth.SignedBeaconBlockHeader, error) { + root, err := w.b.Block.Body.HashTreeRoot() + if err != nil { + return nil, errors.Wrapf(err, "could not hash block") + } + + return ð.SignedBeaconBlockHeader{ + Header: ð.BeaconBlockHeader{ + Slot: w.b.Block.Slot, + ProposerIndex: w.b.Block.ProposerIndex, + ParentRoot: w.b.Block.ParentRoot, + StateRoot: w.b.Block.StateRoot, + BodyRoot: root[:], + }, + Signature: w.Signature(), + }, nil +} + +// mergeBeaconBlock is the wrapper for the actual block. +type mergeBeaconBlock struct { + b *eth.BeaconBlockMerge +} + +// WrappedMergeBeaconBlock is constructor which wraps a protobuf merge object +// with the block wrapper. +func WrappedMergeBeaconBlock(b *eth.BeaconBlockMerge) (block.BeaconBlock, error) { + w := mergeBeaconBlock{b: b} + if w.IsNil() { + return nil, ErrNilObjectWrapped + } + return w, nil +} + +// Slot returns the respective slot of the block. +func (w mergeBeaconBlock) Slot() types.Slot { + return w.b.Slot +} + +// ProposerIndex returns proposer index of the beacon block. +func (w mergeBeaconBlock) ProposerIndex() types.ValidatorIndex { + return w.b.ProposerIndex +} + +// ParentRoot returns the parent root of beacon block. +func (w mergeBeaconBlock) ParentRoot() []byte { + return w.b.ParentRoot +} + +// StateRoot returns the state root of the beacon block. +func (w mergeBeaconBlock) StateRoot() []byte { + return w.b.StateRoot +} + +// Body returns the underlying block body. +func (w mergeBeaconBlock) Body() block.BeaconBlockBody { + return mergeBeaconBlockBody{b: w.b.Body} +} + +// IsNil checks if the beacon block is nil. +func (w mergeBeaconBlock) IsNil() bool { + return w.b == nil +} + +// HashTreeRoot returns the ssz root of the block. +func (w mergeBeaconBlock) HashTreeRoot() ([32]byte, error) { + return w.b.HashTreeRoot() +} + +// MarshalSSZ marshals the block into its respective +// ssz form. +func (w mergeBeaconBlock) MarshalSSZ() ([]byte, error) { + return w.b.MarshalSSZ() +} + +// MarshalSSZTo marshals the beacon block to its relevant ssz +// form to the provided byte buffer. +func (w mergeBeaconBlock) MarshalSSZTo(dst []byte) ([]byte, error) { + return w.b.MarshalSSZTo(dst) +} + +// SizeSSZ returns the size of serialized block. +func (w mergeBeaconBlock) SizeSSZ() int { + return w.b.SizeSSZ() +} + +// UnmarshalSSZ unmarshalls the beacon block from its relevant ssz +// form. +func (w mergeBeaconBlock) UnmarshalSSZ(buf []byte) error { + return w.b.UnmarshalSSZ(buf) +} + +// Proto returns the underlying block object in its +// proto form. +func (w mergeBeaconBlock) Proto() proto.Message { + return w.b +} + +// Version of the underlying protobuf object. +func (w mergeBeaconBlock) Version() int { + return version.Merge +} + +// mergeBeaconBlockBody is a wrapper of a beacon block body. +type mergeBeaconBlockBody struct { + b *eth.BeaconBlockBodyMerge +} + +// WrappedMergeBeaconBlockBody is constructor which wraps a protobuf merge object +// with the block wrapper. +func WrappedMergeBeaconBlockBody(b *eth.BeaconBlockBodyMerge) (block.BeaconBlockBody, error) { + w := mergeBeaconBlockBody{b: b} + if w.IsNil() { + return nil, ErrNilObjectWrapped + } + return w, nil +} + +// RandaoReveal returns the randao reveal from the block body. +func (w mergeBeaconBlockBody) RandaoReveal() []byte { + return w.b.RandaoReveal +} + +// Eth1Data returns the eth1 data in the block. +func (w mergeBeaconBlockBody) Eth1Data() *eth.Eth1Data { + return w.b.Eth1Data +} + +// Graffiti returns the graffiti in the block. +func (w mergeBeaconBlockBody) Graffiti() []byte { + return w.b.Graffiti +} + +// ProposerSlashings returns the proposer slashings in the block. +func (w mergeBeaconBlockBody) ProposerSlashings() []*eth.ProposerSlashing { + return w.b.ProposerSlashings +} + +// AttesterSlashings returns the attester slashings in the block. +func (w mergeBeaconBlockBody) AttesterSlashings() []*eth.AttesterSlashing { + return w.b.AttesterSlashings +} + +// Attestations returns the stored attestations in the block. +func (w mergeBeaconBlockBody) Attestations() []*eth.Attestation { + return w.b.Attestations +} + +// Deposits returns the stored deposits in the block. +func (w mergeBeaconBlockBody) Deposits() []*eth.Deposit { + return w.b.Deposits +} + +// VoluntaryExits returns the voluntary exits in the block. +func (w mergeBeaconBlockBody) VoluntaryExits() []*eth.SignedVoluntaryExit { + return w.b.VoluntaryExits +} + +// SyncAggregate returns the sync aggregate in the block. +func (w mergeBeaconBlockBody) SyncAggregate() (*eth.SyncAggregate, error) { + return w.b.SyncAggregate, nil +} + +// IsNil checks if the block body is nil. +func (w mergeBeaconBlockBody) IsNil() bool { + return w.b == nil +} + +// HashTreeRoot returns the ssz root of the block body. +func (w mergeBeaconBlockBody) HashTreeRoot() ([32]byte, error) { + return w.b.HashTreeRoot() +} + +// Proto returns the underlying proto form of the block +// body. +func (w mergeBeaconBlockBody) Proto() proto.Message { + return w.b +} + +// ExecutionPayload returns the Execution payload of the block body. +func (w mergeBeaconBlockBody) ExecutionPayload() (*eth.ExecutionPayload, error) { + return w.b.ExecutionPayload, nil +} diff --git a/proto/prysm/v1alpha1/wrapper/beacon_block_test.go b/proto/prysm/v1alpha1/wrapper/beacon_block_test.go index 710085ce2b2c..f54bf9faf37c 100644 --- a/proto/prysm/v1alpha1/wrapper/beacon_block_test.go +++ b/proto/prysm/v1alpha1/wrapper/beacon_block_test.go @@ -336,15 +336,15 @@ func TestPhase0SignedBeaconBlock_Header(t *testing.T) { assert.DeepEqual(t, signature, header.Signature) } -func TestAltairSignedBeaconBlock_Header(t *testing.T) { +func TestMergeSignedBeaconBlock_Header(t *testing.T) { root := bytesutil.PadTo([]byte("root"), 32) signature := bytesutil.PadTo([]byte("sig"), 96) - body := ðpb.BeaconBlockBodyAltair{} - body = util.HydrateBeaconBlockBodyAltair(body) + body := ðpb.BeaconBlockBodyMerge{} + body = util.HydrateBeaconBlockBodyMerge(body) bodyRoot, err := body.HashTreeRoot() require.NoError(t, err) - block := ðpb.SignedBeaconBlockAltair{ - Block: ðpb.BeaconBlockAltair{ + block := ðpb.SignedBeaconBlockMerge{ + Block: ðpb.BeaconBlockMerge{ Slot: 1, ProposerIndex: 1, ParentRoot: root, @@ -353,7 +353,7 @@ func TestAltairSignedBeaconBlock_Header(t *testing.T) { }, Signature: signature, } - wrapped, err := wrapper.WrappedAltairSignedBeaconBlock(block) + wrapped, err := wrapper.WrappedMergeSignedBeaconBlock(block) require.NoError(t, err) header, err := wrapped.Header() @@ -365,3 +365,308 @@ func TestAltairSignedBeaconBlock_Header(t *testing.T) { assert.DeepEqual(t, root, header.Header.ParentRoot) assert.DeepEqual(t, signature, header.Signature) } + +func TestMergeSignedBeaconBlock_Signature(t *testing.T) { + sig := []byte{0x11, 0x22} + wsb, err := wrapper.WrappedMergeSignedBeaconBlock(ðpb.SignedBeaconBlockMerge{Block: ðpb.BeaconBlockMerge{}, Signature: sig}) + require.NoError(t, err) + + if !bytes.Equal(sig, wsb.Signature()) { + t.Error("Wrong signature returned") + } +} + +func TestMergeSignedBeaconBlock_Block(t *testing.T) { + blk := ðpb.BeaconBlockMerge{Slot: 54} + wsb, err := wrapper.WrappedMergeSignedBeaconBlock(ðpb.SignedBeaconBlockMerge{Block: blk}) + require.NoError(t, err) + + assert.DeepEqual(t, blk, wsb.Block().Proto()) +} + +func TestMergeSignedBeaconBlock_IsNil(t *testing.T) { + _, err := wrapper.WrappedMergeSignedBeaconBlock(nil) + require.Equal(t, wrapper.ErrNilObjectWrapped, err) + + wsb, err := wrapper.WrappedMergeSignedBeaconBlock(ðpb.SignedBeaconBlockMerge{Block: ðpb.BeaconBlockMerge{}}) + require.NoError(t, err) + + assert.Equal(t, false, wsb.IsNil()) +} + +func TestMergeSignedBeaconBlock_Copy(t *testing.T) { + t.Skip("TODO: Missing mutation evaluation helpers") +} + +func TestMergeSignedBeaconBlock_Proto(t *testing.T) { + sb := ðpb.SignedBeaconBlockMerge{ + Block: ðpb.BeaconBlockMerge{Slot: 66}, + Signature: []byte{0x11, 0x22}, + } + wsb, err := wrapper.WrappedMergeSignedBeaconBlock(sb) + require.NoError(t, err) + + assert.Equal(t, sb, wsb.Proto()) +} + +func TestMergeSignedBeaconBlock_PbPhase0Block(t *testing.T) { + wsb, err := wrapper.WrappedMergeSignedBeaconBlock(ðpb.SignedBeaconBlockMerge{Block: ðpb.BeaconBlockMerge{}}) + require.NoError(t, err) + + if _, err := wsb.PbPhase0Block(); err != wrapper.ErrUnsupportedPhase0Block { + t.Errorf("Wrong error returned. Want %v got %v", wrapper.ErrUnsupportedPhase0Block, err) + } +} + +func TestMergeSignedBeaconBlock_PbMergeBlock(t *testing.T) { + sb := ðpb.SignedBeaconBlockMerge{ + Block: ðpb.BeaconBlockMerge{Slot: 66}, + Signature: []byte{0x11, 0x22}, + } + wsb, err := wrapper.WrappedMergeSignedBeaconBlock(sb) + require.NoError(t, err) + + got, err := wsb.PbMergeBlock() + assert.NoError(t, err) + assert.Equal(t, sb, got) +} + +func TestMergeSignedBeaconBlock_MarshalSSZTo(t *testing.T) { + wsb, err := wrapper.WrappedMergeSignedBeaconBlock(util.HydrateSignedBeaconBlockMerge(ðpb.SignedBeaconBlockMerge{})) + assert.NoError(t, err) + + var b []byte + b, err = wsb.MarshalSSZTo(b) + assert.NoError(t, err) + assert.NotEqual(t, 0, len(b)) +} + +func TestMergeSignedBeaconBlock_SSZ(t *testing.T) { + wsb, err := wrapper.WrappedMergeSignedBeaconBlock(util.HydrateSignedBeaconBlockMerge(ðpb.SignedBeaconBlockMerge{})) + assert.NoError(t, err) + + b, err := wsb.MarshalSSZ() + assert.NoError(t, err) + assert.NotEqual(t, 0, len(b)) + + assert.NotEqual(t, 0, wsb.SizeSSZ()) + + assert.NoError(t, wsb.UnmarshalSSZ(b)) +} + +func TestMergeSignedBeaconBlock_Version(t *testing.T) { + wsb, err := wrapper.WrappedMergeSignedBeaconBlock(ðpb.SignedBeaconBlockMerge{Block: ðpb.BeaconBlockMerge{}}) + require.NoError(t, err) + + assert.Equal(t, version.Merge, wsb.Version()) +} + +func TestMergeBeaconBlock_Slot(t *testing.T) { + slot := types.Slot(546) + wb, err := wrapper.WrappedMergeBeaconBlock(ðpb.BeaconBlockMerge{Slot: slot}) + require.NoError(t, err) + + assert.Equal(t, slot, wb.Slot()) +} + +func TestMergeBeaconBlock_ProposerIndex(t *testing.T) { + pi := types.ValidatorIndex(555) + wb, err := wrapper.WrappedMergeBeaconBlock(ðpb.BeaconBlockMerge{ProposerIndex: pi}) + require.NoError(t, err) + + assert.Equal(t, pi, wb.ProposerIndex()) +} + +func TestMergeBeaconBlock_ParentRoot(t *testing.T) { + root := []byte{0xAA, 0xBF, 0x33, 0x01} + wb, err := wrapper.WrappedMergeBeaconBlock(ðpb.BeaconBlockMerge{ParentRoot: root}) + require.NoError(t, err) + + assert.DeepEqual(t, root, wb.ParentRoot()) +} + +func TestMergeBeaconBlock_StateRoot(t *testing.T) { + root := []byte{0xAA, 0xBF, 0x33, 0x01} + wb, err := wrapper.WrappedMergeBeaconBlock(ðpb.BeaconBlockMerge{StateRoot: root}) + require.NoError(t, err) + + assert.DeepEqual(t, root, wb.StateRoot()) +} + +func TestMergeBeaconBlock_Body(t *testing.T) { + body := ðpb.BeaconBlockBodyMerge{Graffiti: []byte{0x44}} + wb, err := wrapper.WrappedMergeBeaconBlock(ðpb.BeaconBlockMerge{Body: body}) + require.NoError(t, err) + + assert.Equal(t, body, wb.Body().Proto()) +} + +func TestMergeBeaconBlock_IsNil(t *testing.T) { + _, err := wrapper.WrappedMergeBeaconBlock(nil) + require.Equal(t, wrapper.ErrNilObjectWrapped, err) + + wb, err := wrapper.WrappedMergeBeaconBlock(ðpb.BeaconBlockMerge{}) + require.NoError(t, err) + + assert.Equal(t, false, wb.IsNil()) +} + +func TestMergeBeaconBlock_HashTreeRoot(t *testing.T) { + wb, err := wrapper.WrappedMergeBeaconBlock(util.HydrateBeaconBlockMerge(ðpb.BeaconBlockMerge{})) + require.NoError(t, err) + + rt, err := wb.HashTreeRoot() + assert.NoError(t, err) + assert.NotEmpty(t, rt) +} + +func TestMergeBeaconBlock_Proto(t *testing.T) { + blk := ðpb.BeaconBlockMerge{ProposerIndex: 234} + wb, err := wrapper.WrappedMergeBeaconBlock(blk) + require.NoError(t, err) + + assert.Equal(t, blk, wb.Proto()) +} + +func TestMergeBeaconBlock_SSZ(t *testing.T) { + wb, err := wrapper.WrappedMergeBeaconBlock(util.HydrateBeaconBlockMerge(ðpb.BeaconBlockMerge{})) + assert.NoError(t, err) + + b, err := wb.MarshalSSZ() + assert.NoError(t, err) + assert.NotEqual(t, 0, len(b)) + + assert.NotEqual(t, 0, wb.SizeSSZ()) + + assert.NoError(t, wb.UnmarshalSSZ(b)) +} + +func TestMergeBeaconBlock_Version(t *testing.T) { + wb, err := wrapper.WrappedMergeBeaconBlock(ðpb.BeaconBlockMerge{}) + require.NoError(t, err) + + assert.Equal(t, version.Merge, wb.Version()) +} + +func TestMergeBeaconBlockBody_RandaoReveal(t *testing.T) { + root := []byte{0xAA, 0xBF, 0x33, 0x01} + wbb, err := wrapper.WrappedMergeBeaconBlockBody(ðpb.BeaconBlockBodyMerge{RandaoReveal: root}) + require.NoError(t, err) + + assert.DeepEqual(t, root, wbb.RandaoReveal()) +} + +func TestMergeBeaconBlockBody_Eth1Data(t *testing.T) { + data := &v1alpha1.Eth1Data{} + body := ðpb.BeaconBlockBodyMerge{ + Eth1Data: data, + } + wbb, err := wrapper.WrappedMergeBeaconBlockBody(body) + require.NoError(t, err) + assert.Equal(t, data, wbb.Eth1Data()) +} + +func TestMergeBeaconBlockBody_Graffiti(t *testing.T) { + graffiti := []byte{0x66, 0xAA} + body := ðpb.BeaconBlockBodyMerge{Graffiti: graffiti} + wbb, err := wrapper.WrappedMergeBeaconBlockBody(body) + require.NoError(t, err) + + assert.DeepEqual(t, graffiti, wbb.Graffiti()) +} + +func TestMergeBeaconBlockBody_ProposerSlashings(t *testing.T) { + ps := []*v1alpha1.ProposerSlashing{ + {Header_1: &v1alpha1.SignedBeaconBlockHeader{ + Signature: []byte{0x11, 0x20}, + }}, + } + body := ðpb.BeaconBlockBodyMerge{ProposerSlashings: ps} + wbb, err := wrapper.WrappedMergeBeaconBlockBody(body) + require.NoError(t, err) + + assert.DeepEqual(t, ps, wbb.ProposerSlashings()) +} + +func TestMergeBeaconBlockBody_AttesterSlashings(t *testing.T) { + as := []*v1alpha1.AttesterSlashing{ + {Attestation_1: &v1alpha1.IndexedAttestation{Signature: []byte{0x11}}}, + } + body := ðpb.BeaconBlockBodyMerge{AttesterSlashings: as} + wbb, err := wrapper.WrappedMergeBeaconBlockBody(body) + require.NoError(t, err) + + assert.DeepEqual(t, as, wbb.AttesterSlashings()) +} + +func TestMergeBeaconBlockBody_Attestations(t *testing.T) { + atts := []*v1alpha1.Attestation{{Signature: []byte{0x88}}} + + body := ðpb.BeaconBlockBodyMerge{Attestations: atts} + wbb, err := wrapper.WrappedMergeBeaconBlockBody(body) + require.NoError(t, err) + + assert.DeepEqual(t, atts, wbb.Attestations()) +} + +func TestMergeBeaconBlockBody_Deposits(t *testing.T) { + deposits := []*v1alpha1.Deposit{ + {Proof: [][]byte{{0x54, 0x10}}}, + } + body := ðpb.BeaconBlockBodyMerge{Deposits: deposits} + wbb, err := wrapper.WrappedMergeBeaconBlockBody(body) + require.NoError(t, err) + + assert.DeepEqual(t, deposits, wbb.Deposits()) +} + +func TestMergeBeaconBlockBody_VoluntaryExits(t *testing.T) { + exits := []*v1alpha1.SignedVoluntaryExit{ + {Exit: &v1alpha1.VoluntaryExit{Epoch: 54}}, + } + body := ðpb.BeaconBlockBodyMerge{VoluntaryExits: exits} + wbb, err := wrapper.WrappedMergeBeaconBlockBody(body) + require.NoError(t, err) + + assert.DeepEqual(t, exits, wbb.VoluntaryExits()) +} + +func TestMergeBeaconBlockBody_IsNil(t *testing.T) { + _, err := wrapper.WrappedMergeBeaconBlockBody(nil) + require.Equal(t, wrapper.ErrNilObjectWrapped, err) + + wbb, err := wrapper.WrappedMergeBeaconBlockBody(ðpb.BeaconBlockBodyMerge{}) + require.NoError(t, err) + assert.Equal(t, false, wbb.IsNil()) + +} + +func TestMergeBeaconBlockBody_HashTreeRoot(t *testing.T) { + wb, err := wrapper.WrappedMergeBeaconBlockBody(util.HydrateBeaconBlockBodyMerge(ðpb.BeaconBlockBodyMerge{})) + assert.NoError(t, err) + + rt, err := wb.HashTreeRoot() + assert.NoError(t, err) + assert.NotEmpty(t, rt) +} + +func TestMergeBeaconBlockBody_Proto(t *testing.T) { + body := ðpb.BeaconBlockBodyMerge{Graffiti: []byte{0x66, 0xAA}} + wbb, err := wrapper.WrappedMergeBeaconBlockBody(body) + require.NoError(t, err) + + assert.Equal(t, body, wbb.Proto()) +} + +func TestMergeBeaconBlockBody_ExecutionPayload(t *testing.T) { + payloads := &v1alpha1.ExecutionPayload{ + BlockNumber: 100, + } + body := ðpb.BeaconBlockBodyMerge{ExecutionPayload: payloads} + wbb, err := wrapper.WrappedMergeBeaconBlockBody(body) + require.NoError(t, err) + + got, err := wbb.ExecutionPayload() + require.NoError(t, err) + assert.DeepEqual(t, payloads, got) +} diff --git a/testing/util/block.go b/testing/util/block.go index 4720fe53bc0c..d82c53c0186c 100644 --- a/testing/util/block.go +++ b/testing/util/block.go @@ -612,3 +612,68 @@ func HydrateBeaconBlockBodyAltair(b *ethpb.BeaconBlockBodyAltair) *ethpb.BeaconB } return b } + +// HydrateSignedBeaconBlockMerge hydrates a signed beacon block with correct field length sizes +// to comply with fssz marshalling and unmarshalling rules. +func HydrateSignedBeaconBlockMerge(b *ethpb.SignedBeaconBlockMerge) *ethpb.SignedBeaconBlockMerge { + if b.Signature == nil { + b.Signature = make([]byte, params.BeaconConfig().BLSSignatureLength) + } + b.Block = HydrateBeaconBlockMerge(b.Block) + return b +} + +// HydrateBeaconBlockMerge hydrates a beacon block with correct field length sizes +// to comply with fssz marshalling and unmarshalling rules. +func HydrateBeaconBlockMerge(b *ethpb.BeaconBlockMerge) *ethpb.BeaconBlockMerge { + if b == nil { + b = ðpb.BeaconBlockMerge{} + } + if b.ParentRoot == nil { + b.ParentRoot = make([]byte, 32) + } + if b.StateRoot == nil { + b.StateRoot = make([]byte, 32) + } + b.Body = HydrateBeaconBlockBodyMerge(b.Body) + return b +} + +// HydrateBeaconBlockBodyMerge hydrates a beacon block body with correct field length sizes +// to comply with fssz marshalling and unmarshalling rules. +func HydrateBeaconBlockBodyMerge(b *ethpb.BeaconBlockBodyMerge) *ethpb.BeaconBlockBodyMerge { + if b == nil { + b = ðpb.BeaconBlockBodyMerge{} + } + if b.RandaoReveal == nil { + b.RandaoReveal = make([]byte, params.BeaconConfig().BLSSignatureLength) + } + if b.Graffiti == nil { + b.Graffiti = make([]byte, 32) + } + if b.Eth1Data == nil { + b.Eth1Data = ðpb.Eth1Data{ + DepositRoot: make([]byte, 32), + BlockHash: make([]byte, 32), + } + } + if b.SyncAggregate == nil { + b.SyncAggregate = ðpb.SyncAggregate{ + SyncCommitteeBits: make([]byte, 64), + SyncCommitteeSignature: make([]byte, 96), + } + } + if b.ExecutionPayload == nil { + b.ExecutionPayload = ðpb.ExecutionPayload{ + ParentHash: make([]byte, 32), + FeeRecipient: make([]byte, 20), + StateRoot: make([]byte, 32), + ReceiptRoot: make([]byte, 32), + LogsBloom: make([]byte, 256), + Random: make([]byte, 32), + BaseFeePerGas: make([]byte, 32), + BlockHash: make([]byte, 32), + } + } + return b +}