From dfb572e38f3bc9f666f1caf30d8019cbbaa76ddc Mon Sep 17 00:00:00 2001 From: lightsing Date: Tue, 9 Dec 2025 14:09:43 +0800 Subject: [PATCH 1/4] fix building in guest --- Cargo.lock | 16 ++++++++++++++++ crates/codec/Cargo.toml | 6 +++++- crates/codec/src/decoding/v2/zstd.rs | 25 +++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e59dfab5..ea78d5ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11478,6 +11478,15 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "ruzstd" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01" +dependencies = [ + "twox-hash", +] + [[package]] name = "ryu" version = "1.0.20" @@ -11676,6 +11685,7 @@ dependencies = [ "bitvec", "derive_more", "eyre", + "ruzstd", "scroll-alloy-consensus", "scroll-l1", "serde_json", @@ -13571,6 +13581,12 @@ dependencies = [ "utf-8", ] +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" + [[package]] name = "typenum" version = "1.19.0" diff --git a/crates/codec/Cargo.toml b/crates/codec/Cargo.toml index 581f8f64..d71f892c 100644 --- a/crates/codec/Cargo.toml +++ b/crates/codec/Cargo.toml @@ -19,11 +19,15 @@ bitvec.workspace = true derive_more = { version = "2.0", default-features = false } eyre = { workspace = true, optional = true } thiserror = { version = "2.0", default-features = false } -zstd = "=0.13.3" +zstd = { version = "=0.13.3", optional = true } +ruzstd = { version = "0.8", optional = true } [dev-dependencies] eyre.workspace = true serde_json = "1.0" [features] +default = ["zstd"] test-utils = ["dep:eyre", "scroll-l1/test-utils"] +zstd = ["dep:zstd"] +ruzstd = ["dep:ruzstd"] diff --git a/crates/codec/src/decoding/v2/zstd.rs b/crates/codec/src/decoding/v2/zstd.rs index e5969031..63f0059b 100644 --- a/crates/codec/src/decoding/v2/zstd.rs +++ b/crates/codec/src/decoding/v2/zstd.rs @@ -2,14 +2,18 @@ use std::io::Read; -use zstd::Decoder; - /// The ZSTD magic number for zstd compressed data header. const ZSTD_MAGIC_NUMBER: [u8; 4] = [0x28, 0xb5, 0x2f, 0xfd]; +#[cfg(not(any(feature = "zstd", feature = "ruzstd")))] +compile_error!("Either feature \"zstd\" or \"ruzstd\" must be enabled for zstd support."); + /// Uncompress the provided data. +#[cfg(feature = "zstd")] pub fn decompress_blob_data(data: &[u8]) -> Vec { + use zstd::Decoder; let mut header_data = ZSTD_MAGIC_NUMBER.to_vec(); + header_data.extend_from_slice(data); // init decoder and owned output data. @@ -31,3 +35,20 @@ pub fn decompress_blob_data(data: &[u8]) -> Vec { output } + +/// Uncompress the provided data. +#[cfg(feature = "ruzstd")] +pub fn decompress_blob_data(data: &[u8]) -> Vec { + use ruzstd::decoding::StreamingDecoder; + + let mut header_data = ZSTD_MAGIC_NUMBER.to_vec(); + header_data.extend_from_slice(data); + + // init decoder and owned output data. + let mut decoder = StreamingDecoder::new(header_data.as_slice()).unwrap(); + // heuristic: use data length as the allocated output capacity. + let mut output = Vec::with_capacity(header_data.len()); + decoder.read_to_end(&mut output).unwrap(); + + output +} From c9554802273f535042cca5dbe44f0ceda65d33a8 Mon Sep 17 00:00:00 2001 From: lightsing Date: Tue, 9 Dec 2025 14:34:45 +0800 Subject: [PATCH 2/4] update default behaviour --- crates/codec/Cargo.toml | 3 +-- crates/codec/src/decoding/v2/zstd.rs | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/codec/Cargo.toml b/crates/codec/Cargo.toml index d71f892c..120ddd5b 100644 --- a/crates/codec/Cargo.toml +++ b/crates/codec/Cargo.toml @@ -20,7 +20,7 @@ derive_more = { version = "2.0", default-features = false } eyre = { workspace = true, optional = true } thiserror = { version = "2.0", default-features = false } zstd = { version = "=0.13.3", optional = true } -ruzstd = { version = "0.8", optional = true } +ruzstd = "0.8" [dev-dependencies] eyre.workspace = true @@ -30,4 +30,3 @@ serde_json = "1.0" default = ["zstd"] test-utils = ["dep:eyre", "scroll-l1/test-utils"] zstd = ["dep:zstd"] -ruzstd = ["dep:ruzstd"] diff --git a/crates/codec/src/decoding/v2/zstd.rs b/crates/codec/src/decoding/v2/zstd.rs index 63f0059b..4b580ead 100644 --- a/crates/codec/src/decoding/v2/zstd.rs +++ b/crates/codec/src/decoding/v2/zstd.rs @@ -2,12 +2,12 @@ use std::io::Read; +#[cfg(feature = "zstd")] +use ruzstd as _; + /// The ZSTD magic number for zstd compressed data header. const ZSTD_MAGIC_NUMBER: [u8; 4] = [0x28, 0xb5, 0x2f, 0xfd]; -#[cfg(not(any(feature = "zstd", feature = "ruzstd")))] -compile_error!("Either feature \"zstd\" or \"ruzstd\" must be enabled for zstd support."); - /// Uncompress the provided data. #[cfg(feature = "zstd")] pub fn decompress_blob_data(data: &[u8]) -> Vec { @@ -37,7 +37,7 @@ pub fn decompress_blob_data(data: &[u8]) -> Vec { } /// Uncompress the provided data. -#[cfg(feature = "ruzstd")] +#[cfg(not(feature = "zstd"))] pub fn decompress_blob_data(data: &[u8]) -> Vec { use ruzstd::decoding::StreamingDecoder; From 3d2bf5d5315873bf84bd0da2f57e0bb6e6edc2f0 Mon Sep 17 00:00:00 2001 From: lightsing Date: Mon, 5 Jan 2026 12:56:03 +0800 Subject: [PATCH 3/4] apply review --- crates/codec/Cargo.toml | 3 +- crates/codec/src/decoding/v2/mod.rs | 2 +- crates/codec/src/decoding/v2/zstd.rs | 45 +++++++++++++++++++++------- crates/codec/src/decoding/v4/mod.rs | 2 +- crates/codec/src/decoding/v7/mod.rs | 2 +- crates/codec/src/error.rs | 8 +++++ 6 files changed, 48 insertions(+), 14 deletions(-) diff --git a/crates/codec/Cargo.toml b/crates/codec/Cargo.toml index 120ddd5b..d71f892c 100644 --- a/crates/codec/Cargo.toml +++ b/crates/codec/Cargo.toml @@ -20,7 +20,7 @@ derive_more = { version = "2.0", default-features = false } eyre = { workspace = true, optional = true } thiserror = { version = "2.0", default-features = false } zstd = { version = "=0.13.3", optional = true } -ruzstd = "0.8" +ruzstd = { version = "0.8", optional = true } [dev-dependencies] eyre.workspace = true @@ -30,3 +30,4 @@ serde_json = "1.0" default = ["zstd"] test-utils = ["dep:eyre", "scroll-l1/test-utils"] zstd = ["dep:zstd"] +ruzstd = ["dep:ruzstd"] diff --git a/crates/codec/src/decoding/v2/mod.rs b/crates/codec/src/decoding/v2/mod.rs index 6427b945..5c83c10b 100644 --- a/crates/codec/src/decoding/v2/mod.rs +++ b/crates/codec/src/decoding/v2/mod.rs @@ -35,7 +35,7 @@ pub fn decode_v2(calldata: &[u8], blob: &[u8]) -> Result { // get blob iterator and collect, skipping unused bytes. let compressed_heap_blob = BlobSliceIter::from_blob_slice(blob).copied().collect::>(); - let uncompressed_heap_blob = decompress_blob_data(&compressed_heap_blob); + let uncompressed_heap_blob = decompress_blob_data(&compressed_heap_blob)?; let buf = &mut (uncompressed_heap_blob.as_slice()); // check buf len. diff --git a/crates/codec/src/decoding/v2/zstd.rs b/crates/codec/src/decoding/v2/zstd.rs index 4b580ead..33667996 100644 --- a/crates/codec/src/decoding/v2/zstd.rs +++ b/crates/codec/src/decoding/v2/zstd.rs @@ -2,22 +2,46 @@ use std::io::Read; -#[cfg(feature = "zstd")] -use ruzstd as _; +#[cfg(not(any(feature = "zstd", feature = "ruzstd")))] +compile_error!("You must enable exactly one of the `zstd` or `ruzstd` features"); +#[cfg(all(feature = "zstd", feature = "ruzstd"))] +compile_error!("Features `zstd` and `ruzstd` are mutually exclusive"); /// The ZSTD magic number for zstd compressed data header. const ZSTD_MAGIC_NUMBER: [u8; 4] = [0x28, 0xb5, 0x2f, 0xfd]; +/// Result type for Zstd operations. +type Result = std::result::Result; + +/// Zstd error type. +#[derive(Debug)] +pub struct ZstdError(Box); + +impl std::fmt::Display for ZstdError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "ZstdError: {}", self.0) + } +} + +impl std::error::Error for ZstdError {} + +impl ZstdError { + /// Consumes the error and returns the inner error. + pub fn into_inner(self) -> Box { + self.0 + } +} + /// Uncompress the provided data. #[cfg(feature = "zstd")] -pub fn decompress_blob_data(data: &[u8]) -> Vec { +pub fn decompress_blob_data(data: &[u8]) -> Result> { use zstd::Decoder; let mut header_data = ZSTD_MAGIC_NUMBER.to_vec(); header_data.extend_from_slice(data); // init decoder and owned output data. - let mut decoder = Decoder::new(header_data.as_slice()).unwrap(); + let mut decoder = Decoder::new(header_data.as_slice()).map_err(|e| ZstdError(Box::new(e)))?; // heuristic: use data length as the allocated output capacity. let mut output = Vec::with_capacity(header_data.len()); @@ -33,22 +57,23 @@ pub fn decompress_blob_data(data: &[u8]) -> Vec { output.extend_from_slice(&dst[..size]); } - output + Ok(output) } /// Uncompress the provided data. -#[cfg(not(feature = "zstd"))] -pub fn decompress_blob_data(data: &[u8]) -> Vec { +#[cfg(feature = "ruzstd")] +pub fn decompress_blob_data(data: &[u8]) -> Result> { use ruzstd::decoding::StreamingDecoder; let mut header_data = ZSTD_MAGIC_NUMBER.to_vec(); header_data.extend_from_slice(data); // init decoder and owned output data. - let mut decoder = StreamingDecoder::new(header_data.as_slice()).unwrap(); + let mut decoder = + StreamingDecoder::new(header_data.as_slice()).map_err(|e| ZstdError(Box::new(e)))?; // heuristic: use data length as the allocated output capacity. let mut output = Vec::with_capacity(header_data.len()); - decoder.read_to_end(&mut output).unwrap(); + decoder.read_to_end(&mut output).map_err(|e| ZstdError(Box::new(e)))?; - output + Ok(output) } diff --git a/crates/codec/src/decoding/v4/mod.rs b/crates/codec/src/decoding/v4/mod.rs index 02b79775..4ce64406 100644 --- a/crates/codec/src/decoding/v4/mod.rs +++ b/crates/codec/src/decoding/v4/mod.rs @@ -31,7 +31,7 @@ pub fn decode_v4(calldata: &[u8], blob: &[u8]) -> Result { debug_assert!(is_compressed == 1 || is_compressed == 0, "incorrect compressed byte flag"); let buf = if is_compressed == 1 { - heap_blob = decompress_blob_data(&heap_blob[1..]); + heap_blob = decompress_blob_data(&heap_blob[1..])?; &mut heap_blob.as_slice() } else { &mut (&heap_blob[1..]) diff --git a/crates/codec/src/decoding/v7/mod.rs b/crates/codec/src/decoding/v7/mod.rs index e98e38cc..d22f35d3 100644 --- a/crates/codec/src/decoding/v7/mod.rs +++ b/crates/codec/src/decoding/v7/mod.rs @@ -49,7 +49,7 @@ pub fn decode_v7(blob: &[u8]) -> Result { // uncompress if necessary. let buf = if is_compressed == 1 { - heap_blob = decompress_blob_data(buf); + heap_blob = decompress_blob_data(buf)?; &mut heap_blob.as_slice() } else { buf diff --git a/crates/codec/src/error.rs b/crates/codec/src/error.rs index 80036f4e..530efc3a 100644 --- a/crates/codec/src/error.rs +++ b/crates/codec/src/error.rs @@ -30,6 +30,8 @@ pub enum DecodingError { InvalidCommitBatchCall(#[from] InvalidCommitBatchCall), #[error("end of file")] Eof, + #[error("zstd decompression error occurred: {0}")] + ZstdDecompression(Box), #[error("decoding error occurred: {0}")] Other(Box), } @@ -46,3 +48,9 @@ impl From for DecodingError { DecodingError::Other(value.into()) } } + +impl From for DecodingError { + fn from(e: crate::decoding::v2::zstd::ZstdError) -> Self { + DecodingError::ZstdDecompression(e.into_inner()) + } +} From 59706295e639180e9b12ab120d31fdafde75efc5 Mon Sep 17 00:00:00 2001 From: lightsing Date: Mon, 5 Jan 2026 13:05:22 +0800 Subject: [PATCH 4/4] update ci --- .github/workflows/lint.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index d4d06330..c668bcf5 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -117,7 +117,7 @@ jobs: with: cache-on-failure: true - name: Run feature check - run: cargo hack check --feature-powerset + run: cargo hack check --feature-powerset --mutually-exclusive-features "zstd,ruzstd" --at-least-one-of "zstd,ruzstd" no_std: runs-on: ubuntu-latest