From 3cd2973c927cbb33018900f64936cd9e5597a8f8 Mon Sep 17 00:00:00 2001 From: Potuz Date: Thu, 6 Mar 2025 18:42:11 -0300 Subject: [PATCH] Return the genesis block root from last validated checkpoint if zero (#15021) * Return the genesis block root from last validated checkpoint if zero When starting a node we load the last validated checkpoint. On tests or a new node this checkpoint can have the zero blockroot (it returns the finalized checkpoint). This PR ensures that it returns the genesis block root instead. It can't affect runnning code since the root is only used at startup in `setup_forkchoice`. But it may affect tests because now `OptimisticForRoot` will error out if there is no genesis block root set on db. * Terence review * fix test --- beacon-chain/blockchain/chain_info_test.go | 1 + beacon-chain/blockchain/process_block_test.go | 4 +++- beacon-chain/db/kv/validated_checkpoint.go | 14 +++++++++++++- changelog/potuz_last_validated.md | 3 +++ 4 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 changelog/potuz_last_validated.md diff --git a/beacon-chain/blockchain/chain_info_test.go b/beacon-chain/blockchain/chain_info_test.go index e850f36ada..72964b4794 100644 --- a/beacon-chain/blockchain/chain_info_test.go +++ b/beacon-chain/blockchain/chain_info_test.go @@ -582,6 +582,7 @@ func TestService_IsOptimisticForRoot_StateSummaryRecovered(t *testing.T) { br, err := b.Block.HashTreeRoot() require.NoError(t, err) util.SaveBlock(t, context.Background(), beaconDB, b) + require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, [32]byte{})) _, err = c.IsOptimisticForRoot(ctx, br) assert.NoError(t, err) summ, err := beaconDB.StateSummary(ctx, br) diff --git a/beacon-chain/blockchain/process_block_test.go b/beacon-chain/blockchain/process_block_test.go index fc0426eb1b..d6de30ce88 100644 --- a/beacon-chain/blockchain/process_block_test.go +++ b/beacon-chain/blockchain/process_block_test.go @@ -1983,6 +1983,7 @@ func TestNoViableHead_Reboot(t *testing.T) { require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, genesisState, genesisRoot), "Could not save genesis state") require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state") + require.NoError(t, service.cfg.BeaconDB.SaveGenesisBlockRoot(ctx, genesisRoot), "Could not save genesis state") for i := 1; i < 6; i++ { driftGenesisTime(service, int64(i), 0) @@ -2117,6 +2118,7 @@ func TestNoViableHead_Reboot(t *testing.T) { require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, genesisState, jroot)) service.cfg.ForkChoiceStore.SetBalancesByRooter(service.cfg.StateGen.ActiveNonSlashedBalancesByRoot) require.NoError(t, service.StartFromSavedState(genesisState)) + require.NoError(t, service.cfg.BeaconDB.SaveGenesisBlockRoot(ctx, genesisRoot)) // Forkchoice has the genesisRoot loaded at startup require.Equal(t, genesisRoot, service.ensureRootNotZeros(service.cfg.ForkChoiceStore.CachedHeadRoot())) @@ -2126,7 +2128,7 @@ func TestNoViableHead_Reboot(t *testing.T) { require.Equal(t, genesisRoot, bytesutil.ToBytes32(headRoot)) optimistic, err := service.IsOptimistic(ctx) require.NoError(t, err) - require.Equal(t, true, optimistic) + require.Equal(t, false, optimistic) // Check that the node's justified checkpoint does not agree with the // last valid state's justified checkpoint diff --git a/beacon-chain/db/kv/validated_checkpoint.go b/beacon-chain/db/kv/validated_checkpoint.go index 3317cd1a3a..2533a556f0 100644 --- a/beacon-chain/db/kv/validated_checkpoint.go +++ b/beacon-chain/db/kv/validated_checkpoint.go @@ -1,8 +1,10 @@ package kv import ( + "bytes" "context" + "github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" bolt "go.etcd.io/bbolt" @@ -19,7 +21,17 @@ func (s *Store) LastValidatedCheckpoint(ctx context.Context) (*ethpb.Checkpoint, if enc == nil { var finErr error checkpoint, finErr = s.FinalizedCheckpoint(ctx) - return finErr + if finErr != nil { + return finErr + } + if bytes.Equal(checkpoint.Root, params.BeaconConfig().ZeroHash[:]) { + bkt = tx.Bucket(blocksBucket) + r := bkt.Get(genesisBlockRootKey) + if r != nil { + checkpoint.Root = r + } + } + return nil } checkpoint = ðpb.Checkpoint{} return decode(ctx, enc, checkpoint) diff --git a/changelog/potuz_last_validated.md b/changelog/potuz_last_validated.md new file mode 100644 index 0000000000..87e3a2405b --- /dev/null +++ b/changelog/potuz_last_validated.md @@ -0,0 +1,3 @@ +### Ignored + +- When starting a node, check that the last validated checkpoint has zero as root and return the genesis block root