diff --git a/consensus-types/blocks/BUILD.bazel b/consensus-types/blocks/BUILD.bazel new file mode 100644 index 0000000000..30b2d526ca --- /dev/null +++ b/consensus-types/blocks/BUILD.bazel @@ -0,0 +1,46 @@ +load("@prysm//tools/go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "factory.go", + "getters.go", + "proto.go", + "types.go", + ], + importpath = "github.com/prysmaticlabs/prysm/consensus-types/blocks", + visibility = ["//visibility:public"], + deps = [ + "//consensus-types/interfaces:go_default_library", + "//consensus-types/primitives:go_default_library", + "//proto/engine/v1:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + "//proto/prysm/v1alpha1/validator-client:go_default_library", + "//runtime/version:go_default_library", + "@com_github_ferranbt_fastssz//:go_default_library", + "@com_github_pkg_errors//:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = [ + "factory_test.go", + "getters_test.go", + "proto_test.go", + ], + embed = [":go_default_library"], + deps = [ + "//consensus-types/primitives:go_default_library", + "//proto/engine/v1:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + "//proto/prysm/v1alpha1/validator-client:go_default_library", + "//runtime/version:go_default_library", + "//testing/assert:go_default_library", + "//testing/require:go_default_library", + "//testing/util:go_default_library", + "@com_github_ferranbt_fastssz//:go_default_library", + "@com_github_prysmaticlabs_go_bitfield//:go_default_library", + ], +) diff --git a/consensus-types/blocks/factory.go b/consensus-types/blocks/factory.go new file mode 100644 index 0000000000..475bdf17bb --- /dev/null +++ b/consensus-types/blocks/factory.go @@ -0,0 +1,130 @@ +package blocks + +import ( + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/consensus-types/interfaces" + eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/runtime/version" +) + +var ( + // ErrUnsupportedSignedBeaconBlock is returned when the struct type is not a supported signed + // beacon block type. + ErrUnsupportedSignedBeaconBlock = errors.New("unsupported signed beacon block") + // errUnsupportedBeaconBlock is returned when the struct type is not a supported beacon block + // type. + errUnsupportedBeaconBlock = errors.New("unsupported beacon block") + // errUnsupportedBeaconBlockBody is returned when the struct type is not a supported beacon block body + // type. + errUnsupportedBeaconBlockBody = errors.New("unsupported beacon block body") + // ErrNilObjectWrapped is returned in a constructor when the underlying object is nil. + ErrNilObjectWrapped = errors.New("attempted to wrap nil object") + errNilSignedBeaconBlock = errors.New("signed beacon block can't be nil") + errNilBeaconBlock = errors.New("beacon block can't be nil") + errNilBeaconBlockBody = errors.New("beacon block body can't be nil") +) + +// NewSignedBeaconBlock creates a signed beacon block from a protobuf signed beacon block. +func NewSignedBeaconBlock(i interface{}) (*SignedBeaconBlock, error) { + switch b := i.(type) { + case *eth.GenericSignedBeaconBlock_Phase0: + return initSignedBlockFromProtoPhase0(b.Phase0) + case *eth.SignedBeaconBlock: + return initSignedBlockFromProtoPhase0(b) + case *eth.GenericSignedBeaconBlock_Altair: + return initSignedBlockFromProtoAltair(b.Altair) + case *eth.SignedBeaconBlockAltair: + return initSignedBlockFromProtoAltair(b) + case *eth.GenericSignedBeaconBlock_Bellatrix: + return initSignedBlockFromProtoBellatrix(b.Bellatrix) + case *eth.SignedBeaconBlockBellatrix: + return initSignedBlockFromProtoBellatrix(b) + case *eth.GenericSignedBeaconBlock_BlindedBellatrix: + return initBlindedSignedBlockFromProtoBellatrix(b.BlindedBellatrix) + case *eth.SignedBlindedBeaconBlockBellatrix: + return initBlindedSignedBlockFromProtoBellatrix(b) + case nil: + return nil, ErrNilObjectWrapped + default: + return nil, errors.Wrapf(ErrUnsupportedSignedBeaconBlock, "unable to create block from type %T", i) + } +} + +// NewBeaconBlock creates a beacon block from a protobuf beacon block. +func NewBeaconBlock(i interface{}) (*BeaconBlock, error) { + switch b := i.(type) { + case *eth.GenericBeaconBlock_Phase0: + return initBlockFromProtoPhase0(b.Phase0) + case *eth.BeaconBlock: + return initBlockFromProtoPhase0(b) + case *eth.GenericBeaconBlock_Altair: + return initBlockFromProtoAltair(b.Altair) + case *eth.BeaconBlockAltair: + return initBlockFromProtoAltair(b) + case *eth.GenericBeaconBlock_Bellatrix: + return initBlockFromProtoBellatrix(b.Bellatrix) + case *eth.BeaconBlockBellatrix: + return initBlockFromProtoBellatrix(b) + case *eth.GenericBeaconBlock_BlindedBellatrix: + return initBlindedBlockFromProtoBellatrix(b.BlindedBellatrix) + case *eth.BlindedBeaconBlockBellatrix: + return initBlindedBlockFromProtoBellatrix(b) + case nil: + return nil, ErrNilObjectWrapped + default: + return nil, errors.Wrapf(errUnsupportedBeaconBlock, "unable to create block from type %T", i) + } +} + +// NewBeaconBlockBody creates a beacon block body from a protobuf beacon block body. +func NewBeaconBlockBody(i interface{}) (*BeaconBlockBody, error) { + switch b := i.(type) { + case *eth.BeaconBlockBody: + return initBlockBodyFromProtoPhase0(b) + case *eth.BeaconBlockBodyAltair: + return initBlockBodyFromProtoAltair(b) + case *eth.BeaconBlockBodyBellatrix: + return initBlockBodyFromProtoBellatrix(b) + case *eth.BlindedBeaconBlockBodyBellatrix: + return initBlindedBlockBodyFromProtoBellatrix(b) + case nil: + return nil, ErrNilObjectWrapped + default: + return nil, errors.Wrapf(errUnsupportedBeaconBlockBody, "unable to create block body from type %T", i) + } +} + +// BuildSignedBeaconBlock assembles a block.SignedBeaconBlock interface compatible struct from a +// given beacon block and the appropriate signature. This method may be used to easily create a +// signed beacon block. +func BuildSignedBeaconBlock(blk interfaces.BeaconBlock, signature []byte) (*SignedBeaconBlock, error) { + pb := blk.Proto() + switch blk.Version() { + case version.Phase0: + pb, ok := pb.(*eth.BeaconBlock) + if !ok { + return nil, errIncorrectBlockVersion + } + return NewSignedBeaconBlock(ð.SignedBeaconBlock{Block: pb, Signature: signature}) + case version.Altair: + pb, ok := pb.(*eth.BeaconBlockAltair) + if !ok { + return nil, errIncorrectBlockVersion + } + return NewSignedBeaconBlock(ð.SignedBeaconBlockAltair{Block: pb, Signature: signature}) + case version.Bellatrix: + pb, ok := pb.(*eth.BeaconBlockBellatrix) + if !ok { + return nil, errIncorrectBlockVersion + } + return NewSignedBeaconBlock(ð.SignedBeaconBlockBellatrix{Block: pb, Signature: signature}) + case version.BellatrixBlind: + pb, ok := pb.(*eth.BlindedBeaconBlockBellatrix) + if !ok { + return nil, errIncorrectBlockVersion + } + return NewSignedBeaconBlock(ð.SignedBlindedBeaconBlockBellatrix{Block: pb, Signature: signature}) + default: + return nil, errUnsupportedBeaconBlock + } +} diff --git a/consensus-types/blocks/factory_test.go b/consensus-types/blocks/factory_test.go new file mode 100644 index 0000000000..bbce80ffda --- /dev/null +++ b/consensus-types/blocks/factory_test.go @@ -0,0 +1,184 @@ +package blocks + +import ( + "bytes" + "testing" + + eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/runtime/version" + "github.com/prysmaticlabs/prysm/testing/assert" + "github.com/prysmaticlabs/prysm/testing/require" +) + +func Test_NewSignedBeaconBlock(t *testing.T) { + t.Run("GenericSignedBeaconBlock_Phase0", func(t *testing.T) { + pb := ð.GenericSignedBeaconBlock_Phase0{ + Phase0: ð.SignedBeaconBlock{ + Block: ð.BeaconBlock{ + Body: ð.BeaconBlockBody{}}}} + b, err := NewSignedBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Phase0, b.version) + }) + t.Run("SignedBeaconBlock", func(t *testing.T) { + pb := ð.SignedBeaconBlock{ + Block: ð.BeaconBlock{ + Body: ð.BeaconBlockBody{}}} + b, err := NewSignedBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Phase0, b.version) + }) + t.Run("GenericSignedBeaconBlock_Altair", func(t *testing.T) { + pb := ð.GenericSignedBeaconBlock_Altair{ + Altair: ð.SignedBeaconBlockAltair{ + Block: ð.BeaconBlockAltair{ + Body: ð.BeaconBlockBodyAltair{}}}} + b, err := NewSignedBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Altair, b.version) + }) + t.Run("SignedBeaconBlockAltair", func(t *testing.T) { + pb := ð.SignedBeaconBlockAltair{ + Block: ð.BeaconBlockAltair{ + Body: ð.BeaconBlockBodyAltair{}}} + b, err := NewSignedBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Altair, b.version) + }) + t.Run("GenericSignedBeaconBlock_Bellatrix", func(t *testing.T) { + pb := ð.GenericSignedBeaconBlock_Bellatrix{ + Bellatrix: ð.SignedBeaconBlockBellatrix{ + Block: ð.BeaconBlockBellatrix{ + Body: ð.BeaconBlockBodyBellatrix{}}}} + b, err := NewSignedBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Bellatrix, b.version) + }) + t.Run("SignedBeaconBlockBellatrix", func(t *testing.T) { + pb := ð.SignedBeaconBlockBellatrix{ + Block: ð.BeaconBlockBellatrix{ + Body: ð.BeaconBlockBodyBellatrix{}}} + b, err := NewSignedBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Bellatrix, b.version) + }) + t.Run("GenericSignedBeaconBlock_BlindedBellatrix", func(t *testing.T) { + pb := ð.GenericSignedBeaconBlock_BlindedBellatrix{ + BlindedBellatrix: ð.SignedBlindedBeaconBlockBellatrix{ + Block: ð.BlindedBeaconBlockBellatrix{ + Body: ð.BlindedBeaconBlockBodyBellatrix{}}}} + b, err := NewSignedBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.BellatrixBlind, b.version) + }) + t.Run("SignedBlindedBeaconBlockBellatrix", func(t *testing.T) { + pb := ð.SignedBlindedBeaconBlockBellatrix{ + Block: ð.BlindedBeaconBlockBellatrix{ + Body: ð.BlindedBeaconBlockBodyBellatrix{}}} + b, err := NewSignedBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.BellatrixBlind, b.version) + }) + t.Run("nil", func(t *testing.T) { + _, err := NewSignedBeaconBlock(nil) + assert.ErrorContains(t, "attempted to wrap nil object", err) + }) + t.Run("unsupported type", func(t *testing.T) { + _, err := NewSignedBeaconBlock(&bytes.Reader{}) + assert.ErrorContains(t, "unable to create block from type *bytes.Reader", err) + }) +} + +func Test_NewBeaconBlock(t *testing.T) { + t.Run("GenericBeaconBlock_Phase0", func(t *testing.T) { + pb := ð.GenericBeaconBlock_Phase0{Phase0: ð.BeaconBlock{Body: ð.BeaconBlockBody{}}} + b, err := NewBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Phase0, b.version) + }) + t.Run("BeaconBlock", func(t *testing.T) { + pb := ð.BeaconBlock{Body: ð.BeaconBlockBody{}} + b, err := NewBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Phase0, b.version) + }) + t.Run("GenericBeaconBlock_Altair", func(t *testing.T) { + pb := ð.GenericBeaconBlock_Altair{Altair: ð.BeaconBlockAltair{Body: ð.BeaconBlockBodyAltair{}}} + b, err := NewBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Altair, b.version) + }) + t.Run("BeaconBlockAltair", func(t *testing.T) { + pb := ð.BeaconBlockAltair{Body: ð.BeaconBlockBodyAltair{}} + b, err := NewBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Altair, b.version) + }) + t.Run("GenericBeaconBlock_Bellatrix", func(t *testing.T) { + pb := ð.GenericBeaconBlock_Bellatrix{Bellatrix: ð.BeaconBlockBellatrix{Body: ð.BeaconBlockBodyBellatrix{}}} + b, err := NewBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Bellatrix, b.version) + }) + t.Run("BeaconBlockBellatrix", func(t *testing.T) { + pb := ð.BeaconBlockBellatrix{Body: ð.BeaconBlockBodyBellatrix{}} + b, err := NewBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.Bellatrix, b.version) + }) + t.Run("GenericBeaconBlock_BlindedBellatrix", func(t *testing.T) { + pb := ð.GenericBeaconBlock_BlindedBellatrix{BlindedBellatrix: ð.BlindedBeaconBlockBellatrix{Body: ð.BlindedBeaconBlockBodyBellatrix{}}} + b, err := NewBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.BellatrixBlind, b.version) + }) + t.Run("BlindedBeaconBlockBellatrix", func(t *testing.T) { + pb := ð.BlindedBeaconBlockBellatrix{Body: ð.BlindedBeaconBlockBodyBellatrix{}} + b, err := NewBeaconBlock(pb) + require.NoError(t, err) + assert.Equal(t, version.BellatrixBlind, b.version) + }) + t.Run("nil", func(t *testing.T) { + _, err := NewBeaconBlock(nil) + assert.ErrorContains(t, "attempted to wrap nil object", err) + }) + t.Run("unsupported type", func(t *testing.T) { + _, err := NewBeaconBlock(&bytes.Reader{}) + assert.ErrorContains(t, "unable to create block from type *bytes.Reader", err) + }) +} + +func Test_NewBeaconBlockBody(t *testing.T) { + t.Run("BeaconBlockBody", func(t *testing.T) { + pb := ð.BeaconBlockBody{} + b, err := NewBeaconBlockBody(pb) + require.NoError(t, err) + assert.Equal(t, version.Phase0, b.version) + }) + t.Run("BeaconBlockBodyAltair", func(t *testing.T) { + pb := ð.BeaconBlockBodyAltair{} + b, err := NewBeaconBlockBody(pb) + require.NoError(t, err) + assert.Equal(t, version.Altair, b.version) + }) + t.Run("BeaconBlockBodyBellatrix", func(t *testing.T) { + pb := ð.BeaconBlockBodyBellatrix{} + b, err := NewBeaconBlockBody(pb) + require.NoError(t, err) + assert.Equal(t, version.Bellatrix, b.version) + }) + t.Run("BlindedBeaconBlockBodyBellatrix", func(t *testing.T) { + pb := ð.BlindedBeaconBlockBodyBellatrix{} + b, err := NewBeaconBlockBody(pb) + require.NoError(t, err) + assert.Equal(t, version.BellatrixBlind, b.version) + }) + t.Run("nil", func(t *testing.T) { + _, err := NewBeaconBlockBody(nil) + assert.ErrorContains(t, "attempted to wrap nil object", err) + }) + t.Run("unsupported type", func(t *testing.T) { + _, err := NewBeaconBlockBody(&bytes.Reader{}) + assert.ErrorContains(t, "unable to create block body from type *bytes.Reader", err) + }) +} diff --git a/consensus-types/blocks/getters.go b/consensus-types/blocks/getters.go new file mode 100644 index 0000000000..1b429d1bf0 --- /dev/null +++ b/consensus-types/blocks/getters.go @@ -0,0 +1,592 @@ +package blocks + +import ( + ssz "github.com/ferranbt/fastssz" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/consensus-types/interfaces" + types "github.com/prysmaticlabs/prysm/consensus-types/primitives" + enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1" + eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" + validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client" + "github.com/prysmaticlabs/prysm/runtime/version" +) + +// BeaconBlockIsNil checks if any composite field of input signed beacon block is nil. +// Access to these nil fields will result in run time panic, +// it is recommended to run these checks as first line of defense. +func BeaconBlockIsNil(b interfaces.SignedBeaconBlock) error { + if b == nil || b.IsNil() { + return errNilSignedBeaconBlock + } + if b.Block().IsNil() { + return errNilBeaconBlock + } + if b.Block().Body().IsNil() { + return errNilBeaconBlockBody + } + return nil +} + +// Signature returns the respective block signature. +func (b *SignedBeaconBlock) Signature() []byte { + return b.signature +} + +// Block returns the underlying beacon block object. +func (b *SignedBeaconBlock) Block() *BeaconBlock { + return b.block +} + +// IsNil checks if the underlying beacon block is nil. +func (b *SignedBeaconBlock) IsNil() bool { + return b == nil || b.block.IsNil() +} + +// Copy performs a deep copy of the signed beacon block object. +func (b *SignedBeaconBlock) Copy() (*SignedBeaconBlock, error) { + pb, err := b.Proto() + if err != nil { + return nil, err + } + switch b.version { + case version.Phase0: + cp := eth.CopySignedBeaconBlock(pb.(*eth.SignedBeaconBlock)) + return initSignedBlockFromProtoPhase0(cp) + case version.Altair: + cp := eth.CopySignedBeaconBlockAltair(pb.(*eth.SignedBeaconBlockAltair)) + return initSignedBlockFromProtoAltair(cp) + case version.Bellatrix: + cp := eth.CopySignedBeaconBlockBellatrix(pb.(*eth.SignedBeaconBlockBellatrix)) + return initSignedBlockFromProtoBellatrix(cp) + case version.BellatrixBlind: + cp := eth.CopySignedBlindedBeaconBlockBellatrix(pb.(*eth.SignedBlindedBeaconBlockBellatrix)) + return initBlindedSignedBlockFromProtoBellatrix(cp) + default: + return nil, errIncorrectBlockVersion + } +} + +// PbGenericBlock returns a generic signed beacon block. +func (b *SignedBeaconBlock) PbGenericBlock() (*eth.GenericSignedBeaconBlock, error) { + pb, err := b.Proto() + if err != nil { + return nil, err + } + switch b.version { + case version.Phase0: + return ð.GenericSignedBeaconBlock{ + Block: ð.GenericSignedBeaconBlock_Phase0{Phase0: pb.(*eth.SignedBeaconBlock)}, + }, nil + case version.Altair: + return ð.GenericSignedBeaconBlock{ + Block: ð.GenericSignedBeaconBlock_Altair{Altair: pb.(*eth.SignedBeaconBlockAltair)}, + }, nil + case version.Bellatrix: + return ð.GenericSignedBeaconBlock{ + Block: ð.GenericSignedBeaconBlock_Bellatrix{Bellatrix: pb.(*eth.SignedBeaconBlockBellatrix)}, + }, nil + case version.BellatrixBlind: + return ð.GenericSignedBeaconBlock{ + Block: ð.GenericSignedBeaconBlock_BlindedBellatrix{BlindedBellatrix: pb.(*eth.SignedBlindedBeaconBlockBellatrix)}, + }, nil + default: + return nil, errIncorrectBlockVersion + } + +} + +// PbPhase0Block returns the underlying protobuf object. +func (b *SignedBeaconBlock) PbPhase0Block() (*eth.SignedBeaconBlock, error) { + if b.version != version.Phase0 { + return nil, errNotSupported("PbPhase0Block", b.version) + } + pb, err := b.Proto() + if err != nil { + return nil, err + } + return pb.(*eth.SignedBeaconBlock), nil +} + +// PbAltairBlock returns the underlying protobuf object. +func (b *SignedBeaconBlock) PbAltairBlock() (*eth.SignedBeaconBlockAltair, error) { + if b.version != version.Altair { + return nil, errNotSupported("PbAltairBlock", b.version) + } + pb, err := b.Proto() + if err != nil { + return nil, err + } + return pb.(*eth.SignedBeaconBlockAltair), nil +} + +// PbBellatrixBlock returns the underlying protobuf object. +func (b *SignedBeaconBlock) PbBellatrixBlock() (*eth.SignedBeaconBlockBellatrix, error) { + if b.version != version.Bellatrix { + return nil, errNotSupported("PbBellatrixBlock", b.version) + } + pb, err := b.Proto() + if err != nil { + return nil, err + } + return pb.(*eth.SignedBeaconBlockBellatrix), nil +} + +// PbBlindedBellatrixBlock returns the underlying protobuf object. +func (b *SignedBeaconBlock) PbBlindedBellatrixBlock() (*eth.SignedBlindedBeaconBlockBellatrix, error) { + if b.version != version.BellatrixBlind { + return nil, errNotSupported("PbBlindedBellatrixBlock", b.version) + } + pb, err := b.Proto() + if err != nil { + return nil, err + } + return pb.(*eth.SignedBlindedBeaconBlockBellatrix), nil +} + +// Version of the underlying protobuf object. +func (b *SignedBeaconBlock) Version() int { + return b.version +} + +// Header converts the underlying protobuf object from blinded block to header format. +func (b *SignedBeaconBlock) Header() (*eth.SignedBeaconBlockHeader, error) { + if b.IsNil() { + return nil, errNilBlock + } + root, err := b.block.body.HashTreeRoot() + if err != nil { + return nil, errors.Wrapf(err, "could not hash block body") + } + + return ð.SignedBeaconBlockHeader{ + Header: ð.BeaconBlockHeader{ + Slot: b.block.slot, + ProposerIndex: b.block.proposerIndex, + ParentRoot: b.block.parentRoot, + StateRoot: b.block.stateRoot, + BodyRoot: root[:], + }, + Signature: b.signature, + }, nil +} + +// MarshalSSZ marshals the signed beacon block to its relevant ssz form. +func (b *SignedBeaconBlock) MarshalSSZ() ([]byte, error) { + pb, err := b.Proto() + if err != nil { + return []byte{}, err + } + switch b.version { + case version.Phase0: + return pb.(*eth.SignedBeaconBlock).MarshalSSZ() + case version.Altair: + return pb.(*eth.SignedBeaconBlockAltair).MarshalSSZ() + case version.Bellatrix: + return pb.(*eth.SignedBeaconBlockBellatrix).MarshalSSZ() + case version.BellatrixBlind: + return pb.(*eth.SignedBlindedBeaconBlockBellatrix).MarshalSSZ() + default: + return []byte{}, errIncorrectBlockVersion + } +} + +// MarshalSSZTo marshals the signed beacon block's ssz +// form to the provided byte buffer. +func (b *SignedBeaconBlock) MarshalSSZTo(dst []byte) ([]byte, error) { + pb, err := b.Proto() + if err != nil { + return []byte{}, err + } + switch b.version { + case version.Phase0: + return pb.(*eth.SignedBeaconBlock).MarshalSSZTo(dst) + case version.Altair: + return pb.(*eth.SignedBeaconBlockAltair).MarshalSSZTo(dst) + case version.Bellatrix: + return pb.(*eth.SignedBeaconBlockBellatrix).MarshalSSZTo(dst) + case version.BellatrixBlind: + return pb.(*eth.SignedBlindedBeaconBlockBellatrix).MarshalSSZTo(dst) + default: + return []byte{}, errIncorrectBlockVersion + } +} + +// SizeSSZ returns the size of the serialized signed block +func (b *SignedBeaconBlock) SizeSSZ() (int, error) { + pb, err := b.Proto() + if err != nil { + return 0, err + } + switch b.version { + case version.Phase0: + return pb.(*eth.SignedBeaconBlock).SizeSSZ(), nil + case version.Altair: + return pb.(*eth.SignedBeaconBlockAltair).SizeSSZ(), nil + case version.Bellatrix: + return pb.(*eth.SignedBeaconBlockBellatrix).SizeSSZ(), nil + case version.BellatrixBlind: + return pb.(*eth.SignedBlindedBeaconBlockBellatrix).SizeSSZ(), nil + default: + return 0, errIncorrectBlockVersion + } +} + +// UnmarshalSSZ unmarshals the signed beacon block from its relevant ssz form. +func (b *SignedBeaconBlock) UnmarshalSSZ(buf []byte) error { + var newBlock *SignedBeaconBlock + switch b.version { + case version.Phase0: + pb := ð.SignedBeaconBlock{} + if err := pb.UnmarshalSSZ(buf); err != nil { + return err + } + var err error + newBlock, err = initSignedBlockFromProtoPhase0(pb) + if err != nil { + return err + } + case version.Altair: + pb := ð.SignedBeaconBlockAltair{} + if err := pb.UnmarshalSSZ(buf); err != nil { + return err + } + var err error + newBlock, err = initSignedBlockFromProtoAltair(pb) + if err != nil { + return err + } + case version.Bellatrix: + pb := ð.SignedBeaconBlockBellatrix{} + if err := pb.UnmarshalSSZ(buf); err != nil { + return err + } + var err error + newBlock, err = initSignedBlockFromProtoBellatrix(pb) + if err != nil { + return err + } + case version.BellatrixBlind: + pb := ð.SignedBlindedBeaconBlockBellatrix{} + if err := pb.UnmarshalSSZ(buf); err != nil { + return err + } + var err error + newBlock, err = initBlindedSignedBlockFromProtoBellatrix(pb) + if err != nil { + return err + } + default: + return errIncorrectBlockVersion + } + *b = *newBlock + return nil +} + +// Slot returns the respective slot of the block. +func (b *BeaconBlock) Slot() types.Slot { + return b.slot +} + +// ProposerIndex returns the proposer index of the beacon block. +func (b *BeaconBlock) ProposerIndex() types.ValidatorIndex { + return b.proposerIndex +} + +// ParentRoot returns the parent root of beacon block. +func (b *BeaconBlock) ParentRoot() []byte { + return b.parentRoot +} + +// StateRoot returns the state root of the beacon block. +func (b *BeaconBlock) StateRoot() []byte { + return b.stateRoot +} + +// Body returns the underlying block body. +func (b *BeaconBlock) Body() *BeaconBlockBody { + return b.body +} + +// IsNil checks if the beacon block is nil. +func (b *BeaconBlock) IsNil() bool { + return b == nil || b.Body().IsNil() +} + +// IsBlinded checks if the beacon block is a blinded block. +func (b *BeaconBlock) IsBlinded() bool { + switch b.version { + case version.Phase0, version.Altair, version.Bellatrix: + return false + case version.BellatrixBlind: + return true + default: + return false + } +} + +// Version of the underlying protobuf object. +func (b *BeaconBlock) Version() int { + return b.version +} + +// HashTreeRoot returns the ssz root of the block. +func (b *BeaconBlock) HashTreeRoot() ([32]byte, error) { + pb, err := b.Proto() + if err != nil { + return [32]byte{}, err + } + switch b.version { + case version.Phase0: + return pb.(*eth.BeaconBlock).HashTreeRoot() + case version.Altair: + return pb.(*eth.BeaconBlockAltair).HashTreeRoot() + case version.Bellatrix: + return pb.(*eth.BeaconBlockBellatrix).HashTreeRoot() + case version.BellatrixBlind: + return pb.(*eth.BlindedBeaconBlockBellatrix).HashTreeRoot() + default: + return [32]byte{}, errIncorrectBlockVersion + } +} + +// HashTreeRootWith ssz hashes the BeaconBlock object with a hasher. +func (b *BeaconBlock) HashTreeRootWith(h *ssz.Hasher) error { + pb, err := b.Proto() + if err != nil { + return err + } + switch b.version { + case version.Phase0: + return pb.(*eth.BeaconBlock).HashTreeRootWith(h) + case version.Altair: + return pb.(*eth.BeaconBlockAltair).HashTreeRootWith(h) + case version.Bellatrix: + return pb.(*eth.BeaconBlockBellatrix).HashTreeRootWith(h) + case version.BellatrixBlind: + return pb.(*eth.BlindedBeaconBlockBellatrix).HashTreeRootWith(h) + default: + return errIncorrectBlockVersion + } +} + +// MarshalSSZ marshals the block into its respective +// ssz form. +func (b *BeaconBlock) MarshalSSZ() ([]byte, error) { + pb, err := b.Proto() + if err != nil { + return []byte{}, err + } + switch b.version { + case version.Phase0: + return pb.(*eth.BeaconBlock).MarshalSSZ() + case version.Altair: + return pb.(*eth.BeaconBlockAltair).MarshalSSZ() + case version.Bellatrix: + return pb.(*eth.BeaconBlockBellatrix).MarshalSSZ() + case version.BellatrixBlind: + return pb.(*eth.BlindedBeaconBlockBellatrix).MarshalSSZ() + default: + return []byte{}, errIncorrectBlockVersion + } +} + +// MarshalSSZTo marshals the beacon block's ssz +// form to the provided byte buffer. +func (b *BeaconBlock) MarshalSSZTo(dst []byte) ([]byte, error) { + pb, err := b.Proto() + if err != nil { + return []byte{}, err + } + switch b.version { + case version.Phase0: + return pb.(*eth.BeaconBlock).MarshalSSZTo(dst) + case version.Altair: + return pb.(*eth.BeaconBlockAltair).MarshalSSZTo(dst) + case version.Bellatrix: + return pb.(*eth.BeaconBlockBellatrix).MarshalSSZTo(dst) + case version.BellatrixBlind: + return pb.(*eth.BlindedBeaconBlockBellatrix).MarshalSSZTo(dst) + default: + return []byte{}, errIncorrectBlockVersion + } +} + +// SizeSSZ returns the size of the serialized block. +func (b *BeaconBlock) SizeSSZ() (int, error) { + pb, err := b.Proto() + if err != nil { + return 0, err + } + switch b.version { + case version.Phase0: + return pb.(*eth.BeaconBlock).SizeSSZ(), nil + case version.Altair: + return pb.(*eth.BeaconBlockAltair).SizeSSZ(), nil + case version.Bellatrix: + return pb.(*eth.BeaconBlockBellatrix).SizeSSZ(), nil + case version.BellatrixBlind: + return pb.(*eth.BlindedBeaconBlockBellatrix).SizeSSZ(), nil + default: + return 0, errIncorrectBlockVersion + } +} + +// UnmarshalSSZ unmarshals the beacon block from its relevant ssz form. +func (b *BeaconBlock) UnmarshalSSZ(buf []byte) error { + var newBlock *BeaconBlock + switch b.version { + case version.Phase0: + pb := ð.BeaconBlock{} + if err := pb.UnmarshalSSZ(buf); err != nil { + return err + } + var err error + newBlock, err = initBlockFromProtoPhase0(pb) + if err != nil { + return err + } + case version.Altair: + pb := ð.BeaconBlockAltair{} + if err := pb.UnmarshalSSZ(buf); err != nil { + return err + } + var err error + newBlock, err = initBlockFromProtoAltair(pb) + if err != nil { + return err + } + case version.Bellatrix: + pb := ð.BeaconBlockBellatrix{} + if err := pb.UnmarshalSSZ(buf); err != nil { + return err + } + var err error + newBlock, err = initBlockFromProtoBellatrix(pb) + if err != nil { + return err + } + case version.BellatrixBlind: + pb := ð.BlindedBeaconBlockBellatrix{} + if err := pb.UnmarshalSSZ(buf); err != nil { + return err + } + var err error + newBlock, err = initBlindedBlockFromProtoBellatrix(pb) + if err != nil { + return err + } + default: + return errIncorrectBlockVersion + } + *b = *newBlock + return nil +} + +// AsSignRequestObject returns the underlying sign request object. +func (b *BeaconBlock) AsSignRequestObject() (validatorpb.SignRequestObject, error) { + pb, err := b.Proto() + if err != nil { + return nil, err + } + switch b.version { + case version.Phase0: + return &validatorpb.SignRequest_Block{Block: pb.(*eth.BeaconBlock)}, nil + case version.Altair: + return &validatorpb.SignRequest_BlockV2{BlockV2: pb.(*eth.BeaconBlockAltair)}, nil + case version.Bellatrix: + return &validatorpb.SignRequest_BlockV3{BlockV3: pb.(*eth.BeaconBlockBellatrix)}, nil + case version.BellatrixBlind: + return &validatorpb.SignRequest_BlindedBlockV3{BlindedBlockV3: pb.(*eth.BlindedBeaconBlockBellatrix)}, nil + default: + return nil, errIncorrectBlockVersion + } +} + +// IsNil checks if the block body is nil. +func (b *BeaconBlockBody) IsNil() bool { + return b == nil +} + +// RandaoReveal returns the randao reveal from the block body. +func (b *BeaconBlockBody) RandaoReveal() []byte { + return b.randaoReveal +} + +// Eth1Data returns the eth1 data in the block. +func (b *BeaconBlockBody) Eth1Data() *eth.Eth1Data { + return b.eth1Data +} + +// Graffiti returns the graffiti in the block. +func (b *BeaconBlockBody) Graffiti() []byte { + return b.graffiti +} + +// ProposerSlashings returns the proposer slashings in the block. +func (b *BeaconBlockBody) ProposerSlashings() []*eth.ProposerSlashing { + return b.proposerSlashings +} + +// AttesterSlashings returns the attester slashings in the block. +func (b *BeaconBlockBody) AttesterSlashings() []*eth.AttesterSlashing { + return b.attesterSlashings +} + +// Attestations returns the stored attestations in the block. +func (b *BeaconBlockBody) Attestations() []*eth.Attestation { + return b.attestations +} + +// Deposits returns the stored deposits in the block. +func (b *BeaconBlockBody) Deposits() []*eth.Deposit { + return b.deposits +} + +// VoluntaryExits returns the voluntary exits in the block. +func (b *BeaconBlockBody) VoluntaryExits() []*eth.SignedVoluntaryExit { + return b.voluntaryExits +} + +// SyncAggregate returns the sync aggregate in the block. +func (b *BeaconBlockBody) SyncAggregate() (*eth.SyncAggregate, error) { + if b.version == version.Phase0 { + return nil, errNotSupported("SyncAggregate", b.version) + } + return b.syncAggregate, nil +} + +// ExecutionPayload returns the execution payload of the block body. +func (b *BeaconBlockBody) ExecutionPayload() (*enginev1.ExecutionPayload, error) { + if b.version != version.Bellatrix { + return nil, errNotSupported("ExecutionPayload", b.version) + } + return b.executionPayload, nil +} + +// ExecutionPayloadHeader returns the execution payload header of the block body. +func (b *BeaconBlockBody) ExecutionPayloadHeader() (*eth.ExecutionPayloadHeader, error) { + if b.version != version.BellatrixBlind { + return nil, errNotSupported("ExecutionPayloadHeader", b.version) + } + return b.executionPayloadHeader, nil +} + +// HashTreeRoot returns the ssz root of the block body. +func (b *BeaconBlockBody) HashTreeRoot() ([32]byte, error) { + pb, err := b.Proto() + if err != nil { + return [32]byte{}, err + } + switch b.version { + case version.Phase0: + return pb.(*eth.BeaconBlockBody).HashTreeRoot() + case version.Altair: + return pb.(*eth.BeaconBlockBodyAltair).HashTreeRoot() + case version.Bellatrix: + return pb.(*eth.BeaconBlockBodyBellatrix).HashTreeRoot() + case version.BellatrixBlind: + return pb.(*eth.BlindedBeaconBlockBodyBellatrix).HashTreeRoot() + default: + return [32]byte{}, errIncorrectBodyVersion + } +} diff --git a/consensus-types/blocks/getters_test.go b/consensus-types/blocks/getters_test.go new file mode 100644 index 0000000000..c2124d6871 --- /dev/null +++ b/consensus-types/blocks/getters_test.go @@ -0,0 +1,314 @@ +package blocks + +import ( + "testing" + + ssz "github.com/ferranbt/fastssz" + types "github.com/prysmaticlabs/prysm/consensus-types/primitives" + enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1" + eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" + validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client" + "github.com/prysmaticlabs/prysm/runtime/version" + "github.com/prysmaticlabs/prysm/testing/assert" + "github.com/prysmaticlabs/prysm/testing/require" + "github.com/prysmaticlabs/prysm/testing/util" +) + +func Test_SignedBeaconBlock_Signature(t *testing.T) { + sb := &SignedBeaconBlock{signature: []byte("signature")} + assert.DeepEqual(t, []byte("signature"), sb.Signature()) +} + +func Test_SignedBeaconBlock_Block(t *testing.T) { + b := &BeaconBlock{} + sb := &SignedBeaconBlock{block: b} + assert.Equal(t, b, sb.Block()) +} + +func Test_SignedBeaconBlock_IsNil(t *testing.T) { + t.Run("nil signed block", func(t *testing.T) { + var sb *SignedBeaconBlock + assert.Equal(t, true, sb.IsNil()) + }) + t.Run("nil block", func(t *testing.T) { + sb := &SignedBeaconBlock{} + assert.Equal(t, true, sb.IsNil()) + }) + t.Run("nil body", func(t *testing.T) { + sb := &SignedBeaconBlock{block: &BeaconBlock{}} + assert.Equal(t, true, sb.IsNil()) + }) + t.Run("not nil", func(t *testing.T) { + sb := &SignedBeaconBlock{block: &BeaconBlock{body: &BeaconBlockBody{}}} + assert.Equal(t, false, sb.IsNil()) + }) +} + +func Test_SignedBeaconBlock_Copy(t *testing.T) { + bb := &BeaconBlockBody{} + b := &BeaconBlock{body: bb} + sb := &SignedBeaconBlock{block: b} + cp, err := sb.Copy() + require.NoError(t, err) + assert.NotEqual(t, cp, sb) + assert.NotEqual(t, cp.block, sb.block) + assert.NotEqual(t, cp.block.body, sb.block.body) +} + +func Test_SignedBeaconBlock_Version(t *testing.T) { + sb := &SignedBeaconBlock{version: 128} + assert.Equal(t, 128, sb.Version()) +} + +func Test_SignedBeaconBlock_Header(t *testing.T) { + bb := &BeaconBlockBody{ + version: version.Phase0, + randaoReveal: make([]byte, 96), + eth1Data: ð.Eth1Data{ + DepositRoot: make([]byte, 32), + BlockHash: make([]byte, 32), + }, + graffiti: make([]byte, 32), + } + sb := &SignedBeaconBlock{ + version: version.Phase0, + block: &BeaconBlock{ + version: version.Phase0, + slot: 128, + proposerIndex: 128, + parentRoot: []byte("parentroot"), + stateRoot: []byte("stateroot"), + body: bb, + }, + signature: []byte("signature"), + } + h, err := sb.Header() + require.NoError(t, err) + assert.DeepEqual(t, sb.signature, h.Signature) + assert.Equal(t, sb.block.slot, h.Header.Slot) + assert.Equal(t, sb.block.proposerIndex, h.Header.ProposerIndex) + assert.DeepEqual(t, sb.block.parentRoot, h.Header.ParentRoot) + assert.DeepEqual(t, sb.block.stateRoot, h.Header.StateRoot) + expectedHTR, err := bb.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR[:], h.Header.BodyRoot) +} + +func Test_SignedBeaconBlock_UnmarshalSSZ(t *testing.T) { + pb := util.HydrateSignedBeaconBlock(ð.SignedBeaconBlock{}) + buf, err := pb.MarshalSSZ() + require.NoError(t, err) + expectedHTR, err := pb.HashTreeRoot() + require.NoError(t, err) + sb := &SignedBeaconBlock{} + require.NoError(t, sb.UnmarshalSSZ(buf)) + msg, err := sb.Proto() + require.NoError(t, err) + actualPb, ok := msg.(*eth.SignedBeaconBlock) + require.Equal(t, true, ok) + actualHTR, err := actualPb.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, actualHTR) +} + +func Test_BeaconBlock_Slot(t *testing.T) { + b := &BeaconBlock{slot: 128} + assert.Equal(t, types.Slot(128), b.Slot()) +} + +func Test_BeaconBlock_ProposerIndex(t *testing.T) { + b := &BeaconBlock{proposerIndex: 128} + assert.Equal(t, types.ValidatorIndex(128), b.ProposerIndex()) +} + +func Test_BeaconBlock_ParentRoot(t *testing.T) { + b := &BeaconBlock{parentRoot: []byte("parentroot")} + assert.DeepEqual(t, []byte("parentroot"), b.ParentRoot()) +} + +func Test_BeaconBlock_StateRoot(t *testing.T) { + b := &BeaconBlock{stateRoot: []byte("stateroot")} + assert.DeepEqual(t, []byte("stateroot"), b.StateRoot()) +} + +func Test_BeaconBlock_Body(t *testing.T) { + bb := &BeaconBlockBody{} + b := &BeaconBlock{body: bb} + assert.Equal(t, bb, b.Body()) +} + +func Test_BeaconBlock_IsNil(t *testing.T) { + t.Run("nil block", func(t *testing.T) { + var b *BeaconBlock + assert.Equal(t, true, b.IsNil()) + }) + t.Run("nil block body", func(t *testing.T) { + b := &BeaconBlock{} + assert.Equal(t, true, b.IsNil()) + }) + t.Run("not nil", func(t *testing.T) { + b := &BeaconBlock{body: &BeaconBlockBody{}} + assert.Equal(t, false, b.IsNil()) + }) +} + +func Test_BeaconBlock_IsBlinded(t *testing.T) { + assert.Equal(t, false, (&BeaconBlock{version: version.Phase0}).IsBlinded()) + assert.Equal(t, false, (&BeaconBlock{version: version.Altair}).IsBlinded()) + assert.Equal(t, false, (&BeaconBlock{version: version.Bellatrix}).IsBlinded()) + assert.Equal(t, true, (&BeaconBlock{version: version.BellatrixBlind}).IsBlinded()) + assert.Equal(t, false, (&BeaconBlock{version: 128}).IsBlinded()) +} + +func Test_BeaconBlock_Version(t *testing.T) { + b := &BeaconBlock{version: 128} + assert.Equal(t, 128, b.Version()) +} + +func Test_BeaconBlock_HashTreeRoot(t *testing.T) { + pb := util.HydrateBeaconBlock(ð.BeaconBlock{}) + expectedHTR, err := pb.HashTreeRoot() + require.NoError(t, err) + b, err := initBlockFromProtoPhase0(pb) + require.NoError(t, err) + actualHTR, err := b.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, actualHTR) +} + +func Test_BeaconBlock_HashTreeRootWith(t *testing.T) { + pb := util.HydrateBeaconBlock(ð.BeaconBlock{}) + expectedHTR, err := pb.HashTreeRoot() + require.NoError(t, err) + b, err := initBlockFromProtoPhase0(pb) + require.NoError(t, err) + h := ssz.DefaultHasherPool.Get() + require.NoError(t, b.HashTreeRootWith(h)) + actualHTR, err := h.HashRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, actualHTR) +} + +func Test_BeaconBlock_UnmarshalSSZ(t *testing.T) { + pb := util.HydrateBeaconBlock(ð.BeaconBlock{}) + buf, err := pb.MarshalSSZ() + require.NoError(t, err) + expectedHTR, err := pb.HashTreeRoot() + require.NoError(t, err) + b := &BeaconBlock{} + require.NoError(t, b.UnmarshalSSZ(buf)) + msg, err := b.Proto() + require.NoError(t, err) + actualPb, ok := msg.(*eth.BeaconBlock) + require.Equal(t, true, ok) + actualHTR, err := actualPb.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, actualHTR) +} + +func Test_BeaconBlock_AsSignRequestObject(t *testing.T) { + pb := util.HydrateBeaconBlock(ð.BeaconBlock{}) + expectedHTR, err := pb.HashTreeRoot() + require.NoError(t, err) + b, err := initBlockFromProtoPhase0(pb) + require.NoError(t, err) + signRequestObj, err := b.AsSignRequestObject() + require.NoError(t, err) + actualSignRequestObj, ok := signRequestObj.(*validatorpb.SignRequest_Block) + require.Equal(t, true, ok) + actualHTR, err := actualSignRequestObj.Block.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, actualHTR) +} + +func Test_BeaconBlockBody_IsNil(t *testing.T) { + t.Run("nil block body", func(t *testing.T) { + var bb *BeaconBlockBody + assert.Equal(t, true, bb.IsNil()) + }) + t.Run("not nil", func(t *testing.T) { + bb := &BeaconBlockBody{} + assert.Equal(t, false, bb.IsNil()) + }) +} + +func Test_BeaconBlockBody_RandaoReveal(t *testing.T) { + bb := &BeaconBlockBody{randaoReveal: []byte("randaoreveal")} + assert.DeepEqual(t, []byte("randaoreveal"), bb.RandaoReveal()) +} + +func Test_BeaconBlockBody_Eth1Data(t *testing.T) { + e := ð.Eth1Data{} + bb := &BeaconBlockBody{eth1Data: e} + assert.Equal(t, e, bb.Eth1Data()) +} + +func Test_BeaconBlockBody_Graffiti(t *testing.T) { + bb := &BeaconBlockBody{graffiti: []byte("graffiti")} + assert.DeepEqual(t, []byte("graffiti"), bb.Graffiti()) +} + +func Test_BeaconBlockBody_ProposerSlashings(t *testing.T) { + ps := make([]*eth.ProposerSlashing, 0) + bb := &BeaconBlockBody{proposerSlashings: ps} + assert.DeepSSZEqual(t, ps, bb.ProposerSlashings()) +} + +func Test_BeaconBlockBody_AttesterSlashings(t *testing.T) { + as := make([]*eth.AttesterSlashing, 0) + bb := &BeaconBlockBody{attesterSlashings: as} + assert.DeepSSZEqual(t, as, bb.AttesterSlashings()) +} + +func Test_BeaconBlockBody_Attestations(t *testing.T) { + a := make([]*eth.Attestation, 0) + bb := &BeaconBlockBody{attestations: a} + assert.DeepSSZEqual(t, a, bb.Attestations()) +} + +func Test_BeaconBlockBody_Deposits(t *testing.T) { + d := make([]*eth.Deposit, 0) + bb := &BeaconBlockBody{deposits: d} + assert.DeepSSZEqual(t, d, bb.Deposits()) +} + +func Test_BeaconBlockBody_VoluntaryExits(t *testing.T) { + ve := make([]*eth.SignedVoluntaryExit, 0) + bb := &BeaconBlockBody{voluntaryExits: ve} + assert.DeepSSZEqual(t, ve, bb.VoluntaryExits()) +} + +func Test_BeaconBlockBody_SyncAggregate(t *testing.T) { + sa := ð.SyncAggregate{} + bb := &BeaconBlockBody{version: version.Altair, syncAggregate: sa} + result, err := bb.SyncAggregate() + require.NoError(t, err) + assert.Equal(t, result, sa) +} + +func Test_BeaconBlockBody_ExecutionPayload(t *testing.T) { + ep := &enginev1.ExecutionPayload{} + bb := &BeaconBlockBody{version: version.Bellatrix, executionPayload: ep} + result, err := bb.ExecutionPayload() + require.NoError(t, err) + assert.Equal(t, result, ep) +} + +func Test_BeaconBlockBody_ExecutionPayloadHeader(t *testing.T) { + eph := ð.ExecutionPayloadHeader{} + bb := &BeaconBlockBody{version: version.BellatrixBlind, executionPayloadHeader: eph} + result, err := bb.ExecutionPayloadHeader() + require.NoError(t, err) + assert.Equal(t, result, eph) +} + +func Test_BeaconBlockBody_HashTreeRoot(t *testing.T) { + pb := util.HydrateBeaconBlockBody(ð.BeaconBlockBody{}) + expectedHTR, err := pb.HashTreeRoot() + require.NoError(t, err) + b, err := initBlockBodyFromProtoPhase0(pb) + require.NoError(t, err) + actualHTR, err := b.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, actualHTR) +} diff --git a/consensus-types/blocks/proto.go b/consensus-types/blocks/proto.go new file mode 100644 index 0000000000..4660e86cbb --- /dev/null +++ b/consensus-types/blocks/proto.go @@ -0,0 +1,416 @@ +package blocks + +import ( + "github.com/pkg/errors" + eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/runtime/version" + "google.golang.org/protobuf/proto" +) + +// Proto returns the underlying protobuf signed beacon block. +func (b *SignedBeaconBlock) Proto() (proto.Message, error) { + if b == nil { + return nil, errNilBlock + } + + blockMessage, err := b.block.Proto() + if err != nil { + return nil, err + } + + switch b.version { + case version.Phase0: + block, ok := blockMessage.(*eth.BeaconBlock) + if !ok { + return nil, errors.Wrap(err, incorrectBlockVersion) + } + return ð.SignedBeaconBlock{ + Block: block, + Signature: b.signature, + }, nil + case version.Altair: + block, ok := blockMessage.(*eth.BeaconBlockAltair) + if !ok { + return nil, errors.Wrap(err, incorrectBlockVersion) + } + return ð.SignedBeaconBlockAltair{ + Block: block, + Signature: b.signature, + }, nil + case version.Bellatrix: + block, ok := blockMessage.(*eth.BeaconBlockBellatrix) + if !ok { + return nil, errors.Wrap(err, incorrectBlockVersion) + } + return ð.SignedBeaconBlockBellatrix{ + Block: block, + Signature: b.signature, + }, nil + case version.BellatrixBlind: + block, ok := blockMessage.(*eth.BlindedBeaconBlockBellatrix) + if !ok { + return nil, errors.Wrap(err, incorrectBlockVersion) + } + return ð.SignedBlindedBeaconBlockBellatrix{ + Block: block, + Signature: b.signature, + }, nil + default: + return nil, errors.New("unsupported signed beacon block version") + } +} + +// Proto returns the underlying protobuf beacon block. +func (b *BeaconBlock) Proto() (proto.Message, error) { + if b == nil { + return nil, errNilBlock + } + + bodyMessage, err := b.body.Proto() + if err != nil { + return nil, err + } + + switch b.version { + case version.Phase0: + body, ok := bodyMessage.(*eth.BeaconBlockBody) + if !ok { + return nil, errors.Wrap(err, incorrectBodyVersion) + } + return ð.BeaconBlock{ + Slot: b.slot, + ProposerIndex: b.proposerIndex, + ParentRoot: b.parentRoot, + StateRoot: b.stateRoot, + Body: body, + }, nil + case version.Altair: + body, ok := bodyMessage.(*eth.BeaconBlockBodyAltair) + if !ok { + return nil, errors.Wrap(err, incorrectBodyVersion) + } + return ð.BeaconBlockAltair{ + Slot: b.slot, + ProposerIndex: b.proposerIndex, + ParentRoot: b.parentRoot, + StateRoot: b.stateRoot, + Body: body, + }, nil + case version.Bellatrix: + body, ok := bodyMessage.(*eth.BeaconBlockBodyBellatrix) + if !ok { + return nil, errors.Wrap(err, incorrectBodyVersion) + } + return ð.BeaconBlockBellatrix{ + Slot: b.slot, + ProposerIndex: b.proposerIndex, + ParentRoot: b.parentRoot, + StateRoot: b.stateRoot, + Body: body, + }, nil + case version.BellatrixBlind: + body, ok := bodyMessage.(*eth.BlindedBeaconBlockBodyBellatrix) + if !ok { + return nil, errors.Wrap(err, incorrectBodyVersion) + } + return ð.BlindedBeaconBlockBellatrix{ + Slot: b.slot, + ProposerIndex: b.proposerIndex, + ParentRoot: b.parentRoot, + StateRoot: b.stateRoot, + Body: body, + }, nil + default: + return nil, errors.New("unsupported beacon block version") + } +} + +// Proto returns the underlying protobuf beacon block body. +func (b *BeaconBlockBody) Proto() (proto.Message, error) { + if b == nil { + return nil, errNilBody + } + + switch b.version { + case version.Phase0: + return ð.BeaconBlockBody{ + RandaoReveal: b.randaoReveal, + Eth1Data: b.eth1Data, + Graffiti: b.graffiti, + ProposerSlashings: b.proposerSlashings, + AttesterSlashings: b.attesterSlashings, + Attestations: b.attestations, + Deposits: b.deposits, + VoluntaryExits: b.voluntaryExits, + }, nil + case version.Altair: + return ð.BeaconBlockBodyAltair{ + RandaoReveal: b.randaoReveal, + Eth1Data: b.eth1Data, + Graffiti: b.graffiti, + ProposerSlashings: b.proposerSlashings, + AttesterSlashings: b.attesterSlashings, + Attestations: b.attestations, + Deposits: b.deposits, + VoluntaryExits: b.voluntaryExits, + SyncAggregate: b.syncAggregate, + }, nil + case version.Bellatrix: + return ð.BeaconBlockBodyBellatrix{ + RandaoReveal: b.randaoReveal, + Eth1Data: b.eth1Data, + Graffiti: b.graffiti, + ProposerSlashings: b.proposerSlashings, + AttesterSlashings: b.attesterSlashings, + Attestations: b.attestations, + Deposits: b.deposits, + VoluntaryExits: b.voluntaryExits, + SyncAggregate: b.syncAggregate, + ExecutionPayload: b.executionPayload, + }, nil + case version.BellatrixBlind: + return ð.BlindedBeaconBlockBodyBellatrix{ + RandaoReveal: b.randaoReveal, + Eth1Data: b.eth1Data, + Graffiti: b.graffiti, + ProposerSlashings: b.proposerSlashings, + AttesterSlashings: b.attesterSlashings, + Attestations: b.attestations, + Deposits: b.deposits, + VoluntaryExits: b.voluntaryExits, + SyncAggregate: b.syncAggregate, + ExecutionPayloadHeader: b.executionPayloadHeader, + }, nil + default: + return nil, errors.New("unsupported beacon block body version") + } +} + +func initSignedBlockFromProtoPhase0(pb *eth.SignedBeaconBlock) (*SignedBeaconBlock, error) { + if pb == nil { + return nil, errNilBlock + } + + block, err := initBlockFromProtoPhase0(pb.Block) + if err != nil { + return nil, err + } + b := &SignedBeaconBlock{ + version: version.Phase0, + block: block, + signature: pb.Signature, + } + return b, nil +} + +func initSignedBlockFromProtoAltair(pb *eth.SignedBeaconBlockAltair) (*SignedBeaconBlock, error) { + if pb == nil { + return nil, errNilBlock + } + + block, err := initBlockFromProtoAltair(pb.Block) + if err != nil { + return nil, err + } + b := &SignedBeaconBlock{ + version: version.Altair, + block: block, + signature: pb.Signature, + } + return b, nil +} + +func initSignedBlockFromProtoBellatrix(pb *eth.SignedBeaconBlockBellatrix) (*SignedBeaconBlock, error) { + if pb == nil { + return nil, errNilBlock + } + + block, err := initBlockFromProtoBellatrix(pb.Block) + if err != nil { + return nil, err + } + b := &SignedBeaconBlock{ + version: version.Bellatrix, + block: block, + signature: pb.Signature, + } + return b, nil +} + +func initBlindedSignedBlockFromProtoBellatrix(pb *eth.SignedBlindedBeaconBlockBellatrix) (*SignedBeaconBlock, error) { + if pb == nil { + return nil, errNilBlock + } + + block, err := initBlindedBlockFromProtoBellatrix(pb.Block) + if err != nil { + return nil, err + } + b := &SignedBeaconBlock{ + version: version.BellatrixBlind, + block: block, + signature: pb.Signature, + } + return b, nil +} + +func initBlockFromProtoPhase0(pb *eth.BeaconBlock) (*BeaconBlock, error) { + if pb == nil { + return nil, errNilBlock + } + + body, err := initBlockBodyFromProtoPhase0(pb.Body) + if err != nil { + return nil, err + } + b := &BeaconBlock{ + version: version.Phase0, + slot: pb.Slot, + proposerIndex: pb.ProposerIndex, + parentRoot: pb.ParentRoot, + stateRoot: pb.StateRoot, + body: body, + } + return b, nil +} + +func initBlockFromProtoAltair(pb *eth.BeaconBlockAltair) (*BeaconBlock, error) { + if pb == nil { + return nil, errNilBlock + } + + body, err := initBlockBodyFromProtoAltair(pb.Body) + if err != nil { + return nil, err + } + b := &BeaconBlock{ + version: version.Altair, + slot: pb.Slot, + proposerIndex: pb.ProposerIndex, + parentRoot: pb.ParentRoot, + stateRoot: pb.StateRoot, + body: body, + } + return b, nil +} + +func initBlockFromProtoBellatrix(pb *eth.BeaconBlockBellatrix) (*BeaconBlock, error) { + if pb == nil { + return nil, errNilBlock + } + + body, err := initBlockBodyFromProtoBellatrix(pb.Body) + if err != nil { + return nil, err + } + b := &BeaconBlock{ + version: version.Bellatrix, + slot: pb.Slot, + proposerIndex: pb.ProposerIndex, + parentRoot: pb.ParentRoot, + stateRoot: pb.StateRoot, + body: body, + } + return b, nil +} + +func initBlindedBlockFromProtoBellatrix(pb *eth.BlindedBeaconBlockBellatrix) (*BeaconBlock, error) { + if pb == nil { + return nil, errNilBlock + } + + body, err := initBlindedBlockBodyFromProtoBellatrix(pb.Body) + if err != nil { + return nil, err + } + b := &BeaconBlock{ + version: version.BellatrixBlind, + slot: pb.Slot, + proposerIndex: pb.ProposerIndex, + parentRoot: pb.ParentRoot, + stateRoot: pb.StateRoot, + body: body, + } + return b, nil +} + +func initBlockBodyFromProtoPhase0(pb *eth.BeaconBlockBody) (*BeaconBlockBody, error) { + if pb == nil { + return nil, errNilBody + } + + b := &BeaconBlockBody{ + version: version.Phase0, + randaoReveal: pb.RandaoReveal, + eth1Data: pb.Eth1Data, + graffiti: pb.Graffiti, + proposerSlashings: pb.ProposerSlashings, + attesterSlashings: pb.AttesterSlashings, + attestations: pb.Attestations, + deposits: pb.Deposits, + voluntaryExits: pb.VoluntaryExits, + } + return b, nil +} + +func initBlockBodyFromProtoAltair(pb *eth.BeaconBlockBodyAltair) (*BeaconBlockBody, error) { + if pb == nil { + return nil, errNilBody + } + + b := &BeaconBlockBody{ + version: version.Altair, + randaoReveal: pb.RandaoReveal, + eth1Data: pb.Eth1Data, + graffiti: pb.Graffiti, + proposerSlashings: pb.ProposerSlashings, + attesterSlashings: pb.AttesterSlashings, + attestations: pb.Attestations, + deposits: pb.Deposits, + voluntaryExits: pb.VoluntaryExits, + syncAggregate: pb.SyncAggregate, + } + return b, nil +} + +func initBlockBodyFromProtoBellatrix(pb *eth.BeaconBlockBodyBellatrix) (*BeaconBlockBody, error) { + if pb == nil { + return nil, errNilBody + } + + b := &BeaconBlockBody{ + version: version.Bellatrix, + randaoReveal: pb.RandaoReveal, + eth1Data: pb.Eth1Data, + graffiti: pb.Graffiti, + proposerSlashings: pb.ProposerSlashings, + attesterSlashings: pb.AttesterSlashings, + attestations: pb.Attestations, + deposits: pb.Deposits, + voluntaryExits: pb.VoluntaryExits, + syncAggregate: pb.SyncAggregate, + executionPayload: pb.ExecutionPayload, + } + return b, nil +} + +func initBlindedBlockBodyFromProtoBellatrix(pb *eth.BlindedBeaconBlockBodyBellatrix) (*BeaconBlockBody, error) { + if pb == nil { + return nil, errNilBody + } + + b := &BeaconBlockBody{ + version: version.BellatrixBlind, + randaoReveal: pb.RandaoReveal, + eth1Data: pb.Eth1Data, + graffiti: pb.Graffiti, + proposerSlashings: pb.ProposerSlashings, + attesterSlashings: pb.AttesterSlashings, + attestations: pb.Attestations, + deposits: pb.Deposits, + voluntaryExits: pb.VoluntaryExits, + syncAggregate: pb.SyncAggregate, + executionPayloadHeader: pb.ExecutionPayloadHeader, + } + return b, nil +} diff --git a/consensus-types/blocks/proto_test.go b/consensus-types/blocks/proto_test.go new file mode 100644 index 0000000000..05ef91331d --- /dev/null +++ b/consensus-types/blocks/proto_test.go @@ -0,0 +1,871 @@ +package blocks + +import ( + "testing" + + "github.com/prysmaticlabs/go-bitfield" + enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1" + eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/runtime/version" + "github.com/prysmaticlabs/prysm/testing/assert" + "github.com/prysmaticlabs/prysm/testing/require" +) + +type fields struct { + b20 []byte + b32 []byte + b48 []byte + b96 []byte + b256 []byte + deposits []*eth.Deposit + atts []*eth.Attestation + proposerSlashings []*eth.ProposerSlashing + attesterSlashings []*eth.AttesterSlashing + voluntaryExits []*eth.SignedVoluntaryExit + syncAggregate *eth.SyncAggregate + execPayload *enginev1.ExecutionPayload + execPayloadHeader *eth.ExecutionPayloadHeader +} + +func Test_SignedBeaconBlock_Proto(t *testing.T) { + f := getFields() + + t.Run("Phase0", func(t *testing.T) { + expectedBlock := ð.SignedBeaconBlock{ + Block: ð.BeaconBlock{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbPhase0(), + }, + Signature: f.b96, + } + block := &SignedBeaconBlock{ + version: version.Phase0, + block: &BeaconBlock{ + version: version.Phase0, + slot: 128, + proposerIndex: 128, + parentRoot: f.b32, + stateRoot: f.b32, + body: bodyPhase0(), + }, + signature: f.b96, + } + + result, err := block.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.SignedBeaconBlock) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) + t.Run("Altair", func(t *testing.T) { + expectedBlock := ð.SignedBeaconBlockAltair{ + Block: ð.BeaconBlockAltair{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbAltair(), + }, + Signature: f.b96, + } + block := &SignedBeaconBlock{ + version: version.Altair, + block: &BeaconBlock{ + version: version.Altair, + slot: 128, + proposerIndex: 128, + parentRoot: f.b32, + stateRoot: f.b32, + body: bodyAltair(), + }, + signature: f.b96, + } + + result, err := block.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.SignedBeaconBlockAltair) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) + t.Run("Bellatrix", func(t *testing.T) { + expectedBlock := ð.SignedBeaconBlockBellatrix{ + Block: ð.BeaconBlockBellatrix{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbBellatrix(), + }, + Signature: f.b96, + } + block := &SignedBeaconBlock{ + version: version.Bellatrix, + block: &BeaconBlock{ + version: version.Bellatrix, + slot: 128, + proposerIndex: 128, + parentRoot: f.b32, + stateRoot: f.b32, + body: bodyBellatrix(), + }, + signature: f.b96, + } + + result, err := block.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.SignedBeaconBlockBellatrix) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) + t.Run("BellatrixBlind", func(t *testing.T) { + expectedBlock := ð.SignedBlindedBeaconBlockBellatrix{ + Block: ð.BlindedBeaconBlockBellatrix{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbBlindedBellatrix(), + }, + Signature: f.b96, + } + block := &SignedBeaconBlock{ + version: version.BellatrixBlind, + block: &BeaconBlock{ + version: version.BellatrixBlind, + slot: 128, + proposerIndex: 128, + parentRoot: f.b32, + stateRoot: f.b32, + body: bodyBlindedBellatrix(), + }, + signature: f.b96, + } + + result, err := block.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.SignedBlindedBeaconBlockBellatrix) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) +} + +func Test_BeaconBlock_Proto(t *testing.T) { + f := getFields() + + t.Run("Phase0", func(t *testing.T) { + expectedBlock := ð.BeaconBlock{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbPhase0(), + } + block := &BeaconBlock{ + version: version.Phase0, + slot: 128, + proposerIndex: 128, + parentRoot: f.b32, + stateRoot: f.b32, + body: bodyPhase0(), + } + + result, err := block.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.BeaconBlock) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) + t.Run("Altair", func(t *testing.T) { + expectedBlock := ð.BeaconBlockAltair{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbAltair(), + } + block := &BeaconBlock{ + version: version.Altair, + slot: 128, + proposerIndex: 128, + parentRoot: f.b32, + stateRoot: f.b32, + body: bodyAltair(), + } + + result, err := block.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.BeaconBlockAltair) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) + t.Run("Bellatrix", func(t *testing.T) { + expectedBlock := ð.BeaconBlockBellatrix{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbBellatrix(), + } + block := &BeaconBlock{ + version: version.Bellatrix, + slot: 128, + proposerIndex: 128, + parentRoot: f.b32, + stateRoot: f.b32, + body: bodyBellatrix(), + } + + result, err := block.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.BeaconBlockBellatrix) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) + t.Run("BellatrixBlind", func(t *testing.T) { + expectedBlock := ð.BlindedBeaconBlockBellatrix{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbBlindedBellatrix(), + } + block := &BeaconBlock{ + version: version.BellatrixBlind, + slot: 128, + proposerIndex: 128, + parentRoot: f.b32, + stateRoot: f.b32, + body: bodyBlindedBellatrix(), + } + + result, err := block.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.BlindedBeaconBlockBellatrix) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) +} + +func Test_BeaconBlockBody_Proto(t *testing.T) { + t.Run("Phase0", func(t *testing.T) { + expectedBody := bodyPbPhase0() + body := bodyPhase0() + + result, err := body.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.BeaconBlockBody) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBody.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) + t.Run("Altair", func(t *testing.T) { + expectedBody := bodyPbAltair() + body := bodyAltair() + result, err := body.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.BeaconBlockBodyAltair) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBody.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) + t.Run("Bellatrix", func(t *testing.T) { + expectedBody := bodyPbBellatrix() + body := bodyBellatrix() + result, err := body.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.BeaconBlockBodyBellatrix) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBody.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) + t.Run("BellatrixBlind", func(t *testing.T) { + expectedBody := bodyPbBlindedBellatrix() + body := bodyBlindedBellatrix() + result, err := body.Proto() + require.NoError(t, err) + resultBlock, ok := result.(*eth.BlindedBeaconBlockBodyBellatrix) + require.Equal(t, true, ok) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBody.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + }) +} + +func Test_initSignedBlockFromProtoPhase0(t *testing.T) { + f := getFields() + expectedBlock := ð.SignedBeaconBlock{ + Block: ð.BeaconBlock{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbPhase0(), + }, + Signature: f.b96, + } + resultBlock, err := initSignedBlockFromProtoPhase0(expectedBlock) + require.NoError(t, err) + resultHTR, err := resultBlock.block.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.Block.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + assert.DeepEqual(t, expectedBlock.Signature, resultBlock.signature) +} + +func Test_initSignedBlockFromProtoAltair(t *testing.T) { + f := getFields() + expectedBlock := ð.SignedBeaconBlockAltair{ + Block: ð.BeaconBlockAltair{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbAltair(), + }, + Signature: f.b96, + } + resultBlock, err := initSignedBlockFromProtoAltair(expectedBlock) + require.NoError(t, err) + resultHTR, err := resultBlock.block.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.Block.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + assert.DeepEqual(t, expectedBlock.Signature, resultBlock.signature) +} + +func Test_initSignedBlockFromProtoBellatrix(t *testing.T) { + f := getFields() + expectedBlock := ð.SignedBeaconBlockBellatrix{ + Block: ð.BeaconBlockBellatrix{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbBellatrix(), + }, + Signature: f.b96, + } + resultBlock, err := initSignedBlockFromProtoBellatrix(expectedBlock) + require.NoError(t, err) + resultHTR, err := resultBlock.block.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.Block.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + assert.DeepEqual(t, expectedBlock.Signature, resultBlock.signature) +} + +func Test_initBlindedSignedBlockFromProtoBellatrix(t *testing.T) { + f := getFields() + expectedBlock := ð.SignedBlindedBeaconBlockBellatrix{ + Block: ð.BlindedBeaconBlockBellatrix{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbBlindedBellatrix(), + }, + Signature: f.b96, + } + resultBlock, err := initBlindedSignedBlockFromProtoBellatrix(expectedBlock) + require.NoError(t, err) + resultHTR, err := resultBlock.block.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.Block.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) + assert.DeepEqual(t, expectedBlock.Signature, resultBlock.signature) +} + +func Test_initBlockFromProtoPhase0(t *testing.T) { + f := getFields() + expectedBlock := ð.BeaconBlock{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbPhase0(), + } + resultBlock, err := initBlockFromProtoPhase0(expectedBlock) + require.NoError(t, err) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) +} + +func Test_initBlockFromProtoAltair(t *testing.T) { + f := getFields() + expectedBlock := ð.BeaconBlockAltair{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbAltair(), + } + resultBlock, err := initBlockFromProtoAltair(expectedBlock) + require.NoError(t, err) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) +} + +func Test_initBlockFromProtoBellatrix(t *testing.T) { + f := getFields() + expectedBlock := ð.BeaconBlockBellatrix{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbBellatrix(), + } + resultBlock, err := initBlockFromProtoBellatrix(expectedBlock) + require.NoError(t, err) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) +} + +func Test_initBlockFromProtoBlindedBellatrix(t *testing.T) { + f := getFields() + expectedBlock := ð.BlindedBeaconBlockBellatrix{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: f.b32, + StateRoot: f.b32, + Body: bodyPbBlindedBellatrix(), + } + resultBlock, err := initBlindedBlockFromProtoBellatrix(expectedBlock) + require.NoError(t, err) + resultHTR, err := resultBlock.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBlock.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) +} + +func Test_initBlockBodyFromProtoPhase0(t *testing.T) { + expectedBody := bodyPbPhase0() + resultBody, err := initBlockBodyFromProtoPhase0(expectedBody) + require.NoError(t, err) + resultHTR, err := resultBody.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBody.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) +} + +func Test_initBlockBodyFromProtoAltair(t *testing.T) { + expectedBody := bodyPbAltair() + resultBody, err := initBlockBodyFromProtoAltair(expectedBody) + require.NoError(t, err) + resultHTR, err := resultBody.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBody.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) +} + +func Test_initBlockBodyFromProtoBellatrix(t *testing.T) { + expectedBody := bodyPbBellatrix() + resultBody, err := initBlockBodyFromProtoBellatrix(expectedBody) + require.NoError(t, err) + resultHTR, err := resultBody.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBody.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) +} + +func Test_initBlockBodyFromProtoBlindedBellatrix(t *testing.T) { + expectedBody := bodyPbBlindedBellatrix() + resultBody, err := initBlindedBlockBodyFromProtoBellatrix(expectedBody) + require.NoError(t, err) + resultHTR, err := resultBody.HashTreeRoot() + require.NoError(t, err) + expectedHTR, err := expectedBody.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHTR, resultHTR) +} + +func bodyPbPhase0() *eth.BeaconBlockBody { + f := getFields() + return ð.BeaconBlockBody{ + RandaoReveal: f.b96, + Eth1Data: ð.Eth1Data{ + DepositRoot: f.b32, + DepositCount: 128, + BlockHash: f.b32, + }, + Graffiti: f.b32, + ProposerSlashings: f.proposerSlashings, + AttesterSlashings: f.attesterSlashings, + Attestations: f.atts, + Deposits: f.deposits, + VoluntaryExits: f.voluntaryExits, + } +} + +func bodyPbAltair() *eth.BeaconBlockBodyAltair { + f := getFields() + return ð.BeaconBlockBodyAltair{ + RandaoReveal: f.b96, + Eth1Data: ð.Eth1Data{ + DepositRoot: f.b32, + DepositCount: 128, + BlockHash: f.b32, + }, + Graffiti: f.b32, + ProposerSlashings: f.proposerSlashings, + AttesterSlashings: f.attesterSlashings, + Attestations: f.atts, + Deposits: f.deposits, + VoluntaryExits: f.voluntaryExits, + SyncAggregate: f.syncAggregate, + } +} + +func bodyPbBellatrix() *eth.BeaconBlockBodyBellatrix { + f := getFields() + return ð.BeaconBlockBodyBellatrix{ + RandaoReveal: f.b96, + Eth1Data: ð.Eth1Data{ + DepositRoot: f.b32, + DepositCount: 128, + BlockHash: f.b32, + }, + Graffiti: f.b32, + ProposerSlashings: f.proposerSlashings, + AttesterSlashings: f.attesterSlashings, + Attestations: f.atts, + Deposits: f.deposits, + VoluntaryExits: f.voluntaryExits, + SyncAggregate: f.syncAggregate, + ExecutionPayload: f.execPayload, + } +} + +func bodyPbBlindedBellatrix() *eth.BlindedBeaconBlockBodyBellatrix { + f := getFields() + return ð.BlindedBeaconBlockBodyBellatrix{ + RandaoReveal: f.b96, + Eth1Data: ð.Eth1Data{ + DepositRoot: f.b32, + DepositCount: 128, + BlockHash: f.b32, + }, + Graffiti: f.b32, + ProposerSlashings: f.proposerSlashings, + AttesterSlashings: f.attesterSlashings, + Attestations: f.atts, + Deposits: f.deposits, + VoluntaryExits: f.voluntaryExits, + SyncAggregate: f.syncAggregate, + ExecutionPayloadHeader: f.execPayloadHeader, + } +} + +func bodyPhase0() *BeaconBlockBody { + f := getFields() + return &BeaconBlockBody{ + version: version.Phase0, + randaoReveal: f.b96, + eth1Data: ð.Eth1Data{ + DepositRoot: f.b32, + DepositCount: 128, + BlockHash: f.b32, + }, + graffiti: f.b32, + proposerSlashings: f.proposerSlashings, + attesterSlashings: f.attesterSlashings, + attestations: f.atts, + deposits: f.deposits, + voluntaryExits: f.voluntaryExits, + } +} + +func bodyAltair() *BeaconBlockBody { + f := getFields() + return &BeaconBlockBody{ + version: version.Altair, + randaoReveal: f.b96, + eth1Data: ð.Eth1Data{ + DepositRoot: f.b32, + DepositCount: 128, + BlockHash: f.b32, + }, + graffiti: f.b32, + proposerSlashings: f.proposerSlashings, + attesterSlashings: f.attesterSlashings, + attestations: f.atts, + deposits: f.deposits, + voluntaryExits: f.voluntaryExits, + syncAggregate: f.syncAggregate, + } +} + +func bodyBellatrix() *BeaconBlockBody { + f := getFields() + return &BeaconBlockBody{ + version: version.Bellatrix, + randaoReveal: f.b96, + eth1Data: ð.Eth1Data{ + DepositRoot: f.b32, + DepositCount: 128, + BlockHash: f.b32, + }, + graffiti: f.b32, + proposerSlashings: f.proposerSlashings, + attesterSlashings: f.attesterSlashings, + attestations: f.atts, + deposits: f.deposits, + voluntaryExits: f.voluntaryExits, + syncAggregate: f.syncAggregate, + executionPayload: f.execPayload, + } +} + +func bodyBlindedBellatrix() *BeaconBlockBody { + f := getFields() + return &BeaconBlockBody{ + version: version.BellatrixBlind, + randaoReveal: f.b96, + eth1Data: ð.Eth1Data{ + DepositRoot: f.b32, + DepositCount: 128, + BlockHash: f.b32, + }, + graffiti: f.b32, + proposerSlashings: f.proposerSlashings, + attesterSlashings: f.attesterSlashings, + attestations: f.atts, + deposits: f.deposits, + voluntaryExits: f.voluntaryExits, + syncAggregate: f.syncAggregate, + executionPayloadHeader: f.execPayloadHeader, + } +} + +func getFields() fields { + b20 := make([]byte, 20) + b32 := make([]byte, 32) + b48 := make([]byte, 48) + b96 := make([]byte, 96) + b256 := make([]byte, 256) + b20[0], b20[5], b20[10] = 'q', 'u', 'x' + b32[0], b32[5], b32[10] = 'f', 'o', 'o' + b48[0], b48[5], b48[10] = 'b', 'a', 'r' + b96[0], b96[5], b96[10] = 'b', 'a', 'z' + b256[0], b256[5], b256[10] = 'x', 'y', 'z' + deposits := make([]*eth.Deposit, 16) + for i := range deposits { + deposits[i] = ð.Deposit{} + deposits[i].Proof = make([][]byte, 33) + for j := range deposits[i].Proof { + deposits[i].Proof[j] = b32 + } + deposits[i].Data = ð.Deposit_Data{ + PublicKey: b48, + WithdrawalCredentials: b32, + Amount: 128, + Signature: b96, + } + } + atts := make([]*eth.Attestation, 128) + for i := range atts { + atts[i] = ð.Attestation{} + atts[i].Signature = b96 + atts[i].AggregationBits = bitfield.NewBitlist(1) + atts[i].Data = ð.AttestationData{ + Slot: 128, + CommitteeIndex: 128, + BeaconBlockRoot: b32, + Source: ð.Checkpoint{ + Epoch: 128, + Root: b32, + }, + Target: ð.Checkpoint{ + Epoch: 128, + Root: b32, + }, + } + } + proposerSlashing := ð.ProposerSlashing{ + Header_1: ð.SignedBeaconBlockHeader{ + Header: ð.BeaconBlockHeader{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: b32, + StateRoot: b32, + BodyRoot: b32, + }, + Signature: b96, + }, + Header_2: ð.SignedBeaconBlockHeader{ + Header: ð.BeaconBlockHeader{ + Slot: 128, + ProposerIndex: 128, + ParentRoot: b32, + StateRoot: b32, + BodyRoot: b32, + }, + Signature: b96, + }, + } + attesterSlashing := ð.AttesterSlashing{ + Attestation_1: ð.IndexedAttestation{ + AttestingIndices: []uint64{1, 2, 8}, + Data: ð.AttestationData{ + Slot: 128, + CommitteeIndex: 128, + BeaconBlockRoot: b32, + Source: ð.Checkpoint{ + Epoch: 128, + Root: b32, + }, + Target: ð.Checkpoint{ + Epoch: 128, + Root: b32, + }, + }, + Signature: b96, + }, + Attestation_2: ð.IndexedAttestation{ + AttestingIndices: []uint64{1, 2, 8}, + Data: ð.AttestationData{ + Slot: 128, + CommitteeIndex: 128, + BeaconBlockRoot: b32, + Source: ð.Checkpoint{ + Epoch: 128, + Root: b32, + }, + Target: ð.Checkpoint{ + Epoch: 128, + Root: b32, + }, + }, + Signature: b96, + }, + } + voluntaryExit := ð.SignedVoluntaryExit{ + Exit: ð.VoluntaryExit{ + Epoch: 128, + ValidatorIndex: 128, + }, + Signature: b96, + } + syncCommitteeBits := bitfield.NewBitvector512() + syncCommitteeBits.SetBitAt(1, true) + syncCommitteeBits.SetBitAt(2, true) + syncCommitteeBits.SetBitAt(8, true) + syncAggregate := ð.SyncAggregate{ + SyncCommitteeBits: syncCommitteeBits, + SyncCommitteeSignature: b96, + } + execPayload := &enginev1.ExecutionPayload{ + ParentHash: b32, + FeeRecipient: b20, + StateRoot: b32, + ReceiptsRoot: b32, + LogsBloom: b256, + PrevRandao: b32, + BlockNumber: 128, + GasLimit: 128, + GasUsed: 128, + Timestamp: 128, + ExtraData: b32, + BaseFeePerGas: b32, + BlockHash: b32, + Transactions: [][]byte{ + []byte("transaction1"), + []byte("transaction2"), + []byte("transaction8"), + }, + } + execPayloadHeader := ð.ExecutionPayloadHeader{ + ParentHash: b32, + FeeRecipient: b20, + StateRoot: b32, + ReceiptsRoot: b32, + LogsBloom: b256, + PrevRandao: b32, + BlockNumber: 128, + GasLimit: 128, + GasUsed: 128, + Timestamp: 128, + ExtraData: b32, + BaseFeePerGas: b32, + BlockHash: b32, + TransactionsRoot: b32, + } + + return fields{ + b20: b20, + b32: b32, + b48: b48, + b96: b96, + b256: b256, + deposits: deposits, + atts: atts, + proposerSlashings: []*eth.ProposerSlashing{proposerSlashing}, + attesterSlashings: []*eth.AttesterSlashing{attesterSlashing}, + voluntaryExits: []*eth.SignedVoluntaryExit{voluntaryExit}, + syncAggregate: syncAggregate, + execPayload: execPayload, + execPayloadHeader: execPayloadHeader, + } +} diff --git a/consensus-types/blocks/testing/BUILD.bazel b/consensus-types/blocks/testing/BUILD.bazel new file mode 100644 index 0000000000..320cfc1688 --- /dev/null +++ b/consensus-types/blocks/testing/BUILD.bazel @@ -0,0 +1,20 @@ +load("@prysm//tools/go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + testonly = True, + srcs = [ + "factory.go", + "mutator.go", + ], + importpath = "github.com/prysmaticlabs/prysm/consensus-types/blocks/testing", + visibility = ["//visibility:public"], + deps = [ + "//consensus-types/blocks:go_default_library", + "//consensus-types/interfaces:go_default_library", + "//consensus-types/primitives:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + "//runtime/version:go_default_library", + "@com_github_pkg_errors//:go_default_library", + ], +) diff --git a/consensus-types/blocks/testing/factory.go b/consensus-types/blocks/testing/factory.go new file mode 100644 index 0000000000..98e4400601 --- /dev/null +++ b/consensus-types/blocks/testing/factory.go @@ -0,0 +1,27 @@ +package testing + +import ( + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/consensus-types/blocks" + eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" +) + +// NewSignedBeaconBlockFromGeneric creates a signed beacon block +// from a protobuf generic signed beacon block. +func NewSignedBeaconBlockFromGeneric(gb *eth.GenericSignedBeaconBlock) (*blocks.SignedBeaconBlock, error) { + if gb == nil { + return nil, blocks.ErrNilObjectWrapped + } + switch bb := gb.Block.(type) { + case *eth.GenericSignedBeaconBlock_Phase0: + return blocks.NewSignedBeaconBlock(bb.Phase0) + case *eth.GenericSignedBeaconBlock_Altair: + return blocks.NewSignedBeaconBlock(bb.Altair) + case *eth.GenericSignedBeaconBlock_Bellatrix: + return blocks.NewSignedBeaconBlock(bb.Bellatrix) + case *eth.GenericSignedBeaconBlock_BlindedBellatrix: + return blocks.NewSignedBeaconBlock(bb.BlindedBellatrix) + default: + return nil, errors.Wrapf(blocks.ErrUnsupportedSignedBeaconBlock, "unable to create block from type %T", gb) + } +} diff --git a/consensus-types/blocks/testing/mutator.go b/consensus-types/blocks/testing/mutator.go new file mode 100644 index 0000000000..904fab2ed5 --- /dev/null +++ b/consensus-types/blocks/testing/mutator.go @@ -0,0 +1,79 @@ +package testing + +import ( + "github.com/prysmaticlabs/prysm/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/consensus-types/interfaces" + types "github.com/prysmaticlabs/prysm/consensus-types/primitives" + eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/runtime/version" +) + +type blockMutator struct { + Phase0 func(beaconBlock *eth.SignedBeaconBlock) + Altair func(beaconBlock *eth.SignedBeaconBlockAltair) + Bellatrix func(beaconBlock *eth.SignedBeaconBlockBellatrix) +} + +func (m blockMutator) apply(b interfaces.SignedBeaconBlock) error { + switch b.Version() { + case version.Phase0: + bb, err := b.PbPhase0Block() + if err != nil { + return err + } + m.Phase0(bb) + return nil + case version.Altair: + bb, err := b.PbAltairBlock() + if err != nil { + return err + } + m.Altair(bb) + return nil + case version.Bellatrix: + bb, err := b.PbBellatrixBlock() + if err != nil { + return err + } + m.Bellatrix(bb) + return nil + default: + return blocks.ErrUnsupportedSignedBeaconBlock + } +} + +// SetBlockStateRoot modifies the block's state root. +func SetBlockStateRoot(b interfaces.SignedBeaconBlock, sr [32]byte) error { + return blockMutator{ + Phase0: func(bb *eth.SignedBeaconBlock) { bb.Block.StateRoot = sr[:] }, + Altair: func(bb *eth.SignedBeaconBlockAltair) { bb.Block.StateRoot = sr[:] }, + Bellatrix: func(bb *eth.SignedBeaconBlockBellatrix) { bb.Block.StateRoot = sr[:] }, + }.apply(b) +} + +// SetBlockParentRoot modifies the block's parent root. +func SetBlockParentRoot(b interfaces.SignedBeaconBlock, pr [32]byte) error { + return blockMutator{ + Phase0: func(bb *eth.SignedBeaconBlock) { bb.Block.ParentRoot = pr[:] }, + Altair: func(bb *eth.SignedBeaconBlockAltair) { bb.Block.ParentRoot = pr[:] }, + Bellatrix: func(bb *eth.SignedBeaconBlockBellatrix) { bb.Block.ParentRoot = pr[:] }, + }.apply(b) +} + +// SetBlockSlot modifies the block's slot. +func SetBlockSlot(b interfaces.SignedBeaconBlock, s types.Slot) error { + return blockMutator{ + Phase0: func(bb *eth.SignedBeaconBlock) { bb.Block.Slot = s }, + Altair: func(bb *eth.SignedBeaconBlockAltair) { bb.Block.Slot = s }, + Bellatrix: func(bb *eth.SignedBeaconBlockBellatrix) { bb.Block.Slot = s }, + }.apply(b) +} + +// SetProposerIndex modifies the block's proposer index. +func SetProposerIndex(b interfaces.SignedBeaconBlock, idx types.ValidatorIndex) error { + return blockMutator{ + Phase0: func(bb *eth.SignedBeaconBlock) { bb.Block.ProposerIndex = idx }, + Altair: func(bb *eth.SignedBeaconBlockAltair) { bb.Block.ProposerIndex = idx }, + Bellatrix: func(bb *eth.SignedBeaconBlockBellatrix) { bb.Block.ProposerIndex = idx }, + }.apply(b) +} diff --git a/consensus-types/blocks/types.go b/consensus-types/blocks/types.go new file mode 100644 index 0000000000..aad810e10b --- /dev/null +++ b/consensus-types/blocks/types.go @@ -0,0 +1,62 @@ +package blocks + +import ( + "fmt" + + "github.com/pkg/errors" + types "github.com/prysmaticlabs/prysm/consensus-types/primitives" + engine "github.com/prysmaticlabs/prysm/proto/engine/v1" + eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/runtime/version" +) + +const ( + incorrectBlockVersion = "incorrect beacon block version" + incorrectBodyVersion = "incorrect beacon block body version" +) + +var ( + // ErrUnsupportedGetter is returned when a getter access is not supported for a specific beacon block version. + ErrUnsupportedGetter = errors.New("unsupported getter") + errNilBlock = errors.New("received nil beacon block") + errNilBody = errors.New("received nil beacon block body") + errIncorrectBlockVersion = errors.New(incorrectBlockVersion) + errIncorrectBodyVersion = errors.New(incorrectBodyVersion) +) + +// BeaconBlockBody is the main beacon block body structure. It can represent any block type. +type BeaconBlockBody struct { + version int + randaoReveal []byte + eth1Data *eth.Eth1Data + graffiti []byte + proposerSlashings []*eth.ProposerSlashing + attesterSlashings []*eth.AttesterSlashing + attestations []*eth.Attestation + deposits []*eth.Deposit + voluntaryExits []*eth.SignedVoluntaryExit + syncAggregate *eth.SyncAggregate + executionPayload *engine.ExecutionPayload + executionPayloadHeader *eth.ExecutionPayloadHeader +} + +// BeaconBlock is the main beacon block structure. It can represent any block type. +type BeaconBlock struct { + version int + slot types.Slot + proposerIndex types.ValidatorIndex + parentRoot []byte + stateRoot []byte + body *BeaconBlockBody +} + +// SignedBeaconBlock is the main signed beacon block structure. It can represent any block type. +type SignedBeaconBlock struct { + version int + block *BeaconBlock + signature []byte +} + +func errNotSupported(funcName string, ver int) error { + return errors.Wrap(ErrUnsupportedGetter, fmt.Sprintf("%s is not supported for %s", funcName, version.String(ver))) +}