Skip to content

feat(starfish): send full block #6803

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

VorobyevIlya
Copy link
Contributor

@VorobyevIlya VorobyevIlya commented May 8, 2025

Description of change

This PR introduces a full block structure, which contains a header and transactions.

Changes in network communications:
In streaming we now use SerialiedBlocks structure which contain serialization of a header and serializetion of transactions.
In synchronizer Functions fetching blocks are removed or changed to fetch headers. The only place where we still fetch blocks is in the commitSyncer.

Commit:
Certified commit contains blocks, CommittedSubDag contains only headers for now, blocks should be added later. In stake verification we use only headers, since it is enough.

CoreThreadDispatcher: a new command AddBlockHeaders was added. Several Fake/Mock dispatchers were merged into one.

Storage: we store now both headers and full blocks. If blocks are written to disk then their headers are written there too. There is a possibility to read blocks or only headers. Changes implemented both for mem_store and RocksDB.

Linearizer now operates with headers.

DagState and BlockManager:
DagState works with headers now since for building DAG only headers are important. However, we still store recent_blocks since we need to request blocks for fetching.
Functions such as accept block work with headers now. However, there can be situations when we already have data but the corresponding block header is not accepted yet. We can also have accepted header without data. Structures for storing such blocks and headers were added to BlockManager. They should be cleaned at some point, it is something to be done in future PRs.

Links to any relevant issues

closes #6707.

Type of change

Choose a type of change, and delete any options that are not relevant.

  • Enhancement (a non-breaking change which adds functionality)

How the change has been tested

  • Basic tests (linting, compilation, formatting, unit/integration tests)
  • Patch-specific tests (correctness, functionality coverage)

Change checklist

Tick the boxes that are relevant to your changes, and delete any items that are not.

  • I have followed the contribution guidelines for this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • I have checked that new and existing unit tests pass locally with my changes

Release Notes

  • Protocol:
  • Nodes (Validators and Full nodes):
  • Indexer:
  • JSON-RPC:
  • GraphQL:
  • CLI:
  • Rust SDK:
  • REST API:

Copy link

vercel bot commented May 8, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

4 Skipped Deployments
Name Status Preview Comments Updated (UTC)
apps-backend ⬜️ Ignored (Inspect) Visit Preview Jun 4, 2025 9:29am
apps-ui-kit ⬜️ Ignored (Inspect) Visit Preview Jun 4, 2025 9:29am
rebased-explorer ⬜️ Ignored (Inspect) Visit Preview Jun 4, 2025 9:29am
wallet-dashboard ⬜️ Ignored (Inspect) Visit Preview Jun 4, 2025 9:29am

@VorobyevIlya VorobyevIlya self-assigned this May 8, 2025
@iota-ci iota-ci added consensus Issues related to the Core Consensus team core-protocol labels May 8, 2025
@VorobyevIlya VorobyevIlya force-pushed the consensus/feat/starfish/send-full-block branch from 7a9fb27 to c1e421a Compare May 9, 2025 19:32
@VorobyevIlya VorobyevIlya force-pushed the consensus/feat/starfish/send-full-block branch from 6ecd338 to 6c73112 Compare May 20, 2025 10:08
@piotrm50 piotrm50 force-pushed the consensus/feat/starfish-consensus branch from 6b470f7 to 3d6f76d Compare May 20, 2025 14:07
@github-actions github-actions bot added the ci Issues related to our CI pipeline label May 21, 2025
@VorobyevIlya VorobyevIlya force-pushed the consensus/feat/starfish/send-full-block branch 2 times, most recently from be705ab to 7c46133 Compare May 21, 2025 10:31
suspended_block_headers: BTreeMap<BlockRef, SuspendedBlockHeader>,
/// Keeps full blocks for suspended block headers
suspended_blocks: BTreeMap<BlockRef, VerifiedBlock>,
// TODO: should it be here? need to discuss
Copy link
Member

@polinikita polinikita May 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a brief explanation. Is it ever ever-growing set? If so, it might be too big at the end.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, there should be some eviction mechanism there. I will add to do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is needed here as we only will fetch missing transactions that become committed at some point in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, removing it

@VorobyevIlya VorobyevIlya marked this pull request as ready for review May 27, 2025 14:42
@VorobyevIlya VorobyevIlya requested a review from a team as a code owner May 27, 2025 14:42
Copy link
Contributor

@piotrm50 piotrm50 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left some comments and questions

/// Handles the request to fetch blocks by references from the peer.
async fn handle_fetch_blocks(
&self,
peer: AuthorityIndex,
block_refs: Vec<BlockRef>,
highest_accepted_rounds: Vec<Round>,
) -> ConsensusResult<Vec<Bytes>>;
) -> ConsensusResult<(Vec<Bytes>, Vec<Bytes>)>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are those two vectors of bytes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add the comment above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function returns pair of Vec. The first vector contains serialization of the headers of blocks from block_refs
and the second contains serializations of transactions of these blocks.

async fn fetch_blocks(
&self,
peer: AuthorityIndex,
block_refs: Vec<BlockRef>,
highest_accepted_rounds: Vec<Round>,
timeout: Duration,
) -> ConsensusResult<Vec<Bytes>> {
) -> ConsensusResult<(Vec<Bytes>, Vec<Bytes>)> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be easier to handle if we introduce a new type called Block that wraps BlockHeader and Transactions - we already have SerializedBlock which contains those two serialized things anyway, but I think it's a bit weird to handle those things separately afterwards.

@@ -1007,7 +1123,25 @@ pub(crate) struct SubscribeBlocksRequest {
#[derive(Clone, prost::Message)]
pub(crate) struct SubscribeBlocksResponse {
#[prost(bytes = "bytes", tag = "1")]
block: Bytes,
serialized_block_header: Bytes,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we send headers and transactions separately, instead of having sending a serialized Block type that wraps those two things? Would not that be easier to handle?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be easier to handle at the network level, but not on the consensus level. It requires Serialization of two serialized vectors, which I am not sure that efficient. The same for deserialization. First, we deserialize Bytes into Block, then we need to split this and serialize into Bytes block_header and transaction_data. This does not sound good to me.

@@ -601,46 +602,50 @@ impl<C: NetworkClient> CommitSyncer<C> {
)
.await?;
// 5. Verify the same number of blocks are returned as requested.
if request_block_refs.len() != serialized_blocks.len() {
if request_block_refs.len() != serialized_blocks.0.len()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Working with a tuple here looks weird imo - let's try to create a wrapper type.

@@ -443,20 +532,35 @@ impl DagState {

/// Gets the last proposed block from this authority.
/// If no block is proposed yet, returns the genesis block.
pub(crate) fn get_last_proposed_block(&self) -> VerifiedBlockHeader {
self.get_last_block_for_authority(self.context.own_index)
pub(crate) fn get_last_proposed_block(&self) -> Option<VerifiedBlock> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this return an option now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

previously Genesis block was instead of None. I think it is better like this, but there is no big difference. The comment above was outdated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now it's inconsistent with the following methods get_last_proposed_block_header and get_last_block_header_for_authority.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed it back

}

impl BlockStoreAPI
for parking_lot::lock_api::RwLockWriteGuard<'_, parking_lot::RawRwLock, DagState>
{
fn get_blocks(&self, refs: &[BlockRef]) -> Vec<Option<VerifiedBlockHeader>> {
fn get_blocks(&self, refs: &[BlockRef]) -> Vec<Option<VerifiedBlock>> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this still needed? If not needed then I'd remove it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, removed it

@@ -468,7 +572,7 @@ impl DagState {
.iter()
.find(|(block_ref, _)| block_ref.author == authority)
.expect("Genesis should be found for authority {authority_index}");
genesis_block.clone()
(**genesis_block).clone()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is just transformation to header, we changed function to return header

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think explicitly writing genesis_block.verified_block_header is more readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, fixed

@piotrm50 piotrm50 linked an issue Jun 2, 2025 that may be closed by this pull request
@VorobyevIlya VorobyevIlya force-pushed the consensus/feat/starfish/send-full-block branch from 75c965a to 7802696 Compare June 2, 2025 10:57
polinikita and others added 3 commits June 2, 2025 13:09
fix clippy warnings

fix transaction commitment for test header

clippy

some comments

fixed serialized block verification

comments and cleaning up

fix fetched bytes computation

add some comments

renamed handle send block to handle subscribe block

remove send block from network client

fix assert

implement fetch blocks for tonic network

fix writing to disc only headers and only blocks

fix test checking cashed block to work with headers

changes synchronizerHandle to work with headers instead of blocks

add logic to store full block data for suspended headers in block manager

create separate recent_refs_by_authority structures for headers and blocks

create accept_block function which accepts header into DagState and also saves the block into recent blocks

change test for getting blocks from cash to work with headers

implemented reading block headers from rocksdb

implemented check for headers in store and fixed corresponding test

read headers instead of blocks in dagState creation. Implemented read_headers in mem_store

fix verified block creation

merge all fake and mock core dispatchers

add addBlockHeaders to coreThreadCommand

fix tests compilation

fix imports

add a new struct VerifiedBlock

fix warnings

fmt

create add block headers command

it compiles!

fixing wrapper continues

fix decoupling header from transactions

decouple serialized bytes

fix typo

implement a wrapper around serialized header and transactions -- SerializedBlock (not finished)

implement write and read functions for blocks for RocksDB

fix test compilation

fix compilation errors

add a new struct VerifiedBlock
@VorobyevIlya VorobyevIlya force-pushed the consensus/feat/starfish/send-full-block branch from 7802696 to 7793322 Compare June 2, 2025 14:33
Copy link
Contributor

@piotrm50 piotrm50 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left some small comments, but now looks good 👍

fn try_from(verified_block: VerifiedBlock) -> ConsensusResult<Self> {
let (serialized_block_header, serialized_transactions) = verified_block.serialized();
let serialized_header_and_transactions = SerializedHeaderAndTransactions {
serialized_block_header: serialized_block_header.clone(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need .clone() here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think yes, I have only references to Bytes here, I can't move them unless I change serialized function or get access to this data in some other way. But cloning Bytes should be cheap, it doesn't copy bytes but works with references

@VorobyevIlya VorobyevIlya merged commit 8cbbe97 into consensus/feat/starfish-consensus Jun 4, 2025
31 of 33 checks passed
@VorobyevIlya VorobyevIlya deleted the consensus/feat/starfish/send-full-block branch June 4, 2025 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ci Issues related to our CI pipeline consensus Issues related to the Core Consensus team core-protocol
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Send and receive produced full block with data via streaming
4 participants