Skip to content

Commit 3ea5c53

Browse files
authored
portal_bridge history: fully support gossip of block by number (#2853)
+ some minor cleanup & reuse of code
1 parent 01ca415 commit 3ea5c53

File tree

4 files changed

+80
-53
lines changed

4 files changed

+80
-53
lines changed

fluffy/eth_data/era1.nim

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import
1313
stew/[endians2, io2, byteutils, arrayops],
1414
stint,
1515
snappy,
16-
eth/common/[headers, blocks_rlp, receipts_rlp],
16+
eth/common/[headers_rlp, blocks_rlp, receipts_rlp],
1717
beacon_chain/spec/beacon_time,
1818
ssz_serialization,
1919
ncli/e2store,
@@ -184,7 +184,7 @@ proc fromCompressedRlpBytes(bytes: openArray[byte], T: type): Result[T, string]
184184
try:
185185
ok(rlp.decode(decodeFramed(bytes, checkIntegrity = false), T))
186186
except RlpError as e:
187-
err("Invalid Compressed RLP data" & e.msg)
187+
err("Invalid compressed RLP data for " & $T & ": " & e.msg)
188188

189189
proc init*(T: type Era1Group, f: IoHandle, startNumber: uint64): Result[T, string] =
190190
discard ?f.appendHeader(E2Version, 0)
@@ -498,7 +498,7 @@ iterator era1BlockHeaders*(f: Era1File): headers.Header =
498498

499499
for blockNumber in startNumber .. endNumber:
500500
let header = f.getBlockHeader(blockNumber).valueOr:
501-
raiseAssert("Failed to read block header")
501+
raiseAssert("Failed to read block header: " & error)
502502
yield header
503503

504504
iterator era1BlockTuples*(f: Era1File): BlockTuple =
@@ -508,5 +508,5 @@ iterator era1BlockTuples*(f: Era1File): BlockTuple =
508508

509509
for blockNumber in startNumber .. endNumber:
510510
let blockTuple = f.getBlockTuple(blockNumber).valueOr:
511-
raiseAssert("Failed to read block header")
511+
raiseAssert("Failed to read block tuple: " & error)
512512
yield blockTuple

fluffy/tools/portal_bridge/portal_bridge_conf.nim

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import
1212
confutils,
1313
confutils/std/net,
1414
nimcrypto/hash,
15+
../../network_metadata,
16+
../../eth_data/era1,
1517
../../[conf, logging]
1618

1719
export net
@@ -36,6 +38,8 @@ proc defaultPortalBridgeStateDir*(): string =
3638
else:
3739
defaultDataDir() / "bridge" / "state"
3840

41+
const defaultEndEra* = uint64(era(network_metadata.mergeBlockNumber - 1))
42+
3943
type
4044
TrustedDigest* = MDigest[32 * 8]
4145

@@ -117,6 +121,13 @@ type
117121
name: "backfill"
118122
.}: bool
119123

124+
startEra* {.desc: "The era to start from", defaultValue: 0, name: "start-era".}:
125+
uint64
126+
127+
endEra* {.
128+
desc: "The era to stop at", defaultValue: defaultEndEra, name: "end-era"
129+
.}: uint64
130+
120131
audit* {.
121132
desc:
122133
"Run pre-merge backfill in audit mode, which will only gossip content that if failed to fetch from the network",

fluffy/tools/portal_bridge/portal_bridge_history.nim

Lines changed: 64 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ proc getBlockReceipts(
140140

141141
proc gossipBlockHeader(
142142
client: RpcClient, id: Hash32 | uint64, headerWithProof: BlockHeaderWithProof
143-
): Future[Result[void, string]] {.async: (raises: []).} =
143+
): Future[Result[void, string]] {.async: (raises: [CancelledError]).} =
144144
let
145145
contentKey = blockHeaderContentKey(id)
146146
encodedContentKeyHex = contentKey.encode.asSeq().toHex()
@@ -154,13 +154,13 @@ proc gossipBlockHeader(
154154
return err("JSON-RPC portal_historyGossip failed: " & $e.msg)
155155

156156
info "Block header gossiped", peers, contentKey = encodedContentKeyHex
157-
return ok()
157+
ok()
158158

159159
proc gossipBlockBody(
160160
client: RpcClient,
161161
hash: Hash32,
162162
body: PortalBlockBodyLegacy | PortalBlockBodyShanghai,
163-
): Future[Result[void, string]] {.async: (raises: []).} =
163+
): Future[Result[void, string]] {.async: (raises: [CancelledError]).} =
164164
let
165165
contentKey = blockBodyContentKey(hash)
166166
encodedContentKeyHex = contentKey.encode.asSeq().toHex()
@@ -174,11 +174,11 @@ proc gossipBlockBody(
174174
return err("JSON-RPC portal_historyGossip failed: " & $e.msg)
175175

176176
info "Block body gossiped", peers, contentKey = encodedContentKeyHex
177-
return ok()
177+
ok()
178178

179179
proc gossipReceipts(
180180
client: RpcClient, hash: Hash32, receipts: PortalReceipts
181-
): Future[Result[void, string]] {.async: (raises: []).} =
181+
): Future[Result[void, string]] {.async: (raises: [CancelledError]).} =
182182
let
183183
contentKey = receiptsContentKey(hash)
184184
encodedContentKeyHex = contentKey.encode.asSeq().toHex()
@@ -285,7 +285,7 @@ proc gossipHeadersWithProof(
285285
era1File: string,
286286
epochRecordFile: Opt[string] = Opt.none(string),
287287
verifyEra = false,
288-
): Future[Result[void, string]] {.async: (raises: []).} =
288+
): Future[Result[void, string]] {.async: (raises: [CancelledError]).} =
289289
let f = ?Era1File.open(era1File)
290290

291291
if verifyEra:
@@ -296,54 +296,72 @@ proc gossipHeadersWithProof(
296296
# UX hassle it adds to provide the accumulator ssz files.
297297
let epochRecord =
298298
if epochRecordFile.isNone:
299+
info "Building accumulator from era1 file", era1File
299300
?f.buildAccumulator()
300301
else:
301302
?readEpochRecordCached(epochRecordFile.get())
302303

303-
for (contentKey, contentValue) in f.headersWithProof(epochRecord):
304-
let peers =
305-
try:
306-
await portalClient.portal_historyGossip(
307-
contentKey.asSeq.toHex(), contentValue.toHex()
308-
)
309-
except CatchableError as e:
310-
return err("JSON-RPC portal_historyGossip failed: " & $e.msg)
311-
info "Block header gossiped", peers, contentKey
304+
info "Gossip headers from era1 file", era1File
312305

306+
for blockHeader in f.era1BlockHeaders:
307+
doAssert blockHeader.isPreMerge()
308+
309+
let
310+
headerWithProof = buildHeaderWithProof(blockHeader, epochRecord).valueOr:
311+
raiseAssert "Failed to build header with proof: " & $blockHeader.number
312+
blockHash = blockHeader.rlpHash()
313+
314+
# gossip block header by hash
315+
?(await portalClient.gossipBlockHeader(blockHash, headerWithProof))
316+
# gossip block header by number
317+
?(await portalClient.gossipBlockHeader(blockHeader.number, headerWithProof))
318+
319+
info "Succesfully gossiped headers from era1 file", era1File
313320
ok()
314321

315322
proc gossipBlockContent(
316323
portalClient: RpcClient, era1File: string, verifyEra = false
317-
): Future[Result[void, string]] {.async: (raises: []).} =
324+
): Future[Result[void, string]] {.async: (raises: [CancelledError]).} =
318325
let f = ?Era1File.open(era1File)
319326

320327
if verifyEra:
321328
let _ = ?f.verify()
322329

323-
for (contentKey, contentValue) in f.blockContent():
324-
let peers =
325-
try:
326-
await portalClient.portal_historyGossip(
327-
contentKey.asSeq.toHex(), contentValue.toHex()
328-
)
329-
except CatchableError as e:
330-
return err("JSON-RPC portal_historyGossip failed: " & $e.msg)
331-
info "Block content gossiped", peers, contentKey
330+
info "Gossip bodies and receipts from era1 file", era1File
332331

332+
for (header, body, receipts, _) in f.era1BlockTuples:
333+
let blockHash = header.rlpHash()
334+
335+
# gossip block body
336+
?(
337+
await portalClient.gossipBlockBody(
338+
blockHash, PortalBlockBodyLegacy.fromBlockBody(body)
339+
)
340+
)
341+
342+
# gossip receipts
343+
?(
344+
await portalClient.gossipReceipts(
345+
blockHash, PortalReceipts.fromReceipts(receipts)
346+
)
347+
)
348+
349+
info "Succesfully gossiped bodies and receipts from era1 file", era1File
333350
ok()
334351

335352
proc runBackfillLoop(
336-
portalClient: RpcClient, web3Client: RpcClient, era1Dir: string
353+
portalClient: RpcClient,
354+
web3Client: RpcClient,
355+
era1Dir: string,
356+
startEra: uint64,
357+
endEra: uint64,
337358
) {.async: (raises: [CancelledError]).} =
338-
let
339-
rng = newRng()
340-
accumulator = loadAccumulator()
341-
while true:
359+
let accumulator = loadAccumulator()
360+
361+
for era in startEra .. endEra:
342362
let
343-
# Grab a random era1 to backfill
344-
era = rng[].rand(int(era(network_metadata.mergeBlockNumber - 1)))
345363
root = accumulator.historicalEpochs[era]
346-
eraFile = era1Dir / era1FileName("mainnet", Era1(era), Digest(data: root))
364+
era1File = era1Dir / era1FileName("mainnet", Era1(era), Digest(data: root))
347365

348366
# Note:
349367
# There are two design options here:
@@ -360,40 +378,36 @@ proc runBackfillLoop(
360378
# new era1 can be gossiped (might need another custom json-rpc that checks
361379
# the offer queue)
362380
when false:
363-
info "Gossip headers from era1 file", eraFile
381+
info "Gossip headers from era1 file", era1File
364382
let headerRes =
365383
try:
366-
await portalClient.portal_debug_historyGossipHeaders(eraFile)
384+
await portalClient.portal_debug_historyGossipHeaders(era1File)
367385
except CatchableError as e:
368386
error "JSON-RPC portal_debug_historyGossipHeaders failed", error = e.msg
369387
false
370388

371389
if headerRes:
372-
info "Gossip block content from era1 file", eraFile
390+
info "Gossip block content from era1 file", era1File
373391
let res =
374392
try:
375-
await portalClient.portal_debug_historyGossipBlockContent(eraFile)
393+
await portalClient.portal_debug_historyGossipBlockContent(era1File)
376394
except CatchableError as e:
377395
error "JSON-RPC portal_debug_historyGossipBlockContent failed",
378396
error = e.msg
379397
false
380398
if res:
381-
error "Failed to gossip block content from era1 file", eraFile
399+
error "Failed to gossip block content from era1 file", era1File
382400
else:
383-
error "Failed to gossip headers from era1 file", eraFile
401+
error "Failed to gossip headers from era1 file", era1File
384402
else:
385-
info "Gossip headers from era1 file", eraFile
386-
(await portalClient.gossipHeadersWithProof(eraFile)).isOkOr:
387-
error "Failed to gossip headers from era1 file", error, eraFile
403+
(await portalClient.gossipHeadersWithProof(era1File)).isOkOr:
404+
error "Failed to gossip headers from era1 file", error, era1File
388405
continue
389406

390-
info "Gossip block content from era1 file", eraFile
391-
(await portalClient.gossipBlockContent(eraFile)).isOkOr:
392-
error "Failed to gossip block content from era1 file", error, eraFile
407+
(await portalClient.gossipBlockContent(era1File)).isOkOr:
408+
error "Failed to gossip block content from era1 file", error, era1File
393409
continue
394410

395-
info "Succesfully gossiped era1 file", eraFile
396-
397411
proc runBackfillLoopAuditMode(
398412
portalClient: RpcClient, web3Client: RpcClient, era1Dir: string
399413
) {.async: (raises: [CancelledError]).} =
@@ -548,7 +562,9 @@ proc runHistory*(config: PortalBridgeConf) =
548562
portalClient, web3Client, config.era1Dir.string
549563
)
550564
else:
551-
asyncSpawn runBackfillLoop(portalClient, web3Client, config.era1Dir.string)
565+
asyncSpawn runBackfillLoop(
566+
portalClient, web3Client, config.era1Dir.string, config.startEra, config.endEra
567+
)
552568

553569
while true:
554570
poll()

0 commit comments

Comments
 (0)