@@ -280,6 +280,137 @@ where
280
280
}
281
281
}
282
282
283
+ /// Bincode-compatible [`ReceiptEnvelope`] serde implementation.
284
+ #[ cfg( all( feature = "serde" , feature = "serde-bincode-compat" ) ) ]
285
+ pub ( crate ) mod serde_bincode_compat {
286
+ use crate :: { Receipt , ReceiptWithBloom , TxType } ;
287
+ use alloc:: borrow:: Cow ;
288
+ use alloy_primitives:: { Bloom , Log , U8 } ;
289
+ use serde:: { Deserialize , Deserializer , Serialize , Serializer } ;
290
+ use serde_with:: { DeserializeAs , SerializeAs } ;
291
+
292
+ /// Bincode-compatible [`super::ReceiptEnvelope`] serde implementation.
293
+ ///
294
+ /// Intended to use with the [`serde_with::serde_as`] macro in the following way:
295
+ /// ```rust
296
+ /// use alloy_consensus::{serde_bincode_compat, ReceiptEnvelope};
297
+ /// use serde::{de::DeserializeOwned, Deserialize, Serialize};
298
+ /// use serde_with::serde_as;
299
+ ///
300
+ /// #[serde_as]
301
+ /// #[derive(Serialize, Deserialize)]
302
+ /// struct Data<T: Serialize + DeserializeOwned + Clone + 'static> {
303
+ /// #[serde_as(as = "serde_bincode_compat::ReceiptEnvelope<'_, T>")]
304
+ /// receipt: ReceiptEnvelope<T>,
305
+ /// }
306
+ /// ```
307
+ #[ derive( Debug , Serialize , Deserialize ) ]
308
+ pub struct ReceiptEnvelope < ' a , T : Clone = Log > {
309
+ #[ serde( deserialize_with = "deserde_txtype" ) ]
310
+ tx_type : TxType ,
311
+ success : bool ,
312
+ cumulative_gas_used : u64 ,
313
+ logs_bloom : Cow < ' a , Bloom > ,
314
+ logs : Cow < ' a , [ T ] > ,
315
+ }
316
+
317
+ /// Ensures that txtype is deserialized symmetrically as U8
318
+ fn deserde_txtype < ' de , D > ( deserializer : D ) -> Result < TxType , D :: Error >
319
+ where
320
+ D : Deserializer < ' de > ,
321
+ {
322
+ let value = U8 :: deserialize ( deserializer) ?;
323
+ value. to :: < u8 > ( ) . try_into ( ) . map_err ( serde:: de:: Error :: custom)
324
+ }
325
+
326
+ impl < ' a , T : Clone > From < & ' a super :: ReceiptEnvelope < T > > for ReceiptEnvelope < ' a , T > {
327
+ fn from ( value : & ' a super :: ReceiptEnvelope < T > ) -> Self {
328
+ Self {
329
+ tx_type : value. tx_type ( ) ,
330
+ success : value. status ( ) ,
331
+ cumulative_gas_used : value. cumulative_gas_used ( ) ,
332
+ logs_bloom : Cow :: Borrowed ( value. logs_bloom ( ) ) ,
333
+ logs : Cow :: Borrowed ( value. logs ( ) ) ,
334
+ }
335
+ }
336
+ }
337
+
338
+ impl < ' a , T : Clone > From < ReceiptEnvelope < ' a , T > > for super :: ReceiptEnvelope < T > {
339
+ fn from ( value : ReceiptEnvelope < ' a , T > ) -> Self {
340
+ let ReceiptEnvelope { tx_type, success, cumulative_gas_used, logs_bloom, logs } = value;
341
+ let receipt = ReceiptWithBloom {
342
+ receipt : Receipt {
343
+ status : success. into ( ) ,
344
+ cumulative_gas_used,
345
+ logs : logs. into_owned ( ) ,
346
+ } ,
347
+ logs_bloom : logs_bloom. into_owned ( ) ,
348
+ } ;
349
+ match tx_type {
350
+ TxType :: Legacy => Self :: Legacy ( receipt) ,
351
+ TxType :: Eip2930 => Self :: Eip2930 ( receipt) ,
352
+ TxType :: Eip1559 => Self :: Eip1559 ( receipt) ,
353
+ TxType :: Eip4844 => Self :: Eip4844 ( receipt) ,
354
+ TxType :: Eip7702 => Self :: Eip7702 ( receipt) ,
355
+ }
356
+ }
357
+ }
358
+
359
+ impl < T : Serialize + Clone > SerializeAs < super :: ReceiptEnvelope < T > > for ReceiptEnvelope < ' _ , T > {
360
+ fn serialize_as < S > (
361
+ source : & super :: ReceiptEnvelope < T > ,
362
+ serializer : S ,
363
+ ) -> Result < S :: Ok , S :: Error >
364
+ where
365
+ S : Serializer ,
366
+ {
367
+ ReceiptEnvelope :: < ' _ , T > :: from ( source) . serialize ( serializer)
368
+ }
369
+ }
370
+
371
+ impl < ' de , T : Deserialize < ' de > + Clone > DeserializeAs < ' de , super :: ReceiptEnvelope < T > >
372
+ for ReceiptEnvelope < ' de , T >
373
+ {
374
+ fn deserialize_as < D > ( deserializer : D ) -> Result < super :: ReceiptEnvelope < T > , D :: Error >
375
+ where
376
+ D : Deserializer < ' de > ,
377
+ {
378
+ ReceiptEnvelope :: < ' _ , T > :: deserialize ( deserializer) . map ( Into :: into)
379
+ }
380
+ }
381
+
382
+ #[ cfg( test) ]
383
+ mod tests {
384
+ use super :: super :: { serde_bincode_compat, ReceiptEnvelope } ;
385
+ use alloy_primitives:: Log ;
386
+ use arbitrary:: Arbitrary ;
387
+ use rand:: Rng ;
388
+ use serde:: { Deserialize , Serialize } ;
389
+ use serde_with:: serde_as;
390
+
391
+ #[ test]
392
+ fn test_receipt_evelope_bincode_roundtrip ( ) {
393
+ #[ serde_as]
394
+ #[ derive( Debug , PartialEq , Eq , Serialize , Deserialize ) ]
395
+ struct Data {
396
+ #[ serde_as( as = "serde_bincode_compat::ReceiptEnvelope<'_>" ) ]
397
+ transaction : ReceiptEnvelope < Log > ,
398
+ }
399
+
400
+ let mut bytes = [ 0u8 ; 1024 ] ;
401
+ rand:: thread_rng ( ) . fill ( bytes. as_mut_slice ( ) ) ;
402
+ let data = Data {
403
+ transaction : ReceiptEnvelope :: arbitrary ( & mut arbitrary:: Unstructured :: new ( & bytes) )
404
+ . unwrap ( ) ,
405
+ } ;
406
+
407
+ let encoded = bincode:: serialize ( & data) . unwrap ( ) ;
408
+ let decoded: Data = bincode:: deserialize ( & encoded) . unwrap ( ) ;
409
+ assert_eq ! ( decoded, data) ;
410
+ }
411
+ }
412
+ }
413
+
283
414
#[ cfg( test) ]
284
415
mod test {
285
416
#[ cfg( feature = "serde" ) ]
0 commit comments