mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-01-11 14:54:12 +00:00
cleanups (#189)
* add simple bitfield type (fixes #19) * fix bit endianess to match spec * consolidate attestation and block logging * cruft cleanup * run optimizer on tests, speeds up build
This commit is contained in:
parent
13c7f7fcec
commit
ee89ef1c79
@ -31,11 +31,11 @@ requires "nim >= 0.19.0",
|
||||
|
||||
### Helper functions
|
||||
proc test(name: string, defaultLang = "c") =
|
||||
# TODO, don't forget to change defaultLang to `cpp` if the project requires C++
|
||||
if not dirExists "build":
|
||||
mkDir "build"
|
||||
--run
|
||||
switch("out", ("./build/" & name))
|
||||
switch("opt", "speed")
|
||||
setCommand defaultLang, "tests/" & name & ".nim"
|
||||
|
||||
### tasks
|
||||
|
@ -1,8 +1,8 @@
|
||||
import
|
||||
deques, options, sequtils, tables,
|
||||
chronicles,
|
||||
./spec/[beaconstate, datatypes, crypto, digest, helpers, validator], extras,
|
||||
./beacon_chain_db, ./ssz, ./block_pool,
|
||||
./spec/[beaconstate, bitfield, datatypes, crypto, digest, helpers, validator],
|
||||
./extras, ./beacon_chain_db, ./ssz, ./block_pool,
|
||||
beacon_node_types
|
||||
|
||||
proc init*(T: type AttestationPool, blockPool: BlockPool): T =
|
||||
@ -13,17 +13,6 @@ proc init*(T: type AttestationPool, blockPool: BlockPool): T =
|
||||
latestAttestations: initTable[ValidatorPubKey, BlockRef]()
|
||||
)
|
||||
|
||||
proc overlaps(a, b: seq[byte]): bool =
|
||||
for i in 0..<a.len:
|
||||
if (a[i] and b[i]) > 0'u8:
|
||||
return true
|
||||
|
||||
proc combineBitfield(tgt: var seq[byte], src: seq[byte]) =
|
||||
for i in 0 ..< tgt.len:
|
||||
# TODO:
|
||||
# when BLS signatures are combined, we must ensure that
|
||||
# the same participant key is not included on both sides
|
||||
tgt[i] = tgt[i] or src[i]
|
||||
|
||||
proc combine*(tgt: var Attestation, src: Attestation, flags: UpdateFlags) =
|
||||
# Combine the signature and participation bitfield, with the assumption that
|
||||
@ -34,7 +23,7 @@ proc combine*(tgt: var Attestation, src: Attestation, flags: UpdateFlags) =
|
||||
# TODO:
|
||||
# when BLS signatures are combined, we must ensure that
|
||||
# the same participant key is not included on both sides
|
||||
tgt.aggregation_bitfield.combineBitfield(src.aggregation_bitfield)
|
||||
tgt.aggregation_bitfield.combine(src.aggregation_bitfield)
|
||||
|
||||
if skipValidation notin flags:
|
||||
tgt.aggregate_signature.combine(src.aggregate_signature)
|
||||
@ -70,11 +59,11 @@ proc validate(
|
||||
finalizedEpoch = humaneEpochNum(state.finalized_epoch)
|
||||
return
|
||||
|
||||
if not allIt(attestation.custody_bitfield, it == 0):
|
||||
if not allIt(attestation.custody_bitfield.bits, it == 0):
|
||||
notice "Invalid custody bitfield for phase 0"
|
||||
return false
|
||||
|
||||
if not anyIt(attestation.aggregation_bitfield, it != 0):
|
||||
if not anyIt(attestation.aggregation_bitfield.bits, it != 0):
|
||||
notice "Empty aggregation bitfield"
|
||||
return false
|
||||
|
||||
@ -83,21 +72,6 @@ proc validate(
|
||||
it.shard == attestation.data.shard),
|
||||
it.committee)[0]
|
||||
|
||||
# Extra checks not in specs
|
||||
# https://github.com/status-im/nim-beacon-chain/pull/105#issuecomment-462432544
|
||||
if attestation.aggregation_bitfield.len != (crosslink_committee.len + 7) div 8:
|
||||
notice "Invalid aggregation bitfield length",
|
||||
attestationLen = attestation.aggregation_bitfield.len,
|
||||
committeeLen = crosslink_committee.len
|
||||
return false
|
||||
|
||||
if attestation.custody_bitfield.len != (crosslink_committee.len + 7) div 8:
|
||||
notice "Invalid custody bitfield length",
|
||||
attestationLen = attestation.aggregation_bitfield.len,
|
||||
committeeLen = crosslink_committee.len
|
||||
return false
|
||||
# End extra checks
|
||||
|
||||
## the rest; turns into expensive NOP until then.
|
||||
if skipValidation notin flags:
|
||||
let
|
||||
@ -236,12 +210,7 @@ proc add*(pool: var AttestationPool,
|
||||
pool.updateLatestVotes(state, attestationSlot, participants, a.blck)
|
||||
|
||||
info "Attestation resolved",
|
||||
slot = humaneSlotNum(attestation.data.slot),
|
||||
shard = attestation.data.shard,
|
||||
beaconBlockRoot = shortLog(attestation.data.beacon_block_root),
|
||||
sourceEpoch = humaneEpochNum(attestation.data.source_epoch),
|
||||
justifiedBlockRoot = shortLog(attestation.data.justified_block_root),
|
||||
signature = shortLog(attestation.aggregate_signature),
|
||||
attestationData = shortLog(attestation.data),
|
||||
validations = a.validations.len() # TODO popcount of union
|
||||
|
||||
found = true
|
||||
@ -259,12 +228,7 @@ proc add*(pool: var AttestationPool,
|
||||
pool.updateLatestVotes(state, attestationSlot, participants, blck)
|
||||
|
||||
info "Attestation resolved",
|
||||
slot = humaneSlotNum(attestation.data.slot),
|
||||
shard = attestation.data.shard,
|
||||
beaconBlockRoot = shortLog(attestation.data.beacon_block_root),
|
||||
sourceEpoch = humaneEpochNum(attestation.data.source_epoch),
|
||||
justifiedBlockRoot = shortLog(attestation.data.justified_block_root),
|
||||
signature = shortLog(attestation.aggregate_signature),
|
||||
attestationData = shortLog(attestation.data),
|
||||
validations = 1
|
||||
|
||||
else:
|
||||
@ -318,9 +282,9 @@ proc getAttestationsForBlock*(pool: AttestationPool,
|
||||
for v in a.validations[1..^1]:
|
||||
if not attestation.aggregation_bitfield.overlaps(
|
||||
v.aggregation_bitfield):
|
||||
attestation.aggregation_bitfield.combineBitfield(
|
||||
attestation.aggregation_bitfield.combine(
|
||||
v.aggregation_bitfield)
|
||||
attestation.custody_bitfield.combineBitfield(v.custody_bitfield)
|
||||
attestation.custody_bitfield.combine(v.custody_bitfield)
|
||||
attestation.aggregate_signature.combine(v.aggregate_signature)
|
||||
|
||||
result.add(attestation)
|
||||
|
@ -1,7 +1,8 @@
|
||||
import
|
||||
std_shims/[os_shims, objects], net, sequtils, options, tables, osproc, random,
|
||||
chronos, chronicles, confutils, serialization/errors,
|
||||
spec/[datatypes, digest, crypto, beaconstate, helpers, validator], conf, time,
|
||||
spec/[bitfield, datatypes, digest, crypto, beaconstate, helpers, validator],
|
||||
conf, time,
|
||||
state_transition, fork_choice, ssz, beacon_chain_db, validator_pool, extras,
|
||||
attestation_pool, block_pool, eth2_network, beacon_node_types,
|
||||
mainchain_monitor, trusted_state_snapshots, version,
|
||||
@ -344,15 +345,15 @@ proc makeAttestation(node: BeaconNode,
|
||||
# Careful - after await. node.state (etc) might have changed in async race
|
||||
validatorSignature = await validator.signAttestation(attestationData)
|
||||
|
||||
var aggregationBitfield = repeat(0'u8, ceil_div8(committeeLen))
|
||||
bitSet(aggregationBitfield, indexInCommittee)
|
||||
var aggregationBitfield = BitField.init(committeeLen)
|
||||
set_bitfield_bit(aggregationBitfield, indexInCommittee)
|
||||
|
||||
var attestation = Attestation(
|
||||
data: attestationData,
|
||||
aggregate_signature: validatorSignature,
|
||||
aggregation_bitfield: aggregationBitfield,
|
||||
# Stub in phase0
|
||||
custody_bitfield: newSeq[byte](aggregationBitfield.len)
|
||||
custody_bitfield: BitField.init(committeeLen)
|
||||
)
|
||||
|
||||
# TODO what are we waiting for here? broadcast should never block, and never
|
||||
@ -360,11 +361,9 @@ proc makeAttestation(node: BeaconNode,
|
||||
await node.network.broadcast(topicAttestations, attestation)
|
||||
|
||||
info "Attestation sent",
|
||||
slot = humaneSlotNum(attestationData.slot),
|
||||
shard = attestationData.shard,
|
||||
attestationData = shortLog(attestationData),
|
||||
validator = shortValidatorKey(node, validator.idx),
|
||||
signature = shortLog(validatorSignature),
|
||||
beaconBlockRoot = shortLog(attestationData.beacon_block_root)
|
||||
signature = shortLog(validatorSignature)
|
||||
|
||||
proc proposeBlock(node: BeaconNode,
|
||||
validator: AttachedValidator,
|
||||
@ -434,9 +433,8 @@ proc proposeBlock(node: BeaconNode,
|
||||
await node.network.broadcast(topicBeaconBlocks, newBlock)
|
||||
|
||||
info "Block proposed",
|
||||
slot = humaneSlotNum(slot),
|
||||
stateRoot = shortLog(newBlock.state_root),
|
||||
parentRoot = shortLog(newBlock.previous_block_root),
|
||||
blck = shortLog(newBlock),
|
||||
blockRoot = shortLog(proposal.block_root),
|
||||
validator = shortValidatorKey(node, validator.idx),
|
||||
idx = validator.idx
|
||||
|
||||
@ -631,11 +629,7 @@ proc onAttestation(node: BeaconNode, attestation: Attestation) =
|
||||
# yet - in particular, we haven't verified that it belongs to particular chain
|
||||
# we're on, or that it follows the rules of the protocol
|
||||
debug "Attestation received",
|
||||
slot = humaneSlotNum(attestation.data.slot),
|
||||
shard = attestation.data.shard,
|
||||
beaconBlockRoot = shortLog(attestation.data.beacon_block_root),
|
||||
sourceEpoch = humaneEpochNum(attestation.data.source_epoch),
|
||||
justifiedBlockRoot = shortLog(attestation.data.justified_block_root),
|
||||
attestationData = shortLog(attestation.data),
|
||||
signature = shortLog(attestation.aggregate_signature)
|
||||
|
||||
node.attestationPool.add(node.state.data, attestation)
|
||||
@ -645,17 +639,8 @@ proc onBeaconBlock(node: BeaconNode, blck: BeaconBlock) =
|
||||
# don't know if it's part of the chain we're currently building.
|
||||
let blockRoot = hash_tree_root_final(blck)
|
||||
debug "Block received",
|
||||
blockRoot = shortLog(blockRoot),
|
||||
slot = humaneSlotNum(blck.slot),
|
||||
stateRoot = shortLog(blck.state_root),
|
||||
parentRoot = shortLog(blck.previous_block_root),
|
||||
signature = shortLog(blck.signature),
|
||||
proposer_slashings = blck.body.proposer_slashings.len,
|
||||
attester_slashings = blck.body.attester_slashings.len,
|
||||
attestations = blck.body.attestations.len,
|
||||
deposits = blck.body.deposits.len,
|
||||
voluntary_exits = blck.body.voluntary_exits.len,
|
||||
transfers = blck.body.transfers.len
|
||||
blck = shortLog(blck),
|
||||
blockRoot = shortLog(blockRoot)
|
||||
|
||||
if not node.blockPool.add(node.state, blockRoot, blck):
|
||||
# TODO the fact that add returns a bool that causes the parent block to be
|
||||
|
@ -1,10 +1,10 @@
|
||||
import # Beacon Node
|
||||
eth/[p2p, keys],
|
||||
spec/digest,
|
||||
spec/[bitfield, digest],
|
||||
beacon_chain_db, conf, mainchain_monitor, eth2_network
|
||||
|
||||
import # Attestation Pool
|
||||
spec/[datatypes, crypto, digest],
|
||||
spec/[bitfield, datatypes, crypto, digest],
|
||||
deques, tables
|
||||
# block_pool
|
||||
|
||||
@ -47,8 +47,8 @@ type
|
||||
#
|
||||
# #############################################
|
||||
Validation* = object
|
||||
aggregation_bitfield*: seq[byte]
|
||||
custody_bitfield*: seq[byte] ##\
|
||||
aggregation_bitfield*: BitField
|
||||
custody_bitfield*: BitField ##\
|
||||
## Phase 1 - the handling of this field is probably broken..
|
||||
aggregate_signature*: ValidatorSig
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
import
|
||||
chronicles, math, options, sequtils,
|
||||
../extras, ../ssz,
|
||||
./crypto, ./datatypes, ./digest, ./helpers, ./validator
|
||||
./bitfield, ./crypto, ./datatypes, ./digest, ./helpers, ./validator
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_effective_balance
|
||||
func get_effective_balance*(state: BeaconState, index: ValidatorIndex): Gwei =
|
||||
@ -336,7 +336,7 @@ func get_block_root*(state: BeaconState,
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_attestation_participants
|
||||
func get_attestation_participants*(state: BeaconState,
|
||||
attestation_data: AttestationData,
|
||||
bitfield: seq[byte]): seq[ValidatorIndex] =
|
||||
bitfield: BitField): seq[ValidatorIndex] =
|
||||
## Return the participant indices at for the ``attestation_data`` and
|
||||
## ``bitfield``.
|
||||
## Attestation participants in the attestation data are called out in a
|
||||
@ -347,7 +347,6 @@ func get_attestation_participants*(state: BeaconState,
|
||||
## Return the participant indices at for the ``attestation_data`` and ``bitfield``.
|
||||
##
|
||||
# TODO Linear search through shard list? borderline ok, it's a small list
|
||||
# TODO bitfield type needed, once bit order settles down
|
||||
# TODO iterator candidate
|
||||
|
||||
## Return the participant indices at for the ``attestation_data`` and
|
||||
@ -369,7 +368,7 @@ func get_attestation_participants*(state: BeaconState,
|
||||
result = @[]
|
||||
for i, validator_index in crosslink_committee:
|
||||
let aggregation_bit = get_bitfield_bit(bitfield, i)
|
||||
if aggregation_bit == 1:
|
||||
if aggregation_bit:
|
||||
result.add(validator_index)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#ejections
|
||||
@ -504,33 +503,18 @@ proc checkAttestation*(
|
||||
crosslink_data_root = attestation.data.crosslink_data_root)
|
||||
return
|
||||
|
||||
doAssert allIt(attestation.custody_bitfield, it == 0) #TO BE REMOVED IN PHASE 1
|
||||
doAssert anyIt(attestation.aggregation_bitfield, it != 0)
|
||||
doAssert allIt(attestation.custody_bitfield.bits, it == 0) #TO BE REMOVED IN PHASE 1
|
||||
doAssert anyIt(attestation.aggregation_bitfield.bits, it != 0)
|
||||
|
||||
let crosslink_committee = mapIt(
|
||||
filterIt(get_crosslink_committees_at_slot(state, attestation_data_slot),
|
||||
it.shard == attestation.data.shard),
|
||||
it.committee)[0]
|
||||
|
||||
# Extra checks not in specs
|
||||
# https://github.com/status-im/nim-beacon-chain/pull/105#issuecomment-462432544
|
||||
doAssert attestation.aggregation_bitfield.len == (
|
||||
crosslink_committee.len + 7) div 8, (
|
||||
"Error: got " & $attestation.aggregation_bitfield.len &
|
||||
" but expected " & $((crosslink_committee.len + 7) div 8)
|
||||
)
|
||||
|
||||
doAssert attestation.custody_bitfield.len == (
|
||||
crosslink_committee.len + 7) div 8, (
|
||||
"Error: got " & $attestation.custody_bitfield.len &
|
||||
" but expected " & $((crosslink_committee.len + 7) div 8)
|
||||
)
|
||||
# End extra checks
|
||||
|
||||
doAssert allIt(0 ..< len(crosslink_committee),
|
||||
if get_bitfield_bit(attestation.aggregation_bitfield, it) == 0b0:
|
||||
if not get_bitfield_bit(attestation.aggregation_bitfield, it):
|
||||
# Should always be true in phase 0, because of above assertion
|
||||
get_bitfield_bit(attestation.custody_bitfield, it) == 0b0
|
||||
not get_bitfield_bit(attestation.custody_bitfield, it)
|
||||
else:
|
||||
true)
|
||||
|
||||
|
47
beacon_chain/spec/bitfield.nim
Normal file
47
beacon_chain/spec/bitfield.nim
Normal file
@ -0,0 +1,47 @@
|
||||
type
|
||||
BitField* = object
|
||||
## A simple bit field type that follows the semantics of the spec, with
|
||||
## regards to bit endian operations
|
||||
# TODO nim-ranges contains utilities for with bitsets - could try to
|
||||
# recycle that, but there are open questions about bit endianess there.
|
||||
# TODO define a json serialization.. together with spec tests?
|
||||
# https://github.com/ethereum/eth2.0-tests/tree/master/state
|
||||
bits*: seq[byte]
|
||||
|
||||
func ceil_div8(v: int): int = (v + 7) div 8
|
||||
|
||||
func init*(T: type BitField, bits: int): BitField =
|
||||
BitField(bits: newSeq[byte](ceil_div8(bits)))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_bitfield_bit
|
||||
func get_bitfield_bit*(bitfield: BitField, i: int): bool =
|
||||
# Extract the bit in ``bitfield`` at position ``i``.
|
||||
doAssert 0 <= i div 8, "i: " & $i & " i div 8: " & $(i div 8)
|
||||
doAssert i div 8 < bitfield.bits.len, "i: " & $i & " i div 8: " & $(i div 8)
|
||||
((bitfield.bits[i div 8] shr (i mod 8)) mod 2) > 0'u8
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#verify_bitfield
|
||||
func verify_bitfield*(bitfield: BitField, committee_size: int): bool =
|
||||
# Verify ``bitfield`` against the ``committee_size``.
|
||||
if len(bitfield.bits) != (committee_size + 7) div 8:
|
||||
return false
|
||||
|
||||
# Check `bitfield` is padded with zero bits only
|
||||
for i in committee_size ..< (len(bitfield.bits) * 8):
|
||||
if get_bitfield_bit(bitfield, i):
|
||||
return false
|
||||
|
||||
true
|
||||
|
||||
# TODO spec candidatidates below, though they're used only indirectly there..
|
||||
func set_bitfield_bit*(bitfield: var BitField, i: int) =
|
||||
bitfield.bits[i div 8] = bitfield.bits[i div 8] or 1'u8 shl (i mod 8)
|
||||
|
||||
func combine*(tgt: var BitField, src: BitField) =
|
||||
for i in 0 ..< tgt.bits.len:
|
||||
tgt.bits[i] = tgt.bits[i] or src.bits[i]
|
||||
|
||||
proc overlaps*(a, b: BitField): bool =
|
||||
for i in 0..<a.bits.len:
|
||||
if (a.bits[i] and b.bits[i]) > 0'u8:
|
||||
return true
|
@ -20,7 +20,7 @@
|
||||
import
|
||||
hashes, math,
|
||||
eth/[common, rlp],
|
||||
./crypto, ./digest
|
||||
./bitfield, ./crypto, ./digest
|
||||
|
||||
# TODO Data types:
|
||||
# Presently, we're reusing the data types from the serialization (uint64) in the
|
||||
@ -207,7 +207,7 @@ type
|
||||
data*: AttestationData ## \
|
||||
## Attestation data
|
||||
|
||||
custody_bitfield*: seq[byte] ##\
|
||||
custody_bitfield*: BitField ##\
|
||||
## Custody bitfield
|
||||
|
||||
aggregate_signature*: ValidatorSig ## \
|
||||
@ -215,13 +215,13 @@ type
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#attestation
|
||||
Attestation* = object
|
||||
aggregation_bitfield*: seq[byte] ##\
|
||||
aggregation_bitfield*: BitField ##\
|
||||
## Attester aggregation bitfield
|
||||
|
||||
data*: AttestationData ##\
|
||||
## Attestation data
|
||||
|
||||
custody_bitfield*: seq[byte] ##\
|
||||
custody_bitfield*: BitField ##\
|
||||
## Custody bitfield
|
||||
|
||||
aggregate_signature*: ValidatorSig ##\
|
||||
@ -471,10 +471,10 @@ type
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#pendingattestation
|
||||
PendingAttestation* = object
|
||||
aggregation_bitfield*: seq[byte] # Attester participation bitfield
|
||||
data*: AttestationData # Attestation data
|
||||
custody_bitfield*: seq[byte] # Custody bitfield
|
||||
inclusion_slot*: Slot # Inclusion slot
|
||||
aggregation_bitfield*: BitField ## Attester participation bitfield
|
||||
data*: AttestationData ## Attestation data
|
||||
custody_bitfield*: BitField ## Custody bitfield
|
||||
inclusion_slot*: Slot ## Inclusion slot
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#historicalbatch
|
||||
HistoricalBatch* = object
|
||||
@ -618,6 +618,21 @@ func shortLog*(v: BeaconBlock): tuple[
|
||||
shortLog(v.signature)
|
||||
)
|
||||
|
||||
func shortLog*(v: AttestationData): tuple[
|
||||
slot: uint64, beacon_block_root: string, source_epoch: uint64,
|
||||
target_root: string, epoch_boundary_root: string,
|
||||
justified_block_root: string, shard: uint64,
|
||||
previous_crosslink_epoch: uint64, previous_crosslink_data_root: string,
|
||||
crosslink_data_root: string
|
||||
] = (
|
||||
humaneSlotNum(v.slot), shortLog(v.beacon_block_root),
|
||||
humaneEpochNum(v.source_epoch), shortLog(v.target_root),
|
||||
shortLog(v.epoch_boundary_root), shortLog(v.justified_block_root),
|
||||
v.shard, humaneEpochNum(v.previous_crosslink.epoch),
|
||||
shortLog(v.previous_crosslink.crosslink_data_root),
|
||||
shortLog(v.crosslink_data_root)
|
||||
)
|
||||
|
||||
import nimcrypto, json_serialization
|
||||
export json_serialization
|
||||
export writeValue, readValue, append, read
|
||||
|
@ -9,31 +9,6 @@
|
||||
|
||||
import ./datatypes, ./digest, sequtils, math
|
||||
|
||||
# TODO spec candidate? there's bits in nim-ranges but that one has some API
|
||||
# issues regarding bit endianess that need resolving..
|
||||
func bitSet*(bitfield: var openArray[byte], index: int) =
|
||||
bitfield[index div 8] = bitfield[index div 8] or 1'u8 shl (7 - (index mod 8))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_bitfield_bit
|
||||
func get_bitfield_bit*(bitfield: openarray[byte], i: int): byte =
|
||||
# Extract the bit in ``bitfield`` at position ``i``.
|
||||
doAssert 0 <= i div 8, "i: " & $i & " i div 8: " & $(i div 8)
|
||||
doAssert i div 8 < bitfield.len, "i: " & $i & " i div 8: " & $(i div 8)
|
||||
(bitfield[i div 8] shr (7 - (i mod 8))) mod 2
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#verify_bitfield
|
||||
func verify_bitfield*(bitfield: openarray[byte], committee_size: int): bool =
|
||||
# Verify ``bitfield`` against the ``committee_size``.
|
||||
if len(bitfield) != (committee_size + 7) div 8:
|
||||
return false
|
||||
|
||||
# Check `bitfield` is padded with zero bits only
|
||||
for i in committee_size ..< (len(bitfield) * 8):
|
||||
if get_bitfield_bit(bitfield, i) == 0b1:
|
||||
return false
|
||||
|
||||
true
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#split
|
||||
func split*[T](lst: openArray[T], N: Positive): seq[seq[T]] =
|
||||
## split lst in N pieces, with each piece having `len(lst) div N` or
|
||||
@ -54,8 +29,6 @@ func get_new_recent_block_roots*(old_block_roots: seq[Eth2Digest],
|
||||
for _ in 0 ..< min(d, old_block_roots.len):
|
||||
result.add parent_hash
|
||||
|
||||
func ceil_div8*(v: int): int = (v + 7) div 8 # TODO use a proper bitarray!
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#integer_squareroot
|
||||
func integer_squareroot*(n: SomeInteger): SomeInteger =
|
||||
## The largest integer ``x`` such that ``x**2`` is less than ``n``.
|
||||
|
@ -11,7 +11,7 @@
|
||||
import
|
||||
endians, typetraits, options, algorithm,
|
||||
faststreams/input_stream, serialization, eth/common, nimcrypto/keccak,
|
||||
./spec/[crypto, datatypes, digest]
|
||||
./spec/[bitfield, crypto, datatypes, digest]
|
||||
|
||||
# ################### Helper functions ###################################
|
||||
|
||||
@ -93,6 +93,9 @@ func sszLen(v: seq | array): int =
|
||||
for i in v:
|
||||
result += sszLen(i)
|
||||
|
||||
func sszLen(v: BitField): int =
|
||||
sszLen(v.bits)
|
||||
|
||||
# fromBytesSSZ copies the wire representation to a Nim variable,
|
||||
# assuming there's enough data in the buffer
|
||||
func fromBytesSSZ(T: type SomeInteger, data: openarray[byte]): T =
|
||||
@ -176,6 +179,9 @@ proc writeValue*(w: var SszWriter, obj: auto) =
|
||||
# https://github.com/nim-lang/Nim/issues/9984
|
||||
for elem in obj:
|
||||
w.writeValue elem
|
||||
elif obj is BitField:
|
||||
for elem in obj.bits:
|
||||
w.writeValue elem
|
||||
else:
|
||||
obj.serializeFields(fieldName, field):
|
||||
# for research/serialized_sizes, remove when appropriate
|
||||
@ -227,6 +233,11 @@ proc readValue*(r: var SszReader, result: var auto) =
|
||||
while r.stream[].pos < endPos:
|
||||
result.add r.readValue(ElemType)
|
||||
|
||||
elif T is BitField:
|
||||
type ElemType = type(result.bits[0])
|
||||
while r.stream[].pos < endPos:
|
||||
result.bits.add r.readValue(ElemType)
|
||||
|
||||
elif T is array:
|
||||
type ElemType = type(result[0])
|
||||
var i = 0
|
||||
@ -308,6 +319,10 @@ func hash_tree_root*[T: seq|array](x: T): array[32, byte] =
|
||||
## Sequences are tree-hashed
|
||||
merkleHash(x)
|
||||
|
||||
func hash_tree_root*[T: BitField](x: T): array[32, byte] =
|
||||
## Sequences are tree-hashed
|
||||
merkleHash(x.bits)
|
||||
|
||||
func hash_tree_root*[T: object|tuple](x: T): array[32, byte] =
|
||||
## Containers have their fields recursively hashed, concatenated and hashed
|
||||
withHash:
|
||||
|
@ -33,7 +33,7 @@
|
||||
import
|
||||
algorithm, collections/sets, chronicles, math, options, sequtils, tables,
|
||||
./extras, ./ssz,
|
||||
./spec/[beaconstate, crypto, datatypes, digest, helpers, validator]
|
||||
./spec/[beaconstate, bitfield, crypto, datatypes, digest, helpers, validator]
|
||||
|
||||
func flatten[T](v: openArray[seq[T]]): seq[T] =
|
||||
# TODO not in nim - doh.
|
||||
@ -182,7 +182,7 @@ proc processProposerSlashings(
|
||||
func verify_slashable_attestation(state: BeaconState, slashable_attestation: SlashableAttestation): bool =
|
||||
# Verify validity of ``slashable_attestation`` fields.
|
||||
|
||||
if anyIt(slashable_attestation.custody_bitfield, it != 0): # [TO BE REMOVED IN PHASE 1]
|
||||
if anyIt(slashable_attestation.custody_bitfield.bits, it != 0): # [TO BE REMOVED IN PHASE 1]
|
||||
return false
|
||||
|
||||
if len(slashable_attestation.validator_indices) == 0:
|
||||
@ -192,7 +192,8 @@ func verify_slashable_attestation(state: BeaconState, slashable_attestation: Sla
|
||||
if slashable_attestation.validator_indices[i] >= slashable_attestation.validator_indices[i + 1]:
|
||||
return false
|
||||
|
||||
if not verify_bitfield(slashable_attestation.custody_bitfield, len(slashable_attestation.validator_indices)):
|
||||
if not verify_bitfield(slashable_attestation.custody_bitfield,
|
||||
len(slashable_attestation.validator_indices)):
|
||||
return false
|
||||
|
||||
if len(slashable_attestation.validator_indices) > MAX_INDICES_PER_SLASHABLE_VOTE:
|
||||
@ -203,7 +204,7 @@ func verify_slashable_attestation(state: BeaconState, slashable_attestation: Sla
|
||||
custody_bit_1_indices: seq[uint64] = @[]
|
||||
|
||||
for i, validator_index in slashable_attestation.validator_indices:
|
||||
if get_bitfield_bit(slashable_attestation.custody_bitfield, i) == 0b0:
|
||||
if not get_bitfield_bit(slashable_attestation.custody_bitfield, i):
|
||||
custody_bit_0_indices.add(validator_index)
|
||||
else:
|
||||
custody_bit_1_indices.add(validator_index)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import
|
||||
confutils,
|
||||
../beacon_chain/[extras, ssz],
|
||||
../beacon_chain/spec/[beaconstate, datatypes, digest, validator],
|
||||
../beacon_chain/spec/[beaconstate, bitfield, datatypes, digest, validator],
|
||||
../tests/testutil
|
||||
|
||||
proc stateSize(deposits: int, maxContent = false) =
|
||||
@ -19,7 +19,7 @@ proc stateSize(deposits: int, maxContent = false) =
|
||||
validatorsPerCommittee =
|
||||
len(crosslink_committees[0].committee) # close enough..
|
||||
for a in state.latest_attestations.mitems():
|
||||
a.aggregation_bitfield.setLen(validatorsPerCommittee)
|
||||
a.aggregation_bitfield = BitField.init(validatorsPerCommittee)
|
||||
echo "Validators: ", deposits, ", total: ", SSZ.encode(state).len
|
||||
|
||||
dispatch(stateSize)
|
||||
|
@ -9,6 +9,7 @@ import
|
||||
./test_attestation_pool,
|
||||
./test_beacon_chain_db,
|
||||
./test_beacon_node,
|
||||
./test_bitfield,
|
||||
./test_beaconstate,
|
||||
./test_block_pool,
|
||||
./test_helpers,
|
||||
|
@ -4,10 +4,6 @@ set -eux
|
||||
|
||||
. $(dirname $0)/vars.sh
|
||||
|
||||
if [[ "$1" == "0" ]]; then
|
||||
BOOTSTRAP_NODES_FLAG=""
|
||||
fi
|
||||
|
||||
DATA_DIR=$SIMULATION_DIR/node-${1}
|
||||
|
||||
V_PREFIX="$VALIDATORS_DIR/v$(printf '%06d' ${1})"
|
||||
@ -35,4 +31,3 @@ $BEACON_NODE_BIN \
|
||||
--udpPort:$PORT \
|
||||
$NAT_FLAG \
|
||||
--stateSnapshot:$SNAPSHOT_FILE
|
||||
|
||||
|
@ -66,8 +66,6 @@ COMMANDS=()
|
||||
LAST_NODE=$(( $NUM_NODES - 1 ))
|
||||
|
||||
for i in $(seq 0 $LAST_NODE); do
|
||||
BOOTSTRAP_NODES_FLAG="--bootstrapNodesFile:$MASTER_NODE_ADDRESS_FILE"
|
||||
|
||||
if [[ "$i" == "0" ]]; then
|
||||
sleep 0
|
||||
elif [ "$USE_MULTITAIL" = "no" ]; then
|
||||
|
27
tests/test_bitfield.nim
Normal file
27
tests/test_bitfield.nim
Normal file
@ -0,0 +1,27 @@
|
||||
import
|
||||
unittest,
|
||||
../beacon_chain/spec/[bitfield]
|
||||
|
||||
suite "BitField":
|
||||
test "roundtrips":
|
||||
var
|
||||
a = BitField.init(100)
|
||||
b = BitField.init(100)
|
||||
|
||||
check:
|
||||
not a.get_bitfield_bit(0)
|
||||
|
||||
a.set_bitfield_bit(1)
|
||||
|
||||
check:
|
||||
not a.get_bitfield_bit(0)
|
||||
a.get_bitfield_bit(1)
|
||||
|
||||
b.set_bitfield_bit(2)
|
||||
|
||||
a.combine(b)
|
||||
|
||||
check:
|
||||
not a.get_bitfield_bit(0)
|
||||
a.get_bitfield_bit(1)
|
||||
a.get_bitfield_bit(2)
|
@ -9,7 +9,7 @@ import
|
||||
options, sequtils,
|
||||
eth/trie/[db],
|
||||
../beacon_chain/[beacon_chain_db, extras, ssz, state_transition, validator_pool],
|
||||
../beacon_chain/spec/[beaconstate, crypto, datatypes, digest, helpers, validator]
|
||||
../beacon_chain/spec/[beaconstate, bitfield, crypto, datatypes, digest, helpers, validator]
|
||||
|
||||
func makeFakeValidatorPrivKey*(i: int): ValidatorPrivKey =
|
||||
var i = i + 1 # 0 does not work, as private key...
|
||||
@ -176,8 +176,8 @@ proc makeAttestation*(
|
||||
doAssert sac_index != -1, "find_shard_committe should guarantee this"
|
||||
|
||||
var
|
||||
aggregation_bitfield = repeat(0'u8, ceil_div8(sac.committee.len))
|
||||
bitSet(aggregation_bitfield, sac_index)
|
||||
aggregation_bitfield = BitField.init(sac.committee.len)
|
||||
set_bitfield_bit(aggregation_bitfield, sac_index)
|
||||
|
||||
let
|
||||
msg = hash_tree_root_final(
|
||||
@ -197,7 +197,7 @@ proc makeAttestation*(
|
||||
data: data,
|
||||
aggregation_bitfield: aggregation_bitfield,
|
||||
aggregate_signature: sig,
|
||||
custody_bitfield: repeat(0'u8, aggregation_bitfield.len)
|
||||
custody_bitfield: BitField.init(sac.committee.len)
|
||||
)
|
||||
|
||||
proc makeTestDB*(tailState: BeaconState, tailBlock: BeaconBlock): BeaconChainDB =
|
||||
|
Loading…
x
Reference in New Issue
Block a user