Skip to content

Commit d63cb74

Browse files
authored
Portal: Implementation of new history network (#3427)
* Portal: Implementation of finalized history network * Add content id derivation + content key tests + nph format * Enable finalized history network to portal client * Portal finalized history: Add native API and JSON-RPC API * Add getHeader callback for finalized history network * Rename finalized history network to history network * Adjust content id derivation to differentiate body and receipts * Change content id prefixes to 0x00 and 0x01 as per spec change * Use StoredReceipt instead of Receipt (devp2p/eth69 adjusted type) This is the type defined/referred to in the specifications * Add tests for history content, network and endpoints Also bump portal-spec-tests repo for new test vectors
1 parent 9a7f81a commit d63cb74

18 files changed

+1201
-6
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Nimbus
2+
# Copyright (c) 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 results, stint, ssz_serialization, ../../../common/common_types
11+
12+
export ssz_serialization, common_types, results
13+
14+
type
15+
ContentType* = enum
16+
blockBody = 0x00
17+
receipts = 0x01
18+
19+
BlockNumberKey* = object
20+
blockNumber*: uint64
21+
22+
ContentKey* = object
23+
case contentType*: ContentType
24+
of blockBody:
25+
blockBodyKey*: BlockNumberKey
26+
of receipts:
27+
receiptsKey*: BlockNumberKey
28+
29+
func blockBodyContentKey*(blockNumber: uint64): ContentKey =
30+
ContentKey(
31+
contentType: blockBody, blockBodyKey: BlockNumberKey(blockNumber: blockNumber)
32+
)
33+
34+
func receiptsContentKey*(blockNumber: uint64): ContentKey =
35+
ContentKey(
36+
contentType: receipts, receiptsKey: BlockNumberKey(blockNumber: blockNumber)
37+
)
38+
39+
template blockNumber*(contentKey: ContentKey): uint64 =
40+
## Returns the block number for the given content key
41+
case contentKey.contentType
42+
of blockBody: contentKey.blockBodyKey.blockNumber
43+
of receipts: contentKey.receiptsKey.blockNumber
44+
45+
proc readSszBytes*(data: openArray[byte], val: var ContentKey) {.raises: [SszError].} =
46+
mixin readSszValue
47+
48+
readSszValue(data, val)
49+
50+
func encode*(contentKey: ContentKey): ContentKeyByteList =
51+
ContentKeyByteList.init(SSZ.encode(contentKey))
52+
53+
func decode*(contentKey: ContentKeyByteList): Opt[ContentKey] =
54+
try:
55+
Opt.some(SSZ.decode(contentKey.asSeq(), ContentKey))
56+
except SerializationError:
57+
return Opt.none(ContentKey)
58+
59+
func reverseBits(n: uint64, width: int): uint64 =
60+
## Reverse the lowest `width` bits of `n`
61+
# TODO: can improve
62+
var res: uint64 = 0
63+
for i in 0 ..< width:
64+
if ((n shr i) and 1) != 0:
65+
res = res or (1'u64 shl (width - 1 - i))
66+
res
67+
68+
const
69+
CYCLE_BITS = 16
70+
OFFSET_BITS = 256 - CYCLE_BITS # 240
71+
REVERSED_OFFSET_BITS = 64 - CYCLE_BITS # 48
72+
73+
func toContentId*(blockNumber: uint64, contentType: ContentType): UInt256 =
74+
## Returns the content id for a given block number
75+
let
76+
cycleBits = blockNumber mod (1'u64 shl CYCLE_BITS)
77+
offsetBits = blockNumber div (1'u64 shl CYCLE_BITS)
78+
79+
reversedOffsetBits = reverseBits(offsetBits, REVERSED_OFFSET_BITS)
80+
81+
(cycleBits.stuint(256) shl OFFSET_BITS) or
82+
(reversedOffsetBits.stuint(256) shl (OFFSET_BITS - REVERSED_OFFSET_BITS)) or
83+
ord(contentType).stuint(256)
84+
85+
func toContentId*(contentKey: ContentKey): ContentId =
86+
case contentKey.contentType
87+
of blockBody:
88+
toContentId(contentKey.blockBodyKey.blockNumber, contentKey.contentType)
89+
of receipts:
90+
toContentId(contentKey.receiptsKey.blockNumber, contentKey.contentType)
91+
92+
func toContentId*(bytes: ContentKeyByteList): Opt[ContentId] =
93+
let contentKey = ?bytes.decode()
94+
Opt.some(contentKey.toContentId())
95+
96+
func `$`*(x: BlockNumberKey): string =
97+
"block_number: " & $x.blockNumber
98+
99+
func `$`*(x: ContentKey): string =
100+
var res = "(type: " & $x.contentType & ", "
101+
102+
case x.contentType
103+
of blockBody:
104+
res.add($x.blockBodyKey)
105+
of receipts:
106+
res.add($x.receiptsKey)
107+
108+
res.add(")")
109+
110+
res
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Nimbus
2+
# Copyright (c) 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 eth/common/blocks_rlp, eth/common/receipts_rlp
11+
12+
export blocks_rlp, receipts_rlp
13+
14+
type
15+
StoredReceipts* = seq[StoredReceipt]
16+
ContentValueType* = BlockBody | StoredReceipts
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Nimbus
2+
# Copyright (c) 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 ./content/content_keys, ./content/content_values
11+
12+
export content_keys, content_values
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Nimbus
2+
# Copyright (c) 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 results, chronicles, chronos, ./history_network
11+
12+
export results, history_network
13+
14+
proc getBlockBody*(
15+
n: HistoryNetwork, header: Header
16+
): Future[Opt[BlockBody]] {.async: (raises: [CancelledError], raw: true).} =
17+
n.getContent(blockBodyContentKey(header.number), BlockBody, header)
18+
19+
proc getReceipts*(
20+
n: HistoryNetwork, header: Header
21+
): Future[Opt[StoredReceipts]] {.async: (raises: [CancelledError], raw: true).} =
22+
n.getContent(receiptsContentKey(header.number), StoredReceipts, header)

0 commit comments

Comments
 (0)