Skip to content

Commit c260201

Browse files
authored
Cleanup of portal block proofs + comments (#3156)
1 parent f9020ed commit c260201

11 files changed

+205
-159
lines changed

fluffy/eth_data/history_data_seeding.nim

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
# # Nimbus - Portal Network
2-
# # Copyright (c) 2022-2024 Status Research & Development GmbH
3-
# # Licensed and distributed under either of
4-
# # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
5-
# # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
6-
# # at your option. This file may not be copied, modified, or distributed except according to those terms.
1+
# Nimbus - Portal Network
2+
# Copyright (c) 2022-2025 Status Research & Development GmbH
3+
# Licensed and distributed under either of
4+
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
5+
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
6+
# at your option. This file may not be copied, modified, or distributed except according to those terms.
77

88
{.push raises: [].}
99

@@ -12,8 +12,11 @@ import
1212
chronos,
1313
chronicles,
1414
../network/wire/portal_protocol,
15-
../network/history/
16-
[history_content, history_network, validation/historical_hashes_accumulator],
15+
../network/history/[
16+
history_content,
17+
history_network,
18+
validation/block_proof_historical_hashes_accumulator,
19+
],
1720
"."/[era1, history_data_ssz_e2s]
1821

1922
from eth/common/eth_types_rlp import rlpHash

fluffy/network/history/history_validation.nim

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ import
1414
../../network_metadata,
1515
./history_type_conversions,
1616
./validation/[
17-
historical_hashes_accumulator, block_proof_historical_roots,
17+
block_proof_historical_hashes_accumulator, block_proof_historical_roots,
1818
block_proof_historical_summaries,
1919
]
2020

2121
from eth/common/eth_types_rlp import rlpHash
2222

23-
export historical_hashes_accumulator
23+
export block_proof_historical_hashes_accumulator
2424

2525
type HistoryAccumulators* = object
2626
historicalHashes*: FinishedHistoricalHashesAccumulator
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Nimbus
2+
# Copyright (c) 2022-2025 Status Research & Development GmbH
3+
# Licensed and distributed under either of
4+
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
5+
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
6+
# at your option. This file may not be copied, modified, or distributed except according to those terms.
7+
8+
{.push raises: [].}
9+
10+
import
11+
eth/common/[headers_rlp],
12+
ssz_serialization,
13+
ssz_serialization/[proofs, merkleization],
14+
../../../common/common_types,
15+
../history_content,
16+
./historical_hashes_accumulator
17+
18+
from eth/common/eth_types_rlp import rlpHash
19+
20+
export
21+
ssz_serialization, merkleization, proofs, common_types, historical_hashes_accumulator
22+
23+
#
24+
# Implementation of pre-merge block proofs by making use of the frozen HistoricalHashesAccumulator
25+
#
26+
# Types are defined here:
27+
# https://github.com/ethereum/portal-network-specs/blob/31bc7e58e2e8acfba895d5a12a9ae3472894d398/history/history-network.md#block-header
28+
#
29+
# Proof system explained here:
30+
# https://github.com/ethereum/portal-network-specs/blob/31bc7e58e2e8acfba895d5a12a9ae3472894d398/history/history-network.md#blockproofhistoricalhashesaccumulator
31+
#
32+
# The HistoricalHashesAccumulator is frozen at TheMerge, this means that it can
33+
# only be used for the blocks before TheMerge.
34+
#
35+
# Requirements:
36+
#
37+
# - For building the proofs:
38+
# Portal node/bridge that has access to all the EL chain historical data (blocks)
39+
# for that specific period. This can be provided through era1 files.
40+
#
41+
# - For verifying the proofs:
42+
# To verify the proof the HistoricalHashesAccumulator is required.
43+
# As this field is frozen, it can be baked into the client.
44+
# Root of the HistoricalHashesAccumulator can be cross-verified with EIP-7643 data:
45+
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7643.md#pre-pos-root
46+
#
47+
48+
# Total size: 15 * 32 bytes = 480 bytes
49+
type HistoricalHashesAccumulatorProof* = array[15, Digest]
50+
51+
func getEpochIndex*(blockNumber: uint64): uint64 =
52+
blockNumber div EPOCH_SIZE
53+
54+
func getEpochIndex*(header: Header): uint64 =
55+
## Get the index for the historical epochs
56+
getEpochIndex(header.number)
57+
58+
func getHeaderRecordIndex*(blockNumber: uint64, epochIndex: uint64): uint64 =
59+
## Get the relative header index for the epoch accumulator
60+
uint64(blockNumber - epochIndex * EPOCH_SIZE)
61+
62+
func getHeaderRecordIndex*(header: Header, epochIndex: uint64): uint64 =
63+
## Get the relative header index for the epoch accumulator
64+
getHeaderRecordIndex(header.number, epochIndex)
65+
66+
func isPreMerge*(blockNumber: uint64): bool =
67+
blockNumber < mergeBlockNumber
68+
69+
func isPreMerge*(header: Header): bool =
70+
isPreMerge(header.number)
71+
72+
func verifyProof*(
73+
a: FinishedHistoricalHashesAccumulator,
74+
header: Header,
75+
proof: HistoricalHashesAccumulatorProof,
76+
): bool =
77+
let
78+
epochIndex = getEpochIndex(header)
79+
epochRecordHash = Digest(data: a.historicalEpochs[epochIndex])
80+
81+
leave = hash_tree_root(header.rlpHash())
82+
headerRecordIndex = getHeaderRecordIndex(header, epochIndex)
83+
84+
# For lists, leaves starts at epochSize*2 (because of the extra len branch).
85+
# Then another *2 to enter one layer deeper in the `HeaderRecord`.
86+
# list_root
87+
# / \
88+
# list_data_root len(list)
89+
# / \
90+
# /\ /\
91+
# .......
92+
# / ... /\
93+
# hr_root
94+
# / \
95+
# blockhash
96+
gIndex = GeneralizedIndex(EPOCH_SIZE * 2 * 2 + (headerRecordIndex * 2))
97+
98+
verify_merkle_multiproof(@[leave], proof, @[gIndex], epochRecordHash)
99+
100+
func buildProof*(
101+
header: Header, epochRecord: EpochRecord | EpochRecordCached
102+
): Result[HistoricalHashesAccumulatorProof, string] =
103+
doAssert(header.isPreMerge(), "Must be pre merge header")
104+
105+
let
106+
epochIndex = getEpochIndex(header)
107+
headerRecordIndex = getHeaderRecordIndex(header, epochIndex)
108+
109+
gIndex = GeneralizedIndex(EPOCH_SIZE * 2 * 2 + (headerRecordIndex * 2))
110+
111+
var proof: HistoricalHashesAccumulatorProof
112+
?epochRecord.build_proof(gIndex, proof)
113+
114+
ok(proof)
115+
116+
func buildHeaderWithProof*(
117+
header: Header, epochRecord: EpochRecord | EpochRecordCached
118+
): Result[BlockHeaderWithProof, string] =
119+
let proof = ?buildProof(header, epochRecord)
120+
121+
ok(
122+
BlockHeaderWithProof(
123+
header: ByteList[MAX_HEADER_LENGTH].init(rlp.encode(header)),
124+
proof: ByteList[MAX_HEADER_PROOF_LENGTH].init(SSZ.encode(proof)),
125+
)
126+
)

fluffy/network/history/validation/block_proof_historical_roots.nim

+18-58
Original file line numberDiff line numberDiff line change
@@ -4,71 +4,31 @@
44
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
55
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
66
# at your option. This file may not be copied, modified, or distributed except according to those terms.
7-
8-
# This is a PoC of how execution block headers in the Portal history network
9-
# could be proven to be part of the canonical chain by means of a proof that
10-
# exists out a chain of proofs.
11-
#
12-
# To verify this proof you need access to the BeaconState field
13-
# historical_roots and the block hash of the execution block.
14-
#
15-
# The chain traverses from proving that the block hash is the one of the
16-
# ExecutionPayload in the BeaconBlockBody, to proving that this BeaconBlockBody
17-
# is the one that is rooted in the BeaconBlockHeader, to proving that this
18-
# BeaconBlockHeader is rooted in the historical_roots.
19-
#
20-
# TODO: The middle proof is perhaps a bit silly as it doesn't win much space
21-
# compared to just providing the BeaconHeader.
22-
#
23-
# Requirements:
247
#
25-
# For building the proofs:
26-
# - Node that has access to all the beacon chain data (state and blocks) and
27-
# - it will be required to rebuild the HistoricalBatches.
8+
# Implementation of post-merge block proofs by making use of the historical_roots
9+
# accumulator.
10+
# Types are defined here:
11+
# https://github.com/ethereum/portal-network-specs/blob/31bc7e58e2e8acfba895d5a12a9ae3472894d398/history/history-network.md#block-header
2812
#
29-
# For verifying the proofs:
30-
# - As mentioned, the historical_roots field of the state is required. This
31-
# is currently in no way available over any of the consensus layer libp2p
32-
# protocols. Thus a light client cannot really be build using these proofs,
33-
# which makes it rather useless for now.
34-
# - The historical_roots could be put available on the network together with
35-
# a proof against the right state root. An example of this can be seen in
36-
# ./fluffy/network/history/experimental/beacon_chain_historical_roots.nim
13+
# Proof system explained here:
14+
# https://github.com/ethereum/portal-network-specs/blob/31bc7e58e2e8acfba895d5a12a9ae3472894d398/history/history-network.md#blockproofhistoricalroots
3715
#
38-
# Caveat:
16+
# The proof chain traverses from proving that the block hash is the one of the
17+
# ExecutionPayload in the BeaconBlock to proving that this BeaconBlock is rooted
18+
# in the historical_roots.
3919
#
40-
# Roots in historical_roots are only added every `SLOTS_PER_HISTORICAL_ROOT`
41-
# slots. Recent blocks that are not part of a historical_root cannot be proven
42-
# through this mechanism. They need to be directly looked up in the block_roots
43-
# BeaconState field.
44-
#
45-
# Alternative:
46-
#
47-
# This PoC is written with the idea of keeping execution BlockHeaders and
48-
# BlockBodies available in the Portal history network in the same way post-merge
49-
# as it is pre-merge. One could also simply decide to store the BeaconBlocks or
50-
# BeaconBlockHeaders and BeaconBlockBodies directly. And get the execution
51-
# payloads from there. This would require only 1 (or two, depending on what you
52-
# store) of the proofs and might be more convenient if you want to / need to
53-
# store the beacon data also on the network. It would require some rebuilding
54-
# the structure of the Execution BlockHeader.
55-
#
56-
# Alternative ii:
57-
#
58-
# Verifying a specific block could also be done by making use of the
59-
# LightClientUpdates. Picking the closest update, and walking back blocks from
60-
# that block to the specific block. How much data is required to download would
61-
# depend on the location of the block, but it could be quite significant.
62-
# Of course, this again could be thrown in some accumulator, but that would
63-
# then be required to be stored on the state to make it easy verifiable.
64-
# A PoC of this process would be nice and it could be more useful for a system
65-
# like the Nimbus verified proxy.
20+
# The historical_roots accumulator is frozen at the Capella fork, this means that
21+
# it can only be used for the blocks from TheMerge until the Capella fork (= Bellatrix).
6622
#
23+
# Requirements:
6724
#
68-
# The usage of this PoC can be seen in
69-
# ./fluffy/tests/test_beacon_chain_block_proof.nim
25+
# - For building the proofs:
26+
# Portal node/bridge that has access to all the beacon chain data (blocks +
27+
# specific state) for that specific period. This can be provided through era files.
7028
#
71-
# TODO: Probably needs to make usage of forks instead of just bellatrix.
29+
# - For verifying the proofs:
30+
# To verify the proof the historical_roots field of the BeaconState is required.
31+
# As this field is frozen, it can be baked into the client.
7232
#
7333

7434
{.push raises: [].}

fluffy/network/history/validation/block_proof_historical_summaries.nim

+31-11
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,41 @@
44
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
55
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
66
# at your option. This file may not be copied, modified, or distributed except according to those terms.
7-
8-
# This is a PoC of how execution block headers in the Portal history network
9-
# could be proven to be part of the canonical chain by means of a proof that
10-
# exists out a chain of proofs.
117
#
12-
# It is the equivalent of beacon_chain_block_proof.nim but after Capella fork
13-
# making use of historical_summaries instead of the frozen historical_roots.
8+
# Implementation of post-merge block proofs by making use of the historical_summaries
9+
# accumulator.
10+
# Types are defined here:
11+
# https://github.com/ethereum/portal-network-specs/blob/31bc7e58e2e8acfba895d5a12a9ae3472894d398/history/history-network.md#block-header
12+
#
13+
# Proof system explained here:
14+
# https://github.com/ethereum/portal-network-specs/blob/31bc7e58e2e8acfba895d5a12a9ae3472894d398/history/history-network.md#blockproofhistoricalsummaries
15+
#
16+
# The proof chain traverses from proving that the block hash is the one of the
17+
# ExecutionPayload in the BeaconBlock to proving that this BeaconBlock is rooted
18+
# in the historical_summaries.
19+
#
20+
# The historical_summaries accumulator is updated for every period since Capella.
21+
# It can thus be used for block proofs for blocks after the Capella fork.
22+
#
23+
# Caveat:
24+
# Roots in historical_summaries are only added every `SLOTS_PER_HISTORICAL_ROOT`
25+
# slots. Recent blocks that are not part of a HistoricalSummary cannot be proven
26+
# through this mechanism.
27+
#
28+
# Requirements:
1429
#
30+
# - For building the proofs:
31+
# Portal node/bridge that has access to all the beacon chain data (blocks +
32+
# specific state) for that specific period. This can be provided through era files.
1533
#
16-
# The usage of this PoC can be seen in
17-
# ./fluffy/tests/test_beacon_chain_block_proof_capella.nim
34+
# - For verifying the proofs:
35+
# To verify the proof the historical_summaries field of the BeaconState is required.
36+
# As the historical_summaries evolve over time, it is made available over the
37+
# Portal beacon network for retrieval.
1838
#
19-
# TODO: Fit both beacon_chain_block_proof_bellatrix.nim and
20-
# beacon_chain_block_proof_capella.nim better together and add fork selection
21-
# on top of it.
39+
# Caveat:
40+
# The historical_roots accumulator is frozen at the Capella fork, this means that
41+
# it can only be used for the blocks before the Capella fork (= Bellatrix).
2242
#
2343

2444
{.push raises: [].}

0 commit comments

Comments
 (0)