radix_transactions/model/hash/
encoder.rs1use bech32::{ToBase32, Variant};
2
3use crate::internal_prelude::*;
4
5pub struct TransactionHashBech32Encoder {
6 pub hrp_set: HrpSet,
7}
8
9impl TransactionHashBech32Encoder {
10 pub fn for_simulator() -> Self {
11 Self::new(&NetworkDefinition::simulator())
12 }
13
14 pub fn new(network: &NetworkDefinition) -> Self {
15 Self {
16 hrp_set: network.into(),
17 }
18 }
19
20 pub fn encode<T>(&self, hash: &T) -> Result<String, TransactionHashBech32EncodeError>
21 where
22 T: IsTransactionHash,
23 {
24 let mut buf = String::new();
25 self.encode_to_fmt(&mut buf, hash)?;
26 Ok(buf)
27 }
28
29 pub fn encode_to_fmt<T, F>(
30 &self,
31 fmt: &mut F,
32 hash: &T,
33 ) -> Result<(), TransactionHashBech32EncodeError>
34 where
35 T: IsTransactionHash,
36 F: fmt::Write,
37 {
38 let hrp = hash.hrp(&self.hrp_set);
39 let data = hash.as_inner_hash().as_slice();
40 Self::encode_to_fmt_raw(fmt, hrp, data)
41 }
42
43 fn encode_to_fmt_raw<F: fmt::Write>(
44 fmt: &mut F,
45 hrp: &str,
46 data: &[u8],
47 ) -> Result<(), TransactionHashBech32EncodeError> {
48 match bech32_encode_to_fmt(fmt, hrp, data.to_base32(), Variant::Bech32m) {
49 Ok(Ok(())) => Ok(()),
50 Ok(Err(format_error)) => {
51 Err(TransactionHashBech32EncodeError::FormatError(format_error))
52 }
53 Err(encoding_error) => Err(TransactionHashBech32EncodeError::Bech32mEncodingError(
54 encoding_error,
55 )),
56 }
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use crate::internal_prelude::*;
63
64 #[test]
65 fn intent_hash_is_bech32_encoded_as_expected() {
66 let encoder = TransactionHashBech32Encoder::for_simulator();
68 let transaction = transaction();
69 let hash = transaction
70 .prepare(PreparationSettings::latest_ref())
71 .unwrap()
72 .transaction_intent_hash();
73
74 let encoded = encoder.encode(&hash).unwrap();
76
77 assert_eq!(
79 encoded,
80 "txid_sim1vrjkzlt8pekg5s46tum5na8lzpulvc3p72p92nkdm2dd8p0vkx2svr7ejr"
81 )
82 }
83
84 #[test]
85 fn signed_intent_hash_is_bech32_encoded_as_expected() {
86 let encoder = TransactionHashBech32Encoder::for_simulator();
88 let transaction = transaction();
89 let hash = transaction
90 .prepare(PreparationSettings::latest_ref())
91 .unwrap()
92 .signed_transaction_intent_hash();
93
94 let encoded = encoder.encode(&hash).unwrap();
96
97 assert_eq!(
99 encoded,
100 "signedintent_sim1c3f6q287pvw2pfs2extnh4yfmtc6ephgga7shf23nck85467026qrzn64x"
101 )
102 }
103
104 #[test]
105 fn notarized_transaction_hash_is_bech32_encoded_as_expected() {
106 let encoder = TransactionHashBech32Encoder::for_simulator();
108 let transaction = transaction();
109 let hash = transaction
110 .prepare(PreparationSettings::latest_ref())
111 .unwrap()
112 .notarized_transaction_hash();
113
114 let encoded = encoder.encode(&hash).unwrap();
116
117 assert_eq!(
119 encoded,
120 "notarizedtransaction_sim16aya9aqejr35u23g4gklcs3mya5nllxyy4y2y4yw9lur3wq6cdfsgpgkww"
121 )
122 }
123
124 fn transaction() -> NotarizedTransactionV1 {
125 let pk = Secp256k1PrivateKey::from_u64(1).unwrap();
126 let manifest = ManifestBuilder::new().build();
127 let header = TransactionHeaderV1 {
128 network_id: 0xf2,
129 start_epoch_inclusive: Epoch::of(0),
130 end_epoch_exclusive: Epoch::of(10),
131 nonce: 10,
132 notary_is_signatory: true,
133 notary_public_key: pk.public_key().into(),
134 tip_percentage: 0,
135 };
136 TransactionBuilder::new()
137 .manifest(manifest)
138 .header(header)
139 .notarize(&pk)
140 .build()
141 }
142}