Skip to content

Commit b2f971f

Browse files
committed
Add new len param to instantiate2_address_impl
1 parent 80473e1 commit b2f971f

File tree

2 files changed

+73
-11
lines changed

2 files changed

+73
-11
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ and this project adheres to
2424
- cosmwasm-std: Document safety invariants of the internal memory repr ([#2344])
2525
- cosmwasm-std: Enforce non-null pointers using `ptr::NonNull` in the internal
2626
memory repr ([#2344])
27+
- cosmwasm-std: Let private `instantiate2_address_impl` take a new `len`
28+
argument to allow truncating address data as part of the generation process.
2729

2830
## Fixed
2931

packages/std/src/addresses.rs

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -313,18 +313,28 @@ pub fn instantiate2_address(
313313
// Non-empty msg values are discouraged.
314314
// See https://medium.com/cosmwasm/dev-note-3-limitations-of-instantiate2-and-how-to-deal-with-them-a3f946874230.
315315
let msg = b"";
316-
instantiate2_address_impl(checksum, creator, salt, msg)
316+
let len = 32;
317+
instantiate2_address_impl(checksum, creator, salt, msg, len)
317318
}
318319

319320
/// The instantiate2 address derivation implementation. This API is used for
320321
/// testing purposes only. The `msg` field is discouraged and should not be used.
321322
/// 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>.
322331
#[doc(hidden)]
323332
fn instantiate2_address_impl(
324333
checksum: &[u8],
325334
creator: &CanonicalAddr,
326335
salt: &[u8],
327336
msg: &[u8],
337+
len: usize,
328338
) -> Result<CanonicalAddr, Instantiate2AddressError> {
329339
if checksum.len() != 32 {
330340
return Err(Instantiate2AddressError::InvalidChecksumLength);
@@ -344,7 +354,17 @@ fn instantiate2_address_impl(
344354
key.extend_from_slice(salt);
345355
key.extend_from_slice(&(msg.len() as u64).to_be_bytes());
346356
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+
348368
Ok(address_data.into())
349369
}
350370

@@ -650,7 +670,7 @@ mod tests {
650670
"5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847"
651671
));
652672
assert_eq!(
653-
instantiate2_address_impl(&checksum1, &creator1, &salt1, msg1).unwrap(),
673+
instantiate2_address_impl(&checksum1, &creator1, &salt1, msg1, 32).unwrap(),
654674
expected
655675
);
656676

@@ -659,7 +679,7 @@ mod tests {
659679
"0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835"
660680
));
661681
assert_eq!(
662-
instantiate2_address_impl(&checksum1, &creator1, &salt1, msg2).unwrap(),
682+
instantiate2_address_impl(&checksum1, &creator1, &salt1, msg2, 32).unwrap(),
663683
expected
664684
);
665685

@@ -668,7 +688,7 @@ mod tests {
668688
"83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167"
669689
));
670690
assert_eq!(
671-
instantiate2_address_impl(&checksum1, &creator1, &salt1, msg3).unwrap(),
691+
instantiate2_address_impl(&checksum1, &creator1, &salt1, msg3, 32).unwrap(),
672692
expected
673693
);
674694

@@ -677,40 +697,79 @@ mod tests {
677697
"9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564"
678698
));
679699
assert_eq!(
680-
instantiate2_address_impl(&checksum1, &creator1, &salt2, b"").unwrap(),
700+
instantiate2_address_impl(&checksum1, &creator1, &salt2, b"", 32).unwrap(),
681701
expected
682702
);
683703

684704
// Salt too short or too long
685705
let empty = Vec::<u8>::new();
686706
assert!(matches!(
687-
instantiate2_address_impl(&checksum1, &creator1, &empty, b"").unwrap_err(),
707+
instantiate2_address_impl(&checksum1, &creator1, &empty, b"", 32).unwrap_err(),
688708
Instantiate2AddressError::InvalidSaltLength
689709
));
690710
let too_long = vec![0x11; 65];
691711
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(),
693713
Instantiate2AddressError::InvalidSaltLength
694714
));
695715

696716
// invalid checksum length
697717
let broken_cs = hex!("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2");
698718
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(),
700720
Instantiate2AddressError::InvalidChecksumLength
701721
));
702722
let broken_cs = hex!("");
703723
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(),
705725
Instantiate2AddressError::InvalidChecksumLength
706726
));
707727
let broken_cs = hex!("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2aaaa");
708728
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(),
710730
Instantiate2AddressError::InvalidChecksumLength
711731
));
712732
}
713733

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+
714773
#[test]
715774
fn instantiate2_address_impl_works_for_cosmjs_test_vectors() {
716775
// Test data from https://github.com/cosmos/cosmjs/pull/1253
@@ -774,6 +833,7 @@ mod tests {
774833
&input.creator_data.into(),
775834
&input.salt,
776835
&msg,
836+
32,
777837
)
778838
.unwrap();
779839
assert_eq!(addr, intermediate.address_data);

0 commit comments

Comments
 (0)