package v2_test import ( "context" "testing" v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2" "github.com/prysmaticlabs/prysm/container/trie" "github.com/prysmaticlabs/prysm/crypto/bls" "github.com/prysmaticlabs/prysm/testing/require" "github.com/prysmaticlabs/prysm/testing/util" ) func TestBeaconStateMerkleProofs(t *testing.T) { ctx := context.Background() st, _ := util.DeterministicGenesisStateAltair(t, 256) htr, err := st.HashTreeRoot(ctx) require.NoError(t, err) t.Run("current sync committee", func(t *testing.T) { sc, err := st.CurrentSyncCommittee() require.NoError(t, err) // Verify the Merkle proof. scRoot, err := sc.HashTreeRoot() require.NoError(t, err) proof, err := st.CurrentSyncCommitteeProof(ctx) require.NoError(t, err) valid := trie.VerifyMerkleProof(htr[:], scRoot[:], v2.CurrentSyncCommitteeGeneralizedIndex(), proof) require.Equal(t, true, valid) }) t.Run("next sync committee", func(t *testing.T) { nextSC, err := st.NextSyncCommittee() require.NoError(t, err) proof, err := st.NextSyncCommitteeProof(ctx) require.NoError(t, err) // Verify the Merkle proof. nextSCRoot, err := nextSC.HashTreeRoot() require.NoError(t, err) valid := trie.VerifyMerkleProof(htr[:], nextSCRoot[:], v2.NextSyncCommitteeGeneralizedIndex(), proof) require.Equal(t, true, valid) // Edit the sync committee. privKey, err := bls.RandKey() require.NoError(t, err) nextSC.AggregatePubkey = privKey.PublicKey().Marshal() require.NoError(t, st.SetNextSyncCommittee(nextSC)) // Verifying the old Merkle proof for the new value should fail. nextSCRoot, err = nextSC.HashTreeRoot() require.NoError(t, err) valid = trie.VerifyMerkleProof(htr[:], nextSCRoot[:], v2.NextSyncCommitteeGeneralizedIndex(), proof) require.Equal(t, false, valid) // Generating a new, valid proof should pass. proof, err = st.NextSyncCommitteeProof(ctx) require.NoError(t, err) htr, err = st.HashTreeRoot(ctx) require.NoError(t, err) valid = trie.VerifyMerkleProof(htr[:], nextSCRoot[:], v2.NextSyncCommitteeGeneralizedIndex(), proof) require.Equal(t, true, valid) }) t.Run("finalized root", func(t *testing.T) { finalizedRoot := st.FinalizedCheckpoint().Root // Verify the Merkle proof. htr, err = st.HashTreeRoot(ctx) require.NoError(t, err) proof, err := st.FinalizedRootProof(ctx) require.NoError(t, err) gIndex := v2.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) require.NoError(t, err) cpt := st.FinalizedCheckpoint() require.NoError(t, err) // Edit the checkpoint. cpt.Epoch = 100 require.NoError(t, st.SetFinalizedCheckpoint(cpt)) // Produce a proof for the finalized root. proof, err := st.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 := st.FinalizedCheckpoint().Root gIndex := v2.FinalizedRootGeneralizedIndex() valid := trie.VerifyMerkleProof(currentRoot[:], finalizedRoot, gIndex, proof) require.Equal(t, false, valid) newRoot, err := st.HashTreeRoot(ctx) require.NoError(t, err) valid = trie.VerifyMerkleProof(newRoot[:], finalizedRoot, gIndex, proof) require.Equal(t, true, valid) }) }