erigon-pulse/cl/phase1/forkchoice/fork_choice_test.go
2024-01-01 22:18:11 +01:00

152 lines
7.0 KiB
Go

package forkchoice_test
import (
"context"
_ "embed"
"fmt"
"testing"
"github.com/ledgerwatch/erigon/cl/antiquary/tests"
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
"github.com/ledgerwatch/erigon/cl/phase1/core/state"
"github.com/ledgerwatch/erigon/cl/phase1/forkchoice"
"github.com/ledgerwatch/erigon/cl/phase1/forkchoice/fork_graph"
"github.com/ledgerwatch/erigon/cl/pool"
"github.com/ledgerwatch/erigon/cl/transition"
"github.com/spf13/afero"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cl/utils"
"github.com/stretchr/testify/require"
)
//go:embed test_data/anchor_state.ssz_snappy
var anchorStateEncoded []byte
//go:embed test_data/block_0x3af8b5b42ca135c75b32abb32b3d71badb73695d3dc638bacfb6c8b7bcbee1a9.ssz_snappy
var block3aEncoded []byte
//go:embed test_data/block_0xc2788d6005ee2b92c3df2eff0aeab0374d155fa8ca1f874df305fa376ce334cf.ssz_snappy
var blockc2Encoded []byte
//go:embed test_data/block_0xd4503d46e43df56de4e19acb0f93b3b52087e422aace49a7c3816cf59bafb0ad.ssz_snappy
var blockd4Encoded []byte
//go:embed test_data/attestation_0xfb924d35b2888d9cd70e6879c1609e6cad7ea3b028a501967747d96e49068cb6.ssz_snappy
var attestationEncoded []byte
// this is consensus spec test altair/forkchoice/ex_ante/ex_ante_attestations_is_greater_than_proposer_boost_with_boost
func TestForkChoiceBasic(t *testing.T) {
expectedCheckpoint := solid.NewCheckpointFromParameters(libcommon.HexToHash("0x564d76d91f66c1fb2977484a6184efda2e1c26dd01992e048353230e10f83201"), 0)
// Decode test blocks
block0x3a, block0xc2, block0xd4 := cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig), cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig), cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig)
require.NoError(t, utils.DecodeSSZSnappy(block0x3a, block3aEncoded, int(clparams.AltairVersion)))
require.NoError(t, utils.DecodeSSZSnappy(block0xc2, blockc2Encoded, int(clparams.AltairVersion)))
require.NoError(t, utils.DecodeSSZSnappy(block0xd4, blockd4Encoded, int(clparams.AltairVersion)))
// decode test attestation
testAttestation := &solid.Attestation{}
require.NoError(t, utils.DecodeSSZSnappy(testAttestation, attestationEncoded, int(clparams.AltairVersion)))
// Initialize forkchoice store
anchorState := state.New(&clparams.MainnetBeaconConfig)
require.NoError(t, utils.DecodeSSZSnappy(anchorState, anchorStateEncoded, int(clparams.AltairVersion)))
pool := pool.NewOperationsPool(&clparams.MainnetBeaconConfig)
store, err := forkchoice.NewForkChoiceStore(context.Background(), anchorState, nil, nil, pool, fork_graph.NewForkGraphDisk(anchorState, afero.NewMemMapFs()))
require.NoError(t, err)
// first steps
store.OnTick(0)
store.OnTick(12)
require.NoError(t, store.OnBlock(block0x3a, false, true))
// Check if we get correct status (1)
require.Equal(t, store.Time(), uint64(12))
require.Equal(t, store.ProposerBoostRoot(), libcommon.HexToHash("0xc9bd7bcb6dfa49dc4e5a67ca75e89062c36b5c300bc25a1b31db4e1a89306071"))
require.Equal(t, store.JustifiedCheckpoint(), expectedCheckpoint)
require.Equal(t, store.FinalizedCheckpoint(), expectedCheckpoint)
headRoot, headSlot, err := store.GetHead()
require.NoError(t, err)
require.Equal(t, headRoot, libcommon.HexToHash("0xc9bd7bcb6dfa49dc4e5a67ca75e89062c36b5c300bc25a1b31db4e1a89306071"))
require.Equal(t, headSlot, uint64(1))
// process another tick and another block
store.OnTick(36)
require.NoError(t, store.OnBlock(block0xc2, false, true))
// Check if we get correct status (2)
require.Equal(t, store.Time(), uint64(36))
require.Equal(t, store.ProposerBoostRoot(), libcommon.HexToHash("0x744cc484f6503462f0f3a5981d956bf4fcb3e57ab8687ed006467e05049ee033"))
require.Equal(t, store.JustifiedCheckpoint(), expectedCheckpoint)
require.Equal(t, store.FinalizedCheckpoint(), expectedCheckpoint)
headRoot, headSlot, err = store.GetHead()
require.NoError(t, err)
require.Equal(t, headSlot, uint64(3))
require.Equal(t, headRoot, libcommon.HexToHash("0x744cc484f6503462f0f3a5981d956bf4fcb3e57ab8687ed006467e05049ee033"))
// last block
require.NoError(t, store.OnBlock(block0xd4, false, true))
require.Equal(t, store.Time(), uint64(36))
require.Equal(t, store.ProposerBoostRoot(), libcommon.HexToHash("0x744cc484f6503462f0f3a5981d956bf4fcb3e57ab8687ed006467e05049ee033"))
require.Equal(t, store.JustifiedCheckpoint(), expectedCheckpoint)
require.Equal(t, store.FinalizedCheckpoint(), expectedCheckpoint)
headRoot, headSlot, err = store.GetHead()
require.NoError(t, err)
require.Equal(t, headSlot, uint64(3))
require.Equal(t, headRoot, libcommon.HexToHash("0x744cc484f6503462f0f3a5981d956bf4fcb3e57ab8687ed006467e05049ee033"))
// lastly do attestation
require.NoError(t, store.OnAttestation(testAttestation, false))
// Try processing a voluntary exit
err = store.OnVoluntaryExit(&cltypes.SignedVoluntaryExit{
VoluntaryExit: &cltypes.VoluntaryExit{
Epoch: 0,
ValidatorIndex: 0,
},
}, true)
require.NoError(t, err)
// Try processing a bls execution change exit
err = store.OnBlsToExecutionChange(&cltypes.SignedBLSToExecutionChange{
Message: &cltypes.BLSToExecutionChange{
ValidatorIndex: 0,
},
}, true)
require.NoError(t, err)
require.Equal(t, len(pool.VoluntaryExistsPool.Raw()), 1)
}
func TestForkChoiceChainBellatrix(t *testing.T) {
blocks, anchorState, _ := tests.GetBellatrixRandom()
intermediaryState, err := anchorState.Copy()
require.NoError(t, err)
intermediaryBlockRoot := blocks[0].Block.ParentRoot
for i := 0; i < 35; i++ {
require.NoError(t, transition.TransitionState(intermediaryState, blocks[i], nil, false))
intermediaryBlockRoot, err = blocks[i].Block.HashSSZ()
require.NoError(t, err)
}
// Initialize forkchoice store
pool := pool.NewOperationsPool(&clparams.MainnetBeaconConfig)
store, err := forkchoice.NewForkChoiceStore(context.Background(), anchorState, nil, nil, pool, fork_graph.NewForkGraphDisk(anchorState, afero.NewMemMapFs()))
store.OnTick(2000)
require.NoError(t, err)
for _, block := range blocks {
require.NoError(t, store.OnBlock(block, false, true))
}
root1, err := blocks[20].Block.HashSSZ()
require.NoError(t, err)
rewards, ok := store.BlockRewards(libcommon.Hash(root1))
require.True(t, ok)
require.Equal(t, rewards.Attestations, uint64(0x511ad))
// test randao mix
mixes := solid.NewHashVector(int(clparams.MainnetBeaconConfig.EpochsPerHistoricalVector))
require.True(t, store.RandaoMixes(intermediaryBlockRoot, mixes))
for i := 0; i < mixes.Length(); i++ {
require.Equal(t, mixes.Get(i), intermediaryState.RandaoMixes().Get(i), fmt.Sprintf("mixes mismatch at index %d, have: %x, expected: %x", i, mixes.Get(i), intermediaryState.RandaoMixes().Get(i)))
}
currentIntermediarySyncCommittee, nextIntermediarySyncCommittee, ok := store.GetSyncCommittees(intermediaryBlockRoot)
require.True(t, ok)
require.Equal(t, intermediaryState.CurrentSyncCommittee(), currentIntermediarySyncCommittee)
require.Equal(t, intermediaryState.NextSyncCommittee(), nextIntermediarySyncCommittee)
}