2023-04-13 19:11:40 +00:00
|
|
|
# beacon_chain
|
2024-01-06 14:26:56 +00:00
|
|
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
2023-04-13 19:11:40 +00:00
|
|
|
# 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.
|
|
|
|
|
|
|
|
{.push raises: [].}
|
|
|
|
|
2024-01-13 09:52:13 +00:00
|
|
|
import
|
|
|
|
std/tables,
|
|
|
|
../spec/helpers
|
|
|
|
|
2023-08-29 16:46:25 +00:00
|
|
|
from std/sequtils import mapIt
|
|
|
|
from std/strutils import join
|
2023-04-13 19:11:40 +00:00
|
|
|
|
|
|
|
const
|
2024-03-24 03:29:44 +00:00
|
|
|
MaxBlobs = 3 * SLOTS_PER_EPOCH * MAX_BLOBS_PER_BLOCK
|
|
|
|
## Same limit as `MaxOrphans` in `block_quarantine`;
|
|
|
|
## blobs may arrive before an orphan is tagged `blobless`
|
2023-04-13 19:11:40 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
BlobQuarantine* = object
|
2024-07-25 16:51:22 +00:00
|
|
|
blobs*: OrderedTable[
|
|
|
|
(Eth2Digest, BlobIndex, KzgCommitment), ForkedBlobSidecar]
|
2024-01-13 09:52:13 +00:00
|
|
|
onBlobSidecarCallback*: OnBlobSidecarCallback
|
|
|
|
|
2023-04-28 12:57:35 +00:00
|
|
|
BlobFetchRecord* = object
|
|
|
|
block_root*: Eth2Digest
|
|
|
|
indices*: seq[BlobIndex]
|
2023-04-13 19:11:40 +00:00
|
|
|
|
2024-07-23 20:22:29 +00:00
|
|
|
OnBlobSidecarCallback = proc(
|
|
|
|
data: BlobSidecarInfoObject) {.gcsafe, raises: [].}
|
2024-01-13 09:52:13 +00:00
|
|
|
|
2023-04-28 12:57:35 +00:00
|
|
|
func shortLog*(x: seq[BlobIndex]): string =
|
|
|
|
"<" & x.mapIt($it).join(", ") & ">"
|
|
|
|
|
|
|
|
func shortLog*(x: seq[BlobFetchRecord]): string =
|
|
|
|
"[" & x.mapIt(shortLog(it.block_root) & shortLog(it.indices)).join(", ") & "]"
|
2023-04-13 19:11:40 +00:00
|
|
|
|
2024-07-25 16:51:22 +00:00
|
|
|
func put*(quarantine: var BlobQuarantine, blobSidecar: ForkedBlobSidecar) =
|
2024-03-24 05:03:51 +00:00
|
|
|
if quarantine.blobs.lenu64 >= MaxBlobs:
|
2023-08-29 16:46:25 +00:00
|
|
|
# FIFO if full. For example, sync manager and request manager can race to
|
|
|
|
# put blobs in at the same time, so one gets blob insert -> block resolve
|
|
|
|
# -> blob insert sequence, which leaves garbage blobs.
|
2023-12-01 18:58:46 +00:00
|
|
|
#
|
|
|
|
# This also therefore automatically garbage-collects otherwise valid garbage
|
|
|
|
# blobs which are correctly signed, point to either correct block roots or a
|
|
|
|
# block root which isn't ever seen, and then are for any reason simply never
|
|
|
|
# used.
|
|
|
|
var oldest_blob_key: (Eth2Digest, BlobIndex, KzgCommitment)
|
2023-08-29 16:46:25 +00:00
|
|
|
for k in quarantine.blobs.keys:
|
|
|
|
oldest_blob_key = k
|
|
|
|
break
|
|
|
|
quarantine.blobs.del oldest_blob_key
|
2024-07-25 16:51:22 +00:00
|
|
|
withForkyBlob(blobSidecar):
|
|
|
|
let block_root = hash_tree_root(forkyBlob[].signed_block_header.message)
|
|
|
|
discard quarantine.blobs.hasKeyOrPut(
|
|
|
|
(block_root, forkyBlob[].index, forkyBlob[].kzg_commitment), blobSidecar)
|
|
|
|
|
|
|
|
func put*(quarantine: var BlobQuarantine, blobSidecar: ref ForkyBlobSidecar) =
|
|
|
|
quarantine.put(ForkedBlobSidecar.init(blobSidecar))
|
2023-04-13 19:11:40 +00:00
|
|
|
|
2023-11-05 08:13:57 +00:00
|
|
|
func hasBlob*(
|
|
|
|
quarantine: BlobQuarantine,
|
|
|
|
slot: Slot,
|
|
|
|
proposer_index: uint64,
|
|
|
|
index: BlobIndex): bool =
|
2024-07-25 16:51:22 +00:00
|
|
|
for blobSidecar in quarantine.blobs.values:
|
|
|
|
withForkyBlob(blobSidecar):
|
|
|
|
template block_header: untyped = forkyBlob[].signed_block_header.message
|
|
|
|
if block_header.slot == slot and
|
|
|
|
block_header.proposer_index == proposer_index and
|
|
|
|
forkyBlob[].index == index:
|
|
|
|
return true
|
2023-11-05 08:13:57 +00:00
|
|
|
false
|
2023-04-13 19:11:40 +00:00
|
|
|
|
2023-12-01 18:58:46 +00:00
|
|
|
func popBlobs*(
|
|
|
|
quarantine: var BlobQuarantine, digest: Eth2Digest,
|
2024-07-25 16:51:22 +00:00
|
|
|
blck:
|
|
|
|
deneb.SignedBeaconBlock |
|
|
|
|
electra.SignedBeaconBlock): auto =
|
|
|
|
const blobFork = blobForkAtConsensusFork(typeof(blck).kind).expect("Blobs OK")
|
|
|
|
type ResultType = blobFork.BlobSidecars
|
|
|
|
var r: ResultType = @[]
|
2023-12-01 18:58:46 +00:00
|
|
|
for idx, kzg_commitment in blck.message.body.blob_kzg_commitments:
|
2024-07-25 16:51:22 +00:00
|
|
|
var b: ForkedBlobSidecar
|
2023-12-01 18:58:46 +00:00
|
|
|
if quarantine.blobs.pop((digest, BlobIndex idx, kzg_commitment), b):
|
2024-07-25 16:51:22 +00:00
|
|
|
# It was already verified that the blob is linked to `blck`.
|
|
|
|
# Therefore, we can assume that `BlobFork` is correct.
|
|
|
|
doAssert b.kind == blobFork,
|
|
|
|
"Must verify blob inclusion proof before `BlobQuarantine.put`"
|
|
|
|
r.add(b.forky(blobFork))
|
2023-04-13 19:11:40 +00:00
|
|
|
r
|
|
|
|
|
2024-07-25 16:51:22 +00:00
|
|
|
func hasBlobs*(
|
|
|
|
quarantine: BlobQuarantine,
|
|
|
|
blck:
|
|
|
|
deneb.SignedBeaconBlock |
|
|
|
|
electra.SignedBeaconBlock): bool =
|
2023-12-01 18:58:46 +00:00
|
|
|
for idx, kzg_commitment in blck.message.body.blob_kzg_commitments:
|
|
|
|
if (blck.root, BlobIndex idx, kzg_commitment) notin quarantine.blobs:
|
2023-04-13 19:11:40 +00:00
|
|
|
return false
|
|
|
|
true
|
2023-04-28 12:57:35 +00:00
|
|
|
|
2024-07-25 16:51:22 +00:00
|
|
|
func blobFetchRecord*(
|
|
|
|
quarantine: BlobQuarantine,
|
|
|
|
blck:
|
|
|
|
deneb.SignedBeaconBlock |
|
|
|
|
electra.SignedBeaconBlock): BlobFetchRecord =
|
2023-04-28 12:57:35 +00:00
|
|
|
var indices: seq[BlobIndex]
|
|
|
|
for i in 0..<len(blck.message.body.blob_kzg_commitments):
|
|
|
|
let idx = BlobIndex(i)
|
2023-12-01 18:58:46 +00:00
|
|
|
if not quarantine.blobs.hasKey(
|
|
|
|
(blck.root, idx, blck.message.body.blob_kzg_commitments[i])):
|
2023-04-28 12:57:35 +00:00
|
|
|
indices.add(idx)
|
|
|
|
BlobFetchRecord(block_root: blck.root, indices: indices)
|
2024-01-13 09:52:13 +00:00
|
|
|
|
|
|
|
func init*(
|
|
|
|
T: type BlobQuarantine, onBlobSidecarCallback: OnBlobSidecarCallback): T =
|
|
|
|
T(onBlobSidecarCallback: onBlobSidecarCallback)
|