Skip to content

Commit 38c7a58

Browse files
authored
chore(compression): include registry root in compressed block header (#2909)
## Linked Issues/PRs <!-- List of related issues/PRs --> part of #2232 closes #2568 ## Description <!-- List of detailed changes --> enhances the compression and decompression processes to handle a new `registry_root` field. ### Feature flag `fault-proving` support: * [`.github/workflows/ci.yml`](diffhunk://#diff-b803fcb7f17ed9235f1e5cb1fcd2f5d3b2838429d4368ae4c57ce4436577f03fR152-R153): Added a new `nextest` command to run integration tests with the `fault-proving` feature enabled. ### Compression and decompression updates: * [`crates/compression/src/compress.rs`](diffhunk://#diff-6d3f24703843ef40147c63bb3cd0f1fa8d6277ce298cc704d21514bdd480d552R44-R69): Introduced conditional modules and traits for `CompressDb` based on the `fault-proving` feature, and included `registry_root` in the compression process. [[1]](diffhunk://#diff-6d3f24703843ef40147c63bb3cd0f1fa8d6277ce298cc704d21514bdd480d552R44-R69) [[2]](diffhunk://#diff-6d3f24703843ef40147c63bb3cd0f1fa8d6277ce298cc704d21514bdd480d552R96-R106) * [`crates/compression/src/decompress.rs`](diffhunk://#diff-d0b271dacdbc77c5808aab48fee0fa85f338d593e1adc25e8bd0205c370dd824R49-R71): Added conditional modules and traits for `DecompressDb` and included `registry_root` verification in the decompression process. [[1]](diffhunk://#diff-d0b271dacdbc77c5808aab48fee0fa85f338d593e1adc25e8bd0205c370dd824R49-R71) [[2]](diffhunk://#diff-d0b271dacdbc77c5808aab48fee0fa85f338d593e1adc25e8bd0205c370dd824R115-R131) ### Registry root handling: * [`crates/compression/src/compressed_block_payload/v1.rs`](diffhunk://#diff-d8d7fa8cb497931632674d904112a5bbea802757e71df7d92e06474a71463307R22-R24): Added `RegistryRoot` type and included it in `CompressedBlockHeader` and `CompressedBlockPayloadV1`. [[1]](diffhunk://#diff-d8d7fa8cb497931632674d904112a5bbea802757e71df7d92e06474a71463307R22-R24) [[2]](diffhunk://#diff-d8d7fa8cb497931632674d904112a5bbea802757e71df7d92e06474a71463307L32-R42) [[3]](diffhunk://#diff-d8d7fa8cb497931632674d904112a5bbea802757e71df7d92e06474a71463307R64) [[4]](diffhunk://#diff-d8d7fa8cb497931632674d904112a5bbea802757e71df7d92e06474a71463307R121-R124) * [`crates/compression/src/lib.rs`](diffhunk://#diff-be21606b619b01dffba7556a2716b7083b03ab1525dd249f6a517e92d16d27baR63-R64): Updated `VersionedCompressedBlock` to handle `registry_root`. [[1]](diffhunk://#diff-be21606b619b01dffba7556a2716b7083b03ab1525dd249f6a517e92d16d27baR63-R64) [[2]](diffhunk://#diff-be21606b619b01dffba7556a2716b7083b03ab1525dd249f6a517e92d16d27baR77) ### Error handling and trait implementations: * [`crates/services/compression/src/errors.rs`](diffhunk://#diff-4e1e8a438c26f0ee9cde7ff8e033cb1ab58ffd3f5fad9dd5f39a74269a4a971cR32-R34): Added a new error variant `FailedToComputeRegistryRoot`. * [`crates/services/compression/src/temporal_registry.rs`](diffhunk://#diff-390e459c3eb588077c8f7a95ae572fcf01a144a449ce1fbccf2d3dc61b489546R359-R517): Implemented `ComputeRegistryRoot` trait and related methods for computing and verifying `registry_root`. ### Configuration updates: * [`crates/services/compression/Cargo.toml`](diffhunk://#diff-3b348e1ded89f349afd45656ad5c57ebbab5e690f2bf64e059dd5d7c32de228dR45-R50): Added `fault-proving` feature dependencies. * [`tests/Cargo.toml`](diffhunk://#diff-9abb8310fe65807f370f136db9528106606118c7e98654141b0bbd87b07639f7R95-R103): Added `fault-proving` feature dependencies for testing. ## Checklist - [x] Breaking changes are clearly marked as such in the PR description and changelog - [x] New behavior is reflected in tests - [x] [The specification](https://github.com/FuelLabs/fuel-specs/) matches the implemented behavior (link update PR if changes are needed) ### Before requesting review - [x] I have reviewed the code myself - [x] I have created follow-up issues caused by this PR and linked them here ### After merging, notify other teams [Add or remove entries as needed] - [ ] [Rust SDK](https://github.com/FuelLabs/fuels-rs/) - [ ] [Sway compiler](https://github.com/FuelLabs/sway/) - [ ] [Platform documentation](https://github.com/FuelLabs/devrel-requests/issues/new?assignees=&labels=new+request&projects=&template=NEW-REQUEST.yml&title=%5BRequest%5D%3A+) (for out-of-organization contributors, the person merging the PR will do this) - [ ] Someone else?
1 parent 6d7524d commit 38c7a58

File tree

12 files changed

+276
-16
lines changed

12 files changed

+276
-16
lines changed

.changes/breaking/2909.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Compressed block headers now include a merkle root of the temporal registry after compression was performed.

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ jobs:
149149
args: run -p fuel-core-client --no-default-features
150150
- command: nextest
151151
args: run -p fuel-core-chain-config --no-default-features
152+
- command: nextest
153+
args: run --workspace --features fault-proving --test integration_tests
152154
# Don't split this command; this is a workaround.
153155
# We need to run `cargo check` first to fetch the locked dependencies
154156
# for `fuel-core 0.26.0`(because of the bug with `--offline`

crates/compression/src/compress.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,32 @@ use std::collections::{
4141
HashSet,
4242
};
4343

44-
pub trait CompressDb: TemporalRegistryAll + EvictorDbAll + UtxoIdToPointer {}
45-
impl<T> CompressDb for T where T: TemporalRegistryAll + EvictorDbAll + UtxoIdToPointer {}
44+
#[cfg(not(feature = "fault-proving"))]
45+
pub mod not_fault_proving {
46+
use super::*;
47+
pub trait CompressDb: TemporalRegistryAll + EvictorDbAll + UtxoIdToPointer {}
48+
impl<T> CompressDb for T where T: TemporalRegistryAll + EvictorDbAll + UtxoIdToPointer {}
49+
}
50+
51+
#[cfg(feature = "fault-proving")]
52+
pub mod fault_proving {
53+
use super::*;
54+
use crate::ports::GetRegistryRoot;
55+
pub trait CompressDb:
56+
TemporalRegistryAll + EvictorDbAll + UtxoIdToPointer + GetRegistryRoot
57+
{
58+
}
59+
impl<T> CompressDb for T where
60+
T: TemporalRegistryAll + EvictorDbAll + UtxoIdToPointer + GetRegistryRoot
61+
{
62+
}
63+
}
64+
65+
#[cfg(feature = "fault-proving")]
66+
use fault_proving::CompressDb;
67+
68+
#[cfg(not(feature = "fault-proving"))]
69+
use not_fault_proving::CompressDb;
4670

4771
/// This must be called for all new blocks in sequence, otherwise the result will be garbage, since
4872
/// the registry is valid for only the current block height. On any other height you could be
@@ -69,10 +93,17 @@ where
6993
let transactions = target.compress_with(&mut ctx).await?;
7094
let registrations: RegistrationsPerTable = ctx.finalize()?;
7195

96+
#[cfg(feature = "fault-proving")]
97+
let registry_root = db
98+
.registry_root()
99+
.map_err(|e| anyhow::anyhow!("Failed to get registry root: {}", e))?;
100+
72101
Ok(VersionedCompressedBlock::new(
73102
block.header(),
74103
registrations,
75104
transactions,
105+
#[cfg(feature = "fault-proving")]
106+
registry_root,
76107
))
77108
}
78109

crates/compression/src/compressed_block_payload/v1.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ use fuel_core_types::{
1919
fuel_types::BlockHeight,
2020
};
2121

22+
/// The root of the registry.
23+
pub type RegistryRoot = fuel_core_types::fuel_tx::Bytes32;
24+
2225
/// A partially complete fuel block header that does not
2326
/// have any generated fields because it has not been executed yet.
2427
#[derive(
@@ -29,12 +32,14 @@ pub struct CompressedBlockHeader {
2932
pub application: ApplicationHeader<Empty>,
3033
/// The consensus header.
3134
pub consensus: ConsensusHeader<Empty>,
32-
// The block id.
35+
/// The block id.
3336
pub block_id: BlockId,
37+
// The registry root
38+
pub registry_root: RegistryRoot,
3439
}
3540

36-
impl From<&BlockHeader> for CompressedBlockHeader {
37-
fn from(header: &BlockHeader) -> Self {
41+
impl CompressedBlockHeader {
42+
fn new(header: &BlockHeader, registry_root: RegistryRoot) -> Self {
3843
let ConsensusHeader {
3944
prev_root,
4045
height,
@@ -56,6 +61,7 @@ impl From<&BlockHeader> for CompressedBlockHeader {
5661
generated: Empty {},
5762
},
5863
block_id: header.id(),
64+
registry_root,
5965
}
6066
}
6167
}
@@ -112,9 +118,10 @@ impl CompressedBlockPayloadV1 {
112118
header: &BlockHeader,
113119
registrations: RegistrationsPerTable,
114120
transactions: Vec<CompressedTransaction>,
121+
registry_root: RegistryRoot,
115122
) -> Self {
116123
Self {
117-
header: CompressedBlockHeader::from(header),
124+
header: CompressedBlockHeader::new(header, registry_root),
118125
registrations,
119126
transactions,
120127
}

crates/compression/src/decompress.rs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,29 @@ use fuel_core_types::{
4646
tai64::Tai64,
4747
};
4848

49-
pub trait DecompressDb: TemporalRegistryAll + HistoryLookup {}
50-
impl<T> DecompressDb for T where T: TemporalRegistryAll + HistoryLookup {}
49+
#[cfg(not(feature = "fault-proving"))]
50+
pub mod not_fault_proving {
51+
use super::*;
52+
pub trait DecompressDb: TemporalRegistryAll + HistoryLookup {}
53+
impl<T> DecompressDb for T where T: TemporalRegistryAll + HistoryLookup {}
54+
}
55+
56+
#[cfg(feature = "fault-proving")]
57+
pub mod fault_proving {
58+
use super::*;
59+
use crate::ports::GetRegistryRoot;
60+
pub trait DecompressDb:
61+
TemporalRegistryAll + HistoryLookup + GetRegistryRoot
62+
{
63+
}
64+
impl<T> DecompressDb for T where T: TemporalRegistryAll + HistoryLookup + GetRegistryRoot {}
65+
}
66+
67+
#[cfg(feature = "fault-proving")]
68+
use fault_proving::DecompressDb;
69+
70+
#[cfg(not(feature = "fault-proving"))]
71+
use not_fault_proving::DecompressDb;
5172

5273
/// This must be called for all decompressed blocks in sequence, otherwise the result will be garbage.
5374
pub async fn decompress<D>(
@@ -58,8 +79,6 @@ pub async fn decompress<D>(
5879
where
5980
D: DecompressDb,
6081
{
61-
// TODO: merkle root verification: https://github.com/FuelLabs/fuel-core/issues/2232
62-
6382
block
6483
.registrations()
6584
.write_to_registry(&mut db, block.consensus_header().time)?;
@@ -93,6 +112,23 @@ where
93112
anyhow::bail!("Last transaction is not a mint");
94113
}
95114

115+
#[cfg(feature = "fault-proving")]
116+
{
117+
match block {
118+
VersionedCompressedBlock::V0(_) => {}
119+
VersionedCompressedBlock::V1(ref block) => {
120+
let registry_root_after_decompression = ctx
121+
.db
122+
.registry_root()
123+
.map_err(|e| anyhow::anyhow!("Failed to get registry root: {}", e))?;
124+
let registry_root_after_compression = block.header.registry_root;
125+
if registry_root_after_decompression != registry_root_after_compression {
126+
anyhow::bail!("Registry root mismatch");
127+
}
128+
}
129+
}
130+
}
131+
96132
Ok(PartialFuelBlock {
97133
header: block.partial_block_header(),
98134
transactions,

crates/compression/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ impl VersionedCompressedBlock {
6060
header: &BlockHeader,
6161
registrations: RegistrationsPerTable,
6262
transactions: Vec<CompressedTransaction>,
63+
#[cfg(feature = "fault-proving")]
64+
registry_root: crate::compressed_block_payload::v1::RegistryRoot,
6365
) -> Self {
6466
#[cfg(not(feature = "fault-proving"))]
6567
return Self::V0(CompressedBlockPayloadV0::new(
@@ -72,6 +74,7 @@ impl VersionedCompressedBlock {
7274
header,
7375
registrations,
7476
transactions,
77+
registry_root,
7578
))
7679
}
7780
}
@@ -250,6 +253,8 @@ mod tests {
250253
use fuel_core_types::blockchain::primitives::BlockId;
251254
use std::str::FromStr;
252255

256+
use crate::compressed_block_payload::v1::RegistryRoot;
257+
253258
proptest!(|(strategy in postcard_roundtrip_strategy())| {
254259
let PostcardRoundtripStrategy {
255260
da_height,
@@ -274,6 +279,7 @@ mod tests {
274279
generated: Empty,
275280
},
276281
block_id: BlockId::from_str("0xecea85c17070bc2e65f911310dbd01198f4436052ebba96cded9ddf30c58dd1a").unwrap(),
282+
registry_root: RegistryRoot::from_str("0xecea85c17070bc2e65f911310dbd01198f4436052ebba96cded9ddf30c58dd1b").unwrap(),
277283
};
278284

279285

@@ -302,6 +308,7 @@ mod tests {
302308

303309
if let VersionedCompressedBlock::V1(block) = decompressed {
304310
assert_eq!(block.header.block_id, header.block_id);
311+
assert_eq!(block.header.registry_root, header.registry_root);
305312
} else {
306313
panic!("Expected V1 block, got {:?}", decompressed);
307314
}

crates/compression/src/ports.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,29 @@ where
119119
<D as EvictorDb<T>>::set_latest_assigned_key(self, key)
120120
}
121121
}
122+
123+
#[cfg(feature = "fault-proving")]
124+
pub mod fault_proving {
125+
pub trait GetRegistryRoot {
126+
type Error: core::fmt::Display;
127+
fn registry_root(
128+
&self,
129+
) -> Result<crate::compressed_block_payload::v1::RegistryRoot, Self::Error>;
130+
}
131+
132+
impl<D> GetRegistryRoot for &mut D
133+
where
134+
D: GetRegistryRoot,
135+
{
136+
type Error = D::Error;
137+
fn registry_root(
138+
&self,
139+
) -> Result<crate::compressed_block_payload::v1::RegistryRoot, Self::Error>
140+
{
141+
D::registry_root(self)
142+
}
143+
}
144+
}
145+
146+
#[cfg(feature = "fault-proving")]
147+
pub use fault_proving::*;

crates/fuel-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,5 @@ fault-proving = [
130130
"fuel-core-sync?/fault-proving",
131131
"fuel-core-importer/fault-proving",
132132
"fuel-core-poa/fault-proving",
133+
"fuel-core-compression-service/fault-proving",
133134
]

crates/services/compression/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,9 @@ test-helpers = [
4242
"dep:rand",
4343
"dep:fuel-core-chain-config",
4444
]
45+
fault-proving = [
46+
"fuel-core-compression/fault-proving",
47+
"fuel-core-chain-config?/fault-proving",
48+
"fuel-core-types/fault-proving",
49+
"fuel-core-storage/fault-proving",
50+
]

crates/services/compression/src/errors.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub enum CompressionError {
2929
/// Failed to compress block
3030
#[error("failed to compress block: `{0}`")]
3131
FailedToCompressBlock(anyhow::Error),
32+
/// Failed to compute registry root
33+
#[error("failed to compute registry root: `{0}`")]
34+
FailedToComputeRegistryRoot(StorageError),
3235
/// Failed to handle new block
3336
#[error("failed to handle new block: `{0}`")]
3437
FailedToHandleNewBlock(String),

0 commit comments

Comments
 (0)