summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine A <>2022-01-03 02:14:52 +0100
committerAntoine A <>2022-01-03 02:14:52 +0100
commitcf984689d19c3a2f532ee0005dbcce19c87e59f3 (patch)
tree52da2da7e2727d9265f1902cab40cf0eefdba583
parentfe30526e0158774da8dbc52242a4e769746259d5 (diff)
downloaddepolymerization-cf984689d19c3a2f532ee0005dbcce19c87e59f3.tar.gz
depolymerization-cf984689d19c3a2f532ee0005dbcce19c87e59f3.tar.bz2
depolymerization-cf984689d19c3a2f532ee0005dbcce19c87e59f3.zip
Handle blockchain reorganisation
-rw-r--r--Cargo.lock14
-rw-r--r--btc-wire/src/main.rs88
-rw-r--r--makefile1
-rw-r--r--script/setup.sh56
-rw-r--r--script/test_btc_fail.sh3
-rw-r--r--script/test_btc_fork.sh147
-rw-r--r--script/test_btc_reconnect.sh6
-rw-r--r--script/test_btc_stress.sh7
-rw-r--r--script/test_btc_wire.sh59
-rw-r--r--taler-api/src/api_common.rs4
-rw-r--r--test.conf2
11 files changed, 316 insertions, 71 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 21a833b..47de10e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -651,13 +651,13 @@ dependencies = [
[[package]]
name = "http"
-version = "0.2.5"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
+checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03"
dependencies = [
"bytes",
"fnv",
- "itoa 0.4.8",
+ "itoa 1.0.1",
]
[[package]]
@@ -1048,9 +1048,9 @@ dependencies = [
[[package]]
name = "ppv-lite86"
-version = "0.2.15"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
+checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "proc-macro2"
@@ -1689,9 +1689,9 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
[[package]]
name = "version_check"
-version = "0.9.3"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs
index b078231..83c65fb 100644
--- a/btc-wire/src/main.rs
+++ b/btc-wire/src/main.rs
@@ -11,12 +11,13 @@ use postgres::{fallible_iterator::FallibleIterator, Client};
use rand::{rngs::OsRng, RngCore};
use reconnect::{AutoReconnectRPC, AutoReconnectSql};
use std::{
- collections::HashMap,
+ collections::{HashMap, HashSet},
path::PathBuf,
+ process::exit,
str::FromStr,
time::{Duration, SystemTime},
};
-use taler_api::api_common::{crockford_base32_encode, Amount};
+use taler_api::api_common::{base32, Amount};
use taler_config::Config;
use taler_log::log::{error, info, warn};
use url::Url;
@@ -83,11 +84,11 @@ fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectSql, config: &Config)
if let Some(row) = &row {
let id: i32 = row.get(0);
let amount = taler_amount_to_btc_amount(&Amount::from_str(row.get(1))?)?;
- let reserve_pub: &[u8] = row.get(2);
+ let wtid: &[u8] = row.get(2);
let addr: Address = btc_payto_addr(&Url::parse(row.get(3))?)?;
let exchange_base_url: Url = Url::parse(row.get(4))?;
let info = Info::Transaction {
- wtid: reserve_pub.try_into()?,
+ wtid: wtid.try_into()?,
url: exchange_base_url,
};
let metadata = encode_info(&info);
@@ -101,7 +102,7 @@ fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectSql, config: &Config)
&[&(TxStatus::Sent as i16), &tx_id.as_ref(), &id],
)?;
let amount = btc_amount_to_taler_amount(&amount.to_signed().unwrap());
- info!("send {} {} in {}", addr, amount, tx_id);
+ info!(">> {} {} in {} to {}", amount, base32(&wtid), tx_id, addr);
}
Err(e) => {
info!("sender: RPC - {}", e);
@@ -139,7 +140,7 @@ fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectSql, config: &Config)
fail_point("Skip send_op_return", 0.2)?;
match rpc.bounce(&bounced, &fee, &metadata) {
Ok(it) => {
- info!("bounce {} in {}", &bounced, &it);
+ info!("|| {} in {}", &bounced, &it);
tx.execute(
"UPDATE bounce SET txid = $1, status = $2 WHERE id = $3",
&[&it.as_ref(), &(BounceStatus::Sent as i16), &id],
@@ -150,7 +151,7 @@ fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectSql, config: &Config)
code: ErrorCode::RpcWalletInsufficientFunds | ErrorCode::RpcWalletError,
msg,
} => {
- info!("ignore bounce {} because {}", &bounced, msg);
+ info!("|| (ignore) {} because {}", &bounced, msg);
tx.execute(
"UPDATE bounce SET status = $1 WHERE id = $2",
&[&(BounceStatus::Ignored as i16), &id],
@@ -166,7 +167,8 @@ fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectSql, config: &Config)
// TODO check if transactions are abandoned
- let mut failed = false;
+ // Alway start with a sync work
+ let mut skip_notification = true;
loop {
let rpc = rpc.client();
let db = db.client();
@@ -176,8 +178,7 @@ fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectSql, config: &Config)
// Wait for the next notification
{
let mut ntf = db.notifications();
- // On failure retry without waiting for notifications
- if !failed && ntf.is_empty() {
+ if !skip_notification && ntf.is_empty() {
// Block until next notification
ntf.blocking_iter().next()?;
}
@@ -205,9 +206,10 @@ fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectSql, config: &Config)
})();
if let Err(e) = result {
error!("worker: DB - {}", e);
- failed = true;
+ // On failure retry without waiting for notifications
+ skip_notification = true;
} else {
- failed = false;
+ skip_notification = false;
}
}
}
@@ -223,7 +225,7 @@ fn sync_chain(
let min_confirmations = config.confirmation;
// Get a set of transactions ids to parse
- let (txs, lastblock): (HashMap<Txid, (Category, i32)>, BlockHash) = {
+ let (txs, removed, lastblock): (HashMap<Txid, (Category, i32)>, HashSet<Txid>, BlockHash) = {
// Get all transactions made since this block
let list = rpc.list_since_block(last_hash.as_ref(), min_confirmations, true)?;
// Only keep ids and category
@@ -232,9 +234,35 @@ fn sync_chain(
.into_iter()
.map(|tx| (tx.txid, (tx.category, tx.confirmations)))
.collect();
- (txs, list.lastblock)
+ let removed = list
+ .removed
+ .into_iter()
+ .filter_map(|tx| (tx.category == Category::Receive).then(|| tx.txid))
+ .collect();
+ (txs, removed, list.lastblock)
};
+ // Check if a confirmed incoming transaction have been removed by a blockchain reorganisation
+ if !removed.is_empty() {
+ for id in removed {
+ if let Ok((full, key)) = rpc.get_tx_segwit_key(&id) {
+ // If the removed tx is not in confirmed the txs list and the tx is stored in the database hard error
+ if txs
+ .get(&id)
+ .map(|(_, confirmations)| *confirmations < min_confirmations as i32)
+ .unwrap_or(true)
+ && db
+ .query_opt("SELECT 1 FROM tx_in WHERE reserve_pub=$1", &[&key.as_ref()])?
+ .is_some()
+ {
+ let credit_addr = full.details[0].address.as_ref().unwrap();
+ error!("Received transaction {} in {} from {} have been removed from the blockchain, bitcoin backing is compromised until the transaction reappear", base32(&key), id, credit_addr);
+ exit(1);
+ }
+ }
+ }
+ }
+
for (id, (category, confirmations)) in txs {
match category {
Category::Send => {
@@ -244,7 +272,7 @@ fn sync_chain(
match decode_info(&bytes) {
Ok(info) => {
match info {
- Info::Transaction { wtid, url } => {
+ Info::Transaction { wtid, .. } => {
let addr = full.details[0].address.as_ref().unwrap();
let amount = btc_amount_to_taler_amount(&full.amount);
@@ -262,8 +290,11 @@ fn sync_chain(
&[&(TxStatus::Sent as i16), &_id],
)?;
warn!(
- "send (recoverd) {} {} in {}",
- addr, amount, &id
+ ">> (recovered) {} {} in {} to {}",
+ amount,
+ base32(&wtid),
+ id,
+ addr
);
}
TxStatus::Sent => {}
@@ -281,10 +312,11 @@ fn sync_chain(
)?;
if nb > 0 {
warn!(
- "onchain {} {} in tx {}",
- crockford_base32_encode(&wtid),
- &url,
- id
+ ">> (onchain) {} {} in {} to {}",
+ amount,
+ base32(&wtid),
+ id,
+ addr
);
}
}
@@ -303,7 +335,7 @@ fn sync_chain(
"UPDATE bounce SET status=$1 where id=$2",
&[&(BounceStatus::Sent as i16), &_id],
)?;
- warn!("recovered bounce {} in {}", &bounced, &id);
+ warn!("|| (recovered) {} in {}", &bounced, &id);
}
BounceStatus::Ignored => error!("watcher: ignored bounce {} found in chain at {}", bounced, id),
BounceStatus::Sent => {}
@@ -314,7 +346,7 @@ fn sync_chain(
&[&bounced.as_ref(), &id.as_ref(), &(BounceStatus::Sent as i16)],
)?;
if nb > 0 {
- warn!("onchain bounce {} in {}", &bounced, &id);
+ warn!("|| (onchain) {} in {}", &bounced, &id);
}
}
}
@@ -342,8 +374,11 @@ fn sync_chain(
])?;
if nb > 0 {
info!(
- "receive {} << {} {} in {}",
- &debit_addr, &credit_addr, &amount, &id
+ "<< {} {} in {} from {}",
+ amount,
+ base32(&reserve_pub),
+ id,
+ debit_addr
);
}
}
@@ -433,7 +468,6 @@ fn main() {
let db_listener = AutoReconnectSql::new(&config.db_url, Duration::from_secs(5));
let db_worker = AutoReconnectSql::new(&config.db_url, Duration::from_secs(5));
- let join = std::thread::spawn(move || block_listener(rpc_listener, db_listener));
+ std::thread::spawn(move || block_listener(rpc_listener, db_listener));
worker(rpc_worker, db_worker, config);
- join.join().unwrap();
}
diff --git a/makefile b/makefile
index df745a4..1434a14 100644
--- a/makefile
+++ b/makefile
@@ -7,4 +7,5 @@ test:
script/test_btc_wire.sh
script/test_btc_reconnect.sh
script/test_btc_fail.sh
+ script/test_btc_fork.sh
script/test_btc_stress.sh \ No newline at end of file
diff --git a/script/setup.sh b/script/setup.sh
index ef3896a..080ed75 100644
--- a/script/setup.sh
+++ b/script/setup.sh
@@ -19,9 +19,11 @@ trap cleanup EXIT
DIR=$(mktemp -d)
BTC_DIR=$DIR/bitcoin
+BTC_DIR2=$DIR/bitcoin2
DB_DIR=$DIR/db
-mkdir -p $BTC_DIR
-mkdir -p $DB_DIR
+for dir in $BTC_DIR $BTC_DIR2 $DB_DIR; do
+ mkdir -p $dir
+done
# Load test.conf as bash variables
function load_config() {
@@ -29,6 +31,8 @@ function load_config() {
BANK_ENDPOINT=http://127.0.0.1:$PORT/
}
+# ----- Database ----- #
+
# Create new postgresql cluster and init database schema
function setup_db() {
pg_ctl init -D $DB_DIR &> /dev/null
@@ -43,20 +47,47 @@ function reset_db() {
psql $DB_URL < wire-gateway/db/schema.sql > /dev/null
}
-# Start a bitcoind regtest server in a temporary directory
+# ----- Bitcoin node ----- #
+
+# Start a bitcoind regtest node
function init_btc() {
echo "regtest=1" > $BTC_DIR/bitcoin.conf
echo "txindex=1" >> $BTC_DIR/bitcoin.conf
echo "fallbackfee=0.00000001" >> $BTC_DIR/bitcoin.conf
- BTC_CLI="bitcoin-cli -regtest -datadir=$BTC_DIR"
- bitcoind -datadir=$BTC_DIR &> btc.log &
+ BTC_CLI="bitcoin-cli -datadir=$BTC_DIR"
+ bitcoind -datadir=$BTC_DIR -port=8345 &> btc.log &
+ BTC_PID="$!"
$BTC_CLI -rpcwait getnetworkinfo > /dev/null
}
+# Start a second bitcoind regtest node connected to the first one
+function init_btc2() {
+ echo "regtest=1" > $BTC_DIR2/bitcoin.conf
+ echo "txindex=1" >> $BTC_DIR2/bitcoin.conf
+ echo "fallbackfee=0.00000001" >> $BTC_DIR2/bitcoin.conf
+ echo "[regtest]" >> $BTC_DIR2/bitcoin.conf
+ echo "rpcport=18345" >> $BTC_DIR2/bitcoin.conf
+ BTC_CLI2="bitcoin-cli -datadir=$BTC_DIR2"
+ bitcoind -datadir=$BTC_DIR2 -port=8346 &> btc2.log &
+ $BTC_CLI2 -rpcwait getnetworkinfo > /dev/null
+ $BTC_CLI addnode 127.0.0.1:8346 onetry
+}
+
+# Disconnect the two nodes
+function btc2_deco() {
+ $BTC_CLI disconnectnode 127.0.0.1:8346
+}
+
+# Create a fork on the second node and reconnect the two node
+function btc2_fork() {
+ $BTC_CLI2 generatetoaddress ${1:-50} $RESERVE > /dev/null
+ $BTC_CLI addnode 127.0.0.1:8346 onetry
+ sleep 1
+}
+
# Start a bitcoind regest server in a previously created temporary directory and load wallets
function restart_btc() {
- BTC_CLI="bitcoin-cli -regtest -datadir=$BTC_DIR"
- bitcoind -datadir=$BTC_DIR -fallbackfee=0.00000001 &>> btc.log &
+ bitcoind -datadir=$BTC_DIR &>> btc.log &
$BTC_CLI -rpcwait getnetworkinfo > /dev/null
for wallet in wire client reserve; do
$BTC_CLI loadwallet $wallet > /dev/null
@@ -76,6 +107,11 @@ function setup_btc() {
mine_btc
}
+function stop_btc() {
+ kill $BTC_PID
+ wait $BTC_PID
+}
+
# Mine blocks
function mine_btc() {
$BTC_CLI generatetoaddress "${1:-1}" $RESERVE > /dev/null
@@ -105,16 +141,20 @@ function check_balance() {
fi
}
+# ----- btc-wire ----- #
+
# Start btc_wire
function btc_wire() {
cargo build --bin btc-wire --release &> /dev/null
target/release/btc-wire $BTC_DIR &> btc_wire.log &
+ WIRE_PID="$!"
}
# Start btc_wire with random failures
function fail_btc_wire() {
cargo build --bin btc-wire --release --features fail &> /dev/null
target/release/btc-wire $BTC_DIR &> btc_wire.log &
+ WIRE_PID="$!"
}
# Start multiple btc_wire in parallel
@@ -124,6 +164,8 @@ function stressed_btc_wire() {
target/release/btc-wire $BTC_DIR &> btc_wire1.log &
}
+# ----- Gateway ------ #
+
# Start wire_gateway in test mode
function gateway() {
cargo build --bin wire-gateway --release --features test &> /dev/null
diff --git a/script/test_btc_fail.sh b/script/test_btc_fail.sh
index 849a525..ee7e23b 100644
--- a/script/test_btc_fail.sh
+++ b/script/test_btc_fail.sh
@@ -13,7 +13,7 @@ echo "Start database"
setup_db
echo "Start bitcoin node"
init_btc
-echo "Start bitcoin regtest"
+echo "Setup bitcoin"
setup_btc
echo "Start failing btc-wire"
fail_btc_wire
@@ -73,6 +73,7 @@ for n in `$SEQ`; do
$BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.000$n > /dev/null
mine_btc
done
+next_btc
sleep 20
echo " OK"
diff --git a/script/test_btc_fork.sh b/script/test_btc_fork.sh
new file mode 100644
index 0000000..1bfc8e8
--- /dev/null
+++ b/script/test_btc_fork.sh
@@ -0,0 +1,147 @@
+#!/bin/bash
+
+## Test btc_wire correctness when a blockchain reorganisation occurs
+
+set -eu
+
+source "${BASH_SOURCE%/*}/setup.sh"
+
+echo "----- Setup -----"
+echo "Load config file"
+load_config
+echo "Start database"
+setup_db
+echo "Start bitcoin node"
+init_btc
+echo "Setup bitcoin"
+setup_btc
+echo "Start second bitcoin node"
+init_btc2
+echo "Start btc-wire"
+btc_wire
+echo "Start gateway"
+gateway
+echo ""
+
+# Check btc-wire is running
+function check_up() {
+ if [ `ps -p $WIRE_PID | grep -c $WIRE_PID` == 0 ]; then
+ echo "btc_wire with pid $WIRE_PID should be up"
+ ps -p $WIRE_PID
+ exit 1
+ fi
+}
+
+# Check btc-wire is not running
+function check_down() {
+ if [ `ps -p $WIRE_PID | grep -c $WIRE_PID` != 0 ]; then
+ echo "btc_wire with pid $WIRE_PID should be down"
+ ps -p $WIRE_PID
+ exit 1
+ fi
+}
+
+SEQ="seq 10 20"
+
+echo "----- Handle reorg incoming transactions -----"
+
+echo "Loose second bitcoin node"
+btc2_deco
+
+echo -n "Gen incoming transactions:"
+for n in `$SEQ`; do
+ btc-wire-cli -d $BTC_DIR transfer 0.000$n
+ mine_btc # Mine transactions
+done
+next_btc # Trigger btc_wire
+check_delta "incoming?delta=-100" "$SEQ" "0.000"
+check_balance 9.99826299 0.00165000
+echo " OK"
+
+echo -n "Perform fork and check btc-wire hard error:"
+check_up
+btc2_fork
+check_balance 9.99826299 0.00000000
+check_down
+echo " OK"
+
+echo -n "Check btc-wire hard error on restart:"
+btc_wire
+sleep 1
+check_down
+echo " OK"
+
+echo -n "Recover orphaned transactions:"
+next_btc
+check_balance 9.99826299 0.00165000
+echo " OK"
+
+echo -n "Check btc-wire heal on restart:"
+btc_wire
+sleep 1
+check_up
+echo " OK"
+
+echo "----- Handle reorg outgoing transactions -----"
+
+echo "Loose second bitcoin node"
+btc2_deco
+
+echo -n "Gen outgoing transactions:"
+for n in `$SEQ`; do
+ taler-exchange-wire-gateway-client \
+ -b $BANK_ENDPOINT \
+ -C payto://bitcoin/$CLIENT \
+ -a BTC:0.0000$n > /dev/null
+done
+sleep 1
+mine_btc # Mine transactions
+check_delta "outgoing?delta=-100" "$SEQ"
+check_balance 9.99842799 0.00146311
+echo " OK"
+
+echo -n "Perform fork and check btc-wire still up:"
+check_up
+btc2_fork
+check_balance 9.99826299 0.00146311
+check_up
+echo " OK"
+
+echo -n "Recover orphaned transactions:"
+next_btc
+check_balance 9.99842799 0.00146311
+echo " OK"
+
+echo "----- Handle reorg bounce -----"
+
+echo -n "Clear wire wallet:"
+$BTC_CLI -rpcwallet=wire sendtoaddress $CLIENT `$BTC_CLI -rpcwallet=wire getbalance` "" "" true > /dev/null
+mine_btc
+echo " OK"
+
+echo "Loose second bitcoin node"
+btc2_deco
+
+echo -n "Generate bounce:"
+for n in `$SEQ`; do
+ $BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.000$n > /dev/null
+ mine_btc
+done
+next_btc
+sleep 1
+check_balance "*" 0.00011000
+echo " OK"
+
+echo -n "Perform fork and check btc-wire still up:"
+check_up
+btc2_fork
+check_balance "*" 0.00000000
+check_up
+echo " OK"
+
+echo -n "Recover orphaned transactions:"
+next_btc
+check_balance "*" 0.00011000
+echo " OK"
+
+echo "All tests passed" \ No newline at end of file
diff --git a/script/test_btc_reconnect.sh b/script/test_btc_reconnect.sh
index 3ab9292..32088b8 100644
--- a/script/test_btc_reconnect.sh
+++ b/script/test_btc_reconnect.sh
@@ -13,7 +13,7 @@ echo "Start database"
setup_db
echo "Start bitcoin node"
init_btc
-echo "Start bitcoin regtest"
+echo "Setup bitcoin"
setup_btc
echo "Start btc-wire"
btc_wire
@@ -40,9 +40,7 @@ btc-wire-cli -d $BTC_DIR transfer 0.00004
next_btc
check_balance 9.99948077 0.00050200
echo "Stop bitcoin node"
-PID=`jobs -p bitcoind`
-kill $PID
-wait $PID
+stop_btc
echo -n "Requesting exchange incoming transaction list:"
taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -i 2>&1 | grep -q "504" && echo " OK" || echo " Failed"
diff --git a/script/test_btc_stress.sh b/script/test_btc_stress.sh
index 91f8f8b..10c7021 100644
--- a/script/test_btc_stress.sh
+++ b/script/test_btc_stress.sh
@@ -13,7 +13,7 @@ echo "Start database"
setup_db
echo "Start bitcoin node"
init_btc
-echo "Start bitcoin regtest"
+echo "Setup bitcoin"
setup_btc
echo "Start btc-wire stressed"
stressed_btc_wire
@@ -97,7 +97,10 @@ for n in `$SEQ`; do
$BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.000$n > /dev/null
mine_btc
done
-sleep 20
+next_btc
+sleep 10
+mine_btc
+sleep 10
echo " OK"
echo -n "Check balance:"
diff --git a/script/test_btc_wire.sh b/script/test_btc_wire.sh
index 3b48bae..6559bac 100644
--- a/script/test_btc_wire.sh
+++ b/script/test_btc_wire.sh
@@ -13,7 +13,7 @@ echo "Start database"
setup_db
echo "Start bitcoin node"
init_btc
-echo "Start bitcoin regtest"
+echo "Setup bitcoin"
setup_btc
echo "Start btc-wire"
btc_wire
@@ -21,37 +21,56 @@ echo "Start gateway"
gateway
echo ""
-echo "---- Receive -----"
+SEQ="seq 10 20"
+
+echo "----- Receive -----"
echo -n "Making wire transfer to exchange:"
-btc-wire-cli -d $BTC_DIR transfer 0.00004
-next_btc
-check_balance 9.99995209 0.00004000
+for n in `$SEQ`; do
+ btc-wire-cli -d $BTC_DIR transfer 0.000$n
+ mine_btc # Mine transactions
+done
+next_btc # Trigger btc_wire
+check_balance 9.99826299 0.00165000
echo " OK"
echo -n "Requesting exchange incoming transaction list:"
-taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -i | grep BTC:0.00004 > /dev/null
+check_delta "incoming?delta=-100" "$SEQ" "0.000"
echo " OK"
-echo "---- Bounce-----"
-$BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.00042
-next_btc
-check_balance 9.99993883 0.00005000
-
-echo "---- Send -----"
+echo "----- Send -----"
echo -n "Making wire transfer from exchange:"
-taler-exchange-wire-gateway-client \
- -b $BANK_ENDPOINT \
- -C payto://bitcoin/$CLIENT \
- -a BTC:0.00002 > /dev/null
-sleep 0.3
-mine_btc
-check_balance 9.99995883 0.00002801
+for n in `$SEQ`; do
+ taler-exchange-wire-gateway-client \
+ -b $BANK_ENDPOINT \
+ -C payto://bitcoin/$CLIENT \
+ -a BTC:0.0000$n > /dev/null
+done
+sleep 1
+mine_btc # Mine transactions
+check_balance 9.99842799 0.00146311
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
+check_delta "outgoing?delta=-100" "$SEQ"
+echo " OK"
+
+echo "----- Bounce -----"
+
+echo -n "Clear wire wallet:"
+$BTC_CLI -rpcwallet=wire sendtoaddress $CLIENT `$BTC_CLI -rpcwallet=wire getbalance` "" "" true > /dev/null
+mine_btc
+echo " OK"
+
+echo -n "Bounce:"
+for n in `$SEQ`; do
+ $BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.000$n > /dev/null
+ mine_btc
+done
+next_btc
+sleep 1
+check_balance "*" 0.00011000
echo " OK"
echo "All tests passed" \ No newline at end of file
diff --git a/taler-api/src/api_common.rs b/taler-api/src/api_common.rs
index 778e884..ab635ec 100644
--- a/taler-api/src/api_common.rs
+++ b/taler-api/src/api_common.rs
@@ -296,13 +296,13 @@ impl<const L: usize> FromStr for Base32<L> {
}
}
-pub fn crockford_base32_encode(bytes: &[u8]) -> String {
+pub fn base32(bytes: &[u8]) -> String {
base32::encode(base32::Alphabet::Crockford, bytes)
}
impl<const L: usize> Display for Base32<L> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(&crockford_base32_encode(&self.0))
+ f.write_str(&base32(&self.0))
}
}
diff --git a/test.conf b/test.conf
index 420edde..c0b88f0 100644
--- a/test.conf
+++ b/test.conf
@@ -6,7 +6,7 @@ DB_URL = postgres://localhost:5454/postgres?user=postgres&password=passwor
PORT = 8060
UNIXPATH = TODO
PAYTO = payto://bitcoin/bcrt1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj
-CONFIRMATION = 1
+CONFIRMATION = 3
BTC_WALLET = wire
BTC_DATA_DIR = ~/.bitcoin
BOUNCE_FEE = 1000 \ No newline at end of file