gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-depolymerization] branch master updated (0b51ecd -> 245d087)


From: gnunet
Subject: [taler-depolymerization] branch master updated (0b51ecd -> 245d087)
Date: Thu, 17 Feb 2022 16:45:46 +0100

This is an automated email from the git hooks/post-receive script.

antoine pushed a change to branch master
in repository depolymerization.

    from 0b51ecd  Fix PWD name conflict
     new 17bbd09  btc-wire: rename magic id to random prefix and improve 
deposit metadata format documentation
     new c16d203  btc-wire: simplify rpc code and improve documentation
     new 245d087  Cleaning and replace code requiring rust version > 1.56.1

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 btc-wire/README.md                 |  45 +++++-
 btc-wire/src/bin/btc-wire-utils.rs |   6 +-
 btc-wire/src/bin/segwit-demo.rs    |  35 +++--
 btc-wire/src/config.rs             |  13 +-
 btc-wire/src/lib.rs                |  35 +----
 btc-wire/src/loops/analysis.rs     |   2 +-
 btc-wire/src/loops/watcher.rs      |   2 +-
 btc-wire/src/loops/worker.rs       |  10 +-
 btc-wire/src/main.rs               |   2 +-
 btc-wire/src/rpc.rs                | 277 +++++++++++++++++++------------------
 btc-wire/src/rpc_utils.rs          |   6 +-
 btc-wire/src/segwit.rs             |  42 +++---
 common/src/config.rs               |  29 ++--
 common/src/lib.rs                  |   2 +-
 common/src/log.rs                  |  22 +++
 script/prepare.sh                  |  19 +--
 test/common.sh                     |   2 +-
 wire-gateway/src/main.rs           |   2 +-
 18 files changed, 296 insertions(+), 255 deletions(-)

diff --git a/btc-wire/README.md b/btc-wire/README.md
index f8823e0..c41e745 100644
--- a/btc-wire/README.md
+++ b/btc-wire/README.md
@@ -52,12 +52,49 @@ with the same random pattern, at the exception of the first 
bit with must be 0
 for the first half and 1 for the second one. You must then send a single
 transaction with the three addresses as recipients.
 
-As a few lines of code can carry more meaning that many words you can find a
+Segwit addresses are encoded using a bitcoin specific format: 
+[bech32](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki)
+
+As a few lines of code can carry more meaning that many words, you can find a
 [simple rust example](src/bin/segwit-demo.rs) in this project and run it with
-`make segwit_demo`.
+`make segwit_demo`. 
 
-Segwit addresses are encoded using a bitcoin specific format: [bech32](
-[bech32](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki))
+```
+Ⅰ - Parse payto uri
+Got payto uri: 
payto://bitcoin/bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4?amount=BTC:0.1&subject=0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00
+Send 0.1 BTC to bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 with reserve public 
key 0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00
+
+Ⅱ - Generate fake segwit addresses
+Decode reserve public key: 
0x07f3d46620a0c138f5131f82d553706df68175cf4b6018b097a5c77e7b4453c0
+Generate random prefix 0x7ea4c272
+Split reserve public key in two:
+0x07f3d46620a0c138f5131f82d553706d
+0xf68175cf4b6018b097a5c77e7b4453c0
+Concatenate random prefix with each reserve public key half:
+0x7ea4c27207f3d46620a0c138f5131f82d553706d
+0x7ea4c272f68175cf4b6018b097a5c77e7b4453c0
+Set first bit of the first half:
+0x7ea4c27207f3d46620a0c138f5131f82d553706d
+Unset first bit of the second half:
+0xfea4c272f68175cf4b6018b097a5c77e7b4453c0
+Encode each half using bech32 to generate a segwit address:
+bc1q06jvyus8702xvg9qcyu02yclst24xurdjvsnqz
+bc1ql6jvyuhks96u7jmqrzcf0fw80ea5g57q2eccn6
+
+Ⅲ - Send to many
+Send a single bitcoin transaction with the three addresses as recipient as 
follow:
+
+In bitcoincore wallet use 'Add Recipient' button to add two additional 
recipient and copy adresses and amounts
+bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 0.10000000 BTC
+bc1q06jvyus8702xvg9qcyu02yclst24xurdjvsnqz 0.00000294 BTC
+bc1ql6jvyuhks96u7jmqrzcf0fw80ea5g57q2eccn6 0.00000294 BTC
+
+In Electrum wallet paste the following three lines in 'Pay to' field :
+bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4,0.10000000
+bc1q06jvyus8702xvg9qcyu02yclst24xurdjvsnqz,0.00000294
+bc1ql6jvyuhks96u7jmqrzcf0fw80ea5g57q2eccn6,0.00000294
+Make sure the amount show 0.10000588 BTC, else you have to change the base 
unit to BTC
+```
 
 ## Implementation details
 
diff --git a/btc-wire/src/bin/btc-wire-utils.rs 
b/btc-wire/src/bin/btc-wire-utils.rs
index 266c55d..9f7255f 100644
--- a/btc-wire/src/bin/btc-wire-utils.rs
+++ b/btc-wire/src/bin/btc-wire-utils.rs
@@ -76,7 +76,7 @@ pub fn auto_wallet(rpc: &mut Rpc, config: &BitcoinConfig, 
name: &str) -> (Rpc, A
     rpc.load_wallet(name).ok();
     let mut wallet = Rpc::wallet(config, name).unwrap();
     let addr = wallet
-        .get_new_address()
+        .gen_addr()
         .unwrap_or_else(|_| panic!("Failed to get wallet address {}", name));
     (wallet, addr)
 }
@@ -109,7 +109,7 @@ fn main() {
                 Network::Regtest => {
                     // Manually mine a block
                     let (_, addr) = auto_wallet(&mut rpc, &btc_config, &to);
-                    rpc.generate(1, &addr).unwrap();
+                    rpc.mine(1, &addr).unwrap();
                 }
                 _ => {
                     // Wait for next network block
@@ -119,7 +119,7 @@ fn main() {
         }
         Cmd::Abandon { from } => {
             let (mut wire, _) = auto_wallet(&mut rpc, &btc_config, &from);
-            let list = wire.list_since_block(None, 1, false).unwrap();
+            let list = wire.list_since_block(None, 1).unwrap();
             for tx in list.transactions {
                 if tx.category == Category::Send && tx.confirmations == 0 {
                     wire.abandon_tx(&tx.txid).unwrap();
diff --git a/btc-wire/src/bin/segwit-demo.rs b/btc-wire/src/bin/segwit-demo.rs
index 607b6e2..e34a1c8 100644
--- a/btc-wire/src/bin/segwit-demo.rs
+++ b/btc-wire/src/bin/segwit-demo.rs
@@ -6,14 +6,20 @@ use common::{
 };
 
 pub fn main() {
-    let address = "bc1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj";
+    let address = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4";
     let amount = Amount::from_sat(10000000);
     let reserve_pub = "0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00";
     let btc = amount.as_btc();
 
     println!("Ⅰ - Parse payto uri");
-    println!("Got payto uri: 
payto://bitcoin/{address}?amount=BTC:{btc}&subject={reserve_pub}");
-    println!("Send {btc} BTC to {address} with reserve public key 
{reserve_pub}");
+    println!(
+        "Got payto uri: payto://bitcoin/{}?amount=BTC:{}&subject={}",
+        address, btc, reserve_pub
+    );
+    println!(
+        "Send {} BTC to {} with reserve public key {}",
+        btc, address, reserve_pub
+    );
 
     println!("\nⅡ - Generate fake segwit addresses");
     let decoded: [u8; 32] = base32::decode(Alphabet::Crockford, reserve_pub)
@@ -21,17 +27,17 @@ pub fn main() {
         .try_into()
         .unwrap();
     println!("Decode reserve public key: 0x{}", hex::encode(&decoded[..]));
-    let magic_id: [u8; 4] = rand_slice();
-    println!("Generate magic id: 0x{}", hex::encode(&magic_id));
+    let prefix: [u8; 4] = rand_slice();
+    println!("Generate random prefix 0x{}", hex::encode(&prefix));
     println!(
         "Split reserve public key in two:\n0x{}\n0x{}",
         hex::encode(&decoded[..16]),
         hex::encode(&decoded[16..])
     );
-    let mut first_half = [&magic_id, &decoded[..16]].concat();
-    let mut second_half = [&magic_id, &decoded[16..]].concat();
+    let mut first_half = [&prefix, &decoded[..16]].concat();
+    let mut second_half = [&prefix, &decoded[16..]].concat();
     println!(
-        "Concatenate magic id with each reserve public key half:\n0x{}\n0x{}",
+        "Concatenate random prefix with each reserve public key 
half:\n0x{}\n0x{}",
         hex::encode(&first_half),
         hex::encode(&second_half)
     );
@@ -52,5 +58,16 @@ pub fn main() {
 
     println!("\nⅢ - Send to many");
     let minimum = rpc_utils::segwit_min_amount().as_btc();
-    println!("Send a single bitcoin transaction with the three addresses as 
recipient as follow:\n{address} {btc}BTC\n{first} {minimum}BTC\n{second} 
{minimum}BTC");
+    println!("Send a single bitcoin transaction with the three addresses as 
recipient as follow:");
+    println!("\nIn bitcoincore wallet use 'Add Recipient' button to add two 
additional recipient and copy adresses and amounts");
+    for (address, amount) in [(address, btc), (&first, minimum), (&second, 
minimum)] {
+        println!("{} {:.8} BTC", address, amount);
+    }
+    println!("\nIn Electrum wallet paste the following three lines in 'Pay to' 
field :");
+    for (address, amount) in [(address, btc), (&first, minimum), (&second, 
minimum)] {
+        println!("{},{:.8}", address, amount);
+    }
+    println!(
+        "Make sure the amount show 0.10000588 BTC, else you have to change the 
base unit to BTC"
+    )
 }
diff --git a/btc-wire/src/config.rs b/btc-wire/src/config.rs
index 405960d..516d38d 100644
--- a/btc-wire/src/config.rs
+++ b/btc-wire/src/config.rs
@@ -16,12 +16,11 @@
 use std::{
     net::SocketAddr,
     path::{Path, PathBuf},
-    process::exit,
     str::FromStr,
 };
 
 use bitcoin::Network;
-use common::log::log::error;
+use common::log::{fail, ExpectFail};
 
 pub const WIRE_WALLET_NAME: &str = "wire";
 
@@ -69,13 +68,11 @@ impl BitcoinConfig {
         let main = conf.general_section();
 
         if !main.contains_key("txindex") {
-            error!("require a bitcoind node running with 'txindex' option");
-            exit(1);
+            fail("require a bitcoind node running with 'txindex' option");
         }
 
         if !main.contains_key("maxtxfee") {
-            error!("require a bitcoind node running with 'maxtxfee' option");
-            exit(1);
+            fail("require a bitcoind node running with 'maxtxfee' option");
         }
 
         let network = if let Some("1") = main.get("testnet") {
@@ -97,14 +94,14 @@ impl BitcoinConfig {
 
         let port = if let Some(addr) = section.and_then(|s| s.get("rpcport")) {
             addr.parse()
-                .expect("bitcoin config value 'rpcport' is not a valid port 
number")
+                .expect_fail("bitcoin config value 'rpcport' is not a valid 
port number")
         } else {
             rpc_port(network)
         };
 
         let addr = if let Some(addr) = section.and_then(|s| s.get("rpcbind")) {
             SocketAddr::from_str(addr)
-                .expect("bitcoin config value 'rpcbind' is not a valid socket 
address")
+                .expect_fail("bitcoin config value 'rpcbind' is not a valid 
socket address")
         } else {
             ([127, 0, 0, 1], port).into()
         };
diff --git a/btc-wire/src/lib.rs b/btc-wire/src/lib.rs
index 3e9f692..15390d4 100644
--- a/btc-wire/src/lib.rs
+++ b/btc-wire/src/lib.rs
@@ -16,7 +16,7 @@
 use std::str::FromStr;
 
 use bitcoin::{hashes::hex::FromHex, Address, Amount, Network, Txid};
-use rpc::{Rpc, Category, TransactionFull};
+use rpc::{Category, Rpc, Transaction};
 use rpc_utils::{segwit_min_amount, sender_address};
 use segwit::{decode_segwit_msg, encode_segwit_key};
 
@@ -70,7 +70,7 @@ impl Rpc {
     pub fn get_tx_segwit_key(
         &mut self,
         id: &Txid,
-    ) -> Result<(TransactionFull, [u8; 32]), GetSegwitErr> {
+    ) -> Result<(Transaction, [u8; 32]), GetSegwitErr> {
         let full = self.get_tx(id)?;
 
         let addresses: Vec<String> = full
@@ -90,31 +90,11 @@ impl Rpc {
         Ok((full, metadata))
     }
 
-    /// Send a transaction with metadata encoded using OP_RETURN
-    pub fn send_op_return(
-        &mut self,
-        to: &Address,
-        amount: &Amount,
-        metadata: &[u8],
-        subtract_fee: bool,
-        replaceable: bool,
-    ) -> rpc::Result<Txid> {
-        assert!(metadata.len() > 0, "No medatata");
-        assert!(metadata.len() <= 80, "Max 80 bytes");
-        self.send_custom(
-            &[],
-            [(to, amount)],
-            Some(metadata),
-            subtract_fee,
-            replaceable,
-        )
-    }
-
     /// Get detailed information about an in-wallet transaction and its 
op_return metadata
     pub fn get_tx_op_return(
         &mut self,
         id: &Txid,
-    ) -> Result<(TransactionFull, Vec<u8>), GetOpReturnErr> {
+    ) -> Result<(Transaction, Vec<u8>), GetOpReturnErr> {
         let full = self.get_tx(id)?;
 
         let op_return_out = full
@@ -140,7 +120,7 @@ impl Rpc {
         &mut self,
         id: &Txid,
         bounce_fee: &Amount,
-        metadata: &[u8],
+        metadata: Option<&[u8]>,
     ) -> Result<Txid, rpc::Error> {
         let full = self.get_tx(id)?;
         let detail = &full.details[0];
@@ -150,11 +130,6 @@ impl Rpc {
         let sender = sender_address(self, &full)?;
         let bounce_amount = 
Amount::from_sat(amount.as_sat().saturating_sub(bounce_fee.as_sat()));
         // Send refund making recipient pay the transaction fees
-        let id = if metadata.is_empty() {
-            self.send(&sender, &bounce_amount, true)?
-        } else {
-            self.send_op_return(&sender, &bounce_amount, metadata, true, 
false)?
-        };
-        Ok(id)
+        self.send(&sender, &bounce_amount, metadata, true)
     }
 }
diff --git a/btc-wire/src/loops/analysis.rs b/btc-wire/src/loops/analysis.rs
index a3d5770..57b7bd1 100644
--- a/btc-wire/src/loops/analysis.rs
+++ b/btc-wire/src/loops/analysis.rs
@@ -42,7 +42,7 @@ pub fn analysis(mut rpc: AutoRpcCommon, mut db: 
AutoReconnectDb, state: &WireSta
                     .get_chain_tips()?
                     .into_iter()
                     .filter_map(|t| {
-                        (t.status == ChainTipsStatus::ValidFork).then(|| 
t.branch_length)
+                        (t.status == ChainTipsStatus::ValidFork).then(|| 
t.length)
                     })
                     .max()
                     .unwrap_or(0) as u16;
diff --git a/btc-wire/src/loops/watcher.rs b/btc-wire/src/loops/watcher.rs
index b4a2596..50c0039 100644
--- a/btc-wire/src/loops/watcher.rs
+++ b/btc-wire/src/loops/watcher.rs
@@ -1,4 +1,3 @@
-use btc_wire::rpc::AutoRpcCommon;
 /*
   This file is part of TALER
   Copyright (C) 2022 Taler Systems SA
@@ -15,6 +14,7 @@ use btc_wire::rpc::AutoRpcCommon;
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 use common::{log::log::error, reconnect::AutoReconnectDb};
+use btc_wire::rpc::AutoRpcCommon;
 
 use super::LoopResult;
 
diff --git a/btc-wire/src/loops/worker.rs b/btc-wire/src/loops/worker.rs
index 90b4ae4..7bfaab7 100644
--- 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, AutoRpcWallet, Category, ErrorCode, Rpc, TransactionFull},
+    rpc::{self, AutoRpcWallet, Category, ErrorCode, Rpc, Transaction},
     rpc_utils::sender_address,
     GetOpReturnErr, GetSegwitErr,
 };
@@ -166,7 +166,7 @@ fn sync_chain(
         BlockHash,
     ) = {
         // Get all transactions made since this block
-        let list = rpc.list_since_block(Some(&last_hash), min_confirmations, 
true)?;
+        let list = rpc.list_since_block(Some(&last_hash), min_confirmations)?;
         // Only keep ids and category
         let txs = list
             .transactions
@@ -349,7 +349,7 @@ fn sync_chain_incoming_confirmed(
 /// Sync database with an outgoing withdraw transaction, return true if stuck
 fn sync_chain_withdraw(
     id: &Txid,
-    full: &TransactionFull,
+    full: &Transaction,
     wtid: &[u8; 32],
     rpc: &mut Rpc,
     db: &mut Client,
@@ -559,7 +559,7 @@ fn withdraw(db: &mut Client, rpc: &mut Rpc) -> 
LoopResult<bool> {
         let url = sql_url(row, 4);
         let metadata = OutMetadata::Withdraw { wtid, url };
 
-        let tx_id = rpc.send_op_return(&addr, &amount, &metadata.encode(), 
false, true)?;
+        let tx_id = rpc.send(&addr, &amount, Some(&metadata.encode()), false)?;
         fail_point("(injected) fail withdraw", 0.3)?;
         db.execute(
             "UPDATE tx_out SET status=$1, txid=$2 WHERE id=$3",
@@ -583,7 +583,7 @@ fn bounce(db: &mut Client, rpc: &mut Rpc, fee: &BtcAmount) 
-> LoopResult<bool> {
         let bounced: Txid = sql_txid(row, 1);
         let metadata = OutMetadata::Bounce { bounced };
 
-        match rpc.bounce(&bounced, fee, &metadata.encode()) {
+        match rpc.bounce(&bounced, fee, Some(&metadata.encode())) {
             Ok(it) => {
                 fail_point("(injected) fail bounce", 0.3)?;
                 db.execute(
diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs
index d9a0675..6c5dbf3 100644
--- a/btc-wire/src/main.rs
+++ b/btc-wire/src/main.rs
@@ -147,7 +147,7 @@ fn init(config: Option<PathBuf>, init: Init) {
                 // Or generate a new one
                 let new = Rpc::wallet(&btc_conf, WIRE_WALLET_NAME)
                     .expect("Failed to connect to wallet bitcoin RPC server")
-                    .get_new_address()
+                    .gen_addr()
                     .expect("Failed to generate new address")
                     .to_string();
                 db.execute(
diff --git a/btc-wire/src/rpc.rs b/btc-wire/src/rpc.rs
index 66ab359..8fe8121 100644
--- a/btc-wire/src/rpc.rs
+++ b/btc-wire/src/rpc.rs
@@ -16,7 +16,7 @@
 //! This is a very simple RPC client designed only for a specific bitcoind 
version
 //! and to use on an secure localhost connection to a trusted node
 //!
-//! No http format of body length check as we trust the node output
+//! No http format or body length check as we trust the node output
 //! No asynchronous request as bitcoind put requests in a queue and process
 //! them synchronously and we do not want to fill this queue
 //!
@@ -51,7 +51,7 @@ pub fn auto_rpc_wallet(config: BitcoinConfig, wallet: 
&'static str) -> AutoRpcWa
                 .ok()?;
             Some(rpc)
         },
-        |client| client.net_info().is_err(),
+        |client| client.get_chain_tips().is_err(),
     )
 }
 
@@ -65,7 +65,7 @@ pub fn auto_rpc_common(config: BitcoinConfig) -> 
AutoRpcCommon {
                 .map_err(|err| error!("connect RPC: {}", err))
                 .ok()
         },
-        |client| client.net_info().is_err(),
+        |client| client.get_chain_tips().is_err(),
     )
 }
 
@@ -78,17 +78,17 @@ struct RpcRequest<'a, T: serde::Serialize> {
 
 #[derive(Debug, serde::Deserialize)]
 #[serde(untagged)]
-enum BtcResponse<T> {
+enum RpcResponse<T> {
     RpcResponse {
         result: Option<T>,
-        error: Option<BtcErr>,
+        error: Option<RpcError>,
         id: u64,
     },
     Error(String),
 }
 
 #[derive(Debug, serde::Deserialize)]
-struct BtcErr {
+struct RpcError {
     code: ErrorCode,
     message: String,
 }
@@ -202,9 +202,9 @@ impl Rpc {
         }
         // Read body
         let amount = sock.read_until(b'\n', buf)?;
-        let response: BtcResponse<T> = serde_json::from_slice(&buf[..amount])?;
+        let response: RpcResponse<T> = serde_json::from_slice(&buf[..amount])?;
         match response {
-            BtcResponse::RpcResponse { result, error, id } => {
+            RpcResponse::RpcResponse { result, error, id } => {
                 assert_eq!(self.id, id);
                 self.id += 1;
                 if let Some(ok) = result {
@@ -219,23 +219,23 @@ impl Rpc {
                     })
                 }
             }
-            BtcResponse::Error(msg) => Err(Error::Bitcoin(msg)),
+            RpcResponse::Error(msg) => Err(Error::Bitcoin(msg)),
         }
     }
 
-    pub fn net_info(&mut self) -> Result<Nothing> {
-        self.call("getnetworkinfo", &EMPTY)
-    }
-
-    pub fn load_wallet(&mut self, name: &str) -> Result<Wallet> {
-        self.call("loadwallet", &[name])
-    }
+    /* ----- Wallet management ----- */
 
     /// Create encrypted native bitcoin wallet
     pub fn create_wallet(&mut self, name: &str, passwd: &str) -> 
Result<Wallet> {
         self.call("createwallet", &(name, (), (), passwd, (), true))
     }
 
+    /// Load existing wallet
+    pub fn load_wallet(&mut self, name: &str) -> Result<Wallet> {
+        self.call("loadwallet", &[name])
+    }
+
+    /// Unlock loaded wallet
     pub fn unlock_wallet(&mut self, passwd: &str) -> Result<()> {
         // TODO Capped at 3yrs, is it enough ?
         match self.call("walletpassphrase", &(passwd, 100000000)) {
@@ -244,114 +244,125 @@ impl Rpc {
         }
     }
 
-    pub fn get_new_address(&mut self) -> Result<Address> {
+    /* ----- Wallet utils ----- */
+
+    /// Generate a new address fot the current wallet
+    pub fn gen_addr(&mut self) -> Result<Address> {
         self.call("getnewaddress", &EMPTY)
     }
 
-    pub fn generate(&mut self, nb: u16, address: &Address) -> 
Result<Vec<BlockHash>> {
+    /// Get current balance amount
+    pub fn get_balance(&mut self) -> Result<Amount> {
+        let btc: f64 = self.call("getbalance", &EMPTY)?;
+        Ok(Amount::from_btc(btc).unwrap())
+    }
+
+    /* ----- Mining ----- */
+
+    /// Mine a certain amount of block to profit a given address
+    pub fn mine(&mut self, nb: u16, address: &Address) -> 
Result<Vec<BlockHash>> {
         self.call("generatetoaddress", &(nb, address))
     }
 
+    /* ----- Getter ----- */
+
+    /// Get block hash at a given height
     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])
+    /// Get blockchain info
+    pub fn get_blockchain_info(&mut self) -> Result<BlockchainInfo> {
+        self.call("getblockchaininfo", &EMPTY)
     }
 
-    pub fn get_balance(&mut self) -> Result<Amount> {
-        let btc: f64 = self.call("getbalance", &EMPTY)?;
-        Ok(Amount::from_btc(btc).unwrap())
+    /// Get chain tips
+    pub fn get_chain_tips(&mut self) -> Result<Vec<ChainTips>> {
+        self.call("getchaintips", &EMPTY)
     }
 
-    pub fn get_blockchain_info(&mut self) -> Result<BlockchainInfo> {
-        self.call("getblockchaininfo", &EMPTY)
+    /// Get wallet transaction info from id
+    pub fn get_tx(&mut self, id: &Txid) -> Result<Transaction> {
+        self.call("gettransaction", &(id, (), true))
+    }
+
+    /// Get transaction inputs and outputs
+    pub fn get_input_output(&mut self, id: &Txid) -> Result<InputOutput> {
+        self.call("getrawtransaction", &(id, true))
     }
 
-    pub fn send(&mut self, address: &Address, amount: &Amount, subtract_fee: 
bool) -> Result<Txid> {
-        let btc = amount.as_btc();
-        self.call("sendtoaddress", &(address, btc, (), (), subtract_fee))
+    /* ----- Transactions ----- */
+
+    /// Send bitcoin transaction
+    pub fn send(
+        &mut self,
+        to: &Address,
+        amount: &Amount,
+        data: Option<&[u8]>,
+        subtract_fee: bool,
+    ) -> Result<Txid> {
+        self.send_custom([], [(to, amount)], data, subtract_fee)
+            .map(|it| it.txid)
     }
 
-    /// Send transaction to multiple recipients
-    pub fn send_many<'a, 'b>(
+    /// Send bitcoin transaction with multiple recipients
+    pub fn send_many<'a>(
         &mut self,
-        recipients: impl IntoIterator<Item = (&'a Address, &'b Amount)>,
+        to: impl IntoIterator<Item = (&'a Address, &'a Amount)>,
     ) -> Result<Txid> {
-        let amounts = Value::Object(
-            recipients
-                .into_iter()
-                .map(|(addr, amount)| (addr.to_string(), 
amount.as_btc().into()))
-                .collect(),
-        );
-        self.call("sendmany", &("", amounts))
+        self.send_custom([], to, None, false).map(|it| it.txid)
     }
 
-    pub fn send_custom<'a, 'b, 'c>(
+    fn send_custom<'a>(
         &mut self,
-        inputs: impl IntoIterator<Item = &'a Txid>,
-        outputs: impl IntoIterator<Item = (&'b Address, &'c Amount)>,
+        from: impl IntoIterator<Item = &'a Txid>,
+        to: impl IntoIterator<Item = (&'a Address, &'a Amount)>,
         data: Option<&[u8]>,
         subtract_fee: bool,
-        replaceable: bool,
-    ) -> Result<Txid> {
-        let mut outputs: Vec<Value> = outputs
+    ) -> Result<SendResult> {
+        // We use the experimental 'send' rpc command as it is the only 
capable to send metadata in a single rpc call
+        let inputs: Vec<_> = from
+            .into_iter()
+            .enumerate()
+            .map(|(i, id)| json!({"txid": id.to_string(), "vout": i}))
+            .collect();
+        let mut outputs: Vec<Value> = to
             .into_iter()
             .map(|(addr, amount)| json!({&addr.to_string(): amount.as_btc()}))
             .collect();
-        let len = outputs.len();
-        let hex: String = self.call(
-            "createrawtransaction",
+        let nb_outputs = outputs.len();
+        if let Some(data) = data {
+            assert!(data.len() > 0, "No medatata");
+            assert!(data.len() <= 80, "Max 80 bytes");
+            outputs.push(json!({ "data".to_string(): data.to_hex() }));
+        }
+        self.call(
+            "send",
             &(
-                Value::Array(
-                    inputs
-                        .into_iter()
-                        .enumerate()
-                        .map(|(i, id)| json!({"txid": id.to_string(), "vout": 
i}))
-                        .collect(),
-                ),
-                Value::Array({
-                    if let Some(data) = data {
-                        outputs.push(json!({ "data".to_string(): data.to_hex() 
}));
-                    }
-                    outputs
-                }),
+                outputs,
                 (),
-                true,
-            ),
-        )?;
-        let funded: HexWrapper = self.call(
-            "fundrawtransaction",
-            &(
-                hex,
-                FundOption {
+                (),
+                (),
+                SendOption {
+                    add_inputs: true,
+                    inputs,
                     subtract_fee_from_outputs: if subtract_fee {
-                        (0..len).into_iter().collect()
+                        (0..nb_outputs).into_iter().collect()
                     } else {
                         vec![]
                     },
-                    replaceable,
+                    replaceable: true,
                 },
             ),
-        )?;
-        let signed: HexWrapper = self.call("signrawtransactionwithwallet", 
&[&funded.hex])?;
-        self.call("sendrawtransaction", &[&signed.hex])
+        )
     }
 
-    pub fn bump_fee(&mut self, id: &Txid) -> Result<Bump> {
+    /// Bump transaction fees of a wallet debit
+    pub fn bump_fee(&mut self, id: &Txid) -> Result<BumpResult> {
         self.call("bumpfee", &[id])
     }
 
-    pub fn list_since_block(
-        &mut self,
-        hash: Option<&BlockHash>,
-        confirmation: u16,
-        include_remove: bool,
-    ) -> Result<ListSinceBlock> {
-        self.call("listsinceblock", &(hash, confirmation, (), include_remove))
-    }
-
+    /// Abandon a pending transaction
     pub fn abandon_tx(&mut self, id: &Txid) -> Result<()> {
         match self.call("abandontransaction", &[&id]) {
             Err(Error::Null) => Ok(()),
@@ -359,46 +370,26 @@ impl Rpc {
         }
     }
 
-    pub fn get_chain_tips(&mut self) -> Result<Vec<ChainTips>> {
-        self.call("getchaintips", &EMPTY)
-    }
+    /* ----- Watcher ----- */
 
-    pub fn get_tx(&mut self, id: &Txid) -> Result<TransactionFull> {
-        self.call("gettransaction", &(id, (), true))
+    /// Block until a new block is mined
+    pub fn wait_for_new_block(&mut self, timeout: u64) -> Result<Nothing> {
+        self.call("waitfornewblock", &[timeout])
     }
 
-    pub fn get_raw(&mut self, id: &Txid) -> Result<RawTransaction> {
-        self.call("getrawtransaction", &(id, true))
+    /// List new and removed transaction since a block
+    pub fn list_since_block(
+        &mut self,
+        hash: Option<&BlockHash>,
+        confirmation: u16,
+    ) -> Result<ListSinceBlock> {
+        self.call("listsinceblock", &(hash, confirmation, (), true))
     }
 }
 
-#[derive(Debug, serde::Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct FundOption {
-    pub subtract_fee_from_outputs: Vec<usize>,
-    pub replaceable: bool,
-}
-
 #[derive(Debug, serde::Deserialize)]
 pub struct Wallet {
     pub name: String,
-    pub warning: Option<String>,
-}
-
-#[derive(Debug, serde::Deserialize)]
-pub struct VoutScriptPubKey {
-    pub asm: String,
-    // nulldata do not have an address
-    pub address: Option<Address>,
-}
-
-#[derive(Debug, serde::Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct Vout {
-    #[serde(with = "bitcoin::util::amount::serde::as_btc")]
-    pub value: Amount,
-    pub n: u32,
-    pub script_pub_key: VoutScriptPubKey,
 }
 
 #[derive(Clone, Debug, serde::Deserialize)]
@@ -409,16 +400,20 @@ pub struct BlockchainInfo {
 }
 
 #[derive(Debug, serde::Deserialize)]
-pub struct Vin {
-    pub sequence: u32,
-    /// Not provided for coinbase txs.
-    pub txid: Option<Txid>,
-    /// Not provided for coinbase txs.
-    pub vout: Option<u32>,
+pub struct BumpResult {
+    pub txid: Txid,
+}
+
+#[derive(Debug, serde::Serialize)]
+pub struct SendOption {
+    pub add_inputs: bool,
+    pub inputs: Vec<Value>,
+    pub subtract_fee_from_outputs: Vec<usize>,
+    pub replaceable: bool,
 }
 
 #[derive(Debug, serde::Deserialize)]
-pub struct Bump {
+pub struct SendResult {
     pub txid: Txid,
 }
 
@@ -439,7 +434,6 @@ pub struct TransactionDetail {
     pub category: Category,
     #[serde(with = "bitcoin::util::amount::serde::as_btc")]
     pub amount: SignedAmount,
-    pub vout: u32,
     #[serde(default, with = "bitcoin::util::amount::serde::as_btc::opt")]
     pub fee: Option<SignedAmount>,
     /// Ony for send transaction
@@ -462,13 +456,37 @@ pub struct ListSinceBlock {
 }
 
 #[derive(Debug, serde::Deserialize)]
-pub struct RawTransaction {
+pub struct VoutScriptPubKey {
+    pub asm: String,
+    // nulldata do not have an address
+    pub address: Option<Address>,
+}
+
+#[derive(Debug, serde::Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Vout {
+    #[serde(with = "bitcoin::util::amount::serde::as_btc")]
+    pub value: Amount,
+    pub n: u32,
+    pub script_pub_key: VoutScriptPubKey,
+}
+
+#[derive(Debug, serde::Deserialize)]
+pub struct Vin {
+    /// Not provided for coinbase txs.
+    pub txid: Option<Txid>,
+    /// Not provided for coinbase txs.
+    pub vout: Option<u32>,
+}
+
+#[derive(Debug, serde::Deserialize)]
+pub struct InputOutput {
     pub vin: Vec<Vin>,
     pub vout: Vec<Vout>,
 }
 
 #[derive(Debug, serde::Deserialize)]
-pub struct TransactionFull {
+pub struct Transaction {
     pub confirmations: i32,
     pub time: u64,
     #[serde(with = "bitcoin::util::amount::serde::as_btc")]
@@ -478,20 +496,13 @@ pub struct TransactionFull {
     pub replaces_txid: Option<Txid>,
     pub replaced_by_txid: Option<Txid>,
     pub details: Vec<TransactionDetail>,
-    pub decoded: RawTransaction,
-}
-
-#[derive(Debug, serde::Deserialize)]
-pub struct HexWrapper {
-    pub hex: String,
+    pub decoded: InputOutput,
 }
 
 #[derive(Clone, PartialEq, Eq, serde::Deserialize, Debug)]
 pub struct ChainTips {
-    pub height: u64,
-    pub hash: bitcoin::BlockHash,
     #[serde(rename = "branchlen")]
-    pub branch_length: usize,
+    pub length: usize,
     pub status: ChainTipsStatus,
 }
 
diff --git a/btc-wire/src/rpc_utils.rs b/btc-wire/src/rpc_utils.rs
index 335b526..aefbb14 100644
--- a/btc-wire/src/rpc_utils.rs
+++ b/btc-wire/src/rpc_utils.rs
@@ -17,7 +17,7 @@ use std::{path::PathBuf, str::FromStr};
 
 use bitcoin::{Address, Amount};
 
-use crate::rpc::{self, Rpc, TransactionFull};
+use crate::rpc::{self, Rpc, Transaction};
 
 pub const CLIENT: &str = "client";
 pub const WIRE: &str = "wire";
@@ -48,9 +48,9 @@ pub fn segwit_min_amount() -> Amount {
 }
 
 /// Get the first sender address from a raw transaction
-pub fn sender_address(rpc: &mut Rpc, full: &TransactionFull) -> 
rpc::Result<Address> {
+pub fn sender_address(rpc: &mut Rpc, full: &Transaction) -> 
rpc::Result<Address> {
     let first = &full.decoded.vin[0];
-    let tx = rpc.get_raw(&first.txid.unwrap())?;
+    let tx = rpc.get_input_output(&first.txid.unwrap())?;
     Ok(tx
         .vout
         .into_iter()
diff --git a/btc-wire/src/segwit.rs b/btc-wire/src/segwit.rs
index 3555ffd..5b7414d 100644
--- a/btc-wire/src/segwit.rs
+++ b/btc-wire/src/segwit.rs
@@ -14,7 +14,7 @@
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 use bech32::{u5, FromBase32, ToBase32, Variant};
-use common::rand::{rngs::OsRng, RngCore};
+use common::{rand::rngs::OsRng, rand_slice};
 
 /// Encode metadata into a segwit address
 pub fn encode_segwit_addr(hrp: &str, metada: &[u8; 20]) -> String {
@@ -28,12 +28,12 @@ pub fn encode_segwit_addr(hrp: &str, metada: &[u8; 20]) -> 
String {
 fn encode_segwit_key_half(
     hrp: &str,
     is_first: bool,
-    magic_id: &[u8; 4],
+    prefix: &[u8; 4],
     key_half: &[u8; 16],
 ) -> String {
-    // Combine magic_it and the key half
+    // Combine prefix and the key half
     let mut buf = [0u8; 20];
-    buf[..4].copy_from_slice(magic_id);
+    buf[..4].copy_from_slice(prefix);
     buf[4..].copy_from_slice(key_half);
     // Toggle first bit for ordering
     if is_first {
@@ -47,15 +47,14 @@ fn encode_segwit_key_half(
 
 /// Encode a 32B key into two segwit adresses
 pub fn encode_segwit_key(hrp: &str, msg: &[u8; 32]) -> [String; 2] {
-    // Generate a random magic identifier
-    let mut magic_id = [0; 4];
-    OsRng.fill_bytes(&mut magic_id);
+    // Generate a random prefix
+    let prefix = rand_slice();
     // Split key in half;
     let split: (&[u8; 16], &[u8; 16]) =
         (msg[..16].try_into().unwrap(), msg[16..].try_into().unwrap());
     [
-        encode_segwit_key_half(hrp, true, &magic_id, split.0),
-        encode_segwit_key_half(hrp, false, &magic_id, split.1),
+        encode_segwit_key_half(hrp, true, &prefix, split.0),
+        encode_segwit_key_half(hrp, false, &prefix, split.1),
     ]
 }
 
@@ -63,10 +62,10 @@ pub fn encode_segwit_key(hrp: &str, msg: &[u8; 32]) -> 
[String; 2] {
 pub enum DecodeSegWitErr {
     #[error("There is less than 2 segwit addresses")]
     MissingSegWitAddress,
-    #[error("No adresses are sharing a magic id")]
-    NoMagicIdMatch,
-    #[error("More than two addresses are sharing a magic id")]
-    MagicIdCollision,
+    #[error("No adresses are sharing a common prefix")]
+    NoPrefixMatch,
+    #[error("More than two addresses are sharing a common prefix")]
+    PrefixCollision,
 }
 
 /// Decode a 32B key into from adresses
@@ -79,12 +78,12 @@ pub fn decode_segwit_msg(segwit_addrs: &[impl AsRef<str>]) 
-> Result<[u8; 32], D
                 // Skip version
                 let pg: Vec<u8> = Vec::from_base32(&wp[1..]).unwrap();
                 if pg.len() == 20 {
-                    let mut magic_id: [u8; 4] = pg[..4].try_into().unwrap();
+                    let mut prefix: [u8; 4] = pg[..4].try_into().unwrap();
                     let key_half: [u8; 16] = pg[4..].try_into().unwrap();
                     let is_first = !pg[0] & 0b1000_0000 == 0;
                     // Clear first bit
-                    magic_id[0] &= 0b0111_1111;
-                    Some((is_first, magic_id, key_half))
+                    prefix[0] &= 0b0111_1111;
+                    Some((is_first, prefix, key_half))
                 } else {
                     None
                 }
@@ -95,20 +94,21 @@ pub fn decode_segwit_msg(segwit_addrs: &[impl AsRef<str>]) 
-> Result<[u8; 32], D
     if decoded.len() < 2 {
         return Err(DecodeSegWitErr::MissingSegWitAddress);
     }
-    // Keep only the addresses with duplicated magic id
+    // Keep only the addresses with duplicated prefix
+    // TODO use sort_unstable_by and partition_dedup_by_key when stable
     let matches: Vec<&(bool, [u8; 4], [u8; 16])> = decoded
         .iter()
-        .filter(|(_, magic, _)| {
+        .filter(|(_, prefix, _)| {
             decoded
                 .iter()
-                .filter(|(_, other, _)| other == magic)
+                .filter(|(_, other, _)| other == prefix)
                 .count()
                 > 1
         })
         .collect();
 
     if matches.len() > 2 {
-        return Err(DecodeSegWitErr::MagicIdCollision);
+        return Err(DecodeSegWitErr::PrefixCollision);
     } else if matches.len() < 2 {
         return Err(DecodeSegWitErr::MissingSegWitAddress);
     }
@@ -122,7 +122,7 @@ pub fn decode_segwit_msg(segwit_addrs: &[impl AsRef<str>]) 
-> Result<[u8; 32], D
 
 // TODO find a way to hide that function while using it in test and benchmark
 pub fn rand_addresses(hrp: &str, key: &[u8; 32]) -> Vec<String> {
-    use common::{rand::prelude::SliceRandom, rand_slice};
+    use common::rand::prelude::SliceRandom;
 
     let mut rng_address: Vec<String> =
         std::iter::repeat_with(|| encode_segwit_addr(hrp, &rand_slice()))
diff --git a/common/src/config.rs b/common/src/config.rs
index 0596bbb..0607ef1 100644
--- a/common/src/config.rs
+++ b/common/src/config.rs
@@ -14,15 +14,15 @@
   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},
-    process::{exit, Command},
+    process::Command,
     str::FromStr,
 };
 use url::Url;
 
+use crate::log::{fail, ExpectFail};
+
 pub trait Config: Sized {
     /// Load using taler-config
     fn load_taler_config(file: Option<&Path>, currency: Option<&'static str>) 
-> Self {
@@ -32,9 +32,7 @@ pub trait Config: Sized {
             cmd.arg("-c");
             cmd.arg(path);
         }
-        let output = cmd
-            .output()
-            .unwrap_or_else(|_| fail("Failed to execute taler-config"));
+        let output = cmd.output().expect_fail("Failed to execute 
taler-config");
         if !output.status.success() {
             panic!(
                 "taler-config failure:\n{}",
@@ -152,7 +150,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(|| fail(format_args!("missing config section {}", 
name)))
+        .expect_fail(format_args!("missing config section {}", name))
 }
 
 fn require<T>(
@@ -161,7 +159,7 @@ fn require<T>(
     lambda: fn(properties: &Properties, name: &str) -> Option<T>,
 ) -> T {
     let result = lambda(properties, name);
-    result.unwrap_or_else(|| fail(format_args!("missing config {}", name)))
+    result.expect_fail(format_args!("missing config {}", name))
 }
 
 fn string(properties: &Properties, name: &str) -> Option<String> {
@@ -170,28 +168,19 @@ 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(|_| fail(format_args!("config value {} is not a 
valid path", name)))
+        PathBuf::from_str(s).expect_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(|_| fail(format_args!("config value {} is not a 
number", name)))
+            .expect_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(|_| fail(format_args!("config value {} is not a 
valid url", name)))
+        Url::parse(s).expect_fail(format_args!("config value {} is not a valid 
url", name))
     })
 }
-
-/* ----- Helper report functions ----- */
-
-fn fail(msg: impl Display) -> ! {
-    error!("{}", msg);
-    exit(1);
-}
diff --git a/common/src/lib.rs b/common/src/lib.rs
index 35c1fea..99a815d 100644
--- a/common/src/lib.rs
+++ b/common/src/lib.rs
@@ -36,7 +36,7 @@ pub mod status;
 /// Secure random slice generator using getrandom
 pub fn rand_slice<const N: usize>() -> [u8; N] {
     let mut slice = [0; N];
-    OsRng.fill_bytes(slice.as_mut_slice());
+    OsRng.fill_bytes(&mut slice);
     slice
 }
 
diff --git a/common/src/log.rs b/common/src/log.rs
index ccbfeb1..468b791 100644
--- a/common/src/log.rs
+++ b/common/src/log.rs
@@ -15,6 +15,8 @@
 */
 use flexi_logger::{DeferredNow, LogSpecification, Record};
 pub use log;
+use log::error;
+use std::{fmt::Display, process::exit};
 use time::{format_description::FormatItem, macros::format_description};
 
 const TIME_FORMAT: &[FormatItem<'static>] = format_description!(
@@ -45,4 +47,24 @@ pub fn init() {
         .unwrap();
 }
 
+pub trait ExpectFail<T> {
+    fn expect_fail(self, msg: impl Display) -> T;
+}
+
+impl<T, E> ExpectFail<T> for Result<T, E> {
+    fn expect_fail(self, msg: impl Display) -> T {
+        self.unwrap_or_else(|_| fail(msg))
+    }
+}
 
+impl<T> ExpectFail<T> for Option<T> {
+    fn expect_fail(self, msg: impl Display) -> T {
+        self.unwrap_or_else(|| fail(msg))
+    }
+}
+
+/// Log error message then exit
+pub fn fail(msg: impl Display) -> ! {
+    error!("{}", msg);
+    exit(1);
+}
diff --git a/script/prepare.sh b/script/prepare.sh
index 232210a..6aa4a54 100644
--- a/script/prepare.sh
+++ b/script/prepare.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-## Install required dependencies to run tests
+## Install required dependencies to run tests without sudo
 
 set -eu
 
@@ -16,13 +16,9 @@ function cleanup() {
 
 trap cleanup EXIT
 
-echo "Ⅰ - Install latest postgres from source"
-cd $DIR
-git clone --depth 1 https://git.postgresql.org/git/postgresql.git
-cd postgresql
-./configure --prefix ~/postgresql
-make
-make install
+echo "Ⅰ - Find installed postgres version"
+PG_VER=`pg_config --version | egrep -o '[0-9]{1,}' | head -1`
+echo "Found version $PG_VER"
 
 echo "Ⅱ - Install bitcoind version 0.22"
 cd $DIR
@@ -32,7 +28,6 @@ mkdir -pv ~/bitcoin
 tar xvzf btc.tar.gz
 mv -v bitcoin-22.0/* ~/bitcoin
 
-
 echo "Ⅲ - Install Go Ethereum (Geth) v1.10.15 "
 cd $DIR
 curl -L 
https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.10.15-8be800ff.tar.gz
 -o geth.tar.gz
@@ -41,8 +36,6 @@ mkdir -pv ~/geth
 tar xvzf geth.tar.gz
 mv -v geth-alltools-linux-amd64-1.10.15-8be800ff/* ~/geth
 
-echo "Ⅳ - Config"
+echo "Ⅳ - PATH"
 
-echo "Add ~/postgresql/bin to your path"
-echo "Add ~/bitcoin/bin to your path"
-echo "Add ~/geth to your path"
\ No newline at end of file
+echo "Add 
PATH=\"$HOME/geth:$HOME/bitcoin/bin:/usr/lib/postgresql/$PG_VER/bin:$PATH:$PATH\"
 to your bash profile"
\ No newline at end of file
diff --git a/test/common.sh b/test/common.sh
index de93956..716707a 100644
--- a/test/common.sh
+++ b/test/common.sh
@@ -291,7 +291,7 @@ function eth_deco() {
 function eth_fork() {
     $WIRE_UTILS2 mine $RESERVE ${1:-}
     $WIRE_UTILS connect $WIRE_DIR2
-    sleep 5
+    sleep 6
 }
 
 # Restart an initialized geth dev node
diff --git a/wire-gateway/src/main.rs b/wire-gateway/src/main.rs
index e6e4199..262d39b 100644
--- a/wire-gateway/src/main.rs
+++ b/wire-gateway/src/main.rs
@@ -492,7 +492,7 @@ fn status_watcher(state: &'static ServerState) {
 
     loop {
         if let Err(err) = inner(state) {
-            error!("status-watcher: {err}");
+            error!("status-watcher: {}", err);
         }
         std::thread::sleep(Duration::from_secs(5));
     }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]