hash -> root

ethereum/eth2.0-specs#285
This commit is contained in:
Jacek Sieka 2018-12-11 15:53:18 -06:00
parent 7ea51d5b0b
commit 5b35b6c2dc
No known key found for this signature in database
GPG Key ID: 6299FEB3EB6FA465
8 changed files with 85 additions and 85 deletions

View File

@ -82,7 +82,7 @@ func on_startup*(initial_validator_entries: openArray[InitialValidator],
# Recent state
latest_state_recalculation_slot: INITIAL_SLOT_NUMBER,
latest_block_hashes: repeat(ZERO_HASH, EPOCH_LENGTH * 2),
latest_block_roots: repeat(ZERO_HASH, EPOCH_LENGTH * 2),
# PoW receipt root
processed_pow_receipt_root: processed_pow_receipt_root,
@ -95,19 +95,19 @@ func on_startup*(initial_validator_entries: openArray[InitialValidator],
),
)
func get_block_hash*(state: BeaconState,
func get_block_root*(state: BeaconState,
slot: uint64): Eth2Digest =
let earliest_slot_in_array =
state.slot - len(state.latest_block_hashes).uint64
state.slot - len(state.latest_block_roots).uint64
assert earliest_slot_in_array <= slot
assert slot < state.slot
state.latest_block_hashes[(slot - earliest_slot_in_array).int]
state.latest_block_roots[(slot - earliest_slot_in_array).int]
func append_to_recent_block_hashes*(old_block_hashes: seq[Eth2Digest],
func append_to_recent_block_roots*(old_block_roots: seq[Eth2Digest],
parent_slot, current_slot: uint64,
parent_hash: Eth2Digest): seq[Eth2Digest] =
let d = current_slot - parent_slot
result = old_block_hashes
result = old_block_roots
result.add repeat(parent_hash, d)
func get_attestation_participants*(state: BeaconState,
@ -180,14 +180,14 @@ func checkAttestation*(state: BeaconState, attestation: Attestation): bool =
if attestation.data.justified_slot != expected_justified_slot:
return
let expected_justified_block_hash =
get_block_hash(state, attestation.data.justified_slot)
if attestation.data.justified_block_hash != expected_justified_block_hash:
let expected_justified_block_root =
get_block_root(state, attestation.data.justified_slot)
if attestation.data.justified_block_root != expected_justified_block_root:
return
if state.latest_crosslinks[attestation.data.shard].shard_block_hash notin [
attestation.data.latest_crosslink_hash,
attestation.data.shard_block_hash]:
if state.latest_crosslinks[attestation.data.shard].shard_block_root notin [
attestation.data.latest_crosslink_root,
attestation.data.shard_block_root]:
return
let
@ -197,7 +197,7 @@ func checkAttestation*(state: BeaconState, attestation: Attestation): bool =
participants, state.validator_registry[it].pubkey))
# Verify that aggregate_signature verifies using the group pubkey.
let msg = hashSSZ(attestation.data)
let msg = hash_tree_root(attestation.data)
if not BLSVerify(
group_public_key, @msg & @[0'u8], attestation.aggregate_signature,
@ -206,7 +206,7 @@ func checkAttestation*(state: BeaconState, attestation: Attestation): bool =
return
# To be removed in Phase1:
if attestation.data.shard_block_hash != ZERO_HASH:
if attestation.data.shard_block_root != ZERO_HASH:
return
true

View File

@ -154,22 +154,22 @@ type
AttestationData* = object
slot*: uint64
shard*: uint64
beacon_block_hash*: Eth2Digest ##\
beacon_block_root*: Eth2Digest ##\
## Hash of the block we're signing
epoch_boundary_hash*: Eth2Digest ##\
epoch_boundary_root*: Eth2Digest ##\
## Hash of the ancestor at the cycle boundary
shard_block_hash*: Eth2Digest ##\
shard_block_root*: Eth2Digest ##\
## Shard block hash being attested to
latest_crosslink_hash*: Eth2Digest ##\
latest_crosslink_root*: Eth2Digest ##\
## Last crosslink hash
justified_slot*: uint64 ##\
## Slot of last justified beacon block
justified_block_hash*: Eth2Digest ##\
justified_block_root*: Eth2Digest ##\
## Hash of last justified beacon block
Deposit* = object
@ -237,7 +237,7 @@ type
slot*: uint64
shard*: uint64 ##\
## Shard number (or `BEACON_CHAIN_SHARD_NUMBER` for beacon chain)
block_hash*: Eth2Digest
block_root*: Eth2Digest
BeaconState* = object
slot*: uint64
@ -269,7 +269,7 @@ type
latest_crosslinks*: array[SHARD_COUNT, CrosslinkRecord]
latest_state_recalculation_slot*: uint64
latest_block_hashes*: seq[Eth2Digest] ##\
latest_block_roots*: seq[Eth2Digest] ##\
## Needed to process attestations, older to newer
latest_penalized_exit_balances*: seq[uint64] ##\
## Balances penalized in the current withdrawal period
@ -290,7 +290,7 @@ type
CrosslinkRecord* = object
slot*: uint64 # Slot number
shard_block_hash*: Eth2Digest # Shard chain block hash
shard_block_root*: Eth2Digest # Shard chain block hash
ShardCommittee* = object
shard*: uint64 # Shard number

View File

@ -68,15 +68,15 @@ func split*[T](lst: openArray[T], N: Positive): seq[seq[T]] =
for i in 0 ..< N:
result[i] = lst[lst.len * i div N ..< lst.len * (i+1) div N] # TODO: avoid alloc via toOpenArray
func get_new_recent_block_hashes*(old_block_hashes: seq[Eth2Digest],
func get_new_recent_block_roots*(old_block_roots: seq[Eth2Digest],
parent_slot, current_slot: int64,
parent_hash: Eth2Digest
): seq[Eth2Digest] =
# Should throw for `current_slot - CYCLE_LENGTH * 2 - 1` according to spec comment
let d = current_slot - parent_slot
result = old_block_hashes[d .. ^1]
for _ in 0 ..< min(d, old_block_hashes.len):
result = old_block_roots[d .. ^1]
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!

View File

@ -36,7 +36,7 @@ func get_new_validators*(current_validators: seq[ValidatorRecord],
#
# Check that validator really did register
# TODO fix tests and enable (nightmare)
# let msg = hashSSZ((pubkey, withdrawal_credentials, randao_commitment))
# let msg = hash_tree_root((pubkey, withdrawal_credentials, randao_commitment))
# assert BLSVerify(
# pubkey, msg, proof_of_possession,
# get_domain(fork_data, current_slot, DOMAIN_DEPOSIT))
@ -121,10 +121,10 @@ func get_new_validator_registry_delta_chain_tip(
## Compute the next hash in the validator registry delta hash chain.
withEth2Hash:
h.update hashSSZ(current_validator_registry_delta_chain_tip)
h.update hashSSZ(flag.uint8)
h.update hashSSZ(index)
h.update hashSSZ(pubkey)
h.update hash_tree_root(current_validator_registry_delta_chain_tip)
h.update hash_tree_root(flag.uint8)
h.update hash_tree_root(index)
h.update hash_tree_root(pubkey)
func get_effective_balance*(validator: ValidatorRecord): uint64 =
min(validator.balance, MAX_DEPOSIT)

View File

@ -130,7 +130,7 @@ func serialize*[T](value: T): seq[byte] =
# ################### Hashing ###################################
# Sample hashSSZ implementation based on:
# Sample hash_tree_root implementation based on:
# https://github.com/ethereum/eth2.0-specs/blob/98312f40b5742de6aa73f24e6225ee68277c4614/specs/simple-serialize.md
# and
# https://github.com/ethereum/beacon_chain/pull/134
@ -163,46 +163,46 @@ func merkleHash[T](lst: seq[T]): array[32, byte]
# ################### Hashing interface ###################################
func hashSSZ*(x: SomeInteger): array[sizeof(x), byte] =
func hash_tree_root*(x: SomeInteger): array[sizeof(x), byte] =
## Convert directly to bytes the size of the int. (e.g. ``uint16 = 2 bytes``)
## All integers are serialized as **big endian**.
toBytesSSZ(x)
func hashSSZ*(x: Uint24): array[3, byte] =
func hash_tree_root*(x: Uint24): array[3, byte] =
## Convert directly to bytes the size of the int. (e.g. ``uint16 = 2 bytes``)
## All integers are serialized as **big endian**.
toBytesSSZ(x)
func hashSSZ*(x: EthAddress): array[sizeof(x), byte] =
func hash_tree_root*(x: EthAddress): array[sizeof(x), byte] =
## Addresses copied as-is
toBytesSSZ(x)
func hashSSZ*(x: Eth2Digest): array[32, byte] =
func hash_tree_root*(x: Eth2Digest): array[32, byte] =
## Hash32 copied as-is
toBytesSSZ(x)
func hashSSZ*(x: openArray[byte]): array[32, byte] =
func hash_tree_root*(x: openArray[byte]): array[32, byte] =
## Blobs are hashed
hash(x)
func hashSSZ*(x: ValidatorRecord): array[32, byte] =
func hash_tree_root*(x: ValidatorRecord): array[32, byte] =
## Containers have their fields recursively hashed, concatenated and hashed
# TODO hash_ssz.py code contains special cases for some types, why?
withHash:
# tmp.add(x.pubkey) # TODO uncertain future of public key format
h.update hashSSZ(x.withdrawal_credentials)
h.update hashSSZ(x.randao_skips)
h.update hashSSZ(x.balance)
# h.update hashSSZ(x.status) # TODO it's an enum, deal with it
h.update hashSSZ(x.latest_status_change_slot)
h.update hashSSZ(x.exit_count)
h.update hash_tree_root(x.withdrawal_credentials)
h.update hash_tree_root(x.randao_skips)
h.update hash_tree_root(x.balance)
# h.update hash_tree_root(x.status) # TODO it's an enum, deal with it
h.update hash_tree_root(x.latest_status_change_slot)
h.update hash_tree_root(x.exit_count)
func hashSSZ*(x: ShardCommittee): array[32, byte] =
func hash_tree_root*(x: ShardCommittee): array[32, byte] =
withHash:
h.update hashSSZ(x.shard)
h.update hash_tree_root(x.shard)
h.update merkleHash(x.committee)
func hashSSZ*[T: not enum](x: T): array[32, byte] =
func hash_tree_root*[T: not enum](x: T): array[32, byte] =
when T is seq:
## Sequences are tree-hashed
merkleHash(x)
@ -212,15 +212,15 @@ func hashSSZ*[T: not enum](x: T): array[32, byte] =
# TODO or.. https://github.com/ethereum/eth2.0-specs/issues/275
var fields: seq[tuple[name: string, value: seq[byte]]]
for name, field in x.fieldPairs:
fields.add (name, @(hashSSZ(field)))
fields.add (name, @(hash_tree_root(field)))
withHash:
for name, value in fields.sortedByIt(it.name):
h.update hashSSZ(value.value)
h.update hash_tree_root(value.value)
# #################################
# HashSSZ not part of official spec
func hashSSZ*(x: enum): array[32, byte] =
# hash_tree_root not part of official spec
func hash_tree_root*(x: enum): array[32, byte] =
## TODO - Warning ⚠️: not part of the spec
## as of https://github.com/ethereum/beacon_chain/pull/133/files
## This is a "stub" needed for BeaconBlock hashing
@ -228,13 +228,13 @@ func hashSSZ*(x: enum): array[32, byte] =
withHash:
h.update [uint8 x]
func hashSSZ*(x: ValidatorPubKey): array[32, byte] =
func hash_tree_root*(x: ValidatorPubKey): array[32, byte] =
## TODO - Warning ⚠️: not part of the spec
## as of https://github.com/ethereum/beacon_chain/pull/133/files
## This is a "stub" needed for BeaconBlock hashing
x.getRaw().hash()
func hashSSZ*(x: ValidatorSig): array[32, byte] =
func hash_tree_root*(x: ValidatorSig): array[32, byte] =
## TODO - Warning ⚠️: not part of the spec
## as of https://github.com/ethereum/beacon_chain/pull/133/files
## This is a "stub" needed for BeaconBlock hashing
@ -258,9 +258,9 @@ func merkleHash[T](lst: seq[T]): array[32, byte] =
if len(lst) == 0:
chunkz.add @emptyChunk
elif sizeof(hashSSZ(lst[0])) < CHUNK_SIZE:
elif sizeof(hash_tree_root(lst[0])) < CHUNK_SIZE:
# See how many items fit in a chunk
let itemsPerChunk = CHUNK_SIZE div sizeof(hashSSZ(lst[0]))
let itemsPerChunk = CHUNK_SIZE div sizeof(hash_tree_root(lst[0]))
chunkz.setLen((len(lst) + itemsPerChunk - 1) div itemsPerChunk)
@ -270,12 +270,12 @@ func merkleHash[T](lst: seq[T]): array[32, byte] =
if i == chunkz.len - 1:
let idx = i * itemsPerChunk + j
if idx >= lst.len: break # Last chunk may be partial!
chunkz[i].add hashSSZ(lst[i * itemsPerChunk + j])
chunkz[i].add hash_tree_root(lst[i * itemsPerChunk + j])
else:
# Leave large items alone
chunkz.setLen(len(lst))
for i in 0..<len(lst):
chunkz[i].add hashSSZ(lst[i])
chunkz[i].add hash_tree_root(lst[i])
while chunkz.len() > 1:
if chunkz.len() mod 2 == 1:

View File

@ -72,10 +72,10 @@ func verifyProposerSignature(state: BeaconState, blck: BeaconBlock): bool =
blck_without_sig.signature = ValidatorSig()
let
proposal_hash = hashSSZ(ProposalSignedData(
proposal_hash = hash_tree_root(ProposalSignedData(
slot: state.slot,
shard: BEACON_CHAIN_SHARD,
block_hash: Eth2Digest(data: hashSSZ(blck_without_sig))
block_root: Eth2Digest(data: hash_tree_root(blck_without_sig))
))
let validator_idx = get_beacon_proposer_index(state, state.slot)
@ -139,13 +139,13 @@ func processSlot(state: var BeaconState, latest_block: BeaconBlock): bool =
# TODO state not rolled back in case of failure
let
latest_hash = Eth2Digest(data: hashSSZ(latest_block))
latest_hash = Eth2Digest(data: hash_tree_root(latest_block))
state.slot += 1
state.latest_block_hashes.add latest_hash
state.latest_block_roots.add latest_hash
if state.latest_block_hashes.len < 2 or
state.latest_block_hashes[^2] != state.latest_block_hashes[^1]:
if state.latest_block_roots.len < 2 or
state.latest_block_roots[^2] != state.latest_block_roots[^1]:
# TODO a bit late for the following checks?
# https://github.com/ethereum/eth2.0-specs/issues/284
if latest_block.slot != state.slot:
@ -181,7 +181,7 @@ func boundary_attestations(
): seq[PendingAttestationRecord] =
# TODO spec - add as helper?
filterIt(attestations,
it.data.epoch_boundary_hash == boundary_hash and
it.data.epoch_boundary_root == boundary_hash and
it.data.justified_slot == state.justified_slot)
func sum_effective_balances(
@ -193,7 +193,7 @@ func sum_effective_balances(
func lowerThan(candidate, current: Eth2Digest): bool =
# return true iff candidate is "lower" than current, per spec rule:
# "ties broken by favoring lower `shard_block_hash` values"
# "ties broken by favoring lower `shard_block_root` values"
# TODO spec - clarify hash ordering..
for i, v in current.data:
if v > candidate.data[i]: return true
@ -220,7 +220,7 @@ func processEpoch(state: var BeaconState, blck: BeaconBlock): bool =
reward_quotient = BASE_REWARD_QUOTIENT * int_sqrt(total_balance_in_eth)
# TODO not in spec, convenient
epoch_boundary_hash = get_block_hash(state, s)
epoch_boundary_root = get_block_root(state, s)
proc base_reward(v: ValidatorRecord): uint64 =
get_effective_balance(v) div reward_quotient.uint64
@ -232,7 +232,7 @@ func processEpoch(state: var BeaconState, blck: BeaconBlock): bool =
s <= it.data.slot and it.data.slot < s + EPOCH_LENGTH)
this_epoch_boundary_attestations =
boundary_attestations(state, epoch_boundary_hash,
boundary_attestations(state, epoch_boundary_root,
this_epoch_attestations)
this_epoch_boundary_attesters =
@ -246,7 +246,7 @@ func processEpoch(state: var BeaconState, blck: BeaconBlock): bool =
s <= it.data.slot + EPOCH_LENGTH and it.data.slot < s)
previous_epoch_boundary_attestations =
boundary_attestations(state, epoch_boundary_hash,
boundary_attestations(state, epoch_boundary_root,
previous_epoch_attestations)
previous_epoch_boundary_attesters =
@ -260,23 +260,23 @@ func processEpoch(state: var BeaconState, blck: BeaconBlock): bool =
# these closures outside this scope, but still..
let statePtr = state.addr
func attesting_validators(
obj: ShardCommittee, shard_block_hash: Eth2Digest): seq[Uint24] =
obj: ShardCommittee, shard_block_root: Eth2Digest): seq[Uint24] =
flatten(
mapIt(
filterIt(concat(this_epoch_attestations, previous_epoch_attestations),
it.data.shard == obj.shard and
it.data.shard_block_hash == shard_block_hash),
it.data.shard_block_root == shard_block_root),
get_attestation_participants(statePtr[], it.data, it.participation_bitfield)))
func winning_hash(obj: ShardCommittee): Eth2Digest =
# * Let `winning_hash(obj)` be the winning `shard_block_hash` value.
# ... such that `sum([get_effective_balance(v) for v in attesting_validators(obj, shard_block_hash)])`
# is maximized (ties broken by favoring lower `shard_block_hash` values).
# * Let `winning_hash(obj)` be the winning `shard_block_root` value.
# ... such that `sum([get_effective_balance(v) for v in attesting_validators(obj, shard_block_root)])`
# is maximized (ties broken by favoring lower `shard_block_root` values).
let candidates =
mapIt(
filterIt(concat(this_epoch_attestations, previous_epoch_attestations),
it.data.shard == obj.shard),
it.data.shard_block_hash)
it.data.shard_block_root)
var max_hash = candidates[0]
var max_val =
@ -351,7 +351,7 @@ func processEpoch(state: var BeaconState, blck: BeaconBlock): bool =
2'u64 * total_balance_sac(obj):
state.latest_crosslinks[obj.shard] = CrosslinkRecord(
slot: state.latest_state_recalculation_slot + EPOCH_LENGTH,
shard_block_hash: winning_hash(obj))
shard_block_root: winning_hash(obj))
block: # Justification and finalization rewards and penalties
let
@ -468,7 +468,7 @@ func processEpoch(state: var BeaconState, blck: BeaconBlock): bool =
block: # Final updates
# TODO Remove all attestation records older than slot `s`.
state.latest_block_hashes = state.latest_block_hashes[EPOCH_LENGTH..^1]
state.latest_block_roots = state.latest_block_roots[EPOCH_LENGTH..^1]
true

View File

@ -9,7 +9,7 @@ func attestation_signed_data(
slot: int64,
shard_id: int16,
parent_hashes: seq[array[32, byte]],
shard_block_hash: array[32, byte],
shard_block_root: array[32, byte],
justified_slot: int64
): MDigest[256]=
@ -27,7 +27,7 @@ func attestation_signed_data(
bigEndian16(be_shard_id.addr, shard_id.unsafeAddr)
ctx.update be_shard_id
ctx.update shard_block_hash
ctx.update shard_block_root
var be_justified_slot: array[8, byte]
bigEndian64(be_justified_slot[0].addr, justified_slot.unsafeAddr)
@ -55,7 +55,7 @@ proc main(nb_samples: Natural) =
slot = rand(4096 .. 4096 + 256) # 256 slots = 1.1 hour
shard_id = int16 rand(high(int16))
parent_hashes = newSeqWith(num_parent_hashes, randBytes32())
shard_block_hash = randBytes32()
shard_block_root = randBytes32()
echo '\n'
echo "######################"
@ -70,7 +70,7 @@ proc main(nb_samples: Natural) =
echo &"Slot: {slot:>64}"
echo &"Shard_id: {shard_id:>64}"
echo &"Parent_hash[0]: {parent_hashes[0].toHex:>64}"
echo &"Shard_block_hash: {shard_block_hash.toHex:>64}"
echo &"shard_block_root: {shard_block_root.toHex:>64}"
echo &"justified_slot: {justified_slot:>64}"
echo '\n'
@ -102,7 +102,7 @@ proc main(nb_samples: Natural) =
slot,
shard_id,
parent_hashes,
shard_block_hash,
shard_block_root,
justified_slot
)
stop = cpuTime()

View File

@ -64,17 +64,17 @@ suite "Tree hashing":
test "Hash ValidatorRecord":
let vr = ValidatorRecord()
check: hashSSZ(vr).len > 0
check: hash_tree_root(vr).len > 0
test "Hash ShardCommittee":
let sc = ShardCommittee()
check: hashSSZ(sc).len > 0
check: hash_tree_root(sc).len > 0
test "Hash BeaconBlock":
## TODO: Test genesis hash when spec is updated
let bb = BeaconBlock()
check: hashSSZ(bb).len > 0
check: hash_tree_root(bb).len > 0
test "Hash integer":
check: hashSSZ(0x01'u32) == [0'u8, 0, 0, 1] # big endian!
check: hashSSZ(Uint24(0x01)) == [0'u8, 0, 1] # big endian!
check: hash_tree_root(0x01'u32) == [0'u8, 0, 0, 1] # big endian!
check: hash_tree_root(Uint24(0x01)) == [0'u8, 0, 1] # big endian!