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.
This commit is contained in:
Jacek Sieka 2021-04-20 14:17:11 +02:00 committed by Zahary Karadjov
parent e1a8049ed5
commit 54d6884c89
No known key found for this signature in database
GPG Key ID: C8936F8A3073D609
2 changed files with 42 additions and 3 deletions

View File

@ -567,7 +567,7 @@ proc getBlockSummary*(db: BeaconChainDB, key: Eth2Digest): Opt[BeaconBlockSummar
result.err()
proc getStateOnlyMutableValidators(
db: BeaconChainDB, key: Eth2Digest, output: var BeaconState,
db: BeaconChainDB, store: KvStoreRef, key: Eth2Digest, output: var BeaconState,
rollback: RollbackProc): bool =
## Load state into `output` - BeaconState is large so we want to avoid
## re-allocating it if possible
@ -580,7 +580,7 @@ proc getStateOnlyMutableValidators(
# TODO RVO is inefficient for large objects:
# https://github.com/nim-lang/Nim/issues/13879
case db.stateStore.getEncoded(
case store.getEncoded(
subkey(
BeaconStateNoImmutableValidators, key),
isomorphicCast[BeaconStateNoImmutableValidators](output))
@ -620,7 +620,7 @@ proc getState*(
# https://github.com/nim-lang/Nim/issues/14126
# TODO RVO is inefficient for large objects:
# https://github.com/nim-lang/Nim/issues/13879
if getStateOnlyMutableValidators(db, key, output, rollback):
if getStateOnlyMutableValidators(db, db.stateStore, key, output, rollback):
return true
case db.backend.getEncoded(subkey(BeaconState, key), output)
@ -682,6 +682,38 @@ proc containsState*(db: BeaconChainDB, key: Eth2Digest): bool =
proc containsStateDiff*(db: BeaconChainDB, key: Eth2Digest): bool =
db.backend.contains(subkey(BeaconStateDiff, key)).expect("working database (disk broken/full?)")
proc repairGenesisState*(db: BeaconChainDB, key: Eth2Digest): KvResult[void] =
# Nimbus 1.0 reads and writes writes genesis BeaconState to `backend`
# Nimbus 1.1 writes a genesis BeaconStateNoImmutableValidators to `backend` and
# reads both BeaconState and BeaconStateNoImmutableValidators from `backend`
# Nimbus 1.2 writes a genesis BeaconStateNoImmutableValidators to `stateStore`
# and reads BeaconState from `backend` and BeaconStateNoImmutableValidators
# from `stateStore`. This means that 1.2 cannot read a database created with
# 1.1 and earlier versions can't read databases created with either of 1.1
# and 1.2.
# Here, we will try to repair the database so that no matter what, there will
# be a `BeaconState` in `backend`:
if ? db.backend.contains(subkey(BeaconState, key)):
# No compatibility issues, life goes on
discard
elif ? db.backend.contains(subkey(BeaconStateNoImmutableValidators, key)):
# 1.1 writes this but not a full state - rewrite a full state
var output = new BeaconState
if not getStateOnlyMutableValidators(db, db.backend, key, output[], noRollback):
return err("Cannot load partial state")
putStateFull(db, output[])
elif ? db.stateStore.contains(subkey(BeaconStateNoImmutableValidators, key)):
# 1.2 writes this but not a full state - rewrite a full state
var output = new BeaconState
if not getStateOnlyMutableValidators(db, db.stateStore, key, output[], noRollback):
return err("Cannot load partial state")
putStateFull(db, output[])
ok()
iterator getAncestors*(db: BeaconChainDB, root: Eth2Digest):
TrustedSignedBeaconBlock =
## Load a chain of ancestors for blck - returns a list of blocks with the

View File

@ -1099,6 +1099,11 @@ proc isInitialized*(T: type ChainDAGRef, db: BeaconChainDB): bool =
if not (headBlock.isSome() and tailBlock.isSome()):
return false
# 1.1 and 1.2 need a compatibility hack
if db.repairGenesisState(tailBlock.get().message.state_root).isErr():
notice "Could not repair genesis state"
return false
if not db.containsState(tailBlock.get().message.state_root):
return false
@ -1120,6 +1125,7 @@ proc preInit*(
validators = tailState.validators.len()
db.putState(tailState)
db.putStateFull(tailState)
db.putBlock(tailBlock)
db.putTailBlock(tailBlock.root)
db.putHeadBlock(tailBlock.root)
@ -1130,6 +1136,7 @@ proc preInit*(
else:
doAssert genesisState.slot == GENESIS_SLOT
db.putState(genesisState)
db.putStateFull(genesisState)
let genesisBlock = get_initial_beacon_block(genesisState)
db.putBlock(genesisBlock)
db.putStateRoot(genesisBlock.root, GENESIS_SLOT, genesisBlock.message.state_root)