depolymerization

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

commit 79f0adf3132feab2135ddf51e58e33a7f9c4dc81
parent 328d7758e31a025301be956310cbb47a3ed4b29a
Author: Antoine A <>
Date:   Sun,  6 Feb 2022 18:54:51 +0100

Improve tests

Diffstat:
Mbtc-wire/src/bin/btc-wire-cli.rs | 3++-
Mbtc-wire/src/bin/btc-wire-utils.rs | 46+++++++++++++++++++++++++++++-----------------
Mbtc-wire/src/config.rs | 4++--
Mbtc-wire/src/loops/worker.rs | 40+++++++++++++---------------------------
Mbtc-wire/src/rpc.rs | 4++++
Meth-wire/src/bin/eth-wire-cli.rs | 3++-
Meth-wire/src/bin/eth-wire-utils.rs | 3++-
Meth-wire/src/loops/worker.rs | 2+-
Mtest/btc/reconnect.sh | 2+-
Mtest/btc/stress.sh | 10++++++----
Mtest/common.sh | 25++++++++++++-------------
11 files changed, 74 insertions(+), 68 deletions(-)

diff --git a/btc-wire/src/bin/btc-wire-cli.rs b/btc-wire/src/bin/btc-wire-cli.rs @@ -20,10 +20,11 @@ use btc_wire::{ }; use common::{ config::{Config, CoreConfig}, - postgres::{Client, NoTls}, + postgres::{Client, NoTls}, log::init, }; fn main() { + init(); let args: Vec<_> = std::env::args().collect(); // Parse taler config let config = CoreConfig::load_from_file(&args[2]); diff --git a/btc-wire/src/bin/btc-wire-utils.rs b/btc-wire/src/bin/btc-wire-utils.rs @@ -15,16 +15,16 @@ */ use std::path::PathBuf; -use bitcoin::{Address, Amount, Network}; +use bitcoin::{Address, Amount, BlockHash, Network}; use btc_wire::{ config::BitcoinConfig, - rpc::{Rpc, Category, Error, ErrorCode}, + rpc::{Category, Error, ErrorCode, Rpc}, rpc_utils::default_data_dir, }; use common::{ config::{Config, CoreConfig}, postgres::{Client, NoTls}, - rand_slice, + rand_slice, log::init, }; #[derive(argh::FromArgs)] @@ -43,7 +43,7 @@ enum Cmd { Transfer(TransferCmd), NextBlock(NextBlockCmd), Abandon(AbandonCmd), - ClearDB(ClearCmd), + ResetDB(ResetCmd), } #[derive(argh::FromArgs)] @@ -82,9 +82,9 @@ struct AbandonCmd { } #[derive(argh::FromArgs)] -#[argh(subcommand, name = "cleardb")] +#[argh(subcommand, name = "resetdb")] /// Clear database -struct ClearCmd { +struct ResetCmd { #[argh(positional)] /// taler config config: String, @@ -92,7 +92,7 @@ struct ClearCmd { struct App { config: BitcoinConfig, - client: Rpc, + rpc: Rpc, } impl App { @@ -101,12 +101,15 @@ impl App { let config = BitcoinConfig::load(data_dir).unwrap(); let client = Rpc::common(&config).unwrap(); - Self { config, client } + Self { + config, + rpc: client, + } } pub fn auto_wallet(&mut self, name: &str) -> (Rpc, Address) { // Auto load - if let Err(err) = self.client.load_wallet(name) { + if let Err(err) = self.rpc.load_wallet(name) { match err { Error::RPC { code, .. } if code == ErrorCode::RpcWalletAlreadyLoaded => {} e => Err(e).unwrap(), @@ -124,21 +127,22 @@ impl App { Network::Regtest => { // Manually mine a block let (_, addr) = self.auto_wallet(wallet); - self.client.generate(1, &addr).unwrap(); + self.rpc.generate(1, &addr).unwrap(); } _ => { // Wait for next network block - self.client.wait_for_new_block(0).ok(); + self.rpc.wait_for_new_block(0).ok(); } } } } fn main() { + init(); let args: Args = argh::from_env(); + let mut app = App::start(args.datadir); match args.cmd { Cmd::Transfer(TransferCmd { from, to, amount }) => { - let mut app = App::start(args.datadir); let (mut client, _) = app.auto_wallet(&from); let (_, to) = app.auto_wallet(&to); let tx = client @@ -147,11 +151,9 @@ fn main() { println!("{}", tx); } Cmd::NextBlock(NextBlockCmd { to }) => { - let mut app = App::start(args.datadir); app.next_block(&to); } Cmd::Abandon(AbandonCmd { from }) => { - let mut app = App::start(args.datadir); let (mut wire, _) = app.auto_wallet(&from); let list = wire.list_since_block(None, 1, false).unwrap(); for tx in list.transactions { @@ -160,11 +162,21 @@ fn main() { } } } - Cmd::ClearDB(ClearCmd { config }) => { + Cmd::ResetDB(ResetCmd { config }) => { let config = CoreConfig::load_from_file(&config); + let hash: BlockHash = app.rpc.get_block_hash(0).unwrap(); let mut db = Client::connect(&config.db_url, NoTls).unwrap(); - db.execute("DROP TABLE IF EXISTS state, tx_in, tx_out, bounce", &[]) - .unwrap(); + let mut tx = db.transaction().unwrap(); + // Clear transaction tables and reset state + tx.execute("DELETE FROM tx_in", &[]).unwrap(); + tx.execute("DELETE FROM tx_out", &[]).unwrap(); + tx.execute("DELETE FROM bounce", &[]).unwrap(); + tx.execute( + "UPDATE state SET value=$1 WHERE name='last_hash'", + &[&hash.as_ref()], + ) + .unwrap(); + tx.commit().unwrap(); } } } diff --git a/btc-wire/src/config.rs b/btc-wire/src/config.rs @@ -69,12 +69,12 @@ impl BitcoinConfig { let main = conf.general_section(); if !main.contains_key("txindex") { - error!("btc_wire require a bitcoin core node running with 'txindex' option"); + error!("require a bitcoind node running with 'txindex' option"); exit(1); } if !main.contains_key("maxtxfee") { - error!("btc_wire require a bitcoin core node running with 'maxtxfee' option"); + error!("require a bitcoind node running with 'maxtxfee' option"); exit(1); } diff --git a/btc-wire/src/loops/worker.rs b/btc-wire/src/loops/worker.rs @@ -155,7 +155,7 @@ fn withdraw(db: &mut Client, rpc: &mut Rpc) -> LoopResult<bool> { Ok(row.is_some()) } -/// Bounce a transaction on the blockchain, return false if nor more requested transaction are found +/// Bounce a transaction on the blockchain, return false if no more requested transaction are found fn bounce(db: &mut Client, rpc: &mut Rpc, fee: &BtcAmount) -> LoopResult<bool> { // We rely on the advisory lock to ensure we are the only one sending transactions let row = db.query_opt( @@ -195,10 +195,9 @@ fn bounce(db: &mut Client, rpc: &mut Rpc, fee: &BtcAmount) -> LoopResult<bool> { } /// Retrieve last stored hash -fn last_hash(db: &mut Client) -> Result<Option<BlockHash>, postgres::Error> { - Ok(db - .query_opt("SELECT value FROM state WHERE name='last_hash'", &[])? - .map(|r| BlockHash::from_slice(r.get(0)).unwrap())) +fn last_hash(db: &mut Client) -> Result<BlockHash, postgres::Error> { + let row = db.query_one("SELECT value FROM state WHERE name='last_hash'", &[])?; + Ok(BlockHash::from_slice(row.get(0)).unwrap()) } /// Parse new transactions, return true if the database is up to date with the latest mined block @@ -215,7 +214,7 @@ fn sync_chain( // Get a set of transactions ids to parse 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)?; + let list = rpc.list_since_block(Some(&last_hash), min_confirmations, true)?; // Only keep ids and category let txs = list .transactions @@ -254,9 +253,6 @@ fn sync_chain( Category::Receive if confirmations >= min_confirmations as i32 => { sync_chain_incoming_confirmed(&id, rpc, db)? } - Category::Receive if confirmations < 0 => { - panic!("receive conflict {} {}", id, confirmations) - } _ => { // Ignore coinbase and unconfirmed send transactions } @@ -264,23 +260,13 @@ fn sync_chain( } // Move last_hash forward - { - let nb_row = if let Some(hash) = &last_hash { - db.execute( - "UPDATE state SET value=$1 WHERE name='last_hash' AND value=$2", - &[&lastblock.as_ref(), &hash.as_ref()], - )? - } else { - db.execute( - "INSERT INTO state (name, value) VALUES ('last_hash', $1) ON CONFLICT (name) DO NOTHING", + db.execute( + "UPDATE state SET value=$1 WHERE name='last_hash'", &[&lastblock.as_ref()], - )? - }; + )?; - if nb_row == 0 { - error!("watcher: hash state collision, database have been altered by another process"); - } - } + + dbg!(last_hash, lastblock); Ok(true) } @@ -372,9 +358,7 @@ fn sync_chain_outgoing( OutMetadata::Withdraw { wtid, .. } => { sync_chain_withdraw(id, &full, &wtid, rpc, db, confirmations, state)? } - OutMetadata::Bounce { bounced } => { - sync_chain_bounce(id, &bounced, db, confirmations)? - } + OutMetadata::Bounce { bounced } => sync_chain_bounce(id, &bounced, db, confirmations)?, }, Ok((_, Err(e))) => warn!("send: decode-info {} - {}", id, e), Err(e) => match e { @@ -563,6 +547,7 @@ fn sync_chain_bounce( } } } + Ok(()) } @@ -572,6 +557,7 @@ fn sync_chain_incoming_confirmed( rpc: &mut Rpc, db: &mut Client, ) -> Result<(), LoopError> { + dbg!(id); match rpc.get_tx_segwit_key(id) { Ok((full, reserve_pub)) => { // Store transactions in database diff --git a/btc-wire/src/rpc.rs b/btc-wire/src/rpc.rs @@ -210,6 +210,10 @@ impl Rpc { self.call("generatetoaddress", &(nb, address)) } + pub fn get_block_hash(&mut self, height: u32) -> Result<BlockHash> { + self.call("getblockhash", &[height]) + } + pub fn wait_for_new_block(&mut self, timeout: u64) -> Result<Nothing> { self.call("waitfornewblock", &[timeout]) } diff --git a/eth-wire/src/bin/eth-wire-cli.rs b/eth-wire/src/bin/eth-wire-cli.rs @@ -18,10 +18,11 @@ use eth_wire::{rpc::Rpc, BlockState}; use ethereum_types::H160; use common::{ config::{Config, CoreConfig}, - postgres::{Client, NoTls}, + postgres::{Client, NoTls}, log::init, }; fn main() { + init(); let args: Vec<_> = std::env::args().collect(); let config = CoreConfig::load_from_file(&args[2]); assert_eq!(config.currency, "ETH"); diff --git a/eth-wire/src/bin/eth-wire-utils.rs b/eth-wire/src/bin/eth-wire-utils.rs @@ -15,7 +15,7 @@ */ use std::{path::PathBuf, str::FromStr}; -use common::{api_common::Amount, rand_slice}; +use common::{api_common::Amount, rand_slice, log::init}; use eth_wire::{ rpc::{hex::Hex, Rpc, TransactionRequest}, taler_util::taler_to_eth, @@ -115,6 +115,7 @@ struct BalanceCmd { } fn main() { + init(); let args: Args = argh::from_env(); match args.cmd { Cmd::Deposit(DepositCmd { diff --git a/eth-wire/src/loops/worker.rs b/eth-wire/src/loops/worker.rs @@ -207,7 +207,7 @@ fn withdraw(db: &mut Client, rpc: &mut Rpc, state: &WireState) -> LoopResult<boo Ok(row.is_some()) } -/// Bounce a transaction on the blockchain, return false if nor more requested transaction are found +/// Bounce a transaction on the blockchain, return false if no more requested transaction are found fn bounce(db: &mut Client, rpc: &mut Rpc, fee: U256) -> LoopResult<bool> { // We rely on the advisory lock to ensure we are the only one sending transactions let row = db.query_opt( diff --git a/test/btc/reconnect.sh b/test/btc/reconnect.sh @@ -71,7 +71,7 @@ echo " OK" echo "----- Recover DB -----" echo "Reset database" -reset_db # Clear database tables +reset_db mine_btc # Trigger worker sleep 2 diff --git a/test/btc/stress.sh b/test/btc/stress.sh @@ -68,9 +68,10 @@ next_btc # Mine transactions echo "----- Recover DB -----" echo "Reset database" -reset_db # Clear database tables -mine_btc # Trigger worker sleep 5 +reset_db +mine_btc # Trigger worker +sleep 10 echo -n "Requesting exchange incoming transaction list:" check_delta "incoming?delta=-100" "$SEQ" "0.000" @@ -109,9 +110,10 @@ echo " OK" echo "----- Recover DB -----" echo "Reset database" -reset_db # Clear database tables -mine_btc # Trigger worker sleep 5 +reset_db +mine_btc # Trigger worker +sleep 10 echo -n "Requesting exchange incoming transaction list:" check_delta "incoming?delta=-100" "$SEQ" "0.000" diff --git a/test/common.sh b/test/common.sh @@ -45,11 +45,11 @@ function load_config() { source <(grep = $CONF | sed 's/ *= */=/' | sed 's/=\(.*\)/="\1"/g1') BANK_ENDPOINT=http://127.0.0.1:$PORT/ if [ "$CURRENCY" == "BTC" ]; then - WIRE_CLI=btc-wire-cli - WIRE_UTILS=btc-wire-utils + WIRE_CLI="btc-wire-cli" + WIRE_UTILS="btc-wire-utils -d $WIRE_DIR" else - WIRE_CLI=eth-wire-cli - WIRE_UTILS=eth-wire-utils + WIRE_CLI="eth-wire-cli" + WIRE_UTILS="eth-wire-utils -d $WIRE_DIR" fi } @@ -84,8 +84,7 @@ function setup_db() { # Erase database function reset_db() { - $WIRE_UTILS cleardb $CONF - $WIRE_CLI initdb $CONF + $WIRE_UTILS resetdb $CONF } # ----- Bitcoin node ----- # @@ -196,15 +195,15 @@ function check_balance() { # Start btc-wire function btc_wire() { cargo build --bin btc-wire --release &> log/cargo.log - target/release/btc-wire $CONF &> log/btc_wire.log & + target/release/btc-wire $CONF &> log/wire.log & WIRE_PID="$!" } # Start multiple btc_wire with random failures in parallel function stress_btc_wire() { cargo build --bin btc-wire --release --features fail &> log/cargo.log - target/release/btc-wire $CONF &> log/btc_wire.log & - target/release/btc-wire $CONF &> log/btc_wire1.log & + target/release/btc-wire $CONF &> log/wire.log & + target/release/btc-wire $CONF &> log/wire.log & } # ----- Ethereum node ----- # @@ -252,8 +251,8 @@ function init_eth() { # Check client and wire balance function check_balance_eth() { - local CLIENT_BALANCE=`eth-wire-utils -d $WIRE_DIR balance $CLIENT` - local WIRE_BALANCE=`eth-wire-utils -d $WIRE_DIR balance $WIRE` + local CLIENT_BALANCE=`$WIRE_UTILS balance $CLIENT` + local WIRE_BALANCE=`$WIRE_UTILS balance $WIRE` local CLIENT="${1:-*}" if [ "$1" == "*" ]; then local CLIENT="$CLIENT_BALANCE" @@ -270,13 +269,13 @@ function check_balance_eth() { # Start eth-wire function eth_wire() { cargo build --bin eth-wire --release &> log/cargo.log - target/release/eth-wire $CONF &> log/eth_wire.log & + target/release/eth-wire $CONF &> log/wire.log & WIRE_PID="$!" } # Mine ethereum blocks function mine_eth() { - eth-wire-utils -d $WIRE_DIR mine $RESERVE ${1:-} + $WIRE_UTILS mine $RESERVE ${1:-} } # Mine previous transactions