diff --git a/beacon-chain/blockchain/kzg/validation_test.go b/beacon-chain/blockchain/kzg/validation_test.go index 6ab79c6478..ddfcb0eb08 100644 --- a/beacon-chain/blockchain/kzg/validation_test.go +++ b/beacon-chain/blockchain/kzg/validation_test.go @@ -366,7 +366,7 @@ func TestVerifyCellKZGProofBatchFromBlobData(t *testing.T) { randBlob := random.GetRandBlob(123) var blob Blob copy(blob[:], randBlob[:]) - + // Create invalid commitment (wrong size) invalidCommitment := make([]byte, 32) // Should be 48 bytes cellProofs := make([][]byte, numberOfColumns) @@ -456,10 +456,10 @@ func TestVerifyCellKZGProofBatchFromBlobData(t *testing.T) { copy(blob[:], randBlob[:]) commitment, err := BlobToKZGCommitment(&blob) require.NoError(t, err) - + blobs[i] = blob[:] commitments[i] = commitment[:] - + // Add cell proofs - make some invalid in the second blob for j := uint64(0); j < numberOfColumns; j++ { if i == 1 && j == 64 { diff --git a/beacon-chain/rpc/eth/beacon/handlers_equivocation_test.go b/beacon-chain/rpc/eth/beacon/handlers_equivocation_test.go index f0e47b7d80..5f0521463f 100644 --- a/beacon-chain/rpc/eth/beacon/handlers_equivocation_test.go +++ b/beacon-chain/rpc/eth/beacon/handlers_equivocation_test.go @@ -17,19 +17,19 @@ func TestBlocks_NewSignedBeaconBlock_EquivocationFix(t *testing.T) { var block structs.SignedBeaconBlock err := json.Unmarshal([]byte(rpctesting.Phase0Block), &block) require.NoError(t, err) - + // Convert to generic format genericBlock, err := block.ToGeneric() require.NoError(t, err) - + // Test the FIX: pass genericBlock.Block instead of genericBlock // This is what our fix changed in handlers.go line 704 and 858 _, err = blocks.NewSignedBeaconBlock(genericBlock.Block) require.NoError(t, err, "NewSignedBeaconBlock should work with genericBlock.Block") - + // Test the BROKEN version: pass genericBlock directly (this should fail) _, err = blocks.NewSignedBeaconBlock(genericBlock) if err == nil { t.Errorf("NewSignedBeaconBlock should fail with whole genericBlock but succeeded") } -} \ No newline at end of file +} diff --git a/beacon-chain/rpc/prysm/v1alpha1/beacon/config_test.go b/beacon-chain/rpc/prysm/v1alpha1/beacon/config_test.go index 1002b05071..68a30df3b2 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/beacon/config_test.go +++ b/beacon-chain/rpc/prysm/v1alpha1/beacon/config_test.go @@ -19,7 +19,7 @@ func TestServer_GetBeaconConfig(t *testing.T) { conf := params.BeaconConfig() confType := reflect.TypeOf(conf).Elem() numFields := confType.NumField() - + // Count only exported fields, as unexported fields are not included in the config exportedFields := 0 for i := 0; i < numFields; i++ { diff --git a/changelog/ttsao_add-fulu-fork-transition-tests.md b/changelog/ttsao_add-fulu-fork-transition-tests.md new file mode 100644 index 0000000000..a4d4c4ba85 --- /dev/null +++ b/changelog/ttsao_add-fulu-fork-transition-tests.md @@ -0,0 +1,3 @@ +### Added + +- Add Fulu fork transition tests for mainnet and minimal configurations diff --git a/testing/spectest/mainnet/BUILD.bazel b/testing/spectest/mainnet/BUILD.bazel index 66af0d466c..10deb54e86 100644 --- a/testing/spectest/mainnet/BUILD.bazel +++ b/testing/spectest/mainnet/BUILD.bazel @@ -176,6 +176,7 @@ go_test( "fulu__epoch_processing__slashings_test.go", "fulu__finality__finality_test.go", "fulu__fork__upgrade_to_fulu_test.go", + "fulu__fork_transition__transition_test.go", "fulu__forkchoice__forkchoice_test.go", "fulu__merkle_proof__merkle_proof_test.go", "fulu__networking__custody_groups_test.go", diff --git a/testing/spectest/mainnet/fulu__fork_transition__transition_test.go b/testing/spectest/mainnet/fulu__fork_transition__transition_test.go new file mode 100644 index 0000000000..31a4d38dd0 --- /dev/null +++ b/testing/spectest/mainnet/fulu__fork_transition__transition_test.go @@ -0,0 +1,11 @@ +package mainnet + +import ( + "testing" + + "github.com/OffchainLabs/prysm/v6/testing/spectest/shared/fulu/fork" +) + +func TestMainnet_Fulu_Transition(t *testing.T) { + fork.RunForkTransitionTest(t, "mainnet") +} diff --git a/testing/spectest/minimal/BUILD.bazel b/testing/spectest/minimal/BUILD.bazel index 42faac0d38..eed7ba0b7d 100644 --- a/testing/spectest/minimal/BUILD.bazel +++ b/testing/spectest/minimal/BUILD.bazel @@ -182,6 +182,7 @@ go_test( "fulu__epoch_processing__sync_committee_updates_test.go", "fulu__finality__finality_test.go", "fulu__fork__upgrade_to_fulu_test.go", + "fulu__fork_transition__transition_test.go", "fulu__forkchoice__forkchoice_test.go", "fulu__merkle_proof__merkle_proof_test.go", "fulu__networking__custody_columns_test.go", diff --git a/testing/spectest/minimal/fulu__fork_transition__transition_test.go b/testing/spectest/minimal/fulu__fork_transition__transition_test.go new file mode 100644 index 0000000000..6e3f143302 --- /dev/null +++ b/testing/spectest/minimal/fulu__fork_transition__transition_test.go @@ -0,0 +1,11 @@ +package minimal + +import ( + "testing" + + "github.com/OffchainLabs/prysm/v6/testing/spectest/shared/fulu/fork" +) + +func TestMinimal_Fulu_Transition(t *testing.T) { + fork.RunForkTransitionTest(t, "minimal") +} diff --git a/testing/spectest/shared/fulu/fork/BUILD.bazel b/testing/spectest/shared/fulu/fork/BUILD.bazel index 4a5851e651..18d324c503 100644 --- a/testing/spectest/shared/fulu/fork/BUILD.bazel +++ b/testing/spectest/shared/fulu/fork/BUILD.bazel @@ -3,13 +3,20 @@ load("@prysm//tools/go:def.bzl", "go_library") go_library( name = "go_default_library", testonly = True, - srcs = ["upgrade_to_fulu.go"], + srcs = [ + "transition.go", + "upgrade_to_fulu.go", + ], importpath = "github.com/OffchainLabs/prysm/v6/testing/spectest/shared/fulu/fork", visibility = ["//visibility:public"], deps = [ "//beacon-chain/core/fulu:go_default_library", "//beacon-chain/core/helpers:go_default_library", + "//beacon-chain/core/transition:go_default_library", "//beacon-chain/state/state-native:go_default_library", + "//config/params:go_default_library", + "//consensus-types/blocks:go_default_library", + "//consensus-types/primitives:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//testing/require:go_default_library", "//testing/spectest/utils:go_default_library", diff --git a/testing/spectest/shared/fulu/fork/transition.go b/testing/spectest/shared/fulu/fork/transition.go new file mode 100644 index 0000000000..858220038e --- /dev/null +++ b/testing/spectest/shared/fulu/fork/transition.go @@ -0,0 +1,125 @@ +package fork + +import ( + "context" + "fmt" + "testing" + + "github.com/OffchainLabs/prysm/v6/beacon-chain/core/helpers" + "github.com/OffchainLabs/prysm/v6/beacon-chain/core/transition" + state_native "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native" + "github.com/OffchainLabs/prysm/v6/config/params" + "github.com/OffchainLabs/prysm/v6/consensus-types/blocks" + types "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" + ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" + "github.com/OffchainLabs/prysm/v6/testing/require" + "github.com/OffchainLabs/prysm/v6/testing/spectest/utils" + "github.com/OffchainLabs/prysm/v6/testing/util" + "github.com/golang/snappy" +) + +type Config struct { + PostFork string `json:"post_fork"` + ForkEpoch int `json:"fork_epoch"` + ForkBlock *int `json:"fork_block"` + BlocksCount int `json:"blocks_count"` +} + +// RunForkTransitionTest is a helper function that runs fulu's transition core tests. +func RunForkTransitionTest(t *testing.T, config string) { + params.SetupTestConfigCleanup(t) + require.NoError(t, utils.SetConfig(t, config)) + + testFolders, testsFolderPath := utils.TestFolders(t, config, "fulu", "transition/core/pyspec_tests") + for _, folder := range testFolders { + t.Run(folder.Name(), func(t *testing.T) { + helpers.ClearCache() + file, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "meta.yaml") + require.NoError(t, err) + config := &Config{} + require.NoError(t, utils.UnmarshalYaml(file, config), "Failed to Unmarshal") + + preforkBlocks := make([]*ethpb.SignedBeaconBlockElectra, 0) + postforkBlocks := make([]*ethpb.SignedBeaconBlockFulu, 0) + // Fork happens without any pre-fork blocks. + if config.ForkBlock == nil { + for i := 0; i < config.BlocksCount; i++ { + fileName := fmt.Sprint("blocks_", i, ".ssz_snappy") + blockFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), fileName) + require.NoError(t, err) + blockSSZ, err := snappy.Decode(nil /* dst */, blockFile) + require.NoError(t, err, "Failed to decompress") + block := ðpb.SignedBeaconBlockFulu{} + require.NoError(t, block.UnmarshalSSZ(blockSSZ), "Failed to unmarshal") + postforkBlocks = append(postforkBlocks, block) + } + // Fork happens with pre-fork blocks. + } else { + for i := 0; i <= *config.ForkBlock; i++ { + fileName := fmt.Sprint("blocks_", i, ".ssz_snappy") + blockFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), fileName) + require.NoError(t, err) + blockSSZ, err := snappy.Decode(nil /* dst */, blockFile) + require.NoError(t, err, "Failed to decompress") + block := ðpb.SignedBeaconBlockElectra{} + require.NoError(t, block.UnmarshalSSZ(blockSSZ), "Failed to unmarshal") + preforkBlocks = append(preforkBlocks, block) + } + for i := *config.ForkBlock + 1; i < config.BlocksCount; i++ { + fileName := fmt.Sprint("blocks_", i, ".ssz_snappy") + blockFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), fileName) + require.NoError(t, err) + blockSSZ, err := snappy.Decode(nil /* dst */, blockFile) + require.NoError(t, err, "Failed to decompress") + block := ðpb.SignedBeaconBlockFulu{} + require.NoError(t, block.UnmarshalSSZ(blockSSZ), "Failed to unmarshal") + postforkBlocks = append(postforkBlocks, block) + } + } + + preBeaconStateFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "pre.ssz_snappy") + require.NoError(t, err) + preBeaconStateSSZ, err := snappy.Decode(nil /* dst */, preBeaconStateFile) + require.NoError(t, err, "Failed to decompress") + beaconStateBase := ðpb.BeaconStateElectra{} + require.NoError(t, beaconStateBase.UnmarshalSSZ(preBeaconStateSSZ), "Failed to unmarshal") + beaconState, err := state_native.InitializeFromProtoElectra(beaconStateBase) + require.NoError(t, err) + + bc := params.BeaconConfig().Copy() + bc.FuluForkEpoch = types.Epoch(config.ForkEpoch) + params.OverrideBeaconConfig(bc) + + ctx := context.Background() + var ok bool + for _, b := range preforkBlocks { + wsb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + st, err := transition.ExecuteStateTransition(ctx, beaconState, wsb) + require.NoError(t, err) + beaconState, ok = st.(*state_native.BeaconState) + require.Equal(t, true, ok) + } + + for _, b := range postforkBlocks { + wsb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + st, err := transition.ExecuteStateTransition(ctx, beaconState, wsb) + require.NoError(t, err) + beaconState, ok = st.(*state_native.BeaconState) + require.Equal(t, true, ok) + } + + postBeaconStateFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "post.ssz_snappy") + require.NoError(t, err) + postBeaconStateSSZ, err := snappy.Decode(nil /* dst */, postBeaconStateFile) + require.NoError(t, err, "Failed to decompress") + postBeaconState := ðpb.BeaconStateFulu{} + require.NoError(t, postBeaconState.UnmarshalSSZ(postBeaconStateSSZ), "Failed to unmarshal") + + pbState, err := state_native.ProtobufBeaconStateFulu(beaconState.ToProto()) + require.NoError(t, err) + require.DeepEqual(t, postBeaconState, pbState, "Did not get expected post state") + }) + } +}