From 33fd8b1fae6b005e9b6a5589ef921017f4671685 Mon Sep 17 00:00:00 2001 From: Kim De Mey Date: Thu, 11 May 2023 19:08:34 +0200 Subject: [PATCH] Add historical_roots with proof + test (#1579) --- .../beacon_chain_historical_roots.nim | 8 ++- .../beacon_chain_historical_summaries.nim | 49 +++++++++++++++++++ fluffy/tests/all_fluffy_tests.nim | 3 +- .../test_beacon_chain_historical_roots.nim | 9 ++-- ...test_beacon_chain_historical_summaries.nim | 49 +++++++++++++++++++ 5 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 fluffy/network/history/experimental/beacon_chain_historical_summaries.nim create mode 100644 fluffy/tests/test_beacon_chain_historical_summaries.nim diff --git a/fluffy/network/history/experimental/beacon_chain_historical_roots.nim b/fluffy/network/history/experimental/beacon_chain_historical_roots.nim index b9aaed60c..902d2f0d6 100644 --- a/fluffy/network/history/experimental/beacon_chain_historical_roots.nim +++ b/fluffy/network/history/experimental/beacon_chain_historical_roots.nim @@ -7,10 +7,16 @@ # # Example of how the beacon state historical_roots field could be provided with -# a Merkle proof that can be verified against the right state root. +# a Merkle proof that can be verified against the right beacon state root. # These historical_roots with their proof could for example be provided over the # network and verified on the receivers end. # +# Note: +# Since Capella the historical_roots field is frozen. Thus providing the +# historical_roots with a Proof against the latest state seems a bit silly. +# One idea could be to embed it into the client just as is done for the +# execution header accumulator. +# {.push raises: [].} diff --git a/fluffy/network/history/experimental/beacon_chain_historical_summaries.nim b/fluffy/network/history/experimental/beacon_chain_historical_summaries.nim new file mode 100644 index 000000000..4460ccaa7 --- /dev/null +++ b/fluffy/network/history/experimental/beacon_chain_historical_summaries.nim @@ -0,0 +1,49 @@ +# Nimbus +# Copyright (c) 2023 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. + +# +# Example of how the beacon state historical_summaries field could be provided +# with a Merkle proof that can be verified against the right beacon state root. +# These historical_summaries with their proof could for example be provided over +# the network and verified on the receivers end. +# + +{.push raises: [].} + +import + stew/results, + beacon_chain/spec/forks, + beacon_chain/spec/datatypes/capella + +export results + +type + HistoricalSummaries* = HashList[HistoricalSummary, Limit HISTORICAL_ROOTS_LIMIT] + HistoricalSummariesProof* = array[5, Digest] + HistoricalSummariesWithProof* = object + historical_summaries: HistoricalSummaries + proof: HistoricalSummariesProof + +func buildProof*( + state: ForkedHashedBeaconState): Result[HistoricalSummariesProof, string] = + let gIndex = GeneralizedIndex(59) # 31 + 28 = 59 + + var proof: HistoricalSummariesProof + withState(state): + ? forkyState.data.build_proof(gIndex, proof) + + ok(proof) + +func verifyProof*( + historical_summaries: HistoricalSummaries, + proof: HistoricalSummariesProof, + stateRoot: Digest): bool = + let + gIndex = GeneralizedIndex(59) + leave = hash_tree_root(historical_summaries) + + verify_merkle_multiproof(@[leave], proof, @[gIndex], stateRoot) diff --git a/fluffy/tests/all_fluffy_tests.nim b/fluffy/tests/all_fluffy_tests.nim index 7a4c72884..1698fd53a 100644 --- a/fluffy/tests/all_fluffy_tests.nim +++ b/fluffy/tests/all_fluffy_tests.nim @@ -17,4 +17,5 @@ import ./test_content_db, ./test_discovery_rpc, ./test_beacon_chain_block_proof, - ./test_beacon_chain_historical_roots + ./test_beacon_chain_historical_roots, + ./test_beacon_chain_historical_summaries diff --git a/fluffy/tests/test_beacon_chain_historical_roots.nim b/fluffy/tests/test_beacon_chain_historical_roots.nim index 71e72ed90..2be08f76d 100644 --- a/fluffy/tests/test_beacon_chain_historical_roots.nim +++ b/fluffy/tests/test_beacon_chain_historical_roots.nim @@ -13,19 +13,16 @@ import unittest2, beacon_chain/spec/forks, beacon_chain/spec/datatypes/bellatrix, + # Test helpers beacon_chain/../tests/testblockutil, - # Mock helpers beacon_chain/../tests/mocking/mock_genesis, + beacon_chain/../tests/consensus_spec/fixtures_utils, ../network/history/experimental/beacon_chain_historical_roots suite "Beacon Chain Historical Roots": let - cfg = block: - var res = defaultRuntimeConfig - res.ALTAIR_FORK_EPOCH = GENESIS_EPOCH - res.BELLATRIX_FORK_EPOCH = GENESIS_EPOCH - res + cfg = genesisTestRuntimeConfig(ConsensusFork.Bellatrix) state = newClone(initGenesisState(cfg = cfg)) var cache = StateCache() diff --git a/fluffy/tests/test_beacon_chain_historical_summaries.nim b/fluffy/tests/test_beacon_chain_historical_summaries.nim new file mode 100644 index 000000000..13436a3a6 --- /dev/null +++ b/fluffy/tests/test_beacon_chain_historical_summaries.nim @@ -0,0 +1,49 @@ +# Nimbus +# Copyright (c) 2023 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. + +{.used.} + +{.push raises: [].} + +import + unittest2, + beacon_chain/spec/forks, + beacon_chain/spec/datatypes/capella, + # Test helpers + beacon_chain/../tests/testblockutil, + beacon_chain/../tests/mocking/mock_genesis, + beacon_chain/../tests/consensus_spec/fixtures_utils, + + ../network/history/experimental/beacon_chain_historical_summaries + +suite "Beacon Chain Historical Summaries": + let + cfg = genesisTestRuntimeConfig(ConsensusFork.Capella) + state = newClone(initGenesisState(cfg = cfg)) + var cache = StateCache() + + var blocks: seq[capella.SignedBeaconBlock] + # Note: + # Adding 8192 blocks. First block is genesis block and not one of these. + # Then one extra block is needed to get the historical summaries, block + # roots and state roots processed. + # index i = 0 is second block. + # index i = 8190 is 8192th block and last one that is part of the first + # historical root + for i in 0..= ConsensusFork.Capella: + let historical_summaries = forkyState.data.historical_summaries + let res = buildProof(state[]) + check res.isOk() + let proof = res.get() + + withState(state[]): + check verifyProof(historical_summaries, proof, forkyState.root)