Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions nimbus/common/chain_config_hash.nim
Original file line number Diff line number Diff line change
@@ -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)
6 changes: 5 additions & 1 deletion nimbus/db/storage_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type
canonicalHeadHash = 4
slotHashToSlot = 5
contractHash = 6
transitionStatus = 7
dataDirId = 7
safeHash = 8
finalizedHash = 9
beaconState = 10
Expand Down Expand Up @@ -59,6 +59,10 @@ func canonicalHeadHashKey*(): DbKey {.inline.} =
result.data[0] = byte ord(canonicalHeadHash)
result.dataEndPos = 1

func dataDirIdKey*(): DbKey {.inline.} =
result.data[0] = byte ord(dataDirId)
result.dataEndPos = 1

func slotHashToSlotKey*(h: openArray[byte]): DbKey {.inline.} =
doAssert(h.len == 32)
result.data[0] = byte ord(slotHashToSlot)
Expand Down
24 changes: 23 additions & 1 deletion nimbus/nimbus_execution_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ import
metrics,
metrics/chronicles_support,
kzg4844/kzg,
stew/byteutils,
./rpc,
./version,
./constants,
./nimbus_desc,
./nimbus_import,
./core/eip4844,
./db/core_db/persistent,
./sync/handlers
./db/storage_types,
./sync/handlers,
./common/chain_config_hash

from beacon_chain/nimbus_binary_common import setupFileLimits

Expand Down Expand Up @@ -153,6 +156,24 @@ proc setupMetrics(nimbus: NimbusNode, conf: NimbusConf) =
nimbus.metricsServer = res.get
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) =
## logging
setLogLevel(conf.logLevel)
Expand Down Expand Up @@ -192,6 +213,7 @@ proc run(nimbus: NimbusNode, conf: NimbusConf) =
string conf.dataDir,
conf.dbOptions(noKeyCache = conf.cmd == NimbusCmd.`import`))

preventLoadingDataDirForTheWrongNetwork(coreDB, conf)
setupMetrics(nimbus, conf)

let com = CommonRef.new(
Expand Down
Loading