Skip to content

Commit

Permalink
Merge branch 'tomas/fix-addr-storage-key-ord' (#1256)
Browse files Browse the repository at this point in the history
* tomas/fix-addr-storage-key-ord:
  changelog: add #1256
  [ci] wasm checksums update
  core/types/address: order addresses by their string (bech32m) format
  tets/core/storage: add a test for order of addresses in storage keys
  • Loading branch information
tzemanovic committed Apr 11, 2023
2 parents 5edb5b8 + eeec602 commit 80f7700
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Addresses are now being ordered by their string format (bech32m)
to ensure that their order is preserved inside raw storage keys.
([#1256](https://github.com/anoma/namada/pull/1256))
25 changes: 16 additions & 9 deletions core/src/types/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,7 @@ pub type Result<T> = std::result::Result<T, DecodeError>;

/// An account's address
#[derive(
Clone,
BorshSerialize,
BorshDeserialize,
BorshSchema,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Clone, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq, Eq, Hash,
)]
pub enum Address {
/// An established address is generated on-chain
Expand All @@ -123,6 +115,21 @@ pub enum Address {
Internal(InternalAddress),
}

// We're using the string format of addresses (bech32m) for ordering to ensure
// that addresses as strings, storage keys and storage keys as strings preserve
// the order.
impl PartialOrd for Address {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.encode().partial_cmp(&other.encode())
}
}

impl Ord for Address {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.encode().cmp(&other.encode())
}
}

impl Address {
/// Encode an address with Bech32m encoding
pub fn encode(&self) -> String {
Expand Down
43 changes: 43 additions & 0 deletions core/src/types/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,7 @@ mod tests {
use proptest::prelude::*;

use super::*;
use crate::types::address::testing::arb_address;

proptest! {
/// Tests that any key that doesn't contain reserved prefixes is valid.
Expand Down Expand Up @@ -1380,6 +1381,48 @@ mod tests {
assert_eq!(epochs.get_epoch(BlockHeight(550)), Some(Epoch(7)));
assert_eq!(epochs.get_epoch(BlockHeight(600)), Some(Epoch(8)));
}

proptest! {
/// Ensure that addresses in storage keys preserve the order of the
/// addresses.
#[test]
fn test_address_in_storage_key_order(
addr1 in arb_address(),
addr2 in arb_address(),
) {
test_address_in_storage_key_order_aux(addr1, addr2)
}
}

fn test_address_in_storage_key_order_aux(addr1: Address, addr2: Address) {
println!("addr1 {addr1}");
println!("addr2 {addr2}");
let expected_order = addr1.cmp(&addr2);

// Turn the addresses into strings
let str1 = addr1.to_string();
let str2 = addr2.to_string();
println!("addr1 str {str1}");
println!("addr1 str {str2}");
let order = str1.cmp(&str2);
assert_eq!(order, expected_order);

// Turn the addresses into storage keys
let key1 = Key::from(addr1.to_db_key());
let key2 = Key::from(addr2.to_db_key());
println!("addr1 key {key1}");
println!("addr2 key {key2}");
let order = key1.cmp(&key2);
assert_eq!(order, expected_order);

// Turn the addresses into raw storage keys (formatted to strings)
let raw1 = addr1.raw();
let raw2 = addr2.raw();
println!("addr 1 raw {raw1}");
println!("addr 2 raw {raw2}");
let order = raw1.cmp(&raw2);
assert_eq!(order, expected_order);
}
}

/// Helpers for testing with storage types.
Expand Down

0 comments on commit 80f7700

Please sign in to comment.