package forkchoice import ( "fmt" "path" "testing" "github.com/golang/snappy" "github.com/prysmaticlabs/prysm/beacon-chain/core/transition" "github.com/prysmaticlabs/prysm/beacon-chain/state" v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2" v3 "github.com/prysmaticlabs/prysm/beacon-chain/state/v3" fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams" "github.com/prysmaticlabs/prysm/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/consensus-types/wrapper" ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/runtime/version" "github.com/prysmaticlabs/prysm/testing/require" "github.com/prysmaticlabs/prysm/testing/spectest/utils" "github.com/prysmaticlabs/prysm/testing/util" ) func init() { transition.SkipSlotCache.Disable() } // Run executes "forkchoice" test. func Run(t *testing.T, config string, fork int) { require.NoError(t, utils.SetConfig(t, config)) testFolders, _ := utils.TestFolders(t, config, version.String(fork), "fork_choice") for _, folder := range testFolders { folderPath := path.Join("fork_choice", folder.Name(), "pyspec_tests") testFolders, testsFolderPath := utils.TestFolders(t, config, version.String(fork), folderPath) for _, folder := range testFolders { t.Run(folder.Name(), func(t *testing.T) { preStepsFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "steps.yaml") require.NoError(t, err) var steps []Step require.NoError(t, utils.UnmarshalYaml(preStepsFile, &steps)) preBeaconStateFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "anchor_state.ssz_snappy") require.NoError(t, err) preBeaconStateSSZ, err := snappy.Decode(nil /* dst */, preBeaconStateFile) require.NoError(t, err) blockFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "anchor_block.ssz_snappy") require.NoError(t, err) blockSSZ, err := snappy.Decode(nil /* dst */, blockFile) require.NoError(t, err) var beaconState state.BeaconState var beaconBlock interfaces.SignedBeaconBlock switch fork { case version.Phase0: beaconState = unmarshalPhase0State(t, preBeaconStateSSZ) beaconBlock = unmarshalPhase0Block(t, blockSSZ) case version.Altair: beaconState = unmarshalAltairState(t, preBeaconStateSSZ) beaconBlock = unmarshalAltairBlock(t, blockSSZ) case version.Bellatrix: beaconState = unmarshalBellatrixState(t, preBeaconStateSSZ) beaconBlock = unmarshalBellatrixBlock(t, blockSSZ) default: t.Fatalf("unknown fork version: %v", fork) } builder := NewBuilder(t, beaconState, beaconBlock) for _, step := range steps { if step.Tick != nil { builder.Tick(t, int64(*step.Tick)) } if step.Block != nil { blockFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), fmt.Sprint(*step.Block, ".ssz_snappy")) require.NoError(t, err) blockSSZ, err := snappy.Decode(nil /* dst */, blockFile) require.NoError(t, err) var beaconBlock interfaces.SignedBeaconBlock switch fork { case version.Phase0: beaconBlock = unmarshalSignedPhase0Block(t, blockSSZ) case version.Altair: beaconBlock = unmarshalSignedAltairBlock(t, blockSSZ) case version.Bellatrix: beaconBlock = unmarshalSignedBellatrixBlock(t, blockSSZ) default: t.Fatalf("unknown fork version: %v", fork) } if step.Valid != nil && !*step.Valid { builder.InvalidBlock(t, beaconBlock) } else { builder.ValidBlock(t, beaconBlock) } } if step.AttesterSlashing != nil { slashingFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), fmt.Sprint(*step.AttesterSlashing, ".ssz_snappy")) require.NoError(t, err) slashingSSZ, err := snappy.Decode(nil /* dst */, slashingFile) require.NoError(t, err) slashing := ðpb.AttesterSlashing{} require.NoError(t, slashing.UnmarshalSSZ(slashingSSZ), "Failed to unmarshal") builder.AttesterSlashing(slashing) } if step.Attestation != nil { attFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), fmt.Sprint(*step.Attestation, ".ssz_snappy")) require.NoError(t, err) attSSZ, err := snappy.Decode(nil /* dst */, attFile) require.NoError(t, err) att := ðpb.Attestation{} require.NoError(t, att.UnmarshalSSZ(attSSZ), "Failed to unmarshal") builder.Attestation(t, att) } if step.PowBlock != nil { powBlockFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), fmt.Sprint(*step.PowBlock, ".ssz_snappy")) require.NoError(t, err) p, err := snappy.Decode(nil /* dst */, powBlockFile) require.NoError(t, err) pb := ðpb.PowBlock{} require.NoError(t, pb.UnmarshalSSZ(p), "Failed to unmarshal") builder.PoWBlock(t, pb) } builder.Check(t, step.Check) } }) } } } func unmarshalPhase0State(t *testing.T, raw []byte) state.BeaconState { base := ðpb.BeaconState{} require.NoError(t, base.UnmarshalSSZ(raw)) st, err := v1.InitializeFromProto(base) require.NoError(t, err) return st } func unmarshalPhase0Block(t *testing.T, raw []byte) interfaces.SignedBeaconBlock { base := ðpb.BeaconBlock{} require.NoError(t, base.UnmarshalSSZ(raw)) blk, err := wrapper.WrappedSignedBeaconBlock(ðpb.SignedBeaconBlock{Block: base, Signature: make([]byte, fieldparams.BLSSignatureLength)}) require.NoError(t, err) return blk } func unmarshalSignedPhase0Block(t *testing.T, raw []byte) interfaces.SignedBeaconBlock { base := ðpb.SignedBeaconBlock{} require.NoError(t, base.UnmarshalSSZ(raw)) blk, err := wrapper.WrappedSignedBeaconBlock(base) require.NoError(t, err) return blk } func unmarshalAltairState(t *testing.T, raw []byte) state.BeaconState { base := ðpb.BeaconStateAltair{} require.NoError(t, base.UnmarshalSSZ(raw)) st, err := v2.InitializeFromProto(base) require.NoError(t, err) return st } func unmarshalAltairBlock(t *testing.T, raw []byte) interfaces.SignedBeaconBlock { base := ðpb.BeaconBlockAltair{} require.NoError(t, base.UnmarshalSSZ(raw)) blk, err := wrapper.WrappedSignedBeaconBlock(ðpb.SignedBeaconBlockAltair{Block: base, Signature: make([]byte, fieldparams.BLSSignatureLength)}) require.NoError(t, err) return blk } func unmarshalSignedAltairBlock(t *testing.T, raw []byte) interfaces.SignedBeaconBlock { base := ðpb.SignedBeaconBlockAltair{} require.NoError(t, base.UnmarshalSSZ(raw)) blk, err := wrapper.WrappedSignedBeaconBlock(base) require.NoError(t, err) return blk } func unmarshalBellatrixState(t *testing.T, raw []byte) state.BeaconState { base := ðpb.BeaconStateBellatrix{} require.NoError(t, base.UnmarshalSSZ(raw)) st, err := v3.InitializeFromProto(base) require.NoError(t, err) return st } func unmarshalBellatrixBlock(t *testing.T, raw []byte) interfaces.SignedBeaconBlock { base := ðpb.BeaconBlockBellatrix{} require.NoError(t, base.UnmarshalSSZ(raw)) blk, err := wrapper.WrappedSignedBeaconBlock(ðpb.SignedBeaconBlockBellatrix{Block: base, Signature: make([]byte, fieldparams.BLSSignatureLength)}) require.NoError(t, err) return blk } func unmarshalSignedBellatrixBlock(t *testing.T, raw []byte) interfaces.SignedBeaconBlock { base := ðpb.SignedBeaconBlockBellatrix{} require.NoError(t, base.UnmarshalSSZ(raw)) blk, err := wrapper.WrappedSignedBeaconBlock(base) require.NoError(t, err) return blk }