@@ -313,18 +313,28 @@ pub fn instantiate2_address(
313
313
// Non-empty msg values are discouraged.
314
314
// See https://medium.com/cosmwasm/dev-note-3-limitations-of-instantiate2-and-how-to-deal-with-them-a3f946874230.
315
315
let msg = b"" ;
316
- instantiate2_address_impl ( checksum, creator, salt, msg)
316
+ let len = 32 ;
317
+ instantiate2_address_impl ( checksum, creator, salt, msg, len)
317
318
}
318
319
319
320
/// The instantiate2 address derivation implementation. This API is used for
320
321
/// testing purposes only. The `msg` field is discouraged and should not be used.
321
322
/// Use [`instantiate2_address`].
323
+ ///
324
+ /// `len` is the address length on bytes. The resulting address data will be truncated to
325
+ /// that length. A value > 32 is invalid because [`hash`] returns only 32 bytes of data.
326
+ /// A value of 0 is considered invalid because it indicates a bug.
327
+ /// For ADR-028 compatibility, 32 must be used.
328
+ /// However, some chains use 20 for compatibility with the Ethereum ecosystem.
329
+ /// Using any other value than 32 requires a coordination with the chain implementation.
330
+ /// See also <https://github.com/CosmWasm/cosmwasm/issues/2155>.
322
331
#[ doc( hidden) ]
323
332
fn instantiate2_address_impl (
324
333
checksum : & [ u8 ] ,
325
334
creator : & CanonicalAddr ,
326
335
salt : & [ u8 ] ,
327
336
msg : & [ u8 ] ,
337
+ len : usize ,
328
338
) -> Result < CanonicalAddr , Instantiate2AddressError > {
329
339
if checksum. len ( ) != 32 {
330
340
return Err ( Instantiate2AddressError :: InvalidChecksumLength ) ;
@@ -344,7 +354,17 @@ fn instantiate2_address_impl(
344
354
key. extend_from_slice ( salt) ;
345
355
key. extend_from_slice ( & ( msg. len ( ) as u64 ) . to_be_bytes ( ) ) ;
346
356
key. extend_from_slice ( msg) ;
347
- let address_data = hash ( "module" , & key) ;
357
+ let mut address_data = hash ( "module" , & key) ;
358
+
359
+ // Use the first `len` bytes
360
+ // Fingers crossed Rust can optimize this whole block out in the default case (32), because otherwise
361
+ // truncate will do a resize for len == address_data.len(), see https://github.com/rust-lang/rust/issues/76089
362
+ if len != 32 {
363
+ debug_assert ! ( len <= 32 ) ;
364
+ debug_assert ! ( len > 0 ) ;
365
+ address_data. truncate ( len) ;
366
+ }
367
+
348
368
Ok ( address_data. into ( ) )
349
369
}
350
370
@@ -650,7 +670,7 @@ mod tests {
650
670
"5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847"
651
671
) ) ;
652
672
assert_eq ! (
653
- instantiate2_address_impl( & checksum1, & creator1, & salt1, msg1) . unwrap( ) ,
673
+ instantiate2_address_impl( & checksum1, & creator1, & salt1, msg1, 32 ) . unwrap( ) ,
654
674
expected
655
675
) ;
656
676
@@ -659,7 +679,7 @@ mod tests {
659
679
"0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835"
660
680
) ) ;
661
681
assert_eq ! (
662
- instantiate2_address_impl( & checksum1, & creator1, & salt1, msg2) . unwrap( ) ,
682
+ instantiate2_address_impl( & checksum1, & creator1, & salt1, msg2, 32 ) . unwrap( ) ,
663
683
expected
664
684
) ;
665
685
@@ -668,7 +688,7 @@ mod tests {
668
688
"83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167"
669
689
) ) ;
670
690
assert_eq ! (
671
- instantiate2_address_impl( & checksum1, & creator1, & salt1, msg3) . unwrap( ) ,
691
+ instantiate2_address_impl( & checksum1, & creator1, & salt1, msg3, 32 ) . unwrap( ) ,
672
692
expected
673
693
) ;
674
694
@@ -677,40 +697,79 @@ mod tests {
677
697
"9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564"
678
698
) ) ;
679
699
assert_eq ! (
680
- instantiate2_address_impl( & checksum1, & creator1, & salt2, b"" ) . unwrap( ) ,
700
+ instantiate2_address_impl( & checksum1, & creator1, & salt2, b"" , 32 ) . unwrap( ) ,
681
701
expected
682
702
) ;
683
703
684
704
// Salt too short or too long
685
705
let empty = Vec :: < u8 > :: new ( ) ;
686
706
assert ! ( matches!(
687
- instantiate2_address_impl( & checksum1, & creator1, & empty, b"" ) . unwrap_err( ) ,
707
+ instantiate2_address_impl( & checksum1, & creator1, & empty, b"" , 32 ) . unwrap_err( ) ,
688
708
Instantiate2AddressError :: InvalidSaltLength
689
709
) ) ;
690
710
let too_long = vec ! [ 0x11 ; 65 ] ;
691
711
assert ! ( matches!(
692
- instantiate2_address_impl( & checksum1, & creator1, & too_long, b"" ) . unwrap_err( ) ,
712
+ instantiate2_address_impl( & checksum1, & creator1, & too_long, b"" , 32 ) . unwrap_err( ) ,
693
713
Instantiate2AddressError :: InvalidSaltLength
694
714
) ) ;
695
715
696
716
// invalid checksum length
697
717
let broken_cs = hex ! ( "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2" ) ;
698
718
assert ! ( matches!(
699
- instantiate2_address_impl( & broken_cs, & creator1, & salt1, b"" ) . unwrap_err( ) ,
719
+ instantiate2_address_impl( & broken_cs, & creator1, & salt1, b"" , 32 ) . unwrap_err( ) ,
700
720
Instantiate2AddressError :: InvalidChecksumLength
701
721
) ) ;
702
722
let broken_cs = hex ! ( "" ) ;
703
723
assert ! ( matches!(
704
- instantiate2_address_impl( & broken_cs, & creator1, & salt1, b"" ) . unwrap_err( ) ,
724
+ instantiate2_address_impl( & broken_cs, & creator1, & salt1, b"" , 32 ) . unwrap_err( ) ,
705
725
Instantiate2AddressError :: InvalidChecksumLength
706
726
) ) ;
707
727
let broken_cs = hex ! ( "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2aaaa" ) ;
708
728
assert ! ( matches!(
709
- instantiate2_address_impl( & broken_cs, & creator1, & salt1, b"" ) . unwrap_err( ) ,
729
+ instantiate2_address_impl( & broken_cs, & creator1, & salt1, b"" , 32 ) . unwrap_err( ) ,
710
730
Instantiate2AddressError :: InvalidChecksumLength
711
731
) ) ;
712
732
}
713
733
734
+ #[ test]
735
+ fn instantiate2_address_impl_truncates_address_data_to_first_len_bytes ( ) {
736
+ // test data from above
737
+ let checksum =
738
+ HexBinary :: from_hex ( "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5" )
739
+ . unwrap ( ) ;
740
+ let creator = CanonicalAddr :: from ( hex ! ( "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc" ) ) ;
741
+ let salt = hex ! ( "61" ) ;
742
+
743
+ let data = [
744
+ (
745
+ 32 ,
746
+ "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847" ,
747
+ ) ,
748
+ (
749
+ 31 ,
750
+ "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f8" ,
751
+ ) ,
752
+ (
753
+ 30 ,
754
+ "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775" ,
755
+ ) ,
756
+ ( 21 , "5e865d3e45ad3e961f77fd77d46543417ced44d924" ) ,
757
+ ( 20 , "5e865d3e45ad3e961f77fd77d46543417ced44d9" ) ,
758
+ ( 19 , "5e865d3e45ad3e961f77fd77d46543417ced44" ) ,
759
+ ( 16 , "5e865d3e45ad3e961f77fd77d4654341" ) ,
760
+ ( 8 , "5e865d3e45ad3e96" ) ,
761
+ ( 1 , "5e" ) ,
762
+ ] ;
763
+
764
+ for ( len, expected) in data {
765
+ let expected = CanonicalAddr :: from ( HexBinary :: from_hex ( expected) . unwrap ( ) ) ;
766
+ assert_eq ! (
767
+ instantiate2_address_impl( & checksum, & creator, & salt, b"" , len) . unwrap( ) ,
768
+ expected
769
+ ) ;
770
+ }
771
+ }
772
+
714
773
#[ test]
715
774
fn instantiate2_address_impl_works_for_cosmjs_test_vectors ( ) {
716
775
// Test data from https://github.com/cosmos/cosmjs/pull/1253
@@ -774,6 +833,7 @@ mod tests {
774
833
& input. creator_data . into ( ) ,
775
834
& input. salt ,
776
835
& msg,
836
+ 32 ,
777
837
)
778
838
. unwrap ( ) ;
779
839
assert_eq ! ( addr, intermediate. address_data) ;
0 commit comments