mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-07 20:43:57 -05:00
Allow Pcli to Run State Transitions Easily (#13484)
* add all this in * gaz * add flag
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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",
|
||||
"//config/params: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",
|
||||
|
||||
@@ -11,10 +11,14 @@ 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/config/params"
|
||||
"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"
|
||||
@@ -28,6 +32,7 @@ func main() {
|
||||
var blockPath string
|
||||
var preStatePath string
|
||||
var expectedPostStatePath string
|
||||
var network string
|
||||
var sszPath string
|
||||
var sszType string
|
||||
|
||||
@@ -157,8 +162,36 @@ func main() {
|
||||
Usage: "Path to expected post state file(ssz)",
|
||||
Destination: &expectedPostStatePath,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "network",
|
||||
Usage: "Network to run the state transition in",
|
||||
Destination: &network,
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
if network != "" {
|
||||
switch network {
|
||||
case params.PraterName:
|
||||
if err := params.SetActive(params.PraterConfig()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case params.GoerliName:
|
||||
if err := params.SetActive(params.PraterConfig()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case params.SepoliaName:
|
||||
if err := params.SetActive(params.SepoliaConfig()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case params.HoleskyName:
|
||||
if err := params.SetActive(params.HoleskyConfig()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
default:
|
||||
log.Fatalf("Unknown network provided: %s", network)
|
||||
}
|
||||
}
|
||||
|
||||
if blockPath == "" {
|
||||
log.Info("Block path not provided for state transition. " +
|
||||
"Please provide path")
|
||||
@@ -172,11 +205,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 +226,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 +235,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 +254,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 +282,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)
|
||||
|
||||
Reference in New Issue
Block a user