commit 187f435336d86935a92b4d55a5a17cd5e24b9aab
parent 3e080b281767c1d9623cf97091d2e4e1c01b450c
Author: Antoine A <>
Date: Tue, 15 Feb 2022 11:24:23 +0100
btc-wire: metadata doc draft
Diffstat:
9 files changed, 87 insertions(+), 6 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -156,6 +156,7 @@ dependencies = [
"bitcoin",
"common",
"criterion",
+ "hex",
"rust-ini",
"serde",
"serde_json",
diff --git a/btc-wire/Cargo.toml b/btc-wire/Cargo.toml
@@ -32,6 +32,8 @@ base64 = "0.13.0"
common = { path = "../common" }
# Ini parser
rust-ini = "0.17.0"
+# Hexadecimal encoding
+hex = "0.4.3"
[dev-dependencies]
# statistics-driven micro-benchmarks
diff --git a/btc-wire/README.md b/btc-wire/README.md
@@ -40,6 +40,25 @@ the RPC server, `txindex=1` and `maxtxfee` are mandatory.
7. Run wire-gateway `wire-gateway`
8. Run btc-wire `btc-wire`
+## Deposit metadata format
+
+Starting from a bitcoin payto URI you will have to generate fake segwit
+addresses to encode the reserve public key as metadata into a common bitcoin
+transaction.
+
+A single segwit address can contain 20B of chosen data and the reserve pub key
+is 32B. We use two fake adresses consisting of the two key half prepended
+with the same random pattern, at the exception of the first bit with must be 0
+for the first half and 1 for the second one. You must then send a single
+transaction with the three addresses as recipients.
+
+As a few lines of code can carry more meaning that many words you can find a
+[simple rust example](src/bin/segwit-demo.rs) in this project and run it with
+`make segwit_demo`.
+
+Segwit addresses are encoded using a bitcoin specific format: [bech32](
+[bech32](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki))
+
## Implementation details
### Stuck transaction
diff --git a/btc-wire/src/bin/segwit-demo.rs b/btc-wire/src/bin/segwit-demo.rs
@@ -0,0 +1,56 @@
+use bitcoin::Amount;
+use btc_wire::{rpc_utils, segwit::encode_segwit_addr};
+use common::{
+ base32::{self, Alphabet},
+ rand_slice,
+};
+
+pub fn main() {
+ let address = "bc1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj";
+ let amount = Amount::from_sat(10000000);
+ let reserve_pub = "0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00";
+ let btc = amount.as_btc();
+
+ println!("Ⅰ - Parse payto uri");
+ println!("Got payto uri: payto://bitcoin/{address}?amount=BTC:{btc}&subject={reserve_pub}");
+ println!("Send {btc} BTC to {address} with reserve public key {reserve_pub}");
+
+ println!("\nⅡ - Generate fake segwit addresses");
+ let decoded: [u8; 32] = base32::decode(Alphabet::Crockford, reserve_pub)
+ .unwrap()
+ .try_into()
+ .unwrap();
+ println!("Decode reserve public key: 0x{}", hex::encode(&decoded[..]));
+ let magic_id: [u8; 4] = rand_slice();
+ println!("Generate magic id: 0x{}", hex::encode(&magic_id));
+ println!(
+ "Split reserve public key in two:\n0x{}\n0x{}",
+ hex::encode(&decoded[..16]),
+ hex::encode(&decoded[16..])
+ );
+ let mut first_half = [&magic_id, &decoded[..16]].concat();
+ let mut second_half = [&magic_id, &decoded[16..]].concat();
+ println!(
+ "Concatenate magic id with each reserve public key half:\n0x{}\n0x{}",
+ hex::encode(&first_half),
+ hex::encode(&second_half)
+ );
+ first_half[0] &= 0b0111_1111;
+ second_half[0] |= 0b1000_0000;
+ println!(
+ "Set first bit of the first half:\n0x{}\nUnset first bit of the second half:\n0x{}",
+ hex::encode(&first_half),
+ hex::encode(&second_half)
+ );
+ // bech32: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
+ let first = encode_segwit_addr("bc", first_half[..].try_into().unwrap());
+ let second = encode_segwit_addr("bc", second_half[..].try_into().unwrap());
+ println!(
+ "Encode each half using bech32 to generate a segwit address:\n{}\n{}",
+ first, second
+ );
+
+ println!("\nⅢ - Send to many");
+ let minimum = rpc_utils::segwit_min_amount().as_btc();
+ println!("Send a single bitcoin transaction with the three addresses as recipient as follow:\n{address} {btc}BTC\n{first} {minimum}BTC\n{second} {minimum}BTC");
+}
diff --git a/btc-wire/src/segwit.rs b/btc-wire/src/segwit.rs
@@ -17,7 +17,7 @@ use bech32::{u5, FromBase32, ToBase32, Variant};
use common::rand::{rngs::OsRng, RngCore};
/// Encode metadata into a segwit address
-fn encode_segwit_addr(hrp: &str, metada: &[u8; 20]) -> String {
+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());
diff --git a/common/src/lib.rs b/common/src/lib.rs
@@ -20,6 +20,7 @@ use rand::{rngs::OsRng, RngCore};
pub use postgres;
pub use rand;
pub use url;
+pub use base32;
pub mod api_common;
pub mod api_wire;
diff --git a/makefile b/makefile
@@ -28,4 +28,7 @@ test_eth: install
test/eth/hell.sh
test/eth/analysis.sh
-test: install test_gateway test_eth test_btc
-\ No newline at end of file
+test: install test_gateway test_eth test_btc
+
+segwit_demo:
+ cargo run --release --bin segwit-demo
+\ No newline at end of file
diff --git a/script/prepare.sh b/script/prepare.sh
@@ -33,7 +33,7 @@ tar xvzf btc.tar.gz
mv -v bitcoin-22.0/* ~/bitcoin
-echo "Ⅳ - Install Go Ethereum (Geth) v1.10.15 "
+echo "Ⅲ - Install Go Ethereum (Geth) v1.10.15 "
cd $DIR
curl -L https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.10.15-8be800ff.tar.gz -o geth.tar.gz
rm -rfv ~/geth
@@ -41,7 +41,7 @@ mkdir -pv ~/geth
tar xvzf geth.tar.gz
mv -v geth-alltools-linux-amd64-1.10.15-8be800ff/* ~/geth
-echo "Ⅲ - Config"
+echo "Ⅳ - Config"
echo "Add ~/postgresql/bin to your path"
echo "Add ~/bitcoin/bin to your path"
diff --git a/test/conf/taler_btc_lifetime.conf b/test/conf/taler_btc_lifetime.conf
@@ -9,6 +9,5 @@ DB_URL = postgres://localhost:5454/postgres?user=postgres&password=passwo
PORT = 8060
PAYTO = payto://bitcoin/bcrt1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj
CONFIRMATION = 3
-BOUNCE_FEE = 1000
HTTP_LIFETIME = 10
WIRE_LIFETIME = 10
\ No newline at end of file