Skip to content

Commit e592f97

Browse files
committed
refactor bech32m string encoding for address and MASP addresses
1 parent 7ed315a commit e592f97

4 files changed

Lines changed: 263 additions & 195 deletions

File tree

core/src/types/address.rs

Lines changed: 27 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,20 @@ use std::fmt::{Debug, Display};
66
use std::hash::Hash;
77
use std::str::FromStr;
88

9-
use bech32::{self, FromBase32, ToBase32, Variant};
109
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
1110
use serde::{Deserialize, Serialize};
1211
use sha2::{Digest, Sha256};
13-
use thiserror::Error;
1412

15-
use crate::types::key;
13+
use crate::impl_display_and_from_str_via_format;
1614
use crate::types::key::PublicKeyHash;
15+
use crate::types::{key, string_encoding};
1716

1817
/// The length of an established [`Address`] encoded with Borsh.
1918
pub const ESTABLISHED_ADDRESS_BYTES_LEN: usize = 45;
2019

2120
/// The length of [`Address`] encoded with Bech32m.
22-
pub const ADDRESS_LEN: usize = 79 + ADDRESS_HRP.len();
21+
pub const ADDRESS_LEN: usize = 79 + string_encoding::hrp_len::<Address>();
2322

24-
/// human-readable part of Bech32m encoded address
25-
// TODO use "a" for live network
26-
const ADDRESS_HRP: &str = "atest";
27-
/// We're using "Bech32m" variant
28-
pub const BECH32M_VARIANT: bech32::Variant = Variant::Bech32m;
2923
pub(crate) const HASH_LEN: usize = 40;
3024

3125
/// An address string before bech32m encoding must be this size.
@@ -71,6 +65,12 @@ mod internal {
7165
"ano::ETH Bridge Address ";
7266
}
7367

68+
/// Error from decoding address from string
69+
pub type DecodeError = string_encoding::DecodeError;
70+
71+
/// Result of decoding address from string
72+
pub type Result<T> = std::result::Result<T, DecodeError>;
73+
7474
/// Fixed-length address strings prefix for established addresses.
7575
const PREFIX_ESTABLISHED: &str = "est";
7676
/// Fixed-length address strings prefix for implicit addresses.
@@ -80,24 +80,6 @@ const PREFIX_INTERNAL: &str = "ano";
8080
/// Fixed-length address strings prefix for IBC addresses.
8181
const PREFIX_IBC: &str = "ibc";
8282

83-
#[allow(missing_docs)]
84-
#[derive(Error, Debug)]
85-
pub enum DecodeError {
86-
#[error("Error decoding address from Bech32m: {0}")]
87-
DecodeBech32(bech32::Error),
88-
#[error("Error decoding address from base32: {0}")]
89-
DecodeBase32(bech32::Error),
90-
#[error("Unexpected Bech32m human-readable part {0}, expected {1}")]
91-
UnexpectedBech32Prefix(String, String),
92-
#[error("Unexpected Bech32m variant {0:?}, expected {BECH32M_VARIANT:?}")]
93-
UnexpectedBech32Variant(bech32::Variant),
94-
#[error("Invalid address encoding")]
95-
InvalidInnerEncoding(std::io::Error),
96-
}
97-
98-
/// Result of a function that may fail
99-
pub type Result<T> = std::result::Result<T, DecodeError>;
100-
10183
/// An account's address
10284
#[derive(
10385
Clone,
@@ -122,34 +104,12 @@ pub enum Address {
122104
impl Address {
123105
/// Encode an address with Bech32m encoding
124106
pub fn encode(&self) -> String {
125-
let bytes = self.to_fixed_len_string();
126-
bech32::encode(ADDRESS_HRP, bytes.to_base32(), BECH32M_VARIANT)
127-
.unwrap_or_else(|_| {
128-
panic!(
129-
"The human-readable part {} should never cause a failure",
130-
ADDRESS_HRP
131-
)
132-
})
107+
string_encoding::Format::encode(self)
133108
}
134109

135110
/// Decode an address from Bech32m encoding
136111
pub fn decode(string: impl AsRef<str>) -> Result<Self> {
137-
let (prefix, hash_base32, variant) = bech32::decode(string.as_ref())
138-
.map_err(DecodeError::DecodeBech32)?;
139-
if prefix != ADDRESS_HRP {
140-
return Err(DecodeError::UnexpectedBech32Prefix(
141-
prefix,
142-
ADDRESS_HRP.into(),
143-
));
144-
}
145-
match variant {
146-
BECH32M_VARIANT => {}
147-
_ => return Err(DecodeError::UnexpectedBech32Variant(variant)),
148-
}
149-
let bytes: Vec<u8> = FromBase32::from_base32(&hash_base32)
150-
.map_err(DecodeError::DecodeBase32)?;
151-
Self::try_from_fixed_len_string(&mut &bytes[..])
152-
.map_err(DecodeError::InvalidInnerEncoding)
112+
string_encoding::Format::decode(string)
153113
}
154114

155115
/// Try to get a raw hash of an address, only defined for established and
@@ -163,7 +123,7 @@ impl Address {
163123
}
164124

165125
/// Convert an address to a fixed length 7-bit ascii string bytes
166-
fn to_fixed_len_string(&self) -> Vec<u8> {
126+
pub fn to_fixed_len_string(&self) -> Vec<u8> {
167127
let mut string = match self {
168128
Address::Established(EstablishedAddress { hash }) => {
169129
format!("{}::{}", PREFIX_ESTABLISHED, hash)
@@ -209,7 +169,7 @@ impl Address {
209169
}
210170

211171
/// Try to parse an address from fixed-length utf-8 encoded address string.
212-
fn try_from_fixed_len_string(buf: &mut &[u8]) -> std::io::Result<Self> {
172+
pub fn try_from_fixed_len_string(buf: &mut &[u8]) -> std::io::Result<Self> {
213173
use std::io::{Error, ErrorKind};
214174
let string = std::str::from_utf8(buf)
215175
.map_err(|err| Error::new(ErrorKind::InvalidData, err))?;
@@ -302,6 +262,20 @@ impl Address {
302262
}
303263
}
304264

265+
impl string_encoding::Format for Address {
266+
const HRP: &'static str = string_encoding::ADDRESS_HRP;
267+
268+
fn to_bytes(&self) -> Vec<u8> {
269+
Self::to_fixed_len_string(self)
270+
}
271+
272+
fn decode_bytes(bytes: &[u8]) -> std::result::Result<Self, std::io::Error> {
273+
Self::try_from_fixed_len_string(&mut &bytes[..])
274+
}
275+
}
276+
277+
impl_display_and_from_str_via_format!(Address);
278+
305279
impl serde::Serialize for Address {
306280
fn serialize<S>(
307281
&self,
@@ -326,26 +300,12 @@ impl<'de> serde::Deserialize<'de> for Address {
326300
}
327301
}
328302

329-
impl Display for Address {
330-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
331-
write!(f, "{}", self.encode())
332-
}
333-
}
334-
335303
impl Debug for Address {
336304
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
337305
self.pretty_fmt(f)
338306
}
339307
}
340308

341-
impl FromStr for Address {
342-
type Err = DecodeError;
343-
344-
fn from_str(s: &str) -> Result<Self> {
345-
Address::decode(s)
346-
}
347-
}
348-
349309
/// An established address is generated on-chain
350310
#[derive(
351311
Debug,

0 commit comments

Comments
 (0)