use signed_root as canonical block root (#211)
* no need to pass prev_block_root when updating state * some Slot fixes * fix `hash_tree_root` for Slot, Epoch * detect missing hash_tree_root type support * remove some <0.5 state checks
This commit is contained in:
parent
803a0570be
commit
81c66fbce0
|
@ -59,7 +59,7 @@ proc putState*(db: BeaconChainDB, value: BeaconState) =
|
|||
db.putState(hash_tree_root(value), value)
|
||||
|
||||
proc putBlock*(db: BeaconChainDB, value: BeaconBlock) =
|
||||
db.putBlock(hash_tree_root(value), value)
|
||||
db.putBlock(signed_root(value), value)
|
||||
|
||||
proc putHeadBlock*(db: BeaconChainDB, key: Eth2Digest) =
|
||||
db.backend.put(subkey(kHeadBlock), key.data) # TODO head block?
|
||||
|
|
|
@ -144,7 +144,7 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
|
|||
let
|
||||
tailState = Json.loadFile(snapshotFile, BeaconState)
|
||||
tailBlock = get_initial_beacon_block(tailState)
|
||||
blockRoot = hash_tree_root(tailBlock)
|
||||
blockRoot = signed_root(tailBlock)
|
||||
|
||||
notice "Creating new database from snapshot",
|
||||
blockRoot = shortLog(blockRoot),
|
||||
|
@ -286,15 +286,14 @@ proc makeAttestation(node: BeaconNode,
|
|||
shard: uint64,
|
||||
committeeLen: int,
|
||||
indexInCommittee: int) {.async.} =
|
||||
|
||||
|
||||
# TODO - move that to "updateState"
|
||||
# Epoch underflow - https://github.com/status-im/nim-beacon-chain/issues/207
|
||||
doAssert node.state.data.current_justified_epoch != GENESIS_EPOCH - 1,
|
||||
"Underflow in justified epoch field before making attestation"
|
||||
|
||||
let
|
||||
attestationData =
|
||||
makeAttestationData(node.state.data, shard, node.state.blck.root)
|
||||
attestationData = makeAttestationData(state, shard, head.root)
|
||||
|
||||
# Careful - after await. node.state (etc) might have changed in async race
|
||||
validatorSignature = await validator.signAttestation(attestationData)
|
||||
|
@ -359,7 +358,7 @@ proc proposeBlock(node: BeaconNode,
|
|||
)
|
||||
|
||||
let ok =
|
||||
updateState(node.state.data, head.root, newBlock, {skipValidation})
|
||||
updateState(node.state.data, newBlock, {skipValidation})
|
||||
doAssert ok # TODO: err, could this fail somehow?
|
||||
node.state.root = hash_tree_root(node.state.data)
|
||||
|
||||
|
@ -368,7 +367,7 @@ proc proposeBlock(node: BeaconNode,
|
|||
newBlock.signature =
|
||||
await validator.signBlockProposal(node.state.data.fork, newBlock)
|
||||
|
||||
let blockRoot = hash_tree_root(newBlock)
|
||||
let blockRoot = signed_root(newBlock)
|
||||
|
||||
# TODO return new BlockRef from add?
|
||||
let newBlockRef = node.blockPool.add(node.state, blockRoot, newBlock)
|
||||
|
@ -415,7 +414,7 @@ proc onAttestation(node: BeaconNode, attestation: Attestation) =
|
|||
proc onBeaconBlock(node: BeaconNode, blck: BeaconBlock) =
|
||||
# We received a block but don't know much about it yet - in particular, we
|
||||
# don't know if it's part of the chain we're currently building.
|
||||
let blockRoot = hash_tree_root(blck)
|
||||
let blockRoot = signed_root(blck)
|
||||
debug "Block received",
|
||||
blck = shortLog(blck),
|
||||
blockRoot = shortLog(blockRoot)
|
||||
|
|
|
@ -141,7 +141,7 @@ proc add*(
|
|||
## the state parameter may be updated to include the given block, if
|
||||
## everything checks out
|
||||
# TODO reevaluate passing the state in like this
|
||||
doAssert blockRoot == hash_tree_root(blck)
|
||||
doAssert blockRoot == signed_root(blck)
|
||||
|
||||
# Already seen this block??
|
||||
if blockRoot in pool.blocks:
|
||||
|
@ -177,7 +177,7 @@ proc add*(
|
|||
# but maybe we should use it as a hint that our clock is wrong?
|
||||
updateState(pool, state, parent, blck.slot - 1)
|
||||
|
||||
if not updateState(state.data, parent.root, blck, {}):
|
||||
if not updateState(state.data, blck, {}):
|
||||
# TODO find a better way to log all this block data
|
||||
notice "Invalid block",
|
||||
blck = shortLog(blck),
|
||||
|
@ -304,8 +304,8 @@ proc checkUnresolved*(pool: var BlockPool): seq[Eth2Digest] =
|
|||
proc skipAndUpdateState(
|
||||
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
|
||||
afterUpdate: proc (state: BeaconState)): bool =
|
||||
skipSlots(state, blck.previous_block_root, blck.slot - 1, afterUpdate)
|
||||
let ok = updateState(state, blck.previous_block_root, blck, flags)
|
||||
skipSlots(state, blck.slot - 1, afterUpdate)
|
||||
let ok = updateState(state, blck, flags)
|
||||
|
||||
afterUpdate(state)
|
||||
|
||||
|
@ -350,7 +350,7 @@ proc updateState*(
|
|||
state.blck = blck
|
||||
state.root = ancestors[0].data.state_root
|
||||
|
||||
skipSlots(state.data, state.blck.root, slot) do (state: BeaconState):
|
||||
skipSlots(state.data, slot) do (state: BeaconState):
|
||||
pool.maybePutState(state)
|
||||
|
||||
return
|
||||
|
@ -398,13 +398,10 @@ proc updateState*(
|
|||
for i in countdown(ancestors.len - 2, 0):
|
||||
let last = ancestors[i]
|
||||
|
||||
skipSlots(
|
||||
state.data, last.data.previous_block_root,
|
||||
last.data.slot - 1) do(state: BeaconState):
|
||||
skipSlots(state.data, last.data.slot - 1) do(state: BeaconState):
|
||||
pool.maybePutState(state)
|
||||
|
||||
let ok = updateState(
|
||||
state.data, last.data.previous_block_root, last.data, {skipValidation})
|
||||
let ok = updateState(state.data, last.data, {skipValidation})
|
||||
doAssert ok,
|
||||
"We only keep validated blocks in the database, should never fail"
|
||||
|
||||
|
@ -413,7 +410,7 @@ proc updateState*(
|
|||
|
||||
pool.maybePutState(state.data)
|
||||
|
||||
skipSlots(state.data, state.blck.root, slot) do (state: BeaconState):
|
||||
skipSlots(state.data, slot) do (state: BeaconState):
|
||||
pool.maybePutState(state)
|
||||
|
||||
proc loadTailState*(pool: BlockPool): StateData =
|
||||
|
|
|
@ -219,7 +219,7 @@ func get_temporary_block_header*(blck: BeaconBlock): BeaconBlockHeader =
|
|||
## Return the block header corresponding to a block with ``state_root`` set
|
||||
## to ``ZERO_HASH``.
|
||||
BeaconBlockHeader(
|
||||
slot: blck.slot.uint64,
|
||||
slot: blck.slot,
|
||||
previous_block_root: blck.previous_block_root,
|
||||
state_root: ZERO_HASH,
|
||||
block_body_root: hash_tree_root(blck.body),
|
||||
|
@ -230,7 +230,7 @@ func get_temporary_block_header*(blck: BeaconBlock): BeaconBlockHeader =
|
|||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#on-genesis
|
||||
func get_empty_block*(): BeaconBlock =
|
||||
# Nim default values fill this in mostly correctly.
|
||||
result.slot = GENESIS_SLOT
|
||||
BeaconBlock(slot: GENESIS_SLOT)
|
||||
|
||||
func get_genesis_beacon_state*(
|
||||
genesis_validator_deposits: openArray[Deposit],
|
||||
|
@ -323,7 +323,7 @@ func get_genesis_beacon_state*(
|
|||
state
|
||||
|
||||
# TODO candidate for spec?
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#on-genesis
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.5.1/specs/core/0_beacon-chain.md#on-genesis
|
||||
func get_initial_beacon_block*(state: BeaconState): BeaconBlock =
|
||||
BeaconBlock(
|
||||
slot: GENESIS_SLOT,
|
||||
|
|
|
@ -328,7 +328,7 @@ type
|
|||
|
||||
#https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#beaconblockheader
|
||||
BeaconBlockHeader* = object
|
||||
slot*: uint64
|
||||
slot*: Slot
|
||||
previous_block_root*: Eth2Digest
|
||||
state_root*: Eth2Digest
|
||||
block_body_root*: Eth2Digest
|
||||
|
|
|
@ -40,6 +40,9 @@ serializationFormat SSZ,
|
|||
proc init*(T: type SszReader, stream: ByteStreamVar): T =
|
||||
result.stream = stream
|
||||
|
||||
func toSSZType(x: Slot|Epoch): auto = x.uint64
|
||||
func toSSZType(x: auto): auto = x
|
||||
|
||||
# toBytesSSZ convert simple fixed-length types to their SSZ wire representation
|
||||
func toBytesSSZ(x: SomeInteger): array[sizeof(x), byte] =
|
||||
## Convert directly to bytes the size of the int. (e.g. ``uint16 = 2 bytes``)
|
||||
|
@ -78,9 +81,9 @@ type
|
|||
# TODO can't put ranges like ValidatorIndex in here:
|
||||
# https://github.com/nim-lang/Nim/issues/10027
|
||||
SomeInteger | EthAddress | Eth2Digest | ValidatorPubKey | ValidatorSig |
|
||||
bool
|
||||
bool | Slot | Epoch
|
||||
|
||||
func sszLen(v: BasicType): int = toBytesSSZ(v).len
|
||||
func sszLen(v: BasicType): int = toBytesSSZ(v.toSSZType()).len
|
||||
func sszLen(v: ValidatorIndex): int = toBytesSSZ(v).len
|
||||
|
||||
func sszLen(v: object | tuple): int =
|
||||
|
@ -156,9 +159,6 @@ proc endRecord*(w: var SszWriter, memo: RecordWritingMemo) =
|
|||
let finalSize = uint32(w.stream.pos - memo.initialStreamPos - 4)
|
||||
memo.sizePrefixCursor.endWrite(finalSize.toBytesSSZ)
|
||||
|
||||
func toSSZType(x: Slot|Epoch): auto = x.uint64
|
||||
func toSSZType(x: auto): auto = x
|
||||
|
||||
proc writeValue*(w: var SszWriter, obj: auto) =
|
||||
# We are not using overloads here, because this leads to
|
||||
# slightly better error messages when the user provides
|
||||
|
@ -303,9 +303,10 @@ proc pack(values: seq|array): iterator(): Chunk =
|
|||
# TODO I get a feeling a copy of the array is taken to the closure, which
|
||||
# also needs fixing
|
||||
# TODO avoid closure iterators that involve GC
|
||||
var tmp = newSeqOfCap[byte](values.len() * sizeof(toBytesSSZ(values[0])))
|
||||
var tmp =
|
||||
newSeqOfCap[byte](values.len() * sizeof(toBytesSSZ(values[0].toSSZType())))
|
||||
for v in values:
|
||||
tmp.add toBytesSSZ(v)
|
||||
tmp.add toBytesSSZ(v.toSSZType)
|
||||
|
||||
for v in 0..<tmp.len div sizeof(Chunk):
|
||||
var c: Chunk
|
||||
|
@ -385,23 +386,27 @@ func hash_tree_root*[T](value: T): Eth2Digest =
|
|||
var roots = iterator(): Chunk =
|
||||
for v in value.fields:
|
||||
yield hash_tree_root(v).data
|
||||
|
||||
merkleize(roots)
|
||||
else:
|
||||
static: doAssert false, "Unexpected type: " & T.name
|
||||
)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/simple-serialize.md#signed-roots
|
||||
func signed_root*[T: object](x: T): array[32, byte] =
|
||||
func signed_root*[T: object](x: T): Eth2Digest =
|
||||
# TODO write tests for this (check vs hash_tree_root)
|
||||
|
||||
var found_field_name = false
|
||||
|
||||
## TODO this isn't how 0.5 defines signed_root, but works well enough
|
||||
## for now.
|
||||
withHash:
|
||||
var roots = iterator(): Chunk =
|
||||
for name, field in x.fieldPairs:
|
||||
# TODO we should truncate the last field, regardless of its name.. this
|
||||
# hack works for now - how to skip the last fieldPair though??
|
||||
if name == "signature":
|
||||
found_field_name = true
|
||||
break
|
||||
h.update hash_tree_root(field.toSSZType).data
|
||||
yield hash_tree_root(field).data
|
||||
|
||||
doAssert found_field_name
|
||||
let root = merkleize(roots)
|
||||
|
||||
doAssert found_field_name
|
||||
|
||||
Eth2Digest(data: root)
|
||||
|
|
|
@ -39,7 +39,7 @@ func flatten[T](v: openArray[seq[T]]): seq[T] =
|
|||
# TODO not in nim - doh.
|
||||
for x in v: result.add x
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#block-header
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#block-header
|
||||
proc processBlockHeader(
|
||||
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
||||
# Verify that the slots match
|
||||
|
@ -49,18 +49,14 @@ proc processBlockHeader(
|
|||
state_slot = humaneSlotNum(state.slot)
|
||||
return false
|
||||
|
||||
## https://github.com/ethereum/eth2.0-specs/pull/816/files remove when
|
||||
## switched to 0.5.1
|
||||
when false:
|
||||
## TODO Re-enable when it works; currently, some code in processBlock
|
||||
## also checks this invariant in a different way. tag as 0.4.0.
|
||||
if not (blck.previous_block_root.data ==
|
||||
signed_root(state.latest_block_header)):
|
||||
notice "Block header: previous block root mismatch",
|
||||
previous_block_root = blck.previous_block_root,
|
||||
latest_block_header = state.latest_block_header,
|
||||
latest_block_header_root = hash_tree_root(state.latest_block_header)
|
||||
return false
|
||||
# state_root not set yet, when skipping validation
|
||||
if skipValidation notin flags and not (blck.previous_block_root ==
|
||||
signed_root(state.latest_block_header)):
|
||||
notice "Block header: previous block root mismatch",
|
||||
latest_block_header = state.latest_block_header,
|
||||
blck = shortLog(blck),
|
||||
latest_block_header_root = shortLog(signed_root(state.latest_block_header))
|
||||
return false
|
||||
|
||||
state.latest_block_header = get_temporary_block_header(blck)
|
||||
|
||||
|
@ -68,12 +64,12 @@ proc processBlockHeader(
|
|||
state.validator_registry[get_beacon_proposer_index(state, state.slot)]
|
||||
if skipValidation notin flags and not bls_verify(
|
||||
proposer.pubkey,
|
||||
signed_root(blck),
|
||||
signed_root(blck).data,
|
||||
blck.signature,
|
||||
get_domain(state.fork, get_current_epoch(state), DOMAIN_BEACON_BLOCK)):
|
||||
notice "Block header: invalid block header",
|
||||
proposer_pubkey = proposer.pubkey,
|
||||
signed_root_block = signed_root(blck),
|
||||
block_root = shortLog(signed_root(blck)),
|
||||
block_signature = blck.signature
|
||||
return false
|
||||
|
||||
|
@ -152,7 +148,7 @@ proc processProposerSlashings(
|
|||
for i, header in @[proposer_slashing.header_1, proposer_slashing.header_2]:
|
||||
if not bls_verify(
|
||||
proposer.pubkey,
|
||||
signed_root(header),
|
||||
signed_root(header).data,
|
||||
header.signature,
|
||||
get_domain(
|
||||
state.fork, slot_to_epoch(header.slot), DOMAIN_BEACON_BLOCK)):
|
||||
|
@ -344,7 +340,7 @@ proc processExits(
|
|||
# Verify signature
|
||||
if skipValidation notin flags:
|
||||
if not bls_verify(
|
||||
validator.pubkey, signed_root(exit), exit.signature,
|
||||
validator.pubkey, signed_root(exit).data, exit.signature,
|
||||
get_domain(state.fork, exit.epoch, DOMAIN_VOLUNTARY_EXIT)):
|
||||
notice "Exit: invalid signature"
|
||||
return false
|
||||
|
@ -438,7 +434,7 @@ proc processTransfers(state: var BeaconState, blck: BeaconBlock,
|
|||
# Verify that the signature is valid
|
||||
if skipValidation notin flags:
|
||||
if not bls_verify(
|
||||
pubkey=transfer.pubkey, signed_root(transfer), transfer.signature,
|
||||
transfer.pubkey, signed_root(transfer).data, transfer.signature,
|
||||
get_domain(
|
||||
state.fork, slot_to_epoch(transfer.slot), DOMAIN_TRANSFER)):
|
||||
notice "Transfer: incorrect signature"
|
||||
|
@ -454,23 +450,17 @@ proc processTransfers(state: var BeaconState, blck: BeaconBlock,
|
|||
|
||||
true
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#per-slot-processing
|
||||
func advanceSlot(state: var BeaconState) =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#per-slot-processing
|
||||
func advance_slot(state: var BeaconState) =
|
||||
## Time on the beacon chain moves in slots. Every time we make it to a new
|
||||
## slot, a proposer creates a block to represent the state of the beacon
|
||||
## chain at that time. In case the proposer is missing, it may happen that
|
||||
## the no block is produced during the slot.
|
||||
if false and not (state.slot > GENESIS_SLOT):
|
||||
return
|
||||
|
||||
# TODO 0.4.0-ish still
|
||||
state.slot += 1
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#state-caching
|
||||
func cacheState(state: var BeaconState) =
|
||||
if not (state.slot > GENESIS_SLOT):
|
||||
return
|
||||
|
||||
let previous_slot_state_root = hash_tree_root(state)
|
||||
|
||||
# store the previous slot's post state transition root
|
||||
|
@ -483,13 +473,7 @@ func cacheState(state: var BeaconState) =
|
|||
|
||||
# store latest known block for previous slot
|
||||
state.latest_block_roots[state.slot mod SLOTS_PER_HISTORICAL_ROOT] =
|
||||
Eth2Digest(data: signed_root(state.latest_block_header))
|
||||
|
||||
func processSlot(state: var BeaconState, previous_block_root: Eth2Digest) =
|
||||
advanceSlot(state)
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#block-roots
|
||||
state.latest_block_roots[(state.slot - 1) mod SLOTS_PER_HISTORICAL_ROOT] =
|
||||
previous_block_root
|
||||
signed_root(state.latest_block_header)
|
||||
|
||||
proc processBlock(
|
||||
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
||||
|
@ -499,19 +483,6 @@ proc processBlock(
|
|||
# TODO when there's a failure, we should reset the state!
|
||||
# TODO probably better to do all verification first, then apply state changes
|
||||
|
||||
# Spec does not have this check explicitly, but requires that this condition
|
||||
# holds - so we give verify it as well - this would happen naturally if
|
||||
# `blck.previous_block_root` was used in `processSlot` - but that doesn't cut it for
|
||||
# blockless slot processing.
|
||||
# TODO compare with processBlockHeader check, might be redundant and to be removed
|
||||
let stateParentRoot =
|
||||
state.latest_block_roots[(state.slot - 1) mod SLOTS_PER_HISTORICAL_ROOT]
|
||||
if not (blck.previous_block_root == stateParentRoot):
|
||||
notice "Unexpected parent root",
|
||||
blockParentRoot = blck.previous_block_root,
|
||||
stateParentRoot
|
||||
return false
|
||||
|
||||
if not processBlockHeader(state, blck, flags):
|
||||
notice "Block header not valid", slot = humaneSlotNum(state.slot)
|
||||
return false
|
||||
|
@ -1119,8 +1090,7 @@ proc verifyStateRoot(state: BeaconState, blck: BeaconBlock): bool =
|
|||
else:
|
||||
true
|
||||
|
||||
proc advanceState*(
|
||||
state: var BeaconState, previous_block_root: Eth2Digest) =
|
||||
proc advanceState*(state: var BeaconState) =
|
||||
## Sometimes we need to update the state even though we don't have a block at
|
||||
## hand - this happens for example when a block proposer fails to produce a
|
||||
## a block.
|
||||
|
@ -1143,11 +1113,10 @@ proc advanceState*(
|
|||
## 3. The per-slot transitions, which happens at every slot.
|
||||
## The per-slot transitions focus on the slot counter and block roots
|
||||
## records updates.
|
||||
processSlot(state, previous_block_root)
|
||||
advance_slot(state)
|
||||
|
||||
proc updateState*(
|
||||
state: var BeaconState, previous_block_root: Eth2Digest,
|
||||
new_block: BeaconBlock, flags: UpdateFlags): bool =
|
||||
state: var BeaconState, new_block: BeaconBlock, flags: UpdateFlags): bool =
|
||||
## Time in the beacon chain moves by slots. Every time (haha.) that happens,
|
||||
## we will update the beacon state. Normally, the state updates will be driven
|
||||
## by the contents of a new block, but it may happen that the block goes
|
||||
|
@ -1181,7 +1150,7 @@ proc updateState*(
|
|||
var old_state = state
|
||||
|
||||
# These should never fail.
|
||||
advanceState(state, previous_block_root)
|
||||
advanceState(state)
|
||||
|
||||
# Block updates - these happen when there's a new block being suggested
|
||||
# by the block proposer. Every actor in the network will update its state
|
||||
|
@ -1201,7 +1170,7 @@ proc updateState*(
|
|||
state = old_state
|
||||
false
|
||||
|
||||
proc skipSlots*(state: var BeaconState, parentRoot: Eth2Digest, slot: Slot,
|
||||
proc skipSlots*(state: var BeaconState, slot: Slot,
|
||||
afterSlot: proc (state: BeaconState) = nil) =
|
||||
if state.slot < slot:
|
||||
debug "Advancing state with empty slots",
|
||||
|
@ -1209,7 +1178,7 @@ proc skipSlots*(state: var BeaconState, parentRoot: Eth2Digest, slot: Slot,
|
|||
stateSlot = humaneSlotNum(state.slot)
|
||||
|
||||
while state.slot < slot:
|
||||
advanceState(state, parentRoot)
|
||||
advanceState(state)
|
||||
|
||||
if not afterSlot.isNil:
|
||||
afterSlot(state)
|
||||
|
|
|
@ -28,7 +28,7 @@ proc signBlockProposal*(v: AttachedValidator, fork: Fork,
|
|||
blck: BeaconBlock): Future[ValidatorSig] {.async.} =
|
||||
if v.kind == inProcess:
|
||||
await sleepAsync(1)
|
||||
result = bls_sign(v.privKey, signed_root(blck),
|
||||
result = bls_sign(v.privKey, signed_root(blck).data,
|
||||
get_domain(fork, slot_to_epoch(blck.slot), DOMAIN_BEACON_BLOCK))
|
||||
else:
|
||||
# TODO:
|
||||
|
|
|
@ -60,7 +60,7 @@ cli do(slots = 1945,
|
|||
var
|
||||
attestations: array[MIN_ATTESTATION_INCLUSION_DELAY, seq[Attestation]]
|
||||
state = genesisState
|
||||
latest_block_root = hash_tree_root(genesisBlock)
|
||||
latest_block_root = signed_root(genesisBlock)
|
||||
timers: array[Timers, RunningStat]
|
||||
attesters: RunningStat
|
||||
r: Rand
|
||||
|
@ -90,7 +90,7 @@ cli do(slots = 1945,
|
|||
withTimer(timers[t]):
|
||||
blck = addBlock(state, latest_block_root, body, flags)
|
||||
latest_block_root = withTimerRet(timers[tHashBlock]):
|
||||
hash_tree_root(blck)
|
||||
signed_root(blck)
|
||||
|
||||
if attesterRatio > 0.0:
|
||||
# attesterRatio is the fraction of attesters that actually do their
|
||||
|
|
|
@ -28,7 +28,7 @@ suite "Attestation pool processing":
|
|||
pool = AttestationPool.init(blockPool)
|
||||
state = blockPool.loadTailState()
|
||||
# Slot 0 is a finalized slot - won't be making attestations for it..
|
||||
advanceState(state.data, state.blck.root)
|
||||
advanceState(state.data)
|
||||
|
||||
let
|
||||
# Create an attestation for slot 1 signed by the only attester we have!
|
||||
|
@ -51,7 +51,7 @@ suite "Attestation pool processing":
|
|||
pool = AttestationPool.init(blockPool)
|
||||
state = blockPool.loadTailState()
|
||||
# Slot 0 is a finalized slot - won't be making attestations for it..
|
||||
advanceState(state.data, state.blck.root)
|
||||
advanceState(state.data)
|
||||
|
||||
let
|
||||
# Create an attestation for slot 1 signed by the only attester we have!
|
||||
|
@ -60,7 +60,7 @@ suite "Attestation pool processing":
|
|||
attestation1 = makeAttestation(
|
||||
state.data, state.blck.root, crosslink_committees1[0].committee[0])
|
||||
|
||||
advanceState(state.data, state.blck.root)
|
||||
advanceState(state.data)
|
||||
|
||||
let
|
||||
crosslink_committees2 =
|
||||
|
|
|
@ -25,7 +25,7 @@ suite "Beacon chain DB":
|
|||
|
||||
let
|
||||
blck = BeaconBlock()
|
||||
root = hash_tree_root(blck)
|
||||
root = signed_root(blck)
|
||||
|
||||
db.putBlock(blck)
|
||||
|
||||
|
@ -58,11 +58,11 @@ suite "Beacon chain DB":
|
|||
|
||||
let
|
||||
a0 = BeaconBlock(slot: GENESIS_SLOT + 0)
|
||||
a0r = hash_tree_root(a0)
|
||||
a0r = signed_root(a0)
|
||||
a1 = BeaconBlock(slot: GENESIS_SLOT + 1, previous_block_root: a0r)
|
||||
a1r = hash_tree_root(a1)
|
||||
a1r = signed_root(a1)
|
||||
a2 = BeaconBlock(slot: GENESIS_SLOT + 2, previous_block_root: a1r)
|
||||
a2r = hash_tree_root(a2)
|
||||
a2r = signed_root(a2)
|
||||
|
||||
doAssert toSeq(db.getAncestors(a0r)) == []
|
||||
doAssert toSeq(db.getAncestors(a2r)) == []
|
||||
|
|
|
@ -36,7 +36,7 @@ suite "Block pool processing":
|
|||
|
||||
let
|
||||
b1 = makeBlock(state.data, state.blck.root, BeaconBlockBody())
|
||||
b1Root = hash_tree_root(b1)
|
||||
b1Root = signed_root(b1)
|
||||
|
||||
# TODO the return value is ugly here, need to fix and test..
|
||||
discard pool.add(state, b1Root, b1)
|
||||
|
@ -55,9 +55,9 @@ suite "Block pool processing":
|
|||
|
||||
let
|
||||
b1 = addBlock(state.data, state.blck.root, BeaconBlockBody(), {})
|
||||
b1Root = hash_tree_root(b1)
|
||||
b1Root = signed_root(b1)
|
||||
b2 = addBlock(state.data, b1Root, BeaconBlockBody(), {})
|
||||
b2Root = hash_tree_root(b2)
|
||||
b2Root = signed_root(b2)
|
||||
|
||||
discard pool.add(state, b2Root, b2)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
options, sequtils, unittest,
|
||||
options, sequtils, unittest, chronicles,
|
||||
./testutil,
|
||||
../beacon_chain/spec/[beaconstate, crypto, datatypes, digest, helpers, validator],
|
||||
../beacon_chain/[extras, state_transition, ssz]
|
||||
|
@ -21,23 +21,23 @@ suite "Block processing":
|
|||
genesisState = get_genesis_beacon_state(
|
||||
makeInitialDeposits(), 0, Eth1Data(), {})
|
||||
genesisBlock = get_initial_beacon_block(genesisState)
|
||||
genesisRoot = signed_root(genesisBlock)
|
||||
|
||||
test "Passes from genesis state, no block":
|
||||
var
|
||||
state = genesisState
|
||||
previous_block_root = hash_tree_root(genesisBlock)
|
||||
|
||||
advanceState(state, previous_block_root)
|
||||
advanceState(state)
|
||||
check:
|
||||
state.slot == genesisState.slot + 1
|
||||
|
||||
test "Passes from genesis state, empty block":
|
||||
var
|
||||
state = genesisState
|
||||
previous_block_root = hash_tree_root(genesisBlock)
|
||||
previous_block_root = signed_root(genesisBlock)
|
||||
new_block = makeBlock(state, previous_block_root, BeaconBlockBody())
|
||||
|
||||
let block_ok = updateState(state, previous_block_root, new_block, {})
|
||||
let block_ok = updateState(state, new_block, {})
|
||||
|
||||
check:
|
||||
block_ok
|
||||
|
@ -47,10 +47,9 @@ suite "Block processing":
|
|||
test "Passes through epoch update, no block":
|
||||
var
|
||||
state = genesisState
|
||||
previous_block_root = hash_tree_root(genesisBlock)
|
||||
|
||||
for i in 1..SLOTS_PER_EPOCH.int:
|
||||
advanceState(state, previous_block_root)
|
||||
advanceState(state)
|
||||
|
||||
check:
|
||||
state.slot == genesisState.slot + SLOTS_PER_EPOCH
|
||||
|
@ -58,18 +57,17 @@ suite "Block processing":
|
|||
test "Passes through epoch update, empty block":
|
||||
var
|
||||
state = genesisState
|
||||
previous_block_root = hash_tree_root(genesisBlock)
|
||||
previous_block_root = genesisRoot
|
||||
|
||||
for i in 1..SLOTS_PER_EPOCH.int:
|
||||
var new_block = makeBlock(state, previous_block_root, BeaconBlockBody())
|
||||
|
||||
let block_ok = updateState(
|
||||
state, previous_block_root, new_block, {})
|
||||
let block_ok = updateState(state, new_block, {})
|
||||
|
||||
check:
|
||||
block_ok
|
||||
|
||||
previous_block_root = hash_tree_root(new_block)
|
||||
previous_block_root = signed_root(new_block)
|
||||
|
||||
check:
|
||||
state.slot == genesisState.slot + SLOTS_PER_EPOCH
|
||||
|
@ -77,10 +75,10 @@ suite "Block processing":
|
|||
test "Attestation gets processed at epoch":
|
||||
var
|
||||
state = genesisState
|
||||
previous_block_root = hash_tree_root(genesisBlock)
|
||||
previous_block_root = genesisRoot
|
||||
|
||||
# Slot 0 is a finalized slot - won't be making attestations for it..
|
||||
advanceState(state, previous_block_root)
|
||||
advanceState(state)
|
||||
|
||||
let
|
||||
# Create an attestation for slot 1 signed by the only attester we have!
|
||||
|
@ -92,19 +90,19 @@ suite "Block processing":
|
|||
# Some time needs to pass before attestations are included - this is
|
||||
# to let the attestation propagate properly to interested participants
|
||||
while state.slot < GENESIS_SLOT + MIN_ATTESTATION_INCLUSION_DELAY + 1:
|
||||
advanceState(state, previous_block_root)
|
||||
advanceState(state)
|
||||
|
||||
let
|
||||
new_block = makeBlock(state, previous_block_root, BeaconBlockBody(
|
||||
attestations: @[attestation]
|
||||
))
|
||||
discard updateState(state, previous_block_root, new_block, {})
|
||||
discard updateState(state, new_block, {})
|
||||
|
||||
check:
|
||||
state.current_epoch_attestations.len == 1
|
||||
|
||||
while state.slot < 191:
|
||||
advanceState(state, previous_block_root)
|
||||
advanceState(state)
|
||||
|
||||
# Would need to process more epochs for the attestation to be removed from
|
||||
# the state! (per above bug)
|
||||
|
|
|
@ -106,12 +106,11 @@ proc addBlock*(
|
|||
slot: state.slot + 1,
|
||||
previous_block_root: previous_block_root,
|
||||
state_root: Eth2Digest(), # we need the new state first
|
||||
body: new_body,
|
||||
signature: ValidatorSig(), # we need the rest of the block first!
|
||||
body: new_body
|
||||
)
|
||||
|
||||
let block_ok = updateState(
|
||||
state, previous_block_root, new_block, {skipValidation})
|
||||
let block_ok = updateState(state, new_block, {skipValidation})
|
||||
doAssert block_ok
|
||||
|
||||
# Ok, we have the new state as it would look with the block applied - now we
|
||||
|
@ -126,12 +125,12 @@ proc addBlock*(
|
|||
let block_root = signed_root(new_block)
|
||||
# We have a signature - put it in the block and we should be done!
|
||||
new_block.signature =
|
||||
bls_sign(proposerPrivkey, block_root,
|
||||
bls_sign(proposerPrivkey, block_root.data,
|
||||
get_domain(state.fork, slot_to_epoch(new_block.slot), DOMAIN_BEACON_BLOCK))
|
||||
|
||||
doAssert bls_verify(
|
||||
proposer.pubkey,
|
||||
block_root, new_block.signature,
|
||||
block_root.data, new_block.signature,
|
||||
get_domain(state.fork, slot_to_epoch(new_block.slot), DOMAIN_BEACON_BLOCK)),
|
||||
"we just signed this message - it should pass verification!"
|
||||
|
||||
|
@ -192,7 +191,7 @@ proc makeAttestation*(
|
|||
|
||||
proc makeTestDB*(tailState: BeaconState, tailBlock: BeaconBlock): BeaconChainDB =
|
||||
let
|
||||
tailRoot = hash_tree_root(tailBlock)
|
||||
tailRoot = signed_root(tailBlock)
|
||||
|
||||
result = init(BeaconChainDB, newMemoryDB())
|
||||
result.putState(tailState)
|
||||
|
|
Loading…
Reference in New Issue