commit 171993db6cc36166d98b940354a960c287ef6895
parent d576e6948658a54ef2612846ab2f39d094fd9ae2
Author: Antoine A <>
Date: Tue, 16 Nov 2021 11:10:52 +0100
Improve network agnosticism
Diffstat:
3 files changed, 53 insertions(+), 50 deletions(-)
diff --git a/benches/metadata.rs b/benches/metadata.rs
@@ -2,7 +2,6 @@ use criterion::{criterion_group, criterion_main, Criterion};
use depolymerization::{
decode_segwit_msg, encode_segwit_key,
utils::{rand_addresses, rand_key},
- Network,
};
fn criterion_benchmark(c: &mut Criterion) {
@@ -10,13 +9,13 @@ fn criterion_benchmark(c: &mut Criterion) {
group.bench_function("encode", |b| {
b.iter_batched(
rand_key,
- |key| encode_segwit_key(Network::MainNet, &key),
+ |key| encode_segwit_key("bench", &key),
criterion::BatchSize::SmallInput,
);
});
group.bench_function("decode", |b| {
b.iter_batched(
- || rand_addresses(Network::MainNet, &rand_key()),
+ || rand_addresses("bench", &rand_key()),
|addrs| decode_segwit_msg(&addrs),
criterion::BatchSize::SmallInput,
);
diff --git a/src/lib.rs b/src/lib.rs
@@ -1,36 +1,18 @@
use bech32::{u5, FromBase32, ToBase32, Variant};
-use bitcoincore_rpc::{Client, RpcApi, bitcoin::{Address, Amount, Txid, hashes::hex::{FromHex, ToHex}}, json::ScriptPubkeyType, jsonrpc::serde_json::{json, Value}};
+use bitcoincore_rpc::{
+ bitcoin::{
+ hashes::hex::{FromHex, ToHex},
+ Address, Amount, Network, Txid,
+ },
+ json::ScriptPubkeyType,
+ jsonrpc::serde_json::{json, Value},
+ Client, RpcApi,
+};
use rand::{rngs::OsRng, RngCore};
use rpc_patch::{ClientPatched, GetTransactionFull};
mod rpc_patch;
-/// Bitcoin networks
-#[derive(Debug, Clone, Copy)]
-pub enum Network {
- MainNet,
- TestNet,
- RegTest,
-}
-
-impl Network {
- pub fn segwit_hrp(&self) -> &'static str {
- match self {
- Network::MainNet => "bc",
- Network::TestNet => "tb",
- Network::RegTest => "bcrt",
- }
- }
-
- pub fn dir(&self) -> &'static str {
- match self {
- Network::MainNet => "mainnet",
- Network::TestNet => "testnet",
- Network::RegTest => "regtest",
- }
- }
-}
-
/// Minimum dust amount to perform a transaction to a segwit address
fn segwit_min_amount() -> Amount {
// https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.cpp
@@ -38,16 +20,16 @@ fn segwit_min_amount() -> Amount {
}
/// Encode metadata into a segwit address
-fn encode_segwit_addr(network: Network, metada: &[u8; 20]) -> String {
+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(network.segwit_hrp(), buf, Variant::Bech32).unwrap()
+ bech32::encode(hrp, buf, Variant::Bech32).unwrap()
}
/// Encode half of a 32B key into a segwit address
fn encode_segwit_key_half(
- network: Network,
+ hrp: &str,
is_first: bool,
magic_id: &[u8; 4],
key_half: &[u8; 16],
@@ -63,11 +45,11 @@ fn encode_segwit_key_half(
buf[0] |= 0b1000_0000 // Set first bit
}
// Encode into an fake segwit address
- encode_segwit_addr(network, &buf)
+ encode_segwit_addr(hrp, &buf)
}
/// Encode a 32B key into two segwit adresses
-pub fn encode_segwit_key(network: Network, msg: &[u8; 32]) -> [String; 2] {
+pub fn encode_segwit_key(hrp: &str, msg: &[u8; 32]) -> [String; 2] {
// Generate a random magic identifier
let mut magic_id = [0; 4];
OsRng.fill_bytes(&mut magic_id);
@@ -76,8 +58,8 @@ pub fn encode_segwit_key(network: Network, msg: &[u8; 32]) -> [String; 2] {
split.0.copy_from_slice(&msg[..16]);
split.1.copy_from_slice(&msg[16..]);
[
- encode_segwit_key_half(network, true, &magic_id, &split.0),
- encode_segwit_key_half(network, false, &magic_id, &split.1),
+ encode_segwit_key_half(hrp, true, &magic_id, &split.0),
+ encode_segwit_key_half(hrp, false, &magic_id, &split.1),
]
}
@@ -113,7 +95,6 @@ pub trait ClientExtended {
/// Send a transaction with a 32B key as metadata encoded using fake segwit addresses
fn send_segwit_key(
&self,
- network: Network,
to: &Address,
amount: Amount,
metadata: &[u8; 32],
@@ -141,12 +122,16 @@ pub trait ClientExtended {
impl ClientExtended for Client {
fn send_segwit_key(
&self,
- network: Network,
to: &Address,
amount: Amount,
metadata: &[u8; 32],
) -> bitcoincore_rpc::Result<Txid> {
- let addresses = encode_segwit_key(network, metadata);
+ let hrp = match to.network {
+ Network::Bitcoin => "bc",
+ Network::Testnet | Network::Signet => "tb",
+ Network::Regtest => "bcrt",
+ };
+ let addresses = encode_segwit_key(hrp, metadata);
let mut recipients = vec![(to.to_string(), amount)];
recipients.extend(
addresses
@@ -222,7 +207,7 @@ impl ClientExtended for Client {
// TODO error handling
.unwrap();
let hex = op_return_out.script_pub_key.asm.split_once(' ').unwrap().1;
- let metadata= Vec::from_hex(hex).unwrap();
+ let metadata = Vec::from_hex(hex).unwrap();
Ok((full, metadata))
}
@@ -289,7 +274,7 @@ pub fn decode_segwit_msg(segwit_addrs: &[impl AsRef<str>]) -> Result<[u8; 32], D
}
pub mod utils {
- use crate::{encode_segwit_addr, encode_segwit_key, Network};
+ use crate::{encode_segwit_addr, encode_segwit_key};
pub fn rand_key() -> [u8; 32] {
let mut key = [0; 32];
@@ -303,13 +288,13 @@ pub mod utils {
key
}
- pub fn rand_addresses(network: Network, key: &[u8; 32]) -> Vec<String> {
+ pub fn rand_addresses(hrp: &str, key: &[u8; 32]) -> Vec<String> {
let mut rng_address: Vec<String> =
- std::iter::repeat_with(|| encode_segwit_addr(network, &rand_data()))
+ std::iter::repeat_with(|| encode_segwit_addr(hrp, &rand_data()))
.take(2)
.collect();
- let mut addresses = encode_segwit_key(network, &key).to_vec();
+ let mut addresses = encode_segwit_key(hrp, &key).to_vec();
addresses.append(&mut rng_address);
fastrand::shuffle(&mut addresses);
addresses
@@ -321,14 +306,13 @@ mod test {
use crate::{
decode_segwit_msg, encode_segwit_key,
utils::{rand_addresses, rand_key},
- Network,
};
#[test]
fn test_shuffle() {
for _ in 0..1000 {
let key = rand_key();
- let mut addresses = encode_segwit_key(Network::RegTest, &key);
+ let mut addresses = encode_segwit_key("test", &key);
fastrand::shuffle(&mut addresses);
let decoded =
decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>())
@@ -341,7 +325,7 @@ mod test {
fn test_shuffle_many() {
for _ in 0..1000 {
let key = rand_key();
- let addresses = rand_addresses(Network::TestNet, &key);
+ let addresses = rand_addresses("test", &key);
let decoded =
decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>())
.unwrap();
diff --git a/src/main.rs b/src/main.rs
@@ -4,12 +4,30 @@ use bitcoincore_rpc::{
bitcoin::{Amount, Txid},
Auth, Client, RpcApi,
};
-use depolymerization::{utils::rand_key, ClientExtended, Network};
+use depolymerization::{utils::rand_key, ClientExtended};
const CLIENT: &str = "client";
const WIRE: &str = "wire";
const RPC_URL: &str = "http://localhost:18443";
+/// Bitcoin networks
+#[derive(Debug, Clone, Copy)]
+pub enum Network {
+ MainNet,
+ TestNet,
+ RegTest,
+}
+
+impl Network {
+ pub fn dir(&self) -> &'static str {
+ match self {
+ Network::MainNet => "mainnet",
+ Network::TestNet => "testnet",
+ Network::RegTest => "regtest",
+ }
+ }
+}
+
fn data_dir_path() -> PathBuf {
// https://github.com/bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md#:~:text=By%20default%2C%20the%20configuration%20file,file%3E%20option%20in%20the%20bitcoin.
if cfg!(target_os = "windows") {
@@ -44,6 +62,7 @@ struct Args {
#[argh(switch, short = 'w')]
wire: bool,
}
+
fn common_rpc(network: Network) -> Client {
Client::new(
RPC_URL,
@@ -51,6 +70,7 @@ fn common_rpc(network: Network) -> Client {
)
.expect("Failed to open common client")
}
+
fn wallet_rpc(network: Network, wallet: &str) -> Client {
Client::new(
&format!("{}/wallet/{}", RPC_URL, wallet),
@@ -152,7 +172,7 @@ fn main() {
// Segwit test
let key = rand_key();
client_rpc
- .send_segwit_key(network, &wire_addr, Amount::from_sat(4200), &key)
+ .send_segwit_key(&wire_addr, Amount::from_sat(4200), &key)
.unwrap();
client_rpc.generate_to_address(1, &client_addr).unwrap();
let last = last_transaction(&wire_rpc).unwrap();