From 562eafe1245f0382d765bbc2e1ebf0329b2dc8f7 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Wed, 13 Mar 2019 23:23:01 +0200 Subject: [PATCH] Finish the Spec/Epoch types refactoring --- beacon_chain/spec/beaconstate.nim | 11 +++++----- beacon_chain/spec/datatypes.nim | 34 ++++++++++++++++++++++--------- beacon_chain/spec/helpers.nim | 6 ++++-- beacon_chain/state_transition.nim | 6 +++--- beacon_chain/sync_protocol.nim | 31 +++++++++++++++------------- 5 files changed, 53 insertions(+), 35 deletions(-) diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index 6fb2c3498..28962a19c 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -218,7 +218,7 @@ func get_genesis_beacon_state*( for i in 0 ..< SHARD_COUNT: state.latest_crosslinks[i] = Crosslink( - epoch: GENESIS_EPOCH.uint64, crosslink_data_root: ZERO_HASH) + epoch: GENESIS_EPOCH, crosslink_data_root: ZERO_HASH) # Process genesis deposits for deposit in genesis_validator_deposits: @@ -401,8 +401,7 @@ proc checkAttestation*( return let expected_justified_block_root = - get_block_root( - state, get_epoch_start_slot(attestation.data.justified_epoch.Epoch)) + get_block_root(state, get_epoch_start_slot(attestation.data.justified_epoch)) if not (attestation.data.justified_block_root == expected_justified_block_root): warn("Unexpected justified block root", attestation_justified_block_root = attestation.data.justified_block_root, @@ -413,7 +412,7 @@ proc checkAttestation*( attestation.data.latest_crosslink, Crosslink( crosslink_data_root: attestation.data.crosslink_data_root, - epoch: slot_to_epoch(attestation_data_slot).uint64)]): + epoch: slot_to_epoch(attestation_data_slot))]): warn("Unexpected crosslink shard", state_latest_crosslinks_attestation_data_shard = state.latest_crosslinks[attestation.data.shard], @@ -516,12 +515,12 @@ proc makeAttestationData*( justified_block_root = get_block_root(state, justified_slot) AttestationData( - slot: state.slot.uint64, + slot: state.slot, shard: shard, beacon_block_root: beacon_block_root, epoch_boundary_root: epoch_boundary_root, crosslink_data_root: Eth2Digest(), # Stub in phase0 latest_crosslink: state.latest_crosslinks[shard], - justified_epoch: state.justified_epoch.uint64, + justified_epoch: state.justified_epoch, justified_block_root: justified_block_root, ) diff --git a/beacon_chain/spec/datatypes.nim b/beacon_chain/spec/datatypes.nim index 1a01b1165..eaa9dcc14 100644 --- a/beacon_chain/spec/datatypes.nim +++ b/beacon_chain/spec/datatypes.nim @@ -18,7 +18,8 @@ # types / composition import - eth/common, hashes, math, + hashes, math, + eth/[common, rlp], ./crypto, ./digest # TODO Data types: @@ -228,7 +229,7 @@ type # https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attestationdata AttestationData* = object - slot*: uint64 ##\ + slot*: Slot ##\ ## Slot number shard*: uint64 ##\ @@ -246,7 +247,7 @@ type latest_crosslink*: Crosslink ##\ ## Last crosslink - justified_epoch*: uint64 ##\ + justified_epoch*: Epoch ##\ ## Last justified epoch in the beacon state justified_block_root*: Eth2Digest ##\ @@ -284,7 +285,7 @@ type # https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#voluntaryexit VoluntaryExit* = object # Minimum epoch for processing exit - epoch*: uint64 + epoch*: Epoch # Index of the exiting validator validator_index*: uint64 # Validator signature @@ -451,7 +452,7 @@ type # https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#crosslink Crosslink* = object - epoch*: uint64 ##\ + epoch*: Epoch ##\ ## Epoch number crosslink_data_root*: Eth2Digest ##\ @@ -522,7 +523,7 @@ type func shortValidatorKey*(state: BeaconState, validatorIdx: int): string = ($state.validator_registry[validatorIdx].pubkey)[0..7] -template ethTimeUnit(typ: type) = +template ethTimeUnit(typ: type) {.dirty.} = proc `+`*(x: typ, y: uint64): typ {.borrow.} proc `-`*(x: typ, y: uint64): typ {.borrow.} proc `-`*(x: uint64, y: typ): typ {.borrow.} @@ -554,13 +555,26 @@ template ethTimeUnit(typ: type) = proc `$`*(x: typ): string {.borrow.} proc hash*(x: typ): Hash {.borrow.} -ethTimeUnit(Slot) -ethTimeUnit(Epoch) + # Serialization + proc read*(rlp: var Rlp, T: type typ): typ {.inline.} = + typ(rlp.read(uint64)) -func humaneSlotNum*(s: auto): uint64 = + proc append*(writer: var RlpWriter, value: typ) = + writer.append uint64(value) + + proc writeValue*(writer: var JsonWriter, value: typ) = + writeValue(writer, uint64 value) + + proc readValue*(reader: var JsonReader, value: var typ) = + value = typ reader.readValue(uint64) + +ethTimeUnit Slot +ethTimeUnit Epoch + +func humaneSlotNum*(s: Slot): uint64 = s.Slot - GENESIS_SLOT -func humaneEpochNum*(e: auto): uint64 = +func humaneEpochNum*(e: Epoch): uint64 = e.Epoch - GENESIS_EPOCH import nimcrypto, json_serialization diff --git a/beacon_chain/spec/helpers.nim b/beacon_chain/spec/helpers.nim index e2e89763b..622d8b8c2 100644 --- a/beacon_chain/spec/helpers.nim +++ b/beacon_chain/spec/helpers.nim @@ -218,11 +218,13 @@ func bytes_to_int*(data: seq[byte]): uint64 = # https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#int_to_bytes1-int_to_bytes2- # Have 1, 4, and 32-byte versions. 2+ more and maybe worth metaprogramming. -func int_to_bytes32*(x: uint64|Epoch) : array[32, byte] = +func int_to_bytes32*(x: uint64): array[32, byte] = ## Little-endian data representation ## TODO remove uint64 when those callers fade away for i in 0 ..< 8: - result[24 + i] = byte((x.uint64 shr i*8) and 0xff) + result[24 + i] = byte((x shr i*8) and 0xff) + +func int_to_bytes32*(x: Epoch): array[32, byte] {.borrow.} func int_to_bytes1*(x: int): array[1, byte] = assert x >= 0 diff --git a/beacon_chain/state_transition.nim b/beacon_chain/state_transition.nim index e8a4caaee..3d6df04c8 100644 --- a/beacon_chain/state_transition.nim +++ b/beacon_chain/state_transition.nim @@ -304,7 +304,7 @@ proc processExits( if skipValidation notin flags: if not bls_verify( validator.pubkey, signed_root(exit, "signature"), exit.signature, - get_domain(state.fork, exit.epoch.Epoch, DOMAIN_EXIT)): + get_domain(state.fork, exit.epoch, DOMAIN_EXIT)): notice "Exit: invalid signature" return false @@ -717,7 +717,7 @@ func processEpoch(state: var BeaconState) = if 3'u64 * total_attesting_balance(crosslink_committee) >= 2'u64 * get_total_balance(state, crosslink_committee.committee): state.latest_crosslinks[crosslink_committee.shard] = Crosslink( - epoch: slot_to_epoch(slot).uint64, + epoch: slot_to_epoch(slot), crosslink_data_root: winning_root(crosslink_committee)) # https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#rewards-and-penalties @@ -745,7 +745,7 @@ func processEpoch(state: var BeaconState) = for v in get_attestation_participants( state, a.data, a.aggregation_bitfield): if v notin result: - result[v] = a.inclusion_slot - a.data.slot + result[v] = Slot(a.inclusion_slot - a.data.slot) block: # Justification and finalization let diff --git a/beacon_chain/sync_protocol.nim b/beacon_chain/sync_protocol.nim index 3a08c7f30..70232b369 100644 --- a/beacon_chain/sync_protocol.nim +++ b/beacon_chain/sync_protocol.nim @@ -1,7 +1,7 @@ import options, tables, chronicles, chronos, ranges/bitranges, - spec/[datatypes, crypto, digest], + spec/[datatypes, crypto, digest], eth/rlp, beacon_node_types, eth2_network, beacon_chain_db, block_pool, time, ssz from beacon_node import onBeaconBlock @@ -43,7 +43,10 @@ proc fromHeaderAndBody(b: var BeaconBlock, h: BeaconBlockHeader, body: BeaconBlo b.signature = h.signature b.body = body -proc importBlocks(node: BeaconNode, roots: openarray[(Eth2Digest, uint64)], headers: openarray[BeaconBlockHeader], bodies: openarray[BeaconBlockBody]) = +proc importBlocks(node: BeaconNode, + roots: openarray[(Eth2Digest, Slot)], + headers: openarray[BeaconBlockHeader], + bodies: openarray[BeaconBlockBody]) = var bodyMap = initTable[Eth2Digest, int]() for i, b in bodies: @@ -74,9 +77,9 @@ p2pProtocol BeaconSync(version = 1, var latestFinalizedRoot: Eth2Digest # TODO - latestFinalizedEpoch: uint64 = node.state.data.finalized_epoch.uint64 + latestFinalizedEpoch = node.state.data.finalized_epoch bestRoot: Eth2Digest # TODO - bestSlot: uint64 = node.state.data.slot.uint64 + bestSlot = node.state.data.slot let m = await handshake(peer, timeout = 500, status(networkId, latestFinalizedRoot, @@ -94,11 +97,11 @@ p2pProtocol BeaconSync(version = 1, # Send roots # TODO: Currently we send all block roots in one "packet". Maybe # they should be split to multiple packets. - type Root = (Eth2Digest, uint64) + type Root = (Eth2Digest, Slot) var roots = newSeqOfCap[Root](128) - for i in m.bestSlot .. bestSlot: - for r in blockPool.blockRootsForSlot(i): - roots.add((r, i)) + for i in int(m.bestSlot) .. int(bestSlot): + for r in blockPool.blockRootsForSlot(i.Slot): + roots.add((r, i.Slot)) await peer.beaconBlockRoots(roots) else: @@ -115,28 +118,28 @@ p2pProtocol BeaconSync(version = 1, peer: Peer, networkId: int, latestFinalizedRoot: Eth2Digest, - latestFinalizedEpoch: uint64, + latestFinalizedEpoch: Epoch, bestRoot: Eth2Digest, - bestSlot: uint64) {.libp2pProtocol("hello", "1.0.0").} + bestSlot: Slot) {.libp2pProtocol("hello", "1.0.0").} proc beaconBlockRoots( peer: Peer, - roots: openarray[(Eth2Digest, uint64)]) {.libp2pProtocol("rpc/beacon_block_roots", "1.0.0").} + roots: openarray[(Eth2Digest, Slot)]) {.libp2pProtocol("rpc/beacon_block_roots", "1.0.0").} requestResponse: proc getBeaconBlockHeaders( peer: Peer, blockRoot: Eth2Digest, - slot: uint64, + slot: Slot, maxHeaders: int, skipSlots: int) {.libp2pProtocol("rpc/beacon_block_headers", "1.0.0").} = # TODO: validate maxHeaders and implement slipSlots - var s = slot + var s = slot.int var headers = newSeqOfCap[BeaconBlockHeader](maxHeaders) let db = peer.networkState.db let blockPool = peer.networkState.node.blockPool while headers.len < maxHeaders: - for r in blockPool.blockRootsForSlot(s): + for r in blockPool.blockRootsForSlot(s.Slot): headers.add(db.getBlock(r).get().toHeader) if headers.len == maxHeaders: break inc s