depolymerization

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

commit e18367bae0a1cd3223896a6e55e7fac4b14f5266
parent d2a167cd660f3beae6dc4515b85a71bff9383f5d
Author: Antoine A <>
Date:   Wed, 23 Feb 2022 18:43:29 +0100

Better initialization and improved instrumentation test

Diffstat:
Mbtc-wire/src/bin/btc-wire-utils.rs | 2+-
Mbtc-wire/src/loops/analysis.rs | 3++-
Mbtc-wire/src/main.rs | 21++++++++++++++-------
Mbtc-wire/src/rpc.rs | 32++++++++++++++++++++++----------
Meth-wire/src/main.rs | 24+++++++++++++++++++-----
Minstrumentation/src/main.rs | 16++--------------
Ascript/tmp_db.sh | 26++++++++++++++++++++++++++
Mtest/btc/analysis.sh | 2--
Mtest/btc/bumpfee.sh | 2--
Mtest/btc/config.sh | 2--
Mtest/btc/conflict.sh | 4----
Mtest/btc/hell.sh | 4----
Mtest/btc/lifetime.sh | 2--
Mtest/btc/maxfee.sh | 2--
Mtest/btc/reconnect.sh | 2--
Mtest/btc/reorg.sh | 2--
Mtest/btc/stress.sh | 2--
Mtest/btc/wire.sh | 2--
Mtest/common.sh | 4++++
Mtest/eth/analysis.sh | 2--
Mtest/eth/hell.sh | 4----
Mtest/eth/lifetime.sh | 2--
Mtest/eth/maxfee.sh | 2--
Mtest/eth/reconnect.sh | 2--
Mtest/eth/reorg.sh | 2--
Mtest/eth/stress.sh | 2--
Mtest/eth/test.sh | 2--
Mtest/eth/wire.sh | 2--
Mtest/gateway/api.sh | 4++--
29 files changed, 92 insertions(+), 86 deletions(-)

diff --git a/btc-wire/src/bin/btc-wire-utils.rs b/btc-wire/src/bin/btc-wire-utils.rs @@ -127,7 +127,7 @@ fn main() { } } Cmd::Resetdb => { - let hash: BlockHash = rpc.get_block_hash(0).unwrap(); + let hash: BlockHash = rpc.get_genesis().unwrap(); let mut db = Client::connect(&config.unwrap().db_url, NoTls).unwrap(); let mut tx = db.transaction().unwrap(); // Clear transaction tables and reset state diff --git a/btc-wire/src/loops/analysis.rs b/btc-wire/src/loops/analysis.rs @@ -13,7 +13,7 @@ You should have received a copy of the GNU Affero General Public License along with TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -use std::sync::atomic::Ordering; +use std::{sync::atomic::Ordering, time::Duration}; use btc_wire::rpc::{AutoRpcCommon, ChainTipsStatus}; use common::{ @@ -70,6 +70,7 @@ pub fn analysis(mut rpc: AutoRpcCommon, mut db: AutoReconnectDb, state: &WireSta })(); if let Err(e) = result { error!("analysis: {}", e); + std::thread::sleep(Duration::from_secs(5)); } } } diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs @@ -79,6 +79,11 @@ fn init(config: Option<PathBuf>, init: Init) { let config = CoreConfig::load_taler_config(config.as_deref(), Some("BTC")); // Connect to database let mut db = Client::connect(&config.db_url, NoTls).expect("Failed to connect to database"); + // Parse bitcoin config + let btc_conf = BitcoinConfig::load(config.data_dir.unwrap_or_else(default_data_dir)) + .expect("Failed to load bitcoin configuration"); + // Connect to bitcoin node + let mut rpc = Rpc::common(&btc_conf).expect("Failed to connect to bitcoin RPC server"); match init { Init::Initdb => { // Load schema @@ -91,16 +96,18 @@ fn init(config: Option<PathBuf>, init: Init) { &[&[1u8].as_ref()], ) .expect("Failed to initialise database state"); + // Init last_hash if not already set + let genesis_hash = rpc.get_genesis().expect("Failed to get genesis hash"); + db + .execute( + "INSERT INTO state (name, value) VALUES ('last_hash', $1) ON CONFLICT (name) DO NOTHING", + &[&genesis_hash.as_ref()], + ) + .expect("Failed to update database state"); println!("Database initialised"); } Init::Initwallet => { - // Parse bitcoin config - let btc_conf = BitcoinConfig::load(config.data_dir.unwrap_or_else(default_data_dir)) - .expect("Failed to load bitcoin configuration"); - // Connect to bitcoin node - let mut rpc = Rpc::common(&btc_conf).expect("Failed to connect to bitcoin RPC server"); - - // Skip previous blocks + // Skip past blocks let info = rpc .get_blockchain_info() .expect("Failed to get blockchain info"); diff --git a/btc-wire/src/rpc.rs b/btc-wire/src/rpc.rs @@ -31,8 +31,8 @@ use serde_json::{json, Value}; use std::{ fmt::Debug, io::{self, BufRead, BufReader, Write}, - net::TcpStream, - time::Duration, + net::{TcpStream, SocketAddr}, + time::{Duration, Instant}, }; use crate::config::{BitcoinConfig, BtcAuth}; @@ -113,6 +113,8 @@ const EMPTY: [(); 0] = []; /// Bitcoin RPC connection pub struct Rpc { + last_call: Instant, + addr: SocketAddr, path: String, id: u64, cookie: String, @@ -149,6 +151,8 @@ impl Rpc { let conn = BufReader::new(sock); Ok(Self { + last_call: Instant::now(), + addr: config.addr, path, id: 0, cookie: format!("Basic {}", base64::encode(token)), @@ -161,7 +165,13 @@ impl Rpc { where T: serde::de::DeserializeOwned + Debug, { - // TODO rethink timeout + // Handle bitcoind RPC client timeout + if self.last_call.elapsed() > Duration::from_secs(60) { + // Create new connection + let sock = TcpStream::connect_timeout(&self.addr, Duration::from_secs(5))?; + self.conn = BufReader::new(sock); + } + let request = RpcRequest { method, id: self.id, @@ -203,7 +213,7 @@ impl Rpc { // Read body let amount = sock.read_until(b'\n', buf)?; let response: RpcResponse<T> = serde_json::from_slice(&buf[..amount])?; - match response { + let result = match response { RpcResponse::RpcResponse { result, error, id } => { assert_eq!(self.id, id); self.id += 1; @@ -220,7 +230,9 @@ impl Rpc { } } RpcResponse::Error(msg) => Err(Error::Bitcoin(msg)), - } + }; + self.last_call = Instant::now(); + return result; } /* ----- Wallet management ----- */ @@ -266,11 +278,6 @@ impl Rpc { /* ----- Getter ----- */ - /// Get block hash at a given height - pub fn get_block_hash(&mut self, height: u32) -> Result<BlockHash> { - self.call("getblockhash", &[height]) - } - /// Get blockchain info pub fn get_blockchain_info(&mut self) -> Result<BlockchainInfo> { self.call("getblockchaininfo", &EMPTY) @@ -291,6 +298,11 @@ impl Rpc { self.call("getrawtransaction", &(id, true)) } + /// Get genesis block hash + pub fn get_genesis(&mut self) -> Result<BlockHash> { + self.call("getblockhash", &[0]) + } + /* ----- Transactions ----- */ /// Send bitcoin transaction diff --git a/eth-wire/src/main.rs b/eth-wire/src/main.rs @@ -84,8 +84,13 @@ fn main() { } fn init(config: Option<PathBuf>, init: Init) { + // Parse taler config let config = CoreConfig::load_taler_config(config.as_deref(), Some("ETH")); + // Connect to database let mut db = Client::connect(&config.db_url, NoTls).expect("Failed to connect to database"); + // Connect to ethereum node + let mut rpc = Rpc::new(config.data_dir.unwrap().join("geth.ipc")) + .expect("Failed to connect to ethereum RPC server"); match init { Init::Initdb => { @@ -99,15 +104,24 @@ fn init(config: Option<PathBuf>, init: Init) { &[&[1u8].as_ref()], ) .expect("Failed to initialise database state"); + // Init sync if not already set + let block = rpc.earliest_block().expect("Failed to get earliest block"); + let state = SyncState { + tip_hash: block.hash.unwrap(), + tip_height: block.number.unwrap(), + conf_height: block.number.unwrap(), + }; + db + .execute( + "INSERT INTO state (name, value) VALUES ('sync', $1) ON CONFLICT (name) DO NOTHING", + &[&state.to_bytes().as_ref()], + ) + .expect("Failed to update database state"); println!("Database initialised"); } Init::Initwallet => { - // Connect to ethereum node - let mut rpc = Rpc::new(config.data_dir.unwrap().join("geth.ipc")) - .expect("Failed to connect to ethereum RPC server"); - // Skip previous blocks - let block = rpc.latest_block().expect("Failed to get current block"); + let block = rpc.latest_block().expect("Failed to get latest block"); let state = SyncState { tip_hash: block.hash.unwrap(), tip_height: block.number.unwrap(), diff --git a/instrumentation/src/main.rs b/instrumentation/src/main.rs @@ -89,7 +89,7 @@ pub fn main() { rpc.create_wallet(CLIENT, "").unwrap(); } Err(rpc::Error::RPC { - code: ErrorCode::RpcWalletError, + code: ErrorCode::RpcWalletError | ErrorCode::RpcWalletAlreadyLoaded, .. }) => {} Err(e) => panic!("{}", e), @@ -106,18 +106,6 @@ pub fn main() { } let mut since = client_rpc.list_since_block(None, 1).unwrap().lastblock; // Load wire - match rpc.load_wallet(WIRE) { - Ok(_) => {} - Err(rpc::Error::RPC { - code: ErrorCode::RpcWalletError, - .. - }) => {} - Err(rpc::Error::RPC { - code: ErrorCode::RpcWalletNotFound, - .. - }) => panic!("Wire wallet is not initialized"), - Err(e) => panic!("{}", e), - }; let mut wire_rpc = Rpc::wallet(&btc_config, WIRE).unwrap(); let wire_addr = wire_rpc.gen_addr().unwrap(); // Load balances @@ -243,7 +231,7 @@ pub fn main() { pending = false; rpc.wait_for_new_block().unwrap(); print_now("."); - let sync = rpc.list_since_block(Some(&since), 1).unwrap(); + let sync = wire_rpc.list_since_block(Some(&since), 1).unwrap(); for tx in sync.transactions { if tx.confirmations == 0 { pending = true; diff --git a/script/tmp_db.sh b/script/tmp_db.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +## Generate a new database in a temporary directory for instrumentation test against a local blockchain + +source "${BASH_SOURCE%/*}/common.sh" + +DIR=$(mktemp -d) + +# Cleanup to run whenever we exit +function cleanup() { + pg_ctl stop -D $DIR -w &> /dev/null + wait + rm -rf $DIR &> /dev/null || true +} + +# Install cleanup handler (except for kill -9) +trap cleanup EXIT + +echo "----- Setup db -----" +pg_ctl init -D $DIR +echo "port=5454" >> $DIR/postgresql.conf +pg_ctl start -D $DIR -o "-c unix_socket_directories=$DIR" +echo "CREATE ROLE postgres LOGIN SUPERUSER PASSWORD 'password'" | psql -h localhost -p 5454 postgres > /dev/null +echo "" + +read -p "Waiting for input to close DB:" IGNORE diff --git a/test/btc/analysis.sh b/test/btc/analysis.sh @@ -10,8 +10,6 @@ CONFIG=taler_btc.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start second bitcoin node" diff --git a/test/btc/bumpfee.sh b/test/btc/bumpfee.sh @@ -10,8 +10,6 @@ CONFIG=taler_btc_bump.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start second bitcoin node" diff --git a/test/btc/config.sh b/test/btc/config.sh @@ -14,8 +14,6 @@ function test() { echo "Load config file" load_config - echo "Start database" - setup_db echo "Start bitcoin node" init_btc echo "Cleanup" diff --git a/test/btc/conflict.sh b/test/btc/conflict.sh @@ -10,8 +10,6 @@ CONFIG=taler_btc.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start second bitcoin node" @@ -69,8 +67,6 @@ cleanup source "${BASH_SOURCE%/*}/../common.sh" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start second bitcoin node" diff --git a/test/btc/hell.sh b/test/btc/hell.sh @@ -10,8 +10,6 @@ CONFIG=taler_btc.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start second bitcoin node" @@ -65,8 +63,6 @@ cleanup source "${BASH_SOURCE%/*}/../common.sh" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start second bitcoin node" diff --git a/test/btc/lifetime.sh b/test/btc/lifetime.sh @@ -11,8 +11,6 @@ CONFIG=taler_btc_lifetime.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start btc-wire" diff --git a/test/btc/maxfee.sh b/test/btc/maxfee.sh @@ -10,8 +10,6 @@ CONFIG=taler_btc.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start btc-wire" diff --git a/test/btc/reconnect.sh b/test/btc/reconnect.sh @@ -10,8 +10,6 @@ CONFIG=taler_btc.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start btc-wire" diff --git a/test/btc/reorg.sh b/test/btc/reorg.sh @@ -10,8 +10,6 @@ CONFIG=taler_btc.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start second bitcoin node" diff --git a/test/btc/stress.sh b/test/btc/stress.sh @@ -10,8 +10,6 @@ CONFIG=taler_btc.conf echo "----- Setup stressed -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start stressed btc-wire" diff --git a/test/btc/wire.sh b/test/btc/wire.sh @@ -10,8 +10,6 @@ CONFIG=taler_btc.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start bitcoin node" init_btc echo "Start btc-wire" diff --git a/test/common.sh b/test/common.sh @@ -120,6 +120,8 @@ function init_btc() { NODE_PID="$!" # Wait for RPC server to be online $BTC_CLI -rpcwait getnetworkinfo > /dev/null + # Setup db + setup_db # Create wire wallet $WIRE_CLI initwallet > /dev/null # Create other wallets @@ -262,6 +264,8 @@ function init_eth() { $ETH_CLI init $DIR/genesis.json &>> log/node.log # Start node start_eth $* + # Setup db + setup_db # Create wire address WIRE=`$WIRE_CLI initwallet | grep -oP '(?<=is ).*'` echo -e "PAYTO = payto://ethereum/$WIRE" >> $CONF diff --git a/test/eth/analysis.sh b/test/eth/analysis.sh @@ -10,8 +10,6 @@ CONFIG=taler_eth.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start ethereum node" init_eth --miner.gasprice 0 echo "Start second ethereum node" diff --git a/test/eth/hell.sh b/test/eth/hell.sh @@ -10,8 +10,6 @@ CONFIG=taler_eth.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start ethereum node" init_eth --miner.gasprice 0 echo "Start second ethereum node" @@ -62,8 +60,6 @@ cleanup source "${BASH_SOURCE%/*}/../common.sh" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start ethereum node" init_eth --miner.gasprice 0 echo "Start second ethereum node" diff --git a/test/eth/lifetime.sh b/test/eth/lifetime.sh @@ -11,8 +11,6 @@ CONFIG=taler_eth_lifetime.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start ethereum node" init_eth --miner.gasprice 0 echo "Start eth-wire" diff --git a/test/eth/maxfee.sh b/test/eth/maxfee.sh @@ -10,8 +10,6 @@ CONFIG=taler_eth.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start ethereum node" init_eth --miner.gasprice 0 echo "Start eth-wire" diff --git a/test/eth/reconnect.sh b/test/eth/reconnect.sh @@ -10,8 +10,6 @@ CONFIG=taler_eth.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start ethereum node" init_eth --miner.gasprice 0 echo "Start eth-wire" diff --git a/test/eth/reorg.sh b/test/eth/reorg.sh @@ -10,8 +10,6 @@ CONFIG=taler_eth.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start ethereum node" init_eth --miner.gasprice 0 echo "Start second ethereum node" diff --git a/test/eth/stress.sh b/test/eth/stress.sh @@ -10,8 +10,6 @@ CONFIG=taler_eth.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start ethereum node" init_eth --miner.gasprice 0 echo "Start stressed eth-wire" diff --git a/test/eth/test.sh b/test/eth/test.sh @@ -8,8 +8,6 @@ CONFIG=taler_eth.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start ethereum node" init_eth --miner.gasprice 0 echo "" diff --git a/test/eth/wire.sh b/test/eth/wire.sh @@ -10,8 +10,6 @@ CONFIG=taler_eth.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db echo "Start ethereum node" init_eth --miner.gasprice 0 echo "Start eth-wire" diff --git a/test/gateway/api.sh b/test/gateway/api.sh @@ -23,8 +23,8 @@ CONFIG=taler_btc.conf echo "----- Setup -----" echo "Load config file" load_config -echo "Start database" -setup_db +echo "Start bitcoin node" +init_btc echo "Start gateway" gateway echo ""