diff --git a/CHANGELOG.md b/CHANGELOG.md index 50ed17a44c..08a40aa332 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ More expansive patch notes and explanations may be found in the specific [pathfi The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- The `proof` field in broadcasted invoke v3 transactions is now a base64-encoded byte blob (`Vec`) instead of base64-encoded packed `u32` values (`Vec`). This reflects the upstream change to use compressed proofs. + ## [0.22.0] - 2026-03-19 ### Fixed diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index 14b2afecbd..5093fda9c2 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -697,10 +697,9 @@ pub fn calculate_class_commitment_leaf_hash( ) } -/// A SNOS stwo proof, serialized as a base64-encoded string of big-endian -/// packed `u32` values. +/// A SNOS stwo proof, serialized as a base64-encoded byte string. #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -pub struct Proof(pub Vec); +pub struct Proof(pub Vec); impl Proof { pub fn is_empty(&self) -> bool { @@ -712,8 +711,7 @@ impl serde::Serialize for Proof { fn serialize(&self, serializer: S) -> Result { use base64::Engine; - let bytes: Vec = self.0.iter().flat_map(|v| v.to_be_bytes()).collect(); - let encoded = base64::engine::general_purpose::STANDARD.encode(&bytes); + let encoded = base64::engine::general_purpose::STANDARD.encode(&self.0); serializer.serialize_str(&encoded) } } @@ -729,17 +727,7 @@ impl<'de> serde::Deserialize<'de> for Proof { let bytes = base64::engine::general_purpose::STANDARD .decode(&s) .map_err(serde::de::Error::custom)?; - if bytes.len() % 4 != 0 { - return Err(serde::de::Error::custom(format!( - "proof base64 decoded length {} is not a multiple of 4", - bytes.len() - ))); - } - let values = bytes - .chunks_exact(4) - .map(|chunk| u32::from_be_bytes(chunk.try_into().unwrap())) - .collect(); - Ok(Proof(values)) + Ok(Proof(bytes)) } } @@ -811,7 +799,7 @@ mod tests { #[test] fn round_trip() { - let proof = Proof(vec![0, 123, 456]); + let proof = Proof(vec![0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 1, 200]); let json = serde_json::to_string(&proof).unwrap(); assert_eq!(json, r#""AAAAAAAAAHsAAAHI""#); let deserialized: Proof = serde_json::from_str(&json).unwrap(); @@ -830,13 +818,6 @@ mod tests { assert!(result.is_err()); } - #[test] - fn non_multiple_of_4_length_returns_error() { - // 3 bytes is not a multiple of 4 - let result = serde_json::from_str::(r#""AAAA""#); // decodes to 3 bytes - assert!(result.is_err()); - } - #[test] fn empty_proof_serializes_to_empty_string() { let proof = Proof::default(); diff --git a/crates/p2p_proto/proto/transaction.proto b/crates/p2p_proto/proto/transaction.proto index 54455256b3..c80d139c60 100644 --- a/crates/p2p_proto/proto/transaction.proto +++ b/crates/p2p_proto/proto/transaction.proto @@ -68,7 +68,7 @@ message InvokeV3 { // Used in consensus and mempool contexts where proof is included. message InvokeV3WithProof { InvokeV3 invoke = 1; - repeated uint32 proof = 2; + bytes proof = 2; } // see https://external.integration.starknet.io/feeder_gateway/get_transaction?transactionHash=0x29fd7881f14380842414cdfdd8d6c0b1f2174f8916edcfeb1ede1eb26ac3ef0 diff --git a/crates/p2p_proto/src/transaction.rs b/crates/p2p_proto/src/transaction.rs index 5c9105b522..839576baba 100644 --- a/crates/p2p_proto/src/transaction.rs +++ b/crates/p2p_proto/src/transaction.rs @@ -87,7 +87,7 @@ pub struct InvokeV3 { #[protobuf(name = "crate::proto::transaction::InvokeV3WithProof")] pub struct InvokeV3WithProof { pub invoke: InvokeV3, - pub proof: Vec, + pub proof: Vec, } #[derive(Debug, Clone, PartialEq, Eq, ToProtobuf, TryFromProtobuf, Dummy)] diff --git a/crates/rpc/fixtures/0.10.0/broadcasted_transactions.json b/crates/rpc/fixtures/0.10.0/broadcasted_transactions.json index 21041431f5..9e5f6030cd 100644 --- a/crates/rpc/fixtures/0.10.0/broadcasted_transactions.json +++ b/crates/rpc/fixtures/0.10.0/broadcasted_transactions.json @@ -186,7 +186,7 @@ "0xabc", "0xdef" ], - "proof": "AAAACwAAABY=" + "proof": "CxY=" }, { "type": "DEPLOY_ACCOUNT", diff --git a/crates/rpc/src/dto/primitives.rs b/crates/rpc/src/dto/primitives.rs index e1922a1e29..af2d8ad1a5 100644 --- a/crates/rpc/src/dto/primitives.rs +++ b/crates/rpc/src/dto/primitives.rs @@ -831,8 +831,7 @@ mod pathfinder_common_types { fn serialize(&self, serializer: Serializer) -> Result { use base64::Engine; - let bytes: Vec = self.0.iter().flat_map(|v| v.to_be_bytes()).collect(); - let encoded = base64::engine::general_purpose::STANDARD.encode(&bytes); + let encoded = base64::engine::general_purpose::STANDARD.encode(&self.0); serializer.serialize_str(&encoded) } }