1
1
use crate :: hasher:: { Digest , Size } ;
2
2
use crate :: Error ;
3
+ #[ cfg( all( not( feature = "std" ) , feature = "scale-codec" ) ) ]
4
+ use alloc:: vec;
3
5
use core:: convert:: TryFrom ;
4
6
#[ cfg( feature = "std" ) ]
5
7
use core:: convert:: TryInto ;
@@ -186,7 +188,12 @@ impl parity_scale_codec::Encode for Multihash<crate::U32> {
186
188
digest. copy_from_slice ( & self . digest ) ;
187
189
self . code . encode_to ( dest) ;
188
190
self . size . encode_to ( dest) ;
189
- digest. encode_to ( dest) ;
191
+ // **NOTE** We write the digest directly to dest, since we have known the size of digest.
192
+ //
193
+ // We do not choose to encode &[u8] directly, because it will add extra bytes (the compact length of digest).
194
+ // For a valid multihash, the length of digest must equal to `size`.
195
+ // Therefore, we can only read raw bytes whose length is equal to `size` when decoding.
196
+ dest. write ( & digest[ ..self . size as usize ] ) ;
190
197
}
191
198
}
192
199
@@ -198,11 +205,17 @@ impl parity_scale_codec::Decode for Multihash<crate::U32> {
198
205
fn decode < DecIn : parity_scale_codec:: Input > (
199
206
input : & mut DecIn ,
200
207
) -> Result < Self , parity_scale_codec:: Error > {
208
+ let code = parity_scale_codec:: Decode :: decode ( input) ?;
209
+ let size = parity_scale_codec:: Decode :: decode ( input) ?;
210
+ // For a valid multihash, the length of digest must equal to the size.
211
+ let mut buf = vec ! [ 0u8 ; size as usize ] ;
212
+ input. read ( & mut buf) ?;
201
213
Ok ( Multihash {
202
- code : parity_scale_codec :: Decode :: decode ( input ) ? ,
203
- size : parity_scale_codec :: Decode :: decode ( input ) ? ,
214
+ code,
215
+ size,
204
216
digest : {
205
- let digest = <[ u8 ; 32 ] >:: decode ( input) ?;
217
+ let mut digest = [ 0u8 ; 32 ] ;
218
+ digest[ ..size as usize ] . copy_from_slice ( & buf) ;
206
219
GenericArray :: clone_from_slice ( & digest)
207
220
} ,
208
221
} )
@@ -216,7 +229,12 @@ impl parity_scale_codec::Encode for Multihash<crate::U64> {
216
229
digest. copy_from_slice ( & self . digest ) ;
217
230
self . code . encode_to ( dest) ;
218
231
self . size . encode_to ( dest) ;
219
- digest. encode_to ( dest) ;
232
+ // **NOTE** We write the digest directly to dest, since we have known the size of digest.
233
+ //
234
+ // We do not choose to encode &[u8] directly, because it will add extra bytes (the compact length of digest).
235
+ // For a valid multihash, the length of digest must equal to `size`.
236
+ // Therefore, we can only read raw bytes whose length is equal to `size` when decoding.
237
+ dest. write ( & digest[ ..self . size as usize ] ) ;
220
238
}
221
239
}
222
240
@@ -228,11 +246,17 @@ impl parity_scale_codec::Decode for Multihash<crate::U64> {
228
246
fn decode < DecIn : parity_scale_codec:: Input > (
229
247
input : & mut DecIn ,
230
248
) -> Result < Self , parity_scale_codec:: Error > {
249
+ let code = parity_scale_codec:: Decode :: decode ( input) ?;
250
+ let size = parity_scale_codec:: Decode :: decode ( input) ?;
251
+ // For a valid multihash, the length of digest must equal to the size.
252
+ let mut buf = vec ! [ 0u8 ; size as usize ] ;
253
+ input. read ( & mut buf) ?;
231
254
Ok ( Multihash {
232
- code : parity_scale_codec :: Decode :: decode ( input ) ? ,
233
- size : parity_scale_codec :: Decode :: decode ( input ) ? ,
255
+ code,
256
+ size,
234
257
digest : {
235
- let digest = <[ u8 ; 64 ] >:: decode ( input) ?;
258
+ let mut digest = [ 0u8 ; 64 ] ;
259
+ digest[ ..size as usize ] . copy_from_slice ( & buf) ;
236
260
GenericArray :: clone_from_slice ( & digest)
237
261
} ,
238
262
} )
@@ -302,12 +326,28 @@ mod tests {
302
326
#[ test]
303
327
#[ cfg( feature = "scale-codec" ) ]
304
328
fn test_scale ( ) {
329
+ use crate :: { Hasher , Sha2_256 } ;
305
330
use parity_scale_codec:: { Decode , Encode } ;
306
331
307
- let mh = Multihash :: < crate :: U32 > :: default ( ) ;
308
- let bytes = mh. encode ( ) ;
309
- let mh2: Multihash < crate :: U32 > = Decode :: decode ( & mut & bytes[ ..] ) . unwrap ( ) ;
310
- assert_eq ! ( mh, mh2) ;
332
+ let mh1 = Multihash :: < crate :: U32 > :: wrap (
333
+ Code :: Sha2_256 . into ( ) ,
334
+ Sha2_256 :: digest ( b"hello world" ) . as_ref ( ) ,
335
+ )
336
+ . unwrap ( ) ;
337
+ // println!("mh1: code = {}, size = {}, digest = {:?}", mh1.code(), mh1.size(), mh1.digest());
338
+ let mh1_bytes = mh1. encode ( ) ;
339
+ // println!("Multihash<32>: {}", hex::encode(&mh1_bytes));
340
+ let mh2: Multihash < crate :: U32 > = Decode :: decode ( & mut & mh1_bytes[ ..] ) . unwrap ( ) ;
341
+ assert_eq ! ( mh1, mh2) ;
342
+
343
+ let mh3: Multihash < crate :: U64 > = Code :: Sha2_256 . digest ( b"hello world" ) ;
344
+ // println!("mh3: code = {}, size = {}, digest = {:?}", mh3.code(), mh3.size(), mh3.digest());
345
+ let mh3_bytes = mh3. encode ( ) ;
346
+ // println!("Multihash<64>: {}", hex::encode(&mh3_bytes));
347
+ let mh4: Multihash < crate :: U64 > = Decode :: decode ( & mut & mh3_bytes[ ..] ) . unwrap ( ) ;
348
+ assert_eq ! ( mh3, mh4) ;
349
+
350
+ assert_eq ! ( mh1_bytes, mh3_bytes) ;
311
351
}
312
352
313
353
#[ test]
0 commit comments