commit 9efcd48600a6a6d999b372460f568ef7063a6d40
parent 5c3ee6b9cd5f45d36e102bb2d3ed28c2e23a6154
Author: Antoine A <>
Date: Wed, 16 Feb 2022 18:03:42 +0100
Encrypted wallet with user defined password
Diffstat:
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:"