mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 13:28:01 -05:00
use VersionedUnmarshaller
This commit is contained in:
@@ -44,6 +44,7 @@ go_library(
|
||||
"//consensus-types/wrapper:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//encoding/ssz/detect:go_default_library",
|
||||
"//network/forks:go_default_library",
|
||||
"//proto/eth/v1:go_default_library",
|
||||
"//proto/eth/v2:go_default_library",
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/pkg/errors"
|
||||
@@ -19,6 +18,8 @@ import (
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/encoding/ssz/detect"
|
||||
"github.com/prysmaticlabs/prysm/network/forks"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
|
||||
ethpbv2 "github.com/prysmaticlabs/prysm/proto/eth/v2"
|
||||
"github.com/prysmaticlabs/prysm/proto/migration"
|
||||
@@ -244,56 +245,24 @@ func (bs *Server) SubmitBlockSSZ(ctx context.Context, req *ethpbv2.SignedBeaconB
|
||||
if len(ver) == 0 {
|
||||
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not read eth-consensus-version header")
|
||||
}
|
||||
|
||||
switch strings.ToLower(ver[0]) {
|
||||
case strings.ToLower(ethpbv2.Version_PHASE0.String()):
|
||||
block := ðpbv1.SignedBeaconBlock{}
|
||||
if err := block.UnmarshalSSZ(req.Data); err != nil {
|
||||
return &emptypb.Empty{},
|
||||
status.Errorf(
|
||||
codes.InvalidArgument,
|
||||
"could not unmarshal data into %s block: %v",
|
||||
strings.ToLower(ethpbv2.Version_PHASE0.String()),
|
||||
err,
|
||||
)
|
||||
}
|
||||
if err := bs.submitPhase0Block(ctx, block.Block, block.Signature); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case strings.ToLower(ethpbv2.Version_ALTAIR.String()):
|
||||
block := ðpbv2.SignedBeaconBlockAltair{}
|
||||
if err := block.UnmarshalSSZ(req.Data); err != nil {
|
||||
return &emptypb.Empty{},
|
||||
status.Errorf(
|
||||
codes.InvalidArgument,
|
||||
"could not unmarshal data into %s block: %v",
|
||||
strings.ToLower(ethpbv2.Version_ALTAIR.String()),
|
||||
err,
|
||||
)
|
||||
}
|
||||
if err := bs.submitAltairBlock(ctx, block.Message, block.Signature); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case strings.ToLower(ethpbv2.Version_BELLATRIX.String()):
|
||||
block := ðpbv2.SignedBeaconBlockBellatrix{}
|
||||
if err := block.UnmarshalSSZ(req.Data); err != nil {
|
||||
return &emptypb.Empty{},
|
||||
status.Errorf(
|
||||
codes.InvalidArgument,
|
||||
"could not unmarshal data into %s block: %v",
|
||||
strings.ToLower(ethpbv2.Version_BELLATRIX.String()),
|
||||
err,
|
||||
)
|
||||
}
|
||||
if err := bs.submitBellatrixBlock(ctx, block.Message, block.Signature); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return &emptypb.Empty{}, status.Errorf(codes.InvalidArgument, "Unsupported Eth-Consensus-Version %s", ver)
|
||||
|
||||
schedule := forks.NewOrderedSchedule(params.BeaconConfig())
|
||||
forkVer, err := schedule.VersionForName(ver[0])
|
||||
if err != nil {
|
||||
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not determine fork version: %v", err)
|
||||
}
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
unmarshaler, err := detect.FromForkVersion(forkVer)
|
||||
if err != nil {
|
||||
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not create unmarshaler: %v", err)
|
||||
}
|
||||
block, err := unmarshaler.UnmarshalBeaconBlock(req.Data)
|
||||
if err != nil {
|
||||
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not unmarshal request data into block: %v", err)
|
||||
}
|
||||
root, err := block.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not compute block's hash tree root: %v", err)
|
||||
}
|
||||
return &emptypb.Empty{}, bs.submitBlock(ctx, root, block)
|
||||
}
|
||||
|
||||
// SubmitBlindedBlock instructs the beacon node to use the components of the `SignedBlindedBeaconBlock` to construct
|
||||
|
||||
@@ -144,6 +144,7 @@ type BeaconChainConfig struct {
|
||||
ShardingForkVersion []byte `yaml:"SHARDING_FORK_VERSION" spec:"true"` // ShardingForkVersion is used to represent the fork version for sharding.
|
||||
ShardingForkEpoch types.Epoch `yaml:"SHARDING_FORK_EPOCH" spec:"true"` // ShardingForkEpoch is used to represent the assigned fork epoch for sharding.
|
||||
ForkVersionSchedule map[[fieldparams.VersionLength]byte]types.Epoch // Schedule of fork epochs by version.
|
||||
ForkVersionNames map[[fieldparams.VersionLength]byte]string // Human-readable names of fork versions.
|
||||
|
||||
// Weak subjectivity values.
|
||||
SafetyDecay uint64 // SafetyDecay is defined as the loss in the 1/3 consensus safety margin of the casper FFG mechanism.
|
||||
@@ -195,6 +196,7 @@ type BeaconChainConfig struct {
|
||||
func (b *BeaconChainConfig) InitializeForkSchedule() {
|
||||
// Reset Fork Version Schedule.
|
||||
b.ForkVersionSchedule = configForkSchedule(b)
|
||||
b.ForkVersionNames = configForkNames(b)
|
||||
}
|
||||
|
||||
func configForkSchedule(b *BeaconChainConfig) map[[fieldparams.VersionLength]byte]types.Epoch {
|
||||
@@ -207,3 +209,14 @@ func configForkSchedule(b *BeaconChainConfig) map[[fieldparams.VersionLength]byt
|
||||
fvs[bytesutil.ToBytes4(b.BellatrixForkVersion)] = b.BellatrixForkEpoch
|
||||
return fvs
|
||||
}
|
||||
|
||||
func configForkNames(b *BeaconChainConfig) map[[fieldparams.VersionLength]byte]string {
|
||||
fvn := map[[fieldparams.VersionLength]byte]string{}
|
||||
// Set Genesis fork data.
|
||||
fvn[bytesutil.ToBytes4(b.GenesisForkVersion)] = "phase0"
|
||||
// Set Altair fork data.
|
||||
fvn[bytesutil.ToBytes4(b.AltairForkVersion)] = "altair"
|
||||
// Set Bellatrix fork data.
|
||||
fvn[bytesutil.ToBytes4(b.BellatrixForkVersion)] = "bellatrix"
|
||||
return fvn
|
||||
}
|
||||
|
||||
@@ -128,7 +128,10 @@ var beaconBlockSlot = fieldSpec{
|
||||
t: typeUint64,
|
||||
}
|
||||
|
||||
func slotFromBlock(marshaled []byte) (types.Slot, error) {
|
||||
// SlotFromBlock exploits the fixed-size lower-order bytes in a beacon block
|
||||
// as a heuristic to obtain the value of the block.slot field without first
|
||||
// unmarshaling the block.
|
||||
func SlotFromBlock(marshaled []byte) (types.Slot, error) {
|
||||
slot, err := beaconBlockSlot.uint64(marshaled)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -136,12 +139,12 @@ func slotFromBlock(marshaled []byte) (types.Slot, error) {
|
||||
return types.Slot(slot), nil
|
||||
}
|
||||
|
||||
var errBlockForkMismatch = errors.New("fork or config detected from state is different than block")
|
||||
var errBlockForkMismatch = errors.New("fork or config detected in unmarshaler is different than block")
|
||||
|
||||
// UnmarshalBeaconBlock uses internal knowledge in the VersionedUnmarshaler to pick the right concrete SignedBeaconBlock type,
|
||||
// then Unmarshal()s the type and returns an instance of block.SignedBeaconBlock if successful.
|
||||
func (cf *VersionedUnmarshaler) UnmarshalBeaconBlock(marshaled []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
slot, err := slotFromBlock(marshaled)
|
||||
slot, err := SlotFromBlock(marshaled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestSlotFromBlock(t *testing.T) {
|
||||
b.Block.Slot = slot
|
||||
bb, err := b.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
sfb, err := slotFromBlock(bb)
|
||||
sfb, err := SlotFromBlock(bb)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, slot, sfb)
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestSlotFromBlock(t *testing.T) {
|
||||
ba.Block.Slot = slot
|
||||
bab, err := ba.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
sfba, err := slotFromBlock(bab)
|
||||
sfba, err := SlotFromBlock(bab)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, slot, sfba)
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestSlotFromBlock(t *testing.T) {
|
||||
bm.Block.Slot = slot
|
||||
bmb, err := ba.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
sfbm, err := slotFromBlock(bmb)
|
||||
sfbm, err := SlotFromBlock(bmb)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, slot, sfbm)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package forks
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
@@ -13,10 +14,11 @@ import (
|
||||
type ForkScheduleEntry struct {
|
||||
Version [fieldparams.VersionLength]byte
|
||||
Epoch types.Epoch
|
||||
Name string
|
||||
}
|
||||
|
||||
// OrderedSchedule provides a type that can be used to sort the fork schedule and find the Version
|
||||
// the chain should be at for a given epoch (via VersionForEpoch).
|
||||
// the chain should be at for a given epoch (via VersionForEpoch) or name (via VersionForName).
|
||||
type OrderedSchedule []ForkScheduleEntry
|
||||
|
||||
// Len implements the Len method of sort.Interface
|
||||
@@ -38,6 +40,17 @@ func (o OrderedSchedule) VersionForEpoch(epoch types.Epoch) ([fieldparams.Versio
|
||||
return [fieldparams.VersionLength]byte{}, errors.Wrapf(ErrVersionNotFound, "no epoch in list <= %d", epoch)
|
||||
}
|
||||
|
||||
// VersionForName finds the Version corresponding to the lowercase version of the provided name.
|
||||
func (o OrderedSchedule) VersionForName(name string) ([fieldparams.VersionLength]byte, error) {
|
||||
lower := strings.ToLower(name)
|
||||
for _, e := range o {
|
||||
if e.Name == lower {
|
||||
return e.Version, nil
|
||||
}
|
||||
}
|
||||
return [4]byte{}, errors.Wrapf(ErrVersionNotFound, "no version with name %s", lower)
|
||||
}
|
||||
|
||||
func (o OrderedSchedule) Previous(version [fieldparams.VersionLength]byte) ([fieldparams.VersionLength]byte, error) {
|
||||
for i := len(o) - 1; i >= 0; i-- {
|
||||
if o[i].Version == version {
|
||||
@@ -51,7 +64,7 @@ func (o OrderedSchedule) Previous(version [fieldparams.VersionLength]byte) ([fie
|
||||
return [fieldparams.VersionLength]byte{}, errors.Wrapf(ErrVersionNotFound, "no version in list == %#x", version)
|
||||
}
|
||||
|
||||
// Converts the ForkVersionSchedule map into a list of Version+Epoch values, ordered by Epoch from lowest to highest.
|
||||
// NewOrderedSchedule Converts fork version maps into a list of Version+Epoch+Name values, ordered by Epoch from lowest to highest.
|
||||
// See docs for OrderedSchedule for more detail on what you can do with this type.
|
||||
func NewOrderedSchedule(b *params.BeaconChainConfig) OrderedSchedule {
|
||||
ofs := make(OrderedSchedule, 0)
|
||||
@@ -59,6 +72,7 @@ func NewOrderedSchedule(b *params.BeaconChainConfig) OrderedSchedule {
|
||||
fse := ForkScheduleEntry{
|
||||
Version: version,
|
||||
Epoch: epoch,
|
||||
Name: b.ForkVersionNames[version],
|
||||
}
|
||||
ofs = append(ofs, fse)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestOrderedConfigSchedule(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
bc := testForkVersionScheduleBCC()
|
||||
bc := testForkVersionBCC()
|
||||
ofs := NewOrderedSchedule(bc)
|
||||
for i := range ofs {
|
||||
if ofs[i].Epoch != types.Epoch(math.Pow(2, float64(i))) {
|
||||
@@ -45,7 +45,7 @@ func TestOrderedConfigSchedule(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestVersionForEpoch(t *testing.T) {
|
||||
bc := testForkVersionScheduleBCC()
|
||||
bc := testForkVersionBCC()
|
||||
ofs := NewOrderedSchedule(bc)
|
||||
testCases := []struct {
|
||||
name string
|
||||
@@ -92,7 +92,45 @@ func TestVersionForEpoch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testForkVersionScheduleBCC() *params.BeaconChainConfig {
|
||||
func TestVersionForName(t *testing.T) {
|
||||
bc := testForkVersionBCC()
|
||||
ofs := NewOrderedSchedule(bc)
|
||||
testCases := []struct {
|
||||
testName string
|
||||
version [4]byte
|
||||
versionName string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
testName: "found",
|
||||
version: [4]byte{2, 1, 2, 3},
|
||||
versionName: "third",
|
||||
},
|
||||
{
|
||||
testName: "found lowercase",
|
||||
version: [4]byte{4, 1, 2, 3},
|
||||
versionName: "FiFtH",
|
||||
},
|
||||
{
|
||||
testName: "not found",
|
||||
versionName: "nonexistent",
|
||||
err: ErrVersionNotFound,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
v, err := ofs.VersionForName(tc.versionName)
|
||||
if tc.err == nil {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.ErrorIs(t, err, tc.err)
|
||||
}
|
||||
require.Equal(t, tc.version, v)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testForkVersionBCC() *params.BeaconChainConfig {
|
||||
return ¶ms.BeaconChainConfig{
|
||||
ForkVersionSchedule: map[[4]byte]types.Epoch{
|
||||
{1, 1, 2, 3}: types.Epoch(2),
|
||||
@@ -101,11 +139,18 @@ func testForkVersionScheduleBCC() *params.BeaconChainConfig {
|
||||
{3, 1, 2, 3}: types.Epoch(8),
|
||||
{2, 1, 2, 3}: types.Epoch(4),
|
||||
},
|
||||
ForkVersionNames: map[[4]byte]string{
|
||||
{1, 1, 2, 3}: "second",
|
||||
{0, 1, 2, 3}: "first",
|
||||
{4, 1, 2, 3}: "fifth",
|
||||
{3, 1, 2, 3}: "fourth",
|
||||
{2, 1, 2, 3}: "third",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrevious(t *testing.T) {
|
||||
cfg := testForkVersionScheduleBCC()
|
||||
cfg := testForkVersionBCC()
|
||||
os := NewOrderedSchedule(cfg)
|
||||
unreal := [4]byte{255, 255, 255, 255}
|
||||
_, err := os.Previous(unreal)
|
||||
|
||||
Reference in New Issue
Block a user