From e0eee87bf47448aaef19f8a448cbc59cf9c7db89 Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Tue, 16 Aug 2022 11:19:01 -0500 Subject: [PATCH] Improve beacon chain coverage Part 1 (#11080) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * first node test * adding in configuration flags for code coverage * adding line to remove file on unit test * adding new test for compressed field trie but is currently broken * changing limit on trie * adding new trie length coverage * adding in test for empty copy of trie * adding more trie tests * adding new field trie * adding more field trie tests * adding clarity to chunking equation * fixing linting * clarifying function for limit * updating native state settings to improve ease of future unit tests * improving unit test * fixing unit tests * adding more tests and fixing linting * adding more coverage and removing unused file * increasing node coverage * adding new test for checking config for booleans * fixing db test * fixing linting * adding signing root test * fixing linting * removing accidently created beacondata * switching not non native state * reverting back to proto use for spec test * reverting back to proto for some tests * turning off native state on some tests * switching more to proto state * rolling back disablenativestate * switching to native state in the state-native package for tests * fixing linting * fixing deepsource complaint * fixing some tests to native state and removing some unused flag checks * convert to native state * fixing linting * issues are being triggered by deleting the db this way so reverting change in hopes of changing this * rolling back testing util * rolling back some tests from native state * rolling back db deletion * test switching native state off after test runs * fixing hasher test * fixing altair and bellatrix hashers for native state * Update beacon-chain/node/node_test.go Co-authored-by: Radosław Kapka * Update validator/rpc/auth_token_test.go Co-authored-by: Radosław Kapka * fixing imports * adding altair proof test Co-authored-by: Radosław Kapka --- beacon-chain/core/signing/BUILD.bazel | 1 + .../core/signing/signing_root_test.go | 25 ++ beacon-chain/node/BUILD.bazel | 7 + beacon-chain/node/node_test.go | 96 +++++- beacon-chain/rpc/eth/beacon/validator_test.go | 1 - beacon-chain/state/fieldtrie/BUILD.bazel | 5 + .../state/fieldtrie/field_trie_test.go | 68 ++++ beacon-chain/state/fieldtrie/helpers_test.go | 295 +++++++++++++++++- beacon-chain/state/state-native/BUILD.bazel | 5 +- .../getters_participation_test.go | 2 + .../state-native/getters_validator_test.go | 34 ++ .../state/state-native/hasher_test.go | 23 +- .../state/state-native/proofs_test.go | 135 +++++++- .../state-native/setters_attestation_test.go | 3 + beacon-chain/state/state-native/state_test.go | 7 + beacon-chain/state/state-native/state_trie.go | 5 +- .../state/state-native/state_trie_test.go | 23 +- beacon-chain/state/state-native/types_test.go | 3 + .../state/stateutil/validator_root.go | 13 +- cmd/validator/flags/flags_test.go | 33 ++ testing/util/state.go | 6 +- validator/rpc/auth_token_test.go | 2 + 22 files changed, 745 insertions(+), 47 deletions(-) diff --git a/beacon-chain/core/signing/BUILD.bazel b/beacon-chain/core/signing/BUILD.bazel index 9fef3416c3..7a20b3e421 100644 --- a/beacon-chain/core/signing/BUILD.bazel +++ b/beacon-chain/core/signing/BUILD.bazel @@ -42,6 +42,7 @@ go_test( "//testing/assert:go_default_library", "//testing/require:go_default_library", "//testing/util:go_default_library", + "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_google_gofuzz//:go_default_library", ], ) diff --git a/beacon-chain/core/signing/signing_root_test.go b/beacon-chain/core/signing/signing_root_test.go index df1aa0b5cf..aea5187b11 100644 --- a/beacon-chain/core/signing/signing_root_test.go +++ b/beacon-chain/core/signing/signing_root_test.go @@ -5,6 +5,7 @@ import ( "context" "testing" + "github.com/ethereum/go-ethereum/common/hexutil" fuzz "github.com/google/gofuzz" "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing" @@ -134,3 +135,27 @@ func TestFuzzverifySigningRoot_10000(_ *testing.T) { _ = err } } + +func TestBlockSignatureBatch_NoSigVerification(t *testing.T) { + tests := []struct { + pubkey []byte + mockSignature []byte + domain []byte + wantMessageHexs []string + }{ + { + pubkey: []byte{0xa9, 0x9a, 0x76, 0xed, 0x77, 0x96, 0xf7, 0xbe, 0x22, 0xd5, 0xb7, 0xe8, 0x5d, 0xee, 0xb7, 0xc5, 0x67, 0x7e, 0x88, 0xe5, 0x11, 0xe0, 0xb3, 0x37, 0x61, 0x8f, 0x8c, 0x4e, 0xb6, 0x13, 0x49, 0xb4, 0xbf, 0x2d, 0x15, 0x3f, 0x64, 0x9f, 0x7b, 0x53, 0x35, 0x9f, 0xe8, 0xb9, 0x4a, 0x38, 0xe4, 0x4c}, + mockSignature: []byte{0xa9, 0x9a, 0x76, 0xed, 0x77}, + domain: []byte{4, 0, 0, 0, 245, 165, 253, 66, 209, 106, 32, 48, 39, 152, 239, 110, 211, 9, 151, 155, 67, 0, 61, 35, 32, 217, 240, 232, 234, 152, 49, 169}, + wantMessageHexs: []string{"0xe6012bc68e112797a91ed6889e7453f8e304fb76fbffcec1c62eef280a93f7ba"}, + }, + } + for _, tt := range tests { + block := util.NewBeaconBlock() + got, err := signing.BlockSignatureBatch(tt.pubkey, tt.mockSignature, tt.domain, block.Block.HashTreeRoot) + require.NoError(t, err) + for i, message := range got.Messages { + require.Equal(t, hexutil.Encode(message[:]), tt.wantMessageHexs[i]) + } + } +} diff --git a/beacon-chain/node/BUILD.bazel b/beacon-chain/node/BUILD.bazel index 6d445df546..a6929e78f7 100644 --- a/beacon-chain/node/BUILD.bazel +++ b/beacon-chain/node/BUILD.bazel @@ -79,13 +79,20 @@ go_test( ], embed = [":go_default_library"], deps = [ + "//beacon-chain/blockchain:go_default_library", + "//beacon-chain/builder:go_default_library", "//beacon-chain/core/feed/state:go_default_library", "//beacon-chain/execution:go_default_library", "//beacon-chain/execution/testing:go_default_library", "//cmd:go_default_library", "//cmd/beacon-chain/flags:go_default_library", + "//config/features:go_default_library", + "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types/primitives:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + "//runtime:go_default_library", + "//runtime/interop:go_default_library", "//testing/assert:go_default_library", "//testing/require:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library", diff --git a/beacon-chain/node/node_test.go b/beacon-chain/node/node_test.go index e796a7b5fb..ea883b1bb6 100644 --- a/beacon-chain/node/node_test.go +++ b/beacon-chain/node/node_test.go @@ -1,15 +1,28 @@ package node import ( + "context" "flag" "fmt" + "os" "path/filepath" + "strconv" "testing" + "time" + "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain" + "github.com/prysmaticlabs/prysm/v3/beacon-chain/builder" statefeed "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/feed/state" "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution" mockExecution "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing" "github.com/prysmaticlabs/prysm/v3/cmd" + "github.com/prysmaticlabs/prysm/v3/cmd/beacon-chain/flags" + "github.com/prysmaticlabs/prysm/v3/config/features" + fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams" + "github.com/prysmaticlabs/prysm/v3/config/params" + ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v3/runtime" + "github.com/prysmaticlabs/prysm/v3/runtime/interop" "github.com/prysmaticlabs/prysm/v3/testing/require" logTest "github.com/sirupsen/logrus/hooks/test" "github.com/urfave/cli/v2" @@ -21,7 +34,7 @@ var _ statefeed.Notifier = (*BeaconNode)(nil) // Test that beacon chain node can close. func TestNodeClose_OK(t *testing.T) { hook := logTest.NewGlobal() - + features.Init(&features.Flags{EnableNativeState: true}) tmp := fmt.Sprintf("%s/datadirtest2", t.TempDir()) app := cli.App{} @@ -31,15 +44,90 @@ func TestNodeClose_OK(t *testing.T) { set.String("p2p-encoding", "ssz", "p2p encoding scheme") set.Bool("demo-config", true, "demo configuration") set.String("deposit-contract", "0x0000000000000000000000000000000000000000", "deposit contract address") + set.Bool(cmd.EnableBackupWebhookFlag.Name, true, "") + require.NoError(t, set.Set(cmd.EnableBackupWebhookFlag.Name, "true")) + set.String(cmd.BackupWebhookOutputDir.Name, "datadir", "") + cmd.ValidatorMonitorIndicesFlag.Value = &cli.IntSlice{} + cmd.ValidatorMonitorIndicesFlag.Value.SetInt(1) + ctx := cli.NewContext(&app, set, nil) - context := cli.NewContext(&app, set, nil) - - node, err := New(context) + node, err := New(ctx) require.NoError(t, err) node.Close() require.LogsContain(t, hook, "Stopping beacon node") + features.Init(&features.Flags{EnableNativeState: false}) +} + +func TestNodeStart_Ok(t *testing.T) { + hook := logTest.NewGlobal() + app := cli.App{} + tmp := fmt.Sprintf("%s/datadirtest2", t.TempDir()) + set := flag.NewFlagSet("test", 0) + set.String("datadir", tmp, "node data directory") + features.Init(&features.Flags{EnableNativeState: true}) + ctx := cli.NewContext(&app, set, nil) + node, err := New(ctx, WithBlockchainFlagOptions([]blockchain.Option{}), + WithBuilderFlagOptions([]builder.Option{}), + WithExecutionChainOptions([]execution.Option{})) + require.NoError(t, err) + node.services = &runtime.ServiceRegistry{} + go func() { + node.Start() + }() + time.Sleep(3 * time.Second) + node.Close() + require.LogsContain(t, hook, "Starting beacon node") + +} + +func TestNodeStart_Ok_registerDeterministicGenesisService(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) + numValidators := uint64(1) + hook := logTest.NewGlobal() + app := cli.App{} + tmp := fmt.Sprintf("%s/datadirtest2", t.TempDir()) + set := flag.NewFlagSet("test", 0) + set.String("datadir", tmp, "node data directory") + set.Uint64(flags.InteropNumValidatorsFlag.Name, numValidators, "") + genesisState, _, err := interop.GenerateGenesisState(context.Background(), 0, numValidators) + require.NoError(t, err, "Could not generate genesis beacon state") + for i := uint64(1); i < 2; i++ { + someRoot := [32]byte{} + someKey := [fieldparams.BLSPubkeyLength]byte{} + copy(someRoot[:], strconv.Itoa(int(i))) + copy(someKey[:], strconv.Itoa(int(i))) + genesisState.Validators = append(genesisState.Validators, ðpb.Validator{ + PublicKey: someKey[:], + WithdrawalCredentials: someRoot[:], + EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, + Slashed: false, + ActivationEligibilityEpoch: 1, + ActivationEpoch: 1, + ExitEpoch: 1, + WithdrawableEpoch: 1, + }) + genesisState.Balances = append(genesisState.Balances, params.BeaconConfig().MaxEffectiveBalance) + } + genesisBytes, err := genesisState.MarshalSSZ() + require.NoError(t, err) + require.NoError(t, os.WriteFile("genesis_ssz.json", genesisBytes, 0666)) + set.String(flags.InteropGenesisStateFlag.Name, "genesis_ssz.json", "") + ctx := cli.NewContext(&app, set, nil) + node, err := New(ctx, WithBlockchainFlagOptions([]blockchain.Option{}), + WithBuilderFlagOptions([]builder.Option{}), + WithExecutionChainOptions([]execution.Option{})) + require.NoError(t, err) + node.services = &runtime.ServiceRegistry{} + go func() { + node.Start() + }() + time.Sleep(3 * time.Second) + node.Close() + require.LogsContain(t, hook, "Starting beacon node") + require.NoError(t, os.Remove("genesis_ssz.json")) + features.Init(&features.Flags{EnableNativeState: false}) } // TestClearDB tests clearing the database diff --git a/beacon-chain/rpc/eth/beacon/validator_test.go b/beacon-chain/rpc/eth/beacon/validator_test.go index 7a1a8c80bd..a391354f96 100644 --- a/beacon-chain/rpc/eth/beacon/validator_test.go +++ b/beacon-chain/rpc/eth/beacon/validator_test.go @@ -115,7 +115,6 @@ func TestGetValidator(t *testing.T) { func TestListValidators(t *testing.T) { ctx := context.Background() db := dbTest.SetupDB(t) - var st state.BeaconState st, _ = util.DeterministicGenesisState(t, 8192) diff --git a/beacon-chain/state/fieldtrie/BUILD.bazel b/beacon-chain/state/fieldtrie/BUILD.bazel index a1e752bfb9..bdf4a4bf44 100644 --- a/beacon-chain/state/fieldtrie/BUILD.bazel +++ b/beacon-chain/state/fieldtrie/BUILD.bazel @@ -31,13 +31,18 @@ go_test( data = glob(["testdata/**"]), embed = [":go_default_library"], deps = [ + "//beacon-chain/state/state-native/custom-types:go_default_library", + "//beacon-chain/state/state-native/types:go_default_library", "//beacon-chain/state/stateutil:go_default_library", "//beacon-chain/state/types:go_default_library", + "//config/features:go_default_library", + "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types/primitives:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//testing/assert:go_default_library", "//testing/require:go_default_library", "//testing/util:go_default_library", + "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", ], ) diff --git a/beacon-chain/state/fieldtrie/field_trie_test.go b/beacon-chain/state/fieldtrie/field_trie_test.go index 22a20f6a95..67197a0a9f 100644 --- a/beacon-chain/state/fieldtrie/field_trie_test.go +++ b/beacon-chain/state/fieldtrie/field_trie_test.go @@ -6,6 +6,7 @@ import ( "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/fieldtrie" "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stateutil" stateTypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/types" + "github.com/prysmaticlabs/prysm/v3/config/features" "github.com/prysmaticlabs/prysm/v3/config/params" types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" @@ -15,6 +16,7 @@ import ( ) func TestFieldTrie_NewTrie(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) newState, _ := util.DeterministicGenesisState(t, 40) // 5 represents the enum value of state roots @@ -25,6 +27,7 @@ func TestFieldTrie_NewTrie(t *testing.T) { newRoot, err := trie.TrieRoot() require.NoError(t, err) assert.Equal(t, root, newRoot) + features.Init(&features.Flags{EnableNativeState: false}) } func TestFieldTrie_NewTrie_NilElements(t *testing.T) { @@ -35,11 +38,16 @@ func TestFieldTrie_NewTrie_NilElements(t *testing.T) { } func TestFieldTrie_RecomputeTrie(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) newState, _ := util.DeterministicGenesisState(t, 32) // 10 represents the enum value of validators trie, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(11), stateTypes.CompositeArray, newState.Validators(), params.BeaconConfig().ValidatorRegistryLimit) require.NoError(t, err) + oldroot, err := trie.TrieRoot() + require.NoError(t, err) + require.NotEmpty(t, oldroot) + changedIdx := []uint64{2, 29} val1, err := newState.ValidatorAtIndex(10) require.NoError(t, err) @@ -60,9 +68,38 @@ func TestFieldTrie_RecomputeTrie(t *testing.T) { root, err := trie.RecomputeTrie(changedIdx, newState.Validators()) require.NoError(t, err) assert.Equal(t, expectedRoot, root) + features.Init(&features.Flags{EnableNativeState: false}) +} + +func TestFieldTrie_RecomputeTrie_CompressedArray(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) + newState, _ := util.DeterministicGenesisState(t, 32) + trie, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(12), stateTypes.CompressedArray, newState.Balances(), stateutil.ValidatorLimitForBalancesChunks()) + require.NoError(t, err) + require.Equal(t, trie.Length(), stateutil.ValidatorLimitForBalancesChunks()) + changedIdx := []uint64{4, 8} + require.NoError(t, newState.UpdateBalancesAtIndex(types.ValidatorIndex(changedIdx[0]), uint64(100000000))) + require.NoError(t, newState.UpdateBalancesAtIndex(types.ValidatorIndex(changedIdx[1]), uint64(200000000))) + expectedRoot, err := stateutil.Uint64ListRootWithRegistryLimit(newState.Balances()) + require.NoError(t, err) + root, err := trie.RecomputeTrie(changedIdx, newState.Balances()) + require.NoError(t, err) + + // not equal for some reason :( + assert.Equal(t, expectedRoot, root) + features.Init(&features.Flags{EnableNativeState: false}) +} + +func TestNewFieldTrie_UnknownType(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) + newState, _ := util.DeterministicGenesisState(t, 32) + _, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(12), 4, newState.Balances(), 32) + require.ErrorContains(t, "unrecognized data type", err) + features.Init(&features.Flags{EnableNativeState: false}) } func TestFieldTrie_CopyTrieImmutable(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) newState, _ := util.DeterministicGenesisState(t, 32) // 12 represents the enum value of randao mixes. trie, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(13), stateTypes.BasicArray, newState.RandaoMixes(), uint64(params.BeaconConfig().EpochsPerHistoricalVector)) @@ -83,9 +120,39 @@ func TestFieldTrie_CopyTrieImmutable(t *testing.T) { if root == newRoot { t.Errorf("Wanted roots to be different, but they are the same: %#x", root) } + features.Init(&features.Flags{EnableNativeState: false}) +} + +func TestFieldTrie_CopyAndTransferEmpty(t *testing.T) { + trie, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(13), stateTypes.BasicArray, nil, uint64(params.BeaconConfig().EpochsPerHistoricalVector)) + require.NoError(t, err) + + require.DeepEqual(t, trie, trie.CopyTrie()) + require.DeepEqual(t, trie, trie.TransferTrie()) +} + +func TestFieldTrie_TransferTrie(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) + newState, _ := util.DeterministicGenesisState(t, 32) + maxLength := (params.BeaconConfig().ValidatorRegistryLimit*8 + 31) / 32 + trie, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(12), stateTypes.CompressedArray, newState.Balances(), maxLength) + require.NoError(t, err) + oldRoot, err := trie.TrieRoot() + require.NoError(t, err) + + newTrie := trie.TransferTrie() + root, err := trie.TrieRoot() + require.ErrorIs(t, err, fieldtrie.ErrEmptyFieldTrie) + require.Equal(t, root, [32]byte{}) + require.NotNil(t, newTrie) + newRoot, err := newTrie.TrieRoot() + require.NoError(t, err) + require.DeepEqual(t, oldRoot, newRoot) + features.Init(&features.Flags{EnableNativeState: false}) } func FuzzFieldTrie(f *testing.F) { + features.Init(&features.Flags{EnableNativeState: true}) newState, _ := util.DeterministicGenesisState(f, 40) var data []byte for _, root := range newState.StateRoots() { @@ -107,4 +174,5 @@ func FuzzFieldTrie(f *testing.F) { return } }) + features.Init(&features.Flags{EnableNativeState: false}) } diff --git a/beacon-chain/state/fieldtrie/helpers_test.go b/beacon-chain/state/fieldtrie/helpers_test.go index 18d67a74e6..71cf95436c 100644 --- a/beacon-chain/state/fieldtrie/helpers_test.go +++ b/beacon-chain/state/fieldtrie/helpers_test.go @@ -2,14 +2,22 @@ package fieldtrie import ( "encoding/binary" + "fmt" + "reflect" "sync" "testing" + "github.com/ethereum/go-ethereum/common/hexutil" + customtypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native/custom-types" + nativeStateTypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native/types" "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stateutil" - "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/types" + stateTypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/types" + "github.com/prysmaticlabs/prysm/v3/config/features" + fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams" "github.com/prysmaticlabs/prysm/v3/config/params" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v3/testing/assert" + "github.com/prysmaticlabs/prysm/v3/testing/require" ) func Test_handlePendingAttestation_OutOfRange(t *testing.T) { @@ -71,8 +79,8 @@ func TestValidateIndices_CompressedField(t *testing.T) { RWMutex: new(sync.RWMutex), reference: stateutil.NewRef(0), fieldLayers: nil, - field: types.Balances, - dataType: types.CompressedArray, + field: stateTypes.Balances, + dataType: stateTypes.CompressedArray, length: params.BeaconConfig().ValidatorRegistryLimit / 4, numOfElems: 0, } @@ -83,3 +91,284 @@ func TestValidateIndices_CompressedField(t *testing.T) { assert.ErrorContains(t, "invalid index for field balances", fakeTrie.validateIndices([]uint64{badIdx})) } + +func TestFieldTrie_NativeState_fieldConvertersNative(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) + type args struct { + field stateTypes.BeaconStateField + indices []uint64 + elements interface{} + convertAll bool + } + tests := []struct { + name string + args *args + wantHex []string + errMsg string + expectedLength int + }{ + { + name: "BlockRoots [][]bytes", + args: &args{ + field: nativeStateTypes.FieldIndex(5), + indices: []uint64{}, + elements: [][]byte{[]byte("dfsadfsadf")}, + convertAll: true, + }, + wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"}, + }, + { + name: "BlockRoots customtypes.BlockRoots", + args: &args{ + field: nativeStateTypes.FieldIndex(5), + indices: []uint64{}, + elements: &customtypes.BlockRoots{}, + convertAll: true, + }, + wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"}, + expectedLength: 8192, + }, + { + name: "BlockRoots type not found", + args: &args{ + field: nativeStateTypes.FieldIndex(5), + indices: []uint64{}, + elements: 123, + convertAll: true, + }, + wantHex: nil, + errMsg: "Incorrect type used for block roots", + }, + { + name: "BlockRoots [][]bytes", + args: &args{ + field: nativeStateTypes.FieldIndex(5), + indices: []uint64{}, + elements: [][]byte{[]byte("dfsadfsadf")}, + convertAll: true, + }, + wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"}, + }, + { + name: "StateRoots [][]bytes", + args: &args{ + field: nativeStateTypes.FieldIndex(6), + indices: []uint64{}, + elements: [][]byte{[]byte("dfsadfsadf")}, + convertAll: true, + }, + wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"}, + }, + { + name: "StateRoots customtypes.StateRoots", + args: &args{ + field: nativeStateTypes.FieldIndex(6), + indices: []uint64{}, + elements: &customtypes.StateRoots{}, + convertAll: true, + }, + wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"}, + expectedLength: 8192, + }, + { + name: "StateRoots type not found", + args: &args{ + field: nativeStateTypes.FieldIndex(6), + indices: []uint64{}, + elements: 123, + convertAll: true, + }, + wantHex: nil, + errMsg: "Incorrect type used for state roots", + }, + { + name: "StateRoots [][]bytes convert all false", + args: &args{ + field: nativeStateTypes.FieldIndex(6), + indices: []uint64{}, + elements: [][]byte{[]byte("dfsadfsadf")}, + convertAll: false, + }, + wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"}, + }, + { + name: "StateRoots customtypes.StateRoots convert all false", + args: &args{ + field: nativeStateTypes.FieldIndex(6), + indices: []uint64{}, + elements: &customtypes.StateRoots{}, + convertAll: false, + }, + wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"}, + expectedLength: 8192, + }, + { + name: "RandaoMixes [][]bytes", + args: &args{ + field: nativeStateTypes.FieldIndex(13), + indices: []uint64{}, + elements: [][]byte{[]byte("dfsadfsadf")}, + convertAll: true, + }, + wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"}, + }, + { + name: "RandaoMixes customtypes.RandaoMixes", + args: &args{ + field: nativeStateTypes.FieldIndex(13), + indices: []uint64{}, + elements: &customtypes.RandaoMixes{}, + convertAll: true, + }, + wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"}, + expectedLength: 65536, + }, + { + name: "RandaoMixes type not found", + args: &args{ + field: nativeStateTypes.FieldIndex(13), + indices: []uint64{}, + elements: 123, + convertAll: true, + }, + wantHex: nil, + errMsg: "Incorrect type used for randao mixes", + }, + { + name: "Eth1DataVotes type not found", + args: &args{ + field: nativeStateTypes.FieldIndex(9), + indices: []uint64{}, + elements: []*ethpb.Eth1Data{ + { + DepositRoot: make([]byte, fieldparams.RootLength), + DepositCount: 1, + }, + }, + convertAll: true, + }, + wantHex: []string{"0x4833912e1264aef8a18392d795f3f2eed17cf5c0e8471cb0c0db2ec5aca10231"}, + }, + { + name: "Eth1DataVotes convertAll false", + args: &args{ + field: nativeStateTypes.FieldIndex(9), + indices: []uint64{1}, + elements: []*ethpb.Eth1Data{ + { + DepositRoot: make([]byte, fieldparams.RootLength), + DepositCount: 1, + }, + }, + convertAll: false, + }, + wantHex: []string{"0x4833912e1264aef8a18392d795f3f2eed17cf5c0e8471cb0c0db2ec5aca10231"}, + }, + { + name: "Eth1DataVotes type not found", + args: &args{ + field: nativeStateTypes.FieldIndex(9), + indices: []uint64{}, + elements: 123, + convertAll: true, + }, + wantHex: nil, + errMsg: fmt.Sprintf("Wanted type of %v", reflect.TypeOf([]*ethpb.Eth1Data{}).Name()), + }, + { + name: "Balance", + args: &args{ + field: nativeStateTypes.FieldIndex(12), + indices: []uint64{}, + elements: []uint64{12321312321, 12131241234123123}, + convertAll: true, + }, + wantHex: []string{"0x414e68de0200000073c971b44c192b0000000000000000000000000000000000"}, + }, + { + name: "Validators", + args: &args{ + field: nativeStateTypes.FieldIndex(11), + indices: []uint64{}, + elements: []*ethpb.Validator{ + { + ActivationEpoch: 1, + }, + }, + convertAll: true, + }, + wantHex: []string{"0x79817c24fc7ba90cdac48fd462fafc1cb501884e847b18733f7ca6df214a301e"}, + }, + { + name: "Validators not found", + args: &args{ + field: nativeStateTypes.FieldIndex(11), + indices: []uint64{}, + elements: 123, + convertAll: true, + }, + wantHex: nil, + errMsg: fmt.Sprintf("Wanted type of %v", reflect.TypeOf([]*ethpb.Validator{}).Name()), + }, + { + name: "Attestations", + args: &args{ + field: nativeStateTypes.FieldIndex(15), + indices: []uint64{}, + elements: []*ethpb.PendingAttestation{ + { + ProposerIndex: 1, + }, + }, + convertAll: true, + }, + wantHex: []string{"0x7d7696e7f12593934afcd87a0d38e1a981bee63cb4cf0568ba36a6e0596eeccb"}, + }, + { + name: "Attestations", + args: &args{ + field: nativeStateTypes.FieldIndex(15), + indices: []uint64{1}, + elements: []*ethpb.PendingAttestation{ + { + ProposerIndex: 1, + }, + }, + convertAll: false, + }, + wantHex: []string{"0x7d7696e7f12593934afcd87a0d38e1a981bee63cb4cf0568ba36a6e0596eeccb"}, + }, + { + name: "Type not found", + args: &args{ + field: nativeStateTypes.FieldIndex(999), + indices: []uint64{}, + elements: []*ethpb.PendingAttestation{ + { + ProposerIndex: 1, + }, + }, + convertAll: true, + }, + errMsg: "got unsupported type of", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + roots, err := fieldConvertersNative(tt.args.field, tt.args.indices, tt.args.elements, tt.args.convertAll) + if err != nil && tt.errMsg != "" { + require.ErrorContains(t, tt.errMsg, err) + } else { + for i, root := range roots { + hex := hexutil.Encode(root[:]) + require.Equal(t, tt.wantHex[i], hex) + if tt.expectedLength != 0 { + require.Equal(t, len(roots), tt.expectedLength) + break + } + } + } + }) + } + features.Init(&features.Flags{EnableNativeState: false}) +} diff --git a/beacon-chain/state/state-native/BUILD.bazel b/beacon-chain/state/state-native/BUILD.bazel index 20fc393106..6b6fe566e6 100644 --- a/beacon-chain/state/state-native/BUILD.bazel +++ b/beacon-chain/state/state-native/BUILD.bazel @@ -108,9 +108,7 @@ go_test( "//beacon-chain/state/state-native/types:go_default_library", "//beacon-chain/state/stateutil:go_default_library", "//beacon-chain/state/testing:go_default_library", - "//beacon-chain/state/v1:go_default_library", - "//beacon-chain/state/v2:go_default_library", - "//beacon-chain/state/v3:go_default_library", + "//config/features:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types/blocks:go_default_library", @@ -123,6 +121,7 @@ go_test( "//testing/assert:go_default_library", "//testing/require:go_default_library", "//testing/util:go_default_library", + "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_prysmaticlabs_go_bitfield//:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", "@org_golang_google_protobuf//proto:go_default_library", diff --git a/beacon-chain/state/state-native/getters_participation_test.go b/beacon-chain/state/state-native/getters_participation_test.go index fb413ffba5..05218a14a1 100644 --- a/beacon-chain/state/state-native/getters_participation_test.go +++ b/beacon-chain/state/state-native/getters_participation_test.go @@ -3,6 +3,7 @@ package state_native import ( "testing" + "github.com/prysmaticlabs/prysm/v3/config/features" "github.com/prysmaticlabs/prysm/v3/config/params" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v3/testing/require" @@ -27,6 +28,7 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) { PreviousEpochParticipation: make([]byte, params.BeaconConfig().MinGenesisActiveValidatorCount), Balances: balances, } + features.Init(&features.Flags{EnableNativeState: true}) state, err := InitializeFromProtoAltair(base) require.NoError(t, err) diff --git a/beacon-chain/state/state-native/getters_validator_test.go b/beacon-chain/state/state-native/getters_validator_test.go index 86abbb067c..2d829abefe 100644 --- a/beacon-chain/state/state-native/getters_validator_test.go +++ b/beacon-chain/state/state-native/getters_validator_test.go @@ -3,32 +3,66 @@ package state_native_test import ( "testing" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/prysmaticlabs/prysm/v3/beacon-chain/state" statenative "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native" testtmpl "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/testing" + "github.com/prysmaticlabs/prysm/v3/config/features" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v3/testing/require" + "github.com/prysmaticlabs/prysm/v3/testing/util" ) func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice_Phase0(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) { return statenative.InitializeFromProtoUnsafePhase0(ðpb.BeaconState{ Validators: nil, }) }) + features.Init(&features.Flags{EnableNativeState: false}) } func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice_Altair(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) { return statenative.InitializeFromProtoUnsafeAltair(ðpb.BeaconStateAltair{ Validators: nil, }) }) + features.Init(&features.Flags{EnableNativeState: false}) } func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice_Bellatrix(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) { return statenative.InitializeFromProtoUnsafeBellatrix(ðpb.BeaconStateBellatrix{ Validators: nil, }) }) + features.Init(&features.Flags{EnableNativeState: false}) +} + +func TestValidatorIndexOutOfRangeError(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) + err := statenative.NewValidatorIndexOutOfRangeError(1) + require.Equal(t, err.Error(), "index 1 out of range") + features.Init(&features.Flags{EnableNativeState: false}) +} + +func TestValidatorIndexes(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) + dState, _ := util.DeterministicGenesisState(t, 10) + byteValue := dState.PubkeyAtIndex(1) + t.Run("ValidatorIndexByPubkey", func(t *testing.T) { + require.Equal(t, hexutil.Encode(byteValue[:]), "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b") + }) + t.Run("ValidatorAtIndexReadOnly", func(t *testing.T) { + readOnlyState, err := dState.ValidatorAtIndexReadOnly(1) + require.NoError(t, err) + readOnlyBytes := readOnlyState.PublicKey() + require.NotEmpty(t, readOnlyBytes) + require.Equal(t, hexutil.Encode(readOnlyBytes[:]), hexutil.Encode(byteValue[:])) + }) + features.Init(&features.Flags{EnableNativeState: false}) } diff --git a/beacon-chain/state/state-native/hasher_test.go b/beacon-chain/state/state-native/hasher_test.go index 857f8dd763..d2a28d0094 100644 --- a/beacon-chain/state/state-native/hasher_test.go +++ b/beacon-chain/state/state-native/hasher_test.go @@ -6,9 +6,7 @@ import ( "github.com/prysmaticlabs/go-bitfield" statenative "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native" - v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1" - v2 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2" - v3 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v3" + "github.com/prysmaticlabs/prysm/v3/config/features" "github.com/prysmaticlabs/prysm/v3/config/params" "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" @@ -20,6 +18,7 @@ import ( ) func TestComputeFieldRootsWithHasher_Phase0(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) beaconState, err := util.NewBeaconState(util.FillRootsNaturalOpt) require.NoError(t, err) require.NoError(t, beaconState.SetGenesisTime(123)) @@ -46,10 +45,11 @@ func TestComputeFieldRootsWithHasher_Phase0(t *testing.T) { require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(checkpoint("current"))) require.NoError(t, beaconState.SetFinalizedCheckpoint(checkpoint("finalized"))) - v1State, ok := beaconState.(*v1.BeaconState) + nativeState, ok := beaconState.(*statenative.BeaconState) require.Equal(t, true, ok) - protoState, ok := v1State.InnerStateUnsafe().(*ethpb.BeaconState) + protoState, ok := nativeState.InnerStateUnsafe().(*ethpb.BeaconState) require.Equal(t, true, ok) + initState, err := statenative.InitializeFromProtoPhase0(protoState) require.NoError(t, err) s, ok := initState.(*statenative.BeaconState) @@ -80,9 +80,11 @@ func TestComputeFieldRootsWithHasher_Phase0(t *testing.T) { {0xa9, 0xbb, 0x6a, 0x1f, 0x5d, 0x86, 0x7d, 0xa7, 0x5a, 0x7d, 0x9d, 0x8d, 0xc0, 0x15, 0xb7, 0x0, 0xee, 0xa9, 0x68, 0x51, 0x88, 0x57, 0x5a, 0xd9, 0x4e, 0x1d, 0x8e, 0x44, 0xbf, 0xdc, 0x73, 0xff}, } assert.DeepEqual(t, expected, root) + features.Init(&features.Flags{EnableNativeState: false}) } func TestComputeFieldRootsWithHasher_Altair(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) beaconState, err := util.NewBeaconStateAltair(util.FillRootsNaturalOptAltair) require.NoError(t, err) require.NoError(t, beaconState.SetGenesisTime(123)) @@ -112,9 +114,9 @@ func TestComputeFieldRootsWithHasher_Altair(t *testing.T) { require.NoError(t, beaconState.SetCurrentSyncCommittee(syncCommittee("current"))) require.NoError(t, beaconState.SetNextSyncCommittee(syncCommittee("next"))) - v1State, ok := beaconState.(*v2.BeaconState) + nativeState, ok := beaconState.(*statenative.BeaconState) require.Equal(t, true, ok) - protoState, ok := v1State.InnerStateUnsafe().(*ethpb.BeaconStateAltair) + protoState, ok := nativeState.InnerStateUnsafe().(*ethpb.BeaconStateAltair) require.Equal(t, true, ok) initState, err := statenative.InitializeFromProtoAltair(protoState) require.NoError(t, err) @@ -150,9 +152,11 @@ func TestComputeFieldRootsWithHasher_Altair(t *testing.T) { {0xd6, 0x4c, 0xb1, 0xac, 0x61, 0x7, 0x26, 0xbb, 0xd3, 0x27, 0x2a, 0xcd, 0xdd, 0x55, 0xf, 0x2b, 0x6a, 0xe8, 0x1, 0x31, 0x48, 0x66, 0x2f, 0x98, 0x7b, 0x6d, 0x27, 0x69, 0xd9, 0x40, 0xcc, 0x37}, } assert.DeepEqual(t, expected, root) + features.Init(&features.Flags{EnableNativeState: false}) } func TestComputeFieldRootsWithHasher_Bellatrix(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) beaconState, err := util.NewBeaconStateBellatrix(util.FillRootsNaturalOptBellatrix) require.NoError(t, err) require.NoError(t, beaconState.SetGenesisTime(123)) @@ -185,9 +189,9 @@ func TestComputeFieldRootsWithHasher_Bellatrix(t *testing.T) { require.NoError(t, err) require.NoError(t, beaconState.SetLatestExecutionPayloadHeader(wrappedHeader)) - v1State, ok := beaconState.(*v3.BeaconState) + nativeState, ok := beaconState.(*statenative.BeaconState) require.Equal(t, true, ok) - protoState, ok := v1State.InnerStateUnsafe().(*ethpb.BeaconStateBellatrix) + protoState, ok := nativeState.InnerStateUnsafe().(*ethpb.BeaconStateBellatrix) require.Equal(t, true, ok) initState, err := statenative.InitializeFromProtoBellatrix(protoState) require.NoError(t, err) @@ -224,6 +228,7 @@ func TestComputeFieldRootsWithHasher_Bellatrix(t *testing.T) { {0xbc, 0xbb, 0x39, 0x57, 0x61, 0x1d, 0x54, 0xd6, 0x1b, 0xfe, 0x7a, 0xbd, 0x29, 0x52, 0x57, 0xdd, 0x19, 0x1, 0x89, 0x22, 0x7d, 0xdf, 0x7b, 0x53, 0x9f, 0xb, 0x46, 0x5, 0x9f, 0x80, 0xcc, 0x8e}, } assert.DeepEqual(t, expected, root) + features.Init(&features.Flags{EnableNativeState: false}) } func genesisValidatorsRoot() []byte { diff --git a/beacon-chain/state/state-native/proofs_test.go b/beacon-chain/state/state-native/proofs_test.go index e9a7f3b1c0..6c910e86d0 100644 --- a/beacon-chain/state/state-native/proofs_test.go +++ b/beacon-chain/state/state-native/proofs_test.go @@ -4,45 +4,82 @@ import ( "context" "testing" + "github.com/ethereum/go-ethereum/common/hexutil" statenative "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native" + "github.com/prysmaticlabs/prysm/v3/config/features" "github.com/prysmaticlabs/prysm/v3/container/trie" "github.com/prysmaticlabs/prysm/v3/testing/require" "github.com/prysmaticlabs/prysm/v3/testing/util" ) -func TestBeaconStateMerkleProofs(t *testing.T) { +func TestBeaconStateMerkleProofs_phase0_notsupported(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) ctx := context.Background() st, _ := util.DeterministicGenesisState(t, 256) - htr, err := st.HashTreeRoot(ctx) - require.NoError(t, err) t.Run("current sync committee", func(t *testing.T) { _, err := st.CurrentSyncCommitteeProof(ctx) - require.ErrorContains(t, "unsupported", err) + require.ErrorContains(t, "not supported", err) }) t.Run("next sync committee", func(t *testing.T) { _, err := st.NextSyncCommitteeProof(ctx) - require.ErrorContains(t, "unsupported", err) + require.ErrorContains(t, "not supported", err) }) t.Run("finalized root", func(t *testing.T) { - finalizedRoot := st.FinalizedCheckpoint().Root - proof, err := st.FinalizedRootProof(ctx) + _, err := st.FinalizedRootProof(ctx) + require.ErrorContains(t, "not supported", err) + }) + features.Init(&features.Flags{EnableNativeState: false}) +} +func TestBeaconStateMerkleProofs_altair(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) + ctx := context.Background() + altair, err := util.NewBeaconStateAltair() + require.NoError(t, err) + htr, err := altair.HashTreeRoot(ctx) + require.NoError(t, err) + results := []string{ + "0x173669ae8794c057def63b20372114a628abb029354a2ef50d7a1aaa9a3dab4a", + "0xe8facaa9be1c488207092f135ca6159f7998f313459b4198f46a9433f8b346e6", + "0x0a7910590f2a08faa740a5c40e919722b80a786d18d146318309926a6b2ab95e", + "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x4616e1d9312a92eb228e8cd5483fa1fca64d99781d62129bc53718d194b98c45", + } + t.Run("current sync committee", func(t *testing.T) { + cscp, err := altair.CurrentSyncCommitteeProof(ctx) + require.NoError(t, err) + require.Equal(t, len(cscp), 5) + for i, bytes := range cscp { + require.Equal(t, hexutil.Encode(bytes), results[i]) + } + }) + t.Run("next sync committee", func(t *testing.T) { + nscp, err := altair.NextSyncCommitteeProof(ctx) + require.NoError(t, err) + require.Equal(t, len(nscp), 5) + for i, bytes := range nscp { + require.Equal(t, hexutil.Encode(bytes), results[i]) + } + }) + t.Run("finalized root", func(t *testing.T) { + finalizedRoot := altair.FinalizedCheckpoint().Root + proof, err := altair.FinalizedRootProof(ctx) require.NoError(t, err) gIndex := statenative.FinalizedRootGeneralizedIndex() valid := trie.VerifyMerkleProof(htr[:], finalizedRoot, gIndex, proof) require.Equal(t, true, valid) }) t.Run("recomputes root on dirty fields", func(t *testing.T) { - currentRoot, err := st.HashTreeRoot(ctx) + currentRoot, err := altair.HashTreeRoot(ctx) require.NoError(t, err) - cpt := st.FinalizedCheckpoint() + cpt := altair.FinalizedCheckpoint() require.NoError(t, err) // Edit the checkpoint. cpt.Epoch = 100 - require.NoError(t, st.SetFinalizedCheckpoint(cpt)) + require.NoError(t, altair.SetFinalizedCheckpoint(cpt)) // Produce a proof for the finalized root. - proof, err := st.FinalizedRootProof(ctx) + proof, err := altair.FinalizedRootProof(ctx) require.NoError(t, err) // We expect the previous step to have triggered @@ -50,15 +87,87 @@ func TestBeaconStateMerkleProofs(t *testing.T) { // in a new hash tree root as the finalized checkpoint had previously // changed and should have been marked as a dirty state field. // The proof validity should be false for the old root, but true for the new. - finalizedRoot := st.FinalizedCheckpoint().Root + finalizedRoot := altair.FinalizedCheckpoint().Root gIndex := statenative.FinalizedRootGeneralizedIndex() valid := trie.VerifyMerkleProof(currentRoot[:], finalizedRoot, gIndex, proof) require.Equal(t, false, valid) - newRoot, err := st.HashTreeRoot(ctx) + newRoot, err := altair.HashTreeRoot(ctx) require.NoError(t, err) valid = trie.VerifyMerkleProof(newRoot[:], finalizedRoot, gIndex, proof) require.Equal(t, true, valid) }) + features.Init(&features.Flags{EnableNativeState: false}) +} + +func TestBeaconStateMerkleProofs_bellatrix(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) + ctx := context.Background() + bellatrix, err := util.NewBeaconStateBellatrix() + require.NoError(t, err) + htr, err := bellatrix.HashTreeRoot(ctx) + require.NoError(t, err) + results := []string{ + "0x173669ae8794c057def63b20372114a628abb029354a2ef50d7a1aaa9a3dab4a", + "0xe8facaa9be1c488207092f135ca6159f7998f313459b4198f46a9433f8b346e6", + "0x0a7910590f2a08faa740a5c40e919722b80a786d18d146318309926a6b2ab95e", + "0xa83dc5a6222b6e5d5f11115ec4ba4035512c060e74908c56ebc25ad74dd25c18", + "0x4616e1d9312a92eb228e8cd5483fa1fca64d99781d62129bc53718d194b98c45", + } + t.Run("current sync committee", func(t *testing.T) { + cscp, err := bellatrix.CurrentSyncCommitteeProof(ctx) + require.NoError(t, err) + require.Equal(t, len(cscp), 5) + for i, bytes := range cscp { + require.Equal(t, hexutil.Encode(bytes), results[i]) + } + }) + t.Run("next sync committee", func(t *testing.T) { + nscp, err := bellatrix.NextSyncCommitteeProof(ctx) + require.NoError(t, err) + require.Equal(t, len(nscp), 5) + for i, bytes := range nscp { + require.Equal(t, hexutil.Encode(bytes), results[i]) + } + }) + t.Run("finalized root", func(t *testing.T) { + finalizedRoot := bellatrix.FinalizedCheckpoint().Root + proof, err := bellatrix.FinalizedRootProof(ctx) + require.NoError(t, err) + gIndex := statenative.FinalizedRootGeneralizedIndex() + valid := trie.VerifyMerkleProof(htr[:], finalizedRoot, gIndex, proof) + require.Equal(t, true, valid) + }) + t.Run("recomputes root on dirty fields", func(t *testing.T) { + currentRoot, err := bellatrix.HashTreeRoot(ctx) + require.NoError(t, err) + cpt := bellatrix.FinalizedCheckpoint() + require.NoError(t, err) + + // Edit the checkpoint. + cpt.Epoch = 100 + require.NoError(t, bellatrix.SetFinalizedCheckpoint(cpt)) + + // Produce a proof for the finalized root. + proof, err := bellatrix.FinalizedRootProof(ctx) + require.NoError(t, err) + + // We expect the previous step to have triggered + // a recomputation of dirty fields in the beacon state, resulting + // in a new hash tree root as the finalized checkpoint had previously + // changed and should have been marked as a dirty state field. + // The proof validity should be false for the old root, but true for the new. + finalizedRoot := bellatrix.FinalizedCheckpoint().Root + gIndex := statenative.FinalizedRootGeneralizedIndex() + valid := trie.VerifyMerkleProof(currentRoot[:], finalizedRoot, gIndex, proof) + require.Equal(t, false, valid) + + newRoot, err := bellatrix.HashTreeRoot(ctx) + require.NoError(t, err) + + valid = trie.VerifyMerkleProof(newRoot[:], finalizedRoot, gIndex, proof) + require.Equal(t, true, valid) + }) + features.Init(&features.Flags{EnableNativeState: false}) } diff --git a/beacon-chain/state/state-native/setters_attestation_test.go b/beacon-chain/state/state-native/setters_attestation_test.go index ead3297411..db24597b3d 100644 --- a/beacon-chain/state/state-native/setters_attestation_test.go +++ b/beacon-chain/state/state-native/setters_attestation_test.go @@ -3,12 +3,14 @@ package state_native import ( "testing" + "github.com/prysmaticlabs/prysm/v3/config/features" types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v3/testing/require" ) func TestBeaconState_RotateAttestations(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) st, err := InitializeFromProtoPhase0(ðpb.BeaconState{ Slot: 1, CurrentEpochAttestations: []*ethpb.PendingAttestation{{Data: ðpb.AttestationData{Slot: 456}}}, @@ -21,4 +23,5 @@ func TestBeaconState_RotateAttestations(t *testing.T) { require.Equal(t, true, ok) require.Equal(t, 0, len(s.currentEpochAttestationsVal())) require.Equal(t, types.Slot(456), s.previousEpochAttestationsVal()[0].Data.Slot) + features.Init(&features.Flags{EnableNativeState: false}) } diff --git a/beacon-chain/state/state-native/state_test.go b/beacon-chain/state/state-native/state_test.go index bc55caefcb..d81ce62979 100644 --- a/beacon-chain/state/state-native/state_test.go +++ b/beacon-chain/state/state-native/state_test.go @@ -9,6 +9,7 @@ import ( "github.com/prysmaticlabs/go-bitfield" nativetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native/types" "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stateutil" + "github.com/prysmaticlabs/prysm/v3/config/features" fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams" "github.com/prysmaticlabs/prysm/v3/config/params" types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" @@ -65,6 +66,7 @@ func TestBeaconState_NoDeadlock_Phase0(t *testing.T) { WithdrawableEpoch: 1, }) } + features.Init(&features.Flags{EnableNativeState: true}) newState, err := InitializeFromProtoUnsafePhase0(ðpb.BeaconState{ Validators: vals, }) @@ -121,6 +123,7 @@ func TestBeaconState_NoDeadlock_Altair(t *testing.T) { WithdrawableEpoch: 1, }) } + features.Init(&features.Flags{EnableNativeState: true}) st, err := InitializeFromProtoUnsafeAltair(ðpb.BeaconStateAltair{ Validators: vals, }) @@ -177,6 +180,7 @@ func TestBeaconState_NoDeadlock_Bellatrix(t *testing.T) { WithdrawableEpoch: 1, }) } + features.Init(&features.Flags{EnableNativeState: true}) st, err := InitializeFromProtoUnsafeBellatrix(ðpb.BeaconStateBellatrix{ Validators: vals, }) @@ -249,6 +253,7 @@ func TestBeaconState_AppendBalanceWithTrie(t *testing.T) { for i := 0; i < len(mockrandaoMixes); i++ { mockrandaoMixes[i] = zeroHash[:] } + features.Init(&features.Flags{EnableNativeState: true}) newState, err := InitializeFromProtoPhase0(ðpb.BeaconState{ Slot: 1, GenesisValidatorsRoot: make([]byte, 32), @@ -300,6 +305,7 @@ func TestBeaconState_AppendBalanceWithTrie(t *testing.T) { } func TestBeaconState_ModifyPreviousParticipationBits(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) st, err := InitializeFromProtoUnsafePhase0(ðpb.BeaconState{}) assert.NoError(t, err) assert.ErrorContains(t, "ModifyPreviousParticipationBits is not supported", st.ModifyPreviousParticipationBits(func(val []byte) ([]byte, error) { @@ -308,6 +314,7 @@ func TestBeaconState_ModifyPreviousParticipationBits(t *testing.T) { } func TestBeaconState_ModifyCurrentParticipationBits(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) st, err := InitializeFromProtoUnsafePhase0(ðpb.BeaconState{}) assert.NoError(t, err) assert.ErrorContains(t, "ModifyCurrentParticipationBits is not supported", st.ModifyCurrentParticipationBits(func(val []byte) ([]byte, error) { diff --git a/beacon-chain/state/state-native/state_trie.go b/beacon-chain/state/state-native/state_trie.go index a0b65a4f36..022ac43475 100644 --- a/beacon-chain/state/state-native/state_trie.go +++ b/beacon-chain/state/state-native/state_trie.go @@ -663,10 +663,7 @@ func (b *BeaconState) rootSelector(ctx context.Context, field nativetypes.FieldI return b.recomputeFieldTrie(11, b.validators) case nativetypes.Balances: if b.rebuildTrie[field] { - maxBalCap := uint64(fieldparams.ValidatorRegistryLimit) - elemSize := uint64(8) - balLimit := (maxBalCap*elemSize + 31) / 32 - err := b.resetFieldTrie(field, b.balances, balLimit) + err := b.resetFieldTrie(field, b.balances, stateutil.ValidatorLimitForBalancesChunks()) if err != nil { return [32]byte{}, err } diff --git a/beacon-chain/state/state-native/state_trie_test.go b/beacon-chain/state/state-native/state_trie_test.go index 3de5315a2c..42f660d1a1 100644 --- a/beacon-chain/state/state-native/state_trie_test.go +++ b/beacon-chain/state/state-native/state_trie_test.go @@ -7,6 +7,7 @@ import ( "github.com/prysmaticlabs/prysm/v3/beacon-chain/state" statenative "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native" + "github.com/prysmaticlabs/prysm/v3/config/features" "github.com/prysmaticlabs/prysm/v3/config/params" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" @@ -16,6 +17,7 @@ import ( ) func TestInitializeFromProto_Phase0(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) testState, _ := util.DeterministicGenesisState(t, 64) pbState, err := statenative.ProtobufBeaconStatePhase0(testState.InnerStateUnsafe()) require.NoError(t, err) @@ -85,12 +87,14 @@ func TestInitializeFromProto_Altair(t *testing.T) { } for _, tt := range initTests { t.Run(tt.name, func(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) _, err := statenative.InitializeFromProtoAltair(tt.state) if tt.error != "" { require.ErrorContains(t, tt.error, err) } else { require.NoError(t, err) } + features.Init(&features.Flags{EnableNativeState: false}) }) } } @@ -121,12 +125,14 @@ func TestInitializeFromProto_Bellatrix(t *testing.T) { } for _, tt := range initTests { t.Run(tt.name, func(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) _, err := statenative.InitializeFromProtoBellatrix(tt.state) if tt.error != "" { require.ErrorContains(t, tt.error, err) } else { require.NoError(t, err) } + features.Init(&features.Flags{EnableNativeState: false}) }) } } @@ -159,17 +165,19 @@ func TestInitializeFromProtoUnsafe_Phase0(t *testing.T) { } for _, tt := range initTests { t.Run(tt.name, func(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) _, err := statenative.InitializeFromProtoUnsafePhase0(tt.state) if tt.error != "" { assert.ErrorContains(t, tt.error, err) } else { assert.NoError(t, err) } + features.Init(&features.Flags{EnableNativeState: false}) }) } } -func TestInitializeFromProtoUnsafe_Altair(t *testing.T) { +func TestInitializeFromProtoUnsafe_Altair(_ *testing.T) { type test struct { name string state *ethpb.BeaconStateAltair @@ -192,7 +200,7 @@ func TestInitializeFromProtoUnsafe_Altair(t *testing.T) { _ = initTests } -func TestInitializeFromProtoUnsafe_Bellatrix(t *testing.T) { +func TestInitializeFromProtoUnsafe_Bellatrix(_ *testing.T) { type test struct { name string state *ethpb.BeaconStateBellatrix @@ -268,6 +276,7 @@ func TestBeaconState_HashTreeRoot(t *testing.T) { if err == nil && tt.error != "" { t.Errorf("Expected error, expected %v, recevied %v", tt.error, err) } + features.Init(&features.Flags{EnableNativeState: true}) pbState, err := statenative.ProtobufBeaconStatePhase0(testState.InnerStateUnsafe()) require.NoError(t, err) genericHTR, err := pbState.HashTreeRoot() @@ -280,11 +289,13 @@ func TestBeaconState_HashTreeRoot(t *testing.T) { t.Errorf("Expected HTR to change, received %#x == old %#x", root, oldHTR) } oldHTR = root[:] + features.Init(&features.Flags{EnableNativeState: false}) }) } } func BenchmarkBeaconState(b *testing.B) { + features.Init(&features.Flags{EnableNativeState: true}) testState, _ := util.DeterministicGenesisState(b, 16000) pbState, err := statenative.ProtobufBeaconStatePhase0(testState.InnerStateUnsafe()) require.NoError(b, err) @@ -300,6 +311,7 @@ func BenchmarkBeaconState(b *testing.B) { _, err := pbState.HashTreeRoot() require.NoError(b, err) }) + features.Init(&features.Flags{EnableNativeState: false}) } func TestBeaconState_HashTreeRoot_FieldTrie(t *testing.T) { @@ -355,6 +367,7 @@ func TestBeaconState_HashTreeRoot_FieldTrie(t *testing.T) { if err == nil && tt.error != "" { t.Errorf("Expected error, expected %v, recevied %v", tt.error, err) } + features.Init(&features.Flags{EnableNativeState: true}) pbState, err := statenative.ProtobufBeaconStatePhase0(testState.InnerStateUnsafe()) require.NoError(t, err) genericHTR, err := pbState.HashTreeRoot() @@ -367,6 +380,7 @@ func TestBeaconState_HashTreeRoot_FieldTrie(t *testing.T) { t.Errorf("Expected HTR to change, received %#x == old %#x", root, oldHTR) } oldHTR = root[:] + features.Init(&features.Flags{EnableNativeState: false}) }) } } @@ -415,6 +429,7 @@ func TestBeaconState_ValidatorMutation_Phase0(t *testing.T) { rt, err := testState.HashTreeRoot(context.Background()) require.NoError(t, err) + features.Init(&features.Flags{EnableNativeState: true}) pbState, err = statenative.ProtobufBeaconStatePhase0(testState.InnerStateUnsafe()) require.NoError(t, err) @@ -452,6 +467,7 @@ func TestBeaconState_ValidatorMutation_Phase0(t *testing.T) { } func TestBeaconState_ValidatorMutation_Altair(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) testState, _ := util.DeterministicGenesisStateAltair(t, 400) pbState, err := statenative.ProtobufBeaconStateAltair(testState.InnerStateUnsafe()) require.NoError(t, err) @@ -516,9 +532,11 @@ func TestBeaconState_ValidatorMutation_Altair(t *testing.T) { require.NoError(t, err) assert.Equal(t, rt, rt2) + features.Init(&features.Flags{EnableNativeState: false}) } func TestBeaconState_ValidatorMutation_Bellatrix(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) testState, _ := util.DeterministicGenesisStateBellatrix(t, 400) pbState, err := statenative.ProtobufBeaconStateBellatrix(testState.InnerStateUnsafe()) require.NoError(t, err) @@ -583,4 +601,5 @@ func TestBeaconState_ValidatorMutation_Bellatrix(t *testing.T) { require.NoError(t, err) assert.Equal(t, rt, rt2) + features.Init(&features.Flags{EnableNativeState: false}) } diff --git a/beacon-chain/state/state-native/types_test.go b/beacon-chain/state/state-native/types_test.go index 40bbefde7a..3a8709b9a3 100644 --- a/beacon-chain/state/state-native/types_test.go +++ b/beacon-chain/state/state-native/types_test.go @@ -7,6 +7,7 @@ import ( "testing" statenative "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native" + "github.com/prysmaticlabs/prysm/v3/config/features" fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams" "github.com/prysmaticlabs/prysm/v3/config/params" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" @@ -19,6 +20,7 @@ import ( ) func TestBeaconState_ProtoBeaconStateCompatibility(t *testing.T) { + features.Init(&features.Flags{EnableNativeState: true}) params.SetupTestConfigCleanup(t) ctx := context.Background() genesis := setupGenesisState(t, 64) @@ -52,6 +54,7 @@ func TestBeaconState_ProtoBeaconStateCompatibility(t *testing.T) { } func setupGenesisState(tb testing.TB, count uint64) *ethpb.BeaconState { + features.Init(&features.Flags{EnableNativeState: true}) genesisState, _, err := interop.GenerateGenesisState(context.Background(), 0, count) require.NoError(tb, err, "Could not generate genesis beacon state") for i := uint64(1); i < count; i++ { diff --git a/beacon-chain/state/stateutil/validator_root.go b/beacon-chain/state/stateutil/validator_root.go index fd8606ad63..49bbdc4fdf 100644 --- a/beacon-chain/state/stateutil/validator_root.go +++ b/beacon-chain/state/stateutil/validator_root.go @@ -68,11 +68,7 @@ func Uint64ListRootWithRegistryLimit(balances []uint64) ([32]byte, error) { if err != nil { return [32]byte{}, errors.Wrap(err, "could not pack balances into chunks") } - maxBalCap := uint64(fieldparams.ValidatorRegistryLimit) - elemSize := uint64(8) - balLimit := (maxBalCap*elemSize + 31) / 32 - - balancesRootsRoot, err := ssz.BitwiseMerkleize(hasher, balancesChunks, uint64(len(balancesChunks)), balLimit) + balancesRootsRoot, err := ssz.BitwiseMerkleize(hasher, balancesChunks, uint64(len(balancesChunks)), ValidatorLimitForBalancesChunks()) if err != nil { return [32]byte{}, errors.Wrap(err, "could not compute balances merkleization") } @@ -82,6 +78,13 @@ func Uint64ListRootWithRegistryLimit(balances []uint64) ([32]byte, error) { return ssz.MixInLength(balancesRootsRoot, balancesLengthRoot), nil } +// ValidatorLimitForBalancesChunks returns the limit of validators after going through the chunking process. +func ValidatorLimitForBalancesChunks() uint64 { + maxValidatorLimit := uint64(fieldparams.ValidatorRegistryLimit) + bytesInUint64 := uint64(8) + return (maxValidatorLimit*bytesInUint64 + 31) / 32 // round to nearest chunk +} + // PackUint64IntoChunks packs a list of uint64 values into 32 byte roots. func PackUint64IntoChunks(vals []uint64) ([][32]byte, error) { // Initialize how many uint64 values we can pack diff --git a/cmd/validator/flags/flags_test.go b/cmd/validator/flags/flags_test.go index 63b0b55de8..de506ab6b7 100644 --- a/cmd/validator/flags/flags_test.go +++ b/cmd/validator/flags/flags_test.go @@ -50,3 +50,36 @@ func TestLoadFlagsFromConfig_PreProcessing_Web3signer(t *testing.T) { require.NoError(t, command.Run(context)) require.NoError(t, os.Remove("flags_test.yaml")) } + +func TestLoadFlagsFromConfig_EnableBuilderHasDefaultValue(t *testing.T) { + app := cli.App{} + set := flag.NewFlagSet("test", 0) + context := cli.NewContext(&app, set, nil) + + require.NoError(t, os.WriteFile("flags_test.yaml", []byte("---\nenable-builder: true"), 0666)) + + require.NoError(t, set.Parse([]string{"test-command", "--" + cmd.ConfigFileFlag.Name, "flags_test.yaml"})) + command := &cli.Command{ + Name: "test-command", + Flags: cmd.WrapFlags([]cli.Flag{ + &cli.StringFlag{ + Name: cmd.ConfigFileFlag.Name, + }, + &cli.BoolFlag{ + Name: EnableBuilderFlag.Name, + Value: false, + }, + }), + Before: func(cliCtx *cli.Context) error { + return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags) + }, + Action: func(cliCtx *cli.Context) error { + + require.Equal(t, true, + cliCtx.Bool(EnableBuilderFlag.Name)) + return nil + }, + } + require.NoError(t, command.Run(context)) + require.NoError(t, os.Remove("flags_test.yaml")) +} diff --git a/testing/util/state.go b/testing/util/state.go index 2cbbe93572..a4517caef1 100644 --- a/testing/util/state.go +++ b/testing/util/state.go @@ -101,7 +101,7 @@ func NewBeaconState(options ...NewBeaconStateOption) (state.BeaconState, error) return nil, err } - return st.Copy().(*v1.BeaconState), nil + return st.Copy(), nil } // NewBeaconStateAltair creates a beacon state with minimum marshalable fields. @@ -156,7 +156,7 @@ func NewBeaconStateAltair(options ...func(state *ethpb.BeaconStateAltair) error) return nil, err } - return st.Copy().(*v2.BeaconState), nil + return st.Copy(), nil } // NewBeaconStateBellatrix creates a beacon state with minimum marshalable fields. @@ -223,7 +223,7 @@ func NewBeaconStateBellatrix(options ...func(state *ethpb.BeaconStateBellatrix) return nil, err } - return st.Copy().(*v3.BeaconState), nil + return st.Copy(), nil } // SSZ will fill 2D byte slices with their respective values, so we must fill these in too for round diff --git a/validator/rpc/auth_token_test.go b/validator/rpc/auth_token_test.go index dee1f26d72..2a426fdc1c 100644 --- a/validator/rpc/auth_token_test.go +++ b/validator/rpc/auth_token_test.go @@ -79,6 +79,8 @@ func TestServer_RefreshJWTSecretOnFileChange(t *testing.T) { newSecret := srv.jwtSecret require.Equal(t, true, len(newSecret) > 0) require.Equal(t, true, !bytes.Equal(currentSecret, newSecret)) + err = os.Remove(authTokenFileName) + require.NoError(t, err) } func Test_initializeAuthToken(t *testing.T) {