Skip to content

Commit

Permalink
fault_proving(compression): include commitment to transaction ids wit…
Browse files Browse the repository at this point in the history
…hin compressed block header
  • Loading branch information
rymnc committed Jan 22, 2025
1 parent dfc7fd7 commit 3e090b0
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added
- [2551](https://github.com/FuelLabs/fuel-core/pull/2551): Enhanced the DA compressed block header to include block id.
- [2572](https://github.com/FuelLabs/fuel-core/pull/2572): Enhanced the DA compressed block header to include tx id commitment.

## [Version 0.41.0]

Expand Down
9 changes: 9 additions & 0 deletions crates/compression/src/compress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ use crate::{
VersionedCompressedBlock,
};
use anyhow::Context;
#[cfg(feature = "fault-proving")]
use fuel_core_types::fuel_tx::UniqueIdentifier;

use fuel_core_types::{
blockchain::block::Block,
fuel_compression::{
Expand Down Expand Up @@ -51,12 +54,16 @@ pub async fn compress<D>(
config: Config,
mut db: D,
block: &Block,
#[cfg(feature = "fault-proving")] chain_id: fuel_core_types::fuel_types::ChainId,
) -> anyhow::Result<VersionedCompressedBlock>
where
D: CompressDb,
{
let target = block.transactions_vec();

#[cfg(feature = "fault-proving")]
let tx_ids = target.iter().map(|tx| tx.id(&chain_id)).collect::<Vec<_>>();

let mut prepare_ctx = PrepareCtx {
config,
timestamp: block.header().time(),
Expand All @@ -73,6 +80,8 @@ where
block.header(),
registrations,
transactions,
#[cfg(feature = "fault-proving")]
&tx_ids,
))
}

Expand Down
10 changes: 9 additions & 1 deletion crates/compression/src/compressed_block_payload/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
};
use fuel_core_types::{
blockchain::{
block::PartialFuelBlock,
header::{
ApplicationHeader,
BlockHeader,
Expand All @@ -13,7 +14,10 @@ use fuel_core_types::{
primitives::Empty,
},
fuel_tx::CompressedTransaction,
fuel_types::BlockHeight,
fuel_types::{
BlockHeight,
ChainId,
},
};

/// Compressed block, without the preceding version byte.
Expand Down Expand Up @@ -51,6 +55,10 @@ impl VersionedBlockPayload for CompressedBlockPayloadV0 {
fn partial_block_header(&self) -> PartialBlockHeader {
self.header
}

fn validate_with(&self, _: &PartialFuelBlock, _: &ChainId) -> anyhow::Result<()> {
Ok(())
}
}

impl CompressedBlockPayloadV0 {
Expand Down
51 changes: 46 additions & 5 deletions crates/compression/src/compressed_block_payload/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
};
use fuel_core_types::{
blockchain::{
block::PartialFuelBlock,
header::{
ApplicationHeader,
BlockHeader,
Expand All @@ -15,10 +16,26 @@ use fuel_core_types::{
Empty,
},
},
fuel_tx::CompressedTransaction,
fuel_types::BlockHeight,
fuel_crypto,
fuel_tx::{
Bytes32,
CompressedTransaction,
UniqueIdentifier,
},
fuel_types::{
BlockHeight,
ChainId,
},
};

pub fn generate_tx_commitment(tx_ids: &[Bytes32]) -> Bytes32 {
let mut hasher = fuel_crypto::Hasher::default();
for tx_id in tx_ids {
hasher.input(tx_id.as_ref());
}
hasher.digest()
}

/// A partially complete fuel block header that does not
/// have any generated fields because it has not been executed yet.
#[derive(
Expand All @@ -31,10 +48,12 @@ pub struct CompressedBlockHeader {
pub consensus: ConsensusHeader<Empty>,
// The block id.
pub block_id: BlockId,
// A commitment to all transaction ids in the block
pub tx_commitment: Bytes32,
}

impl From<&BlockHeader> for CompressedBlockHeader {
fn from(header: &BlockHeader) -> Self {
impl CompressedBlockHeader {
fn new(header: &BlockHeader, tx_ids: &[Bytes32]) -> Self {
let ConsensusHeader {
prev_root,
height,
Expand All @@ -56,6 +75,7 @@ impl From<&BlockHeader> for CompressedBlockHeader {
generated: Empty {},
},
block_id: header.id(),
tx_commitment: generate_tx_commitment(tx_ids),
}
}
}
Expand Down Expand Up @@ -103,6 +123,26 @@ impl VersionedBlockPayload for CompressedBlockPayloadV1 {
fn partial_block_header(&self) -> PartialBlockHeader {
PartialBlockHeader::from(&self.header)
}

fn validate_with(
&self,
partial_block: &PartialFuelBlock,
chain_id: &ChainId,
) -> anyhow::Result<()> {
let txs = partial_block
.transactions
.iter()
.map(|tx| tx.id(chain_id))
.collect::<Vec<_>>();
let tx_commitment = generate_tx_commitment(&txs);
let expected = self.header.tx_commitment;
if tx_commitment != expected {
anyhow::bail!(
"Invalid tx commitment. got {tx_commitment}, expected {expected}"
);
}
Ok(())
}
}

impl CompressedBlockPayloadV1 {
Expand All @@ -112,9 +152,10 @@ impl CompressedBlockPayloadV1 {
header: &BlockHeader,
registrations: RegistrationsPerTable,
transactions: Vec<CompressedTransaction>,
tx_ids: &[Bytes32],
) -> Self {
Self {
header: CompressedBlockHeader::from(header),
header: CompressedBlockHeader::new(header, tx_ids),
registrations,
transactions,
}
Expand Down
10 changes: 8 additions & 2 deletions crates/compression/src/decompress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use fuel_core_types::{
},
fuel_types::{
Address,
ChainId,
ContractId,
},
tai64::Tai64,
Expand All @@ -52,6 +53,7 @@ pub async fn decompress<D>(
config: Config,
mut db: D,
block: VersionedCompressedBlock,
chain_id: &ChainId,
) -> anyhow::Result<PartialFuelBlock>
where
D: DecompressDb,
Expand All @@ -74,10 +76,14 @@ where
)
.await?;

Ok(PartialFuelBlock {
let partial_block = PartialFuelBlock {
header: block.partial_block_header(),
transactions,
})
};

block.validate_with(&partial_block, chain_id)?;

Ok(partial_block)
}

pub struct DecompressCtx<D> {
Expand Down
16 changes: 15 additions & 1 deletion crates/compression/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::compressed_block_payload::v0::CompressedBlockPayloadV0;
use crate::compressed_block_payload::v1::CompressedBlockPayloadV1;
use fuel_core_types::{
blockchain::{
block::PartialFuelBlock,
header::{
ApplicationHeader,
BlockHeader,
Expand All @@ -29,7 +30,10 @@ use fuel_core_types::{
primitives::Empty,
},
fuel_tx::CompressedTransaction,
fuel_types::BlockHeight,
fuel_types::{
BlockHeight,
ChainId,
},
};
use registry::RegistrationsPerTable;

Expand All @@ -44,6 +48,11 @@ pub trait VersionedBlockPayload {
fn registrations(&self) -> &RegistrationsPerTable;
fn transactions(&self) -> Vec<CompressedTransaction>;
fn partial_block_header(&self) -> PartialBlockHeader;
fn validate_with(
&self,
partial_block: &PartialFuelBlock,
chain_id: &ChainId,
) -> anyhow::Result<()>;
}

/// Versioned compressed block.
Expand All @@ -60,6 +69,8 @@ impl VersionedCompressedBlock {
header: &BlockHeader,
registrations: RegistrationsPerTable,
transactions: Vec<CompressedTransaction>,
#[cfg(feature = "fault-proving")]
tx_ids: &[fuel_core_types::fuel_types::Bytes32],
) -> Self {
#[cfg(not(feature = "fault-proving"))]
return Self::V0(CompressedBlockPayloadV0::new(
Expand All @@ -72,6 +83,7 @@ impl VersionedCompressedBlock {
header,
registrations,
transactions,
tx_ids,
))
}
}
Expand Down Expand Up @@ -274,6 +286,7 @@ mod tests {
generated: Empty,
},
block_id: BlockId::from_str("0xecea85c17070bc2e65f911310dbd01198f4436052ebba96cded9ddf30c58dd1a").unwrap(),
tx_commitment: Default::default(),
};


Expand Down Expand Up @@ -302,6 +315,7 @@ mod tests {

if let VersionedCompressedBlock::V1(block) = decompressed {
assert_eq!(block.header.block_id, header.block_id);
assert_eq!(block.header.tx_commitment, header.tx_commitment);
} else {
panic!("Expected V1 block, got {:?}", decompressed);
}
Expand Down
3 changes: 3 additions & 0 deletions crates/fuel-core/src/graphql_api/da_compression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub fn da_compress_block<T>(
block: &Block,
block_events: &[Event],
db_tx: &mut T,
#[cfg(feature = "fault-proving")] chain_id: fuel_core_types::fuel_types::ChainId,
) -> anyhow::Result<()>
where
T: OffChainDatabaseTransaction,
Expand All @@ -61,6 +62,8 @@ where
block_events,
},
block,
#[cfg(feature = "fault-proving")]
chain_id,
)
.now_or_never()
.expect("The current implementation resolved all futures instantly")?;
Expand Down
9 changes: 8 additions & 1 deletion crates/fuel-core/src/graphql_api/worker_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,14 @@ where
match self.da_compression_config {
DaCompressionConfig::Disabled => {}
DaCompressionConfig::Enabled(config) => {
da_compress_block(config, block, &result.events, &mut transaction)?;
da_compress_block(
config,
block,
&result.events,
&mut transaction,
#[cfg(feature = "fault-proving")]
self.chain_id,
)?;
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,4 @@ tracing = { workspace = true }
default = ["fuel-core/default"]
only-p2p = ["fuel-core-p2p"]
aws-kms = ["dep:aws-config", "dep:aws-sdk-kms", "fuel-core-bin/aws-kms"]
fault-proving = ["fuel-core-compression/fault-proving", "fuel-core/fault-proving", "fuel-core-bin/fault-proving"]
9 changes: 8 additions & 1 deletion tests/tests/da_compression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ async fn can_fetch_da_compressed_block_from_graphql() {
temporal_registry_retention: Duration::from_secs(3600),
};
config.da_compression = DaCompressionConfig::Enabled(compression_config);
let chain_id = config
.snapshot_reader
.chain_config()
.consensus_parameters
.chain_id();
let srv = FuelService::new_node(config).await.unwrap();
let client = FuelClient::from(srv.bound_address);

Expand Down Expand Up @@ -124,7 +129,9 @@ async fn can_fetch_da_compressed_block_from_graphql() {
},
onchain_db: db.on_chain().view_at(&0u32.into()).unwrap(),
};
let decompressed = decompress(compression_config, db_tx, block).await.unwrap();
let decompressed = decompress(compression_config, db_tx, block, &chain_id)
.await
.unwrap();

assert!(decompressed.transactions.len() == 2);
}
Expand Down

0 comments on commit 3e090b0

Please sign in to comment.