depolymerization

wire gateway for Bitcoin/Ethereum
Log | Files | Refs | Submodules | README | LICENSE

commit 52e7d8b74bdf30f0b718758dc3636d0ebe17c3cf
parent 50be772c9d85eb2c1b59cd6ed9865acf7747e254
Author: Antoine A <>
Date:   Thu, 23 Nov 2023 03:52:49 +0100

Fix dirty fix

Diffstat:
Mbtc-wire/src/segwit.rs | 343++++++++++++++++++++++++++++++++++++++++---------------------------------------
Meth-wire/src/rpc.rs | 17+++--------------
Minstrumentation/src/eth.rs | 8++++----
Minstrumentation/src/main.rs | 3++-
4 files changed, 181 insertions(+), 190 deletions(-)

diff --git a/btc-wire/src/segwit.rs b/btc-wire/src/segwit.rs @@ -1,171 +1,172 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -use bech32::{u5, FromBase32, ToBase32, Variant}; -use common::{rand::rngs::OsRng, rand_slice}; - -/// Encode metadata into a segwit address -pub fn encode_segwit_addr(hrp: &str, metada: &[u8; 20]) -> String { - // We use the version 0 with bech32 encoding - let mut buf = vec![u5::try_from_u8(0).unwrap()]; - buf.extend_from_slice(&metada.to_base32()); - bech32::encode(hrp, buf, Variant::Bech32).unwrap() -} - -/// Encode half of a 32B key into a segwit address -fn encode_segwit_key_half( - hrp: &str, - is_first: bool, - prefix: &[u8; 4], - key_half: &[u8; 16], -) -> String { - // Combine prefix and the key half - let mut buf = [0u8; 20]; - buf[..4].copy_from_slice(prefix); - buf[4..].copy_from_slice(key_half); - // Toggle first bit for ordering - if is_first { - buf[0] &= 0b0111_1111 // Unset first bit - } else { - buf[0] |= 0b1000_0000 // Set first bit - } - // Encode into an fake segwit address - encode_segwit_addr(hrp, &buf) -} - -/// Encode a 32B key into two segwit adresses -pub fn encode_segwit_key(hrp: &str, msg: &[u8; 32]) -> [String; 2] { - // Generate a random prefix - let prefix = rand_slice(); - // Split key in half; - let split: (&[u8; 16], &[u8; 16]) = - (msg[..16].try_into().unwrap(), msg[16..].try_into().unwrap()); - [ - encode_segwit_key_half(hrp, true, &prefix, split.0), - encode_segwit_key_half(hrp, false, &prefix, split.1), - ] -} - -#[derive(Debug, Clone, thiserror::Error)] -pub enum DecodeSegWitErr { - #[error("There is less than 2 segwit addresses")] - MissingSegWitAddress, - #[error("No adresses are sharing a common prefix")] - NoPrefixMatch, - #[error("More than two addresses are sharing a common prefix")] - PrefixCollision, -} - -/// Decode a 32B key into from adresses -pub fn decode_segwit_msg(segwit_addrs: &[impl AsRef<str>]) -> Result<[u8; 32], DecodeSegWitErr> { - // Extract parts from every addresses - let decoded: Vec<(bool, [u8; 4], [u8; 16])> = segwit_addrs - .iter() - .filter_map(|addr| { - bech32::decode(addr.as_ref()).ok().and_then(|(_, wp, _)| { - // Skip version - let pg: Vec<u8> = Vec::from_base32(&wp[1..]).unwrap(); - if pg.len() == 20 { - let mut prefix: [u8; 4] = pg[..4].try_into().unwrap(); - let key_half: [u8; 16] = pg[4..].try_into().unwrap(); - let is_first = !pg[0] & 0b1000_0000 == 0; - // Clear first bit - prefix[0] &= 0b0111_1111; - Some((is_first, prefix, key_half)) - } else { - None - } - }) - }) - .collect(); - - if decoded.len() < 2 { - return Err(DecodeSegWitErr::MissingSegWitAddress); - } - // Keep only the addresses with duplicated prefix - // TODO use sort_unstable_by and partition_dedup_by_key when stable - let matches: Vec<&(bool, [u8; 4], [u8; 16])> = decoded - .iter() - .filter(|(_, prefix, _)| { - decoded - .iter() - .filter(|(_, other, _)| other == prefix) - .count() - > 1 - }) - .collect(); - - if matches.len() > 2 { - return Err(DecodeSegWitErr::PrefixCollision); - } else if matches.len() < 2 { - return Err(DecodeSegWitErr::MissingSegWitAddress); - } - - let mut key = [0; 32]; - for (is_first, _, half) in matches { - key[*is_first as usize * 16..][..16].copy_from_slice(half); - } - Ok(key) -} - -// TODO find a way to hide that function while using it in test and benchmark -pub fn rand_addresses(hrp: &str, key: &[u8; 32]) -> Vec<String> { - use common::rand::prelude::SliceRandom; - - let mut rng_address: Vec<String> = - std::iter::repeat_with(|| encode_segwit_addr(hrp, &rand_slice())) - .take(2) - .collect(); - - let mut addresses = encode_segwit_key(hrp, key).to_vec(); - addresses.append(&mut rng_address); - addresses.shuffle(&mut OsRng); - addresses -} - -#[cfg(test)] -mod test { - use common::{ - rand::{prelude::SliceRandom, rngs::OsRng}, - rand_slice, - }; - - use crate::segwit::{decode_segwit_msg, encode_segwit_key, rand_addresses}; - - #[test] - fn test_shuffle() { - for _ in 0..1000 { - let key = rand_slice(); - let mut addresses = encode_segwit_key("test", &key); - addresses.shuffle(&mut OsRng); - let decoded = - decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>()) - .unwrap(); - assert_eq!(key, decoded); - } - } - - #[test] - fn test_shuffle_many() { - for _ in 0..1000 { - let key = rand_slice(); - let addresses = rand_addresses("test", &key); - let decoded = - decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>()) - .unwrap(); - assert_eq!(key, decoded); - } - } -} +/* + This file is part of TALER + Copyright (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +use bech32::{u5, FromBase32, ToBase32, Variant}; +use common::{rand::rngs::OsRng, rand_slice}; +use std::cmp::Ordering; + +/// Encode metadata into a segwit address +pub fn encode_segwit_addr(hrp: &str, metada: &[u8; 20]) -> String { + // We use the version 0 with bech32 encoding + let mut buf = vec![u5::try_from_u8(0).unwrap()]; + buf.extend_from_slice(&metada.to_base32()); + bech32::encode(hrp, buf, Variant::Bech32).unwrap() +} + +/// Encode half of a 32B key into a segwit address +fn encode_segwit_key_half( + hrp: &str, + is_first: bool, + prefix: &[u8; 4], + key_half: &[u8; 16], +) -> String { + // Combine prefix and the key half + let mut buf = [0u8; 20]; + buf[..4].copy_from_slice(prefix); + buf[4..].copy_from_slice(key_half); + // Toggle first bit for ordering + if is_first { + buf[0] &= 0b0111_1111 // Unset first bit + } else { + buf[0] |= 0b1000_0000 // Set first bit + } + // Encode into an fake segwit address + encode_segwit_addr(hrp, &buf) +} + +/// Encode a 32B key into two segwit adresses +pub fn encode_segwit_key(hrp: &str, msg: &[u8; 32]) -> [String; 2] { + // Generate a random prefix + let prefix = rand_slice(); + // Split key in half; + let split: (&[u8; 16], &[u8; 16]) = + (msg[..16].try_into().unwrap(), msg[16..].try_into().unwrap()); + [ + encode_segwit_key_half(hrp, true, &prefix, split.0), + encode_segwit_key_half(hrp, false, &prefix, split.1), + ] +} + +#[derive(Debug, Clone, thiserror::Error)] +pub enum DecodeSegWitErr { + #[error("There is less than 2 segwit addresses")] + MissingSegWitAddress, + #[error("No adresses are sharing a common prefix")] + NoPrefixMatch, + #[error("More than two addresses are sharing a common prefix")] + PrefixCollision, +} + +/// Decode a 32B key into from adresses +pub fn decode_segwit_msg(segwit_addrs: &[impl AsRef<str>]) -> Result<[u8; 32], DecodeSegWitErr> { + // Extract parts from every addresses + let decoded: Vec<(bool, [u8; 4], [u8; 16])> = segwit_addrs + .iter() + .filter_map(|addr| { + bech32::decode(addr.as_ref()).ok().and_then(|(_, wp, _)| { + // Skip version + let pg: Vec<u8> = Vec::from_base32(&wp[1..]).unwrap(); + if pg.len() == 20 { + let mut prefix: [u8; 4] = pg[..4].try_into().unwrap(); + let key_half: [u8; 16] = pg[4..].try_into().unwrap(); + let is_first = !pg[0] & 0b1000_0000 == 0; + // Clear first bit + prefix[0] &= 0b0111_1111; + Some((is_first, prefix, key_half)) + } else { + None + } + }) + }) + .collect(); + + if decoded.len() < 2 { + return Err(DecodeSegWitErr::MissingSegWitAddress); + } + // Keep only the addresses with duplicated prefix + // TODO use sort_unstable_by and partition_dedup_by_key when stable + let matches: Vec<&(bool, [u8; 4], [u8; 16])> = decoded + .iter() + .filter(|(_, prefix, _)| { + decoded + .iter() + .filter(|(_, other, _)| other == prefix) + .count() + > 1 + }) + .collect(); + + match matches.len().cmp(&2) { + Ordering::Equal => { + let mut key = [0; 32]; + for (is_first, _, half) in matches { + key[*is_first as usize * 16..][..16].copy_from_slice(half); + } + Ok(key) + } + Ordering::Greater => Err(DecodeSegWitErr::PrefixCollision), + Ordering::Less => Err(DecodeSegWitErr::MissingSegWitAddress), + } +} + +// TODO find a way to hide that function while using it in test and benchmark +pub fn rand_addresses(hrp: &str, key: &[u8; 32]) -> Vec<String> { + use common::rand::prelude::SliceRandom; + + let mut rng_address: Vec<String> = + std::iter::repeat_with(|| encode_segwit_addr(hrp, &rand_slice())) + .take(2) + .collect(); + + let mut addresses = encode_segwit_key(hrp, key).to_vec(); + addresses.append(&mut rng_address); + addresses.shuffle(&mut OsRng); + addresses +} + +#[cfg(test)] +mod test { + use common::{ + rand::{prelude::SliceRandom, rngs::OsRng}, + rand_slice, + }; + + use crate::segwit::{decode_segwit_msg, encode_segwit_key, rand_addresses}; + + #[test] + fn test_shuffle() { + for _ in 0..1000 { + let key = rand_slice(); + let mut addresses = encode_segwit_key("test", &key); + addresses.shuffle(&mut OsRng); + let decoded = + decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>()) + .unwrap(); + assert_eq!(key, decoded); + } + } + + #[test] + fn test_shuffle_many() { + for _ in 0..1000 { + let key = rand_slice(); + let addresses = rand_addresses("test", &key); + let decoded = + decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>()) + .unwrap(); + assert_eq!(key, decoded); + } + } +} diff --git a/eth-wire/src/rpc.rs b/eth-wire/src/rpc.rs @@ -180,14 +180,7 @@ impl Rpc { } pub fn subscribe_new_head(&mut self) -> Result<RpcStream<Nothing>> { - self.send("eth_subscribe", &["newHeads"])?; - let id = loop { - match self.receive::<SubscribeDirtyFix>()? { - SubscribeDirtyFix::Fix(_) => { /* TODO debug */ } - SubscribeDirtyFix::Id(id) => break id, - } - }; - let id = self.handle_response(id)?; + let id: String = self.call("eth_subscribe", &["newHeads"])?; Ok(RpcStream::new(self, id)) } @@ -288,7 +281,6 @@ impl<N: Debug + DeserializeOwned> Drop for RpcStream<'_, N> { NotificationOrResponse::Response(_) => return, } } - println!("has unusubsriced") } } @@ -407,11 +399,8 @@ pub trait RpcClient { /* ----- Miner ----- */ - fn miner_set_etherbase(&mut self, addr: &H160) -> Result<()> { - match self.call("miner_setEtherbase", &[addr]) { - Err(Error::Null) => Ok(()), - i => i, - } + fn miner_set_etherbase(&mut self, addr: &H160) -> Result<bool> { + self.call("miner_setEtherbase", &[addr]) } /// Start mining diff --git a/instrumentation/src/eth.rs b/instrumentation/src/eth.rs @@ -321,7 +321,7 @@ impl EthCtx { &unused_port().to_string(), "--port", &unused_port().to_string(), - "--rpc.enabledeprecatedpersonal" + "--rpc.enabledeprecatedpersonal", ], &ctx.log("geth"), ); @@ -330,7 +330,7 @@ impl EthCtx { // Generate wallet let out = cmd_out( - &ctx.wire_bin_path, + &ctx.wire_bin_path, &["-c", ctx.conf.to_str().unwrap(), "initwallet"], ); @@ -442,7 +442,7 @@ impl EthCtx { &unused_port().to_string(), "--port", &unused_port().to_string(), - "--rpc.enabledeprecatedpersonal" + "--rpc.enabledeprecatedpersonal", ], &self.ctx.log("geth2"), ); @@ -485,7 +485,7 @@ impl EthCtx { &unused_port().to_string(), "--port", &unused_port().to_string(), - "--rpc.enabledeprecatedpersonal" + "--rpc.enabledeprecatedpersonal", ], &self.ctx.log("geth"), ); diff --git a/instrumentation/src/main.rs b/instrumentation/src/main.rs @@ -17,7 +17,8 @@ use std::{ panic::catch_unwind, path::PathBuf, - time::{Duration, Instant}, sync::{Arc, Mutex}, + sync::{Arc, Mutex}, + time::{Duration, Instant}, }; use clap::Parser;