Skip to content

Commit 54d6884

Browse files
arnetheduckzah
authored andcommitted
fix sync issue when upgrading from 1.1.0-inited db
This patch writes a full genesis state to `kvstore` if one was missing, which fixes 1.2.0 restarting sync when upgrading from 1.1.0, or when downgrading to a pre-1.1.0 release.
1 parent e1a8049 commit 54d6884

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

beacon_chain/beacon_chain_db.nim

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ proc getBlockSummary*(db: BeaconChainDB, key: Eth2Digest): Opt[BeaconBlockSummar
567567
result.err()
568568

569569
proc getStateOnlyMutableValidators(
570-
db: BeaconChainDB, key: Eth2Digest, output: var BeaconState,
570+
db: BeaconChainDB, store: KvStoreRef, key: Eth2Digest, output: var BeaconState,
571571
rollback: RollbackProc): bool =
572572
## Load state into `output` - BeaconState is large so we want to avoid
573573
## re-allocating it if possible
@@ -580,7 +580,7 @@ proc getStateOnlyMutableValidators(
580580
# TODO RVO is inefficient for large objects:
581581
# https://github.com/nim-lang/Nim/issues/13879
582582

583-
case db.stateStore.getEncoded(
583+
case store.getEncoded(
584584
subkey(
585585
BeaconStateNoImmutableValidators, key),
586586
isomorphicCast[BeaconStateNoImmutableValidators](output))
@@ -620,7 +620,7 @@ proc getState*(
620620
# https://github.com/nim-lang/Nim/issues/14126
621621
# TODO RVO is inefficient for large objects:
622622
# https://github.com/nim-lang/Nim/issues/13879
623-
if getStateOnlyMutableValidators(db, key, output, rollback):
623+
if getStateOnlyMutableValidators(db, db.stateStore, key, output, rollback):
624624
return true
625625

626626
case db.backend.getEncoded(subkey(BeaconState, key), output)
@@ -682,6 +682,38 @@ proc containsState*(db: BeaconChainDB, key: Eth2Digest): bool =
682682
proc containsStateDiff*(db: BeaconChainDB, key: Eth2Digest): bool =
683683
db.backend.contains(subkey(BeaconStateDiff, key)).expect("working database (disk broken/full?)")
684684

685+
proc repairGenesisState*(db: BeaconChainDB, key: Eth2Digest): KvResult[void] =
686+
# Nimbus 1.0 reads and writes writes genesis BeaconState to `backend`
687+
# Nimbus 1.1 writes a genesis BeaconStateNoImmutableValidators to `backend` and
688+
# reads both BeaconState and BeaconStateNoImmutableValidators from `backend`
689+
# Nimbus 1.2 writes a genesis BeaconStateNoImmutableValidators to `stateStore`
690+
# and reads BeaconState from `backend` and BeaconStateNoImmutableValidators
691+
# from `stateStore`. This means that 1.2 cannot read a database created with
692+
# 1.1 and earlier versions can't read databases created with either of 1.1
693+
# and 1.2.
694+
# Here, we will try to repair the database so that no matter what, there will
695+
# be a `BeaconState` in `backend`:
696+
697+
if ? db.backend.contains(subkey(BeaconState, key)):
698+
# No compatibility issues, life goes on
699+
discard
700+
elif ? db.backend.contains(subkey(BeaconStateNoImmutableValidators, key)):
701+
# 1.1 writes this but not a full state - rewrite a full state
702+
var output = new BeaconState
703+
if not getStateOnlyMutableValidators(db, db.backend, key, output[], noRollback):
704+
return err("Cannot load partial state")
705+
706+
putStateFull(db, output[])
707+
elif ? db.stateStore.contains(subkey(BeaconStateNoImmutableValidators, key)):
708+
# 1.2 writes this but not a full state - rewrite a full state
709+
var output = new BeaconState
710+
if not getStateOnlyMutableValidators(db, db.stateStore, key, output[], noRollback):
711+
return err("Cannot load partial state")
712+
713+
putStateFull(db, output[])
714+
715+
ok()
716+
685717
iterator getAncestors*(db: BeaconChainDB, root: Eth2Digest):
686718
TrustedSignedBeaconBlock =
687719
## Load a chain of ancestors for blck - returns a list of blocks with the

beacon_chain/consensus_object_pools/blockchain_dag.nim

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,11 @@ proc isInitialized*(T: type ChainDAGRef, db: BeaconChainDB): bool =
10991099
if not (headBlock.isSome() and tailBlock.isSome()):
11001100
return false
11011101

1102+
# 1.1 and 1.2 need a compatibility hack
1103+
if db.repairGenesisState(tailBlock.get().message.state_root).isErr():
1104+
notice "Could not repair genesis state"
1105+
return false
1106+
11021107
if not db.containsState(tailBlock.get().message.state_root):
11031108
return false
11041109

@@ -1120,6 +1125,7 @@ proc preInit*(
11201125
validators = tailState.validators.len()
11211126

11221127
db.putState(tailState)
1128+
db.putStateFull(tailState)
11231129
db.putBlock(tailBlock)
11241130
db.putTailBlock(tailBlock.root)
11251131
db.putHeadBlock(tailBlock.root)
@@ -1130,6 +1136,7 @@ proc preInit*(
11301136
else:
11311137
doAssert genesisState.slot == GENESIS_SLOT
11321138
db.putState(genesisState)
1139+
db.putStateFull(genesisState)
11331140
let genesisBlock = get_initial_beacon_block(genesisState)
11341141
db.putBlock(genesisBlock)
11351142
db.putStateRoot(genesisBlock.root, GENESIS_SLOT, genesisBlock.message.state_root)

0 commit comments

Comments
 (0)