From 81c66fbce0ccd8ead545eee2aa7bfff97dc08a82 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 26 Mar 2019 19:32:35 -0600 Subject: [PATCH] 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 --- beacon_chain/beacon_chain_db.nim | 2 +- beacon_chain/beacon_node.nim | 13 +++--- beacon_chain/block_pool.nim | 19 ++++---- beacon_chain/spec/beaconstate.nim | 6 +-- beacon_chain/spec/datatypes.nim | 2 +- beacon_chain/ssz.nim | 35 ++++++++------ beacon_chain/state_transition.nim | 77 +++++++++---------------------- beacon_chain/validator_pool.nim | 2 +- research/state_sim.nim | 4 +- tests/test_attestation_pool.nim | 6 +-- tests/test_beacon_chain_db.nim | 8 ++-- tests/test_block_pool.nim | 6 +-- tests/test_state_transition.nim | 30 ++++++------ tests/testutil.nim | 11 ++--- 14 files changed, 94 insertions(+), 127 deletions(-) diff --git a/beacon_chain/beacon_chain_db.nim b/beacon_chain/beacon_chain_db.nim index 1d2b59eac..768d1615b 100644 --- a/beacon_chain/beacon_chain_db.nim +++ b/beacon_chain/beacon_chain_db.nim @@ -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? diff --git a/beacon_chain/beacon_node.nim b/beacon_chain/beacon_node.nim index d7ead1b1c..8f529752b 100644 --- a/beacon_chain/beacon_node.nim +++ b/beacon_chain/beacon_node.nim @@ -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) diff --git a/beacon_chain/block_pool.nim b/beacon_chain/block_pool.nim index df76ad041..f169a3bed 100644 --- a/beacon_chain/block_pool.nim +++ b/beacon_chain/block_pool.nim @@ -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 = diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index 33fccef04..254f7c1b6 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -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, diff --git a/beacon_chain/spec/datatypes.nim b/beacon_chain/spec/datatypes.nim index 7900395d1..8b4498bda 100644 --- a/beacon_chain/spec/datatypes.nim +++ b/beacon_chain/spec/datatypes.nim @@ -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 diff --git a/beacon_chain/ssz.nim b/beacon_chain/ssz.nim index f392d15b0..6adcb261a 100644 --- a/beacon_chain/ssz.nim +++ b/beacon_chain/ssz.nim @@ -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.. 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) diff --git a/beacon_chain/validator_pool.nim b/beacon_chain/validator_pool.nim index 11af48f27..200d5e2eb 100644 --- a/beacon_chain/validator_pool.nim +++ b/beacon_chain/validator_pool.nim @@ -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: diff --git a/research/state_sim.nim b/research/state_sim.nim index 7c7c6ea72..c63d5d11f 100644 --- a/research/state_sim.nim +++ b/research/state_sim.nim @@ -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 diff --git a/tests/test_attestation_pool.nim b/tests/test_attestation_pool.nim index b77dbc0b0..f5f0ed540 100644 --- a/tests/test_attestation_pool.nim +++ b/tests/test_attestation_pool.nim @@ -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 = diff --git a/tests/test_beacon_chain_db.nim b/tests/test_beacon_chain_db.nim index e2f977db2..eaddf3430 100644 --- a/tests/test_beacon_chain_db.nim +++ b/tests/test_beacon_chain_db.nim @@ -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)) == [] diff --git a/tests/test_block_pool.nim b/tests/test_block_pool.nim index 84f49eba0..d0916600a 100644 --- a/tests/test_block_pool.nim +++ b/tests/test_block_pool.nim @@ -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) diff --git a/tests/test_state_transition.nim b/tests/test_state_transition.nim index 8d23048c9..4358a22b0 100644 --- a/tests/test_state_transition.nim +++ b/tests/test_state_transition.nim @@ -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) diff --git a/tests/testutil.nim b/tests/testutil.nim index c60fc1f90..7f4ad9fd7 100644 --- a/tests/testutil.nim +++ b/tests/testutil.nim @@ -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)