Skip to content

Commit 98db455

Browse files
authored
feat(consensus): Update block creation for Starfish (#6702)
# Description of change In this PR, we add two more steps in the creation of the block - We compute the commitment of transaction data to be included in block header (serialization+hash) - We take pending acknowledgments for received transaction data from other peers In addition, we wrap transaction data into VerifiedTransactionData to be used for storing and broadcasting ## Links to any relevant issues Closes #6430 ## Type of change Choose a type of change, and delete any options that are not relevant. - Bug fix (a non-breaking change which fixes an issue) ## How the change has been tested CI ### Infrastructure QA (only required for crates that are maintained by @iotaledger/infrastructure) - [ ] Synchronization of the indexer from genesis for a network including migration objects. - [ ] Restart of indexer synchronization locally without resetting the database. - [ ] Restart of indexer synchronization on a production-like database. - [ ] Deployment of services using Docker. - [ ] Verification of API backward compatibility. ## 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 - [x] Protocol: Updated the block creation function to include acknowledgments and transaction commitment - [ ] Nodes (Validators and Full nodes): - [ ] Indexer: - [ ] JSON-RPC: - [ ] GraphQL: - [ ] CLI: - [ ] Rust SDK: - [ ] REST API:
1 parent b5f016f commit 98db455

File tree

4 files changed

+230
-50
lines changed

4 files changed

+230
-50
lines changed

crates/starfish/config/src/crypto.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ impl AuthorityKeyPair {
170170
}
171171

172172
/// Defines algorithm and format of block and commit digests.
173+
// TODO: change Blake2b256 to Blake3 when starting optimizations
173174
pub type DefaultHashFunction = Blake2b256;
174175
pub const DIGEST_LENGTH: usize = DefaultHashFunction::OUTPUT_SIZE;
175176
pub const INTENT_MESSAGE_LENGTH: usize = INTENT_PREFIX_LENGTH + DIGEST_LENGTH;

crates/starfish/core/src/block_header.rs

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ impl Transaction {
5656
pub fn into_data(self) -> Bytes {
5757
self.data
5858
}
59+
60+
/// Serialises a vector of transactions using the bcs serializer
61+
pub(crate) fn serialize(transactions: &[Transaction]) -> Result<Bytes, bcs::Error> {
62+
let bytes = bcs::to_bytes(transactions)?;
63+
Ok(bytes.into())
64+
}
5965
}
6066

6167
/// A block header includes references to previous round blocks and a commitment
@@ -82,6 +88,7 @@ pub trait BlockHeaderAPI {
8288
// TODO: we should remove this method from the API of the block header and use
8389
// another type of a full block in the consensus output
8490
fn transactions(&self) -> &[Transaction];
91+
fn transactions_commitment(&self) -> TransactionsCommitment;
8592
}
8693

8794
#[derive(Clone, Default, Deserialize, Serialize)]
@@ -99,7 +106,7 @@ pub struct BlockHeaderV1 {
99106
// TODO: we should compress it together with ancestors to
100107
// avoid duplications since in most cases these sets have a big overlap
101108
acknowledgments: Vec<BlockRef>,
102-
transactions_commitment: TransactionDigest,
109+
transactions_commitment: TransactionsCommitment,
103110
commit_votes: Vec<CommitVote>,
104111
}
105112

@@ -110,18 +117,18 @@ impl BlockHeaderV1 {
110117
author: AuthorityIndex,
111118
timestamp_ms: BlockTimestampMs,
112119
ancestors: Vec<BlockRef>,
120+
acknowledgments: Vec<BlockRef>,
113121
commit_votes: Vec<CommitVote>,
122+
transactions_commitment: TransactionsCommitment,
114123
) -> BlockHeaderV1 {
115124
Self {
116125
epoch,
117126
round,
118127
author,
119128
timestamp_ms,
120-
ancestors: ancestors.clone(),
121-
// TODO: we should track availability of transaction data separately and take this
122-
// information from the pending state of DagState. We clone ancestors for now
123-
acknowledgments: ancestors,
124-
transactions_commitment: TransactionDigest::default(),
129+
ancestors,
130+
acknowledgments,
131+
transactions_commitment,
125132
commit_votes,
126133
}
127134
}
@@ -135,7 +142,7 @@ impl BlockHeaderV1 {
135142
ancestors: vec![],
136143
acknowledgments: vec![],
137144
commit_votes: vec![],
138-
transactions_commitment: TransactionDigest::default(),
145+
transactions_commitment: TransactionsCommitment::default(),
139146
}
140147
}
141148
}
@@ -172,6 +179,10 @@ impl BlockHeaderAPI for BlockHeaderV1 {
172179
&self.commit_votes
173180
}
174181

182+
fn transactions_commitment(&self) -> TransactionsCommitment {
183+
self.transactions_commitment
184+
}
185+
175186
fn transactions(&self) -> &[Transaction] {
176187
unimplemented!();
177188
}
@@ -289,27 +300,34 @@ impl AsRef<[u8]> for BlockHeaderDigest {
289300
// is used for BlockDigest computations of BlockHeader does not include
290301
// explicitly the transaction data.
291302
#[derive(Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord)]
292-
pub struct TransactionDigest([u8; starfish_config::DIGEST_LENGTH]);
303+
pub struct TransactionsCommitment([u8; starfish_config::DIGEST_LENGTH]);
293304

294-
impl TransactionDigest {
305+
impl TransactionsCommitment {
295306
/// Lexicographic min & max digest.
296307
pub const MIN: Self = Self([u8::MIN; starfish_config::DIGEST_LENGTH]);
297308
pub const MAX: Self = Self([u8::MAX; starfish_config::DIGEST_LENGTH]);
309+
pub(crate) fn compute_transactions_commitment(
310+
serialized_transactions: &Bytes,
311+
) -> ConsensusResult<TransactionsCommitment> {
312+
let mut hasher = DefaultHashFunction::new();
313+
hasher.update(serialized_transactions);
314+
Ok(TransactionsCommitment(hasher.finalize().into()))
315+
}
298316
}
299317

300-
impl Hash for TransactionDigest {
318+
impl Hash for TransactionsCommitment {
301319
fn hash<H: Hasher>(&self, state: &mut H) {
302320
state.write(&self.0[..8]);
303321
}
304322
}
305323

306-
impl From<TransactionDigest> for Digest<{ DIGEST_LENGTH }> {
307-
fn from(hd: TransactionDigest) -> Self {
324+
impl From<TransactionsCommitment> for Digest<{ DIGEST_LENGTH }> {
325+
fn from(hd: TransactionsCommitment) -> Self {
308326
Digest::new(hd.0)
309327
}
310328
}
311329

312-
impl fmt::Display for TransactionDigest {
330+
impl fmt::Display for TransactionsCommitment {
313331
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
314332
write!(
315333
f,
@@ -321,7 +339,7 @@ impl fmt::Display for TransactionDigest {
321339
}
322340
}
323341

324-
impl fmt::Debug for TransactionDigest {
342+
impl fmt::Debug for TransactionsCommitment {
325343
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
326344
write!(
327345
f,
@@ -331,7 +349,7 @@ impl fmt::Debug for TransactionDigest {
331349
}
332350
}
333351

334-
impl AsRef<[u8]> for TransactionDigest {
352+
impl AsRef<[u8]> for TransactionsCommitment {
335353
fn as_ref(&self) -> &[u8] {
336354
&self.0
337355
}
@@ -556,6 +574,11 @@ impl VerifiedBlockHeader {
556574
self.digest
557575
}
558576

577+
#[cfg_attr(not(test), expect(unused))]
578+
pub(crate) fn transactions_commitment(&self) -> TransactionsCommitment {
579+
self.signed_block_header.inner.transactions_commitment()
580+
}
581+
559582
/// Returns the serialization of the signed block header.
560583
pub(crate) fn serialized(&self) -> &Bytes {
561584
&self.serialized
@@ -606,6 +629,34 @@ impl fmt::Debug for VerifiedBlockHeader {
606629
}
607630
}
608631

632+
/// VerifiedTransactions are transactions that correspond to an existing block
633+
pub struct VerifiedTransactions {
634+
#[expect(dead_code)]
635+
transactions: Vec<Transaction>,
636+
637+
/// The block reference of the block that contains the transactions.
638+
#[expect(dead_code)]
639+
block_ref: BlockRef,
640+
641+
/// The serialized bytes of the transactions.
642+
#[expect(dead_code)]
643+
serialized: Bytes,
644+
}
645+
646+
impl VerifiedTransactions {
647+
pub(crate) fn new(
648+
transactions: Vec<Transaction>,
649+
block_ref: BlockRef,
650+
serialized: Bytes,
651+
) -> Self {
652+
Self {
653+
transactions,
654+
block_ref,
655+
serialized,
656+
}
657+
}
658+
}
659+
609660
/// Generates the genesis blocks for the current Committee.
610661
/// The blocks are returned in authority index order.
611662
pub(crate) fn genesis_block_headers(context: Arc<Context>) -> Vec<VerifiedBlockHeader> {

0 commit comments

Comments
 (0)