Skip to content

Commit b6abc09

Browse files
vicsnljedrz
authored andcommitted
Store a bitset of transmissions in compact subdag.
New types: - CompactCertificate - CompactHeader - Subdag enum can hold either - NarwhalCertificate trait provides an interface - We use BitSet, which used to be part of standard library Co-authored-by ljedrz <ljedrz@users.noreply.github.com>
1 parent 1ddd0b2 commit b6abc09

File tree

53 files changed

+3559
-298
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+3559
-298
lines changed

.circleci/config.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,20 @@ jobs:
484484
- run_test:
485485
workspace_member: snarkvm-ledger-narwhal-batch-header
486486

487+
ledger-narwhal-compact-certificate:
488+
executor: rust-docker
489+
resource_class: << pipeline.parameters.twoxlarge >>
490+
steps:
491+
- run_test:
492+
workspace_member: snarkvm-ledger-narwhal-compact-certificate
493+
494+
ledger-narwhal-compact-header:
495+
executor: rust-docker
496+
resource_class: << pipeline.parameters.twoxlarge >>
497+
steps:
498+
- run_test:
499+
workspace_member: snarkvm-ledger-narwhal-compact-header
500+
487501
ledger-narwhal-data:
488502
executor: rust-docker
489503
resource_class: << pipeline.parameters.small >>
@@ -891,6 +905,8 @@ workflows:
891905
- ledger-narwhal
892906
- ledger-narwhal-batch-certificate
893907
- ledger-narwhal-batch-header
908+
- ledger-narwhal-compact-certificate
909+
- ledger-narwhal-compact-header
894910
- ledger-narwhal-data
895911
- ledger-narwhal-subdag
896912
- ledger-narwhal-transmission

Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ members = [
6868
"ledger/narwhal",
6969
"ledger/narwhal/batch-certificate",
7070
"ledger/narwhal/batch-header",
71+
"ledger/narwhal/compact-certificate",
72+
"ledger/narwhal/compact-header",
7173
"ledger/narwhal/data",
7274
"ledger/narwhal/subdag",
7375
"ledger/narwhal/transmission",
@@ -358,6 +360,18 @@ version = "=4.0.0"
358360
path = "ledger/narwhal/batch-certificate"
359361
version = "=4.0.0"
360362

363+
[workspace.dependencies.snarkvm-ledger-narwhal-compact-certificate]
364+
path = "ledger/narwhal/compact-certificate"
365+
version = "=4.0.0"
366+
367+
[workspace.dependencies.snarkvm-ledger-narwhal-compact-header]
368+
path = "ledger/narwhal/compact-header"
369+
version = "=4.0.0"
370+
371+
[workspace.dependencies.snarkvm-ledger-narwhal-traits]
372+
path = "ledger/narwhal/traits"
373+
version = "=4.0.0"
374+
361375
[workspace.dependencies.snarkvm-ledger-narwhal-subdag]
362376
path = "ledger/narwhal/subdag"
363377
version = "=4.0.0"

ledger/block/src/bytes.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,29 @@ impl<N: Network> FromBytes for Block<N> {
5454
aborted_solution_ids.push(FromBytes::read_le(&mut reader)?);
5555
}
5656

57+
// Read the number of prior solution IDs.
58+
let num_prior_solutions = u16::read_le(&mut reader)?;
59+
// Read the aborted transaction IDs.
60+
let mut prior_solution_ids = Vec::with_capacity(num_prior_solutions as usize);
61+
for _ in 0..num_prior_solutions {
62+
prior_solution_ids.push(FromBytes::read_le(&mut reader)?);
63+
}
64+
5765
// Read the transactions.
5866
let transactions = FromBytes::read_le(&mut reader)?;
5967

68+
// Read the number of prior transaction IDs.
69+
let num_prior_transactions = u32::read_le(&mut reader)?;
70+
// Ensure the number of prior transaction IDs is within bounds (this is an early safety check).
71+
if num_prior_transactions as usize > Transactions::<N>::MAX_TRANSACTIONS {
72+
return Err(error("Invalid number of aborted transaction IDs in the block"));
73+
}
74+
// Read the aborted transaction IDs.
75+
let mut prior_transaction_ids = Vec::with_capacity(num_prior_transactions as usize);
76+
for _ in 0..num_prior_transactions {
77+
prior_transaction_ids.push(FromBytes::read_le(&mut reader)?);
78+
}
79+
6080
// Read the number of aborted transaction IDs.
6181
let num_aborted_transactions = u32::read_le(&mut reader)?;
6282
// Ensure the number of aborted transaction IDs is within bounds (this is an early safety check).
@@ -76,8 +96,10 @@ impl<N: Network> FromBytes for Block<N> {
7696
authority,
7797
ratifications,
7898
solutions,
99+
prior_solution_ids,
79100
aborted_solution_ids,
80101
transactions,
102+
prior_transaction_ids,
81103
aborted_transaction_ids,
82104
)
83105
.map_err(error)?;
@@ -113,13 +135,25 @@ impl<N: Network> ToBytes for Block<N> {
113135
// Write the solutions.
114136
self.solutions.write_le(&mut writer)?;
115137

138+
// Write the prior solution ids.
139+
(u16::try_from(self.prior_solution_ids.len()).map_err(error))?.write_le(&mut writer)?;
140+
self.prior_solution_ids.write_le(&mut writer)?;
141+
116142
// Write the aborted solution IDs.
117143
(u32::try_from(self.aborted_solution_ids.len()).map_err(error))?.write_le(&mut writer)?;
118144
self.aborted_solution_ids.write_le(&mut writer)?;
119145

146+
// Write the prior solution ids.
147+
(u16::try_from(self.prior_solution_ids.len()).map_err(error))?.write_le(&mut writer)?;
148+
self.prior_solution_ids.write_le(&mut writer)?;
149+
120150
// Write the transactions.
121151
self.transactions.write_le(&mut writer)?;
122152

153+
// Write the prior transaction ids.
154+
(u32::try_from(self.prior_transaction_ids.len()).map_err(error))?.write_le(&mut writer)?;
155+
self.prior_transaction_ids.write_le(&mut writer)?;
156+
123157
// Write the aborted transaction IDs.
124158
(u32::try_from(self.aborted_transaction_ids.len()).map_err(error))?.write_le(&mut writer)?;
125159
self.aborted_transaction_ids.write_le(&mut writer)

ledger/block/src/lib.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,14 @@ pub struct Block<N: Network> {
7777
ratifications: Ratifications<N>,
7878
/// The solutions in the block.
7979
solutions: Solutions<N>,
80+
/// The prior solution ids in the block.
81+
prior_solution_ids: Vec<SolutionID<N>>,
8082
/// The aborted solution IDs in this block.
8183
aborted_solution_ids: Vec<SolutionID<N>>,
8284
/// The transactions in this block.
8385
transactions: Transactions<N>,
86+
/// The prior transaction ids in the block.
87+
prior_transaction_ids: Vec<N::TransactionID>,
8488
/// The aborted transaction IDs in this block.
8589
aborted_transaction_ids: Vec<N::TransactionID>,
8690
}
@@ -94,8 +98,10 @@ impl<N: Network> Block<N> {
9498
header: Header<N>,
9599
ratifications: Ratifications<N>,
96100
solutions: Solutions<N>,
101+
prior_solution_ids: Vec<SolutionID<N>>,
97102
aborted_solution_ids: Vec<SolutionID<N>>,
98103
transactions: Transactions<N>,
104+
prior_transaction_ids: Vec<N::TransactionID>,
99105
aborted_transaction_ids: Vec<N::TransactionID>,
100106
rng: &mut R,
101107
) -> Result<Self> {
@@ -110,8 +116,10 @@ impl<N: Network> Block<N> {
110116
authority,
111117
ratifications,
112118
solutions,
119+
prior_solution_ids,
113120
aborted_solution_ids,
114121
transactions,
122+
prior_transaction_ids,
115123
aborted_transaction_ids,
116124
)
117125
}
@@ -124,8 +132,10 @@ impl<N: Network> Block<N> {
124132
subdag: Subdag<N>,
125133
ratifications: Ratifications<N>,
126134
solutions: Solutions<N>,
135+
prior_solution_ids: Vec<SolutionID<N>>,
127136
aborted_solution_ids: Vec<SolutionID<N>>,
128137
transactions: Transactions<N>,
138+
prior_transaction_ids: Vec<N::TransactionID>,
129139
aborted_transaction_ids: Vec<N::TransactionID>,
130140
) -> Result<Self> {
131141
// Construct the beacon authority.
@@ -137,8 +147,10 @@ impl<N: Network> Block<N> {
137147
authority,
138148
ratifications,
139149
solutions,
150+
prior_solution_ids,
140151
aborted_solution_ids,
141152
transactions,
153+
prior_transaction_ids,
142154
aborted_transaction_ids,
143155
)
144156
}
@@ -151,8 +163,10 @@ impl<N: Network> Block<N> {
151163
authority: Authority<N>,
152164
ratifications: Ratifications<N>,
153165
solutions: Solutions<N>,
166+
prior_solution_ids: Vec<SolutionID<N>>,
154167
aborted_solution_ids: Vec<SolutionID<N>>,
155168
transactions: Transactions<N>,
169+
prior_transaction_ids: Vec<N::TransactionID>,
156170
aborted_transaction_ids: Vec<N::TransactionID>,
157171
) -> Result<Self> {
158172
// Ensure the number of aborted solutions IDs is within the allowed range.
@@ -202,8 +216,10 @@ impl<N: Network> Block<N> {
202216
Self::check_subdag_transmissions(
203217
subdag,
204218
&solutions,
219+
&prior_solution_ids,
205220
&aborted_solution_ids,
206221
&transactions,
222+
&prior_transaction_ids,
207223
&aborted_transaction_ids,
208224
)?;
209225
}
@@ -231,8 +247,10 @@ impl<N: Network> Block<N> {
231247
authority,
232248
ratifications,
233249
solutions,
250+
prior_solution_ids,
234251
aborted_solution_ids,
235252
transactions,
253+
prior_transaction_ids,
236254
aborted_transaction_ids,
237255
)
238256
}
@@ -247,8 +265,10 @@ impl<N: Network> Block<N> {
247265
authority: Authority<N>,
248266
ratifications: Ratifications<N>,
249267
solutions: Solutions<N>,
268+
prior_solution_ids: Vec<SolutionID<N>>,
250269
aborted_solution_ids: Vec<SolutionID<N>>,
251270
transactions: Transactions<N>,
271+
prior_transaction_ids: Vec<N::TransactionID>,
252272
aborted_transaction_ids: Vec<N::TransactionID>,
253273
) -> Result<Self> {
254274
// Return the block.
@@ -259,11 +279,81 @@ impl<N: Network> Block<N> {
259279
authority,
260280
ratifications,
261281
solutions,
282+
prior_solution_ids,
262283
aborted_solution_ids,
263284
transactions,
285+
prior_transaction_ids,
264286
aborted_transaction_ids,
265287
})
266288
}
289+
290+
/// Consume the Block and return a Subdag with full batch certificates.
291+
pub fn into_full_subdag(self) -> Result<Subdag<N>> {
292+
let Block {
293+
ratifications,
294+
solutions,
295+
prior_solution_ids,
296+
transactions,
297+
prior_transaction_ids,
298+
aborted_transaction_ids,
299+
authority,
300+
..
301+
} = self;
302+
303+
// Check if Authority is a Quorum
304+
let Authority::Quorum(subdag) = authority else {
305+
bail!("Can only convert block with Quorum Authority to full subdag");
306+
};
307+
308+
// Collect ratification IDs.
309+
let ratification_ids = ratifications.ratification_ids().copied().collect_vec();
310+
// Collect transaction IDs.
311+
let transaction_ids = transactions.transaction_ids().copied().collect_vec();
312+
313+
// Convert Quorum authority to subdag with full batch certificates.
314+
subdag.into_full(
315+
ratification_ids,
316+
solutions.as_puzzle_solutions().cloned(),
317+
prior_solution_ids,
318+
transaction_ids,
319+
prior_transaction_ids,
320+
aborted_transaction_ids,
321+
)
322+
}
323+
324+
/// Borrow the Block and return a Subdag with full batch certificates.
325+
pub fn to_full_subdag(&self) -> Result<Subdag<N>> {
326+
let Block {
327+
ratifications,
328+
solutions,
329+
prior_solution_ids,
330+
transactions,
331+
prior_transaction_ids,
332+
aborted_transaction_ids,
333+
authority,
334+
..
335+
} = self;
336+
337+
// Check if Authority is a Quorum
338+
let Authority::Quorum(subdag) = authority else {
339+
bail!("Can only convert block with Quorum Authority to full subdag");
340+
};
341+
342+
// Collect ratification IDs.
343+
let ratification_ids = ratifications.ratification_ids().copied().collect_vec();
344+
// Collect transaction IDs.
345+
let transaction_ids = transactions.transaction_ids().copied().collect_vec();
346+
347+
// Convert Quorum authority to subdag with full batch certificates.
348+
subdag.clone().into_full(
349+
ratification_ids,
350+
solutions.as_puzzle_solutions().cloned(),
351+
prior_solution_ids.clone(),
352+
transaction_ids,
353+
prior_transaction_ids.clone(),
354+
aborted_transaction_ids.clone(),
355+
)
356+
}
267357
}
268358

269359
impl<N: Network> Block<N> {
@@ -297,11 +387,21 @@ impl<N: Network> Block<N> {
297387
&self.aborted_solution_ids
298388
}
299389

390+
/// Returns the prior solution ids in the block.
391+
pub const fn prior_solution_ids(&self) -> &Vec<SolutionID<N>> {
392+
&self.prior_solution_ids
393+
}
394+
300395
/// Returns the transactions in this block.
301396
pub const fn transactions(&self) -> &Transactions<N> {
302397
&self.transactions
303398
}
304399

400+
/// Returns the prior transactions ids in the block.
401+
pub const fn prior_transaction_ids(&self) -> &Vec<N::TransactionID> {
402+
&self.prior_transaction_ids
403+
}
404+
305405
/// Returns the aborted transaction IDs in this block.
306406
pub const fn aborted_transaction_ids(&self) -> &Vec<N::TransactionID> {
307407
&self.aborted_transaction_ids
@@ -709,8 +809,10 @@ pub mod test_helpers {
709809
ratifications,
710810
None.into(),
711811
vec![],
812+
vec![],
712813
transactions,
713814
vec![],
815+
vec![],
714816
rng,
715817
)
716818
.unwrap();

ledger/block/src/serialize.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ impl<N: Network> Serialize for Block<N> {
2727
block.serialize_field("authority", &self.authority)?;
2828
block.serialize_field("ratifications", &self.ratifications)?;
2929
block.serialize_field("solutions", &self.solutions)?;
30+
block.serialize_field("prior_solution_ids", &self.prior_solution_ids)?;
3031
block.serialize_field("aborted_solution_ids", &self.aborted_solution_ids)?;
3132
block.serialize_field("transactions", &self.transactions)?;
33+
block.serialize_field("prior_transaction_ids", &self.prior_transaction_ids)?;
3234
block.serialize_field("aborted_transaction_ids", &self.aborted_transaction_ids)?;
3335
block.end()
3436
}
@@ -52,8 +54,10 @@ impl<'de, N: Network> Deserialize<'de> for Block<N> {
5254
DeserializeExt::take_from_value::<D>(&mut block, "authority")?,
5355
DeserializeExt::take_from_value::<D>(&mut block, "ratifications")?,
5456
DeserializeExt::take_from_value::<D>(&mut block, "solutions")?,
57+
DeserializeExt::take_from_value::<D>(&mut block, "prior_solution_ids")?,
5558
DeserializeExt::take_from_value::<D>(&mut block, "aborted_solution_ids")?,
5659
DeserializeExt::take_from_value::<D>(&mut block, "transactions")?,
60+
DeserializeExt::take_from_value::<D>(&mut block, "prior_transaction_ids")?,
5761
DeserializeExt::take_from_value::<D>(&mut block, "aborted_transaction_ids")?,
5862
)
5963
.map_err(de::Error::custom)?;

ledger/block/src/solutions/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ impl<N: Network> Solutions<N> {
6565
None => 0,
6666
}
6767
}
68+
69+
pub fn as_puzzle_solutions(&self) -> Option<&PuzzleSolutions<N>> {
70+
self.solutions.as_ref()
71+
}
6872
}
6973

7074
impl<N: Network> Solutions<N> {

ledger/block/src/transactions/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,14 @@ impl<N: Network> Transactions<N> {
221221
self.transactions.keys()
222222
}
223223

224+
/// Returns the unconfirmed transaction IDs, for all transactions in `self`.
225+
pub fn unconfirmed_transaction_ids(&self) -> Result<Vec<N::TransactionID>> {
226+
self.transactions
227+
.values()
228+
.map(|confirmed_tx| confirmed_tx.to_unconfirmed_transaction_id())
229+
.collect::<Result<_>>()
230+
}
231+
224232
/// Returns an iterator over all transactions in `self` that are accepted deploy transactions.
225233
pub fn deployments(&self) -> impl '_ + Iterator<Item = &ConfirmedTransaction<N>> {
226234
self.iter().filter(|tx| tx.is_accepted() && tx.is_deploy())

0 commit comments

Comments
 (0)