From 946d4661ad91d16bb558c9bab3efe67f2dc8ca24 Mon Sep 17 00:00:00 2001 From: nisdas Date: Thu, 18 Jan 2024 21:50:29 +0800 Subject: [PATCH] add all this in --- encoding/ssz/detect/configfork.go | 21 +++++- encoding/ssz/detect/configfork_test.go | 91 ++++++++++++++++++++++++++ tools/pcli/BUILD.bazel | 4 ++ tools/pcli/main.go | 61 +++++++++++------ 4 files changed, 156 insertions(+), 21 deletions(-) diff --git a/encoding/ssz/detect/configfork.go b/encoding/ssz/detect/configfork.go index 79f48fea4197..3238bc86b3d5 100644 --- a/encoding/ssz/detect/configfork.go +++ b/encoding/ssz/detect/configfork.go @@ -49,6 +49,23 @@ func FromState(marshaled []byte) (*VersionedUnmarshaler, error) { return FromForkVersion(cv) } +// FromBlock uses the known size of an offset and signature to determine the slot of a block without unmarshalling it. +// The slot is used to determine the version along with the respective config. +func FromBlock(marshaled []byte) (*VersionedUnmarshaler, error) { + slot, err := slotFromBlock(marshaled) + if err != nil { + return nil, err + } + copiedCfg := params.BeaconConfig().Copy() + epoch := slots.ToEpoch(slot) + fs := forks.NewOrderedSchedule(copiedCfg) + ver, err := fs.VersionForEpoch(epoch) + if err != nil { + return nil, err + } + return FromForkVersion(ver) +} + var ErrForkNotFound = errors.New("version found in fork schedule but can't be matched to a named fork") // FromForkVersion uses a lookup table to resolve a Version (from a beacon node api for instance, or obtained by peeking at @@ -162,7 +179,7 @@ var errBlockForkMismatch = errors.New("fork or config detected in unmarshaler is // UnmarshalBeaconBlock uses internal knowledge in the VersionedUnmarshaler to pick the right concrete ReadOnlySignedBeaconBlock type, // then Unmarshal()s the type and returns an instance of block.ReadOnlySignedBeaconBlock if successful. -func (cf *VersionedUnmarshaler) UnmarshalBeaconBlock(marshaled []byte) (interfaces.ReadOnlySignedBeaconBlock, error) { +func (cf *VersionedUnmarshaler) UnmarshalBeaconBlock(marshaled []byte) (interfaces.SignedBeaconBlock, error) { slot, err := slotFromBlock(marshaled) if err != nil { return nil, err @@ -197,7 +214,7 @@ func (cf *VersionedUnmarshaler) UnmarshalBeaconBlock(marshaled []byte) (interfac // UnmarshalBlindedBeaconBlock uses internal knowledge in the VersionedUnmarshaler to pick the right concrete blinded ReadOnlySignedBeaconBlock type, // then Unmarshal()s the type and returns an instance of block.ReadOnlySignedBeaconBlock if successful. // For Phase0 and Altair it works exactly line UnmarshalBeaconBlock. -func (cf *VersionedUnmarshaler) UnmarshalBlindedBeaconBlock(marshaled []byte) (interfaces.ReadOnlySignedBeaconBlock, error) { +func (cf *VersionedUnmarshaler) UnmarshalBlindedBeaconBlock(marshaled []byte) (interfaces.SignedBeaconBlock, error) { slot, err := slotFromBlock(marshaled) if err != nil { return nil, err diff --git a/encoding/ssz/detect/configfork_test.go b/encoding/ssz/detect/configfork_test.go index 6f3c4f4dd851..e0d13079d72f 100644 --- a/encoding/ssz/detect/configfork_test.go +++ b/encoding/ssz/detect/configfork_test.go @@ -204,6 +204,97 @@ func TestUnmarshalState(t *testing.T) { } } +func TestDetectAndUnmarshalBlock(t *testing.T) { + undo := util.HackDenebMaxuint(t) + defer undo() + altairS, err := slots.EpochStart(params.BeaconConfig().AltairForkEpoch) + require.NoError(t, err) + bellaS, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch) + require.NoError(t, err) + capellaS, err := slots.EpochStart(params.BeaconConfig().CapellaForkEpoch) + require.NoError(t, err) + denebS, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch) + require.NoError(t, err) + cases := []struct { + b func(*testing.T, primitives.Slot) interfaces.ReadOnlySignedBeaconBlock + name string + slot primitives.Slot + errExists bool + }{ + { + name: "genesis - slot 0", + b: signedTestBlockGenesis, + }, + { + name: "last slot of phase 0", + b: signedTestBlockGenesis, + slot: altairS - 1, + }, + { + name: "first slot of altair", + b: signedTestBlockAltair, + slot: altairS, + }, + { + name: "last slot of altair", + b: signedTestBlockAltair, + slot: bellaS - 1, + }, + { + name: "first slot of bellatrix", + b: signedTestBlockBellatrix, + slot: bellaS, + }, + { + name: "first slot of capella", + b: signedTestBlockCapella, + slot: capellaS, + }, + { + name: "last slot of capella", + b: signedTestBlockCapella, + slot: denebS - 1, + }, + { + name: "first slot of deneb", + b: signedTestBlockDeneb, + slot: denebS, + }, + { + name: "bellatrix block in altair slot", + b: signedTestBlockBellatrix, + slot: bellaS - 1, + errExists: true, + }, + { + name: "genesis block in altair slot", + b: signedTestBlockGenesis, + slot: bellaS - 1, + errExists: true, + }, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + b := c.b(t, c.slot) + marshaled, err := b.MarshalSSZ() + require.NoError(t, err) + cf, err := FromBlock(marshaled) + require.NoError(t, err) + bcf, err := cf.UnmarshalBeaconBlock(marshaled) + if c.errExists { + require.NotNil(t, err) + return + } + require.NoError(t, err) + expected, err := b.Block().HashTreeRoot() + require.NoError(t, err) + actual, err := bcf.Block().HashTreeRoot() + require.NoError(t, err) + require.Equal(t, expected, actual) + }) + } +} + func TestUnmarshalBlock(t *testing.T) { undo := util.HackDenebMaxuint(t) defer undo() diff --git a/tools/pcli/BUILD.bazel b/tools/pcli/BUILD.bazel index 583d8d9e596e..fa94ba0afce5 100644 --- a/tools/pcli/BUILD.bazel +++ b/tools/pcli/BUILD.bazel @@ -9,13 +9,17 @@ go_library( visibility = ["//visibility:private"], deps = [ "//beacon-chain/core/transition:go_default_library", + "//beacon-chain/state:go_default_library", "//beacon-chain/state/state-native:go_default_library", "//consensus-types/blocks:go_default_library", + "//consensus-types/interfaces:go_default_library", + "//encoding/ssz/detect:go_default_library", "//encoding/ssz/equality:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//runtime/logging/logrus-prefixed-formatter:go_default_library", "//runtime/version:go_default_library", "@com_github_kr_pretty//:go_default_library", + "@com_github_pkg_errors//:go_default_library", "@com_github_prysmaticlabs_fastssz//:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", "@com_github_urfave_cli_v2//:go_default_library", diff --git a/tools/pcli/main.go b/tools/pcli/main.go index 3a9d3b54559b..37f769df8526 100644 --- a/tools/pcli/main.go +++ b/tools/pcli/main.go @@ -11,10 +11,13 @@ import ( "time" "github.com/kr/pretty" + "github.com/pkg/errors" fssz "github.com/prysmaticlabs/fastssz" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/state" state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native" - "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" + "github.com/prysmaticlabs/prysm/v4/encoding/ssz/detect" "github.com/prysmaticlabs/prysm/v4/encoding/ssz/equality" ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1" prefixed "github.com/prysmaticlabs/prysm/v4/runtime/logging/logrus-prefixed-formatter" @@ -172,11 +175,11 @@ func main() { } blockPath = text } - block := ðpb.SignedBeaconBlock{} - if err := dataFetcher(blockPath, block); err != nil { + block, err := detectBlock(blockPath) + if err != nil { log.Fatal(err) } - blkRoot, err := block.Block.HashTreeRoot() + blkRoot, err := block.Block().HashTreeRoot() if err != nil { log.Fatal(err) } @@ -193,11 +196,7 @@ func main() { } preStatePath = text } - preState := ðpb.BeaconState{} - if err := dataFetcher(preStatePath, preState); err != nil { - log.Fatal(err) - } - stateObj, err := state_native.InitializeFromProtoPhase0(preState) + stateObj, err := detectState(preStatePath) if err != nil { log.Fatal(err) } @@ -206,18 +205,14 @@ func main() { log.Fatal(err) } log.WithFields(log.Fields{ - "blockSlot": fmt.Sprintf("%d", block.Block.Slot), + "blockSlot": fmt.Sprintf("%d", block.Block().Slot()), "preStateSlot": fmt.Sprintf("%d", stateObj.Slot()), }).Infof( "Performing state transition with a block root of %#x and pre state root of %#x", blkRoot, preStateRoot, ) - wsb, err := blocks.NewSignedBeaconBlock(block) - if err != nil { - log.Fatal(err) - } - postState, err := transition.ExecuteStateTransition(context.Background(), stateObj, wsb) + postState, err := transition.ExecuteStateTransition(context.Background(), stateObj, block) if err != nil { log.Fatal(err) } @@ -229,12 +224,12 @@ func main() { // Diff the state if a post state is provided. if expectedPostStatePath != "" { - expectedState := ðpb.BeaconState{} - if err := dataFetcher(expectedPostStatePath, expectedState); err != nil { + expectedState, err := detectState(expectedPostStatePath) + if err != nil { log.Fatal(err) } - if !equality.DeepEqual(expectedState, postState.ToProtoUnsafe()) { - diff, _ := messagediff.PrettyDiff(expectedState, postState.ToProtoUnsafe()) + if !equality.DeepEqual(expectedState.ToProtoUnsafe(), postState.ToProtoUnsafe()) { + diff, _ := messagediff.PrettyDiff(expectedState.ToProtoUnsafe(), postState.ToProtoUnsafe()) log.Errorf("Derived state differs from provided post state: %s", diff) } } @@ -257,6 +252,34 @@ func dataFetcher(fPath string, data fssz.Unmarshaler) error { return data.UnmarshalSSZ(rawFile) } +func detectState(fPath string) (state.BeaconState, error) { + rawFile, err := os.ReadFile(fPath) // #nosec G304 + if err != nil { + return nil, err + } + vu, err := detect.FromState(rawFile) + if err != nil { + return nil, errors.Wrap(err, "error detecting state from file") + } + s, err := vu.UnmarshalBeaconState(rawFile) + if err != nil { + return nil, errors.Wrap(err, "error unmarshalling state") + } + return s, nil +} + +func detectBlock(fPath string) (interfaces.SignedBeaconBlock, error) { + rawFile, err := os.ReadFile(fPath) // #nosec G304 + if err != nil { + return nil, err + } + vu, err := detect.FromBlock(rawFile) + if err != nil { + return nil, err + } + return vu.UnmarshalBeaconBlock(rawFile) +} + func prettyPrint(sszPath string, data fssz.Unmarshaler) { if err := dataFetcher(sszPath, data); err != nil { log.Fatal(err)