You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We currently store pending blocks in our DB, which makes our P2P layer serve them to peers on request. We should instead first do as many checks we can (or at least verify their signature), before storing them.
@MegaRedHand here a list of items I think we should be checking for:
First, check if the propose block matches the slot, is_proposer(proposer_index, slot, num_validators), using the finalized state's validator count.
Check if any entry has duplicate AttestationData in the block.body.attestations list so we don't count more than once.
Also ensure that distinct attestation does not exceed the MAX_ATTESTATIONS_DATA cap, reject blocks that exceed the cap.
Ensure proposer_index and every validator index set in each attestation's aggregation_bits are below the validator count. An index at or above it names a validator that does not exist, so the block can't be valid.
A parent root sanity check to ensure the the parent_root is not equal to the block's root or the zero root.
If the parent header is already in the DB as an earlier pending block, require block.slot > parent.slot.
Reject blocks which parent is on a finalized-conflicting fork and is not the finalized root.
Reject if parent_root is in a set of roots that previously failed the state transition.
Also skip, if header for the parent_root exists.
Cap how many pending blocks the node keeps in total and per slot, evicting the oldest when full, so a flood of unimportable blocks cannot grow memory and disk without bound.
Finally, verifying signature as stated by you using verify_block_signatures(&finalized_state, &signed_block) so forged blocks don't make it through.
Also can some additional clean up be done like:
Deleting DB rows on discard discard_pending_subtree
Drop pending storage for BlocksByRange blocks whose parent is missing, since they arrive in order and a gap means a bad peer, while still pending gossip and BlocksByRoot blocks.
@MegaRedHand here a list of items I think we should be checking for:
First, check if the propose block matches the slot, is_proposer(proposer_index, slot, num_validators), using the finalized state's validator count.
Check if any entry has duplicate AttestationData in the block.body.attestations list so we don't count more than once.
Also ensure that distinct attestation does not exceed the MAX_ATTESTATIONS_DATA cap, reject blocks that exceed the cap.
Ensure proposer_index and every validator index set in each attestation's aggregation_bits are below the validator count. An index at or above it names a validator that does not exist, so the block can't be valid.
A parent root sanity check to ensure the the parent_root is not equal to the block's root or the zero root.
If the parent header is already in the DB as an earlier pending block, require block.slot > parent.slot.
Reject blocks which parent is on a finalized-conflicting fork and is not the finalized root.
Reject if parent_root is in a set of roots that previously failed the state transition.
Also skip, if header for the parent_root exists.
Cap how many pending blocks the node keeps in total and per slot, evicting the oldest when full, so a flood of unimportable blocks cannot grow memory and disk without bound.
Finally, verifying signature as stated by you using verify_block_signatures(&finalized_state, &signed_block) so forged blocks don't make it through.
Also can some additional clean up be done like:
Deleting DB rows on discard discard_pending_subtree
Drop pending storage for BlocksByRange blocks whose parent is missing, since they arrive in order and a gap means a bad peer, while still pending gossip and BlocksByRoot blocks.
Please let me know what your thoughts on these @MegaRedHand
Activity
Aliemeka commentedon Sep 7, 2026
Will love to take a look into this @MegaRedHand
MegaRedHand commentedon Sep 7, 2026
Sure, but I suggest coming up with a list of checks to do before opening a PR
Aliemeka commentedon Sep 8, 2026
Ok
Aliemeka commentedon Sep 8, 2026
@MegaRedHand here a list of items I think we should be checking for:
is_proposer(proposer_index, slot, num_validators), using the finalized state's validator count.AttestationDatain theblock.body.attestationslist so we don't count more than once.MAX_ATTESTATIONS_DATAcap, reject blocks that exceed the cap.proposer_indexand every validator index set in each attestation'saggregation_bitsare below the validator count. An index at or above it names a validator that does not exist, so the block can't be valid.parent_rootis not equal to the block's root or the zero root.block.slot>parent.slot.parent_rootis in a set of roots that previously failed the state transition.verify_block_signatures(&finalized_state, &signed_block)so forged blocks don't make it through.Also can some additional clean up be done like:
discard_pending_subtreeBlocksByRangeblocks whose parent is missing, since they arrive in order and a gap means a bad peer, while still pending gossip andBlocksByRootblocks.Aliemeka commentedon Sep 8, 2026
Please let me know what your thoughts on these @MegaRedHand
MegaRedHand commentedon Sep 9, 2026
Not sure about this one.
I would leave this one for a following PR. Same for the additional clean up of the DB and pending blocks.
The rest of the list looks good.