Add util functions for bytes32 string encoding/decoding (#337)
This commit is contained in:
parent
330b62c986
commit
4afa1c9517
|
@ -808,6 +808,7 @@ dependencies = [
|
|||
"generic-array 0.14.4",
|
||||
"glob",
|
||||
"hex",
|
||||
"hex-literal",
|
||||
"k256",
|
||||
"once_cell",
|
||||
"rand 0.8.4",
|
||||
|
@ -1174,6 +1175,12 @@ version = "0.4.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76505e26b6ca3bbdbbb360b68472abbb80998c5fa5dc43672eca34f28258e138"
|
||||
|
||||
[[package]]
|
||||
name = "hidapi"
|
||||
version = "1.2.6"
|
||||
|
|
|
@ -44,7 +44,7 @@ ethers = { version = "0.4.0", path = "../ethers" }
|
|||
serde_json = { version = "1.0.64", default-features = false }
|
||||
bincode = { version = "1.3.3", default-features = false }
|
||||
once_cell = { version = "1.8.0" }
|
||||
|
||||
hex-literal = "0.3.2"
|
||||
|
||||
[features]
|
||||
celo = [] # celo support extends the transaction format with extra fields
|
||||
|
|
|
@ -36,6 +36,13 @@ pub use rlp;
|
|||
use crate::types::{Address, Bytes, U256};
|
||||
use k256::{ecdsa::SigningKey, EncodedPoint as K256PublicKey};
|
||||
use std::convert::TryInto;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FormatBytes32StringError {
|
||||
#[error("bytes32 strings must not exceed 32 bytes in length")]
|
||||
TextTooLong,
|
||||
}
|
||||
|
||||
/// 1 Ether = 1e18 Wei == 0x0de0b6b3a7640000 Wei
|
||||
pub const WEI_IN_ETHER: U256 = U256([0x0de0b6b3a7640000, 0x0, 0x0, 0x0]);
|
||||
|
@ -156,6 +163,30 @@ pub fn to_checksum(addr: &Address, chain_id: Option<u8>) -> String {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns a bytes32 string representation of text. If the length of text exceeds 32 bytes,
|
||||
/// an error is returned.
|
||||
pub fn format_bytes32_string(text: &str) -> Result<[u8; 32], FormatBytes32StringError> {
|
||||
let str_bytes: &[u8] = text.as_bytes();
|
||||
if str_bytes.len() > 32 {
|
||||
return Err(FormatBytes32StringError::TextTooLong);
|
||||
}
|
||||
|
||||
let mut bytes32: [u8; 32] = [0u8; 32];
|
||||
bytes32[..str_bytes.len()].copy_from_slice(str_bytes);
|
||||
|
||||
Ok(bytes32)
|
||||
}
|
||||
|
||||
/// Returns the decoded string represented by the bytes32 encoded data.
|
||||
pub fn parse_bytes32_string(bytes: &[u8; 32]) -> Result<&str, std::str::Utf8Error> {
|
||||
let mut length = 0;
|
||||
while length < 32 && bytes[length] != 0 {
|
||||
length += 1;
|
||||
}
|
||||
|
||||
std::str::from_utf8(&bytes[..length])
|
||||
}
|
||||
|
||||
/// A bit of hack to find an unused TCP port.
|
||||
///
|
||||
/// Does not guarantee that the given port is unused after the function exists, just that it was
|
||||
|
@ -173,6 +204,7 @@ pub(crate) fn unused_port() -> u16 {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use hex_literal::hex;
|
||||
|
||||
#[test]
|
||||
fn wei_in_ether() {
|
||||
|
@ -359,4 +391,64 @@ mod tests {
|
|||
assert_eq!(expected, get_create2_address(from, salt, init_code))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes32_string_parsing() {
|
||||
let text_bytes_list = vec![
|
||||
(
|
||||
"",
|
||||
hex!("0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
),
|
||||
(
|
||||
"A",
|
||||
hex!("4100000000000000000000000000000000000000000000000000000000000000"),
|
||||
),
|
||||
(
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345",
|
||||
hex!("4142434445464748494a4b4c4d4e4f505152535455565758595a303132333435"),
|
||||
),
|
||||
(
|
||||
"!@#$%^&*(),./;'[]",
|
||||
hex!("21402324255e262a28292c2e2f3b275b5d000000000000000000000000000000"),
|
||||
),
|
||||
];
|
||||
|
||||
for (text, bytes) in text_bytes_list {
|
||||
assert_eq!(text, parse_bytes32_string(&bytes).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes32_string_formatting() {
|
||||
let text_bytes_list = vec![
|
||||
(
|
||||
"",
|
||||
hex!("0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
),
|
||||
(
|
||||
"A",
|
||||
hex!("4100000000000000000000000000000000000000000000000000000000000000"),
|
||||
),
|
||||
(
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345",
|
||||
hex!("4142434445464748494a4b4c4d4e4f505152535455565758595a303132333435"),
|
||||
),
|
||||
(
|
||||
"!@#$%^&*(),./;'[]",
|
||||
hex!("21402324255e262a28292c2e2f3b275b5d000000000000000000000000000000"),
|
||||
),
|
||||
];
|
||||
|
||||
for (text, bytes) in text_bytes_list {
|
||||
assert_eq!(bytes, format_bytes32_string(text).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes32_string_formatting_too_long() {
|
||||
assert!(matches!(
|
||||
format_bytes32_string("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456").unwrap_err(),
|
||||
FormatBytes32StringError::TextTooLong
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue