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:
Jacek Sieka 2019-03-26 19:32:35 -06:00 committed by GitHub
parent 803a0570be
commit 81c66fbce0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 94 additions and 127 deletions

View File

@ -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?

View File

@ -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)

View File

@ -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 =

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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 =

View File

@ -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)) == []

View File

@ -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)

View File

@ -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)

View File

@ -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)