depolymerization

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

commit 9efcd48600a6a6d999b372460f568ef7063a6d40
parent 5c3ee6b9cd5f45d36e102bb2d3ed28c2e23a6154
Author: Antoine A <>
Date:   Wed, 16 Feb 2022 18:03:42 +0100

Encrypted wallet with user defined password

Diffstat:
MCargo.lock | 28++++++++++++++++++----------
MREADME.md | 12++++++++++--
Mbtc-wire/Cargo.toml | 2+-
Mbtc-wire/src/bin/btc-wire-utils.rs | 9++-------
Mbtc-wire/src/loops/analysis.rs | 4++--
Mbtc-wire/src/loops/watcher.rs | 4++--
Mbtc-wire/src/loops/worker.rs | 4++--
Mbtc-wire/src/main.rs | 19+++++++++++--------
Mbtc-wire/src/rpc.rs | 39+++++++++++++++++++++++++++++++++------
Mcommon/Cargo.toml | 2++
Mcommon/src/config.rs | 23+++++++++++------------
Mcommon/src/lib.rs | 15+++++++++++++--
Meth-wire/Cargo.toml | 2+-
Meth-wire/src/bin/eth-wire-utils.rs | 11++++++-----
Meth-wire/src/loops/analysis.rs | 4++--
Meth-wire/src/loops/watcher.rs | 4++--
Meth-wire/src/loops/worker.rs | 4++--
Meth-wire/src/main.rs | 22+++++++++-------------
Meth-wire/src/rpc.rs | 23+++++++++++++++++++----
Mtest/btc/conflict.sh | 4++--
Mtest/btc/wire.sh | 2+-
Mtest/common.sh | 8++++++--
Mtest/eth/analysis.sh | 4++--
Mtest/eth/lifetime.sh | 1+
24 files changed, 160 insertions(+), 90 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -124,7 +124,7 @@ dependencies = [ "base64", "bech32", "bitcoin", - "clap 3.0.14", + "clap 3.1.0", "common", "criterion", "hex", @@ -200,9 +200,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.0.14" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63edc3f163b3c71ec8aa23f9bd6070f77edbf3d1d198b164afa90ff00e4ec62" +checksum = "e5f1fea81f183005ced9e59cdb01737ef2423956dac5a6d731b06b2ecfaa3467" dependencies = [ "atty", "bitflags", @@ -217,9 +217,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.0.14" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1132dc3944b31c20dd8b906b3a9f0a5d0243e092d59171414969657ac6aa85" +checksum = "5fd1122e63869df2cb309f449da1ad54a7c6dfeb7c7e6ccd8e0825d9eb93bb72" dependencies = [ "heck", "proc-macro-error", @@ -244,6 +244,7 @@ dependencies = [ "thiserror", "time", "url", + "zeroize", ] [[package]] @@ -343,11 +344,12 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" dependencies = [ "generic-array", + "typenum", ] [[package]] @@ -442,9 +444,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ "block-buffer", "crypto-common", @@ -480,7 +482,7 @@ dependencies = [ name = "eth-wire" version = "0.1.0" dependencies = [ - "clap 3.0.14", + "clap 3.1.0", "common", "ethereum-types", "hex", @@ -2039,3 +2041,9 @@ dependencies = [ "tokio", "tokio-postgres", ] + +[[package]] +name = "zeroize" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c88870063c39ee00ec285a2f8d6a966e5b6fb2becc4e8dac77ed0d370ed6006" diff --git a/README.md b/README.md @@ -69,4 +69,12 @@ BUMP_DELAY = 0 Modules have specific configuration: - [wire-gateway](wire-gateway/README.md#Configuration) -- [btc-wire](btc-wire/README.md#Configuration) -\ No newline at end of file +- [btc-wire](btc-wire/README.md#Configuration) + +## Security + +Depolymerizer only use encrypted wallet, and provide an easy wait to create +them. However, it is the administrator responsibility to backup its wallet and +password. + +Only the wire need to have the password stored in its environnement. +\ No newline at end of file diff --git a/btc-wire/Cargo.toml b/btc-wire/Cargo.toml @@ -16,7 +16,7 @@ bitcoin = { version = "0.27.1", features = [ "use-serde", ], default-features = false } # Cli args parser -clap = { version = "3.0.14", features = ["derive"] } +clap = { version = "3.1.0", features = ["derive"] } # Bech32 encoding and decoding bech32 = "0.8.1" # Serialization library diff --git a/btc-wire/src/bin/btc-wire-utils.rs b/btc-wire/src/bin/btc-wire-utils.rs @@ -18,7 +18,7 @@ use std::path::PathBuf; use bitcoin::{Address, Amount, BlockHash, Network}; use btc_wire::{ config::BitcoinConfig, - rpc::{Category, Error, ErrorCode, Rpc}, + rpc::{Category, Rpc}, rpc_utils::default_data_dir, }; use clap::StructOpt; @@ -73,12 +73,7 @@ enum Cmd { pub fn auto_wallet(rpc: &mut Rpc, config: &BitcoinConfig, name: &str) -> (Rpc, Address) { // Auto load - if let Err(err) = rpc.load_wallet(name) { - match err { - Error::RPC { code, .. } if code == ErrorCode::RpcWalletAlreadyLoaded => {} - e => Err(e).unwrap(), - } - } + rpc.load_wallet(name).ok(); let mut wallet = Rpc::wallet(config, name).unwrap(); let addr = wallet .get_new_address() diff --git a/btc-wire/src/loops/analysis.rs b/btc-wire/src/loops/analysis.rs @@ -15,7 +15,7 @@ */ use std::sync::atomic::Ordering; -use btc_wire::rpc::{AutoReconnectRPC, ChainTipsStatus}; +use btc_wire::rpc::{AutoRpcCommon, ChainTipsStatus}; use common::{ log::log::{error, warn}, postgres::fallible_iterator::FallibleIterator, @@ -27,7 +27,7 @@ use crate::WireState; use super::LoopResult; /// Analyse blockchain behavior and adapt confirmations in real time -pub fn analysis(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb, state: &WireState) { +pub fn analysis(mut rpc: AutoRpcCommon, mut db: AutoReconnectDb, state: &WireState) { // The biggest fork ever seen let mut max_seen = 0; loop { diff --git a/btc-wire/src/loops/watcher.rs b/btc-wire/src/loops/watcher.rs @@ -1,4 +1,4 @@ -use btc_wire::rpc::AutoReconnectRPC; +use btc_wire::rpc::AutoRpcCommon; /* This file is part of TALER Copyright (C) 2022 Taler Systems SA @@ -19,7 +19,7 @@ use common::{log::log::error, reconnect::AutoReconnectDb}; use super::LoopResult; /// Wait for new block and notify arrival with postgreSQL notifications -pub fn watcher(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb) { +pub fn watcher(mut rpc: AutoRpcCommon, mut db: AutoReconnectDb) { loop { let rpc = rpc.client(); let db = db.client(); diff --git a/btc-wire/src/loops/worker.rs b/btc-wire/src/loops/worker.rs @@ -22,7 +22,7 @@ use std::{ use bitcoin::{hashes::Hash, Amount as BtcAmount, BlockHash, Txid}; use btc_wire::{ - rpc::{self, AutoReconnectRPC, Category, ErrorCode, Rpc, TransactionFull}, + rpc::{self, AutoRpcWallet, Category, ErrorCode, Rpc, TransactionFull}, rpc_utils::sender_address, GetOpReturnErr, GetSegwitErr, }; @@ -46,7 +46,7 @@ use crate::{ use super::{LoopError, LoopResult}; -pub fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb, state: &WireState) { +pub fn worker(mut rpc: AutoRpcWallet, mut db: AutoReconnectDb, state: &WireState) { let mut lifetime = state.config.wire_lifetime; let mut status = true; let mut skip_notification = false; diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs @@ -16,7 +16,7 @@ use bitcoin::{Amount as BtcAmount, Network}; use btc_wire::{ config::{BitcoinConfig, WIRE_WALLET_NAME}, - rpc::{self, auto_reconnect_rpc, ErrorCode, Rpc}, + rpc::{self, auto_rpc_common, auto_rpc_wallet, ErrorCode, Rpc}, rpc_utils::default_data_dir, }; use clap::StructOpt; @@ -24,7 +24,7 @@ use common::{ api_common::Amount, config::{load_btc_config, BtcConfig, Config, CoreConfig}, log::log::info, - named_spawn, + named_spawn, password, postgres::{Client, NoTls}, reconnect::auto_reconnect_db, }; @@ -63,7 +63,6 @@ struct Args { /// Override default configuration file path #[clap(global = true, short, long)] config: Option<PathBuf>, - #[clap(subcommand)] init: Option<Init>, } @@ -76,6 +75,8 @@ enum Init { Initwallet, } +/// TODO support external signer https://github.com/bitcoin/bitcoin/blob/master/doc/external-signer.md + fn main() { common::log::init(); let args = Args::parse(); @@ -127,7 +128,8 @@ fn init(config: Option<PathBuf>, init: Init) { } // Create wallet - let created = match rpc.create_wallet(WIRE_WALLET_NAME) { + let pwd = password(); + let created = match rpc.create_wallet(WIRE_WALLET_NAME, &pwd) { Err(rpc::Error::RPC { code, .. }) if code == ErrorCode::RpcWalletError => false, Err(e) => panic!("{}", e), Ok(_) => true, @@ -161,7 +163,8 @@ fn init(config: Option<PathBuf>, init: Init) { } else { println!("Found already existing wallet") } - println!("Address is {}", &addr); + println!("You must backup the generated key file and your chosen password, more info there: https://github.com/bitcoin/bitcoin/blob/master/doc/managing-wallets.md#14-backing-up-the-wallet"); + println!("Public address is {}", &addr); println!("Add the following line into taler.conf:"); println!("[depolymerizer-bitcoin]"); println!("PAYTO = payto://bitcoin/{}", addr); @@ -204,9 +207,9 @@ fn run(config: Option<PathBuf>) { let mut rpc = Rpc::common(&btc_config).unwrap(); rpc.load_wallet(WIRE_WALLET_NAME).ok(); - let rpc_watcher = auto_reconnect_rpc(btc_config.clone(), WIRE_WALLET_NAME); - let rpc_analysis = auto_reconnect_rpc(btc_config.clone(), WIRE_WALLET_NAME); - let rpc_worker = auto_reconnect_rpc(btc_config, WIRE_WALLET_NAME); + let rpc_watcher = auto_rpc_common(btc_config.clone()); + let rpc_analysis = auto_rpc_common(btc_config.clone()); + let rpc_worker = auto_rpc_wallet(btc_config, WIRE_WALLET_NAME); let db_watcher = auto_reconnect_db(state.config.core.db_url.clone()); let db_analysis = auto_reconnect_db(state.config.core.db_url.clone()); diff --git a/btc-wire/src/rpc.rs b/btc-wire/src/rpc.rs @@ -26,7 +26,7 @@ //! bitcoincore RPC documentation: <https://bitcoincore.org/en/doc/22.0.0/> use bitcoin::{hashes::hex::ToHex, Address, Amount, BlockHash, SignedAmount, Txid}; -use common::{log::log::error, reconnect::AutoReconnect}; +use common::{log::log::error, password, reconnect::AutoReconnect}; use serde_json::{json, Value}; use std::{ fmt::Debug, @@ -37,13 +37,31 @@ use std::{ use crate::config::{BitcoinConfig, BtcAuth}; -pub type AutoReconnectRPC = AutoReconnect<(BitcoinConfig, &'static str), Rpc>; +pub type AutoRpcWallet = AutoReconnect<(BitcoinConfig, &'static str), Rpc>; -pub fn auto_reconnect_rpc(config: BitcoinConfig, wallet: &'static str) -> AutoReconnectRPC { +pub fn auto_rpc_wallet(config: BitcoinConfig, wallet: &'static str) -> AutoRpcWallet { AutoReconnect::new( (config, wallet), |(config, wallet)| { - Rpc::wallet(config, wallet) + let mut rpc = Rpc::wallet(config, wallet) + .map_err(|err| error!("connect RPC: {}", err)) + .ok()?; + rpc.unlock_wallet(&password()) + .map_err(|err| error!("connect RPC: {}", err)) + .ok()?; + Some(rpc) + }, + |client| client.net_info().is_err(), + ) +} + +pub type AutoRpcCommon = AutoReconnect<BitcoinConfig, Rpc>; + +pub fn auto_rpc_common(config: BitcoinConfig) -> AutoRpcCommon { + AutoReconnect::new( + config, + |config| { + Rpc::common(config) .map_err(|err| error!("connect RPC: {}", err)) .ok() }, @@ -213,8 +231,17 @@ impl Rpc { self.call("loadwallet", &[name]) } - pub fn create_wallet(&mut self, name: &str) -> Result<Wallet> { - self.call("createwallet", &[name]) + /// Create encrypted native bitcoin wallet + pub fn create_wallet(&mut self, name: &str, pwd: &str) -> Result<Wallet> { + self.call("createwallet", &(name, (), (), pwd, (), true)) + } + + pub fn unlock_wallet(&mut self, pwd: &str) -> Result<()> { + // TODO Capped at 3yrs, is it enough ? + match self.call("walletpassphrase", &(pwd, 100000000)) { + Err(Error::Null) => Ok(()), + i => i, + } } pub fn get_new_address(&mut self) -> Result<Address> { diff --git a/common/Cargo.toml b/common/Cargo.toml @@ -33,3 +33,5 @@ time = { version = "0.3.7", features = ["formatting", "macros"] } postgres = "0.19.2" # Secure random rand = { version = "0.8.4", features = ["getrandom"] } +# Securely zero memory +zeroize = "1.5.2" diff --git a/common/src/config.rs b/common/src/config.rs @@ -14,6 +14,7 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ use ini::{Ini, Properties}; +use log::error; use std::{ fmt::Display, path::{Path, PathBuf}, @@ -33,7 +34,7 @@ pub trait Config: Sized { } let output = cmd .output() - .unwrap_or_else(|_| err("Failed to execute taler-config")); + .unwrap_or_else(|_| fail("Failed to execute taler-config")); if !output.status.success() { panic!( "taler-config failure:\n{}", @@ -46,7 +47,7 @@ pub trait Config: Sized { let curr = require(taler, "CURRENCY", string); if let Some(currency) = currency { if currency != curr { - err(format_args!( + fail(format_args!( "expected config CURRENCY = {} got {}", curr, currency )) @@ -55,7 +56,7 @@ pub trait Config: Sized { let section_name = match curr.as_str() { "BTC" => "depolymerizer-bitcoin", "ETH" => "depolymerizer-ethereum", - currency => err(format_args!("Unsupported currency {}", currency)), + currency => fail(format_args!("Unsupported currency {}", currency)), }; let dep = section(&conf, section_name); @@ -105,8 +106,6 @@ impl Config for GatewayConfig { } } -// TODO currency name as const generic - #[derive(Debug, Clone, PartialEq, Eq)] pub struct WireConfig { pub base_url: Url, @@ -153,7 +152,7 @@ pub fn load_eth_config(path: Option<&Path>) -> EthConfig { fn section<'a>(ini: &'a Ini, name: &str) -> &'a Properties { ini.section(Some(name)) - .unwrap_or_else(|| err(format_args!("missing config section {}", name))) + .unwrap_or_else(|| fail(format_args!("missing config section {}", name))) } fn require<T>( @@ -162,7 +161,7 @@ fn require<T>( lambda: fn(properties: &Properties, name: &str) -> Option<T>, ) -> T { let result = lambda(properties, name); - result.unwrap_or_else(|| err(format_args!("missing config {}", name))) + result.unwrap_or_else(|| fail(format_args!("missing config {}", name))) } fn string(properties: &Properties, name: &str) -> Option<String> { @@ -172,27 +171,27 @@ fn string(properties: &Properties, name: &str) -> Option<String> { fn path(properties: &Properties, name: &str) -> Option<PathBuf> { properties.get(name).map(|s| { PathBuf::from_str(s) - .unwrap_or_else(|_| err(format_args!("config value {} is not a valid path", name))) + .unwrap_or_else(|_| fail(format_args!("config value {} is not a valid path", name))) }) } fn nb<T: FromStr>(properties: &Properties, name: &str) -> Option<T> { properties.get(name).map(|s| { s.parse() - .unwrap_or_else(|_| err(format_args!("config value {} is not a number", name))) + .unwrap_or_else(|_| fail(format_args!("config value {} is not a number", name))) }) } fn url(properties: &Properties, name: &str) -> Option<Url> { properties.get(name).map(|s| { Url::parse(s) - .unwrap_or_else(|_| err(format_args!("config value {} is not a valid url", name))) + .unwrap_or_else(|_| fail(format_args!("config value {} is not a valid url", name))) }) } /* ----- Helper report functions ----- */ -fn err(msg: impl Display) -> ! { - eprintln!("error: {}", msg); +fn fail(msg: impl Display) -> ! { + error!("{}", msg); exit(1); } diff --git a/common/src/lib.rs b/common/src/lib.rs @@ -1,5 +1,6 @@ -use std::thread::JoinHandle; +use std::{process::exit, thread::JoinHandle}; +use ::log::error; /* This file is part of TALER Copyright (C) 2022 Taler Systems SA @@ -16,11 +17,12 @@ use std::thread::JoinHandle; TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ use rand::{rngs::OsRng, RngCore}; +use zeroize::Zeroizing; +pub use base32; pub use postgres; pub use rand; pub use url; -pub use base32; pub mod api_common; pub mod api_wire; @@ -50,3 +52,12 @@ where .spawn(f) .unwrap() } + +/// Read password from env +pub fn password() -> Zeroizing<String> { + let pwd = std::env::var("PWD").unwrap_or_else(|_| { + error!("Missing env var PWD"); + exit(1); + }); + Zeroizing::new(pwd) +} diff --git a/eth-wire/Cargo.toml b/eth-wire/Cargo.toml @@ -11,7 +11,7 @@ fail = [] [dependencies] # Cli args -clap = { version = "3.0.14", features = ["derive"] } +clap = { version = "3.1.0", features = ["derive"] } # Serialization library serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.78" diff --git a/eth-wire/src/bin/eth-wire-utils.rs b/eth-wire/src/bin/eth-wire-utils.rs @@ -24,7 +24,7 @@ use common::{ config::{Config, CoreConfig}, log::init, postgres::{Client, NoTls}, - rand_slice, + rand_slice, password, }; use eth_wire::{ rpc::{hex::Hex, Rpc, TransactionRequest}, @@ -108,6 +108,7 @@ fn main() { .and_then(|it| it.data_dir.as_deref()) .or(args.datadir.as_deref()); let mut rpc = Rpc::new(data_dir.unwrap().join("geth.ipc")).unwrap(); + let pwd = password(); match args.cmd { Cmd::Deposit(TransactionCmd { from, @@ -117,7 +118,7 @@ fn main() { }) => { let from = H160::from_str(&from).unwrap(); let to = H160::from_str(&to).unwrap(); - rpc.unlock_account(&from, "password").ok(); + rpc.unlock_account(&from, &pwd).ok(); for amount in amounts { let amount = Amount::from_str(&format!("ETH:{}{}", fmt, amount)).unwrap(); let value = taler_to_eth(&amount).unwrap(); @@ -132,7 +133,7 @@ fn main() { }) => { let from = H160::from_str(&from).unwrap(); let to = H160::from_str(&to).unwrap(); - rpc.unlock_account(&from, "password").ok(); + rpc.unlock_account(&from, &pwd).ok(); for amount in amounts { let amount = Amount::from_str(&format!("ETH:{}{}", fmt, amount)).unwrap(); let value = taler_to_eth(&amount).unwrap(); @@ -150,7 +151,7 @@ fn main() { } Cmd::Mine { to, mut amount } => { let to = H160::from_str(&to).unwrap(); - rpc.unlock_account(&to, "password").ok(); + rpc.unlock_account(&to, &pwd).ok(); let mut notifier = rpc.subscribe_new_head().unwrap(); rpc.miner_start().unwrap(); @@ -205,7 +206,7 @@ fn main() { } Cmd::Abandon { from } => { let from = H160::from_str(&from).unwrap(); - rpc.unlock_account(&from, "password").ok(); + rpc.unlock_account(&from, &pwd).ok(); let pending = rpc.pending_transactions().unwrap(); for tx in pending.into_iter().filter(|t| t.from == Some(from)) { // Replace transaction value with 0 diff --git a/eth-wire/src/loops/analysis.rs b/eth-wire/src/loops/analysis.rs @@ -21,7 +21,7 @@ use common::{ postgres::fallible_iterator::FallibleIterator, reconnect::AutoReconnectDb, }; -use eth_wire::rpc::{AutoReconnectRPC, Rpc}; +use eth_wire::rpc::{ Rpc, AutoRpcCommon}; use ethereum_types::{H256, U64}; use crate::WireState; @@ -29,7 +29,7 @@ use crate::WireState; use super::LoopResult; /// Analyse blockchain behavior and adapt confirmations in real time -pub fn analysis(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb, state: &WireState) { +pub fn analysis(mut rpc: AutoRpcCommon, mut db: AutoReconnectDb, state: &WireState) { // The biggest fork ever seen let mut max_seen = 0; let mut tip: Option<(U64, H256)> = None; diff --git a/eth-wire/src/loops/watcher.rs b/eth-wire/src/loops/watcher.rs @@ -14,12 +14,12 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ use common::{log::log::error, reconnect::AutoReconnectDb}; -use eth_wire::rpc::AutoReconnectRPC; +use eth_wire::rpc::AutoRpcCommon; use super::LoopResult; /// Wait for new block and notify arrival with postgreSQL notifications -pub fn watcher(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb) { +pub fn watcher(mut rpc: AutoRpcCommon, mut db: AutoReconnectDb) { loop { let rpc = rpc.client(); let db = db.client(); diff --git a/eth-wire/src/loops/worker.rs b/eth-wire/src/loops/worker.rs @@ -25,7 +25,7 @@ use common::{ }; use eth_wire::{ metadata::{InMetadata, OutMetadata}, - rpc::{self, AutoReconnectRPC, Rpc, Transaction}, + rpc::{self, AutoRpcWallet, Rpc, Transaction}, taler_util::{eth_payto_url, eth_to_taler}, SyncState, }; @@ -40,7 +40,7 @@ use crate::{ use super::LoopResult; -pub fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb, state: &WireState) { +pub fn worker(mut rpc: AutoRpcWallet, mut db: AutoReconnectDb, state: &WireState) { let mut lifetime = state.config.wire_lifetime; let mut status = true; let mut skip_notification = false; diff --git a/eth-wire/src/main.rs b/eth-wire/src/main.rs @@ -20,12 +20,12 @@ use clap::StructOpt; use common::{ api_common::Amount, config::{load_eth_config, Config, CoreConfig, EthConfig}, - named_spawn, + named_spawn, password, postgres::{Client, NoTls}, reconnect::auto_reconnect_db, }; use eth_wire::{ - rpc::{auto_reconnect_rpc, Rpc}, + rpc::{auto_rpc_common, auto_rpc_wallet, Rpc}, taler_util::{eth_payto_addr, taler_to_eth}, SyncState, }; @@ -61,7 +61,6 @@ struct Args { /// Override default configuration file path #[clap(global = true, short, long)] config: Option<PathBuf>, - #[clap(subcommand)] init: Option<Init>, } @@ -76,7 +75,6 @@ enum Init { fn main() { common::log::init(); - let args = Args::parse(); match args.init { @@ -132,9 +130,8 @@ fn init(config: Option<PathBuf>, init: Init) { (H160::from_slice(row.get(0)), false) } else { // Or generate a new one - let new = rpc - .new_account("password") - .expect("Failed creating account"); + let pwd = password(); + let new = rpc.new_account(&pwd).expect("Failed creating account"); db.execute( "INSERT INTO state (name, value) VALUES ('addr', $1)", &[&new.as_bytes()], @@ -150,7 +147,8 @@ fn init(config: Option<PathBuf>, init: Init) { }; let addr = hex::encode(addr.as_bytes()); - println!("Address is {}", &addr); + println!("You must backup the generated key file and your chosen password, more info there: https://geth.ethereum.org/docs/install-and-build/backup-restore"); + println!("Public address is {}", &addr); println!("Add the following line into taler.conf:"); println!("[depolymerizer-ethereum]"); println!("PAYTO = payto://ethereum/{}", addr); @@ -169,11 +167,9 @@ fn run(config: Option<PathBuf>) { config, })); - let rpc_worker = auto_reconnect_rpc(state.config.core.data_dir.clone().unwrap(), state.address); - let rpc_analysis = - auto_reconnect_rpc(state.config.core.data_dir.clone().unwrap(), state.address); - let rpc_watcher = - auto_reconnect_rpc(state.config.core.data_dir.clone().unwrap(), state.address); + let rpc_worker = auto_rpc_wallet(state.config.core.data_dir.clone().unwrap(), state.address); + let rpc_analysis = auto_rpc_common(state.config.core.data_dir.clone().unwrap()); + let rpc_watcher = auto_rpc_common(state.config.core.data_dir.clone().unwrap()); let db_watcher = auto_reconnect_db(state.config.core.db_url.clone()); let db_analysis = auto_reconnect_db(state.config.core.db_url.clone()); diff --git a/eth-wire/src/rpc.rs b/eth-wire/src/rpc.rs @@ -19,7 +19,7 @@ //! We only parse the thing we actually use, this reduce memory usage and //! make our code more compatible with future deprecation -use common::{log::log::error, reconnect::AutoReconnect, url::Url}; +use common::{log::log::error, password, reconnect::AutoReconnect, url::Url}; use ethereum_types::{Address, H256, U256, U64}; use serde::de::DeserializeOwned; use serde_json::error::Category; @@ -33,22 +33,37 @@ use std::{ use self::hex::Hex; -pub type AutoReconnectRPC = AutoReconnect<(PathBuf, Address), Rpc>; +pub type AutoRpcWallet = AutoReconnect<(PathBuf, Address), Rpc>; -pub fn auto_reconnect_rpc(data_dir: PathBuf, address: Address) -> AutoReconnectRPC { +pub fn auto_rpc_wallet(data_dir: PathBuf, address: Address) -> AutoRpcWallet { AutoReconnect::new( (data_dir.join("geth.ipc"), address), |(path, address)| { let mut rpc = Rpc::new(path) .map_err(|err| error!("connect RPC: {}", err)) .ok()?; - rpc.unlock_account(address, "password").ok()?; + rpc.unlock_account(address, &password()) + .map_err(|err| error!("connect RPC: {}", err)) + .ok()?; Some(rpc) }, |client| client.node_info().is_err(), ) } +pub type AutoRpcCommon = AutoReconnect<PathBuf, Rpc>; + +pub fn auto_rpc_common(data_dir: PathBuf) -> AutoRpcCommon { + AutoReconnect::new( + data_dir.join("geth.ipc"), + |path| { + Rpc::new(path) + .map_err(|err| error!("connect RPC: {}", err)) + .ok() + }, + |client| client.node_info().is_err(), + ) +} #[derive(Debug, serde::Serialize)] struct RpcRequest<'a, T: serde::Serialize> { method: &'a str, diff --git a/test/btc/conflict.sh b/test/btc/conflict.sh @@ -103,13 +103,13 @@ mine_btc $CONFIRMATION sleep 1 restart_btc mine_btc -check_balance 9.95994929 0.04001000 +check_balance 9.94997264 0.05001000 echo " OK" echo -n "Resend conflicting transaction:" sleep 5 # Wait for reconnection mine_btc -check_balance 9.99993744 0.00002000 +check_balance 9.99996079 0.00002000 echo " OK" echo "All tests passed!" \ No newline at end of file diff --git a/test/btc/wire.sh b/test/btc/wire.sh @@ -47,7 +47,7 @@ for n in `$SEQ`; do -C payto://bitcoin/$CLIENT \ -a BTC:0.0000$n > /dev/null done -sleep 6 +sleep 10 mine_btc # Mine transactions check_balance 9.95514310 "" echo " OK" diff --git a/test/common.sh b/test/common.sh @@ -32,12 +32,16 @@ for log in log/*; do echo -n "" > $log done +# Generate random password +PWD=`cat /proc/sys/kernel/random/uuid` + # Setup command helpers BTC_CLI="bitcoin-cli -datadir=$WIRE_DIR" BTC_CLI2="bitcoin-cli -datadir=$WIRE_DIR2" ETH_CLI="geth -datadir=$WIRE_DIR" ETH_CLI2="geth -datadir=$WIRE_DIR2" + # ----- Common ----- # # Load test.conf as bash variables @@ -227,7 +231,7 @@ function stress_btc_wire() { function init_eth() { # Create wallets for pswd in "reserve" "client"; do - $ETH_CLI account new --password <(echo "password") &> /dev/null + $ETH_CLI account new --password <(echo $PWD) &> /dev/null done # Retrieve addresses local ADDR=`$ETH_CLI account list 2> /dev/null | grep -oP '(?<={).*?(?=})'` @@ -273,7 +277,7 @@ function init_eth2() { $ETH_CLI2 --port 30305 --miner.gasprice 0 $* &>> log/node2.log & sleep 1 # Create etherbase account for mining - $ETH_CLI2 account new --password <(echo "password") &> /dev/null + $ETH_CLI2 account new --password <(echo $PWD) &> /dev/null # Connect nodes $WIRE_UTILS connect $WIRE_DIR2 } diff --git a/test/eth/analysis.sh b/test/eth/analysis.sh @@ -36,7 +36,7 @@ echo " OK" echo -n "Perform fork and check eth-wire hard error:" gateway_up -eth_fork 5 +eth_fork 6 check_balance_eth 1000000000 0 gateway_down echo " OK" @@ -58,7 +58,7 @@ echo " OK" echo -n "Perform fork and check eth-wire learned from previous attack:" gateway_up -eth_fork 5 +eth_fork 6 check_balance_eth 999580000 420000 gateway_up echo " OK" diff --git a/test/eth/lifetime.sh b/test/eth/lifetime.sh @@ -41,6 +41,7 @@ for n in `$SEQ`; do -C payto://ethereum/$CLIENT \ -a ETH:0.0000$n &> /dev/null || break; done +sleep 1 echo " OK" echo -n "Check down:"