Skip to content

Commit b992421

Browse files
committed
Better error-handling for the slashingdb import/export feature
* Error when specifying an invalid --data-dir (or --validator-dir) * Error when entering an invalid validator public key (e.g. invalid hex value) * Warning when attempting to export a validator not present in the local database Some unnecessary remains of the v1 mode has been removed as well
1 parent 5fadaa2 commit b992421

File tree

7 files changed

+50
-110
lines changed

7 files changed

+50
-110
lines changed

beacon_chain/conf.nim

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@
99

1010
import
1111
strutils, os, options, unicode, uri,
12+
1213
chronicles, chronicles/options as chroniclesOptions,
1314
confutils, confutils/defs, confutils/std/net, stew/shims/net as stewNet,
14-
stew/io2, unicodedb/properties, normalize,
15+
stew/[io2, byteutils], unicodedb/properties, normalize,
1516
eth/common/eth_types as commonEthTypes, eth/net/nat,
1617
eth/p2p/discoveryv5/enr,
1718
json_serialization, web3/[ethtypes, confutils_defs],
18-
spec/[crypto, keystore, digest, datatypes, network],
19+
20+
./spec/[crypto, keystore, digest, datatypes, network],
1921
./networking/network_metadata,
20-
filepath
22+
./validators/slashing_protection_common,
23+
./filepath
2124

2225
export
2326
uri,
@@ -505,7 +508,7 @@ type
505508
desc: "Limit the export to specific validators " &
506509
"(specified as numeric indices or public keys)"
507510
abbr: "v"
508-
name: "validator" }: seq[string]
511+
name: "validator" }: seq[PubKey0x]
509512
exportedInterchangeFile* {.
510513
desc: "EIP-3076 slashing protection interchange file to export"
511514
argument }: OutFile
@@ -559,8 +562,9 @@ type
559562
name: "rpc-port" }: Port
560563

561564
rpcAddress* {.
562-
defaultValue: defaultAdminListenAddress
563-
desc: "Address of the server to connect to for RPC [=127.0.0.1]"
565+
desc: "Address of the server to connect to for RPC"
566+
defaultValue: init(ValidIpAddress, "127.0.0.1")
567+
defaultValueDesc: "127.0.0.1"
564568
name: "rpc-address" }: ValidIpAddress
565569

566570
retryDelay* {.
@@ -623,6 +627,13 @@ func parseCmdArg*(T: type Uri, input: TaintedString): T
623627
func completeCmdArg*(T: type Uri, input: TaintedString): seq[string] =
624628
return @[]
625629

630+
func parseCmdArg*(T: type PubKey0x, input: TaintedString): T
631+
{.raises: [ValueError, Defect].} =
632+
PubKey0x(hexToPaddedByteArray[RawPubKeySize](input.string))
633+
634+
func completeCmdArg*(T: type PubKey0x, input: TaintedString): seq[string] =
635+
return @[]
636+
626637
func parseCmdArg*(T: type Checkpoint, input: TaintedString): T
627638
{.raises: [ValueError, Defect].} =
628639
let sepIdx = find(input.string, ':')

beacon_chain/nimbus_beacon_node.nim

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,8 +1962,7 @@ proc doSlashingImport(conf: BeaconNodeConf) {.raises: [SerializationError, IOErr
19621962
genesis_validators_root = Eth2Digest spdir.metadata.genesis_validators_root,
19631963
basePath = dir,
19641964
dbname = filetrunc,
1965-
modes = {kCompleteArchiveV2},
1966-
disagreementBehavior = kChooseV2
1965+
modes = {kCompleteArchive}
19671966
)
19681967

19691968
# Now import the slashing interchange file

beacon_chain/validators/slashing_protection.nim

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,15 @@ export chronicles
4545

4646
type
4747
SlashProtDBMode* = enum
48-
kCompleteArchiveV1 # Complete Format V1 backend (saves all attestations)
49-
kCompleteArchiveV2 # Complete Format V2 backend (saves all attestations)
50-
kLowWatermarkV2 # Low-Watermark Format V2 backend (prunes attestations)
48+
kCompleteArchive # Complete Format V2 backend (saves all attestations)
49+
kLowWatermark # Low-Watermark Format V2 backend (prunes attestations)
5150

5251
SlashingProtectionDB* = ref object
5352
## Database storing the blocks attested
5453
## by validators attached to a beacon node
5554
## or validator client.
5655
db_v2*: SlashingProtectionDB_v2
5756
modes: set[SlashProtDBMode]
58-
disagreementBehavior: DisagreementBehavior
59-
60-
DisagreementBehavior* = enum
61-
## How to handle disagreement between DB versions
62-
kCrash
63-
kChooseV1
64-
kChooseV2
6557

6658
# DB Multiversioning
6759
# -------------------------------------------------------------
@@ -78,20 +70,18 @@ proc init*(
7870
genesis_validators_root: Eth2Digest,
7971
basePath, dbname: string,
8072
modes: set[SlashProtDBMode],
81-
disagreementBehavior: DisagreementBehavior
8273
): T =
8374
## Initialize or load a slashing protection DB
8475
## This is for Beacon Node usage
8576
## Handles DB version migration
8677

8778
doAssert modes.card >= 1, "No slashing protection mode chosen. Choose a v1, a v2 or v1 and v2 slashing DB mode."
8879
doAssert not(
89-
kCompleteArchiveV2 in modes and
90-
kLowWatermarkV2 in modes), "Mode(s): " & $modes & ". Choose only one of V2 DB modes."
80+
kCompleteArchive in modes and
81+
kLowWatermark in modes), "Mode(s): " & $modes & ". Choose only one of V2 DB modes."
9182

9283
new result
9384
result.modes = modes
94-
result.disagreementBehavior = disagreementBehavior
9585

9686
let (db, requiresMigration) = SlashingProtectionDB_v2.initCompatV1(
9787
genesis_validators_root,
@@ -142,8 +132,7 @@ proc init*(
142132
## Does not handle migration
143133
init(
144134
T, genesis_validators_root, basePath, dbname,
145-
modes = {kLowWatermarkV2},
146-
disagreementBehavior = kChooseV2
135+
modes = {kLowWatermark}
147136
)
148137

149138
proc loadUnchecked*(
@@ -158,15 +147,15 @@ proc loadUnchecked*(
158147
new result
159148

160149
result.modes = {}
161-
result.disagreementBehavior = kCrash
162150

163151
try:
164152
result.db_v2 = SlashingProtectionDB_v2.loadUnchecked(
165153
basePath, dbname, readOnly
166154
)
167-
result.modes.incl(kCompleteArchiveV2)
168-
except:
169-
result.disagreementBehavior = kChooseV1
155+
result.modes.incl(kCompleteArchive)
156+
except CatchableError as err:
157+
error "Failed to load the Slashing protection database", err = err.msg
158+
quit 1
170159

171160
proc close*(db: SlashingProtectionDB) =
172161
## Close a slashing protection database
@@ -280,10 +269,10 @@ proc pruneAfterFinalization*(
280269
## This ensures that even if pruning is called with an incorrect epoch
281270
## slashing protection can fallback to the minimal / high-watermark protection mode.
282271
##
283-
## Pruning is only done if pruning is enabled (DB in kLowWatermarkV2 mode)
272+
## Pruning is only done if pruning is enabled (DB in kLowWatermark mode)
284273
## Pruning is only triggered on v2 database.
285274

286-
if kLowWatermarkV2 in db.modes:
275+
if kLowWatermark in db.modes:
287276
db.db_v2.pruneAfterFinalization(finalizedEpoch)
288277

289278
# The high-level import/export functions are
@@ -305,7 +294,7 @@ proc toSPDIR*(db: SlashingProtectionDB): SPDIR
305294
proc exportSlashingInterchange*(
306295
db: SlashingProtectionDB,
307296
path: string,
308-
validatorsWhiteList: seq[string] = @[],
297+
validatorsWhiteList: seq[PubKey0x] = @[],
309298
prettify = true) {.raises: [Defect, IOError].} =
310299
## Export a database to the Slashing Protection Database Interchange Format
311300
# We could modify toSPDIR to do the filtering directly
@@ -317,7 +306,14 @@ proc exportSlashingInterchange*(
317306
# O(a log b) with b the number of validators to keep
318307
# and a the total number of validators in DB
319308
let validators = validatorsWhiteList.sorted()
320-
spdir.data.keepItIf(validators.binarySearch("0x" & it.pubkey.PubKeyBytes.toHex()) != -1)
309+
spdir.data.keepItIf(validators.binarySearch(it.pubkey) != -1)
310+
311+
if spdir.data.len != validatorsWhiteList.len:
312+
let exportedKeys = spdir.data.mapIt(it.pubkey).sorted()
313+
for v in validators:
314+
if exportedKeys.binarySearch(v) == -1:
315+
warn "Specified validator key not found in the slashing database",
316+
key = v.PubKeyBytes.toHex
321317

322318
Json.saveFile(path, spdir, prettify)
323319
echo "Exported slashing protection DB to '", path, "'"

beacon_chain/validators/slashing_protection_common.nim

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import
1111
# Stdlib
12-
std/[typetraits, strutils, algorithm, sequtils],
12+
std/[typetraits, strutils, algorithm],
1313
# Status
1414
eth/db/[kvstore, kvstore_sqlite3],
1515
stew/results,
@@ -170,6 +170,15 @@ func `==`*(a, b: BadVote): bool =
170170
of BadVoteKind.DatabaseError:
171171
true
172172

173+
template `==`*(a, b: PubKey0x): bool =
174+
PubKeyBytes(a) == PubKeyBytes(b)
175+
176+
template `<`*(a, b: PubKey0x): bool =
177+
PubKeyBytes(a) < PubKeyBytes(b)
178+
179+
template cmp*(a, b: PubKey0x): bool =
180+
cmp(PubKeyBytes(a), PubKeyBytes(b))
181+
173182
func `==`*(a, b: BadProposal): bool =
174183
## Comparison operator.
175184
## Used implictily by Result when comparing the

beacon_chain/validators/slashing_protection_v1.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ proc loadUnchecked*(
398398
subkey(kGenesisValidatorsRoot)
399399
).get(), "The Slashing DB is missing genesis information"
400400

401-
result = T(backend: backend)
401+
T(backend: backend)
402402

403403
proc close*(db: SlashingProtectionDB_v1) =
404404
discard db.backend.close()

docs/slashing_interchange.md

Lines changed: 0 additions & 75 deletions
This file was deleted.

0 commit comments

Comments
 (0)