From af3c15b56af24557a81e6fca90909d7f06b83e72 Mon Sep 17 00:00:00 2001 From: Santiago Carmuega Date: Wed, 26 Jan 2022 18:11:25 -0300 Subject: [PATCH 1/3] fix: Make bech32 encoding network-aware --- src/mapper/crawl.rs | 7 +++-- src/mapper/map.rs | 31 ++------------------- src/mapper/prelude.rs | 25 +++++++++++++++-- src/utils/bech32.rs | 65 +++++++++++++++++++++++++++++++++++++++++++ src/utils/mod.rs | 1 + 5 files changed, 97 insertions(+), 32 deletions(-) create mode 100644 src/utils/bech32.rs diff --git a/src/mapper/crawl.rs b/src/mapper/crawl.rs index 2dcac68b..d5a4f0c8 100644 --- a/src/mapper/crawl.rs +++ b/src/mapper/crawl.rs @@ -5,7 +5,7 @@ use pallas::ledger::alonzo::{ use crate::framework::{Error, EventContext, EventData}; -use super::{map::ToBech32, EventWriter}; +use super::EventWriter; impl EventWriter { fn crawl_metadata(&self, metadata: &Metadata) -> Result<(), Error> { @@ -81,7 +81,10 @@ impl EventWriter { self.append(record.into())?; let child = &self.child_writer(EventContext { - output_address: output.address.try_to_bech32("addr")?.into(), + output_address: self + .bech32_provider + .encode_address(output.address.as_slice())? + .into(), ..EventContext::default() }); diff --git a/src/mapper/map.rs b/src/mapper/map.rs index 753fa346..5d79ef13 100644 --- a/src/mapper/map.rs +++ b/src/mapper/map.rs @@ -7,8 +7,6 @@ use pallas::ledger::alonzo::{ }; use pallas::ledger::alonzo::{NetworkId, TransactionBody, TransactionBodyComponent}; -use bech32::{self, ToBase32}; - use serde_json::{json, Value as JsonValue}; use crate::framework::{ @@ -39,17 +37,6 @@ impl From<&alonzo::StakeCredential> for StakeCredential { } } -pub trait ToBech32 { - fn try_to_bech32(&self, hrp: &str) -> Result; -} - -impl ToBech32 for Vec { - fn try_to_bech32(&self, hrp: &str) -> Result { - let enc = bech32::encode(hrp, self.to_base32(), bech32::Variant::Bech32)?; - Ok(enc) - } -} - fn ip_string_from_bytes(bytes: &[u8]) -> String { format!("{}.{}.{}.{}", bytes[0], bytes[1], bytes[2], bytes[3]) } @@ -157,8 +144,9 @@ impl EventWriter { output: &TransactionOutput, ) -> Result { Ok(TxOutputRecord { - // TODO: add correct bech32 prefix depending on network - address: output.address.try_to_bech32("addr")?, + address: self + .bech32_provider + .encode_address(output.address.as_slice())?, amount: get_tx_output_coin_value(&output.amount), assets: self.collect_asset_records(&output.amount).into(), }) @@ -360,16 +348,3 @@ impl EventWriter { }) } } - -#[cfg(test)] -mod tests { - use super::ToBech32; - - #[test] - fn beach32_encodes_ok() { - let bytes = hex::decode("01ec6ad5daee9febbe300c6160a36d4daf0c5266ae2fe8245cbb581390629814d8165fd547b6f3f6f55842a5f042bcb113e8e86627bc071f37").unwrap(); - let bech32 = bytes.try_to_bech32("addr").unwrap(); - - assert_eq!(bech32, "addr1q8kx44w6a607h03sp3skpgmdfkhsc5nx4ch7sfzuhdvp8yrznq2ds9jl64rmdulk74vy9f0sg27tzylgapnz00q8rumsuhj834"); - } -} diff --git a/src/mapper/prelude.rs b/src/mapper/prelude.rs index 087d52fb..ce8b59c4 100644 --- a/src/mapper/prelude.rs +++ b/src/mapper/prelude.rs @@ -1,7 +1,10 @@ use crate::{ framework::{Event, EventContext, EventData}, pipelining::StageSender, - utils::time::{NaiveConfig as TimeConfig, NaiveProvider as NaiveTime, TimeProvider}, + utils::{ + bech32::{Bech32Config, Bech32Provider}, + time::{NaiveConfig as TimeConfig, NaiveProvider as NaiveTime, TimeProvider}, + }, }; use merge::Merge; use serde::Deserialize; @@ -20,6 +23,7 @@ pub struct ChainWellKnownInfo { pub shelley_known_slot: u64, pub shelley_known_hash: String, pub shelley_known_time: u64, + pub address_hrp: String, } impl ChainWellKnownInfo { @@ -31,6 +35,7 @@ impl ChainWellKnownInfo { shelley_known_hash: "aa83acbf5904c0edfe4d79b3689d3d00fcfc553cf360fd2229b98d464c28e9de".to_string(), shelley_known_time: 1596059091, + address_hrp: "addr".to_string(), }), TESTNET_MAGIC => Ok(ChainWellKnownInfo { shelley_slot_length: 1, @@ -38,6 +43,7 @@ impl ChainWellKnownInfo { shelley_known_hash: "02b1c561715da9e540411123a6135ee319b02f60b9a11a603d3305556c04329f".to_string(), shelley_known_time: 1595967616, + address_hrp: "addr_test".to_string(), }), _ => Err("can't infer well-known chain infro from specified magic".into()), } @@ -68,6 +74,14 @@ impl TryFrom for Point { } } +impl From for Bech32Config { + fn from(other: ChainWellKnownInfo) -> Self { + Bech32Config { + address_hrp: other.address_hrp, + } + } +} + #[derive(Deserialize, Clone, Debug, Default)] pub struct Config { #[serde(default)] @@ -85,6 +99,7 @@ pub(crate) struct EventWriter { context: EventContext, output: StageSender, time_provider: Option, + pub(crate) bech32_provider: Bech32Provider, pub(crate) config: Config, } @@ -97,7 +112,11 @@ impl EventWriter { EventWriter { context: EventContext::default(), output, - time_provider: well_known.map(|x| NaiveTime::new(x.into())), + time_provider: well_known.clone().map(|x| NaiveTime::new(x.into())), + bech32_provider: well_known.map_or_else( + || Bech32Provider::default(), + |x| Bech32Provider::new(x.into()), + ), config, } } @@ -126,10 +145,12 @@ impl EventWriter { pub fn child_writer(&self, mut extra_context: EventContext) -> EventWriter { extra_context.merge(self.context.clone()); + // TODO: too much cloning, lets move to lifecycles here EventWriter { context: extra_context, output: self.output.clone(), time_provider: self.time_provider.clone(), + bech32_provider: self.bech32_provider.clone(), config: self.config.clone(), } } diff --git a/src/utils/bech32.rs b/src/utils/bech32.rs new file mode 100644 index 00000000..39f67a1a --- /dev/null +++ b/src/utils/bech32.rs @@ -0,0 +1,65 @@ +//! Bech32 encoding utils +//! +//! Provides artifacts for encoding different values into bech32 format taking +//! into account the context provided via configuration. + +use bech32::{self, ToBase32}; +use serde::Deserialize; + +use crate::Error; + +#[derive(Clone, Deserialize)] +pub struct Bech32Config { + pub address_hrp: String, +} + +impl Default for Bech32Config { + fn default() -> Self { + Self { + address_hrp: "addr".to_string(), + } + } +} + +#[derive(Clone)] +pub struct Bech32Provider(Bech32Config); + +impl Bech32Provider { + pub fn new(config: Bech32Config) -> Self { + Bech32Provider(config) + } + + pub fn encode_address(&self, data: &[u8]) -> Result { + let enc = bech32::encode( + &self.0.address_hrp, + data.to_base32(), + bech32::Variant::Bech32, + )?; + + Ok(enc) + } +} + +impl Default for Bech32Provider { + fn default() -> Self { + Self(Default::default()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn beach32_encodes_ok() { + let provider = Bech32Provider::new(Bech32Config { + address_hrp: "addr".to_string(), + }); + + let bytes = hex::decode("01ec6ad5daee9febbe300c6160a36d4daf0c5266ae2fe8245cbb581390629814d8165fd547b6f3f6f55842a5f042bcb113e8e86627bc071f37").unwrap(); + + let bech32 = provider.encode_address(bytes.as_slice()).unwrap(); + + assert_eq!(bech32, "addr1q8kx44w6a607h03sp3skpgmdfkhsc5nx4ch7sfzuhdvp8yrznq2ds9jl64rmdulk74vy9f0sg27tzylgapnz00q8rumsuhj834"); + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 227064f8..d34cb5f3 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -2,6 +2,7 @@ use crate::framework::Error; pub mod throttle; +pub(crate) mod bech32; pub(crate) mod time; pub(crate) trait SwallowResult { From 8e241b9444d95e5051d0b82bd8e71d8cb257e6a5 Mon Sep 17 00:00:00 2001 From: Santiago Carmuega Date: Wed, 26 Jan 2022 18:15:45 -0300 Subject: [PATCH 2/3] Apply clippy suggestions --- src/mapper/prelude.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mapper/prelude.rs b/src/mapper/prelude.rs index ce8b59c4..b6bceb2d 100644 --- a/src/mapper/prelude.rs +++ b/src/mapper/prelude.rs @@ -113,10 +113,8 @@ impl EventWriter { context: EventContext::default(), output, time_provider: well_known.clone().map(|x| NaiveTime::new(x.into())), - bech32_provider: well_known.map_or_else( - || Bech32Provider::default(), - |x| Bech32Provider::new(x.into()), - ), + bech32_provider: well_known + .map_or_else(Bech32Provider::default, |x| Bech32Provider::new(x.into())), config, } } From bdbffcba606cf8d04b5cd30c95a83a282ea14331 Mon Sep 17 00:00:00 2001 From: Santiago Carmuega Date: Wed, 26 Jan 2022 18:20:42 -0300 Subject: [PATCH 3/3] Apply clippy suggestions, again --- src/utils/bech32.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/utils/bech32.rs b/src/utils/bech32.rs index 39f67a1a..c6013a5a 100644 --- a/src/utils/bech32.rs +++ b/src/utils/bech32.rs @@ -21,7 +21,7 @@ impl Default for Bech32Config { } } -#[derive(Clone)] +#[derive(Clone, Default)] pub struct Bech32Provider(Bech32Config); impl Bech32Provider { @@ -40,12 +40,6 @@ impl Bech32Provider { } } -impl Default for Bech32Provider { - fn default() -> Self { - Self(Default::default()) - } -} - #[cfg(test)] mod tests { use super::*;