depolymerization

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

commit d1722dd88446ba4b8c425f73b259885aac76165d
parent 9daf1bc6a1f31badab35c2fb1437f93f9581cbcc
Author: Antoine A <>
Date:   Tue,  7 Dec 2021 23:01:40 +0100

Improve testing

Diffstat:
MCargo.lock | 40++++++++++++++++++++--------------------
Mbtc-wire/src/bin/btc-wire-cli.rs | 6++++--
Mbtc-wire/src/main.rs | 12++++++++----
Mbtc-wire/src/rpc_utils.rs | 11++++++++---
Amakefile | 9+++++++++
Dscript/test_bank.sh | 75---------------------------------------------------------------------------
Ascript/test_btc_wire.sh | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascript/test_gateway.sh | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mwire-gateway/Cargo.toml | 4++++
Mwire-gateway/src/main.rs | 37+++++++++++++++++++++++++++++++------
10 files changed, 236 insertions(+), 110 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -161,9 +161,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" @@ -387,9 +387,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12" +checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" dependencies = [ "darling_core", "darling_macro", @@ -397,9 +397,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3" +checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" dependencies = [ "fnv", "ident_case", @@ -411,9 +411,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc" +checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" dependencies = [ "darling_core", "quote", @@ -717,9 +717,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" dependencies = [ "either", ] @@ -759,9 +759,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.108" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" +checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" [[package]] name = "lock_api" @@ -806,9 +806,9 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memoffset" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg", ] @@ -887,9 +887,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "owo-colors" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9ad6d222cdc2351ccabb7af4f68bfaecd601b33c5f10d410ec89d2a273f6fff" +checksum = "8d3b1ca05e7e4171727a5dab03790a344f248eaad925dce8ba0014fd78392b88" [[package]] name = "parking_lot" @@ -1031,9 +1031,9 @@ checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "proc-macro2" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" dependencies = [ "unicode-xid", ] @@ -1177,9 +1177,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" diff --git a/btc-wire/src/bin/btc-wire-cli.rs b/btc-wire/src/bin/btc-wire-cli.rs @@ -119,8 +119,10 @@ fn main() { match args.cmd { Cmd::Init(_) => App::start().init(), Cmd::Reset(_) => { - let path = data_dir_path(); - std::fs::remove_dir_all(path.join(Network::RegTest.dir())).unwrap(); + let path = data_dir_path().join(Network::RegTest.dir()); + if path.exists() { + std::fs::remove_dir_all(path).unwrap(); + } } Cmd::Transfer(TransferCmd { key: _key, diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs @@ -8,7 +8,7 @@ use btc_wire::{ segwit::DecodeSegWitErr, ClientExtended, GetOpReturnErr, GetSegwitErr, }; -use postgres::{fallible_iterator::FallibleIterator, Client, NoTls, Row}; +use postgres::{fallible_iterator::FallibleIterator, Client, NoTls}; use std::{ collections::HashMap, process::exit, @@ -241,6 +241,11 @@ fn watcher(rpc: RPC, mut db: Client) -> Result<(), Box<dyn std::error::Error>> { } } +#[cfg(target_family = "windows")] +const DB_URL: &str = "postgres://localhost/wire_gateway?user=postgres"; +#[cfg(target_family = "unix")] +const DB_URL: &str = "postgres://localhost?user=postgres&password=password"; + fn main() { // Guess network by trying to connect to a JSON RPC server let network = dirty_guess_network(); @@ -249,9 +254,8 @@ fn main() { let rpc_watcher = wallet_rpc(network, "wire"); let rpc_sender = wallet_rpc(network, "wire"); - let postgres_config = "postgres://localhost/wire_gateway?user=postgres"; - let db_watcher = Client::connect(&postgres_config, NoTls).unwrap(); - let db_sender = Client::connect(&postgres_config, NoTls).unwrap(); + let db_watcher = Client::connect(DB_URL, NoTls).unwrap(); + let db_sender = Client::connect(DB_URL, NoTls).unwrap(); let join = std::thread::spawn(move || sender(rpc_sender, db_sender)); watcher(rpc_watcher, db_watcher).unwrap(); join.join().unwrap(); diff --git a/btc-wire/src/rpc_utils.rs b/btc-wire/src/rpc_utils.rs @@ -1,12 +1,13 @@ use std::{path::PathBuf, str::FromStr}; use bitcoincore_rpc::{ - bitcoin::{BlockHash, Txid, Amount, Address}, + bitcoin::{Address, Amount, BlockHash, Txid}, json::{GetTransactionResultDetailCategory, ListTransactionResult}, - Auth, Client, RpcApi, jsonrpc::serde_json::Value, + jsonrpc::serde_json::Value, + Auth, Client, RpcApi, }; -use crate::rpc_patch::{GetTransactionFull, ClientPatched}; +use crate::rpc_patch::{ClientPatched, GetTransactionFull}; pub const CLIENT: &str = "client"; pub const WIRE: &str = "wire"; @@ -133,6 +134,10 @@ pub fn segwit_min_amount() -> Amount { return Amount::from_sat(294); } +pub fn check_address(addr: &str) -> bool { + Address::from_str(addr).is_ok() +} + /// Send transaction to multiple recipients pub fn send_many( client: &Client, diff --git a/makefile b/makefile @@ -0,0 +1,8 @@ +install: + cargo install --path btc-wire + cargo install --path btc-wire --bin btc-wire-cli + cargo install --path wire-gateway + +test: + script/test_gateway.sh + script/test_btc_wire.sh +\ No newline at end of file diff --git a/script/test_bank.sh b/script/test_bank.sh @@ -1,75 +0,0 @@ -#!/bin/bash - -set -eu - -# Cleanup to run whenever we exit -function cleanup() -{ - for n in `jobs -p` - do - kill $n 2> /dev/null || true - done - wait -} - -# Install cleanup handler (except for kill -9) -trap cleanup EXIT - -echo "OK" - -BANK_ENDPOINT=http://172.23.48.1:8080/ - -echo -n "Making wire transfer to exchange ..." -btc-wire-cli.exe transfer 0.00004 -btc-wire-cli.exe nblock -echo " OK" - -echo -n "Requesting exchange incoming transaction list ..." - -taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -i | grep BTC:0.00004 > /dev/null - -echo " OK" - -echo -n "Making wire transfer from exchange..." - -ADDRESS=`bitcoin-cli.exe -rpcwallet=client getnewaddress` -taler-exchange-wire-gateway-client \ - -b $BANK_ENDPOINT \ - -C payto://bitcoin/$ADDRESS \ - -a BTC:0.00002 > /dev/null -btc-wire-cli.exe nblock -echo " OK" - - -echo -n "Requesting exchange's outgoing transaction list..." - -taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -o | grep BTC:0.00002 > /dev/null - -echo " OK" -echo "All tests passed" - - -# ---- Endpoint & Method ----- # - -echo -n "Unknown endpoint..." -test `curl -w %{http_code} -s -o /dev/null ${BANK_ENDPOINT}test` -eq 404 && echo " OK" || echo " Failed" - -echo -n "Method not allowed..." -test `curl -w %{http_code} -s -o /dev/null ${BANK_ENDPOINT}transfer` -eq 405 && echo " OK" || echo " Failed" - -# ----- Request format ----- # - -echo -n "Bad payto url..." -COUNT=0 -for bad_payto in http://bitcoin/$ADDRESS payto://btc/$ADDRESS payto://bitcoin/$ADDRESS?id=admin payto://bitcoin/$ADDRESS#admin -do - taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C $bad_payto -a BTC:0.00042 2>&1 | grep -q "(400/24)" && echo -n " OK" || echo -n " Failed" -done -echo "" - -#echo -n "Bad bitcoin address..." -#taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C payto://bitcoin/ADDRESS -a BTC:0.00042 2>&1 | grep -q "(400/26)" && echo " OK" || echo " Failed" - -echo -n "Bad amount..." -taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C payto://bitcoin/$ADDRESS -a ATC:0.00042 2>&1 | grep -q "(400/26)" && echo " OK" || echo " Failed" -exit 0 diff --git a/script/test_btc_wire.sh b/script/test_btc_wire.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +set -eu + +# Cleanup to run whenever we exit +function cleanup() +{ + for n in `jobs -p` + do + kill $n 2> /dev/null || true + done + wait +} + +# Install cleanup handler (except for kill -9) +trap cleanup EXIT + +BANK_ENDPOINT=http://localhost:8080/ + +echo "Reset database" +sudo -u postgres psql < wire-gateway/db/schema.sql > /dev/null +echo "Reset bitcoin regtest" +btc-wire-cli reset +echo "Start bitcoin node" +bitcoind -regtest -fallbackfee=0.00001 > /dev/null & +bitcoin-cli -rpcwait getnetworkinfo > /dev/null +echo "Init bitcoin regtest" +btc-wire-cli init +echo "Start btc-wire" +cargo build --bin btc-wire &> /dev/null +target/debug/btc-wire &> /dev/null & +echo "Start gateway" +cargo build --bin wire-gateway --features test &> /dev/null +target/debug/wire-gateway &> /dev/null & +for n in `seq 1 50`; do + echo -n "-" + sleep 0.2 + curl -s $BANK_ENDPOINT -o /dev/null && break +done +echo "" + +echo -n "Making wire transfer to exchange ..." +btc-wire-cli transfer 0.00004 +btc-wire-cli nblock +echo " OK" + +echo -n "Requesting exchange incoming transaction list ..." +taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -i | grep BTC:0.00004 > /dev/null +echo " OK" + +echo -n "Making wire transfer from exchange..." + +ADDRESS=`bitcoin-cli -rpcwallet=client getnewaddress` +taler-exchange-wire-gateway-client \ + -b $BANK_ENDPOINT \ + -C payto://bitcoin/$ADDRESS \ + -a BTC:0.00002 > /dev/null +btc-wire-cli nblock +echo " OK" + + +echo -n "Requesting exchange's outgoing transaction list..." + +taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -o | grep BTC:0.00002 > /dev/null + +echo " OK" +echo "All tests passed" +\ No newline at end of file diff --git a/script/test_gateway.sh b/script/test_gateway.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +set -eu + +# Cleanup to run whenever we exit +function cleanup() +{ + for n in `jobs -p` + do + kill $n 2> /dev/null || true + done + wait +} + +# Install cleanup handler (except for kill -9) +trap cleanup EXIT + +BANK_ENDPOINT=http://127.0.0.1:8080/ + +echo "Reset database" +sudo -u postgres psql < wire-gateway/db/schema.sql > /dev/null +echo "Start gateway" +cargo build --bin wire-gateway --features test &> /dev/null +target/debug/wire-gateway &> /dev/null & +for n in `seq 1 50`; do + echo -n "-" + sleep 0.2 + curl -s $BANK_ENDPOINT -o /dev/null && break +done +echo "" + +# Get client address +ADDRESS=address +echo -n "Making wire transfer to exchange ..." +taler-exchange-wire-gateway-client \ + -b $BANK_ENDPOINT \ + -S 0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00 \ + -D payto://bitcoin/$ADDRESS \ + -a BTC:0.00004 > /dev/null +echo " OK" + +echo -n "Requesting exchange incoming transaction list ..." +taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -i | grep BTC:0.00004 > /dev/null +echo " OK" + +echo -n "Making wire transfer from exchange..." +taler-exchange-wire-gateway-client \ + -b $BANK_ENDPOINT \ + -C payto://bitcoin/$ADDRESS \ + -a BTC:0.00002 > /dev/null +echo " OK" + +echo -n "Requesting exchange's outgoing transaction list..." +taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -o | grep BTC:0.00002 > /dev/null +echo " OK" + + +echo "All tests passed" + + +# ---- Endpoint & Method ----- # + +echo -n "Unknown endpoint..." +test `curl -w %{http_code} -s -o /dev/null ${BANK_ENDPOINT}test` -eq 404 && echo " OK" || echo " Failed" + +echo -n "Method not allowed..." +test `curl -w %{http_code} -s -o /dev/null ${BANK_ENDPOINT}transfer` -eq 405 && echo " OK" || echo " Failed" + +# ----- Request format ----- # + +echo -n "Bad payto url..." +COUNT=0 +for bad_payto in http://bitcoin/$ADDRESS payto://btc/$ADDRESS payto://bitcoin/$ADDRESS?id=admin payto://bitcoin/$ADDRESS#admin +do + taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C $bad_payto -a BTC:0.00042 2>&1 | grep -q "(400/24)" && echo -n " OK" || echo -n " Failed" +done +echo "" + +#echo -n "Bad bitcoin address..." +#taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C payto://bitcoin/ADDRESS -a BTC:0.00042 2>&1 | grep -q "(400/26)" && echo " OK" || echo " Failed" + +echo -n "Bad amount..." +taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C payto://bitcoin/$ADDRESS -a ATC:0.00042 2>&1 | grep -q "(400/26)" && echo " OK" || echo " Failed" +exit 0 diff --git a/wire-gateway/Cargo.toml b/wire-gateway/Cargo.toml @@ -3,6 +3,10 @@ name = "wire-gateway" version = "0.1.0" edition = "2021" +[features] +# Enable test admin endpoint +test = [] + [dependencies] # Http library hyper = { version = "0.14.15", features = ["http1", "server", "runtime"] } diff --git a/wire-gateway/src/main.rs b/wire-gateway/src/main.rs @@ -1,7 +1,7 @@ use std::{process::exit, str::FromStr}; use api_common::{Amount, SafeUint64, ShortHashCode, Timestamp}; -use api_wire::{OutgoingBankTransaction, OutgoingHistory}; +use api_wire::{AddIncomingRequest, OutgoingBankTransaction, OutgoingHistory}; use async_compression::tokio::bufread::ZlibDecoder; use error_codes::ErrorCode; use hyper::{ @@ -32,12 +32,16 @@ fn check_pay_to(url: &Url) -> bool { && url.fragment().is_none(); } +const SELF_PAYTO: &str = "payto://bitcoin/bcrt1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj"; +const SELF_URL: &str = "http://localhost:8080"; +#[cfg(target_family = "windows")] +const DB_URL: &str = "postgres://localhost/wire_gateway?user=postgres"; +#[cfg(target_family = "unix")] +const DB_URL: &str = "postgres://localhost?user=postgres&password=password"; + #[tokio::main] async fn main() { - let (client, connection) = - tokio_postgres::connect("postgres://localhost/wire_gateway?user=postgres", NoTls) - .await - .unwrap(); + let (client, connection) = tokio_postgres::connect(DB_URL, NoTls).await.unwrap(); tokio::spawn(async move { if let Err(e) = connection.await { @@ -157,7 +161,7 @@ async fn router( } let timestamp = Timestamp::now(); let row = state.client.query_one("INSERT INTO tx_out (_date, amount, wtid, debit_acc, credit_acc, exchange_url, status) VALUES (now(), $1, $2, $3, $4, $5, $6) RETURNING id", &[ - &request.amount.to_string(), &request.wtid.as_ref(), &"payto://bitcoin/bcrt1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj", &request.credit_account.to_string(), &request.exchange_base_url.to_string(), &0i16 + &request.amount.to_string(), &request.wtid.as_ref(), &SELF_PAYTO, &request.credit_account.to_string(), &request.exchange_base_url.to_string(), &0i16 ]).await.unwrap(); json_response( StatusCode::OK, @@ -247,6 +251,27 @@ async fn router( ) .await } + #[cfg(feature = "test")] + "/admin/add-incoming" => { + assert_method(&parts, Method::POST)?; + let request: AddIncomingRequest = parse_json(&parts, body).await; + // We do not check input as this is an admin endpoint + let timestamp = Timestamp::now(); + let row = state.client.query_one("INSERT INTO tx_in (_date, amount, reserve_pub, debit_acc, credit_acc) VALUES (now(), $1, $2, $3, $4) RETURNING id", &[ + &request.amount.to_string(), &request.reserve_pub.as_ref(), &request.debit_account.to_string(), &"payto://bitcoin/bcrt1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj" + ]).await.unwrap(); + json_response( + StatusCode::OK, + &TransferResponse { + timestamp, + row_id: { + let id: i32 = row.get(0); + SafeUint64::try_from(id as u64).unwrap() + }, + }, + ) + .await + } _ => return Err((StatusCode::NOT_FOUND, ErrorCode::GENERIC_ENDPOINT_UNKNOWN)), }; return Ok(response);