-
Notifications
You must be signed in to change notification settings - Fork 265
/
Copy pathdatatypes.nim
662 lines (531 loc) · 22.8 KB
/
datatypes.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
# beacon_chain
# Copyright (c) 2018-2020 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
# This file contains data types that are part of the spec and thus subject to
# serialization and spec updates.
#
# The spec folder in general contains code that has been hoisted from the
# specification and that follows the spec as closely as possible, so as to make
# it easy to keep up-to-date.
#
# These datatypes are used as specifications for serialization - thus should not
# be altered outside of what the spec says. Likewise, they should not be made
# `ref` - this can be achieved by wrapping them in higher-level
# types / composition
# TODO report compiler crash when this is uncommented
# {.push raises: [Defect].}
{.experimental: "notnil".}
import
macros, hashes, json, strutils, tables,
stew/[byteutils, bitseqs], chronicles,
../ssz/types, ./crypto, ./digest
# TODO Data types:
# Presently, we're reusing the data types from the serialization (uint64) in the
# objects we pass around to the beacon chain logic, thus keeping the two
# similar. This is convenient for keeping up with the specification, but
# will eventually need a more robust approach such that we don't run into
# over- and underflows.
# Some of the open questions are being tracked here:
# https://github.com/ethereum/eth2.0-specs/issues/224
#
# The present approach causes some problems due to how Nim treats unsigned
# integers - here's no high(uint64), arithmetic support is incomplete, there's
# no over/underflow checking available
#
# Eventually, we could also differentiate between user/tainted data and
# internal state that's gone through sanity checks already.
# Constant presets
const const_preset* {.strdefine.} = "mainnet"
when const_preset == "mainnet":
import ./presets/mainnet
export mainnet
elif const_preset == "minimal":
import ./presets/minimal
export minimal
else:
type
Slot* = distinct uint64
Epoch* = distinct uint64
import ./presets/custom
loadCustomPreset const_preset
const
SPEC_VERSION* = "0.11.1" ## \
## Spec version we're aiming to be compatible with, right now
GENESIS_SLOT* = Slot(0)
GENESIS_EPOCH* = (GENESIS_SLOT.int div SLOTS_PER_EPOCH).Epoch ##\
## compute_epoch_at_slot(GENESIS_SLOT)
FAR_FUTURE_EPOCH* = (not 0'u64).Epoch # 2^64 - 1 in spec
# Not part of spec. Still useful, pending removing usage if appropriate.
ZERO_HASH* = Eth2Digest()
# Not part of spec
WEAK_SUBJECTVITY_PERIOD* =
Slot(uint64(4 * 30 * 24 * 60 * 60) div SECONDS_PER_SLOT)
# TODO: This needs revisiting.
# Why was the validator WITHDRAWAL_PERIOD altered in the spec?
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/p2p-interface.md#configuration
ATTESTATION_PROPAGATION_SLOT_RANGE* = 32
SLOTS_PER_ETH1_VOTING_PERIOD* = Slot(EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH)
DEPOSIT_CONTRACT_TREE_DEPTH* = 32
BASE_REWARDS_PER_EPOCH* = 4
template maxSize*(n: int) {.pragma.}
type
# Domains
# ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#domain-types
DomainType* = enum
DOMAIN_BEACON_PROPOSER = 0
DOMAIN_BEACON_ATTESTER = 1
DOMAIN_RANDAO = 2
DOMAIN_DEPOSIT = 3
DOMAIN_VOLUNTARY_EXIT = 4
DOMAIN_SELECTION_PROOF = 5
DOMAIN_AGGREGATE_AND_PROOF = 6
# Phase 1 - Sharding
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase1/beacon-chain.md#misc
DOMAIN_SHARD_PROPOSAL = 128
DOMAIN_SHARD_COMMITTEE = 129
DOMAIN_LIGHT_CLIENT = 130
# Phase 1 - Custody game
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase1/custody-game.md#signature-domain-types
DOMAIN_CUSTODY_BIT_SLASHING = 0x83
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#custom-types
Domain* = array[32, byte]
# https://github.com/nim-lang/Nim/issues/574 and be consistent across
# 32-bit and 64-bit word platforms.
# TODO VALIDATOR_REGISTRY_LIMIT is 1 shl 40 in 0.8.3, and
# proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.}
# in Nim/lib/system/gc.nim quite tightly ties seq addressibility
# to the system wordsize. This lifts smaller, and now incorrect,
# range-limit.
ValidatorIndex* = distinct uint32
Gwei* = uint64
CommitteeIndex* = distinct uint64
BitList*[maxLen: static int] = distinct BitSeq
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#proposerslashing
ProposerSlashing* = object
signed_header_1*: SignedBeaconBlockHeader
signed_header_2*: SignedBeaconBlockHeader
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#attesterslashing
AttesterSlashing* = object
attestation_1*: IndexedAttestation
attestation_2*: IndexedAttestation
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#indexedattestation
IndexedAttestation* = object
# TODO ValidatorIndex, but that doesn't serialize properly
attesting_indices*: List[uint64, MAX_VALIDATORS_PER_COMMITTEE]
data*: AttestationData
signature*: ValidatorSig
CommitteeValidatorsBits* = BitList[MAX_VALIDATORS_PER_COMMITTEE]
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#attestation
Attestation* = object
aggregation_bits*: CommitteeValidatorsBits
data*: AttestationData
signature*: ValidatorSig
Version* = distinct array[4, byte]
ForkDigest* = distinct array[4, byte]
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#forkdata
ForkData* = object
current_version*: Version
genesis_validators_root*: Eth2Digest
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#checkpoint
Checkpoint* = object
epoch*: Epoch
root*: Eth2Digest
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#AttestationData
AttestationData* = object
slot*: Slot
# TODO this is actually a CommitteeIndex; remove some conversions by
# allowing SSZ to directly handle this
index*: uint64
# LMD GHOST vote
beacon_block_root*: Eth2Digest
# FFG vote
source*: Checkpoint
target*: Checkpoint
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#deposit
Deposit* = object
proof*: array[DEPOSIT_CONTRACT_TREE_DEPTH + 1, Eth2Digest] ##\
## Merkle path to deposit root
data*: DepositData
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#depositmessage
DepositMessage* = object
pubkey*: ValidatorPubKey
withdrawal_credentials*: Eth2Digest
amount*: Gwei
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#depositdata
DepositData* = object
pubkey*: ValidatorPubKey
withdrawal_credentials*: Eth2Digest
amount*: uint64
signature*: ValidatorSig # Signing over DepositMessage
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#voluntaryexit
VoluntaryExit* = object
epoch*: Epoch ##\
## Earliest epoch when voluntary exit can be processed
validator_index*: uint64
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#beaconblock
BeaconBlock* = object
## For each slot, a proposer is chosen from the validator pool to propose
## a new block. Once the block as been proposed, it is transmitted to
## validators that will have a chance to vote on it through attestations.
## Each block collects attestations, or votes, on past blocks, thus a chain
## is formed.
slot*: Slot
proposer_index*: uint64
parent_root*: Eth2Digest ##\
## Root hash of the previous block
state_root*: Eth2Digest ##\
## The state root, _after_ this block has been processed
body*: BeaconBlockBody
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#beaconblockheader
BeaconBlockHeader* = object
slot*: Slot
proposer_index*: uint64
parent_root*: Eth2Digest
state_root*: Eth2Digest
body_root*: Eth2Digest
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#beaconblockbody
BeaconBlockBody* = object
randao_reveal*: ValidatorSig
eth1_data*: Eth1Data
graffiti*: Eth2Digest # TODO make that raw bytes
# Operations
proposer_slashings*: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS]
attester_slashings*: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS]
attestations*: List[Attestation, MAX_ATTESTATIONS]
deposits*: List[Deposit, MAX_DEPOSITS]
voluntary_exits*: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#beaconstate
BeaconStateObj* = object
# Versioning
genesis_time*: uint64
genesis_validators_root*: Eth2Digest
slot*: Slot
fork*: Fork
# History
latest_block_header*: BeaconBlockHeader ##\
## `latest_block_header.state_root == ZERO_HASH` temporarily
block_roots*: array[SLOTS_PER_HISTORICAL_ROOT, Eth2Digest] ##\
## Needed to process attestations, older to newer
state_roots*: array[SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
historical_roots*: List[Eth2Digest, HISTORICAL_ROOTS_LIMIT]
# Eth1
eth1_data*: Eth1Data
eth1_data_votes*:
List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH]
eth1_deposit_index*: uint64
# Registry
validators*: List[Validator, VALIDATOR_REGISTRY_LIMIT]
balances*: seq[uint64]
# Randomness
randao_mixes*: array[EPOCHS_PER_HISTORICAL_VECTOR, Eth2Digest]
# Slashings
slashings*: array[EPOCHS_PER_SLASHINGS_VECTOR, uint64] ##\
## Per-epoch sums of slashed effective balances
# Attestations
previous_epoch_attestations*:
List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
current_epoch_attestations*:
List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
# Finality
justification_bits*: uint8 ##\
## Bit set for every recent justified epoch
## Model a Bitvector[4] as a one-byte uint, which should remain consistent
## with ssz/hashing.
previous_justified_checkpoint*: Checkpoint ##\
## Previous epoch snapshot
current_justified_checkpoint*: Checkpoint
finalized_checkpoint*: Checkpoint
BeaconState* = BeaconStateObj
BeaconStateRef* = ref BeaconStateObj not nil
NilableBeaconStateRef* = ref BeaconStateObj
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#validator
Validator* = object
pubkey*: ValidatorPubKey
withdrawal_credentials*: Eth2Digest ##\
## Commitment to pubkey for withdrawals and transfers
effective_balance*: uint64 ##\
## Balance at stake
slashed*: bool
# Status epochs
activation_eligibility_epoch*: Epoch ##\
## When criteria for activation were met
activation_epoch*: Epoch
exit_epoch*: Epoch
withdrawable_epoch*: Epoch ##\
## When validator can withdraw or transfer funds
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#pendingattestation
PendingAttestation* = object
aggregation_bits*: CommitteeValidatorsBits
data*: AttestationData
# TODO this is a Slot
inclusion_delay*: uint64
proposer_index*: uint64
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#historicalbatch
HistoricalBatch* = object
block_roots* : array[SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
state_roots* : array[SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#fork
Fork* = object
# TODO: Spec introduced an alias for Version = array[4, byte]
# and a default parameter to compute_domain
previous_version*: Version
current_version*: Version
epoch*: Epoch ##\
## Epoch of latest fork
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#eth1data
Eth1Data* = object
deposit_root*: Eth2Digest
deposit_count*: uint64
block_hash*: Eth2Digest
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#signingroot
SigningRoot* = object
object_root*: Eth2Digest
domain*: Domain
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#signedvoluntaryexit
SignedVoluntaryExit* = object
message*: VoluntaryExit
signature*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#signedbeaconblock
SignedBeaconBlock* = object
message*: BeaconBlock
signature*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#signedbeaconblockheader
SignedBeaconBlockHeader* = object
message*: BeaconBlockHeader
signature*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/validator.md#aggregateandproof
AggregateAndProof* = object
aggregator_index*: uint64
aggregate*: Attestation
selection_proof*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/validator.md#signedaggregateandproof
SignedAggregateAndProof* = object
message*: AggregateAndProof
signature*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/validator.md#eth1block
Eth1Block* = object
timestamp*: uint64
# All other eth1 block fields
# TODO to be replaced with some magic hash caching
HashedBeaconState* = object
data*: BeaconState
root*: Eth2Digest # hash_tree_root(data)
StateCache* = object
beacon_committee_cache*:
Table[tuple[a: int, b: Eth2Digest], seq[ValidatorIndex]]
active_validator_indices_cache*:
Table[Epoch, seq[ValidatorIndex]]
committee_count_cache*: Table[Epoch, uint64]
macro fieldMaxLen*(x: typed): untyped =
# TODO This macro is a temporary solution for the lack of a
# more proper way to specify the max length of the List[T; N]
# objects in the spec.
# May be replaced with `getCustomPragma` once we upgrade to
# Nim 0.20.2 or with a distinct List type, which would require
# more substantial refactorings in the spec code.
if x.kind != nnkDotExpr:
return newLit(0)
let size = case $x[1]
# Obsolete
of "pubkeys",
"compact_validators",
"aggregation_bits",
"custody_bits": int64(MAX_VALIDATORS_PER_COMMITTEE)
# IndexedAttestation
of "attesting_indices": MAX_VALIDATORS_PER_COMMITTEE
# BeaconBlockBody
of "proposer_slashings": MAX_PROPOSER_SLASHINGS
of "attester_slashings": MAX_ATTESTER_SLASHINGS
of "attestations": MAX_ATTESTATIONS
of "deposits": MAX_DEPOSITS
of "voluntary_exits": MAX_VOLUNTARY_EXITS
# BeaconState
of "historical_roots": HISTORICAL_ROOTS_LIMIT
of "eth1_data_votes":
EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH
of "validators": VALIDATOR_REGISTRY_LIMIT
of "balances": VALIDATOR_REGISTRY_LIMIT
of "previous_epoch_attestations",
"current_epoch_attestations": MAX_ATTESTATIONS *
SLOTS_PER_EPOCH
else: 0
newLit size
func shortValidatorKey*(state: BeaconState, validatorIdx: int): string =
($state.validators[validatorIdx].pubkey)[0..7]
func getDepositMessage*(depositData: DepositData): DepositMessage =
result.pubkey = depositData.pubkey
result.amount = depositData.amount
result.withdrawal_credentials = depositData.withdrawal_credentials
func getDepositMessage*(deposit: Deposit): DepositMessage =
deposit.data.getDepositMessage
template ethTimeUnit(typ: type) {.dirty.} =
proc `+`*(x: typ, y: uint64): typ {.borrow.}
proc `-`*(x: typ, y: uint64): typ {.borrow.}
proc `-`*(x: uint64, y: typ): typ {.borrow.}
# Not closed over type in question (Slot or Epoch)
proc `mod`*(x: typ, y: uint64): uint64 {.borrow.}
proc `div`*(x: typ, y: uint64): uint64 {.borrow.}
proc `div`*(x: uint64, y: typ): uint64 {.borrow.}
proc `-`*(x: typ, y: typ): uint64 {.borrow.}
proc `*`*(x: typ, y: uint64): uint64 {.borrow.}
proc `+=`*(x: var typ, y: typ) {.borrow.}
proc `+=`*(x: var typ, y: uint64) {.borrow.}
proc `-=`*(x: var typ, y: typ) {.borrow.}
proc `-=`*(x: var typ, y: uint64) {.borrow.}
# Comparison operators
proc `<`*(x: typ, y: typ): bool {.borrow.}
proc `<`*(x: typ, y: uint64): bool {.borrow.}
proc `<`*(x: uint64, y: typ): bool {.borrow.}
proc `<=`*(x: typ, y: typ): bool {.borrow.}
proc `<=`*(x: typ, y: uint64): bool {.borrow.}
proc `<=`*(x: uint64, y: typ): bool {.borrow.}
proc `==`*(x: typ, y: typ): bool {.borrow.}
proc `==`*(x: typ, y: uint64): bool {.borrow.}
proc `==`*(x: uint64, y: typ): bool {.borrow.}
# Nim integration
proc `$`*(x: typ): string {.borrow.}
proc hash*(x: typ): Hash {.borrow.}
proc `%`*(x: typ): JsonNode {.borrow.}
# Serialization
proc writeValue*(writer: var JsonWriter, value: typ) =
writeValue(writer, uint64 value)
proc readValue*(reader: var JsonReader, value: var typ) =
value = typ reader.readValue(uint64)
proc writeValue*(writer: var JsonWriter, value: ValidatorIndex) =
writeValue(writer, uint32 value)
proc readValue*(reader: var JsonReader, value: var ValidatorIndex) =
value = ValidatorIndex reader.readValue(uint32)
proc writeValue*(writer: var JsonWriter, value: Version | ForkDigest) =
writeValue(writer, $value)
proc readValue*(reader: var JsonReader, value: var Version) =
let hex = reader.readValue(string)
hexToByteArray(hex, array[4, byte](value))
proc readValue*(reader: var JsonReader, value: var ForkDigest) =
let hex = reader.readValue(string)
hexToByteArray(hex, array[4, byte](value))
# `ValidatorIndex` seq handling.
proc max*(a: ValidatorIndex, b: int) : auto =
max(a.int, b)
proc `[]`*[T](a: var seq[T], b: ValidatorIndex): var T =
a[b.int]
proc `[]`*[T](a: seq[T], b: ValidatorIndex): auto =
a[b.int]
proc `[]=`*[T](a: var seq[T], b: ValidatorIndex, c: T) =
a[b.int] = c
# `ValidatorIndex` Nim integration
proc `==`*(x, y: ValidatorIndex) : bool {.borrow.}
proc hash*(x: ValidatorIndex): Hash {.borrow.}
proc `$`*(x: ValidatorIndex): auto = $(x.int64)
ethTimeUnit Slot
ethTimeUnit Epoch
Json.useCustomSerialization(BeaconState.justification_bits):
read:
let s = reader.readValue(string)
if s.len != 4: raise newException(ValueError, "unexpected number of bytes")
s.parseHexInt.uint8
write:
writer.writeValue "0x" & value.toHex
Json.useCustomSerialization(BitSeq):
read:
BitSeq reader.readValue(string).hexToSeqByte
write:
writer.writeValue "0x" & seq[byte](value).toHex
template readValue*(reader: var JsonReader, value: var BitList) =
type T = type(value)
value = T readValue(reader, BitSeq)
template writeValue*(writer: var JsonWriter, value: BitList) =
writeValue(writer, BitSeq value)
template newClone*[T: not ref](x: T): ref T =
# TODO not nil in return type: https://github.com/nim-lang/Nim/issues/14146
let res = new typeof(x) # TODO safe to do noinit here?
res[] = x
res
template newClone*[T](x: ref T not nil): ref T =
newClone(x[])
template init*(T: type BitList, len: int): auto = T init(BitSeq, len)
template len*(x: BitList): auto = len(BitSeq(x))
template bytes*(x: BitList): auto = bytes(BitSeq(x))
template `[]`*(x: BitList, idx: auto): auto = BitSeq(x)[idx]
template `[]=`*(x: var BitList, idx: auto, val: bool) = BitSeq(x)[idx] = val
template `==`*(a, b: BitList): bool = BitSeq(a) == BitSeq(b)
template setBit*(x: var BitList, idx: int) = setBit(BitSeq(x), idx)
template clearBit*(x: var BitList, idx: int) = clearBit(BitSeq(x), idx)
template overlaps*(a, b: BitList): bool = overlaps(BitSeq(a), BitSeq(b))
template combine*(a: var BitList, b: BitList) = combine(BitSeq(a), BitSeq(b))
template isSubsetOf*(a, b: BitList): bool = isSubsetOf(BitSeq(a), BitSeq(b))
template `$`*(a: BitList): string = $(BitSeq(a))
iterator items*(x: BitList): bool =
for i in 0 ..< x.len:
yield x[i]
when useListType:
template len*[T; N](x: List[T, N]): auto = len(seq[T](x))
template `[]`*[T; N](x: List[T, N], idx: auto): auto = seq[T](x)[idx]
template `[]=`*[T; N](x: List[T, N], idx: auto, val: bool) = seq[T](x)[idx] = val
template `==`*[T; N](a, b: List[T, N]): bool = seq[T](a) == seq[T](b)
template asSeq*[T; N](x: List[T, N]): auto = seq[T](x)
template `&`*[T; N](a, b: List[T, N]): List[T, N] = seq[T](a) & seq[T](b)
else:
template asSeq*[T; N](x: List[T, N]): auto = x
func `$`*(v: ForkDigest | Version): string =
toHex(array[4, byte](v))
# TODO where's borrow support when you need it
func `==`*(a, b: ForkDigest | Version): bool =
array[4, byte](a) == array[4, byte](b)
func len*(v: ForkDigest | Version): int = sizeof(v)
func low*(v: ForkDigest | Version): int = 0
func high*(v: ForkDigest | Version): int = len(v) - 1
func `[]`*(v: ForkDigest | Version, idx: int): byte = array[4, byte](v)[idx]
func shortLog*(s: Slot): uint64 =
s - GENESIS_SLOT
func shortLog*(e: Epoch): uint64 =
e - GENESIS_EPOCH
func shortLog*(v: BeaconBlock): auto =
(
slot: shortLog(v.slot),
proposer_index: v.proposer_index,
parent_root: shortLog(v.parent_root),
state_root: shortLog(v.state_root),
proposer_slashings_len: v.body.proposer_slashings.len(),
attester_slashings_len: v.body.attester_slashings.len(),
attestations_len: v.body.attestations.len(),
deposits_len: v.body.deposits.len(),
voluntary_exits_len: v.body.voluntary_exits.len(),
)
func shortLog*(v: SignedBeaconBlock): auto =
(
blck: shortLog(v.message),
signature: shortLog(v.signature)
)
func shortLog*(v: AttestationData): auto =
(
slot: shortLog(v.slot),
index: v.index,
beacon_block_root: shortLog(v.beacon_block_root),
source_epoch: shortLog(v.source.epoch),
source_root: shortLog(v.source.root),
target_epoch: shortLog(v.target.epoch),
target_root: shortLog(v.target.root)
)
func shortLog*(v: Attestation): auto =
(
aggregation_bits: v.aggregation_bits,
data: shortLog(v.data),
signature: shortLog(v.signature)
)
func shortLog*(cp: Checkpoint): auto =
(
epoch: cp.epoch,
root: shortLog(cp.root)
)
chronicles.formatIt Slot: it.shortLog
chronicles.formatIt Epoch: it.shortLog
chronicles.formatIt BeaconBlock: it.shortLog
chronicles.formatIt AttestationData: it.shortLog
chronicles.formatIt Attestation: it.shortLog
import json_serialization
export json_serialization
export writeValue, readValue