Skip to content

Commit 7cf9747

Browse files
committed
Add encode/decod, add comprehensive test cases for encoding, decoding
1 parent f625171 commit 7cf9747

File tree

1 file changed

+131
-37
lines changed

1 file changed

+131
-37
lines changed

common/src/address.rs

Lines changed: 131 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,18 @@ impl StakeAddress {
214214
}
215215
}
216216

217-
/// Read from a string format
217+
/// Convert to string stake1xxx format
218+
pub fn to_string(&self) -> Result<String> {
219+
let hrp = match self.network {
220+
AddressNetwork::Main => bech32::Hrp::parse("stake")?,
221+
AddressNetwork::Test => bech32::Hrp::parse("stake_test")?,
222+
};
223+
224+
let data = self.to_binary();
225+
Ok(bech32::encode::<bech32::Bech32>(hrp, &data)?)
226+
}
227+
228+
/// Read from a string format ("stake1xxx...")
218229
pub fn from_string(text: &str) -> Result<Self> {
219230
let (hrp, data) = bech32::decode(text)?;
220231
if let Some(header) = data.first() {
@@ -235,6 +246,23 @@ impl StakeAddress {
235246
Err(anyhow!("Empty stake address data"))
236247
}
237248

249+
/// Convert to binary format (29 bytes)
250+
pub fn to_binary(&self) -> Vec<u8> {
251+
let network_bits = match self.network {
252+
AddressNetwork::Main => 0b1u8,
253+
AddressNetwork::Test => 0b0u8,
254+
};
255+
256+
let (stake_bits, stake_hash): (u8, &Vec<u8>) = match &self.payload {
257+
StakeAddressPayload::StakeKeyHash(data) => (0b1110, data),
258+
StakeAddressPayload::ScriptHash(data) => (0b1111, data),
259+
};
260+
261+
let mut data = vec![network_bits | (stake_bits << 4)];
262+
data.extend(stake_hash);
263+
data
264+
}
265+
238266
/// Read from binary format (29 bytes)
239267
pub fn from_binary(data: &[u8]) -> Result<Self> {
240268
if data.len() != 29 {
@@ -252,24 +280,7 @@ impl StakeAddress {
252280
_ => bail!("Unknown header byte {:x} in stake address", data[0]),
253281
};
254282

255-
return Ok(StakeAddress { network, payload });
256-
}
257-
258-
/// Convert to string stake1xxx form
259-
pub fn to_string(&self) -> Result<String> {
260-
let (hrp, network_bits) = match self.network {
261-
AddressNetwork::Main => (bech32::Hrp::parse("stake")?, 1u8),
262-
AddressNetwork::Test => (bech32::Hrp::parse("stake_test")?, 0u8),
263-
};
264-
265-
let (stake_hash, stake_bits): (&Vec<u8>, u8) = match &self.payload {
266-
StakeAddressPayload::StakeKeyHash(data) => (data, 0b1110),
267-
StakeAddressPayload::ScriptHash(data) => (data, 0b1111),
268-
};
269-
270-
let mut data = vec![network_bits | (stake_bits << 4)];
271-
data.extend(stake_hash);
272-
Ok(bech32::encode::<bech32::Bech32>(hrp, &data)?)
283+
Ok(StakeAddress { network, payload })
273284
}
274285
}
275286

@@ -279,20 +290,8 @@ impl<C> minicbor::Encode<C> for StakeAddress {
279290
e: &mut minicbor::Encoder<W>,
280291
_ctx: &mut C,
281292
) -> Result<(), minicbor::encode::Error<W::Error>> {
282-
let network_bits = match self.network {
283-
AddressNetwork::Main => 0b1u8,
284-
AddressNetwork::Test => 0b0u8,
285-
};
286-
287-
let (stake_bits, stake_hash): (u8, &Vec<u8>) = match &self.payload {
288-
StakeAddressPayload::StakeKeyHash(data) => (0b1110, data),
289-
StakeAddressPayload::ScriptHash(data) => (0b1111, data),
290-
};
291-
292-
let mut data = vec![network_bits | (stake_bits << 4)];
293-
data.extend(stake_hash);
294-
295-
e.bytes(&data)?;
293+
let bytes = self.to_binary();
294+
e.writer_mut().write_all(&bytes).map_err(|err| minicbor::encode::Error::write(err))?;
296295
Ok(())
297296
}
298297
}
@@ -302,8 +301,7 @@ impl<'b, C> minicbor::Decode<'b, C> for StakeAddress {
302301
d: &mut minicbor::Decoder<'b>,
303302
_ctx: &mut C,
304303
) -> Result<Self, minicbor::decode::Error> {
305-
let bytes = d.bytes()?;
306-
StakeAddress::from_binary(bytes)
304+
StakeAddress::from_binary(d.input())
307305
.map_err(|e| minicbor::decode::Error::message(e.to_string()))
308306
}
309307
}
@@ -340,10 +338,10 @@ impl Address {
340338
return Some(ptr.clone());
341339
}
342340
}
343-
return None;
341+
None
344342
}
345343

346-
/// Read from string format
344+
/// Read from string format ("addr1...")
347345
pub fn from_string(text: &str) -> Result<Self> {
348346
if text.starts_with("addr1") || text.starts_with("addr_test1") {
349347
Ok(Self::Shelley(ShelleyAddress::from_string(text)?))
@@ -374,6 +372,7 @@ impl Address {
374372
mod tests {
375373
use super::*;
376374
use crate::crypto::keyhash_224;
375+
use minicbor::{Decode, Encode};
377376

378377
#[test]
379378
fn byron_address() {
@@ -637,4 +636,99 @@ mod tests {
637636
"558f3ee09b26d88fac2eddc772a9eda94cce6dbadbe9fee439bd6001"
638637
);
639638
}
639+
640+
fn mainnet_stake_address() -> StakeAddress {
641+
let binary =
642+
hex::decode("e1558f3ee09b26d88fac2eddc772a9eda94cce6dbadbe9fee439bd6001").unwrap();
643+
StakeAddress::from_binary(&binary).unwrap()
644+
}
645+
646+
fn testnet_stake_address() -> StakeAddress {
647+
let binary =
648+
hex::decode("e0558f3ee09b26d88fac2eddc772a9eda94cce6dbadbe9fee439bd6001").unwrap();
649+
StakeAddress::from_binary(&binary).unwrap()
650+
}
651+
652+
#[test]
653+
fn stake_addresses_encode_mainnet_stake() {
654+
let address = mainnet_stake_address();
655+
let expected = address.to_binary();
656+
657+
let mut actual = Vec::new();
658+
let mut encoder = minicbor::Encoder::new(&mut actual);
659+
let result = address.encode(&mut encoder, &mut ());
660+
661+
assert!(result.is_ok());
662+
assert_eq!(actual.len(), 29);
663+
assert_eq!(&actual[..], &expected[..]);
664+
}
665+
666+
#[test]
667+
fn stake_addresses_decode_mainnet_stake() {
668+
let binary = mainnet_stake_address().to_binary();
669+
670+
let mut decoder = minicbor::Decoder::new(&binary);
671+
let decoded = StakeAddress::decode(&mut decoder, &mut ()).unwrap();
672+
673+
assert_eq!(decoded.network, AddressNetwork::Main);
674+
assert_eq!(
675+
match decoded.payload {
676+
StakeAddressPayload::StakeKeyHash(key) => hex::encode(&key),
677+
_ => "STAKE".to_string(),
678+
},
679+
"558f3ee09b26d88fac2eddc772a9eda94cce6dbadbe9fee439bd6001"
680+
);
681+
}
682+
#[test]
683+
fn stake_addresses_round_trip_mainnet_stake() {
684+
let binary =
685+
hex::decode("f1558f3ee09b26d88fac2eddc772a9eda94cce6dbadbe9fee439bd6001").unwrap();
686+
let original = StakeAddress::from_binary(&binary).unwrap();
687+
688+
let mut encoded = Vec::new();
689+
let mut encoder = minicbor::Encoder::new(&mut encoded);
690+
original.encode(&mut encoder, &mut ()).unwrap();
691+
692+
let mut decoder = minicbor::Decoder::new(&encoded);
693+
let decoded = StakeAddress::decode(&mut decoder, &mut ()).unwrap();
694+
695+
assert_eq!(decoded.network, AddressNetwork::Main);
696+
assert_eq!(
697+
match decoded.payload {
698+
StakeAddressPayload::ScriptHash(key) => hex::encode(&key),
699+
_ => "STAKE".to_string(),
700+
},
701+
"558f3ee09b26d88fac2eddc772a9eda94cce6dbadbe9fee439bd6001"
702+
);
703+
}
704+
705+
#[test]
706+
fn stake_addresses_roundtrip_testnet_stake() {
707+
let original = testnet_stake_address();
708+
709+
let mut encoded = Vec::new();
710+
let mut encoder = minicbor::Encoder::new(&mut encoded);
711+
original.encode(&mut encoder, &mut ()).unwrap();
712+
713+
let mut decoder = minicbor::Decoder::new(&encoded);
714+
let decoded = StakeAddress::decode(&mut decoder, &mut ()).unwrap();
715+
716+
assert_eq!(decoded.network, AddressNetwork::Test);
717+
assert_eq!(
718+
match decoded.payload {
719+
StakeAddressPayload::StakeKeyHash(key) => hex::encode(&key),
720+
_ => "SCRIPT".to_string(),
721+
},
722+
"558f3ee09b26d88fac2eddc772a9eda94cce6dbadbe9fee439bd6001"
723+
);
724+
}
725+
726+
#[test]
727+
fn stake_addresses_decode_invalid_length() {
728+
let bad_data = vec![0xe1, 0x00, 0x01, 0x02, 0x03];
729+
let mut decoder = minicbor::Decoder::new(&bad_data);
730+
731+
let result = StakeAddress::decode(&mut decoder, &mut ());
732+
assert!(result.is_err());
733+
}
640734
}

0 commit comments

Comments
 (0)