diff --git a/beacon_chain/merkle_minimal.nim b/beacon_chain/merkle_minimal.nim index b4fa6eb3f..0c24314a2 100644 --- a/beacon_chain/merkle_minimal.nim +++ b/beacon_chain/merkle_minimal.nim @@ -115,17 +115,17 @@ proc testMerkleMinimal*(): bool = block: # SSZ Sanity checks vs Python impl block: # 3 leaves - let leaves = sszList(@[a, b, c], 3'i64) + let leaves = List[Eth2Digest, 3](@[a, b, c]) let root = hash_tree_root(leaves) doAssert $root == "9ff412e827b7c9d40fc7df2725021fd579ab762581d1ff5c270316682868456e".toUpperAscii block: # 2^3 leaves - let leaves = sszList(@[a, b, c], int64(1 shl 3)) + let leaves = List[Eth2Digest, int64(1 shl 3)](@[a, b, c]) let root = hash_tree_root(leaves) doAssert $root == "5248085b588fab1dd1e03f3cd62201602b12e6560665935964f46e805977e8c5".toUpperAscii block: # 2^10 leaves - let leaves = sszList(@[a, b, c], int64(1 shl 10)) + let leaves = List[Eth2Digest, int64(1 shl 10)](@[a, b, c]) let root = hash_tree_root(leaves) doAssert $root == "9fb7d518368dc14e8cc588fb3fd2749beef9f493fef70ae34af5721543c67173".toUpperAscii diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index bb703da8a..d8755269d 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -265,8 +265,7 @@ proc initialize_beacon_state_from_eth1*( validator.activation_epoch = GENESIS_EPOCH # Set genesis validators root for domain separation and chain versioning - state.genesis_validators_root = - hash_tree_root(sszList(state.validators, VALIDATOR_REGISTRY_LIMIT)) + state.genesis_validators_root = hash_tree_root(state.validators) state @@ -402,8 +401,10 @@ proc is_valid_indexed_attestation*( # https://github.com/status-im/nim-chronicles/issues/62 # Verify indices are sorted and unique + # TODO: A simple loop can verify that the indicates are monotonically + # increasing and non-repeating here! let indices = indexed_attestation.attesting_indices - if indices != sorted(toHashSet(indices).toSeq, system.cmp): + if indices.asSeq != sorted(toHashSet(indices.asSeq).toSeq, system.cmp): notice "indexed attestation: indices not sorted" return false @@ -457,7 +458,8 @@ func get_indexed_attestation*(state: BeaconState, attestation: Attestation, IndexedAttestation( attesting_indices: - sorted(mapIt(attesting_indices.toSeq, it.uint64), system.cmp), + List[uint64, MAX_VALIDATORS_PER_COMMITTEE]( + sorted(mapIt(attesting_indices.toSeq, it.uint64), system.cmp)), data: attestation.data, signature: attestation.signature ) diff --git a/beacon_chain/spec/datatypes.nim b/beacon_chain/spec/datatypes.nim index 1fd4026a8..c62394526 100644 --- a/beacon_chain/spec/datatypes.nim +++ b/beacon_chain/spec/datatypes.nim @@ -25,7 +25,10 @@ import macros, hashes, json, strutils, tables, stew/[byteutils, bitseqs], chronicles, - ../ssz/types, ./crypto, ./digest + ../ssz/types as sszTypes, ./crypto, ./digest + +export + sszTypes # TODO Data types: # Presently, we're reusing the data types from the serialization (uint64) in the @@ -125,8 +128,6 @@ type 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 @@ -273,7 +274,7 @@ type # Registry validators*: List[Validator, VALIDATOR_REGISTRY_LIMIT] - balances*: seq[uint64] + balances*: List[uint64, VALIDATOR_REGISTRY_LIMIT] # Randomness randao_mixes*: array[EPOCHS_PER_HISTORICAL_VECTOR, Eth2Digest] @@ -405,43 +406,6 @@ type 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] @@ -549,6 +513,14 @@ Json.useCustomSerialization(BitSeq): write: writer.writeValue "0x" & seq[byte](value).toHex +template readValue*(reader: var JsonReader, value: var List) = + type T = type(value) + type E = ElemType(T) + value = T readValue(reader, seq[E]) + +template writeValue*(writer: var JsonWriter, value: List) = + writeValue(writer, asSeq value) + template readValue*(reader: var JsonReader, value: var BitList) = type T = type(value) value = T readValue(reader, BitSeq) @@ -565,32 +537,6 @@ template newClone*[T: not ref](x: T): ref T = 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)) diff --git a/beacon_chain/spec/state_transition_block.nim b/beacon_chain/spec/state_transition_block.nim index 64bfec414..6e9460378 100644 --- a/beacon_chain/spec/state_transition_block.nim +++ b/beacon_chain/spec/state_transition_block.nim @@ -133,7 +133,7 @@ proc process_randao( # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#eth1-data func process_eth1_data(state: var BeaconState, body: BeaconBlockBody) {.nbench.}= state.eth1_data_votes.add body.eth1_data - if state.eth1_data_votes.count(body.eth1_data) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD.int: + if state.eth1_data_votes.asSeq.count(body.eth1_data) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD.int: state.eth1_data = body.eth1_data # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#is_slashable_validator @@ -250,8 +250,8 @@ proc process_attester_slashing*( var slashed_any = false for index in sorted(toSeq(intersection( - toHashSet(attestation_1.attesting_indices), - toHashSet(attestation_2.attesting_indices)).items), system.cmp): + toHashSet(attestation_1.attesting_indices.asSeq), + toHashSet(attestation_2.attesting_indices.asSeq)).items), system.cmp): if is_slashable_validator( state.validators[index.int], get_current_epoch(state)): slash_validator(state, index.ValidatorIndex, stateCache) @@ -478,9 +478,8 @@ proc makeBeaconBlock*( randao_reveal: randao_reveal, eth1_data: eth1data, graffiti: graffiti, - attestations: attestations, - deposits: deposits) - ) + attestations: List[Attestation, MAX_ATTESTATIONS](attestations), + deposits: List[Deposit, MAX_DEPOSITS](deposits))) let tmpState = newClone(state) let ok = process_block(tmpState[], blck, {skipBlsValidation}, cache) diff --git a/beacon_chain/spec/state_transition_epoch.nim b/beacon_chain/spec/state_transition_epoch.nim index 74c717647..5817e3499 100644 --- a/beacon_chain/spec/state_transition_epoch.nim +++ b/beacon_chain/spec/state_transition_epoch.nim @@ -77,13 +77,13 @@ func get_total_active_balance*(state: BeaconState): Gwei = get_active_validator_indices(state, get_current_epoch(state))) # https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#helper-functions-1 -func get_matching_source_attestations(state: BeaconState, epoch: Epoch): - seq[PendingAttestation] = +func get_matching_source_attestations(state: BeaconState, + epoch: Epoch): seq[PendingAttestation] = doAssert epoch in [get_current_epoch(state), get_previous_epoch(state)] if epoch == get_current_epoch(state): - state.current_epoch_attestations + state.current_epoch_attestations.asSeq else: - state.previous_epoch_attestations + state.previous_epoch_attestations.asSeq func get_matching_target_attestations(state: BeaconState, epoch: Epoch): seq[PendingAttestation] = @@ -384,7 +384,7 @@ func process_final_updates*(state: var BeaconState) {.nbench.}= # Reset eth1 data votes if next_epoch mod EPOCHS_PER_ETH1_VOTING_PERIOD == 0: - state.eth1_data_votes = @[] + state.eth1_data_votes = typeof(state.eth1_data_votes) @[] # Update effective balances with hysteresis for index, validator in state.validators: @@ -420,7 +420,7 @@ func process_final_updates*(state: var BeaconState) {.nbench.}= # Rotate current/previous epoch attestations state.previous_epoch_attestations = state.current_epoch_attestations - state.current_epoch_attestations = @[] + state.current_epoch_attestations = typeof(state.current_epoch_attestations) @[] # https://github.com/ethereum/eth2.0-specs/blob/v0.11.2/specs/phase0/beacon-chain.md#epoch-processing proc process_epoch*(state: var BeaconState, updateFlags: UpdateFlags) diff --git a/beacon_chain/ssz.nim b/beacon_chain/ssz.nim index 1132fd567..1a48e0481 100644 --- a/beacon_chain/ssz.nim +++ b/beacon_chain/ssz.nim @@ -13,9 +13,9 @@ #{.push raises: [Defect].} import - stew/shims/macros, options, algorithm, options, strformat, + options, algorithm, options, strformat, typetraits, stint, stew/[bitops2, bitseqs, objects, varints, ptrops], - stew/ranges/[ptr_arith, stackarrays], + stew/ranges/[ptr_arith, stackarrays], stew/shims/macros, faststreams/[inputs, outputs, buffers], serialization, serialization/testing/tracing, ./spec/[crypto, datatypes, digest], @@ -44,14 +44,12 @@ type SszWriter* = object stream: OutputStream - BasicType = char|bool|SomeUnsignedInt|StUint|ValidatorIndex + BasicType = byte|char|bool|SomeUnsignedInt|StUint SszChunksMerkleizer = object combinedChunks: StackArray[Eth2Digest] totalChunks: uint64 - TypeWithMaxLen*[T; maxLen: static int64] = distinct T - SizePrefixed*[T] = distinct T SszMaxSizeExceeded* = object of SerializationError @@ -89,20 +87,6 @@ method formatMsg*(err: ref SszSizeMismatchError, filename: string): string {.gcs except CatchableError: "SSZ size mismatch" -when false: - # TODO: Nim can't handle yet this simpler definition. File an issue. - template valueOf[T; N](x: TypeWithMaxLen[T, N]): auto = T(x) -else: - proc unwrapImpl[T; N: static int64](x: ptr TypeWithMaxLen[T, N]): ptr T = - cast[ptr T](x) - - template valueOf(x: TypeWithMaxLen): auto = - let xaddr = unsafeAddr x - unwrapImpl(xaddr)[] - -template sszList*(x: seq|array, maxLen: static int64): auto = - TypeWithMaxLen[type(x), maxLen](x) - template toSszType*(x: auto): auto = mixin toSszType @@ -110,9 +94,8 @@ template toSszType*(x: auto): auto = elif x is Eth2Digest: x.data elif x is BlsCurveType: toRaw(x) elif x is BitSeq|BitList: ByteList(x) - elif x is TypeWithMaxLen: toSszType valueOf(x) elif x is ForkDigest|Version: array[4, byte](x) - elif useListType and x is List: seq[x.T](x) + elif x is List: asSeq(x) else: x proc writeFixedSized(s: var (OutputStream|WriteCursor), x: auto) {.raises: [Defect, IOError].} = @@ -279,11 +262,6 @@ proc writeValue*[T](w: var SszWriter, x: SizePrefixed[T]) {.raises: [Defect, IOE buf.writeVarint length cursor.finalWrite buf.writtenBytes -template fromSszBytes*[T; N](_: type TypeWithMaxLen[T, N], - bytes: openarray[byte]): auto = - mixin fromSszBytes - fromSszBytes(T, bytes) - proc readValue*[T](r: var SszReader, val: var T) {.raises: [Defect, MalformedSszError, SszSizeMismatchError, IOError].} = when isFixedSize(T): const minimalSize = fixedPortionSize(T) @@ -435,18 +413,15 @@ template merkleizeFields(totalElements: int, body: untyped): Eth2Digest = addChunk(merkleizer, hash.data) trs "CHUNK ADDED" - template addField2(field) {.used.}= - const maxLen = fieldMaxLen(field) - when maxLen > 0: - type FieldType = type field - addField TypeWithMaxLen[FieldType, maxLen](field) - else: - addField field - body getFinalHash(merkleizer) +template writeBytesLE(chunk: var array[bytesPerChunk, byte], atParam: int, + val: SomeUnsignedInt|StUint) = + let at = atParam + chunk[at ..< at + sizeof(val)] = toBytesLE(val) + func chunkedHashTreeRootForBasicTypes[T](merkleizer: var SszChunksMerkleizer, arr: openarray[T]): Eth2Digest = static: @@ -473,21 +448,17 @@ func chunkedHashTreeRootForBasicTypes[T](merkleizer: var SszChunksMerkleizer, else: static: - assert T is SomeUnsignedInt|StUInt|ValidatorIndex + assert T is SomeUnsignedInt|StUInt assert bytesPerChunk mod sizeof(Т) == 0 const valuesPerChunk = bytesPerChunk div sizeof(Т) - template writeAt(chunk: var array[bytesPerChunk], at: int, val: SomeUnsignedInt|StUint) = - type ArrType = type toBytesLE(val) - (cast[ptr ArrType](addr chunk[at]))[] = toBytesLE(val) - var writtenValues = 0 var chunk: array[bytesPerChunk, byte] while writtenValues < arr.len - valuesPerChunk: for i in 0 ..< valuesPerChunk: - chunk.writeAt(i * sizeof(T), arr[writtenValues + i]) + chunk.writeBytesLE(i * sizeof(T), arr[writtenValues + i]) merkleizer.addChunk chunk inc writtenValues, valuesPerChunk @@ -495,7 +466,7 @@ func chunkedHashTreeRootForBasicTypes[T](merkleizer: var SszChunksMerkleizer, if remainingValues > 0: var lastChunk: array[bytesPerChunk, byte] for i in 0 ..< remainingValues: - chunk.writeAt(i * sizeof(T), arr[writtenValues + i]) + chunk.writeBytesLE(i * sizeof(T), arr[writtenValues + i]) merkleizer.addChunk lastChunk getFinalHash(merkleizer) @@ -552,9 +523,9 @@ func bitlistHashTreeRoot(merkleizer: var SszChunksMerkleizer, x: BitSeq): Eth2Di mixInLength contentsHash, x.len func maxChunksCount(T: type, maxLen: int64): int64 = - when T is BitList: + when T is BitSeq|BitList: (maxLen + bitsPerChunk - 1) div bitsPerChunk - elif T is seq|array: + elif T is array|List|seq|openarray: type E = ElemType(T) when E is BasicType: (maxLen * sizeof(E) + bytesPerChunk - 1) div bytesPerChunk @@ -563,45 +534,37 @@ func maxChunksCount(T: type, maxLen: int64): int64 = else: unsupported T # This should never happen -func hashTreeRootImpl[T](x: T): Eth2Digest = +func hashTreeRootAux[T](x: T): Eth2Digest = when T is SignedBeaconBlock: unsupported T # Blocks are identified by htr(BeaconBlock) so we avoid these elif T is bool|char: result.data[0] = byte(x) - elif T is SomeUnsignedInt|StUint|ValidatorIndex: + elif T is SomeUnsignedInt|StUint: when cpuEndian == bigEndian: result.data[0.. 0: - type FieldType = type f - addField TypeWithMaxLen[FieldType, maxLen](f) - else: - addField f - elif T is seq: - trs "SEQ WITH VAR SIZE" - let hash = merkleizeFields(x.len, for e in x: addField e) - mixInLength hash, x.len + addField f #elif isCaseObject(T): # # TODO implement this else: @@ -610,28 +573,26 @@ func hashTreeRootImpl[T](x: T): Eth2Digest = func hash_tree_root*(x: auto): Eth2Digest {.raises: [Defect], nbench.} = trs "STARTING HASH TREE ROOT FOR TYPE ", name(type(x)) mixin toSszType - when x is TypeWithMaxLen: - const maxLen = x.maxLen - type T = type valueOf(x) + when x is List|BitList: + const maxLen = static(x.maxLen) + type T = type(x) const limit = maxChunksCount(T, maxLen) var merkleizer = createMerkleizer(limit) - when T is BitList: - result = merkleizer.bitlistHashTreeRoot(BitSeq valueOf(x)) - elif T is seq: + when x is BitList: + result = merkleizer.bitlistHashTreeRoot(BitSeq x) + else: type E = ElemType(T) let contentsHash = when E is BasicType: - chunkedHashTreeRootForBasicTypes(merkleizer, valueOf(x)) + chunkedHashTreeRootForBasicTypes(merkleizer, asSeq x) else: - for elem in valueOf(x): + for elem in x: let elemHash = hash_tree_root(elem) merkleizer.addChunk(elemHash.data) merkleizer.getFinalHash() - result = mixInLength(contentsHash, valueOf(x).len) - else: - unsupported T # This should never happen + result = mixInLength(contentsHash, x.len) else: - result = hashTreeRootImpl toSszType(x) + result = hashTreeRootAux toSszType(x) trs "HASH TREE ROOT FOR ", name(type x), " = ", "0x", $result diff --git a/beacon_chain/ssz/bytes_reader.nim b/beacon_chain/ssz/bytes_reader.nim index 1dbf48684..a9d7e75cf 100644 --- a/beacon_chain/ssz/bytes_reader.nim +++ b/beacon_chain/ssz/bytes_reader.nim @@ -97,7 +97,7 @@ func readSszValue*(input: openarray[byte], T: type): T {.raisesssz.} = template readOffset(n: int): int {.used.}= int fromSszBytes(uint32, input.toOpenArray(n, n + offsetSize - 1)) - when useListType and result is List: + when result is List: type ElemType = type result[0] result = T readSszValue(input, seq[ElemType]) @@ -199,8 +199,16 @@ func readSszValue*(input: openarray[byte], T: type): T {.raisesssz.} = SszType) trs "READING COMPLETE ", fieldName - elif useListType and FieldType is List: - field = readSszValue( + elif FieldType is List: + # TODO + # The `typeof(field)` coercion below is required to deal with a Nim + # bug. For some reason, Nim gets confused about the type of the list + # returned from the `readSszValue` function. This could be a generics + # caching issue caused by the use of distinct types. Such an issue + # would be very scary in general, but in this particular situation + # it shouldn't matter, because the different flavours of `List[T, N]` + # won't produce different serializations. + field = typeof(field) readSszValue( input.toOpenArray(startOffset, endOffset - 1), FieldType) diff --git a/beacon_chain/ssz/navigator.nim b/beacon_chain/ssz/navigator.nim index 5d8a8ea32..46fdbb469 100644 --- a/beacon_chain/ssz/navigator.nim +++ b/beacon_chain/ssz/navigator.nim @@ -120,7 +120,7 @@ template `[]`*[R, T](n: SszNavigator[array[R, T]], idx: int): SszNavigator[T] = func `[]`*[T](n: SszNavigator[T]): T {.raisesssz.} = mixin toSszType, fromSszBytes type SszRepr = type toSszType(declval T) - when type(SszRepr) is type(T): + when type(SszRepr) is type(T) or T is List: readSszValue(toOpenArray(n.m), T) else: fromSszBytes(T, toOpenArray(n.m)) diff --git a/beacon_chain/ssz/types.nim b/beacon_chain/ssz/types.nim index 948ceae66..ab19259f6 100644 --- a/beacon_chain/ssz/types.nim +++ b/beacon_chain/ssz/types.nim @@ -1,12 +1,11 @@ {.push raises: [Defect].} import - tables, options, + tables, options, typetraits, stew/shims/macros, stew/[objects, bitseqs], serialization/[object_serialization, errors] const - useListType* = false offsetSize* = 4 type @@ -63,10 +62,41 @@ type of Field: discard -when useListType: - type List*[T; maxLen: static int64] = distinct seq[T] -else: - type List*[T; maxLen: static int64] = seq[T] + List*[T; maxLen: static int64] = distinct seq[T] + BitList*[maxLen: static int] = distinct BitSeq + +template add*(x: List, val: x.T) = add(distinctBase x, val) +template len*(x: List): auto = len(distinctBase x) +template low*(x: List): auto = low(distinctBase x) +template high*(x: List): auto = high(distinctBase x) +template `[]`*(x: List, idx: auto): auto = distinctBase(x)[idx] +template `[]=`*[T; N](x: List[T, N], idx: auto, val: T) = seq[T](x)[idx] = val +template `==`*(a, b: List): bool = distinctBase(a) == distinctBase(b) +template asSeq*(x: List): auto = distinctBase x +template `&`*[T; N](a, b: List[T, N]): List[T, N] = List[T, N](seq[T](a) & seq[T](b)) +template `$`*(x: List): auto = $(distinctBase x) + +template items* (x: List): untyped = items(distinctBase x) +template pairs* (x: List): untyped = pairs(distinctBase x) +template mitems*(x: List): untyped = mitems(distinctBase x) +template mpairs*(x: List): untyped = mpairs(distinctBase 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] macro unsupported*(T: typed): untyped = # TODO: {.fatal.} breaks compilation even in `compiles()` context, diff --git a/beacon_chain/validator_duties.nim b/beacon_chain/validator_duties.nim index f806c075a..d75a735ab 100644 --- a/beacon_chain/validator_duties.nim +++ b/beacon_chain/validator_duties.nim @@ -54,7 +54,7 @@ proc addLocalValidator*(node: BeaconNode, privKey: ValidatorPrivKey) = let pubKey = privKey.toPubKey() - let idx = state.validators.findIt(it.pubKey == pubKey) + let idx = state.validators.asSeq.findIt(it.pubKey == pubKey) if idx == -1: # We allow adding a validator even if its key is not in the state registry: # it might be that the deposit for this validator has not yet been processed diff --git a/tests/mocking/mock_deposits.nim b/tests/mocking/mock_deposits.nim index 1ab69abb9..40f5952d0 100644 --- a/tests/mocking/mock_deposits.nim +++ b/tests/mocking/mock_deposits.nim @@ -210,5 +210,5 @@ proc mockUpdateStateForNewDeposit*( # but confirmed by running it state.eth1_deposit_index = 0 state.eth1_data.deposit_root = - hash_tree_root(sszList(@[result.data], 2'i64^DEPOSIT_CONTRACT_TREE_DEPTH)) + hash_tree_root(List[DepositData, 2'i64^DEPOSIT_CONTRACT_TREE_DEPTH](@[result.data])) state.eth1_data.deposit_count = 1 diff --git a/tests/spec_epoch_processing/justification_finalization_helpers.nim b/tests/spec_epoch_processing/justification_finalization_helpers.nim index 83d91631f..b0a7e04ae 100644 --- a/tests/spec_epoch_processing/justification_finalization_helpers.nim +++ b/tests/spec_epoch_processing/justification_finalization_helpers.nim @@ -27,9 +27,9 @@ proc addMockAttestations*( # Alias the attestations container var attestations: ptr seq[PendingAttestation] if state.get_current_epoch() == epoch: - attestations = state.current_epoch_attestations.addr + attestations = state.current_epoch_attestations.asSeq.addr elif state.get_previous_epoch() == epoch: - attestations = state.previous_epoch_attestations.addr + attestations = state.previous_epoch_attestations.asSeq.addr else: raise newException(ValueError, &"Cannot include attestations from epoch {state.get_current_epoch()} in epoch {epoch}") diff --git a/tests/test_ssz.nim b/tests/test_ssz.nim index 1d390e5ca..384e037bb 100644 --- a/tests/test_ssz.nim +++ b/tests/test_ssz.nim @@ -93,11 +93,11 @@ suiteReport "SSZ navigator": let b = [byte 0x04, 0x05, 0x06].toDigest let c = [byte 0x07, 0x08, 0x09].toDigest - let leaves = sszList(@[a, b, c], int64(1 shl 3)) + let leaves = List[Eth2Digest, int64(1 shl 3)](@[a, b, c]) let root = hash_tree_root(leaves) check $root == "5248085B588FAB1DD1E03F3CD62201602B12E6560665935964F46E805977E8C5" - let leaves2 = sszList(@[a, b, c], int64(1 shl 10)) + let leaves2 = List[Eth2Digest, int64(1 shl 10)](@[a, b, c]) let root2 = hash_tree_root(leaves2) check $root2 == "9FB7D518368DC14E8CC588FB3FD2749BEEF9F493FEF70AE34AF5721543C67173" diff --git a/vendor/nim-serialization b/vendor/nim-serialization index 7ff764ca1..b61fcb51a 160000 --- a/vendor/nim-serialization +++ b/vendor/nim-serialization @@ -1 +1 @@ -Subproject commit 7ff764ca1f921ee709f05219aa740ab6c42872fc +Subproject commit b61fcb51ad817d1d7bba6d6cd255dec3eb2f6987