refactor some Merkle proof generation code outside tests; remove unused variables/functions

This commit is contained in:
Dustin Brody 2020-04-15 09:59:47 +02:00 committed by tersec
parent 8eafa6e094
commit f49dbf68e6
11 changed files with 46 additions and 67 deletions

View File

@ -614,7 +614,6 @@ proc broadcastAggregatedAttestations(
# the corresponding one -- whatver they are, they match.
let
bs = BlockSlot(blck: head, slot: slot)
committees_per_slot = get_committee_count_at_slot(state, slot)
var cache = get_empty_per_epoch_cache()
for committee_index in 0'u64..<committees_per_slot:

View File

@ -1,5 +1,5 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Copyright (c) 2018-2020 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -20,14 +20,7 @@ type
UpdateFlag* = enum
skipMerkleValidation ##\
## When processing deposits, skip verifying the Merkle proof trees of each
## deposit. This is a holdover from both interop issues with the malformed
## proofs and, more currently, nim-beacon-chain's creation of proofs which
## are inconsistent with the current specification. Furthermore several of
## the mocking interfaces deliberately do not create Merkle proofs. Whilst
## this seems less than entirely justifiable, for now enable keeping those
## in place while minimizing the tech debt they create. One, in principle,
## should be able to remove this flag entirely. It is not intrinsically an
## expensive operation to perform.
## deposit.
skipBlsValidation ##\
## Skip verification of BLS signatures in block processing.
## Predominantly intended for use in testing, e.g. to allow extra coverage.

View File

@ -11,9 +11,9 @@
# ---------------------------------------------------------------
import
strutils, macros, bitops,
sequtils, strutils, macros, bitops,
# Specs
../../beacon_chain/spec/[beaconstate, datatypes, digest],
../../beacon_chain/spec/[beaconstate, datatypes, digest, helpers],
../../beacon_chain/ssz
func round_step_down*(x: Natural, step: static Natural): int {.inline.} =
@ -85,6 +85,24 @@ proc getMerkleProof*[Depth: static int](
else:
result[depth] = ZeroHashes[depth]
proc attachMerkleProofs*(deposits: var seq[Deposit]) =
let deposit_data_roots = mapIt(deposits, it.data.hash_tree_root)
var
deposit_data_sums: seq[Eth2Digest]
for prefix_root in hash_tree_roots_prefix(
deposit_data_roots, 1'i64 shl DEPOSIT_CONTRACT_TREE_DEPTH):
deposit_data_sums.add prefix_root
for val_idx in 0 ..< deposits.len:
let merkle_tree = merkleTreeFromLeaves(deposit_data_roots[0..val_idx])
deposits[val_idx].proof[0..31] = merkle_tree.getMerkleProof(val_idx)
deposits[val_idx].proof[32].data[0..7] = int_to_bytes8((val_idx + 1).uint64)
doAssert is_valid_merkle_branch(
deposit_data_roots[val_idx], deposits[val_idx].proof,
DEPOSIT_CONTRACT_TREE_DEPTH + 1, val_idx.uint64,
deposit_data_sums[val_idx])
proc testMerkleMinimal*(): bool =
proc toDigest[N: static int](x: array[N, byte]): Eth2Digest =
result.data[0 .. N-1] = x
@ -126,9 +144,6 @@ proc testMerkleMinimal*(): bool =
macro roundTrips(): untyped =
result = newStmtList()
# Unsure why sszList ident is undeclared in "quote do"
let list = bindSym"sszList"
# compile-time unrolled test
for nleaves in [3, 4, 5, 7, 8, 1 shl 10, 1 shl 32]:
let depth = fastLog2(nleaves-1) + 1
@ -144,8 +159,6 @@ proc testMerkleMinimal*(): bool =
block: # proof for a
let index = 0
let proof = getMerkleProof(tree, index)
#echo "Proof: ", proof
doAssert is_valid_merkle_branch(
a, get_merkle_proof(tree, index = index),
@ -157,7 +170,6 @@ proc testMerkleMinimal*(): bool =
block: # proof for b
let index = 1
let proof = getMerkleProof(tree, index)
doAssert is_valid_merkle_branch(
b, get_merkle_proof(tree, index = index),
@ -169,7 +181,6 @@ proc testMerkleMinimal*(): bool =
block: # proof for c
let index = 2
let proof = getMerkleProof(tree, index)
doAssert is_valid_merkle_branch(
c, get_merkle_proof(tree, index = index),

View File

@ -126,16 +126,6 @@ func compute_fork_data_root(current_version: array[4, byte],
genesis_validators_root: genesis_validators_root
))
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_fork_digest
func compute_fork_digest(current_version: array[4, byte],
genesis_validators_root: Eth2Digest): array[4, byte] =
# Return the 4-byte fork digest for the ``current_version`` and
# ``genesis_validators_root``.
# This is a digest primarily used for domain separation on the p2p layer.
# 4-bytes suffices for practical separation of forks/chains.
result[0..3] =
compute_fork_data_root(current_version, genesis_validators_root).data[0..3]
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_domain
func compute_domain*(
domain_type: DomainType,

View File

@ -1,6 +1,6 @@
import
chronos,
spec/[datatypes]
spec/datatypes
from times import Time, getTime, fromUnix, `<`, `-`

View File

@ -2,7 +2,7 @@ import
os, strutils,
chronicles, chronos, blscurve, nimcrypto, json_serialization, serialization,
web3, stint, eth/keys,
spec/[datatypes, digest, crypto], conf, ssz, interop
spec/[datatypes, digest, crypto], conf, ssz, interop, merkle_minimal
contract(DepositContract):
proc deposit(pubkey: Bytes48, withdrawalCredentials: Bytes32, signature: Bytes96, deposit_data_root: FixedBytes[32])
@ -49,11 +49,17 @@ proc generateDeposits*(totalValidators: int,
let dp = makeDeposit(pubKey, privKey)
writeTextFile(privKeyFn, privKey.toHex())
writeFile(depositFn, dp)
result.add(dp)
# Does quadratic additional work, but fast enough, and otherwise more
# cleanly allows free intermixing of pre-existing and newly generated
# deposit and private key files. TODO: only generate new Merkle proof
# for the most recent deposit if this becomes bottleneck.
attachMerkleProofs(result)
writeTextFile(privKeyFn, privKey.toHex())
writeFile(depositFn, result[result.len - 1])
proc sendDeposits*(
deposits: seq[Deposit],
depositWeb3Url, depositContractAddress, privateKey: string) {.async.} =

View File

@ -14,11 +14,9 @@ import
# Specs
../../beacon_chain/spec/[datatypes, crypto, helpers, digest],
# Internals
../../beacon_chain/[ssz, extras],
../../beacon_chain/[ssz, extras, merkle_minimal],
# Mocking procs
./mock_validator_keys,
# Other test utilities, for attachMerkleProofs()
../testblockutil
./mock_validator_keys
func signMockDepositData(
deposit_data: var DepositData,

View File

@ -80,10 +80,12 @@ macro parseNumConsts(file: static string): untyped =
result = quote do: `constsToCheck`
const
datatypesConsts = @(parseNumConsts(SpecDir/"datatypes.nim"))
mainnetConsts = @(parseNumConsts(SpecDir/"presets"/"mainnet.nim"))
minimalConsts = @(parseNumConsts(SpecDir/"presets"/"minimal.nim"))
const datatypesConsts = @(parseNumConsts(SpecDir/"datatypes.nim"))
when const_preset == "minimal":
const minimalConsts = @(parseNumConsts(SpecDir/"presets"/"minimal.nim"))
else:
const mainnetConsts = @(parseNumConsts(SpecDir/"presets"/"mainnet.nim"))
const IgnoreKeys = [
# Ignore all non-numeric types

View File

@ -198,7 +198,6 @@ when const_preset == "minimal": # Too much stack space used on mainnet
b2Add = pool.add(b2Root, b2)
bs1 = BlockSlot(blck: b1Add, slot: b1.message.slot)
bs1_3 = b1Add.atSlot(3.Slot)
bs2 = BlockSlot(blck: b2Add, slot: b2.message.slot)
bs2_3 = b2Add.atSlot(3.Slot)
var tmpState = pool.headState

View File

@ -8,7 +8,7 @@
{.used.}
import
unittest, ./testutil, ./mocking/merkle_minimal
unittest, ./testutil, ../beacon_chain/merkle_minimal
suiteReport "Mocking utilities":
timedTest "merkle_minimal":

View File

@ -1,16 +1,15 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Copyright (c) 2018-2020 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
options, sequtils, stew/endians2,
options, stew/endians2,
chronicles, eth/trie/[db],
./mocking/merkle_minimal,
../beacon_chain/[beacon_chain_db, block_pool, extras, ssz, state_transition,
validator_pool],
../beacon_chain/[beacon_chain_db, block_pool, extras, merkle_minimal, ssz,
state_transition, validator_pool],
../beacon_chain/spec/[beaconstate, crypto, datatypes, digest,
helpers, validator, state_transition_block]
@ -58,24 +57,6 @@ func makeDeposit(i: int, flags: UpdateFlags): Deposit =
let signing_root = compute_signing_root(result.getDepositMessage, domain)
result.data.signature = bls_sign(privkey, signing_root.data)
proc attachMerkleProofs*(deposits: var seq[Deposit]) =
let deposit_data_roots = mapIt(deposits, it.data.hash_tree_root)
var
deposit_data_sums: seq[Eth2Digest]
for prefix_root in hash_tree_roots_prefix(
deposit_data_roots, 1'i64 shl DEPOSIT_CONTRACT_TREE_DEPTH):
deposit_data_sums.add prefix_root
for val_idx in 0 ..< deposits.len:
let merkle_tree = merkleTreeFromLeaves(deposit_data_roots[0..val_idx])
deposits[val_idx].proof[0..31] = merkle_tree.getMerkleProof(val_idx)
deposits[val_idx].proof[32].data[0..7] = int_to_bytes8((val_idx + 1).uint64)
doAssert is_valid_merkle_branch(
deposit_data_roots[val_idx], deposits[val_idx].proof,
DEPOSIT_CONTRACT_TREE_DEPTH + 1, val_idx.uint64,
deposit_data_sums[val_idx])
proc makeInitialDeposits*(
n = SLOTS_PER_EPOCH, flags: UpdateFlags = {}): seq[Deposit] =
for i in 0..<n.int: