@@ -15,6 +15,7 @@ use std::{
1515 ops:: { Bound , RangeBounds } ,
1616 path:: Path ,
1717 str:: FromStr ,
18+ sync:: Arc ,
1819} ;
1920
2021use alloy_primitives:: U256 ;
@@ -1246,22 +1247,28 @@ impl CompressedBytecode {
12461247
12471248impl BcsHashable < ' _ > for BlobContent { }
12481249
1250+ use serde_with:: * ;
1251+
12491252/// A blob of binary data.
1253+ #[ serde_as]
12501254#[ derive( Hash , Clone , Debug , PartialEq , Eq , Serialize , Deserialize ) ]
12511255pub struct BlobContent {
12521256 /// The type of data represented by the bytes.
12531257 blob_type : BlobType ,
12541258 /// The binary data.
1255- #[ serde( with = "serde_bytes" ) ]
12561259 #[ debug( skip) ]
1257- bytes : Box < [ u8 ] > ,
1260+ #[ serde_as( as = "Arc<Bytes>" ) ]
1261+ bytes : Arc < Box < [ u8 ] > > ,
12581262}
12591263
12601264impl BlobContent {
12611265 /// Creates a new [`BlobContent`] from the provided bytes and [`BlobId`].
12621266 pub fn new ( blob_type : BlobType , bytes : impl Into < Box < [ u8 ] > > ) -> Self {
12631267 let bytes = bytes. into ( ) ;
1264- BlobContent { blob_type, bytes }
1268+ BlobContent {
1269+ blob_type,
1270+ bytes : Arc :: new ( bytes) ,
1271+ }
12651272 }
12661273
12671274 /// Creates a new data [`BlobContent`] from the provided bytes.
@@ -1313,9 +1320,10 @@ impl BlobContent {
13131320 & self . bytes
13141321 }
13151322
1316- /// Gets the inner blob's bytes, consuming the blob.
1317- pub fn into_bytes ( self ) -> Box < [ u8 ] > {
1318- self . bytes
1323+ /// Convert a BlobContent into `Vec<u8>` without cloning if possible.
1324+ pub fn into_vec_or_clone ( self ) -> Vec < u8 > {
1325+ let bytes = Arc :: unwrap_or_clone ( self . bytes ) ;
1326+ bytes. into_vec ( )
13191327 }
13201328
13211329 /// Returns the type of data represented by this blob's bytes.
@@ -1363,11 +1371,12 @@ impl Blob {
13631371
13641372 /// Creates a blob without checking that the hash actually matches the content.
13651373 pub fn new_with_id_unchecked ( blob_id : BlobId , bytes : impl Into < Box < [ u8 ] > > ) -> Self {
1374+ let bytes = bytes. into ( ) ;
13661375 Blob {
13671376 hash : blob_id. hash ,
13681377 content : BlobContent {
13691378 blob_type : blob_id. blob_type ,
1370- bytes : bytes . into ( ) ,
1379+ bytes : Arc :: new ( bytes ) ,
13711380 } ,
13721381 }
13731382 }
@@ -1432,11 +1441,6 @@ impl Blob {
14321441 self . content . bytes ( )
14331442 }
14341443
1435- /// Gets the inner blob's bytes.
1436- pub fn into_bytes ( self ) -> Box < [ u8 ] > {
1437- self . content . into_bytes ( )
1438- }
1439-
14401444 /// Loads data blob from a file.
14411445 pub async fn load_data_blob_from_file ( path : impl AsRef < Path > ) -> io:: Result < Self > {
14421446 Ok ( Self :: new_data ( fs:: read ( path) ?) )
@@ -1590,7 +1594,8 @@ mod metrics {
15901594mod tests {
15911595 use std:: str:: FromStr ;
15921596
1593- use super :: Amount ;
1597+ use super :: { Amount , BlobContent } ;
1598+ use crate :: identifiers:: BlobType ;
15941599
15951600 #[ test]
15961601 fn display_amount ( ) {
@@ -1617,4 +1622,35 @@ mod tests {
16171622 format!( "{:~^+9.1}" , Amount :: from_str( "12.34" ) . unwrap( ) )
16181623 ) ;
16191624 }
1625+
1626+ #[ test]
1627+ fn blob_content_serialization_deserialization ( ) {
1628+ let test_data = b"Hello, world!" . as_slice ( ) ;
1629+ let original_blob = BlobContent :: new ( BlobType :: Data , test_data) ;
1630+
1631+ let serialized = bcs:: to_bytes ( & original_blob) . expect ( "Failed to serialize BlobContent" ) ;
1632+ let deserialized: BlobContent =
1633+ bcs:: from_bytes ( & serialized) . expect ( "Failed to deserialize BlobContent" ) ;
1634+ assert_eq ! ( original_blob, deserialized) ;
1635+
1636+ let serialized =
1637+ serde_json:: to_vec ( & original_blob) . expect ( "Failed to serialize BlobContent" ) ;
1638+ let deserialized: BlobContent =
1639+ serde_json:: from_slice ( & serialized) . expect ( "Failed to deserialize BlobContent" ) ;
1640+ assert_eq ! ( original_blob, deserialized) ;
1641+ }
1642+
1643+ #[ test]
1644+ fn blob_content_hash_consistency ( ) {
1645+ let test_data = b"Hello, world!" ;
1646+ let blob1 = BlobContent :: new ( BlobType :: Data , test_data. as_slice ( ) ) ;
1647+ let blob2 = BlobContent :: new ( BlobType :: Data , Vec :: from ( test_data. as_slice ( ) ) ) ;
1648+
1649+ // Both should have same hash since they contain the same data
1650+ let hash1 = crate :: crypto:: CryptoHash :: new ( & blob1) ;
1651+ let hash2 = crate :: crypto:: CryptoHash :: new ( & blob2) ;
1652+
1653+ assert_eq ! ( hash1, hash2, "Hashes should be equal for same content" ) ;
1654+ assert_eq ! ( blob1. bytes( ) , blob2. bytes( ) , "Byte content should be equal" ) ;
1655+ }
16201656}
0 commit comments