Feature: Prevent loading an existing data directory for the wrong network (#2825)

* Prevent loading an existing data directory for the wrong network

* Fix and add more info
This commit is contained in:
andri lim 2024-11-06 09:01:42 +07:00 committed by GitHub
parent f0f607b23b
commit 6c3bbbf22c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 112 additions and 2 deletions

View File

@ -0,0 +1,84 @@
# Nimbus
# Copyright (c) 2021-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.
{.push raises: [].}
import
std/[typetraits, tables],
eth/common/base,
eth/common/times,
eth/common/hashes,
eth/common/addresses,
stew/endians2,
stint,
nimcrypto/sha2,
./chain_config
# ------------------------------------------------------------------------------
# When the client doing initialization step, it will go through
# complicated steps before the genesis hash is ready. See `CommonRef.init`.
# If the genesis happen to exists in database belonging to other network,
# it will replace the one in CommonRef cache.
# That is the reason why using genesis header or genesis hash + ChainId is
# not a good solution to prevent loading existing data directory for
# the wrong network.
# But the ChainConfig + raw Genesis hash will make the job done before
# CommonRef creation.
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Private helper functions
# ------------------------------------------------------------------------------
func update(ctx: var sha256, val: uint64 | UInt256) =
ctx.update(val.toBytesLE)
func update(ctx: var sha256, val: ChainId | EthTime | NetworkId) =
ctx.update(distinctBase val)
func update(ctx: var sha256, val: bool) =
ctx.update([val.byte])
func update(ctx: var sha256, val: Hash32 | Bytes8 | Bytes32 | Address) =
ctx.update(val.data)
func update[T](ctx: var sha256, val: Opt[T]) =
if val.isSome:
ctx.update(val.get)
func update[K, V](ctx: var sha256, val: Table[K, V]) =
mixin update
for k, v in val:
ctx.update(k)
ctx.update(v)
func update[T: object](ctx: var sha256, val: T) =
for f in fields(val):
ctx.update(f)
func update[T: ref](ctx: var sha256, val: T) =
for f in fields(val[]):
ctx.update(f)
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
func calcHash*(networkId: NetworkId, conf: ChainConfig, genesis: Genesis): Hash32 =
var ctx: sha256
ctx.init()
ctx.update(networkId)
ctx.update(conf)
if genesis.isNil.not:
ctx.update(genesis)
ctx.finish(result.data)
ctx.clear()
func calcHash*(networkId: NetworkId, params: NetworkParams): Hash32 =
calcHash(networkId, params.config, params.genesis)

View File

@ -21,7 +21,7 @@ type
canonicalHeadHash = 4 canonicalHeadHash = 4
slotHashToSlot = 5 slotHashToSlot = 5
contractHash = 6 contractHash = 6
transitionStatus = 7 dataDirId = 7
safeHash = 8 safeHash = 8
finalizedHash = 9 finalizedHash = 9
beaconState = 10 beaconState = 10
@ -59,6 +59,10 @@ func canonicalHeadHashKey*(): DbKey {.inline.} =
result.data[0] = byte ord(canonicalHeadHash) result.data[0] = byte ord(canonicalHeadHash)
result.dataEndPos = 1 result.dataEndPos = 1
func dataDirIdKey*(): DbKey {.inline.} =
result.data[0] = byte ord(dataDirId)
result.dataEndPos = 1
func slotHashToSlotKey*(h: openArray[byte]): DbKey {.inline.} = func slotHashToSlotKey*(h: openArray[byte]): DbKey {.inline.} =
doAssert(h.len == 32) doAssert(h.len == 32)
result.data[0] = byte ord(slotHashToSlot) result.data[0] = byte ord(slotHashToSlot)

View File

@ -17,6 +17,7 @@ import
metrics, metrics,
metrics/chronicles_support, metrics/chronicles_support,
kzg4844/kzg, kzg4844/kzg,
stew/byteutils,
./rpc, ./rpc,
./version, ./version,
./constants, ./constants,
@ -24,7 +25,9 @@ import
./nimbus_import, ./nimbus_import,
./core/eip4844, ./core/eip4844,
./db/core_db/persistent, ./db/core_db/persistent,
./sync/handlers ./db/storage_types,
./sync/handlers,
./common/chain_config_hash
from beacon_chain/nimbus_binary_common import setupFileLimits from beacon_chain/nimbus_binary_common import setupFileLimits
@ -153,6 +156,24 @@ proc setupMetrics(nimbus: NimbusNode, conf: NimbusConf) =
nimbus.metricsServer = res.get nimbus.metricsServer = res.get
waitFor nimbus.metricsServer.start() waitFor nimbus.metricsServer.start()
proc preventLoadingDataDirForTheWrongNetwork(db: CoreDbRef; conf: NimbusConf) =
let
kvt = db.ctx.getKvt()
calculatedId = calcHash(conf.networkId, conf.networkParams)
dataDirIdBytes = kvt.get(dataDirIdKey().toOpenArray).valueOr:
# an empty database
info "Writing data dir ID", ID=calculatedId
kvt.put(dataDirIdKey().toOpenArray, calculatedId.data).isOkOr:
fatal "Cannot write data dir ID", ID=calculatedId
quit(QuitFailure)
return
if calculatedId.data != dataDirIdBytes:
fatal "Data dir already initialized with other network configuration",
get=dataDirIdBytes.toHex,
expected=calculatedId
quit(QuitFailure)
proc run(nimbus: NimbusNode, conf: NimbusConf) = proc run(nimbus: NimbusNode, conf: NimbusConf) =
## logging ## logging
setLogLevel(conf.logLevel) setLogLevel(conf.logLevel)
@ -192,6 +213,7 @@ proc run(nimbus: NimbusNode, conf: NimbusConf) =
string conf.dataDir, string conf.dataDir,
conf.dbOptions(noKeyCache = conf.cmd == NimbusCmd.`import`)) conf.dbOptions(noKeyCache = conf.cmd == NimbusCmd.`import`))
preventLoadingDataDirForTheWrongNetwork(coreDB, conf)
setupMetrics(nimbus, conf) setupMetrics(nimbus, conf)
let com = CommonRef.new( let com = CommonRef.new(