gnunet-svn
[Top][All Lists]
Advanced

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

[taler-depolymerization] branch master updated (e32c20e -> 30d29f5)


From: gnunet
Subject: [taler-depolymerization] branch master updated (e32c20e -> 30d29f5)
Date: Wed, 20 Jul 2022 21:27:12 +0200

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

antoine pushed a change to branch master
in repository depolymerization.

    from e32c20e  Some more typos plus explanation of the denominaton keys
     new a29a243  Rewriting tests in rust
     new 15b9fb4  Use latest nodes versions and improve documentation
     new 30d29f5  Update dependencies

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:
 Cargo.lock                                         | 713 ++++++++-------
 README.md                                          |  29 +-
 btc-wire/Cargo.toml                                |  16 +-
 btc-wire/benches/metadata.rs                       |  78 +-
 btc-wire/src/bin/btc-wire-utils.rs                 | 134 ---
 btc-wire/src/bin/segwit-demo.rs                    |  10 +-
 btc-wire/src/loops.rs                              |   2 +-
 btc-wire/src/loops/analysis.rs                     |   6 +-
 btc-wire/src/loops/watcher.rs                      |   2 +-
 btc-wire/src/loops/worker.rs                       |   4 +-
 btc-wire/src/rpc.rs                                |  33 +-
 common/Cargo.toml                                  |  18 +-
 common/src/sql.rs                                  |   8 +-
 common/src/status.rs                               |   2 +-
 eth-wire/Cargo.toml                                |  10 +-
 eth-wire/src/bin/eth-wire-utils.rs                 | 234 -----
 eth-wire/src/loops/analysis.rs                     |   2 +-
 eth-wire/src/loops/worker.rs                       |  12 +-
 eth-wire/src/rpc.rs                                |   9 +-
 instrumentation/Cargo.toml                         |  17 +-
 instrumentation/README.md                          |  32 +-
 {test => instrumentation}/conf/bitcoin.conf        |   1 +
 {test => instrumentation}/conf/bitcoin2.conf       |   2 +
 {test => instrumentation}/conf/bitcoin_auth0.conf  |   0
 {test => instrumentation}/conf/bitcoin_auth1.conf  |   2 +-
 {test => instrumentation}/conf/bitcoin_auth2.conf  |   0
 {test => instrumentation}/conf/bitcoin_auth3.conf  |   0
 {test => instrumentation}/conf/bitcoin_auth4.conf  |   0
 {test => instrumentation}/conf/bitcoin_auth5.conf  |   0
 {test => instrumentation}/conf/taler_btc.conf      |   0
 {test => instrumentation}/conf/taler_btc_auth.conf |   0
 {test => instrumentation}/conf/taler_btc_bump.conf |   0
 .../conf/taler_btc_lifetime.conf                   |   4 +-
 {test => instrumentation}/conf/taler_eth.conf      |   0
 {test => instrumentation}/conf/taler_eth_bump.conf |   0
 .../conf/taler_eth_lifetime.conf                   |   0
 instrumentation/src/btc.rs                         | 961 +++++++++++++++++++-
 instrumentation/src/eth.rs                         | 990 ++++++++++++++++++++-
 instrumentation/src/gateway.rs                     | 244 +++++
 instrumentation/src/main.rs                        | 119 +--
 instrumentation/src/utils.rs                       | 444 +++++++++
 makefile                                           |  35 -
 script/prepare.sh                                  |  12 +-
 test/btc/analysis.sh                               |  63 --
 test/btc/bumpfee.sh                                | 112 ---
 test/btc/config.sh                                 |  27 -
 test/btc/conflict.sh                               | 110 ---
 test/btc/hell.sh                                   | 112 ---
 test/btc/lifetime.sh                               |  51 --
 test/btc/maxfee.sh                                 |  64 --
 test/btc/reconnect.sh                              |  86 --
 test/btc/reorg.sh                                  | 114 ---
 test/btc/stress.sh                                 | 123 ---
 test/btc/wire.sh                                   |  70 --
 test/common.sh                                     | 405 ---------
 test/eth/analysis.sh                               |  63 --
 test/eth/bumpfee.sh                                | 110 ---
 test/eth/hell.sh                                   | 107 ---
 test/eth/lifetime.sh                               |  49 -
 test/eth/maxfee.sh                                 |  65 --
 test/eth/reconnect.sh                              |  90 --
 test/eth/reorg.sh                                  | 106 ---
 test/eth/stress.sh                                 | 109 ---
 test/eth/test.sh                                   |  16 -
 test/eth/wire.sh                                   |  62 --
 test/gateway/api.sh                                | 133 ---
 test/gateway/auth.sh                               |  31 -
 uri-pack/Cargo.toml                                |   6 +-
 wire-gateway/Cargo.toml                            |  24 +-
 wire-gateway/src/error.rs                          | 256 +++---
 70 files changed, 3395 insertions(+), 3354 deletions(-)
 delete mode 100644 btc-wire/src/bin/btc-wire-utils.rs
 delete mode 100644 eth-wire/src/bin/eth-wire-utils.rs
 rename {test => instrumentation}/conf/bitcoin.conf (70%)
 rename {test => instrumentation}/conf/bitcoin2.conf (58%)
 rename {test => instrumentation}/conf/bitcoin_auth0.conf (100%)
 rename {test => instrumentation}/conf/bitcoin_auth1.conf (84%)
 rename {test => instrumentation}/conf/bitcoin_auth2.conf (100%)
 rename {test => instrumentation}/conf/bitcoin_auth3.conf (100%)
 rename {test => instrumentation}/conf/bitcoin_auth4.conf (100%)
 rename {test => instrumentation}/conf/bitcoin_auth5.conf (100%)
 rename {test => instrumentation}/conf/taler_btc.conf (100%)
 rename {test => instrumentation}/conf/taler_btc_auth.conf (100%)
 rename {test => instrumentation}/conf/taler_btc_bump.conf (100%)
 rename {test => instrumentation}/conf/taler_btc_lifetime.conf (88%)
 rename {test => instrumentation}/conf/taler_eth.conf (100%)
 rename {test => instrumentation}/conf/taler_eth_bump.conf (100%)
 rename {test => instrumentation}/conf/taler_eth_lifetime.conf (100%)
 create mode 100644 instrumentation/src/gateway.rs
 create mode 100644 instrumentation/src/utils.rs
 mode change 100644 => 100755 script/prepare.sh
 delete mode 100755 test/btc/analysis.sh
 delete mode 100755 test/btc/bumpfee.sh
 delete mode 100755 test/btc/config.sh
 delete mode 100755 test/btc/conflict.sh
 delete mode 100755 test/btc/hell.sh
 delete mode 100755 test/btc/lifetime.sh
 delete mode 100755 test/btc/maxfee.sh
 delete mode 100755 test/btc/reconnect.sh
 delete mode 100755 test/btc/reorg.sh
 delete mode 100755 test/btc/stress.sh
 delete mode 100755 test/btc/wire.sh
 delete mode 100644 test/common.sh
 delete mode 100755 test/eth/analysis.sh
 delete mode 100755 test/eth/bumpfee.sh
 delete mode 100755 test/eth/hell.sh
 delete mode 100755 test/eth/lifetime.sh
 delete mode 100755 test/eth/maxfee.sh
 delete mode 100755 test/eth/reconnect.sh
 delete mode 100755 test/eth/reorg.sh
 delete mode 100755 test/eth/stress.sh
 delete mode 100755 test/eth/test.sh
 delete mode 100755 test/eth/wire.sh
 delete mode 100755 test/gateway/api.sh
 delete mode 100755 test/gateway/auth.sh

diff --git a/Cargo.lock b/Cargo.lock
index 59f3e75..d4286bc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,15 @@
 # It is not intended for manual editing.
 version = 3
 
+[[package]]
+name = "addr2line"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
+dependencies = [
+ "gimli",
+]
+
 [[package]]
 name = "adler"
 version = "1.0.2"
@@ -30,9 +39,9 @@ dependencies = [
 
 [[package]]
 name = "async-trait"
-version = "0.1.52"
+version = "0.1.56"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
+checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -56,6 +65,21 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
+[[package]]
+name = "backtrace"
+version = "0.3.66"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
 [[package]]
 name = "base32"
 version = "0.4.0"
@@ -74,13 +98,19 @@ version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "cf9ff0bbfd639f15c74af777d81383cf53efb7c93613f6cab67c6c11e05bbf8b"
 
+[[package]]
+name = "bech32"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "c5738be7561b0eeb501ef1d5c5db3f24e01ceb55fededd9b00039aada34966ad"
+
 [[package]]
 name = "bitcoin"
-version = "0.27.1"
+version = "0.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9a41df6ad9642c5c15ae312dd3d074de38fd3eb7cc87ad4ce10f90292a83fe4d"
+checksum = "05bba324e6baf655b882df672453dbbc527bc938cadd27750ae510aaccc3a66a"
 dependencies = [
- "bech32",
+ "bech32 0.8.1",
  "bitcoin_hashes",
  "secp256k1",
  "serde",
@@ -127,9 +157,9 @@ name = "btc-wire"
 version = "0.1.0"
 dependencies = [
  "base64",
- "bech32",
+ "bech32 0.9.0",
  "bitcoin",
- "clap 3.1.6",
+ "clap 3.2.13",
  "common",
  "criterion",
  "hex",
@@ -142,9 +172,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.9.1"
+version = "3.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
+checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
 
 [[package]]
 name = "byteorder"
@@ -154,18 +184,15 @@ checksum = 
"14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
 [[package]]
 name = "bytes"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
+checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e"
 
 [[package]]
 name = "cast"
-version = "0.2.7"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
-dependencies = [
- "rustc_version",
-]
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
@@ -188,6 +215,7 @@ dependencies = [
  "libc",
  "num-integer",
  "num-traits",
+ "serde",
  "winapi",
 ]
 
@@ -210,16 +238,16 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "3.1.6"
+version = "3.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123"
+checksum = "ac2bd7a1eb07da9ac757c923f69373deb7bc2ba5efc951b873bcb5e693992dca"
 dependencies = [
  "atty",
  "bitflags",
  "clap_derive",
+ "clap_lex",
  "indexmap",
- "lazy_static",
- "os_str_bytes",
+ "once_cell",
  "strsim",
  "termcolor",
  "textwrap 0.15.0",
@@ -227,9 +255,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "3.1.4"
+version = "3.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16"
+checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902"
 dependencies = [
  "heck",
  "proc-macro-error",
@@ -238,16 +266,36 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "clap_lex"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+dependencies = [
+ "os_str_bytes",
+]
+
 [[package]]
 name = "clap_mangen"
-version = "0.1.2"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0649fb4156bbd7306896025005596033879a2051f9a3aa7416ab915df1f8fdac"
+checksum = "937efe4451c32be4ccb3e19549cbb1ea5cb85197f39b87a9662ca1d7b1765d1d"
 dependencies = [
- "clap 3.1.6",
+ "clap 3.2.13",
  "roff",
 ]
 
+[[package]]
+name = "color-backtrace"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "cd6c04463c99389fff045d2b90ce84f5131332712c7ffbede020f5e9ad1ed685"
+dependencies = [
+ "atty",
+ "backtrace",
+ "termcolor",
+]
+
 [[package]]
 name = "common"
 version = "0.1.0"
@@ -288,9 +336,9 @@ dependencies = [
 
 [[package]]
 name = "criterion"
-version = "0.3.5"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
+checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
 dependencies = [
  "atty",
  "cast",
@@ -314,9 +362,9 @@ dependencies = [
 
 [[package]]
 name = "criterion-plot"
-version = "0.4.4"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
+checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
 dependencies = [
  "cast",
  "itertools",
@@ -324,9 +372,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.4"
+version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
+checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"
 dependencies = [
  "cfg-if",
  "crossbeam-utils",
@@ -345,26 +393,26 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.8"
+version = "0.9.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
+checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d"
 dependencies = [
  "autocfg",
  "cfg-if",
  "crossbeam-utils",
- "lazy_static",
  "memoffset",
+ "once_cell",
  "scopeguard",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.8"
+version = "0.8.10"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
+checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
 dependencies = [
  "cfg-if",
- "lazy_static",
+ "once_cell",
 ]
 
 [[package]]
@@ -375,9 +423,9 @@ checksum = 
"7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
 
 [[package]]
 name = "crypto-common"
-version = "0.1.3"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
 dependencies = [
  "generic-array",
  "typenum",
@@ -407,9 +455,9 @@ dependencies = [
 
 [[package]]
 name = "darling"
-version = "0.13.1"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4"
+checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -417,9 +465,9 @@ dependencies = [
 
 [[package]]
 name = "darling_core"
-version = "0.13.1"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324"
+checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f"
 dependencies = [
  "fnv",
  "ident_case",
@@ -431,9 +479,9 @@ dependencies = [
 
 [[package]]
 name = "darling_macro"
-version = "0.13.1"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b"
+checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5"
 dependencies = [
  "darling_core",
  "quote",
@@ -442,13 +490,14 @@ dependencies = [
 
 [[package]]
 name = "deadpool"
-version = "0.9.2"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "3bf0c5365c0925c80a838a6810a1bf38d3304ca6b4eb25829e29e33da12de786"
+checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e"
 dependencies = [
  "async-trait",
  "deadpool-runtime",
  "num_cpus",
+ "retain_mut",
  "tokio",
 ]
 
@@ -492,9 +541,9 @@ checksum = 
"0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
 
 [[package]]
 name = "either"
-version = "1.6.1"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
 
 [[package]]
 name = "env_logger"
@@ -510,7 +559,7 @@ dependencies = [
 name = "eth-wire"
 version = "0.1.0"
 dependencies = [
- "clap 3.1.6",
+ "clap 3.2.13",
  "common",
  "ethereum-types",
  "hex",
@@ -573,21 +622,19 @@ dependencies = [
 
 [[package]]
 name = "flate2"
-version = "1.0.22"
+version = "1.0.24"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
+checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
 dependencies = [
- "cfg-if",
  "crc32fast",
- "libc",
- "miniz_oxide 0.4.4",
+ "miniz_oxide",
 ]
 
 [[package]]
 name = "flexi_logger"
-version = "0.22.3"
+version = "0.22.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "969940c39bc718475391e53a3a59b0157e64929c80cf83ad5dde5f770ecdc423"
+checksum = "ee9a6796ff68a1014f6665dac55341820f26e63ec706e58bfaee468cf0ac174f"
 dependencies = [
  "chrono",
  "glob",
@@ -715,15 +762,21 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.5"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
+checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi 0.10.2+wasi-snapshot-preview1",
+ "wasi",
 ]
 
+[[package]]
+name = "gimli"
+version = "0.26.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
+
 [[package]]
 name = "glob"
 version = "0.3.0"
@@ -738,15 +791,9 @@ checksum = 
"eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
 
 [[package]]
 name = "hashbrown"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
-
-[[package]]
-name = "hashbrown"
-version = "0.12.0"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 dependencies = [
  "ahash",
 ]
@@ -783,20 +830,20 @@ dependencies = [
 
 [[package]]
 name = "http"
-version = "0.2.6"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03"
+checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
 dependencies = [
  "bytes",
  "fnv",
- "itoa 1.0.1",
+ "itoa 1.0.2",
 ]
 
 [[package]]
 name = "http-body"
-version = "0.4.4"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
+checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
 dependencies = [
  "bytes",
  "http",
@@ -805,9 +852,9 @@ dependencies = [
 
 [[package]]
 name = "httparse"
-version = "1.6.0"
+version = "1.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4"
+checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c"
 
 [[package]]
 name = "httpdate"
@@ -817,9 +864,9 @@ checksum = 
"c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
 
 [[package]]
 name = "hyper"
-version = "0.14.18"
+version = "0.14.20"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2"
+checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -829,7 +876,7 @@ dependencies = [
  "http-body",
  "httparse",
  "httpdate",
- "itoa 1.0.1",
+ "itoa 1.0.2",
  "pin-project-lite",
  "socket2",
  "tokio",
@@ -879,12 +926,13 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "1.8.0"
+version = "1.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
+checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
 dependencies = [
  "autocfg",
- "hashbrown 0.11.2",
+ "hashbrown",
+ "serde",
 ]
 
 [[package]]
@@ -902,12 +950,17 @@ version = "0.1.0"
 dependencies = [
  "bitcoin",
  "btc-wire",
- "clap 3.1.6",
+ "clap 3.2.13",
  "clap_mangen",
+ "color-backtrace",
  "common",
  "eth-wire",
  "ethereum-types",
+ "fastrand",
  "hex",
+ "libdeflater",
+ "owo-colors",
+ "tempfile",
  "ureq",
 ]
 
@@ -928,15 +981,15 @@ checksum = 
"b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
 
 [[package]]
 name = "itoa"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
+checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
 
 [[package]]
 name = "js-sys"
-version = "0.3.56"
+version = "0.3.58"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04"
+checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -949,15 +1002,33 @@ checksum = 
"e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.121"
+version = "0.2.126"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
+checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
+
+[[package]]
+name = "libdeflate-sys"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "43afa5b192ff058426ba20a4f35c290ef402478d6045ac934ac15aa947a3898d"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "libdeflater"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "e656b7960ec49e864badc7ad1b810427a7ac8b78511a699ce5cdc3ead0b32e5b"
+dependencies = [
+ "libdeflate-sys",
+]
 
 [[package]]
 name = "listenfd"
-version = "0.5.0"
+version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c02b14f35d9f5f082fd0b1b34aa0ef32e3354c859c721d7f3325b3f79a42ba54"
+checksum = "14e4fcc00ff6731d94b70e16e71f43bda62883461f31230742e3bc6dddf12988"
 dependencies = [
  "libc",
  "uuid",
@@ -966,18 +1037,19 @@ dependencies = [
 
 [[package]]
 name = "lock_api"
-version = "0.4.6"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
+checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
 dependencies = [
+ "autocfg",
  "scopeguard",
 ]
 
 [[package]]
 name = "log"
-version = "0.4.16"
+version = "0.4.17"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
 dependencies = [
  "cfg-if",
 ]
@@ -999,9 +1071,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.4.1"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "memoffset"
@@ -1014,60 +1086,30 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.4.4"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
-dependencies = [
- "adler",
- "autocfg",
-]
-
-[[package]]
-name = "miniz_oxide"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
+checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
 dependencies = [
  "adler",
 ]
 
 [[package]]
 name = "mio"
-version = "0.8.2"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9"
+checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
 dependencies = [
  "libc",
  "log",
- "miow",
- "ntapi",
- "wasi 0.11.0+wasi-snapshot-preview1",
- "winapi",
-]
-
-[[package]]
-name = "miow"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "ntapi"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
-dependencies = [
- "winapi",
+ "wasi",
+ "windows-sys",
 ]
 
 [[package]]
 name = "num-integer"
-version = "0.1.44"
+version = "0.1.45"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
 dependencies = [
  "autocfg",
  "num-traits",
@@ -1075,9 +1117,9 @@ dependencies = [
 
 [[package]]
 name = "num-traits"
-version = "0.2.14"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
 dependencies = [
  "autocfg",
 ]
@@ -1094,18 +1136,27 @@ dependencies = [
 
 [[package]]
 name = "num_threads"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0"
+checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
 dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "object"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "once_cell"
-version = "1.10.0"
+version = "1.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
+checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
 
 [[package]]
 name = "oorandom"
@@ -1120,41 +1171,42 @@ source = 
"registry+https://github.com/rust-lang/crates.io-index";
 checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a"
 dependencies = [
  "dlv-list",
- "hashbrown 0.12.0",
+ "hashbrown",
 ]
 
 [[package]]
 name = "os_str_bytes"
-version = "6.0.0"
+version = "6.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
-dependencies = [
- "memchr",
-]
+checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
+
+[[package]]
+name = "owo-colors"
+version = "3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b"
 
 [[package]]
 name = "parking_lot"
-version = "0.11.2"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
 dependencies = [
- "instant",
  "lock_api",
  "parking_lot_core",
 ]
 
 [[package]]
 name = "parking_lot_core"
-version = "0.8.5"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
+checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
 dependencies = [
  "cfg-if",
- "instant",
  "libc",
  "redox_syscall",
  "smallvec",
- "winapi",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1183,18 +1235,18 @@ dependencies = [
 
 [[package]]
 name = "pin-project"
-version = "1.0.10"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e"
+checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260"
 dependencies = [
  "pin-project-internal",
 ]
 
 [[package]]
 name = "pin-project-internal"
-version = "1.0.10"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb"
+checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1203,9 +1255,9 @@ dependencies = [
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.8"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
+checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
 
 [[package]]
 name = "pin-utils"
@@ -1215,9 +1267,9 @@ checksum = 
"8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
 [[package]]
 name = "plotters"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
+checksum = "9428003b84df1496fb9d6eeee9c5f8145cb41ca375eb0dad204328888832811f"
 dependencies = [
  "num-traits",
  "plotters-backend",
@@ -1228,24 +1280,24 @@ dependencies = [
 
 [[package]]
 name = "plotters-backend"
-version = "0.3.2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c"
+checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
 
 [[package]]
 name = "plotters-svg"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9"
+checksum = "e0918736323d1baff32ee0eade54984f6f201ad7e97d5cfb5d6ab4a358529615"
 dependencies = [
  "plotters-backend",
 ]
 
 [[package]]
 name = "postgres"
-version = "0.19.2"
+version = "0.19.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "eb76d6535496f633fa799bb872ffb4790e9cbdedda9d35564ca0252f930c0dd5"
+checksum = "c8bbcd5f6deb39585a0d9f4ef34c4a41c25b7ad26d23c75d837d78c8e7adc85f"
 dependencies = [
  "bytes",
  "fallible-iterator",
@@ -1257,9 +1309,9 @@ dependencies = [
 
 [[package]]
 name = "postgres-protocol"
-version = "0.6.3"
+version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "79ec03bce71f18b4a27c4c64c6ba2ddf74686d69b91d8714fb32ead3adaed713"
+checksum = "878c6cbf956e03af9aa8204b407b9cbf47c072164800aa918c516cd4b056c50c"
 dependencies = [
  "base64",
  "byteorder",
@@ -1275,9 +1327,9 @@ dependencies = [
 
 [[package]]
 name = "postgres-types"
-version = "0.2.2"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "04619f94ba0cc80999f4fc7073607cb825bc739a883cb6d20900fc5e009d6b0d"
+checksum = "ebd6e8b7189a73169290e89bd24c771071f1012d8fe6f738f5226531f0b03d89"
 dependencies = [
  "bytes",
  "fallible-iterator",
@@ -1327,11 +1379,11 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.36"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
+checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
 dependencies = [
- "unicode-xid",
+ "unicode-ident",
 ]
 
 [[package]]
@@ -1358,9 +1410,9 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.16"
+version = "1.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57"
+checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
 dependencies = [
  "proc-macro2",
 ]
@@ -1397,9 +1449,9 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.5.1"
+version = "1.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
+checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
 dependencies = [
  "autocfg",
  "crossbeam-deque",
@@ -1409,31 +1461,30 @@ dependencies = [
 
 [[package]]
 name = "rayon-core"
-version = "1.9.1"
+version = "1.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
+checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque",
  "crossbeam-utils",
- "lazy_static",
  "num_cpus",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.2.12"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0"
+checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
 dependencies = [
  "bitflags",
 ]
 
 [[package]]
 name = "regex"
-version = "1.5.5"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
+checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1448,9 +1499,24 @@ checksum = 
"6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.25"
+version = "0.6.27"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "retain_mut"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0"
 
 [[package]]
 name = "ring"
@@ -1484,25 +1550,22 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustc-hex"
-version = "2.1.0"
+name = "rustc-demangle"
+version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6"
+checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
 
 [[package]]
-name = "rustc_version"
-version = "0.4.0"
+name = "rustc-hex"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
-dependencies = [
- "semver",
-]
+checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6"
 
 [[package]]
 name = "rustls"
-version = "0.20.4"
+version = "0.20.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921"
+checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033"
 dependencies = [
  "log",
  "ring",
@@ -1512,15 +1575,15 @@ dependencies = [
 
 [[package]]
 name = "rustversion"
-version = "1.0.6"
+version = "1.0.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
+checksum = "24c8ad4f0c00e1eb5bc7614d236a7f1300e3dbd76b68cac8e06fb00b015ad8d8"
 
 [[package]]
 name = "ryu"
-version = "1.0.9"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
+checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
 
 [[package]]
 name = "same-file"
@@ -1549,9 +1612,9 @@ dependencies = [
 
 [[package]]
 name = "secp256k1"
-version = "0.20.3"
+version = "0.22.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a"
+checksum = "26947345339603ae8395f68e2f3d85a6b0a8ddfe6315818e80b8504415099db0"
 dependencies = [
  "secp256k1-sys",
  "serde",
@@ -1559,24 +1622,18 @@ dependencies = [
 
 [[package]]
 name = "secp256k1-sys"
-version = "0.4.2"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036"
+checksum = "152e20a0fd0519390fc43ab404663af8a0b794273d2a91d60ad4a39f13ffe110"
 dependencies = [
  "cc",
 ]
 
-[[package]]
-name = "semver"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d"
-
 [[package]]
 name = "serde"
-version = "1.0.136"
+version = "1.0.140"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
+checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03"
 dependencies = [
  "serde_derive",
 ]
@@ -1593,9 +1650,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.136"
+version = "1.0.140"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
+checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1604,20 +1661,20 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.79"
+version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
+checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
 dependencies = [
- "itoa 1.0.1",
+ "itoa 1.0.2",
  "ryu",
  "serde",
 ]
 
 [[package]]
 name = "serde_repr"
-version = "0.1.7"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5"
+checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1631,27 +1688,32 @@ source = 
"registry+https://github.com/rust-lang/crates.io-index";
 checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
 dependencies = [
  "form_urlencoded",
- "itoa 1.0.1",
+ "itoa 1.0.2",
  "ryu",
  "serde",
 ]
 
 [[package]]
 name = "serde_with"
-version = "1.12.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ec1e6ec4d8950e5b1e894eac0d360742f3b1407a6078a604a731c4b3f49cefbc"
+checksum = "89df7a26519371a3cce44fbb914c2819c84d9b897890987fa3ab096491cc0ea8"
 dependencies = [
- "rustversion",
+ "base64",
+ "chrono",
+ "hex",
+ "indexmap",
  "serde",
+ "serde_json",
  "serde_with_macros",
+ "time",
 ]
 
 [[package]]
 name = "serde_with_macros"
-version = "1.5.1"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "12e47be9471c72889ebafb5e14d5ff930d89ae7a67bbdb5f8abb564f845a927e"
+checksum = "de337f322382fcdfbb21a014f7c224ee041a23785651db67b9827403178f698f"
 dependencies = [
  "darling",
  "proc-macro2",
@@ -1678,15 +1740,18 @@ checksum = 
"7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
 
 [[package]]
 name = "slab"
-version = "0.4.5"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
+checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
+dependencies = [
+ "autocfg",
+]
 
 [[package]]
 name = "smallvec"
-version = "1.8.0"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
+checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
 
 [[package]]
 name = "socket2"
@@ -1734,13 +1799,27 @@ checksum = 
"6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
 
 [[package]]
 name = "syn"
-version = "1.0.89"
+version = "1.0.98"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54"
+checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
 dependencies = [
  "proc-macro2",
  "quote",
- "unicode-xid",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "libc",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
 ]
 
 [[package]]
@@ -1769,18 +1848,18 @@ checksum = 
"b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
 
 [[package]]
 name = "thiserror"
-version = "1.0.30"
+version = "1.0.31"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
+checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.30"
+version = "1.0.31"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
+checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1789,13 +1868,14 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.9"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd"
+checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217"
 dependencies = [
- "itoa 1.0.1",
+ "itoa 1.0.2",
  "libc",
  "num_threads",
+ "serde",
  "time-macros",
 ]
 
@@ -1826,9 +1906,9 @@ dependencies = [
 
 [[package]]
 name = "tinyvec"
-version = "1.5.1"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
 dependencies = [
  "tinyvec_macros",
 ]
@@ -1841,15 +1921,17 @@ checksum = 
"cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
 
 [[package]]
 name = "tokio"
-version = "1.17.0"
+version = "1.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
+checksum = "57aec3cfa4c296db7255446efb4928a6be304b431a806216105542a67b6ca82e"
 dependencies = [
+ "autocfg",
  "bytes",
  "libc",
  "memchr",
  "mio",
  "num_cpus",
+ "once_cell",
  "pin-project-lite",
  "socket2",
  "tokio-macros",
@@ -1858,9 +1940,9 @@ dependencies = [
 
 [[package]]
 name = "tokio-macros"
-version = "1.7.0"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
+checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1869,9 +1951,9 @@ dependencies = [
 
 [[package]]
 name = "tokio-postgres"
-version = "0.7.5"
+version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4b6c8b33df661b548dcd8f9bf87debb8c56c05657ed291122e1188698c2ece95"
+checksum = "19c88a47a23c5d2dc9ecd28fb38fba5fc7e5ddc1fe64488ec145076b0c71c8ae"
 dependencies = [
  "async-trait",
  "byteorder",
@@ -1892,29 +1974,29 @@ dependencies = [
 
 [[package]]
 name = "tokio-util"
-version = "0.6.9"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0"
+checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45"
 dependencies = [
  "bytes",
  "futures-core",
  "futures-sink",
- "log",
  "pin-project-lite",
  "tokio",
+ "tracing",
 ]
 
 [[package]]
 name = "tower-service"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
+checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
 
 [[package]]
 name = "tracing"
-version = "0.1.32"
+version = "0.1.35"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
+checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
 dependencies = [
  "cfg-if",
  "pin-project-lite",
@@ -1923,11 +2005,11 @@ dependencies = [
 
 [[package]]
 name = "tracing-core"
-version = "0.1.23"
+version = "0.1.28"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c"
+checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7"
 dependencies = [
- "lazy_static",
+ "once_cell",
 ]
 
 [[package]]
@@ -1956,15 +2038,21 @@ dependencies = [
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.7"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
+checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7"
 
 [[package]]
 name = "unicode-normalization"
-version = "0.1.19"
+version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
+checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
 dependencies = [
  "tinyvec",
 ]
@@ -1975,12 +2063,6 @@ version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
 
-[[package]]
-name = "unicode-xid"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
-
 [[package]]
 name = "untrusted"
 version = "0.7.1"
@@ -1989,9 +2071,9 @@ checksum = 
"a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
 
 [[package]]
 name = "ureq"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9399fa2f927a3d327187cbd201480cee55bee6ac5d3c77dd27f0c6814cff16d5"
+checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f"
 dependencies = [
  "base64",
  "chunked_transfer",
@@ -2035,9 +2117,9 @@ dependencies = [
 
 [[package]]
 name = "uuid"
-version = "0.8.2"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
+checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
 
 [[package]]
 name = "version_check"
@@ -2066,12 +2148,6 @@ dependencies = [
  "try-lock",
 ]
 
-[[package]]
-name = "wasi"
-version = "0.10.2+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
-
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
@@ -2080,9 +2156,9 @@ checksum = 
"9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.79"
+version = "0.2.81"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06"
+checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -2090,9 +2166,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.79"
+version = "0.2.81"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca"
+checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
 dependencies = [
  "bumpalo",
  "lazy_static",
@@ -2105,9 +2181,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.79"
+version = "0.2.81"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01"
+checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -2115,9 +2191,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.79"
+version = "0.2.81"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc"
+checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2128,15 +2204,15 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.79"
+version = "0.2.81"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
+checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
 
 [[package]]
 name = "web-sys"
-version = "0.3.56"
+version = "0.3.58"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb"
+checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -2154,9 +2230,9 @@ dependencies = [
 
 [[package]]
 name = "webpki-roots"
-version = "0.22.2"
+version = "0.22.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449"
+checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf"
 dependencies = [
  "webpki",
 ]
@@ -2192,19 +2268,62 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
+[[package]]
+name = "windows-sys"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+dependencies = [
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+
 [[package]]
 name = "wire-gateway"
 version = "0.1.0"
 dependencies = [
  "bitcoin",
- "clap 3.1.6",
+ "clap 3.2.13",
  "common",
  "deadpool-postgres",
  "ethereum-types",
  "hyper",
  "hyperlocal",
  "listenfd",
- "miniz_oxide 0.5.1",
+ "miniz_oxide",
  "serde",
  "serde_json",
  "serde_urlencoded",
@@ -2216,6 +2335,6 @@ dependencies = [
 
 [[package]]
 name = "zeroize"
-version = "1.5.4"
+version = "1.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317"
+checksum = "20b578acffd8516a6c3f2a1bdefc1ec37e547bb4e0fb8b6b01a4cafc886b4442"
diff --git a/README.md b/README.md
index f277255..572608b 100644
--- a/README.md
+++ b/README.md
@@ -37,11 +37,11 @@ Depolymerizer require:
 
 #### Bitcoin
 
-[Bitcoind](https://bitcoincore.org/) version >= 22.0 is required
+[Bitcoind](https://bitcoincore.org/) version 23.0 is expected
 
 #### Ethereum
 
-[Geth](https://geth.ethereum.org/) version >= 1.10.0 is required
+[Geth](https://geth.ethereum.org/) version 1.10.20 is expected
 
 ### Initialization
 
@@ -233,27 +233,4 @@ You can have an additional context:
 
 ## Test
 
-Instrumentation test documentation can be founded in the 
[instrumentation](instrumentation/README.md) directory.
-
-### Local testing
-
-Local tests require additional binaries. The following binaries must be in the
-local user PATH:
-
-- `pg_ctl` and `psql` from PostgreSQL
-- `geth` from [go-ethereum](https://geth.ethereum.org/downloads/)
-- `bitcoind` and `bitcoin-cli` from
-  [bitcoincore](https://bitcoincore.org/en/download/)
-- `taler-config` and `taler-exchange-wire-gateway-client` from the
-  [Taler exchange ](https://git.taler.net/exchange.git/)
-
-You can use the [prepare](script/prepare.sh) script to download and extract
-blockchain binaries and find the path of the local Postgres installation.
-However, taler binaries need to be compiled from source for now.
-
-| Command             | Run                |
-| ------------------- | ------------------ |
-| `make test`         | all tests          |
-| `make test_gateway` | wire-gateway tests |
-| `make test_btc`     | btc-wire tests     |
-| `make test_eth`     | eth-wire tests     |
+Instrumentation test documentation can be founded in the 
[instrumentation](instrumentation/README.md) directory.
\ No newline at end of file
diff --git a/btc-wire/Cargo.toml b/btc-wire/Cargo.toml
index 6bf53f2..f1662e1 100644
--- a/btc-wire/Cargo.toml
+++ b/btc-wire/Cargo.toml
@@ -11,20 +11,20 @@ fail = []
 
 [dependencies]
 # Typed bitcoin rpc types
-bitcoin = { version = "0.27.1", features = [
+bitcoin = { version = "0.28.1", features = [
     "std",
     "use-serde",
 ], default-features = false }
 # Cli args parser
-clap = { version = "3.1.5", features = ["derive"] }
+clap = { version = "3.2.13", features = ["derive"] }
 # Bech32 encoding and decoding
-bech32 = "0.8.1"
+bech32 = "0.9.0"
 # Serialization library
-serde = { version = "1.0.136", features = ["derive"] }
-serde_json = "1.0.79"
-serde_repr = "0.1.7"
+serde = { version = "1.0.140", features = ["derive"] }
+serde_json = "1.0.82"
+serde_repr = "0.1.8"
 # Error macros
-thiserror = "1.0.30"
+thiserror = "1.0.31"
 base64 = "0.13.0"
 # Common lib
 common = { path = "../common" }
@@ -35,7 +35,7 @@ hex = "0.4.3"
 
 [dev-dependencies]
 # statistics-driven micro-benchmarks
-criterion = "0.3.5"
+criterion = "0.3.6"
 
 [[bench]]
 name = "metadata"
diff --git a/btc-wire/benches/metadata.rs b/btc-wire/benches/metadata.rs
index 6a2af8a..cea9a9f 100644
--- a/btc-wire/benches/metadata.rs
+++ b/btc-wire/benches/metadata.rs
@@ -1,39 +1,39 @@
-/*
-  This file is part of TALER
-  Copyright (C) 2022 Taler Systems SA
-
-  TALER is free software; you can redistribute it and/or modify it under the
-  terms of the GNU Affero General Public License as published by the Free 
Software
-  Foundation; either version 3, or (at your option) any later version.
-
-  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
-
-  You should have received a copy of the GNU Affero General Public License 
along with
-  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
-*/
-use btc_wire::segwit::{decode_segwit_msg, encode_segwit_key, rand_addresses};
-use criterion::{criterion_group, criterion_main, Criterion};
-use common::rand_slice;
-
-fn criterion_benchmark(c: &mut Criterion) {
-    let mut group = c.benchmark_group("SegWit addresses");
-    group.bench_function("encode", |b| {
-        b.iter_batched(
-            || rand_slice(),
-            |key| encode_segwit_key("bench", &key),
-            criterion::BatchSize::SmallInput,
-        );
-    });
-    group.bench_function("decode", |b| {
-        b.iter_batched(
-            || rand_addresses("bench", &rand_slice()),
-            |addrs| decode_segwit_msg(&addrs),
-            criterion::BatchSize::SmallInput,
-        );
-    });
-}
-
-criterion_group!(benches, criterion_benchmark);
-criterion_main!(benches);
+/*
+  This file is part of TALER
+  Copyright (C) 2022 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+use btc_wire::segwit::{decode_segwit_msg, encode_segwit_key, rand_addresses};
+use common::rand_slice;
+use criterion::{criterion_group, criterion_main, Criterion};
+
+fn criterion_benchmark(c: &mut Criterion) {
+    let mut group = c.benchmark_group("SegWit addresses");
+    group.bench_function("encode", |b| {
+        b.iter_batched(
+            || rand_slice(),
+            |key| encode_segwit_key("bench", &key),
+            criterion::BatchSize::SmallInput,
+        );
+    });
+    group.bench_function("decode", |b| {
+        b.iter_batched(
+            || rand_addresses("bench", &rand_slice()),
+            |addrs| decode_segwit_msg(&addrs),
+            criterion::BatchSize::SmallInput,
+        );
+    });
+}
+
+criterion_group!(benches, criterion_benchmark);
+criterion_main!(benches);
diff --git a/btc-wire/src/bin/btc-wire-utils.rs 
b/btc-wire/src/bin/btc-wire-utils.rs
deleted file mode 100644
index 7520874..0000000
--- a/btc-wire/src/bin/btc-wire-utils.rs
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-  This file is part of TALER
-  Copyright (C) 2022 Taler Systems SA
-
-  TALER is free software; you can redistribute it and/or modify it under the
-  terms of the GNU Affero General Public License as published by the Free 
Software
-  Foundation; either version 3, or (at your option) any later version.
-
-  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
-
-  You should have received a copy of the GNU Affero General Public License 
along with
-  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
-*/
-use std::path::PathBuf;
-
-use bitcoin::{Address, Amount, BlockHash, Network};
-use btc_wire::{
-    btc_config::BitcoinConfig,
-    load_taler_config,
-    rpc::{Category, Rpc},
-};
-use clap::StructOpt;
-use common::{postgres::NoTls, rand_slice};
-
-/// btc-wire test utils
-#[derive(clap::Parser, Debug)]
-#[clap(name = "btc-wire-utils")]
-struct Args {
-    /// Override default configuration file path
-    #[clap(global = true, short, long)]
-    config: Option<PathBuf>,
-    /// Override default data directory path
-    #[clap(global = true, short, long)]
-    datadir: Option<PathBuf>,
-    #[clap(subcommand)]
-    cmd: Cmd,
-}
-
-#[derive(clap::Subcommand, Debug)]
-enum Cmd {
-    /// Perform wire credit transactions
-    Transfer {
-        #[clap(short, long, default_value_t = String::from("client"))]
-        /// sender wallet
-        from: String,
-        #[clap(short, long, default_value_t = String::from("wire"))]
-        /// receiver wallet
-        to: String,
-        /// amount to send in btc
-        amount: f64,
-    },
-    /// Wait or mine the next block
-    Nblock {
-        #[clap(default_value_t = String::from("wire"))]
-        /// receiver wallet
-        to: String,
-    },
-    /// Abandon all unconfirmed transaction
-    Abandon {
-        #[clap(default_value_t = String::from("wire"))]
-        /// sender wallet
-        from: String,
-    },
-    /// Clear database
-    Resetdb,
-}
-
-pub fn auto_wallet(rpc: &mut Rpc, config: &BitcoinConfig, name: &str) -> (Rpc, 
Address) {
-    // Auto load
-    rpc.load_wallet(name).ok();
-    let mut wallet = Rpc::wallet(config, name).unwrap();
-    let addr = wallet
-        .gen_addr()
-        .unwrap_or_else(|_| panic!("Failed to get wallet address {}", name));
-    (wallet, addr)
-}
-
-fn main() {
-    common::log::init();
-    let args = Args::parse();
-    let (taler_config, path, currency) = 
load_taler_config(args.config.as_deref());
-    let btc_config = BitcoinConfig::load(args.datadir.unwrap_or(path), 
currency).unwrap();
-    let mut rpc = Rpc::common(&btc_config).unwrap();
-
-    match args.cmd {
-        Cmd::Transfer { from, to, amount } => {
-            let (mut client, _) = auto_wallet(&mut rpc, &btc_config, &from);
-            let (_, to) = auto_wallet(&mut rpc, &btc_config, &to);
-            let tx = client
-                .send_segwit_key(&to, &Amount::from_btc(amount).unwrap(), 
&rand_slice())
-                .unwrap();
-            println!("{}", tx);
-        }
-        Cmd::Nblock { to } => {
-            match btc_config.network {
-                Network::Regtest => {
-                    // Manually mine a block
-                    let (_, addr) = auto_wallet(&mut rpc, &btc_config, &to);
-                    rpc.mine(1, &addr).unwrap();
-                }
-                _ => {
-                    // Wait for next network block
-                    rpc.wait_for_new_block().ok();
-                }
-            }
-        }
-        Cmd::Abandon { from } => {
-            let (mut wire, _) = auto_wallet(&mut rpc, &btc_config, &from);
-            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();
-                }
-            }
-        }
-        Cmd::Resetdb => {
-            let hash: BlockHash = rpc.get_genesis().unwrap();
-            let mut db = taler_config.db_config().connect(NoTls).unwrap();
-            let mut tx = db.transaction().unwrap();
-            // Clear transaction tables and reset state
-            tx.execute("DELETE FROM tx_in", &[]).unwrap();
-            tx.execute("DELETE FROM tx_out", &[]).unwrap();
-            tx.execute("DELETE FROM bounce", &[]).unwrap();
-            tx.execute(
-                "UPDATE state SET value=$1 WHERE name='last_hash'",
-                &[&hash.as_ref()],
-            )
-            .unwrap();
-            tx.commit().unwrap();
-        }
-    }
-}
diff --git a/btc-wire/src/bin/segwit-demo.rs b/btc-wire/src/bin/segwit-demo.rs
index 0be19a6..7871b81 100644
--- a/btc-wire/src/bin/segwit-demo.rs
+++ b/btc-wire/src/bin/segwit-demo.rs
@@ -1,8 +1,8 @@
 use std::str::FromStr;
 
 use bitcoin::{Address, Amount, Network};
+use btc_wire::segwit::decode_segwit_msg;
 use btc_wire::{rpc_utils, segwit::encode_segwit_addr};
-use btc_wire::{segwit::decode_segwit_msg};
 use common::{
     base32::{self, Alphabet},
     rand_slice,
@@ -81,12 +81,14 @@ pub fn main() {
         "Make sure the amount show 0.10000588 BTC, else you have to change the 
base unit to BTC"
     );
 
-
     let key1 = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4";
     let key2 = "tb1qzxwu2p7urkqx0gq2ltfazf9w2jdu48ya8qwlm0";
     let key3 = "tb1qzxwu2pef8a224xagwq8hej8akuvd63yluu3wrh";
     let addresses = vec![key1, key2, key3];
     let dec = decode_segwit_msg(&addresses);
-    
-    println!("Decode reserve public key: 0x{}", 
hex::encode(&dec.unwrap()[..]));
+
+    println!(
+        "Decode reserve public key: 0x{}",
+        hex::encode(&dec.unwrap()[..])
+    );
 }
diff --git a/btc-wire/src/loops.rs b/btc-wire/src/loops.rs
index 2391fc4..665913b 100644
--- a/btc-wire/src/loops.rs
+++ b/btc-wire/src/loops.rs
@@ -35,4 +35,4 @@ pub enum LoopError {
     Injected(#[from] Injected),
 }
 
-pub type LoopResult<T> = Result<T, LoopError>;
\ No newline at end of file
+pub type LoopResult<T> = Result<T, LoopError>;
diff --git a/btc-wire/src/loops/analysis.rs b/btc-wire/src/loops/analysis.rs
index 32f64cc..f3125fe 100644
--- a/btc-wire/src/loops/analysis.rs
+++ b/btc-wire/src/loops/analysis.rs
@@ -22,8 +22,8 @@ use common::{
     reconnect::AutoReconnectDb,
 };
 
-use crate::WireState;
 use super::LoopResult;
+use crate::WireState;
 
 /// Analyse blockchain behavior and adapt confirmations in real time
 pub fn analysis(mut rpc: AutoRpcCommon, mut db: AutoReconnectDb, state: 
&WireState) {
@@ -40,9 +40,7 @@ pub fn analysis(mut rpc: AutoRpcCommon, mut db: 
AutoReconnectDb, state: &WireSta
                 let fork = rpc
                     .get_chain_tips()?
                     .into_iter()
-                    .filter_map(|t| {
-                        (t.status == ChainTipsStatus::ValidFork).then(|| 
t.length)
-                    })
+                    .filter_map(|t| (t.status == 
ChainTipsStatus::ValidFork).then(|| t.length))
                     .max()
                     .unwrap_or(0) as u32;
                 // The first time we see a fork that big
diff --git a/btc-wire/src/loops/watcher.rs b/btc-wire/src/loops/watcher.rs
index 8c9e2fd..8cb2143 100644
--- a/btc-wire/src/loops/watcher.rs
+++ b/btc-wire/src/loops/watcher.rs
@@ -13,8 +13,8 @@
   You should have received a copy of the GNU Affero General Public License 
along with
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
-use common::{log::log::error, reconnect::AutoReconnectDb};
 use btc_wire::rpc::AutoRpcCommon;
+use common::{log::log::error, reconnect::AutoReconnectDb};
 use std::time::Duration;
 
 use super::LoopResult;
diff --git a/btc-wire/src/loops/worker.rs b/btc-wire/src/loops/worker.rs
index 7cf23ba..fdff815 100644
--- a/btc-wire/src/loops/worker.rs
+++ b/btc-wire/src/loops/worker.rs
@@ -227,8 +227,8 @@ fn sync_chain(
 
     // Move last_hash forward
     db.execute(
-        "UPDATE state SET value=$1 WHERE name='last_hash'",
-        &[&lastblock.as_ref()],
+        "UPDATE state SET value=$1 WHERE name='last_hash' AND value=$2",
+        &[&lastblock.as_ref(), &last_hash.as_inner().as_slice()],
     )?;
 
     Ok(Some(stuck))
diff --git a/btc-wire/src/rpc.rs b/btc-wire/src/rpc.rs
index 9aed519..73b612b 100644
--- a/btc-wire/src/rpc.rs
+++ b/btc-wire/src/rpc.rs
@@ -23,7 +23,7 @@
 //! We only parse the thing we actually use, this reduce memory usage and
 //! make our code more compatible with future deprecation
 //!
-//! bitcoincore RPC documentation: <https://bitcoincore.org/en/doc/22.0.0/>
+//! bitcoincore RPC documentation: <https://bitcoincore.org/en/doc/23.0.0/>
 
 use bitcoin::{hashes::hex::ToHex, Address, Amount, BlockHash, SignedAmount, 
Txid};
 use common::{log::log::error, password, reconnect::AutoReconnect};
@@ -47,7 +47,7 @@ pub fn auto_rpc_wallet(config: BitcoinConfig, wallet: 
&'static str) -> AutoRpcWa
             let mut rpc = Rpc::wallet(config, wallet)
                 .map_err(|err| error!("connect RPC: {}", err))
                 .ok()?;
-            rpc.load_wallet(wallet).ok(); 
+            rpc.load_wallet(wallet).ok();
             rpc.unlock_wallet(&password())
                 .map_err(|err| error!("connect RPC: {}", err))
                 .ok()?;
@@ -114,6 +114,13 @@ pub type Result<T> = std::result::Result<T, Error>;
 
 const EMPTY: [(); 0] = [];
 
+fn expect_null(result: Result<()>) -> Result<()> {
+    match result {
+        Err(Error::Null) => Ok(()),
+        i => i,
+    }
+}
+
 /// Bitcoin RPC connection
 pub struct Rpc {
     last_call: Instant,
@@ -241,10 +248,7 @@ impl Rpc {
     /// 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)) {
-            Err(Error::Null) => Ok(()),
-            i => i,
-        }
+        expect_null(self.call("walletpassphrase", &(passwd, 100000000)))
     }
 
     /* ----- Wallet utils ----- */
@@ -367,10 +371,7 @@ impl Rpc {
 
     /// Abandon a pending transaction
     pub fn abandon_tx(&mut self, id: &Txid) -> Result<()> {
-        match self.call("abandontransaction", &[&id]) {
-            Err(Error::Null) => Ok(()),
-            i => i,
-        }
+        expect_null(self.call("abandontransaction", &[&id]))
     }
 
     /* ----- Watcher ----- */
@@ -388,6 +389,18 @@ impl Rpc {
     ) -> Result<ListSinceBlock> {
         self.call("listsinceblock", &(hash, confirmation.max(1), (), true))
     }
+
+    /* ----- Cluster ----- */
+
+    /// Try a connection to a node once
+    pub fn add_node(&mut self, addr: &str) -> Result<()> {
+        expect_null(self.call("addnode", &(addr, "onetry")))
+    }
+
+    /// Immediately disconnects from the specified peer node.
+    pub fn disconnect_node(&mut self, addr: &str) -> Result<()> {
+        expect_null(self.call("disconnectnode", &(addr, ())))
+    }
 }
 
 #[derive(Debug, serde::Deserialize)]
diff --git a/common/Cargo.toml b/common/Cargo.toml
index 346222b..08c4944 100644
--- a/common/Cargo.toml
+++ b/common/Cargo.toml
@@ -9,31 +9,31 @@ rust-version = "1.56.1"
 
 [dependencies]
 # Serialization framework
-serde = { version = "1.0.136", features = ["derive"] }
+serde = { version = "1.0.140", features = ["derive"] }
 # Serialization helper
-serde_with = "1.12.0"
+serde_with = "2.0.0"
 # JSON serialization
-serde_json = "1.0.79"
+serde_json = "1.0.82"
 # Url format
 url = { version = "2.2.2", features = ["serde"] }
 # Crockford’s base32
 base32 = "0.4.0"
 # Error macros
-thiserror = "1.0.30"
+thiserror = "1.0.31"
 # Ini files
 rust-ini = "0.18.0"
 # Logging
-log = "0.4.14"
-flexi_logger = { version = "0.22.3", default-features = false, features = [
+log = "0.4.17"
+flexi_logger = { version = "0.22.5", default-features = false, features = [
     "use_chrono_for_offset", # Temporary hack for multithreaded code 
https://rustsec.org/advisories/RUSTSEC-2020-0159
 ] }
 # Localized time
-time = { version = "0.3.7", features = ["formatting", "macros"] }
+time = { version = "0.3.11", features = ["formatting", "macros"] }
 # Postgres client
-postgres = "0.19.2"
+postgres = "0.19.3"
 # Secure random
 rand = { version = "0.8.5", features = ["getrandom"] }
 # Securely zero memory
-zeroize = "1.5.3"
+zeroize = "1.5.6"
 # Optimized uri binary format
 uri-pack = { path = "../uri-pack" }
diff --git a/common/src/sql.rs b/common/src/sql.rs
index c070454..d48a446 100644
--- a/common/src/sql.rs
+++ b/common/src/sql.rs
@@ -19,7 +19,10 @@ use std::str::FromStr;
 use postgres::Row;
 use url::Url;
 
-use crate::{api_common::{Amount, SafeU64}, log::OrFail};
+use crate::{
+    api_common::{Amount, SafeU64},
+    log::OrFail,
+};
 
 /// URL from sql
 pub fn sql_url(row: &Row, idx: usize) -> Url {
@@ -30,8 +33,7 @@ pub fn sql_url(row: &Row, idx: usize) -> Url {
 /// Ethereum amount from sql
 pub fn sql_amount(row: &Row, idx: usize) -> Amount {
     let str: &str = row.get(idx);
-    Amount::from_str(str)
-        .or_fail(|_| format!("Database invariant: expected an amount got {}", 
str))
+    Amount::from_str(str).or_fail(|_| format!("Database invariant: expected an 
amount got {}", str))
 }
 
 /// Byte array from sql
diff --git a/common/src/status.rs b/common/src/status.rs
index 08e71a5..bc7d2f3 100644
--- a/common/src/status.rs
+++ b/common/src/status.rs
@@ -16,7 +16,7 @@
 //! Transactions status in database
 
 /// Debit transaction status
-/// 
+///
 ///           -> Requested  API request
 /// Requested -> Sent       Announced to the bitcoin network
 /// Sent      -> Requested  Conflicting transaction (reorg)
diff --git a/eth-wire/Cargo.toml b/eth-wire/Cargo.toml
index aef095e..9be092a 100644
--- a/eth-wire/Cargo.toml
+++ b/eth-wire/Cargo.toml
@@ -11,17 +11,17 @@ fail = []
 
 [dependencies]
 # Cli args
-clap = { version = "3.1.5", features = ["derive"] }
+clap = { version = "3.2.13", features = ["derive"] }
 # Serialization library
-serde = { version = "1.0.136", features = ["derive"] }
-serde_json = "1.0.79"
-serde_repr = "0.1.7"
+serde = { version = "1.0.140", features = ["derive"] }
+serde_json = "1.0.82"
+serde_repr = "0.1.8"
 hex = "0.4.3"
 # Ethereum serializable types
 ethereum-types = { version = "0.13.1", default-features = false, features = [
     "serialize",
 ] }
 # Error macros
-thiserror = "1.0.30"
+thiserror = "1.0.31"
 # Common lib
 common = { path = "../common" }
diff --git a/eth-wire/src/bin/eth-wire-utils.rs 
b/eth-wire/src/bin/eth-wire-utils.rs
deleted file mode 100644
index dff493e..0000000
--- a/eth-wire/src/bin/eth-wire-utils.rs
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
-  This file is part of TALER
-  Copyright (C) 2022 Taler Systems SA
-
-  TALER is free software; you can redistribute it and/or modify it under the
-  terms of the GNU Affero General Public License as published by the Free 
Software
-  Foundation; either version 3, or (at your option) any later version.
-
-  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
-
-  You should have received a copy of the GNU Affero General Public License 
along with
-  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
-*/
-use std::{
-    path::PathBuf,
-    process::exit,
-    str::FromStr,
-    time::{Duration, Instant},
-};
-
-use clap::StructOpt;
-use common::{api_common::Amount, log::init, password, postgres::NoTls, 
rand_slice};
-use eth_wire::{
-    load_taler_config,
-    rpc::{hex::Hex, Rpc, RpcClient, TransactionRequest},
-    taler_util::{taler_to_eth, TRUNC},
-    RpcExtended, SyncState,
-};
-use ethereum_types::{H160, U256};
-
-#[derive(clap::Parser, Debug)]
-#[clap(name = "eth-wire-utils")]
-/// eth-wire test utils
-struct Args {
-    /// Override default configuration file path
-    #[clap(global = true, short, long)]
-    config: Option<PathBuf>,
-    /// Override default data directory path
-    #[clap(global = true, short, long)]
-    datadir: Option<PathBuf>,
-    #[clap(subcommand)]
-    cmd: Cmd,
-}
-
-#[derive(clap::Parser, Debug)]
-struct TransactionCmd {
-    /// sender wallet
-    from: String,
-    /// receiver wallet
-    to: String,
-    /// sender wallet
-    fmt: String,
-    /// amounts to send in eth
-    amounts: Vec<u32>,
-}
-
-#[derive(clap::Subcommand, Debug)]
-enum Cmd {
-    /// Send common ethereum transactions
-    Send(TransactionCmd),
-    /// Send taler credit transactions
-    Credit(TransactionCmd),
-    /// Mine pending transactions and more blocks
-    Mine {
-        /// receiver wallet
-        to: String,
-        #[clap(default_value_t = 0)]
-        /// amount to mine in eth
-        amount: u64,
-    },
-    /// Clear database
-    Resetdb,
-    /// Get eth balance
-    Balance {
-        /// account address
-        addr: String,
-    },
-    // Check client and wire balance
-    CheckBalance {
-        client_addr: String,
-        client: u64,
-        wire_addr: String,
-        wire: u64,
-    },
-    /// Abandon all unconfirmed transaction
-    Abandon {
-        /// sender address
-        from: String,
-    },
-    Export {
-        path: String,
-    },
-}
-
-fn main() {
-    init();
-    let args: Args = Args::parse();
-    let (taler_config, ipc_path, currency) = 
load_taler_config(args.config.as_deref());
-
-    let ipc_path = args.datadir.unwrap_or(ipc_path);
-    let mut rpc = Rpc::new(ipc_path).unwrap();
-    let passwd = password();
-    match args.cmd {
-        Cmd::Credit(TransactionCmd {
-            from,
-            to,
-            fmt,
-            amounts,
-        }) => {
-            let from = H160::from_str(&from).unwrap();
-            let to = H160::from_str(&to).unwrap();
-            rpc.unlock_account(&from, &passwd).ok();
-            for amount in amounts {
-                let amount =
-                    Amount::from_str(&format!("{}:{}{}", currency.to_str(), 
fmt, amount)).unwrap();
-                let value = taler_to_eth(&amount, currency).unwrap();
-                rpc.credit(from, to, value, rand_slice()).unwrap();
-            }
-        }
-        Cmd::Send(TransactionCmd {
-            from,
-            to,
-            fmt,
-            amounts,
-        }) => {
-            let from = H160::from_str(&from).unwrap();
-            let to = H160::from_str(&to).unwrap();
-            rpc.unlock_account(&from, &passwd).ok();
-            for amount in amounts {
-                let amount =
-                    Amount::from_str(&format!("{}:{}{}", currency.to_str(), 
fmt, amount)).unwrap();
-                let value = taler_to_eth(&amount, currency).unwrap();
-                rpc.send_transaction(&TransactionRequest {
-                    from,
-                    to,
-                    value,
-                    nonce: None,
-                    gas_price: None,
-                    data: Hex(vec![]),
-                })
-                .unwrap();
-            }
-        }
-        Cmd::Mine { to, mut amount } => {
-            let to = H160::from_str(&to).unwrap();
-            rpc.unlock_account(&to, &passwd).ok();
-            let mut rpc = rpc.subscribe_new_head().unwrap();
-
-            rpc.miner_start().unwrap();
-            while !rpc.pending_transactions().unwrap().is_empty() {
-                rpc.next().unwrap();
-                amount = amount.saturating_sub(1);
-            }
-            for _ in 0..amount {
-                rpc.next().unwrap();
-            }
-            rpc.miner_stop().unwrap();
-        }
-        Cmd::Resetdb => {
-            let block = rpc.earliest_block().unwrap();
-            let mut db = taler_config.db_config().connect(NoTls).unwrap();
-            let mut tx = db.transaction().unwrap();
-            // Clear transaction tables and reset state
-            tx.execute("DELETE FROM tx_in", &[]).unwrap();
-            tx.execute("DELETE FROM tx_out", &[]).unwrap();
-            tx.execute("DELETE FROM bounce", &[]).unwrap();
-            tx.execute(
-                "UPDATE state SET value=$1 WHERE name='sync'",
-                &[&SyncState {
-                    tip_hash: block.hash.unwrap(),
-                    tip_height: block.number.unwrap(),
-                    conf_height: block.number.unwrap(),
-                }
-                .to_bytes()
-                .as_ref()],
-            )
-            .unwrap();
-            tx.commit().unwrap();
-        }
-        Cmd::Balance { addr } => {
-            let addr = H160::from_str(&addr).unwrap();
-            let balance = rpc.get_balance(&addr).unwrap();
-            println!("{}", (balance / TRUNC).as_u64());
-        }
-        Cmd::CheckBalance {
-            client_addr,
-            client,
-            wire_addr,
-            wire,
-        } => {
-            let start = Instant::now();
-            let client_addr = H160::from_str(&client_addr).unwrap();
-            let wire_addr = H160::from_str(&wire_addr).unwrap();
-            loop {
-                let client_balance = (rpc.get_balance(&client_addr).unwrap() / 
TRUNC).as_u64();
-                let wire_balance = (rpc.get_balance(&wire_addr).unwrap() / 
TRUNC).as_u64();
-                if client_balance == client && wire_balance == wire {
-                    break;
-                } else if start.elapsed() > Duration::from_secs(60) {
-                    println!(
-                        "Expected {} {} got {} {}",
-                        client, wire, client_balance, wire_balance
-                    );
-                    exit(1);
-                } else {
-                    std::thread::sleep(Duration::from_secs(5))
-                }
-            }
-        }
-        Cmd::Abandon { from } => {
-            let from = H160::from_str(&from).unwrap();
-            rpc.unlock_account(&from, &passwd).ok();
-            let pending = rpc.pending_transactions().unwrap();
-            for tx in pending.into_iter().filter(|t| t.from == Some(from)) {
-                // Replace transaction value with 0
-                rpc.send_transaction(&TransactionRequest {
-                    from,
-                    to: tx.to.unwrap(),
-                    value: U256::zero(),
-                    gas_price: Some(U256::from(1u8)), // Bigger gas price to 
replace fee
-                    data: Hex(vec![]),
-                    nonce: Some(tx.nonce),
-                })
-                .unwrap();
-            }
-        }
-        Cmd::Export { path } => {
-            std::fs::remove_file(&path).ok();
-            assert!(rpc.export_chain(&path).unwrap())
-        }
-    }
-}
diff --git a/eth-wire/src/loops/analysis.rs b/eth-wire/src/loops/analysis.rs
index e12feb4..471409c 100644
--- 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::{ Rpc, AutoRpcCommon, RpcClient};
+use eth_wire::rpc::{AutoRpcCommon, Rpc, RpcClient};
 use ethereum_types::{H256, U64};
 
 use crate::WireState;
diff --git a/eth-wire/src/loops/worker.rs b/eth-wire/src/loops/worker.rs
index 2d9d95e..da68160 100644
--- a/eth-wire/src/loops/worker.rs
+++ b/eth-wire/src/loops/worker.rs
@@ -382,7 +382,11 @@ fn sync_chain_outgoing(tx: &SyncTransaction, db: &mut 
Client, state: &WireState)
                                 ],
                             )?;
                             if nb_row > 0 {
-                                warn!("|| (recovered) {} in {}", &bounced, 
hex::encode(tx.hash));
+                                warn!(
+                                    "|| (recovered) {} in {}",
+                                    hex::encode(bounced),
+                                    hex::encode(tx.hash)
+                                );
                             }
                         }
                         BounceStatus::Ignored => error!(
@@ -399,7 +403,11 @@ fn sync_chain_outgoing(tx: &SyncTransaction, db: &mut 
Client, state: &WireState)
         &[&bounced.as_ref(), &tx.hash.as_ref(), &(BounceStatus::Sent as i16)],
             )?;
                     if nb > 0 {
-                        warn!("|| (onchain) {} in {}", &bounced, 
hex::encode(tx.hash));
+                        warn!(
+                            "|| (onchain) {} in {}",
+                            hex::encode(bounced),
+                            hex::encode(tx.hash)
+                        );
                     }
                 }
             }
diff --git a/eth-wire/src/rpc.rs b/eth-wire/src/rpc.rs
index 0908290..ab9f5fd 100644
--- a/eth-wire/src/rpc.rs
+++ b/eth-wire/src/rpc.rs
@@ -372,11 +372,16 @@ pub trait RpcClient {
         self.call("eth_getBlockByNumber", &("earliest", &true))
     }
 
-    /// Get account balance
-    fn get_balance(&mut self, addr: &Address) -> Result<U256> {
+    /// Get latest account balance
+    fn get_balance_latest(&mut self, addr: &Address) -> Result<U256> {
         self.call("eth_getBalance", &(addr, "latest"))
     }
 
+    /// Get pending account balance
+    fn get_balance_pending(&mut self, addr: &Address) -> Result<U256> {
+        self.call("eth_getBalance", &(addr, "pending"))
+    }
+
     /// Get node info
     fn node_info(&mut self) -> Result<NodeInfo> {
         self.call("admin_nodeInfo", &EMPTY)
diff --git a/instrumentation/Cargo.toml b/instrumentation/Cargo.toml
index 3172f14..2690f1c 100644
--- a/instrumentation/Cargo.toml
+++ b/instrumentation/Cargo.toml
@@ -7,17 +7,28 @@ rust-version = "1.56.1"
 
 [dependencies]
 # Cli args parser
-clap = { version = "3.1.5", features = ["derive"] }
+clap = { version = "3.2.13", features = ["derive"] }
 common = { path = "../common" }
 # Bitcoin
 btc-wire = { path = "../btc-wire" }
-bitcoin = { version = "0.27.1", default-features = false }
+bitcoin = { version = "0.28.1", default-features = false }
 # Ethereum
 eth-wire = { path = "../eth-wire" }
 ethereum-types = { version = "0.13.1", default-features = false }
 hex = "0.4.3"
 # Wire Gateway
-ureq = { version = "2.4.0", features = ["json"] }
+ureq = { version = "2.5.0", features = ["json"] }
+# In memory deflate library
+libdeflater = "0.10.0"
+# Generate temporary files
+tempfile = "3.3.0"
+# RNG
+fastrand = "1.7.0"
+# terminal color
+owo-colors = "3.4.0"
+# Better backtrace
+color-backtrace = "0.5.1"
+
 
 [build-dependencies]
 clap_mangen = "0.1"
diff --git a/instrumentation/README.md b/instrumentation/README.md
index eb6883e..d98ff73 100644
--- a/instrumentation/README.md
+++ b/instrumentation/README.md
@@ -1,19 +1,37 @@
 # Depolymerizer instrumentation test
 
-Local tests running on a private development network are meant to test the good
-behavior in case of extreme situations but do not attest our capacity to handle
-real network behavior.
-
 ## Install
 
 `cargo install --path instrumentation`
 
-## Run
+## Offline local tests
+
+Local tests require additional binaries. The following binaries must be in the
+local user PATH:
+
+- `pg_ctl` and `psql` from PostgreSQL
+- `geth` from [go-ethereum](https://geth.ethereum.org/downloads/)
+- `bitcoind` and `bitcoin-cli` from
+  [bitcoincore](https://bitcoincore.org/en/download/)
+- `taler-config` and `taler-exchange-wire-gateway-client` from the
+  [Taler exchange ](https://git.taler.net/exchange.git/)
+
+You can use the [prepare](script/prepare.sh) script to download and extract
+blockchain binaries and find the path of the local Postgres installation.
+However, taler binaries need to be compiled from source for now.
+
+Run `instrumentation --offline` to run all tests.
+
+## Online tests
+
+Local tests running on a private development network are meant to test the good
+behavior in case of extreme situations but do not attest our capacity to handle
+real network behavior.
 
-First, follow a normal setup for the adapter and then run `instrumentation`. 
The
+First, follow a normal setup for the adapter and then run `instrumentation 
--online`. The
 tested blockchain will be determined based on the taler configuration.
 
-## Temporary database
+### Temporary database
 
 If you do not want to use a persistent database for instrumentation tests, 
there
 is a [script](../script/tmp_db.sh) to generate a temporary database similar to
diff --git a/test/conf/bitcoin.conf b/instrumentation/conf/bitcoin.conf
similarity index 70%
rename from test/conf/bitcoin.conf
rename to instrumentation/conf/bitcoin.conf
index b824b91..74de105 100755
--- a/test/conf/bitcoin.conf
+++ b/instrumentation/conf/bitcoin.conf
@@ -2,6 +2,7 @@ regtest=1
 txindex=1
 maxtxfee=0.01
 fallbackfee=0.00000001
+rpcservertimeout=10
 
 [regtest]
 port=8345
diff --git a/test/conf/bitcoin2.conf b/instrumentation/conf/bitcoin2.conf
similarity index 58%
rename from test/conf/bitcoin2.conf
rename to instrumentation/conf/bitcoin2.conf
index 168b564..c739e6b 100755
--- a/test/conf/bitcoin2.conf
+++ b/instrumentation/conf/bitcoin2.conf
@@ -1,6 +1,8 @@
 regtest=1
 txindex=1
+maxtxfee=0.01
 fallbackfee=0.00000001
+rpcservertimeout=0
 
 [regtest]
 port=8346
diff --git a/test/conf/bitcoin_auth0.conf 
b/instrumentation/conf/bitcoin_auth0.conf
similarity index 100%
rename from test/conf/bitcoin_auth0.conf
rename to instrumentation/conf/bitcoin_auth0.conf
diff --git a/test/conf/bitcoin_auth1.conf 
b/instrumentation/conf/bitcoin_auth1.conf
similarity index 84%
rename from test/conf/bitcoin_auth1.conf
rename to instrumentation/conf/bitcoin_auth1.conf
index 89e4a44..980d79b 100755
--- a/test/conf/bitcoin_auth1.conf
+++ b/instrumentation/conf/bitcoin_auth1.conf
@@ -9,4 +9,4 @@ rpcpassword=password
 port=8346
 rpcport=18346
 rpcuser=alice
-rpcpassword=password
\ No newline at end of file
+rpcpassword=password TODO
\ No newline at end of file
diff --git a/test/conf/bitcoin_auth2.conf 
b/instrumentation/conf/bitcoin_auth2.conf
similarity index 100%
rename from test/conf/bitcoin_auth2.conf
rename to instrumentation/conf/bitcoin_auth2.conf
diff --git a/test/conf/bitcoin_auth3.conf 
b/instrumentation/conf/bitcoin_auth3.conf
similarity index 100%
rename from test/conf/bitcoin_auth3.conf
rename to instrumentation/conf/bitcoin_auth3.conf
diff --git a/test/conf/bitcoin_auth4.conf 
b/instrumentation/conf/bitcoin_auth4.conf
similarity index 100%
rename from test/conf/bitcoin_auth4.conf
rename to instrumentation/conf/bitcoin_auth4.conf
diff --git a/test/conf/bitcoin_auth5.conf 
b/instrumentation/conf/bitcoin_auth5.conf
similarity index 100%
rename from test/conf/bitcoin_auth5.conf
rename to instrumentation/conf/bitcoin_auth5.conf
diff --git a/test/conf/taler_btc.conf b/instrumentation/conf/taler_btc.conf
similarity index 100%
rename from test/conf/taler_btc.conf
rename to instrumentation/conf/taler_btc.conf
diff --git a/test/conf/taler_btc_auth.conf 
b/instrumentation/conf/taler_btc_auth.conf
similarity index 100%
rename from test/conf/taler_btc_auth.conf
rename to instrumentation/conf/taler_btc_auth.conf
diff --git a/test/conf/taler_btc_bump.conf 
b/instrumentation/conf/taler_btc_bump.conf
similarity index 100%
rename from test/conf/taler_btc_bump.conf
rename to instrumentation/conf/taler_btc_bump.conf
diff --git a/test/conf/taler_btc_lifetime.conf 
b/instrumentation/conf/taler_btc_lifetime.conf
similarity index 88%
rename from test/conf/taler_btc_lifetime.conf
rename to instrumentation/conf/taler_btc_lifetime.conf
index c24c27f..9b3977e 100755
--- a/test/conf/taler_btc_lifetime.conf
+++ b/instrumentation/conf/taler_btc_lifetime.conf
@@ -10,5 +10,5 @@ PORT          = 8060
 PAYTO         = payto://bitcoin/bcrt1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj
 CONFIRMATION  = 3
 HTTP_LIFETIME = 10
-WIRE_LIFETIME = 10
-AUTH_METHOD  = none
\ No newline at end of file
+WIRE_LIFETIME = 110
+AUTH_METHOD   = none
\ No newline at end of file
diff --git a/test/conf/taler_eth.conf b/instrumentation/conf/taler_eth.conf
similarity index 100%
rename from test/conf/taler_eth.conf
rename to instrumentation/conf/taler_eth.conf
diff --git a/test/conf/taler_eth_bump.conf 
b/instrumentation/conf/taler_eth_bump.conf
similarity index 100%
rename from test/conf/taler_eth_bump.conf
rename to instrumentation/conf/taler_eth_bump.conf
diff --git a/test/conf/taler_eth_lifetime.conf 
b/instrumentation/conf/taler_eth_lifetime.conf
similarity index 100%
rename from test/conf/taler_eth_lifetime.conf
rename to instrumentation/conf/taler_eth_lifetime.conf
diff --git a/instrumentation/src/btc.rs b/instrumentation/src/btc.rs
index ead376e..85620db 100644
--- a/instrumentation/src/btc.rs
+++ b/instrumentation/src/btc.rs
@@ -14,18 +14,29 @@
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 
-use std::{path::Path, time::Duration};
+use std::{
+    ops::{Deref, DerefMut},
+    path::{Path, PathBuf},
+    str::FromStr,
+    sync::atomic::Ordering,
+    thread::sleep,
+    time::Duration,
+};
 
-use bitcoin::{Amount, BlockHash, Network, SignedAmount, Txid, hashes::Hash};
+use bitcoin::{hashes::Hash, Address, Amount, BlockHash, Network, SignedAmount, 
Txid};
 use btc_wire::{
+    btc_config::BitcoinConfig,
     rpc::{self, Category, ErrorCode, Rpc, Transaction},
-    rpc_utils,
+    rpc_utils::{self, segwit_min_amount},
     taler_utils::{btc_payto_url, btc_to_taler},
     WireState,
 };
-use common::{rand_slice, metadata::OutMetadata};
+use common::{currency::CurrencyBtc, metadata::OutMetadata, postgres::NoTls, 
rand_slice};
 
-use crate::{check_incoming, check_outgoing, print_now, transfer};
+use crate::utils::{
+    check_incoming, check_outgoing, cmd_redirect, cmd_redirect_ok, print_now, 
retry, retry_opt,
+    transfer, ChildGuard, CommonCtx, Dirs,
+};
 
 pub const CLIENT: &str = "client";
 pub const WIRE: &str = "wire";
@@ -54,7 +65,7 @@ fn wait_for_pending(since: &mut BlockHash, client_rpc: &mut 
Rpc, wire_rpc: &mut
         }
         break;
     }
-    println!("");
+    println!();
 }
 
 pub fn btc_test(config: Option<&Path>, base_url: &str) {
@@ -95,7 +106,7 @@ pub fn btc_test(config: Option<&Path>, base_url: &str) {
             client_rpc.wait_for_new_block().unwrap();
             print_now(".");
         }
-        println!("");
+        println!();
     }
     let mut since = client_rpc.list_since_block(None, 1).unwrap().lastblock;
     // Load wire
@@ -166,7 +177,7 @@ pub fn btc_test(config: Option<&Path>, base_url: &str) {
         rpc.wait_for_new_block().unwrap();
         print_now(".");
     };
-    println!("");
+    println!();
     wait_for_pending(&mut since, &mut client_rpc, &mut wire_rpc);
 
     println!("Check balance");
@@ -181,7 +192,11 @@ pub fn btc_test(config: Option<&Path>, base_url: &str) {
         new_wire_balance
     );
 
-    check_incoming(base_url, &reserve_pub_key, &taler_test_amount);
+    println!("Check incoming history");
+    assert!(check_incoming(
+        base_url,
+        &[(reserve_pub_key, taler_test_amount.clone())]
+    ));
 
     println!("Get back some money");
     let wtid = rand_slice();
@@ -198,5 +213,931 @@ pub fn btc_test(config: Option<&Path>, base_url: &str) {
     let last_client_balance = client_rpc.get_balance().unwrap();
     assert_eq!(new_client_balance + test_amount, last_client_balance);
 
-    check_outgoing(base_url, &wtid, &state.base_url, &taler_test_amount);
+    println!("Check outgoing history");
+    assert!(check_outgoing(
+        base_url,
+        &state.base_url,
+        &[(wtid, taler_test_amount)]
+    ));
+}
+
+pub struct BtcCtx {
+    btc_node: ChildGuard,
+    _btc_node2: ChildGuard,
+    common_rpc: Rpc,
+    common_rpc2: Rpc,
+    wire_rpc: Rpc,
+    client_rpc: Rpc,
+    reserve_rpc: Rpc,
+    wire_addr: Address,
+    pub client_addr: Address,
+    reserve_addr: Address,
+    state: WireState,
+    conf: u16,
+    common: CommonCtx,
+}
+
+impl Deref for BtcCtx {
+    type Target = CommonCtx;
+
+    fn deref(&self) -> &Self::Target {
+        &self.common
+    }
+}
+
+impl DerefMut for BtcCtx {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.common
+    }
+}
+
+impl BtcCtx {
+    pub fn setup(config: &str, stressed: bool) -> Self {
+        Self::_setup(config, stressed)
+    }
+
+    pub fn config(config: &str) {
+        std::fs::create_dir_all("log").unwrap();
+        for file in std::fs::read_dir("log").unwrap() {
+            std::fs::write(file.unwrap().path(), "").unwrap();
+        }
+        // Generate temporary dirs
+        let dirs = Dirs::generate();
+        // Bitcoin config
+        let config = PathBuf::from_str("instrumentation/conf")
+            .unwrap()
+            .join(config);
+        std::fs::copy(config, dirs.wire_dir.join("bitcoin.conf")).unwrap();
+        // Load config
+        let config =
+            BitcoinConfig::load(dirs.wire_dir.join("bitcoin.conf"), 
CurrencyBtc::Dev).unwrap();
+        // Start bitcoin nodes
+        let _btc_node = cmd_redirect(
+            "bitcoind",
+            &[&format!("-datadir={}", dirs.wire_dir.to_string_lossy())],
+            "log/node.log",
+        );
+        // Connect
+        retry(|| {
+            Rpc::common(&config)
+                .ok()
+                .and_then(|mut it| it.get_blockchain_info().ok())
+                .is_some()
+        })
+    }
+
+    fn _setup(taler_config: &str, stressed: bool) -> Self {
+        let dirs = CommonCtx::setup_dirs(taler_config);
+        // Prepare config
+        let (btc_config2, state) = {
+            // Bitcoin config
+            let config = PathBuf::from_str("instrumentation/conf")
+                .unwrap()
+                .join("bitcoin.conf");
+            std::fs::copy(config, dirs.wire_dir.join("bitcoin.conf")).unwrap();
+            std::fs::copy(
+                "instrumentation/conf/bitcoin2.conf",
+                dirs.wire_dir2.join("bitcoin.conf"),
+            )
+            .unwrap();
+            // Load config
+            let state = WireState::load_taler_config(Some(&dirs.conf));
+            (
+                BitcoinConfig::load(dirs.wire_dir2.join("bitcoin.conf"), 
state.currency).unwrap(),
+                state,
+            )
+        };
+        // Start bitcoin nodes
+        let btc_node = cmd_redirect(
+            "bitcoind",
+            &[&format!("-datadir={}", dirs.wire_dir.to_string_lossy())],
+            "log/node.log",
+        );
+        let btc_node2 = cmd_redirect(
+            "bitcoind",
+            &[&format!("-datadir={}", dirs.wire_dir2.to_string_lossy())],
+            "log/node2.log",
+        );
+
+        let common = CommonCtx::setup(dirs, "btc-wire", stressed, |dirs| {
+            // Generate wallet
+            cmd_redirect_ok(
+                "btc-wire",
+                &["-c", dirs.conf.to_str().unwrap(), "initwallet"],
+                "log/cmd.log",
+                "wire initwallet",
+            );
+        });
+
+        // Setup wallets
+        let mut common_rpc = retry_opt(|| Rpc::common(&state.btc_config).ok());
+        common_rpc.add_node("127.0.0.1:8346").unwrap();
+
+        for name in ["client", "reserve"] {
+            common_rpc.create_wallet(name, "").unwrap();
+        }
+        let common_rpc2 = retry_opt(|| Rpc::common(&btc_config2).ok());
+
+        // Generate money
+        let mut reserve_rpc = Rpc::wallet(&state.btc_config, 
"reserve").unwrap();
+        let mut client_rpc = Rpc::wallet(&state.btc_config, "client").unwrap();
+        let mut wire_rpc = Rpc::wallet(&state.btc_config, "wire").unwrap();
+        let reserve_addr = reserve_rpc.gen_addr().unwrap();
+        let client_addr = client_rpc.gen_addr().unwrap();
+        let wire_addr = wire_rpc.gen_addr().unwrap();
+        common_rpc.mine(101, &reserve_addr).unwrap();
+        reserve_rpc
+            .send(&client_addr, &(Amount::ONE_BTC * 10), None, false)
+            .unwrap();
+        common_rpc.mine(1, &reserve_addr).unwrap();
+
+        let conf = state.confirmation.load(Ordering::SeqCst) as u16;
+        Self {
+            common,
+            btc_node,
+            common_rpc,
+            wire_rpc,
+            client_rpc,
+            reserve_rpc,
+            wire_addr,
+            client_addr,
+            reserve_addr,
+            state,
+            conf,
+            _btc_node2: btc_node2,
+            common_rpc2,
+        }
+    }
+
+    pub fn reset_db(&mut self) {
+        let hash: BlockHash = self.common_rpc.get_genesis().unwrap();
+        let mut db = 
self.common.taler_conf.db_config().connect(NoTls).unwrap();
+        let mut tx = db.transaction().unwrap();
+        // Clear transaction tables and reset state
+        tx.batch_execute("DELETE FROM tx_in;DELETE FROM tx_out;DELETE FROM 
bounce;")
+            .unwrap();
+        tx.execute(
+            "UPDATE state SET value=$1 WHERE name='last_hash'",
+            &[&hash.as_ref()],
+        )
+        .unwrap();
+        tx.commit().unwrap();
+    }
+
+    pub fn stop_node(&mut self) {
+        // We need to kill bitcoin gracefully to avoid corruption
+        #[cfg(unix)]
+        {
+            cmd_redirect_ok(
+                "kill",
+                &[&self.btc_node.0.id().to_string()],
+                "/dev/null",
+                "fill btc node",
+            );
+            self.btc_node.0.wait().unwrap();
+        }
+    }
+
+    pub fn cluster_deco(&mut self) {
+        self.common_rpc.disconnect_node("127.0.0.1:8346").unwrap();
+    }
+
+    pub fn cluster_fork(&mut self, length: u16) {
+        self.common_rpc2.mine(length, &self.reserve_addr).unwrap();
+        self.common_rpc.add_node("127.0.0.1:8346").unwrap();
+    }
+
+    pub fn restart_node(&mut self, additional_args: &[&str]) {
+        self.stop_node();
+        self.resume_node(additional_args);
+    }
+
+    pub fn resume_node(&mut self, additional_args: &[&str]) {
+        let datadir = format!("-datadir={}", 
self.common.dirs.wire_dir.to_string_lossy());
+        let mut args = vec![datadir.as_str()];
+        args.extend_from_slice(additional_args);
+        self.btc_node = cmd_redirect("bitcoind", &args, "log/node.log");
+        self.common_rpc = retry_opt(|| 
Rpc::common(&self.state.btc_config).ok());
+        self.common_rpc.add_node("127.0.0.1:8346").unwrap();
+        for name in ["client", "reserve", "wire"] {
+            self.common_rpc.load_wallet(name).ok();
+        }
+
+        self.reserve_rpc = Rpc::wallet(&self.state.btc_config, 
"reserve").unwrap();
+        self.client_rpc = Rpc::wallet(&self.state.btc_config, 
"client").unwrap();
+        self.wire_rpc = Rpc::wallet(&self.state.btc_config, "wire").unwrap();
+    }
+
+    /* ----- Transaction ------ */
+
+    pub fn credit(&mut self, amount: Amount, metadata: [u8; 32]) {
+        self.client_rpc
+            .send_segwit_key(&self.wire_addr, &amount, &metadata)
+            .unwrap();
+    }
+
+    pub fn debit(&mut self, amount: Amount, metadata: [u8; 32]) {
+        transfer(
+            &self.common.gateway_url,
+            &metadata,
+            &self.state.base_url,
+            btc_payto_url(&self.client_addr),
+            &btc_to_taler(&amount.to_signed().unwrap(), self.state.currency),
+        )
+    }
+
+    pub fn malformed_credit(&mut self, amount: &Amount) {
+        self.client_rpc
+            .send(&self.wire_addr, amount, None, false)
+            .unwrap();
+    }
+
+    pub fn reset_wallet(&mut self) {
+        let amount = self.wire_balance();
+        self.wire_rpc
+            .send(&self.client_addr, &amount, None, true)
+            .unwrap();
+        self.next_block();
+    }
+
+    fn abandon(rpc: &mut Rpc) {
+        let list = rpc.list_since_block(None, 1).unwrap();
+        for tx in list.transactions {
+            if tx.category == Category::Send && tx.confirmations == 0 {
+                rpc.abandon_tx(&tx.txid).unwrap();
+            }
+        }
+    }
+
+    pub fn abandon_wire(&mut self) {
+        Self::abandon(&mut self.wire_rpc);
+    }
+
+    pub fn abandon_client(&mut self) {
+        Self::abandon(&mut self.client_rpc);
+    }
+
+    /* ----- Mining ----- */
+
+    fn mine(&mut self, nb: u16) {
+        self.common_rpc.mine(nb, &self.reserve_addr).unwrap();
+    }
+
+    pub fn next_conf(&mut self) {
+        self.mine(self.conf)
+    }
+
+    pub fn next_block(&mut self) {
+        self.mine(1)
+    }
+
+    /* ----- Balances ----- */
+
+    pub fn client_balance(&mut self) -> Amount {
+        self.client_rpc.get_balance().unwrap()
+    }
+
+    pub fn wire_balance(&mut self) -> Amount {
+        self.wire_rpc.get_balance().unwrap()
+    }
+
+    fn expect_balance(&mut self, balance: Amount, mine: bool, lambda: fn(&mut 
Self) -> Amount) {
+        retry(|| {
+            let check = balance == lambda(self);
+            if !check && mine {
+                self.next_block();
+            }
+            check
+        });
+    }
+
+    pub fn expect_client_balance(&mut self, balance: Amount, mine: bool) {
+        self.expect_balance(balance, mine, Self::client_balance)
+    }
+
+    pub fn expect_wire_balance(&mut self, balance: Amount, mine: bool) {
+        self.expect_balance(balance, mine, Self::wire_balance)
+    }
+
+    /* ----- Wire Gateway ----- */
+
+    pub fn expect_credits(&self, txs: &[([u8; 32], Amount)]) {
+        let txs: Vec<_> = txs
+            .iter()
+            .map(|(metadata, amount)| {
+                (
+                    *metadata,
+                    btc_to_taler(&amount.to_signed().unwrap(), 
self.state.currency),
+                )
+            })
+            .collect();
+        self.common.expect_credits(&txs)
+    }
+
+    pub fn expect_debits(&self, txs: &[([u8; 32], Amount)]) {
+        let txs: Vec<_> = txs
+            .iter()
+            .map(|(metadata, amount)| {
+                (
+                    *metadata,
+                    btc_to_taler(&amount.to_signed().unwrap(), 
self.state.currency),
+                )
+            })
+            .collect();
+        self.common.expect_debits(&self.state.base_url, &txs)
+    }
+}
+
+pub const TESTS: &[(fn(), &str)] = &[
+    (wire, "btc_wire"),
+    (lifetime, "btc_lifetime"),
+    (reconnect, "btc_reconnect"),
+    (stress, "btc_stress"),
+    (conflict, "btc_conflict"),
+    (reorg, "btc_reorg"),
+    (hell, "btc_hell"),
+    (analysis, "btc_analysis"),
+    (bumpfee, "btc_bumpfee"),
+    (maxfee, "btc_maxfee"),
+    (config, "btc_config"),
+];
+
+/// Test btc-wire correctly receive and send transactions on the blockchain
+fn wire() {
+    println!("Setup");
+    let mut ctx = BtcCtx::setup("taler_btc.conf", false);
+
+    println!("Credit");
+    {
+        // Send transactions
+        let mut balance = ctx.wire_balance();
+        let mut txs = Vec::new();
+        for n in 10..100 {
+            let metadata = rand_slice();
+            let amount = Amount::from_sat(n * 1000);
+            ctx.credit(amount, metadata);
+            txs.push((metadata, amount));
+            balance += amount;
+            ctx.next_block();
+        }
+        ctx.next_conf();
+        ctx.expect_credits(&txs);
+        ctx.expect_wire_balance(balance, true);
+    };
+
+    println!("Debit");
+    {
+        let mut balance = ctx.client_balance();
+        let mut txs = Vec::new();
+        for n in 10..100 {
+            let metadata = rand_slice();
+            let amount = Amount::from_sat(n * 100);
+            balance += amount;
+            ctx.debit(amount, metadata);
+            txs.push((metadata, amount));
+        }
+        ctx.next_block();
+        ctx.expect_debits(&txs);
+        ctx.expect_client_balance(balance, true);
+    }
+
+    println!("Bounce");
+    {
+        ctx.reset_wallet();
+        // Send bad transactions
+        let mut balance = ctx.wire_balance();
+        for n in 10..40 {
+            ctx.malformed_credit(&Amount::from_sat(n * 1000));
+            balance += ctx.state.bounce_fee;
+        }
+        ctx.next_conf();
+        ctx.expect_wire_balance(balance, true);
+    }
+}
+
+/// Check btc-wire and wire-gateway correctly stop when a lifetime limit is 
configured
+fn lifetime() {
+    println!("Setup");
+    let mut ctx = BtcCtx::setup("taler_btc_lifetime.conf", false);
+    println!("Check lifetime");
+    // Start up
+    retry(|| ctx.wire_running() && ctx.gateway_running());
+    // Consume lifetime
+    for _ in 0..=ctx.taler_conf.wire_lifetime().unwrap() {
+        ctx.credit(segwit_min_amount(), rand_slice());
+        ctx.next_block();
+    }
+    for _ in 0..=ctx.taler_conf.http_lifetime().unwrap() {
+        ctx.debit(segwit_min_amount(), rand_slice());
+        ctx.next_block();
+    }
+    // End down
+    retry(|| !ctx.wire_running() && !ctx.gateway_running());
+}
+
+/// Check the capacity of wire-gateway and btc-wire to recover from database 
and node loss
+fn reconnect() {
+    println!("Setup");
+    let mut ctx = BtcCtx::setup("taler_btc.conf", false);
+
+    let mut credits = Vec::new();
+    let mut debits = Vec::new();
+
+    println!("With DB");
+    {
+        let metadata = rand_slice();
+        let amount = Amount::from_sat(42000);
+        ctx.credit(amount, metadata);
+        credits.push((metadata, amount));
+        ctx.next_block();
+        ctx.next_conf();
+        ctx.expect_credits(&credits);
+    };
+
+    println!("Without DB");
+    {
+        ctx.stop_db();
+        ctx.malformed_credit(&Amount::from_sat(24000));
+        let metadata = rand_slice();
+        let amount = Amount::from_sat(40000);
+        ctx.credit(amount, metadata);
+        credits.push((metadata, amount));
+        ctx.stop_node();
+        ctx.expect_error();
+    }
+
+    println!("Reconnect DB");
+    {
+        ctx.resume_db();
+        ctx.resume_node(&[]);
+        let metadata = rand_slice();
+        let amount = Amount::from_sat(2000);
+        ctx.debit(amount, metadata);
+        debits.push((metadata, amount));
+        ctx.next_block();
+        sleep(Duration::from_secs(3));
+        ctx.next_block();
+        sleep(Duration::from_secs(3));
+        ctx.next_block();
+        ctx.expect_debits(&debits);
+        ctx.expect_credits(&credits);
+    }
+
+    println!("Recover DB");
+    {
+        let balance = ctx.wire_balance();
+        ctx.reset_db();
+        ctx.next_block();
+        ctx.expect_debits(&debits);
+        ctx.expect_credits(&credits);
+        ctx.expect_wire_balance(balance, true);
+    }
+}
+
+/// Test btc-wire ability to recover from errors in correctness critical paths 
and prevent concurrent sending
+fn stress() {
+    println!("Setup");
+    let mut ctx = BtcCtx::setup("taler_btc.conf", true);
+
+    let mut credits = Vec::new();
+    let mut debits = Vec::new();
+
+    println!("Credit");
+    {
+        let mut balance = ctx.wire_balance();
+        for n in 10..30 {
+            let metadata = rand_slice();
+            let amount = Amount::from_sat(n * 1000);
+            ctx.credit(amount, metadata);
+            credits.push((metadata, amount));
+            balance += amount;
+            ctx.next_block();
+        }
+        ctx.next_conf();
+        ctx.expect_credits(&credits);
+        ctx.expect_wire_balance(balance, true);
+    };
+
+    println!("Debit");
+    {
+        let mut balance = ctx.client_balance();
+        for n in 10..30 {
+            let metadata = rand_slice();
+            let amount = Amount::from_sat(n * 100);
+            balance += amount;
+            ctx.debit(amount, metadata);
+            debits.push((metadata, amount));
+        }
+        ctx.next_block();
+        ctx.expect_debits(&debits);
+        ctx.expect_client_balance(balance, true);
+    }
+
+    println!("Bounce");
+    {
+        ctx.reset_wallet();
+        let mut balance = ctx.wire_balance();
+        for n in 10..30 {
+            ctx.malformed_credit(&Amount::from_sat(n * 1000));
+            balance += ctx.state.bounce_fee;
+        }
+        ctx.next_conf();
+        ctx.expect_wire_balance(balance, true);
+    }
+
+    println!("Recover DB");
+    {
+        let balance = ctx.wire_balance();
+        ctx.reset_db();
+        ctx.next_block();
+        ctx.expect_debits(&debits);
+        ctx.expect_credits(&credits);
+        ctx.expect_wire_balance(balance, true);
+    }
+}
+
+/// Test btc-wire ability to handle conflicting outgoing transactions
+fn conflict() {
+    println!("Setup");
+    let mut ctx = BtcCtx::setup("taler_btc.conf", false);
+
+    println!("Conflict send");
+    {
+        // Perform credit
+        let amount = Amount::from_sat(4200000);
+        ctx.credit(amount, rand_slice());
+        ctx.next_conf();
+        ctx.expect_wire_balance(amount, true);
+        let client = ctx.client_balance();
+        let wire = ctx.wire_balance();
+
+        // Perform debit
+        ctx.debit(Amount::from_sat(400000), rand_slice());
+        retry(|| ctx.wire_balance() < wire);
+
+        // Abandon pending transaction
+        ctx.restart_node(&["-minrelaytxfee=0.0001"]);
+        ctx.abandon_wire();
+        ctx.expect_client_balance(client, false);
+        ctx.expect_wire_balance(wire, false);
+
+        // Generate conflict
+        ctx.debit(Amount::from_sat(500000), rand_slice());
+        retry(|| ctx.wire_balance() < wire);
+
+        // Resend conflicting transaction
+        ctx.restart_node(&[]);
+        ctx.next_block();
+        let wire = ctx.wire_balance();
+        retry(|| ctx.wire_balance() < wire);
+    }
+
+    println!("Setup");
+    drop(ctx);
+    let mut ctx = BtcCtx::setup("taler_btc.conf", false);
+    ctx.credit(Amount::from_sat(3000000), rand_slice());
+    ctx.next_block();
+
+    println!("Conflict bounce");
+    {
+        // Perform bounce
+        let wire = ctx.wire_balance();
+        let bounce_amount = Amount::from_sat(4000000);
+        ctx.malformed_credit(&bounce_amount);
+        ctx.next_conf();
+        let fee = ctx.state.bounce_fee;
+        ctx.expect_wire_balance(wire + fee, true);
+
+        // Abandon pending transaction
+        ctx.restart_node(&["-minrelaytxfee=0.0001"]);
+        ctx.abandon_wire();
+        ctx.expect_wire_balance(wire + bounce_amount, false);
+
+        // Generate conflict
+        let amount = Amount::from_sat(50000);
+        ctx.debit(amount, rand_slice());
+        retry(|| ctx.wire_balance() < (wire + bounce_amount));
+
+        // Resend conflicting transaction
+        ctx.restart_node(&[]);
+        let wire = ctx.wire_balance();
+        ctx.next_block();
+        retry(|| ctx.wire_balance() < wire);
+    }
+}
+
+/// Test btc-wire correctness when a blockchain reorganization occurs
+fn reorg() {
+    println!("Setup");
+    let mut ctx = BtcCtx::setup("taler_btc.conf", false);
+
+    println!("Handle reorg incoming transactions");
+    {
+        // Loose second bitcoin node
+        ctx.cluster_deco();
+
+        // Perform credits
+        let before = ctx.wire_balance();
+        for n in 10..21 {
+            ctx.credit(Amount::from_sat(n * 10000), rand_slice());
+            ctx.next_block();
+        }
+        let after = ctx.wire_balance();
+
+        // Perform fork and check btc-wire hard error
+        ctx.expect_gateway_up();
+        ctx.cluster_fork(22);
+        ctx.expect_wire_balance(before, false);
+        ctx.expect_gateway_down();
+
+        // Recover orphaned transaction
+        ctx.mine(12);
+        ctx.expect_wire_balance(after, false);
+        ctx.expect_gateway_up();
+    }
+
+    println!("Handle reorg outgoing transactions");
+    {
+        // Loose second bitcoin node
+        ctx.cluster_deco();
+
+        // Perform debits
+        let before = ctx.client_balance();
+        let mut after = ctx.client_balance();
+        for n in 10..21 {
+            let amount = Amount::from_sat(n * 100);
+            ctx.debit(amount, rand_slice());
+            after += amount;
+        }
+        ctx.next_block();
+        ctx.expect_client_balance(after, true);
+
+        // Perform fork and check btc-wire still up
+        ctx.expect_gateway_up();
+        ctx.cluster_fork(22);
+        ctx.expect_client_balance(before, false);
+        ctx.expect_gateway_up();
+
+        // Recover orphaned transaction
+        ctx.next_conf();
+        ctx.expect_client_balance(after, false);
+    }
+
+    println!("Handle reorg bounce");
+    {
+        ctx.reset_wallet();
+
+        // Loose second bitcoin node
+        ctx.cluster_deco();
+
+        // Perform bounce
+        let before = ctx.wire_balance();
+        let mut after = ctx.wire_balance();
+        for n in 10..21 {
+            ctx.malformed_credit(&Amount::from_sat(n * 1000));
+            after += ctx.state.bounce_fee;
+        }
+        ctx.next_conf();
+        ctx.expect_wire_balance(after, true);
+
+        // Perform fork and check btc-wire hard error
+        ctx.expect_gateway_up();
+        ctx.cluster_fork(22);
+        ctx.expect_wire_balance(before, false);
+        ctx.expect_gateway_down();
+
+        // Recover orphaned transaction
+        ctx.mine(10);
+        ctx.expect_wire_balance(after, false);
+        ctx.expect_gateway_up();
+    }
+}
+
+/// Test btc-wire correctness when a blockchain reorganization occurs leading 
to past incoming transaction conflict
+fn hell() {
+    fn step(name: &str, action: impl FnOnce(&mut BtcCtx)) {
+        println!("Setup");
+        let mut ctx = BtcCtx::setup("taler_btc.conf", false);
+        println!("{}", name);
+
+        // Loose second bitcoin node
+        ctx.cluster_deco();
+
+        // Perform action
+        action(&mut ctx);
+
+        // Perform fork and check btc-wire hard error
+        ctx.expect_gateway_up();
+        ctx.cluster_fork(ctx.conf * 2);
+        ctx.expect_gateway_down();
+
+        // Generate conflict
+        ctx.restart_node(&["-minrelaytxfee=0.001"]);
+        ctx.abandon_client();
+        let amount = Amount::from_sat(54000);
+        ctx.credit(amount, rand_slice());
+        ctx.expect_wire_balance(amount, true);
+
+        // Check btc-wire suspend operation
+        let bounce_amount = Amount::from_sat(34000);
+        ctx.malformed_credit(&bounce_amount);
+        ctx.next_conf();
+        ctx.expect_wire_balance(amount + bounce_amount, true);
+        ctx.expect_gateway_down();
+    }
+
+    step("Handle reorg conflicting incoming credit", |ctx| {
+        let amount = Amount::from_sat(420000);
+        ctx.credit(amount, rand_slice());
+        ctx.next_conf();
+        ctx.expect_wire_balance(amount, true);
+    });
+
+    step("Handle reorg conflicting incoming bounce", |ctx| {
+        let amount = Amount::from_sat(420000);
+        ctx.malformed_credit(&amount);
+        ctx.next_conf();
+        let fee = ctx.state.bounce_fee;
+        ctx.expect_wire_balance(fee, true);
+    });
+}
+
+/// Test btc-wire ability to learn and protect itself from blockchain behavior
+fn analysis() {
+    println!("Setup");
+    let mut ctx = BtcCtx::setup("taler_btc.conf", false);
+
+    println!("Learn from reorg");
+
+    // Loose second bitcoin node
+    ctx.cluster_deco();
+
+    // Perform credit
+    let before = ctx.wire_balance();
+    ctx.credit(Amount::from_sat(42000), rand_slice());
+    ctx.next_conf();
+    let after = ctx.wire_balance();
+
+    // Perform fork and check btc-wire hard error
+    ctx.expect_gateway_up();
+    ctx.cluster_fork(5);
+    ctx.expect_wire_balance(before, false);
+    ctx.expect_gateway_down();
+
+    // Recover orphaned transaction
+    ctx.next_conf();
+    ctx.expect_wire_balance(after, false);
+    ctx.expect_gateway_up();
+
+    // Loose second bitcoin node
+    ctx.cluster_deco();
+
+    // Perform credit
+    let before = ctx.wire_balance();
+    ctx.credit(Amount::from_sat(42000), rand_slice());
+    ctx.next_conf();
+
+    // Perform fork and check btc-wire learned from previous attack
+    ctx.expect_gateway_up();
+    ctx.cluster_fork(5);
+    ctx.expect_wire_balance(before, false);
+    ctx.expect_gateway_up();
+}
+
+/// Test btc-wire ability to handle stuck transaction correctly
+fn bumpfee() {
+    println!("Setup");
+    let mut ctx = BtcCtx::setup("taler_btc_bump.conf", false);
+
+    // Perform credits to allow wire to perform debits latter
+    for n in 10..13 {
+        ctx.credit(Amount::from_sat(n * 100000), rand_slice());
+        ctx.next_block();
+    }
+    ctx.next_conf();
+
+    println!("Bump fee");
+    {
+        // Perform debit
+        let mut client = ctx.client_balance();
+        let wire = ctx.wire_balance();
+        let amount = Amount::from_sat(40000);
+        ctx.debit(amount, rand_slice());
+        retry(|| ctx.wire_balance() < wire);
+
+        // Bump min relay fee making the previous debit stuck
+        ctx.restart_node(&["-minrelaytxfee=0.0001"]);
+
+        // Check bump happen
+        client += amount;
+        ctx.expect_client_balance(client, true);
+    }
+
+    println!("Bump fee reorg");
+    {
+        // Loose second bitcoin node
+        ctx.cluster_deco();
+
+        // Perform debit
+        let mut client = ctx.client_balance();
+        let wire = ctx.wire_balance();
+        let amount = Amount::from_sat(40000);
+        ctx.debit(amount, rand_slice());
+        retry(|| ctx.wire_balance() < wire);
+
+        // Bump min relay fee and fork making the previous debit stuck and 
problematic
+        ctx.cluster_fork(6);
+        ctx.restart_node(&["-minrelaytxfee=0.0001"]);
+
+        // Check bump happen
+        client += amount;
+        ctx.expect_client_balance(client, true);
+    }
+
+    println!("Setup");
+    drop(ctx);
+    let mut ctx = BtcCtx::setup("taler_btc_bump.conf", true);
+
+    // Perform credits to allow wire to perform debits latter
+    for n in 10..61 {
+        ctx.credit(Amount::from_sat(n * 100000), rand_slice());
+        ctx.next_block();
+    }
+    ctx.next_conf();
+
+    println!("Bump fee stress");
+    {
+        // Loose second bitcoin node
+        ctx.cluster_deco();
+
+        // Perform debits
+        let client = ctx.client_balance();
+        let wire = ctx.wire_balance();
+        let mut total_amount = Amount::ZERO;
+        for n in 10..31 {
+            let amount = Amount::from_sat(n * 10000);
+            total_amount += amount;
+            ctx.debit(amount, rand_slice());
+        }
+        retry(|| ctx.wire_balance() < wire - total_amount);
+
+        // Bump min relay fee making the previous debits stuck
+        ctx.restart_node(&["-minrelaytxfee=0.0001"]);
+
+        // Check bump happen
+        ctx.expect_client_balance(client + total_amount, true);
+    }
+}
+
+/// Test btc-wire handle transaction fees exceeding limits
+fn maxfee() {
+    println!("Setup");
+    let mut ctx = BtcCtx::setup("taler_btc.conf", false);
+
+    // Perform credits to allow wire to perform debits latter
+    for n in 10..31 {
+        ctx.credit(Amount::from_sat(n * 100000), rand_slice());
+        ctx.next_block();
+    }
+    ctx.next_conf();
+
+    let client = ctx.client_balance();
+    let wire = ctx.wire_balance();
+    let mut total_amount = Amount::ZERO;
+
+    println!("Too high fee");
+    {
+        // Change fee config
+        ctx.restart_node(&["-maxtxfee=0.0000001", "-minrelaytxfee=0.0000001"]);
+
+        // Perform debits
+        for n in 10..31 {
+            let amount = Amount::from_sat(n * 10000);
+            total_amount += amount;
+            ctx.debit(amount, rand_slice());
+        }
+        sleep(Duration::from_secs(3));
+
+        // Check no transaction happen
+        ctx.expect_wire_balance(wire, true);
+        ctx.expect_client_balance(client, true);
+    }
+
+    println!("Good feed");
+    {
+        // Restore default config
+        ctx.restart_node(&[]);
+
+        // Check transaction now have been made
+        ctx.expect_client_balance(client + total_amount, true);
+    }
+}
+
+/// Test btc-wire ability to configure itself from bitcoin configuration
+fn config() {
+    for n in 0..5 {
+        let config_name = format!("bitcoin_auth{}.conf", n);
+        println!("Config {}", config_name);
+        BtcCtx::config(&config_name);
+    }
 }
diff --git a/instrumentation/src/eth.rs b/instrumentation/src/eth.rs
index 7a99e4e..ec8ca3c 100644
--- a/instrumentation/src/eth.rs
+++ b/instrumentation/src/eth.rs
@@ -1,14 +1,40 @@
-use std::{path::Path, time::Duration};
+/*
+  This file is part of TALER
+  Copyright (C) 2022 Taler Systems SA
 
-use common::{metadata::OutMetadata, rand_slice};
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+
+use std::{
+    io::Write,
+    ops::{Deref, DerefMut},
+    path::Path,
+    sync::atomic::Ordering,
+    thread::sleep,
+    time::Duration,
+};
+
+use common::{metadata::OutMetadata, postgres::NoTls, rand_slice};
 use eth_wire::{
     rpc::{hex::Hex, Rpc, RpcClient, TransactionRequest},
     taler_util::{eth_payto_url, eth_to_taler, TRUNC},
     RpcExtended, SyncState, WireState,
 };
-use ethereum_types::{H256, U256};
+use ethereum_types::{H160, H256, U256};
 
-use crate::{check_incoming, check_outgoing, print_now, transfer};
+use crate::utils::{
+    check_incoming, check_outgoing, cmd_out, cmd_redirect, cmd_redirect_ok, 
print_now, retry,
+    retry_opt, transfer, ChildGuard, CommonCtx,
+};
 
 fn wait_for_pending(rpc: &mut Rpc) {
     print_now("Wait for pending transactions mining:");
@@ -19,7 +45,7 @@ fn wait_for_pending(rpc: &mut Rpc) {
         print_now(".");
         std::thread::sleep(Duration::from_secs(1)); // Wait for eth-wire to act
     }
-    println!("");
+    println!();
 }
 
 pub fn eth_test(config: Option<&Path>, base_url: &str) {
@@ -41,7 +67,7 @@ pub fn eth_test(config: Option<&Path>, base_url: &str) {
         .unwrap_or_else(|| rpc.new_account("password").unwrap()); // Else 
create account
 
     rpc.unlock_account(&client_addr, "password").unwrap();
-    if rpc.get_balance(&client_addr).unwrap() < min_fund {
+    if rpc.get_balance_latest(&client_addr).unwrap() < min_fund {
         println!(
             "Client need a minimum of {} WEI to run this test, send coins to 
this address: {}",
             min_fund.as_u64(),
@@ -49,17 +75,17 @@ pub fn eth_test(config: Option<&Path>, base_url: &str) {
         );
         print_now("Waiting for fund:");
         let mut rpc = rpc.subscribe_new_head().unwrap();
-        while rpc.get_balance(&client_addr).unwrap() < min_fund {
+        while rpc.get_balance_latest(&client_addr).unwrap() < min_fund {
             rpc.next().unwrap();
             print_now(".");
         }
-        println!("");
+        println!();
     }
 
     wait_for_pending(&mut rpc);
     // Load balances
-    let client_balance = rpc.get_balance(&client_addr).unwrap();
-    let wire_balance = rpc.get_balance(&state.address).unwrap();
+    let client_balance = rpc.get_balance_latest(&client_addr).unwrap();
+    let wire_balance = rpc.get_balance_latest(&state.address).unwrap();
     // Start sync state
     let latest = rpc.latest_block().unwrap();
     let mut sync_state = SyncState {
@@ -120,12 +146,12 @@ pub fn eth_test(config: Option<&Path>, base_url: &str) {
             print_now(".");
         }
     };
-    println!("");
+    println!();
     wait_for_pending(&mut rpc);
 
     println!("Check balance");
-    let new_client_balance = rpc.get_balance(&client_addr).unwrap();
-    let new_wire_balance = rpc.get_balance(&state.address).unwrap();
+    let new_client_balance = rpc.get_balance_latest(&client_addr).unwrap();
+    let new_wire_balance = rpc.get_balance_latest(&state.address).unwrap();
     let client_sent_amount_cost = test_amount * U256::from(2u8);
     let client_sent_fees_cost = [credit_id, zero_id, bounce_id]
         .into_iter()
@@ -146,8 +172,13 @@ pub fn eth_test(config: Option<&Path>, base_url: &str) {
         new_wire_balance
     );
 
-    check_incoming(base_url, &reserve_pub_key, &taler_test_amount);
+    println!("Check incoming history");
+    assert!(check_incoming(
+        base_url,
+        &[(reserve_pub_key, taler_test_amount.clone())]
+    ));
 
+    println!("Get back some money");
     let wtid = rand_slice();
     transfer(
         base_url,
@@ -159,8 +190,935 @@ pub fn eth_test(config: Option<&Path>, base_url: &str) {
     wait_for_pending(&mut rpc);
 
     println!("Check balances");
-    let last_client_balance = rpc.get_balance(&client_addr).unwrap();
+    let last_client_balance = rpc.get_balance_latest(&client_addr).unwrap();
     assert_eq!(new_client_balance + test_amount, last_client_balance);
 
-    check_outgoing(base_url, &wtid, &state.base_url, &taler_test_amount);
+    println!("Check outgoing history");
+    assert!(check_outgoing(
+        base_url,
+        &state.base_url,
+        &[(wtid, taler_test_amount)]
+    ));
+}
+
+struct EthCtx {
+    node: ChildGuard,
+    rpc: Rpc,
+    wire_addr: H160,
+    client_addr: H160,
+    reserve_addr: H160,
+    state: WireState,
+    conf: u16,
+    common: CommonCtx,
+    passwd: String,
+}
+
+impl Deref for EthCtx {
+    type Target = CommonCtx;
+
+    fn deref(&self) -> &Self::Target {
+        &self.common
+    }
+}
+
+impl DerefMut for EthCtx {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.common
+    }
+}
+
+impl EthCtx {
+    pub fn setup(config: &str, stressed: bool) -> Self {
+        let dirs = CommonCtx::setup_dirs(config);
+        // Init chain
+        let passwd = std::env::var("PASSWORD").unwrap();
+        let pswd_path = dirs.dir.path().join("pswd");
+        std::fs::write(&pswd_path, passwd.as_bytes()).unwrap();
+        for _ in ["reserve", "client"] {
+            cmd_redirect_ok(
+                "geth",
+                &[
+                    "--datadir",
+                    dirs.wire_dir.to_str().unwrap(),
+                    "account",
+                    "new",
+                    "--password",
+                    pswd_path.to_str().unwrap(),
+                ],
+                "log/node.log",
+                "create account",
+            )
+        }
+        cmd_redirect_ok(
+            "geth",
+            &[
+                "--datadir",
+                dirs.wire_dir2.to_str().unwrap(),
+                "account",
+                "new",
+                "--password",
+                pswd_path.to_str().unwrap(),
+            ],
+            "log/node2.log",
+            "create account",
+        );
+        let list = cmd_out(
+            "geth",
+            &[
+                "--datadir",
+                dirs.wire_dir.to_str().unwrap(),
+                "account",
+                "list",
+            ],
+        );
+        let addr = &list.lines().nth(1).unwrap()[13..][..40];
+        let genesis = format!(
+            "{{
+            \"config\": {{
+              \"chainId\": 42,
+              \"homesteadBlock\": 0,
+              \"eip150Block\": 0,
+              \"eip155Block\": 0,
+              \"eip158Block\": 0,
+              \"byzantiumBlock\": 0,
+              \"constantinopleBlock\": 0,
+              \"petersburgBlock\": 0,
+              \"istanbulBlock\": 0,
+              \"berlinBlock\": 0,
+              \"londonBlock:\": 0,
+              \"ethash\": {{}}
+            }},
+            \"difficulty\": \"1\",
+            \"gasLimit\": \"0\",
+            \"baseFeePerGas\": null,
+            \"alloc\": {{
+              \"{}\": {{ \"balance\": \"10000000000000000000\" }}
+            }}
+          }}",
+            addr
+        );
+        std::fs::write(dirs.wire_dir.join("genesis.json"), 
genesis.as_bytes()).unwrap();
+
+        cmd_redirect_ok(
+            "geth",
+            &[
+                "--datadir",
+                dirs.wire_dir.to_str().unwrap(),
+                "init",
+                dirs.wire_dir.join("genesis.json").to_str().unwrap(),
+            ],
+            "log/node.log",
+            "init chain",
+        );
+        cmd_redirect_ok(
+            "geth",
+            &[
+                "--datadir",
+                dirs.wire_dir2.to_str().unwrap(),
+                "init",
+                dirs.wire_dir.join("genesis.json").to_str().unwrap(),
+            ],
+            "log/node2.log",
+            "init chain2",
+        );
+
+        let node = cmd_redirect(
+            "geth",
+            &[
+                "--datadir",
+                dirs.wire_dir.to_str().unwrap(),
+                "--miner.gasprice",
+                "10",
+            ],
+            "log/node.log",
+        );
+        let mut rpc = retry_opt(|| Rpc::new(&dirs.wire_dir).ok());
+
+        let common = CommonCtx::setup(dirs, "eth-wire", stressed, |dirs| {
+            // Generate wallet
+            let out = cmd_out(
+                "eth-wire",
+                &["-c", dirs.conf.to_str().unwrap(), "initwallet"],
+            );
+            let payto = format!("\n{}", out.lines().nth(6).unwrap());
+            std::fs::OpenOptions::new()
+                .append(true)
+                .open(&dirs.conf)
+                .unwrap()
+                .write_all(payto.as_bytes())
+                .unwrap();
+        });
+        let state = WireState::load_taler_config(Some(&common.dirs.conf));
+        let accounts = rpc.list_accounts().unwrap();
+        let reserve_addr = accounts[0];
+        let client_addr = accounts[1];
+        let wire_addr = accounts[2];
+        for addr in [&client_addr, &reserve_addr] {
+            rpc.unlock_account(addr, &passwd).unwrap();
+        }
+        let conf = state.confirmation.load(Ordering::SeqCst) as u16;
+
+        Self {
+            node,
+            rpc,
+            reserve_addr,
+            client_addr,
+            wire_addr,
+            state,
+            common,
+            conf,
+            passwd,
+        }
+    }
+
+    pub fn reset_db(&mut self) {
+        let block = self.rpc.earliest_block().unwrap();
+        let mut db = 
self.common.taler_conf.db_config().connect(NoTls).unwrap();
+        let mut tx = db.transaction().unwrap();
+        // Clear transaction tables and reset state
+        tx.batch_execute("DELETE FROM tx_in;DELETE FROM tx_out;DELETE FROM 
bounce;")
+            .unwrap();
+        tx.execute(
+            "UPDATE state SET value=$1 WHERE name='sync'",
+            &[&SyncState {
+                tip_hash: block.hash.unwrap(),
+                tip_height: block.number.unwrap(),
+                conf_height: block.number.unwrap(),
+            }
+            .to_bytes()
+            .as_ref()],
+        )
+        .unwrap();
+        tx.commit().unwrap();
+    }
+
+    pub fn stop_node(&mut self) {
+        // We need to kill node gracefully to avoid corruption
+        #[cfg(unix)]
+        {
+            cmd_redirect_ok(
+                "kill",
+                &[&self.node.0.id().to_string()],
+                "/dev/null",
+                "fill btc node",
+            );
+            self.node.0.wait().unwrap();
+        }
+    }
+
+    // We use the import/export chain functionality to simulate a connected 
node peer
+    // because local network peer are not reliable
+    // importChain RPC crash so we have to use the cli for now
+
+    fn export(rpc: &mut Rpc, path: &str) {
+        std::fs::remove_file(path).ok();
+        assert!(rpc.export_chain(path).unwrap())
+    }
+
+    pub fn cluster_deco(&mut self) {
+        let path = self.dirs.dir.path().join("chain");
+        let path = path.to_str().unwrap();
+        Self::export(&mut self.rpc, path);
+        cmd_redirect_ok(
+            "geth",
+            &[
+                "--datadir",
+                self.dirs.wire_dir2.to_str().unwrap(),
+                "import",
+                path,
+            ],
+            "log/node2.log",
+            "import chain",
+        );
+    }
+
+    pub fn cluster_fork(&mut self, length: u16) {
+        let node2 = cmd_redirect(
+            "geth",
+            &[
+                "--datadir",
+                self.dirs.wire_dir2.to_str().unwrap(),
+                "--port",
+                "30305",
+                "--miner.gasprice",
+                "10",
+            ],
+            "log/node2.log",
+        );
+        let mut rpc = retry_opt(|| Rpc::new(&self.dirs.wire_dir2).ok());
+        Self::_mine(&mut rpc, &self.reserve_addr, length, &self.passwd);
+        let path = self.dirs.dir.path().join("chain");
+        let path = path.to_str().unwrap();
+        Self::export(&mut rpc, path);
+        drop(node2);
+        self.stop_node();
+        cmd_redirect_ok(
+            "geth",
+            &[
+                "--datadir",
+                self.dirs.wire_dir.to_str().unwrap(),
+                "import",
+                path,
+            ],
+            "log/node.log",
+            "import chain",
+        );
+        self.resume_node(&[]);
+    }
+
+    pub fn restart_node(&mut self, additional_args: &[&str]) {
+        self.stop_node();
+        self.resume_node(additional_args);
+    }
+
+    pub fn resume_node(&mut self, additional_args: &[&str]) {
+        let datadir = format!("-datadir={}", 
self.dirs.wire_dir.to_string_lossy());
+        let mut args = vec![datadir.as_str()];
+        args.extend_from_slice(additional_args);
+        self.node = cmd_redirect(
+            "geth",
+            &["--datadir", self.dirs.wire_dir.to_str().unwrap()],
+            "log/node.log",
+        );
+        self.rpc = retry_opt(|| Rpc::new(&self.dirs.wire_dir).ok());
+        for addr in [&self.wire_addr, &self.client_addr, &self.reserve_addr] {
+            self.rpc.unlock_account(addr, &self.passwd).unwrap();
+        }
+    }
+
+    pub fn amount(&self, amount: u32) -> U256 {
+        return U256::from(amount) * TRUNC;
+    }
+
+    /* ----- Transaction ------ */
+
+    pub fn credit(&mut self, amount: U256, metadata: [u8; 32]) {
+        self.rpc
+            .credit(self.client_addr, self.wire_addr, amount, metadata)
+            .unwrap();
+    }
+
+    pub fn debit(&mut self, amount: U256, metadata: [u8; 32]) {
+        transfer(
+            &self.common.gateway_url,
+            &metadata,
+            &self.state.base_url,
+            eth_payto_url(&self.client_addr),
+            &eth_to_taler(&amount, self.state.currency),
+        )
+    }
+
+    pub fn malformed_credit(&mut self, amount: U256) {
+        self.rpc
+            .send_transaction(&TransactionRequest {
+                from: self.client_addr,
+                to: self.wire_addr,
+                value: amount,
+                nonce: None,
+                gas_price: None,
+                data: Hex(vec![]),
+            })
+            .unwrap();
+    }
+
+    pub fn abandon(&mut self) {
+        let pending = self.rpc.pending_transactions().unwrap();
+        for tx in pending
+            .into_iter()
+            .filter(|t| t.from == Some(self.client_addr))
+        {
+            // Replace transaction value with 0
+            self.rpc
+                .send_transaction(&TransactionRequest {
+                    from: self.client_addr,
+                    to: tx.to.unwrap(),
+                    value: U256::zero(),
+                    gas_price: Some(U256::from(110)), // Bigger gas price to 
replace fee
+                    data: Hex(vec![]),
+                    nonce: Some(tx.nonce),
+                })
+                .unwrap();
+        }
+    }
+
+    /* ----- Mining ----- */
+
+    fn _mine(rpc: &mut Rpc, addr: &H160, mut amount: u16, passwd: &str) {
+        rpc.unlock_account(addr, passwd).ok();
+        let mut rpc = rpc.subscribe_new_head().unwrap();
+
+        rpc.miner_start().unwrap();
+        while !rpc.pending_transactions().unwrap().is_empty() {
+            rpc.next().unwrap();
+            amount = amount.saturating_sub(1);
+        }
+        for _ in 0..amount {
+            rpc.next().unwrap();
+        }
+        rpc.miner_stop().unwrap();
+    }
+
+    fn mine(&mut self, nb: u16) {
+        Self::_mine(&mut self.rpc, &self.reserve_addr, nb, &self.passwd)
+    }
+
+    pub fn next_conf(&mut self) {
+        self.mine(self.conf)
+    }
+
+    pub fn next_block(&mut self) {
+        self.mine(1)
+    }
+
+    /* ----- Balances ----- */
+
+    pub fn client_balance(&mut self) -> U256 {
+        self.rpc.get_balance_latest(&self.client_addr).unwrap()
+    }
+
+    pub fn wire_balance(&mut self) -> U256 {
+        self.rpc.get_balance_latest(&self.wire_addr).unwrap()
+    }
+
+    pub fn wire_balance_pending(&mut self) -> U256 {
+        self.rpc.get_balance_pending(&self.wire_addr).unwrap()
+    }
+
+    fn expect_balance(&mut self, balance: U256, mine: bool, lambda: fn(&mut 
Self) -> U256) {
+        retry(|| {
+            let check = balance == lambda(self);
+            if !check && mine {
+                self.next_block();
+            }
+            check
+        });
+    }
+
+    pub fn expect_client_balance(&mut self, balance: U256, mine: bool) {
+        self.expect_balance(balance, mine, Self::client_balance)
+    }
+
+    pub fn expect_wire_balance(&mut self, balance: U256, mine: bool) {
+        self.expect_balance(balance, mine, Self::wire_balance)
+    }
+
+    /* ----- Wire Gateway ----- */
+
+    pub fn expect_credits(&self, txs: &[([u8; 32], U256)]) {
+        let txs: Vec<_> = txs
+            .iter()
+            .map(|(metadata, amount)| (*metadata, eth_to_taler(amount, 
self.state.currency)))
+            .collect();
+        self.common.expect_credits(&txs)
+    }
+
+    pub fn expect_debits(&self, txs: &[([u8; 32], U256)]) {
+        let txs: Vec<_> = txs
+            .iter()
+            .map(|(metadata, amount)| (*metadata, eth_to_taler(amount, 
self.state.currency)))
+            .collect();
+        self.common.expect_debits(&self.state.base_url, &txs)
+    }
+}
+
+pub const TESTS: &[(fn(), &str)] = &[
+    (wire, "eth_wire"),
+    (lifetime, "eth_lifetime"),
+    (reconnect, "eth_reconnect"),
+    (stress, "eth_stress"),
+    (reorg, "eth_reorg"),
+    (hell, "eth_hell"),
+    (analysis, "eth_analysis"),
+    (bumpfee, "eth_bumpfee"),
+    (maxfee, "eth_maxfee"),
+];
+
+/// Test eth-wire correctly receive and send transactions on the blockchain
+fn wire() {
+    println!("Setup");
+    let mut ctx = EthCtx::setup("taler_eth.conf", false);
+
+    println!("Credit");
+    {
+        // Send transactions
+        let mut balance = ctx.wire_balance();
+        let mut txs = Vec::new();
+        for n in 10..100 {
+            let metadata = rand_slice();
+            let amount = ctx.amount(n * 1000);
+            ctx.credit(amount, metadata);
+            txs.push((metadata, amount));
+            balance += amount;
+        }
+        ctx.next_conf();
+        ctx.expect_credits(&txs);
+        ctx.expect_wire_balance(balance, true);
+    };
+
+    println!("Debit");
+    {
+        let mut balance = ctx.client_balance();
+        let mut txs = Vec::new();
+        for n in 10..100 {
+            let metadata = rand_slice();
+            let amount = ctx.amount(n * 100);
+            balance += amount;
+            ctx.debit(amount, metadata);
+            txs.push((metadata, amount));
+        }
+        ctx.next_block();
+        ctx.expect_debits(&txs);
+        ctx.expect_client_balance(balance, true);
+    }
+
+    println!("Bounce");
+    {
+        // Send bad transactions
+        let mut balance = ctx.wire_balance();
+        for n in 10..40 {
+            ctx.malformed_credit(ctx.amount(n * 1000));
+            balance += ctx.state.bounce_fee;
+        }
+        ctx.next_conf();
+        ctx.expect_wire_balance(balance, true);
+    }
+}
+
+/// Test eth-wire and wire-gateway correctly stop when a lifetime limit is 
configured
+fn lifetime() {
+    println!("Setup");
+    let mut ctx = EthCtx::setup("taler_eth_lifetime.conf", false);
+    println!("Check lifetime");
+    // Start up
+    retry(|| ctx.wire_running() && ctx.gateway_running());
+    // Consume lifetime
+    for n in 0..=ctx.taler_conf.wire_lifetime().unwrap() {
+        ctx.credit(ctx.amount(n * 1000), rand_slice());
+        ctx.next_block();
+    }
+    for n in 0..=ctx.taler_conf.http_lifetime().unwrap() {
+        ctx.debit(ctx.amount(n * 1000), rand_slice());
+    }
+    // End down
+    retry(|| !ctx.wire_running() && !ctx.gateway_running());
+}
+
+/// Check the capacity of wire-gateway and eth-wire to recover from database 
and node loss
+fn reconnect() {
+    println!("Setup");
+    let mut ctx = EthCtx::setup("taler_eth.conf", false);
+
+    let mut credits = Vec::new();
+    let mut debits = Vec::new();
+
+    println!("With DB");
+    {
+        let metadata = rand_slice();
+        let amount = ctx.amount(42000);
+        ctx.credit(amount, metadata);
+        credits.push((metadata, amount));
+        ctx.next_block();
+        ctx.next_conf();
+        ctx.expect_credits(&credits);
+    };
+
+    println!("Without DB");
+    {
+        ctx.stop_db();
+        ctx.malformed_credit(ctx.amount(24000));
+        let metadata = rand_slice();
+        let amount = ctx.amount(4000);
+        ctx.credit(amount, metadata);
+        credits.push((metadata, amount));
+        ctx.stop_node();
+        ctx.expect_error();
+    }
+
+    println!("Reconnect DB");
+    {
+        ctx.resume_db();
+        ctx.resume_node(&[]);
+        let metadata = rand_slice();
+        let amount = ctx.amount(2000);
+        ctx.debit(amount, metadata);
+        debits.push((metadata, amount));
+        ctx.next_block();
+        sleep(Duration::from_secs(3));
+        ctx.next_block();
+        sleep(Duration::from_secs(3));
+        ctx.next_block();
+        ctx.expect_debits(&debits);
+        ctx.expect_credits(&credits);
+    }
+
+    println!("Recover DB");
+    {
+        ctx.next_block();
+        sleep(Duration::from_secs(3));
+        ctx.next_block();
+        sleep(Duration::from_secs(3));
+        let balance = ctx.wire_balance();
+        ctx.reset_db();
+        ctx.next_block();
+        ctx.expect_debits(&debits);
+        ctx.expect_credits(&credits);
+        ctx.expect_wire_balance(balance, true);
+    }
+}
+
+/// Test eth-wire ability to recover from errors in correctness critical paths 
and prevent concurrent sending
+fn stress() {
+    println!("Setup");
+    let mut ctx = EthCtx::setup("taler_eth.conf", true);
+
+    let mut credits = Vec::new();
+    let mut debits = Vec::new();
+
+    println!("Credit");
+    {
+        let mut balance = ctx.wire_balance();
+        for n in 10..30 {
+            let metadata = rand_slice();
+            let amount = ctx.amount(n * 1000);
+            ctx.credit(amount, metadata);
+            credits.push((metadata, amount));
+            balance += amount;
+        }
+        ctx.next_conf();
+        ctx.expect_credits(&credits);
+        ctx.expect_wire_balance(balance, true);
+    };
+
+    println!("Debit");
+    {
+        let mut balance = ctx.client_balance();
+        for n in 10..30 {
+            let metadata = rand_slice();
+            let amount = ctx.amount(n * 100);
+            balance += amount;
+            ctx.debit(amount, metadata);
+            debits.push((metadata, amount));
+        }
+        ctx.next_block();
+        ctx.expect_debits(&debits);
+        ctx.expect_client_balance(balance, true);
+    }
+
+    println!("Bounce");
+    {
+        let mut balance = ctx.wire_balance();
+        for n in 10..30 {
+            ctx.malformed_credit(ctx.amount(n * 1000));
+            balance += ctx.state.bounce_fee;
+        }
+        ctx.next_conf();
+        ctx.expect_wire_balance(balance, true);
+    }
+
+    println!("Recover DB");
+    {
+        let balance = ctx.wire_balance();
+        ctx.reset_db();
+        ctx.next_block();
+        ctx.expect_debits(&debits);
+        ctx.expect_credits(&credits);
+        ctx.expect_wire_balance(balance, true);
+    }
+}
+
+/// Test eth-wire correctness when a blockchain reorganization occurs
+fn reorg() {
+    println!("Setup");
+    let mut ctx = EthCtx::setup("taler_eth.conf", false);
+
+    println!("Handle reorg incoming transactions");
+    {
+        // Loose second node
+        ctx.cluster_deco();
+
+        // Perform credits
+        let before = ctx.wire_balance();
+        for n in 10..21 {
+            ctx.credit(ctx.amount(n * 10000), rand_slice());
+        }
+        ctx.next_conf();
+        let after = ctx.wire_balance();
+
+        // Perform fork and check eth-wire hard error
+        ctx.expect_gateway_up();
+        ctx.cluster_fork(10);
+        ctx.expect_wire_balance(before, false);
+        ctx.expect_gateway_down();
+
+        // Recover orphaned transaction
+        ctx.mine(6);
+        ctx.expect_wire_balance(after, false);
+        ctx.expect_gateway_up();
+    }
+
+    println!("Handle reorg outgoing transactions");
+    {
+        // Loose second node
+        ctx.cluster_deco();
+
+        // Perform debits
+        let before = ctx.client_balance();
+        let mut after = ctx.client_balance();
+        for n in 10..21 {
+            let amount = ctx.amount(n * 100);
+            ctx.debit(amount, rand_slice());
+            after += amount;
+        }
+        ctx.next_block();
+        ctx.expect_client_balance(after, true);
+
+        // Perform fork and check eth-wire still up
+        ctx.expect_gateway_up();
+        ctx.cluster_fork(10);
+        ctx.expect_client_balance(before, false);
+        ctx.expect_gateway_up();
+
+        // Recover orphaned transaction
+        ctx.next_conf();
+        ctx.expect_client_balance(after, false);
+    }
+
+    println!("Handle reorg bounce");
+    {
+        // Loose second node
+        ctx.cluster_deco();
+
+        // Perform bounce
+        let before = ctx.wire_balance();
+        let mut after = ctx.wire_balance();
+        for n in 10..21 {
+            ctx.malformed_credit(ctx.amount(n * 1000));
+            after += ctx.state.bounce_fee;
+        }
+        ctx.next_conf();
+        ctx.expect_wire_balance(after, true);
+
+        // Perform fork and check eth-wire hard error
+        ctx.expect_gateway_up();
+        ctx.cluster_fork(10);
+        ctx.expect_wire_balance(before, false);
+        ctx.expect_gateway_down();
+
+        // Recover orphaned transaction
+        ctx.mine(10);
+        sleep(Duration::from_secs(3));
+        ctx.next_block();
+        ctx.expect_wire_balance(after, false);
+        ctx.expect_gateway_up();
+    }
+}
+
+/// Test eth-wire correctness when a blockchain reorganization occurs leading 
to past incoming transaction conflict
+fn hell() {
+    fn step(name: &str, action: impl FnOnce(&mut EthCtx)) {
+        println!("Setup");
+        let mut ctx = EthCtx::setup("taler_eth.conf", false);
+        println!("{}", name);
+
+        // Loose second node
+        ctx.cluster_deco();
+
+        // Perform action
+        action(&mut ctx);
+
+        // Perform fork and check eth-wire hard error
+        ctx.expect_gateway_up();
+        ctx.cluster_fork(ctx.conf * 2);
+        ctx.expect_gateway_down();
+
+        // Generate conflict
+        ctx.restart_node(&["--miner.gasprice", "1000"]);
+        ctx.abandon();
+        let amount = ctx.amount(54000);
+        ctx.credit(amount, rand_slice());
+        ctx.expect_wire_balance(amount, true);
+
+        // Check eth-wire suspend operation
+        let bounce_amount = ctx.amount(34000);
+        ctx.malformed_credit(bounce_amount);
+        ctx.next_conf();
+        ctx.expect_wire_balance(amount + bounce_amount, true);
+        ctx.expect_gateway_down();
+    }
+
+    step("Handle reorg conflicting incoming credit", |ctx| {
+        let amount = ctx.amount(420000);
+        ctx.credit(amount, rand_slice());
+        ctx.next_conf();
+        ctx.expect_wire_balance(amount, true);
+    });
+
+    step("Handle reorg conflicting incoming bounce", |ctx| {
+        let amount = ctx.amount(420000);
+        ctx.malformed_credit(amount);
+        ctx.next_conf();
+        retry(|| ctx.wire_balance_pending() == ctx.state.bounce_fee);
+    });
+}
+
+/// Test eth-wire ability to learn and protect itself from blockchain behavior
+fn analysis() {
+    println!("Setup");
+    let mut ctx = EthCtx::setup("taler_eth.conf", false);
+
+    println!("Learn from reorg");
+
+    // Loose second node
+    ctx.cluster_deco();
+
+    // Perform credit
+    let before = ctx.wire_balance();
+    ctx.credit(ctx.amount(42000), rand_slice());
+    ctx.next_conf();
+    let after = ctx.wire_balance();
+
+    // Perform fork and check eth-wire hard error
+    ctx.expect_gateway_up();
+    ctx.cluster_fork(6);
+    ctx.expect_wire_balance(before, false);
+    ctx.expect_gateway_down();
+
+    // Recover orphaned transaction
+    ctx.mine(6);
+    ctx.expect_wire_balance(after, false);
+    ctx.expect_gateway_up();
+
+    // Loose second node
+    ctx.cluster_deco();
+
+    // Perform credit
+    let before = ctx.wire_balance();
+    ctx.credit(ctx.amount(42000), rand_slice());
+    ctx.next_conf();
+
+    // Perform fork and check eth-wire learned from previous attack
+    ctx.expect_gateway_up();
+    ctx.cluster_fork(5);
+    ctx.expect_wire_balance(before, false);
+    ctx.expect_gateway_up();
+}
+
+/// Test eth-wire ability to handle stuck transaction correctly
+fn bumpfee() {
+    println!("Setup");
+    let mut ctx = EthCtx::setup("taler_eth_bump.conf", false);
+
+    // Perform credits to allow wire to perform debits latter
+    ctx.credit(ctx.amount(90000000), rand_slice());
+    ctx.next_conf();
+
+    println!("Bump fee");
+    {
+        // Perform debit
+        let mut client = ctx.client_balance();
+        let wire = ctx.wire_balance();
+        let amount = ctx.amount(40000);
+        ctx.debit(amount, rand_slice());
+        retry(|| ctx.wire_balance_pending() < wire);
+
+        // Bump min relay fee making the previous debit stuck
+        ctx.restart_node(&["--miner.gasprice", "1000"]);
+
+        // Check bump happen
+        client += amount;
+        ctx.expect_client_balance(client, true);
+    }
+
+    println!("Bump fee reorg");
+    {
+        // Loose second node
+        ctx.cluster_deco();
+
+        // Perform debit
+        let mut client = ctx.client_balance();
+        let wire = ctx.wire_balance();
+        let amount = ctx.amount(40000);
+        ctx.debit(amount, rand_slice());
+        retry(|| ctx.wire_balance_pending() < wire);
+
+        // Bump min relay fee and fork making the previous debit stuck and 
problematic
+        ctx.cluster_fork(6);
+        ctx.restart_node(&["--miner.gasprice", "2000"]);
+
+        // Check bump happen
+        client += amount;
+        ctx.expect_client_balance(client, true);
+    }
+
+    println!("Setup");
+    drop(ctx);
+    let mut ctx = EthCtx::setup("taler_eth_bump.conf", true);
+
+    // Perform credit to allow wire to perform debits latter
+    ctx.credit(ctx.amount(9000000), rand_slice());
+    ctx.next_conf();
+
+    println!("Bump fee stress");
+    {
+        // Loose second node
+        ctx.cluster_deco();
+
+        // Perform debits
+        let client = ctx.client_balance();
+        let wire = ctx.wire_balance();
+        let mut total_amount = U256::zero();
+        for n in 10..31 {
+            let amount = ctx.amount(n * 10000);
+            total_amount += amount;
+            ctx.debit(amount, rand_slice());
+        }
+        retry(|| ctx.wire_balance_pending() < wire - total_amount);
+
+        // Bump min relay fee making the previous debits stuck
+        ctx.restart_node(&["--miner.gasprice", "1000"]);
+
+        // Check bump happen
+        ctx.expect_client_balance(client + total_amount, true);
+    }
+}
+
+/// Test eth-wire handle transaction fees exceeding limits
+fn maxfee() {
+    println!("Setup");
+    let mut ctx = EthCtx::setup("taler_eth.conf", false);
+
+    // Perform credit to allow wire to perform debits latter
+    ctx.credit(ctx.amount(9000000), rand_slice());
+    ctx.next_conf();
+
+    let client = ctx.client_balance();
+    let wire = ctx.wire_balance();
+    let mut total_amount = U256::zero();
+
+    println!("Too high fee");
+    {
+        // Change fee config
+        ctx.restart_node(&["--rpc.txfeecap", "0.00001"]);
+
+        // Perform debits
+        for n in 10..31 {
+            let amount = ctx.amount(n * 10000);
+            total_amount += amount;
+            ctx.debit(amount, rand_slice());
+        }
+        sleep(Duration::from_secs(3));
+
+        // Check no transaction happen
+        ctx.expect_wire_balance(wire, true);
+        ctx.expect_client_balance(client, true);
+    }
+
+    println!("Good feed");
+    {
+        // Restore default config
+        ctx.restart_node(&[""]);
+
+        // Check transaction now have been made
+        ctx.expect_client_balance(client + total_amount, true);
+    }
 }
diff --git a/instrumentation/src/gateway.rs b/instrumentation/src/gateway.rs
new file mode 100644
index 0000000..6a3f5c9
--- /dev/null
+++ b/instrumentation/src/gateway.rs
@@ -0,0 +1,244 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2022 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+
+use std::str::FromStr;
+
+use btc_wire::taler_utils::btc_payto_url;
+use common::{
+    api_common::{Amount as TalerAmount, Base32},
+    api_wire::TransferRequest,
+    rand_slice,
+    url::Url,
+};
+use libdeflater::{CompressionLvl, Compressor};
+use ureq::Response;
+
+use crate::{
+    btc::BtcCtx,
+    utils::{cmd_out, cmd_redirect_ok, gateway_error},
+};
+
+pub const TESTS: &[(fn(), &str)] = &[(api, "api"), (auth, "auth")];
+
+fn client_transfer(gateway_url: &str, payto_url: &str, amount: &str) -> String 
{
+    cmd_out(
+        "taler-exchange-wire-gateway-client",
+        &["-b", gateway_url, "-C", payto_url, "-a", amount],
+    )
+}
+
+fn http_code(response: Result<Response, ureq::Error>) -> u16 {
+    match response {
+        Ok(resp) => resp.status(),
+        Err(err) => match err {
+            ureq::Error::Status(err, _) => err,
+            ureq::Error::Transport(_) => unreachable!(),
+        },
+    }
+}
+
+/// Test wire-gateway conformance to documentation and its security
+fn api() {
+    println!("Setup");
+    let ctx = BtcCtx::setup("taler_btc.conf", false);
+
+    println!("Gateway API");
+    {
+        // Perform debits
+        let mut amounts = Vec::new();
+        for n in 1..10 {
+            let amount = format!("{}:0.000{}", 
ctx.taler_conf.currency.to_str(), n);
+            cmd_out(
+                "taler-exchange-wire-gateway-client",
+                &[
+                    "-b",
+                    &ctx.gateway_url,
+                    "-D",
+                    &btc_payto_url(&ctx.client_addr).to_string(),
+                    "-a",
+                    &amount,
+                ],
+            );
+            amounts.push(amount);
+        }
+
+        // Check history
+        let result = cmd_out(
+            "taler-exchange-wire-gateway-client",
+            &["-b", &ctx.gateway_url, "-i"],
+        );
+        for amount in &amounts {
+            assert!(result.contains(amount));
+        }
+
+        // Perform credits
+        let mut amounts = Vec::new();
+        for n in 1..10 {
+            let amount = format!("{}:0.0000{}", 
ctx.taler_conf.currency.to_str(), n);
+            client_transfer(
+                &ctx.gateway_url,
+                &btc_payto_url(&ctx.client_addr).to_string(),
+                &amount,
+            );
+            amounts.push(amount);
+        }
+
+        // Check history
+        let result = cmd_out(
+            "taler-exchange-wire-gateway-client",
+            &["-b", &ctx.gateway_url, "-o"],
+        );
+        for amount in &amounts {
+            assert!(result.contains(amount));
+        }
+    };
+
+    println!("Endpoint & Method");
+    {
+        // Unknown endpoint
+        gateway_error(&format!("{}test", ctx.gateway_url), 404);
+        // Method not allowed
+        gateway_error(&format!("{}transfer", ctx.gateway_url), 405);
+    }
+
+    let amount = &format!("{}:0.00042", ctx.taler_conf.currency.to_str());
+    let payto = btc_payto_url(&ctx.client_addr).to_string();
+
+    println!("Request format");
+    {
+        // Bad payto_url
+        for url in [
+            "http://bitcoin/$CLIENT";,
+            "payto://btc/$CLIENT",
+            "payto://bitcoin/$CLIENT?id=admin",
+            "payto://bitcoin/$CLIENT#admin",
+            "payto://bitcoin/42$CLIENT",
+        ] {
+            let url = url.replace("$CLIENT", &ctx.client_addr.to_string());
+            let result = client_transfer(&ctx.gateway_url, &url, amount);
+            assert!(result.contains("(400/24)"));
+        }
+
+        // Bad transaction amount
+        let result = client_transfer(&ctx.gateway_url, &payto, "ATC:0.00042");
+        assert!(result.contains("(400/26)"));
+
+        // Bad history delta
+        for delta in [
+            "incoming",
+            "outgoing",
+            "incoming?delta=0",
+            "outgoing?delta=0;",
+        ] {
+            let code =
+                http_code(ureq::get(&format!("{}history/{}", ctx.gateway_url, 
delta)).call());
+            assert_eq!(code, 400);
+        }
+    }
+
+    println!("Transfer idempotence");
+    {
+        let mut request = TransferRequest {
+            request_uid: Base32::from(rand_slice()),
+            amount: TalerAmount::from_str(amount).unwrap(),
+            exchange_base_url: ctx.taler_conf.base_url(),
+            wtid: Base32::from(rand_slice()),
+            credit_account: Url::from_str(&payto).unwrap(),
+        };
+        // Same
+        assert_eq!(
+            http_code(ureq::post(&format!("{}transfer", 
ctx.gateway_url)).send_json(&request)),
+            200
+        );
+        assert_eq!(
+            http_code(ureq::post(&format!("{}transfer", 
ctx.gateway_url)).send_json(&request)),
+            200
+        );
+        // Collision
+        request.amount.fraction += 42;
+        assert_eq!(
+            http_code(ureq::post(&format!("{}transfer", 
ctx.gateway_url)).send_json(&request)),
+            409
+        );
+    }
+
+    println!("Security");
+    {
+        let big_hello: String = (0..1000).map(|_| "Hello_world").collect();
+        // Huge body
+        assert_eq!(
+            http_code(ureq::post(&format!("{}transfer", 
ctx.gateway_url)).send_json(&big_hello)),
+            400
+        );
+
+        // Body length liar
+        assert_eq!(
+            http_code(
+                ureq::post(&format!("{}transfer", ctx.gateway_url))
+                    .set("Content-Length", "1024")
+                    .send_json(&big_hello)
+            ),
+            400
+        );
+
+        // Compression bomb
+        let mut compressor = Compressor::new(CompressionLvl::best());
+        let mut compressed = Vec::new();
+        compressed.resize(compressor.deflate_compress_bound(big_hello.len()), 
0);
+        let size = compressor
+            .deflate_compress(big_hello.as_bytes(), &mut compressed)
+            .unwrap();
+        compressed.resize(size, 0);
+        assert_eq!(
+            http_code(
+                ureq::post(&format!("{}transfer", ctx.gateway_url))
+                    .set("Content-Encoding", "deflate")
+                    .send_bytes(&compressed)
+            ),
+            400
+        );
+    }
+}
+
+/// Check btc-wire and wire-gateway correctly stop when a lifetime limit is 
configured
+fn auth() {
+    println!("Setup");
+    let ctx = BtcCtx::setup("taler_btc_auth.conf", false);
+
+    println!("Authentication");
+    // No auth
+    assert_eq!(
+        http_code(ureq::get(&format!("{}history.outgoing", 
ctx.gateway_url)).call()),
+        401
+    );
+
+    // Auth
+    cmd_redirect_ok(
+        "taler-exchange-wire-gateway-client",
+        &[
+            "--config",
+            ctx.dirs.conf.to_str().unwrap(),
+            "-s",
+            "exchange-accountcredentials-admin",
+            "-C",
+            &btc_payto_url(&ctx.client_addr).to_string(),
+            "-a",
+            &format!("{}:0.00042", ctx.taler_conf.currency.to_str()),
+        ],
+        "log/client.log",
+        "",
+    );
+}
diff --git a/instrumentation/src/main.rs b/instrumentation/src/main.rs
index cc79f9c..6d425f5 100644
--- a/instrumentation/src/main.rs
+++ b/instrumentation/src/main.rs
@@ -14,92 +14,71 @@
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 
-use std::{fmt::Display, io::Write, path::PathBuf};
+use std::{path::PathBuf, time::Instant};
 
 use btc::btc_test;
 use clap::StructOpt;
-use common::{
-    api_common::{Amount, Base32},
-    api_wire::{IncomingBankTransaction, IncomingHistory, OutgoingHistory, 
TransferRequest},
-    config::TalerConfig,
-    currency::Currency,
-    rand_slice,
-    url::Url,
-};
+use common::{config::TalerConfig, currency::Currency};
 use eth::eth_test;
+use owo_colors::OwoColorize;
 
 mod btc;
 mod eth;
-
-fn print_now(disp: impl Display) {
-    print!("{}", disp);
-    std::io::stdout().flush().unwrap();
-}
-
-fn check_incoming(base_url: &str, reserve_pub_key: &[u8; 32], taler_amount: 
&Amount) {
-    println!("Check incoming history");
-    let history: IncomingHistory = ureq::get(&format!("{}/history/incoming", 
base_url))
-        .query("delta", "-5")
-        .call()
-        .unwrap()
-        .into_json()
-        .unwrap();
-    assert!(history.incoming_transactions.iter().any(|h| {
-        matches!(
-            h,
-            IncomingBankTransaction::IncomingReserveTransaction {
-                reserve_pub,
-                amount,
-                ..
-            } if reserve_pub == &Base32::from(*reserve_pub_key) && amount == 
taler_amount
-        )
-    }));
-}
-
-fn transfer(base_url: &str, wtid: &[u8; 32], url: &Url, credit_account: Url, 
amount: &Amount) {
-    println!("Get back some money");
-    ureq::post(&format!("{}/transfer", base_url))
-        .send_json(TransferRequest {
-            request_uid: Base32::from(rand_slice()),
-            amount: amount.clone(),
-            exchange_base_url: url.clone(),
-            wtid: Base32::from(*wtid),
-            credit_account,
-        })
-        .unwrap();
-}
-
-fn check_outgoing(base_url: &str, wtid: &[u8; 32], url: &Url, amount: &Amount) 
{
-    println!("Check outgoing history");
-    let history: OutgoingHistory = ureq::get(&format!("{}/history/outgoing", 
base_url))
-        .query("delta", "-5")
-        .call()
-        .unwrap()
-        .into_json()
-        .unwrap();
-    assert!(history.outgoing_transactions.iter().any(|h| {
-        h.wtid == Base32::from(*wtid) && &h.exchange_base_url == url && 
&h.amount == amount
-    }));
-}
+mod gateway;
+mod utils;
 
 /// Depolymerizer instrumentation test
 #[derive(clap::Parser, Debug)]
 struct Args {
-    /// Override default configuration file path
-    #[clap(global = true, short, long)]
-    config: Option<PathBuf>,
+    #[clap(subcommand)]
+    cmd: Cmd,
+}
+
+#[derive(clap::Subcommand, Debug)]
+enum Cmd {
+    /// Perform online tests on running blockchain
+    Online {
+        /// Override default configuration file path
+        #[clap(global = true, short, long)]
+        config: Option<PathBuf>,
+    },
+    /// Perform offline tests on local private blockchain
+    Offline,
 }
 
 pub fn main() {
     common::log::init();
+    color_backtrace::install();
+
     let args = Args::parse();
-    let taler_config = TalerConfig::load(args.config.as_deref());
-    let base_url = format!("http://localhost:{}";, taler_config.port());
+    match args.cmd {
+        Cmd::Online { config } => {
+            let taler_config = TalerConfig::load(config.as_deref());
+            let base_url = format!("http://localhost:{}";, taler_config.port());
 
-    match taler_config.currency {
-        Currency::BTC(_) => btc_test(args.config.as_deref(), &base_url),
-        Currency::ETH(_) => eth_test(args.config.as_deref(), &base_url),
+            match taler_config.currency {
+                Currency::BTC(_) => btc_test(config.as_deref(), &base_url),
+                Currency::ETH(_) => eth_test(config.as_deref(), &base_url),
+            }
+            println!("Instrumentation test successful");
+        }
+        Cmd::Offline => {
+            let mut tests = Vec::new();
+            tests.extend_from_slice(gateway::TESTS);
+            tests.extend_from_slice(btc::TESTS);
+            tests.extend_from_slice(eth::TESTS);
+            let start = Instant::now();
+            for (test, name) in &tests {
+                let start = Instant::now();
+                println!("{}", name.magenta());
+                test();
+                println!(
+                    "{} {}",
+                    "OK".green(),
+                    format_args!("{:?}", start.elapsed()).bright_black()
+                );
+            }
+            println!("{} tests in {:?}", tests.len(), start.elapsed());
+        }
     }
-
-    println!("Instrumentation test successful");
 }
diff --git a/instrumentation/src/utils.rs b/instrumentation/src/utils.rs
new file mode 100644
index 0000000..f89abb0
--- /dev/null
+++ b/instrumentation/src/utils.rs
@@ -0,0 +1,444 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2022 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+
+use std::{
+    fmt::Display,
+    fmt::Write as _,
+    io::Write as _,
+    path::{Path, PathBuf},
+    process::{Child, Command, Stdio},
+    str::FromStr,
+    thread::sleep,
+    time::{Duration, Instant},
+};
+
+use common::{
+    api_common::{Amount, Base32},
+    api_wire::{IncomingBankTransaction, IncomingHistory, OutgoingHistory, 
TransferRequest},
+    config::TalerConfig,
+    rand_slice,
+    url::Url,
+};
+use tempfile::TempDir;
+
+pub fn print_now(disp: impl Display) {
+    print!("{}", disp);
+    std::io::stdout().flush().unwrap();
+}
+
+#[must_use]
+pub fn check_incoming(base_url: &str, txs: &[([u8; 32], Amount)]) -> bool {
+    let history: IncomingHistory = ureq::get(&format!("{}history/incoming", 
base_url))
+        .query("delta", &format!("-{}", txs.len()))
+        .call()
+        .unwrap()
+        .into_json()
+        .unwrap();
+
+    history.incoming_transactions.len() == txs.len()
+        && txs.iter().all(|(reserve_pub_key, taler_amount)| {
+            history.incoming_transactions.iter().any(|h| {
+                matches!(
+                    h,
+                    IncomingBankTransaction::IncomingReserveTransaction {
+                        reserve_pub,
+                        amount,
+                        ..
+                    } if reserve_pub == &Base32::from(*reserve_pub_key) && 
amount == taler_amount
+                )
+            })
+        })
+}
+
+pub fn gateway_error(path: &str, error: u16) {
+    let err = ureq::get(path).call().unwrap_err();
+    match err {
+        ureq::Error::Status(nb, _) => assert_eq!(nb, error),
+        ureq::Error::Transport(_) => unreachable!(),
+    }
+}
+
+#[must_use]
+pub fn check_gateway_error(base_url: &str) -> bool {
+    matches!(
+        ureq::get(&format!("{}history/incoming", base_url))
+            .query("delta", "-5")
+            .call(),
+        Err(ureq::Error::Status(504, _))
+    )
+}
+
+#[must_use]
+pub fn check_gateway_down(base_url: &str) -> bool {
+    matches!(
+        ureq::get(&format!("{}history/incoming", base_url))
+            .query("delta", "-5")
+            .call(),
+        Err(ureq::Error::Status(502, _))
+    )
+}
+
+#[must_use]
+pub fn check_gateway_up(base_url: &str) -> bool {
+    ureq::get(&format!("{}history/incoming", base_url))
+        .query("delta", "-5")
+        .call()
+        .is_ok()
+}
+
+pub fn transfer(base_url: &str, wtid: &[u8; 32], url: &Url, credit_account: 
Url, amount: &Amount) {
+    ureq::post(&format!("{}transfer", base_url))
+        .send_json(TransferRequest {
+            request_uid: Base32::from(rand_slice()),
+            amount: amount.clone(),
+            exchange_base_url: url.clone(),
+            wtid: Base32::from(*wtid),
+            credit_account,
+        })
+        .unwrap();
+}
+
+#[must_use]
+pub fn check_outgoing(base_url: &str, url: &Url, txs: &[([u8; 32], Amount)]) 
-> bool {
+    let history: OutgoingHistory = ureq::get(&format!("{}history/outgoing", 
base_url))
+        .query("delta", &format!("-{}", txs.len()))
+        .call()
+        .unwrap()
+        .into_json()
+        .unwrap();
+    history.outgoing_transactions.len() == txs.len()
+        && txs.iter().all(|(wtid, amount)| {
+            history.outgoing_transactions.iter().any(|h| {
+                h.wtid == Base32::from(*wtid) && &h.exchange_base_url == url 
&& &h.amount == amount
+            })
+        })
+}
+
+pub struct Dirs {
+    pub dir: TempDir,
+    pub wire_dir: PathBuf,
+    pub wire_dir2: PathBuf,
+    pub db_dir: PathBuf,
+    pub conf: PathBuf,
+}
+
+impl Dirs {
+    pub fn generate() -> Self {
+        let dir = TempDir::new().unwrap();
+        let wire_dir = dir.path().join("wire");
+        let wire_dir2 = dir.path().join("wire2");
+        let db_dir = dir.path().join("db");
+        for dir in [&wire_dir, &wire_dir2, &db_dir] {
+            std::fs::create_dir_all(dir).unwrap();
+        }
+        let conf = dir.path().join("taler.conf");
+        Self {
+            wire_dir,
+            wire_dir2,
+            db_dir,
+            conf,
+            dir,
+        }
+    }
+}
+
+pub struct ChildGuard(pub Child);
+
+impl Drop for ChildGuard {
+    fn drop(&mut self) {
+        self.0.kill().ok();
+    }
+}
+
+pub fn cmd_out(cmd: &str, args: &[&str]) -> String {
+    let output = Command::new(cmd)
+        .args(args)
+        .stdin(Stdio::null())
+        .output()
+        .unwrap();
+    if output.stdout.is_empty() {
+        String::from_utf8(output.stderr).unwrap()
+    } else {
+        String::from_utf8(output.stdout).unwrap()
+    }
+}
+
+pub fn try_cmd_redirect(cmd: &str, args: &[&str], path: &str) -> 
std::io::Result<ChildGuard> {
+    let log_file = std::fs::OpenOptions::new()
+        .create(true)
+        .append(true)
+        .open(path)?;
+
+    let child = Command::new(cmd)
+        .args(args)
+        .stderr(log_file.try_clone()?)
+        .stdout(log_file)
+        .stdin(Stdio::null())
+        .spawn()?;
+    Ok(ChildGuard(child))
+}
+
+pub fn cmd_redirect(cmd: &str, args: &[&str], path: &str) -> ChildGuard {
+    try_cmd_redirect(cmd, args, path).unwrap()
+}
+
+pub fn cmd_ok(mut child: ChildGuard, name: &str) {
+    let result = child.0.wait().unwrap();
+    if !result.success() {
+        panic!("cmd {name} failed");
+    }
+}
+
+pub fn cmd_redirect_ok(cmd: &str, args: &[&str], path: &str, name: &str) {
+    cmd_ok(cmd_redirect(cmd, args, path), name)
+}
+
+pub fn retry_opt<T>(mut lambda: impl FnMut() -> Option<T>) -> T {
+    let start = Instant::now();
+    loop {
+        let result = lambda();
+        if result.is_none() && start.elapsed() < Duration::from_secs(20) {
+            sleep(Duration::from_millis(500));
+        } else {
+            return result.unwrap();
+        }
+    }
+}
+
+pub fn retry(mut lambda: impl FnMut() -> bool) {
+    retry_opt(|| lambda().then(|| ()))
+}
+
+pub struct CommonCtx {
+    pub dirs: Dirs,
+    gateway: ChildGuard,
+    pub gateway_url: String,
+    pub taler_conf: TalerConfig,
+    wire: ChildGuard,
+    _wire2: Option<ChildGuard>,
+}
+
+impl CommonCtx {
+    pub fn setup_dirs(config: &str) -> Dirs {
+        // Setup logs
+        {
+            // Create log dir if no exist
+            std::fs::create_dir_all("log").unwrap();
+            // Clear all previous logs file
+            for file in std::fs::read_dir("log").unwrap() {
+                std::fs::write(file.unwrap().path(), "").unwrap();
+            }
+        }
+        // Generate temporary dirs
+        let dirs = Dirs::generate();
+        // Prepare config
+        {
+            // Generate taler config from base
+            let config = PathBuf::from_str("instrumentation/conf")
+                .unwrap()
+                .join(config);
+            let mut config = std::fs::read_to_string(config).unwrap();
+            write!(
+                &mut config,
+                "\nCONF_PATH = {}\nIPC_PATH={}",
+                dirs.wire_dir.to_string_lossy(),
+                dirs.wire_dir.to_string_lossy()
+            )
+            .unwrap();
+            std::fs::write(&dirs.conf, config).unwrap();
+        }
+
+        // Generate password
+        let pwd: String = (0..30).map(|_| fastrand::alphanumeric()).collect();
+        std::env::set_var("PASSWORD", &pwd);
+
+        dirs
+    }
+
+    pub fn setup(dirs: Dirs, name: &str, stressed: bool, init_wallet: impl 
FnOnce(&Dirs)) -> Self {
+        let taler_conf = TalerConfig::load(Some(&dirs.conf));
+        // Setup database
+        {
+            // Init databases files
+            cmd_redirect_ok(
+                "pg_ctl",
+                &["init", "-D", dirs.db_dir.to_string_lossy().as_ref()],
+                "log/postgres.log",
+                "init_db",
+            );
+            // Generate database config
+            std::fs::write(
+                dirs.db_dir.join("postgresql.conf"),
+                format!(
+                    "port=5454\nunix_socket_directories='{}'\n",
+                    dirs.db_dir.to_string_lossy().as_ref()
+                ),
+            )
+            .unwrap();
+            Self::_start_db(&dirs.db_dir);
+
+            let mut psql = ChildGuard(
+                Command::new("psql")
+                    .args(["-h", "localhost", "-p", "5454", "postgres"])
+                    .stderr(Stdio::null())
+                    .stdout(Stdio::null())
+                    .stdin(Stdio::piped())
+                    .spawn()
+                    .unwrap(),
+            );
+            psql.0
+                .stdin
+                .as_mut()
+                .unwrap()
+                .write_all("CREATE ROLE postgres LOGIN SUPERUSER PASSWORD 
'password'".as_bytes())
+                .unwrap();
+            cmd_ok(psql, "psql setup");
+        }
+
+        // Wire
+        let wire_path = format!("target/release/{}", name);
+        let mut args = vec!["build", "--bin", name, "--release"];
+        if stressed {
+            args.extend_from_slice(&["--features", "fail"]);
+        }
+        cmd_redirect_ok("cargo", &args, "log/cargo.log", "build wire");
+        cmd_redirect_ok(
+            &wire_path,
+            &["-c", dirs.conf.to_string_lossy().as_ref(), "initdb"],
+            "log/cmd.log",
+            "wire initdb",
+        );
+
+        init_wallet(&dirs);
+
+        // Start wires
+        let wire = cmd_redirect(
+            &wire_path,
+            &["-c", dirs.conf.to_string_lossy().as_ref()],
+            "log/wire.log",
+        );
+        let wire2 = stressed.then(|| {
+            cmd_redirect(
+                &wire_path,
+                &["-c", dirs.conf.to_string_lossy().as_ref()],
+                "log/wire2.log",
+            )
+        });
+
+        // Gateway
+        cmd_redirect_ok(
+            "cargo",
+            &[
+                "build",
+                "--bin",
+                "wire-gateway",
+                "--release",
+                "--features",
+                "test",
+            ],
+            "log/cargo.log",
+            "build gateway",
+        );
+        let gateway = cmd_redirect(
+            "target/release/wire-gateway",
+            &["-c", dirs.conf.to_string_lossy().as_ref()],
+            "log/gateway.log",
+        );
+
+        let gateway_url = format!("http://localhost:{}/";, taler_conf.port());
+
+        Self {
+            dirs,
+            gateway,
+            gateway_url,
+            taler_conf,
+            wire,
+            _wire2: wire2,
+        }
+    }
+
+    /* ----- Process ----- */
+
+    #[must_use]
+    pub fn wire_running(&mut self) -> bool {
+        self.wire.0.try_wait().unwrap().is_none()
+    }
+
+    #[must_use]
+    pub fn gateway_running(&mut self) -> bool {
+        self.gateway.0.try_wait().unwrap().is_none()
+    }
+
+    /* ----- Database ----- */
+
+    fn _start_db(path: &Path) {
+        cmd_redirect_ok(
+            "pg_ctl",
+            &["start", "-D", path.to_string_lossy().as_ref()],
+            "log/postgres.log",
+            "start db",
+        )
+    }
+
+    fn _stop_db(path: &Path, log: &Path) -> std::io::Result<ChildGuard> {
+        try_cmd_redirect(
+            "pg_ctl",
+            &["stop", "-D", path.to_string_lossy().as_ref()],
+            log.to_string_lossy().as_ref(),
+        )
+    }
+
+    pub fn resume_db(&self) {
+        Self::_start_db(&self.dirs.db_dir)
+    }
+
+    pub fn stop_db(&self) {
+        cmd_ok(
+            Self::_stop_db(&self.dirs.db_dir, 
"log/postgres.log".as_ref()).unwrap(),
+            "stop db",
+        )
+    }
+
+    /* ----- Wire Gateway -----*/
+
+    pub fn expect_credits(&self, txs: &[([u8; 32], Amount)]) {
+        retry(|| check_incoming(&self.gateway_url, txs))
+    }
+
+    pub fn expect_debits(&self, base_url: &Url, txs: &[([u8; 32], Amount)]) {
+        retry(|| check_outgoing(&self.gateway_url, base_url, txs))
+    }
+
+    pub fn expect_error(&self) {
+        retry(|| check_gateway_error(&self.gateway_url));
+    }
+
+    pub fn expect_gateway_up(&self) {
+        retry(|| check_gateway_up(&self.gateway_url));
+    }
+
+    pub fn expect_gateway_down(&self) {
+        retry(|| check_gateway_down(&self.gateway_url));
+    }
+}
+
+impl Drop for CommonCtx {
+    fn drop(&mut self) {
+        Self::_stop_db(&self.dirs.db_dir, "/dev/null".as_ref())
+            .and_then(|mut it| it.0.wait())
+            .ok();
+    }
+}
diff --git a/makefile b/makefile
index 28a8316..ebf54d6 100644
--- a/makefile
+++ b/makefile
@@ -3,40 +3,5 @@ install:
        cargo install --path eth-wire --bin eth-wire
        cargo install --path wire-gateway
 
-install_test: install
-       cargo install --path btc-wire --bin btc-wire-utils
-       cargo install --path eth-wire --bin eth-wire-utils
-       cargo install --path instrumentation
-
-test_gateway: install_test
-       test/gateway/api.sh
-       test/gateway/auth.sh
-
-test_btc: install_test
-       test/btc/wire.sh
-       test/btc/lifetime.sh
-       test/btc/reconnect.sh
-       test/btc/stress.sh
-       test/btc/conflict.sh
-       test/btc/reorg.sh
-       test/btc/hell.sh
-       test/btc/analysis.sh
-       test/btc/bumpfee.sh
-       test/btc/maxfee.sh
-       test/btc/config.sh
-
-test_eth: install_test
-       test/eth/wire.sh
-       test/eth/lifetime.sh
-       test/eth/reconnect.sh
-       test/eth/stress.sh
-       test/eth/reorg.sh
-       test/eth/hell.sh
-       test/eth/analysis.sh
-       test/eth/bumpfee.sh
-       test/eth/maxfee.sh
-
-test: test_gateway test_eth test_btc
-
 segwit_demo: 
        cargo run --release --bin segwit-demo
\ No newline at end of file
diff --git a/script/prepare.sh b/script/prepare.sh
old mode 100644
new mode 100755
index fec69dd..a926db4
--- a/script/prepare.sh
+++ b/script/prepare.sh
@@ -20,21 +20,21 @@ 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"
+echo "â…¡ - Install bitcoind version 0.23"
 cd $DIR
-curl -L 
https://bitcoin.org/bin/bitcoin-core-22.0/bitcoin-22.0-x86_64-linux-gnu.tar.gz 
-o btc.tar.gz
+curl -L 
https://bitcoincore.org/bin/bitcoin-core-23.0/bitcoin-23.0-x86_64-linux-gnu.tar.gz
 -o btc.tar.gz
 rm -rfv ~/bitcoin
 mkdir -pv ~/bitcoin
 tar xvzf btc.tar.gz
-mv -v bitcoin-22.0/* ~/bitcoin
+mv -v bitcoin-23.0/* ~/bitcoin
 
-echo "â…¢ - Install Go Ethereum (Geth) v1.10.16"
+echo "â…¢ - Install Go Ethereum (Geth) v1.10.20"
 cd $DIR
-curl -L 
https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.10.16-20356e57.tar.gz
 -o geth.tar.gz
+curl -L 
https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.10.20-8f2416a8.tar.gz
 -o geth.tar.gz
 rm -rfv ~/geth
 mkdir -pv ~/geth
 tar xvzf geth.tar.gz
-mv -v geth-alltools-linux-amd64-1.10.16-20356e57/* ~/geth
+mv -v geth-alltools-linux-amd64-1.10.20-8f2416a8/* ~/geth
 
 echo "â…£ - PATH"
 
diff --git a/test/btc/analysis.sh b/test/btc/analysis.sh
deleted file mode 100755
index e340e4e..0000000
--- a/test/btc/analysis.sh
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/bin/bash
-
-## Test btc-wire ability to learn and protect itself from blockchain behavior
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start second bitcoin node"
-init_btc2
-echo "Start btc-wire"
-btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-echo "----- Learn from reorg -----"
-
-echo "Loose second bitcoin node"
-btc_deco
-
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS transfer 0.042 > /dev/null
-next_btc # Trigger btc-wire
-check_balance 9.95799209 0.04200000
-echo " OK"
-
-echo -n "Perform fork and check btc-wire hard error:"
-gateway_up
-btc_fork 5
-check_balance 9.95799209 0.00000000
-gateway_down
-echo " OK"
-
-echo -n "Recover orphaned transactions:"
-next_btc 5 # More block needed to confirm
-check_balance 9.95799209 0.04200000
-gateway_up
-echo " OK"
-
-echo "Loose second bitcoin node"
-btc_deco
-
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS transfer 0.064 > /dev/null
-next_btc 5 # More block needed to confirm
-check_balance 9.89398418 0.10600000
-echo " OK"
-
-echo -n "Perform fork and check btc-wire learned from previous attack:"
-gateway_up
-btc_fork 5
-check_balance 9.89398418 0.10600000
-gateway_up
-echo " OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/btc/bumpfee.sh b/test/btc/bumpfee.sh
deleted file mode 100755
index fa9c5a7..0000000
--- a/test/btc/bumpfee.sh
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/bin/bash
-
-## Test btc-wire ability to handle stuck transaction correctly
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc_bump.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start second bitcoin node"
-init_btc2
-echo "Start btc-wire"
-btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 30"
-
-echo -n "Making wire transfer to exchange:"
-for n in `$SEQ`; do
-    $WIRE_UTILS transfer 0.$n > /dev/null
-    mine_btc # Mine transactions
-done
-next_btc # Trigger btc-wire
-check_balance 5.79983389 4.20000000
-echo " OK"
-
-echo "----- Bump fee -----"
-
-echo -n "Making wire transfer from exchange:"
-taler-exchange-wire-gateway-client \
-    -b $BANK_ENDPOINT \
-    -C payto://bitcoin/$CLIENT \
-    -a $CURRENCY:0.004 > /dev/null
-sleep 1
-check_balance 5.79983389 4.19599801
-echo " OK"
-
-echo -n "Bump relay fee:"
-restart_btc -minrelaytxfee=0.0001
-echo " OK"
-
-echo -n "Check bump:"
-sleep 5
-mine_btc
-sleep 1
-check_balance 5.80383389 4.19598010
-echo " OK"
-
-echo "----- Bump fee reorg -----"
-
-echo "Loose second bitcoin node"
-btc_deco
-
-echo -n "Making wire transfer from exchange:"
-taler-exchange-wire-gateway-client \
-    -b $BANK_ENDPOINT \
-    -C payto://bitcoin/$CLIENT \
-    -a $CURRENCY:0.004 > /dev/null
-sleep 1
-check_balance 5.80383389 4.19196020
-echo " OK"
-
-echo -n "Perform fork and bump relay fee:"
-btc_fork 6
-restart_btc -minrelaytxfee=0.0002
-mine_btc
-echo " OK"
-
-echo -n "Check bump:"
-sleep 5
-next_btc
-sleep 1
-check_balance 5.80783389 4.19194030
-echo " OK"
-
-echo "----- Bump fee stress -----"
-
-echo -n "Replace btc-wire with stressed btc-wire"
-kill $WIRE_PID
-stress_btc_wire
-echo " OK"
-
-echo -n "Making wire transfer from exchange:"
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://bitcoin/$CLIENT \
-        -a $CURRENCY:0.00$n > /dev/null
-done
-sleep 5
-echo " OK"
-
-echo -n "Bump relay fee:"
-restart_btc -minrelaytxfee=0.0003
-echo " OK"
-
-echo -n "Check bump:"
-for n in `seq 0 4`; do
-    sleep 2
-    mine_btc
-done
-check_balance 5.84983389 4.14868660
-echo " OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/btc/config.sh b/test/btc/config.sh
deleted file mode 100755
index f096e6a..0000000
--- a/test/btc/config.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/bash
-
-## Test btc-wire ability to configure itself from bitcoin configuration
-
-set -eu
-
-CONFIG=taler_btc.conf
-
-function test() {
-    echo "----- Config $1 -----"
-
-    BTC_CONFIG=$1
-    source "${BASH_SOURCE%/*}/../common.sh"
-
-    echo "Load config file"
-    load_config
-    echo "Start bitcoin node"
-    init_btc
-    echo "Cleanup"
-    cleanup
-}
-
-for n in `seq 0 5`; do
-    test "bitcoin_auth$n.conf"
-done
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/btc/conflict.sh b/test/btc/conflict.sh
deleted file mode 100755
index 7c87a4d..0000000
--- a/test/btc/conflict.sh
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/bin/bash
-
-## Test btc-wire ability to handle conflicting outgoing transactions
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start second bitcoin node"
-init_btc2
-echo "Start btc-wire"
-btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-echo "----- Conflict send -----"
-
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS transfer 0.042 > /dev/null
-next_btc
-check_balance 9.95799209 0.04200000
-echo " OK"
-
-echo -n "Making wire transfer from exchange:"
-taler-exchange-wire-gateway-client \
-    -b $BANK_ENDPOINT \
-    -C payto://bitcoin/$CLIENT \
-    -a $CURRENCY:0.004 > /dev/null
-sleep 1
-check_balance 9.95799209 0.03799801
-echo " OK"
-
-echo -n "Abandon pending transaction:"
-restart_btc -minrelaytxfee=0.0001
-$WIRE_UTILS abandon
-check_balance 9.95799209 0.04200000
-echo " OK"
-
-echo -n "Generate conflict:"
-taler-exchange-wire-gateway-client \
-    -b $BANK_ENDPOINT \
-    -C payto://bitcoin/$CLIENT \
-    -a $CURRENCY:0.005 > /dev/null
-sleep 5
-restart_btc
-mine_btc
-check_balance 9.96299209 0.03698010
-echo " OK"
-
-echo -n "Resend conflicting transaction:"
-sleep 5 # Wait for reconnection
-mine_btc
-check_delta "outgoing?delta=-100" "seq 4 5" "0.00"
-check_balance 9.96699209 0.03297811
-echo " OK"
-
-echo  "----- Reset -----"
-echo "Cleanup"
-cleanup
-source "${BASH_SOURCE%/*}/../common.sh"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start second bitcoin node"
-init_btc2
-echo "Start btc-wire"
-btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-echo "----- Conflict bounce -----"
-
-echo -n "Bounce:"
-$BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.04 > /dev/null
-mine_btc $CONFIRMATION
-sleep 1
-check_balance 9.95999859 0.00001000
-echo " OK"
-
-echo -n "Abandon pending transaction:"
-restart_btc -minrelaytxfee=0.0001
-$WIRE_UTILS abandon
-check_balance 9.95999859 0.04000000
-echo " OK"
-
-echo -n "Generate conflict:"
-$BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.05 > /dev/null
-mine_btc $CONFIRMATION
-sleep 1
-restart_btc
-mine_btc
-check_balance 9.94997264 0.05001000
-echo " OK"
-
-echo -n "Resend conflicting transaction:"
-sleep 5 # Wait for reconnection
-mine_btc
-check_balance 9.99996079 0.00002000
-echo " OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/btc/hell.sh b/test/btc/hell.sh
deleted file mode 100755
index ad1271a..0000000
--- a/test/btc/hell.sh
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/bin/bash
-
-## Test btc-wire correctness when a blockchain reorganization occurs leading 
to past incoming transaction conflict
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start second bitcoin node"
-init_btc2
-echo "Start btc-wire"
-btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-echo  "----- Handle reorg conflicting incoming credit -----"
-
-echo "Loose second bitcoin node"
-btc_deco
-
-echo -n "Gen incoming transactions:"
-$WIRE_UTILS transfer 0.0042 > /dev/null
-next_btc # Trigger btc-wire
-check_balance 9.99579209 0.00420000
-echo " OK"
-
-echo -n "Perform fork and check btc-wire hard error:"
-gateway_up
-btc_fork 5
-check_balance 9.99579209 0.00000000
-gateway_down
-echo " OK"
-
-echo -n "Generate conflict:"
-restart_btc -minrelaytxfee=0.0001
-$WIRE_UTILS abandon client
-$WIRE_UTILS transfer 0.0054 > /dev/null
-mine_btc
-check_balance 9.99457382 0.00540000
-echo " OK"
-
-echo -n "Check btc-wire suspend function:"
-sleep 5 # Wait for reconnection
-$BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.0042 > /dev/null
-next_btc
-sleep 1
-gateway_down
-check_balance 9.99035972 0.00960000 # Not bounced
-echo " OK"
-
-# Recover by paying for the customer ?
-
-echo  "----- Reset -----"
-echo "Cleanup"
-cleanup
-source "${BASH_SOURCE%/*}/../common.sh"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start second bitcoin node"
-init_btc2
-echo "Start btc-wire"
-btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-echo  "----- Handle reorg conflicting incoming bounce -----"
-
-echo "Loose second bitcoin node"
-btc_deco
-
-echo -n "Generate bounce:"
-$BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.042 > /dev/null
-next_btc
-check_balance 9.99998674 0.00001000
-echo " OK"
-
-echo -n "Perform fork and check btc-wire hard error:"
-gateway_up
-btc_fork 5
-check_balance 9.95799859 0.00000000
-gateway_down
-echo " OK"
-
-echo -n "Generate conflict:"
-restart_btc -minrelaytxfee=0.0001
-$WIRE_UTILS abandon client
-$WIRE_UTILS transfer 0.054 > /dev/null
-mine_btc
-check_balance 9.94597382 0.05400000
-echo " OK"
-
-echo -n "Check btc-wire suspend function:"
-sleep 5 # Wait for reconnection
-$BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.0042 > /dev/null
-next_btc
-sleep 1
-gateway_down
-check_balance 9.94175972 0.05820000 # Not bounced
-echo " OK"
-
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/btc/lifetime.sh b/test/btc/lifetime.sh
deleted file mode 100755
index a4f540c..0000000
--- a/test/btc/lifetime.sh
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/bash
-
-## Check btc-wire and wire-gateway correctly stop when a lifetime limit is 
configured
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc_lifetime.conf
-
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start btc-wire"
-btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 20"
-
-echo "---- Check lifetime -----"
-
-echo -n "Check up:"
-check_up $WIRE_PID btc-wire
-check_up $GATEWAY_PID wire-gateway
-echo " OK"
-
-echo -n "Do some work:"
-for n in `$SEQ`; do
-    $WIRE_UTILS transfer 0.000$n > /dev/null
-    mine_btc # Mine transactions
-done
-next_btc # Trigger btc-wire
-check_balance 9.99826299 0.00165000
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://bitcoin/$CLIENT \
-        -a $CURRENCY:0.0000$n &> /dev/null || break;
-done
-echo " OK"
-
-echo -n "Check down:"
-check_down $WIRE_PID btc-wire
-check_down $GATEWAY_PID wire-gateway
-echo " OK"
-
-echo "All tests passed!"
diff --git a/test/btc/maxfee.sh b/test/btc/maxfee.sh
deleted file mode 100755
index d1211d8..0000000
--- a/test/btc/maxfee.sh
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/bin/bash
-
-## Test btc-wire handle transaction fees exceeding limits
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start btc-wire"
-btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 30"
-
-echo -n "Making wire transfer to exchange: "
-for n in `$SEQ`; do
-    $WIRE_UTILS transfer 0.$n > /dev/null
-    mine_btc # Mine transactions
-done
-next_btc # Trigger btc-wire
-check_balance 5.79983389 4.20000000
-echo "OK"
-
-echo "----- Too high fees -----"
-
-echo -n "Set up node: "
-restart_btc -maxtxfee=0.0000001 -minrelaytxfee=0.0000001
-echo "OK"
-
-echo -n "Making wire transfer from exchange: "
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://bitcoin/$CLIENT \
-        -a $CURRENCY:0.0$n > /dev/null
-done
-sleep 5
-mine_btc
-echo "OK"
-
-echo -n "Check no transaction have been made: "
-check_balance 5.79983389 4.20000000
-echo "OK"
-
-echo "----- Good fees -----"
-
-echo -n "Set up node: "
-restart_btc
-echo "OK"
-
-echo -n "Check transaction have been made: "
-sleep 6
-check_balance 5.79983389 3.77995821
-echo "OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/btc/reconnect.sh b/test/btc/reconnect.sh
deleted file mode 100755
index 8b74fcf..0000000
--- a/test/btc/reconnect.sh
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/bin/bash
-
-## Check the capacity of wire-gateway and btc-wire to recover from database 
and node loss
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start btc-wire"
-btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-echo "----- With DB -----"
-echo "Making wire transfer to exchange:"
-$WIRE_UTILS transfer 0.000042 > /dev/null
-next_btc
-check_balance 9.99995009 0.00004200
-echo -n "Requesting exchange incoming transaction list:"
-check_delta "incoming?delta=-100" "echo 42"
-echo "OK"
-
-echo "----- Without DB -----"
-
-echo "Stop database"
-stop_db
-echo "Making incomplete wire transfer to exchange"
-$BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.00042 &> /dev/null
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS transfer 0.00004 > /dev/null
-next_btc
-check_balance 9.99948077 0.00050200
-echo " OK"
-echo "Stop bitcoin node"
-stop_node
-echo -n "Requesting exchange incoming transaction list:"
-taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -i 2>&1 | grep -q "504" 
&& echo " OK" || echo " Failed"
-
-echo "----- Reconnect DB -----"
-
-echo "Start database"
-start_db
-echo "Resume bitcoin node"
-resume_btc
-sleep 6 # Wait for connection to be available
-echo -n "Making wire transfer from exchange:"
-taler-exchange-wire-gateway-client \
-    -b $BANK_ENDPOINT \
-    -C payto://bitcoin/$CLIENT \
-    -a $CURRENCY:0.00002 > /dev/null
-sleep 1
-mine_btc
-check_balance 9.99990892 0.00007001
-echo " OK"
-
-echo -n "Requesting exchange's outgoing transaction list:"
-check_delta "outgoing?delta=-100" "echo 2"
-echo " OK"
-
-echo "----- Recover DB -----"
-
-echo "Reset database"
-reset_db
-mine_btc # Trigger worker
-sleep 2
-
-echo -n "Checking recover incoming transactions:"
-check_delta "incoming?delta=-100" "echo 42 4"
-echo " OK"
-
-echo -n "Requesting exchange's outgoing transaction list:"
-check_delta "outgoing?delta=-100" "echo 2"
-echo " OK"
-
-echo -n "Balance should not have changed:"
-check_balance 9.99990892 0.00007001
-echo " OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/btc/reorg.sh b/test/btc/reorg.sh
deleted file mode 100755
index 69c272d..0000000
--- a/test/btc/reorg.sh
+++ /dev/null
@@ -1,114 +0,0 @@
-#!/bin/bash
-
-## Test btc-wire correctness when a blockchain reorganization occurs
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start second bitcoin node"
-init_btc2
-echo "Start btc-wire"
-btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 20"
-
-echo  "----- Handle reorg incoming transactions -----"
-
-echo "Loose second bitcoin node"
-btc_deco
-
-echo -n "Gen incoming transactions:"
-for n in `$SEQ`; do
-    $WIRE_UTILS transfer 0.000$n > /dev/null
-    mine_btc # Mine transactions
-done
-next_btc # Trigger btc-wire
-check_delta "incoming?delta=-100" "$SEQ" "0.000"
-check_balance 9.99826299 0.00165000
-echo " OK"
-
-echo -n "Perform fork and check btc-wire hard error:"
-gateway_up
-btc_fork 22
-check_balance 9.99826299 0.00000000
-gateway_down
-echo " OK"
-
-echo -n "Recover orphaned transactions:"
-next_btc 6 # More block needed to confirm
-check_balance 9.99826299 0.00165000
-gateway_up
-echo " OK"
-
-echo "----- Handle reorg outgoing transactions -----"
-
-echo "Loose second bitcoin node"
-btc_deco
-
-echo -n "Gen outgoing transactions:"
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://bitcoin/$CLIENT \
-        -a $CURRENCY:0.0000$n > /dev/null
-done
-sleep 1
-mine_btc # Mine transactions
-check_delta "outgoing?delta=-100" "$SEQ"
-check_balance 9.99842799 0.00146311
-echo " OK"
-
-echo -n "Perform fork and check btc-wire still up:"
-gateway_up
-btc_fork 22
-check_balance 9.99826299 0.00146311
-gateway_up
-echo " OK"
-
-echo -n "Recover orphaned transactions:"
-next_btc 6 # More block needed to confirm
-check_balance 9.99842799 0.00146311
-echo " OK"
-
-echo "----- Handle reorg bounce -----"
-
-clear_wallet
-check_balance "*" 0.00000000
-
-echo "Loose second bitcoin node"
-btc_deco
-
-echo -n "Generate bounce:"
-for n in `$SEQ`; do
-    $BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.000$n > /dev/null
-    mine_btc
-done
-next_btc 6 # More block needed to confirm
-sleep 1
-check_balance "*" 0.00011000
-echo " OK"
-
-echo -n "Perform fork and check btc-wire hard error:"
-gateway_up
-btc_fork 22
-check_balance "*" 0.00000000
-gateway_down
-echo " OK"
-
-echo -n "Recover orphaned transactions:"
-next_btc 6 # More block needed to confirm
-check_balance "*" 0.00011000
-gateway_up
-echo " OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/btc/stress.sh b/test/btc/stress.sh
deleted file mode 100755
index 681e606..0000000
--- a/test/btc/stress.sh
+++ /dev/null
@@ -1,123 +0,0 @@
-#!/bin/bash
-
-## Test btc-wire ability to recover from errors in correctness critical paths 
and prevent concurrent sending
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc.conf
-
-echo  "----- Setup stressed -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start stressed btc-wire"
-stress_btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 30"
-
-echo "----- Handle incoming -----"
-
-echo -n "Making wire transfer to exchange:"
-for n in `$SEQ`; do
-    $WIRE_UTILS transfer 0.000$n > /dev/null
-    mine_btc # Mine transactions
-done
-next_btc # Confirm all transactions
-echo " OK"
-
-echo -n "Requesting exchange incoming transaction list:"
-check_delta "incoming?delta=-100" "$SEQ" "0.000"
-echo " OK"
-
-echo -n "Check balance:"
-check_balance 9.99563389 0.00420000
-echo " OK"
-
-echo "----- Handle outgoing -----"
-
-echo -n "Making wire transfer from exchange:"
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://bitcoin/$CLIENT \
-        -a $CURRENCY:0.0000$n > /dev/null
-done
-sleep 10 # Give time for btc-wire worker to process 
-next_btc # Mine transactions
-echo " OK"
-
-echo -n "Requesting exchange outgoing transaction list:"
-check_delta "outgoing?delta=-100" "$SEQ"
-echo " OK"
-
-echo -n "Check balance:"
-check_balance 9.99605389 0.00373821 
-echo " OK"
-
-echo "----- Recover DB -----"
-
-echo "Reset database"
-reset_db
-mine_btc # Trigger worker
-sleep 10
-
-echo -n "Requesting exchange incoming transaction list:"
-check_delta "incoming?delta=-100" "$SEQ" "0.000"
-echo " OK"
-
-echo -n "Requesting exchange outgoing transaction list:"
-check_delta "outgoing?delta=-100" "$SEQ"
-echo " OK"
-
-echo -n "Check balance:"
-# Balance should not have changed
-check_balance 9.99605389 0.00373821 
-echo " OK"
-
-echo "----- Handle bounce -----"
-
-echo -n "Clear wire wallet:"
-$BTC_CLI -rpcwallet=wire sendtoaddress $CLIENT `$BTC_CLI -rpcwallet=wire 
getbalance` "" "" true > /dev/null
-echo " OK"
-
-echo -n "Making incomplete wire transfer to exchange:"
-for n in `$SEQ`; do
-    $BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.000$n > /dev/null
-    mine_btc
-done
-next_btc
-sleep 5
-mine_btc
-sleep 5
-echo " OK"
-
-echo -n "Check balance:"
-check_balance "*" 0.00021000
-echo " OK"
-
-echo "----- Recover DB -----"
-
-echo "Reset database"
-reset_db
-mine_btc # Trigger worker
-sleep 10
-
-echo -n "Requesting exchange incoming transaction list:"
-check_delta "incoming?delta=-100" "$SEQ" "0.000"
-echo " OK"
-
-echo -n "Requesting exchange outgoing transaction list:"
-check_delta "outgoing?delta=-100" "$SEQ"
-echo " OK"
-
-echo -n "Check balance:"
-# Balance should not have changed
-check_balance "*" 0.00021000
-echo " OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/btc/wire.sh b/test/btc/wire.sh
deleted file mode 100755
index 150ffbf..0000000
--- a/test/btc/wire.sh
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/bin/bash
-
-## Test btc-wire correctly receive and send transactions on the blockchain
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start btc-wire"
-btc_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 99"
-
-echo  "----- Receive -----"
-
-echo -n "Making wire transfer to exchange:"
-for n in `$SEQ`; do
-    $WIRE_UTILS transfer 0.000$n > /dev/null
-    mine_btc # Mine transactions
-done
-next_btc # Trigger btc-wire
-check_balance 9.95023810 0.04905000
-echo " OK"
-
-echo -n "Requesting exchange incoming transaction list:"
-check_delta "incoming?delta=-100" "$SEQ" "0.000"
-echo " OK"
-
-echo  "----- Send -----"
-
-echo -n "Making wire transfer from exchange:"
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://bitcoin/$CLIENT \
-        -a $CURRENCY:0.0000$n > /dev/null
-done
-sleep 15
-mine_btc # Mine transactions
-check_balance 9.95514310 ""
-echo " OK"
-
-echo -n "Requesting exchange's outgoing transaction list:"
-check_delta "outgoing?delta=-100" "$SEQ"
-echo " OK"
-
-echo  "----- Bounce -----"
-
-clear_wallet
-
-echo -n "Bounce:"
-for n in `seq 10 40`; do
-    $BTC_CLI -rpcwallet=client sendtoaddress $WIRE 0.000$n > /dev/null
-    mine_btc
-done
-next_btc
-sleep 3
-check_balance "*" 0.00031000
-echo " OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/common.sh b/test/common.sh
deleted file mode 100644
index a95c5ad..0000000
--- a/test/common.sh
+++ /dev/null
@@ -1,405 +0,0 @@
-#!/bin/bash
-
-## Test utils
-
-set -eu
-
-# Cleanup to run whenever we exit
-function cleanup() {
-    pg_ctl stop -D $DB_DIR -w &> /dev/null
-    for n in `jobs -p`; do
-        kill $n &> /dev/null || true
-    done
-    rm -rf $DIR &> /dev/null || true
-    wait
-}
-
-# Install cleanup handler (except for kill -9)
-trap cleanup EXIT
-
-# Init temporary dirs
-DIR=$(mktemp -d)
-WIRE_DIR=$DIR/wire
-WIRE_DIR2=$DIR/wire2
-DB_DIR=$DIR/db
-CONF=$DIR/taler.conf
-for dir in $WIRE_DIR $WIRE_DIR2 $DB_DIR log; do
-    mkdir -p "$dir"
-done
-
-# Clear logs
-for log in log/*; do
-    echo -n "" > $log
-done
-
-# Generate random password
-export PASSWORD=`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
-function load_config() {
-    cp ${BASH_SOURCE%/*}/conf/$CONFIG $CONF
-    echo -e "\nCONF_PATH = ${WIRE_DIR}" >> $CONF
-    echo -e "IPC_PATH = ${WIRE_DIR}" >> $CONF
-    source <(grep = $CONF | sed 's/ *= */=/' | sed 's/=\(.*\)/="\1"/g1')
-    BANK_ENDPOINT=http://127.0.0.1:${PORT:-8080}/
-    if [[ "$CURRENCY" =~ "BTC" ]]; then
-        WIRE_CLI="btc-wire -c $CONF"
-        WIRE_UTILS="btc-wire-utils -c $CONF"
-        WIRE_UTILS2="btc-wire-utils -c $CONF -d $WIRE_DIR2"
-    else
-        WIRE_CLI="eth-wire -c $CONF"
-        WIRE_UTILS="eth-wire-utils -c $CONF"
-        WIRE_UTILS2="eth-wire-utils -c $CONF -d $WIRE_DIR2"
-    fi
-}
-
-# Check process is running
-function check_up() {
-    if [ `ps -p $1 | grep -c $1` == 0 ]; then
-        echo "${2:-process} with pid $1 should be up"
-        ps -p $1
-        exit 1
-    fi
-}
-
-# Check process is not running
-function check_down() {
-    if [ `ps -p $1 | grep -c $1` != 0 ]; then 
-        echo "${2:-process} with pid $1 should be down"
-        ps -p $1
-        exit 1
-    fi
-}
-
-function stop_node() {
-    kill $NODE_PID 
-    wait $NODE_PID
-}
-
-# ----- Database ----- #
-
-# Create new postgresql cluster and init database
-function setup_db() {
-    pg_ctl init -D $DB_DIR &>> log/postgres.log
-    echo "port=5454" >> $DB_DIR/postgresql.conf
-    start_db
-    echo "CREATE ROLE postgres LOGIN SUPERUSER PASSWORD 'password'" | psql -h 
localhost -p 5454 postgres > /dev/null
-    $WIRE_CLI initdb > /dev/null
-}
-
-# Erase database
-function reset_db() {
-    sleep 5 # Wait for loop to stop
-    $WIRE_UTILS resetdb
-}
-
-# Stop database
-function stop_db() {
-    pg_ctl stop -D $DB_DIR >> log/postgres.log
-}
-
-# Start database
-function start_db() {
-    pg_ctl start -D $DB_DIR -o "-c unix_socket_directories=$DIR" >> 
log/postgres.log
-}
-
-# ----- Bitcoin node ----- #
-
-# Start a bitcoind regtest node, generate money, wallet and addresses
-function init_btc() {
-    cp ${BASH_SOURCE%/*}/conf/${BTC_CONFIG:-bitcoin.conf} 
$WIRE_DIR/bitcoin.conf
-    bitcoind -datadir=$WIRE_DIR $* &>> log/node.log &
-    NODE_PID="$!"
-    # Wait for RPC server to be online
-    $BTC_CLI -rpcwait getnetworkinfo > /dev/null
-    # Setup db
-    setup_db
-    # Create wire wallet
-    $WIRE_CLI initwallet > /dev/null
-    # Create other wallets
-    for wallet in client reserve; do
-        $BTC_CLI createwallet $wallet > /dev/null
-    done
-    # Generate addresses
-    RESERVE=`$BTC_CLI -rpcwallet=reserve getnewaddress`
-    CLIENT=`$BTC_CLI -rpcwallet=client getnewaddress`
-    WIRE=`$BTC_CLI -rpcwallet=wire getnewaddress`
-    # Generate money
-    mine_btc 101
-    $BTC_CLI -rpcwallet=reserve sendtoaddress $CLIENT 10 > /dev/null
-    mine_btc
-}
-
-# Start a second bitcoind regtest node connected to the first one
-function init_btc2() {
-    cp ${BASH_SOURCE%/*}/conf/bitcoin2.conf $WIRE_DIR2/bitcoin.conf
-    bitcoind -datadir=$WIRE_DIR2 $* &>> log/node2.log &
-    $BTC_CLI2 -rpcwait getnetworkinfo > /dev/null    
-    $BTC_CLI addnode 127.0.0.1:8346 onetry
-}
-
-# Disconnect the two nodes
-function btc_deco() {
-    $BTC_CLI disconnectnode 127.0.0.1:8346
-}
-
-# Create a fork on the second node and reconnect the two node
-function btc_fork() {
-    $BTC_CLI2 generatetoaddress $1 $RESERVE > /dev/null
-    $BTC_CLI addnode 127.0.0.1:8346 onetry
-    sleep 1
-}
-
-# Restart a bitcoind regest server in a previously created temporary directory 
and load wallets
-function resume_btc() {
-    # Restart node
-    bitcoind -datadir=$WIRE_DIR $* &>> log/node.log &
-    NODE_PID="$!" 
-    # Load wallets
-    for wallet in wire client reserve; do
-        $BTC_CLI -rpcwait loadwallet $wallet > /dev/null
-    done
-    # Connect second node
-    $BTC_CLI addnode 127.0.0.1:8346 onetry
-}
-
-function restart_btc() {
-    stop_node
-    resume_btc $*
-}
-
-# Mine bitcoin blocks
-function mine_btc() {
-    $BTC_CLI generatetoaddress "${1:-1}" $RESERVE > /dev/null
-}
-
-# Mine previous transactions
-function next_btc() {
-    # Mine enough block to confirm previous transactions
-    mine_btc ${1:-$CONFIRMATION}
-    # Wait for btc-wire to catch up
-    sleep 0.2
-    # Mine one more block to trigger btc-wire
-    mine_btc
-}
-
-# Remove money from wallet wire
-function clear_wallet() {
-    $BTC_CLI -rpcwallet=wire sendtoaddress $CLIENT `$BTC_CLI -rpcwallet=wire 
getbalance` "" "" true > /dev/null
-    mine_btc
-}
-
-# Check client and wire balance
-function check_balance() {
-    local CLIENT_BALANCE=`$BTC_CLI -rpcwallet=client getbalance`
-    local WIRE_BALANCE=`$BTC_CLI -rpcwallet=wire getbalance`
-    local CLIENT="${1:-*}"
-    if [ "$1" == "*" ]; then
-        local CLIENT="$CLIENT_BALANCE"
-    fi
-    if [ "$CLIENT_BALANCE" != "$CLIENT" ] || [ "$WIRE_BALANCE" != 
"${2:-$WIRE_BALANCE}" ]; then
-        echo "expected: client $CLIENT wire ${2:-$WIRE_BALANCE}    got: client 
$CLIENT_BALANCE wire $WIRE_BALANCE"
-        exit 1
-    fi
-}
-
-# ----- btc-wire ----- #
-
-# Start btc-wire
-function btc_wire() {    
-    cargo build --bin btc-wire --release &>> log/cargo.log
-    target/release/btc-wire -c $CONF &>> log/wire.log &
-    WIRE_PID="$!"
-}
-
-# Start multiple btc-wire with random failures in parallel
-function stress_btc_wire() {
-   cargo build --bin btc-wire --release --features fail &>> log/cargo.log
-   target/release/btc-wire -c $CONF &>> log/wire.log & 
-   target/release/btc-wire -c $CONF &>> log/wire1.log & 
-}
-
-# ----- Ethereum node ----- #
-
-# Start a geth dev node, generate money, wallet and addresses
-function init_eth() {
-    # Create wallets
-    for pswd in "reserve" "client"; do
-        $ETH_CLI account new --password <(echo $PASSWORD) &> /dev/null
-    done
-    # Retrieve addresses
-    local ADDR=`$ETH_CLI account list 2> /dev/null | grep -oP '(?<={).*?(?=})'`
-    RESERVE=`sed -n '1p' <(echo "$ADDR")`
-    CLIENT=`sed -n '2p' <(echo "$ADDR")`
-    # Generate genesis 
-    echo "{
-  \"config\": {
-    \"chainId\": 42,
-    \"homesteadBlock\": 0,
-    \"eip150Block\": 0,
-    \"eip155Block\": 0,
-    \"eip158Block\": 0,
-    \"byzantiumBlock\": 0,
-    \"constantinopleBlock\": 0,
-    \"petersburgBlock\": 0,
-    \"istanbulBlock\": 0,
-    \"berlinBlock\": 0,
-       \"londonBlock:\": 0,
-    \"ethash\": {}
-  },
-  \"difficulty\": \"1\",
-  \"gasLimit\": \"0\",
-  \"baseFeePerGas\": null,
-  \"alloc\": {
-    \"$CLIENT\": { \"balance\": \"10000000000000000000\" }
-  }
-}" > $DIR/genesis.json
-    # Initialize blockchain
-    $ETH_CLI init $DIR/genesis.json &>> log/node.log
-    # Start node
-    start_eth $*
-    # Setup db
-    setup_db
-    # Create wire address
-    WIRE=`$WIRE_CLI initwallet | grep -oP '(?<=is ).*'`
-    echo -e "PAYTO = payto://ethereum/$WIRE" >> $CONF
-}
-
-# Initialize a second geth dev node
-function init_eth2() {
-    # Initialize blockchain
-    $ETH_CLI2 init $DIR/genesis.json &>> log/node2.log
-    $ETH_CLI2 account new --password <(echo $PASSWORD) &> /dev/null
-}
-
-# We use the import/export chain functionality to simulate a connected node 
peer 
-# because local network peer are not reliable
-# importChain RPC crash so we have to use the cli for now
-
-# Disconnect the two nodes
-function eth_deco() {
-    $WIRE_UTILS export $DIR/chain &>> log/node.log
-    $ETH_CLI2 import $DIR/chain &>> log/node2.log
-}
-
-# Create a fork on the second node and reconnect the two node
-function eth_fork() {
-    $ETH_CLI2 --port 30305 --miner.gasprice 0 &>> log/node2.log &
-    NODE2_PID="$!"
-    sleep 1
-    $WIRE_UTILS2 mine $RESERVE ${1:-}
-    $WIRE_UTILS2 export $DIR/chain &>> log/node2.log
-    kill $NODE2_PID
-    stop_node
-    $ETH_CLI import $DIR/chain &>> log/node.log
-    start_eth --miner.gasprice 0
-    sleep 5 # Wait for reconnect
-}
-
-# Restart an initialized geth dev node
-function start_eth() { 
-    # Start node
-    $ETH_CLI $* &>> log/node.log &
-    NODE_PID="$!"
-    sleep 2
-}
-
-function restart_eth() {
-    stop_node
-    start_eth $*
-}
-
-# Check client and wire balance
-function check_balance_eth() {
-    $WIRE_UTILS check-balance $CLIENT $1 $WIRE $2
-}
-
-
-# ----- eth-wire ----- #
-
-# Start eth-wire
-function eth_wire() {
-    cargo build --bin eth-wire --release &>> log/cargo.log
-    target/release/eth-wire -c $CONF &>> log/wire.log &
-    WIRE_PID="$!"
-}
-
-# Start multiple eth-wire with random failures in parallel
-function stress_eth_wire() {
-    cargo build --bin eth-wire --release --features fail &>> log/cargo.log
-    target/release/eth-wire -c $CONF &>> log/wire.log &
-    target/release/eth-wire -c $CONF &>> log/wire1.log &
-}
-
-# Mine ethereum blocks
-function mine_eth() {
-    $WIRE_UTILS mine $RESERVE ${1:-}
-}
-
-# Mine previous transactions
-function next_eth() {
-    # Mine enough block to confirm previous transactions
-    mine_eth ${1:-$CONFIRMATION}
-    # Wait for eth-wire to catch up
-    sleep 0.2
-    # Mine one more block to trigger eth-wire
-    mine_eth
-}
-
-# ----- Gateway ------ #
-
-# Start wire-gateway in test mode
-function gateway() {
-    cargo build --bin wire-gateway --release --features test &> /dev/null
-    target/release/wire-gateway -c $CONF &>> log/gateway.log & 
-    GATEWAY_PID="$!"
-    for n in `seq 1 50`; do
-        echo -n "."
-        sleep 0.2
-        curl -s $BANK_ENDPOINT -o /dev/null && break
-    done
-}
-
-# Check wire-gateway is healthy
-function gateway_up() {
-    if [ `curl -w %{http_code} -s ${BANK_ENDPOINT}history/outgoing -o 
/dev/null` -ne 400 ]; then
-        echo "gateway should be up"
-        exit 1
-    fi
-}
-
-# Check wire-gateway is down (backend is blocked)
-function gateway_down() {
-    if [ `curl -w %{http_code} -s ${BANK_ENDPOINT}history/outgoing -o 
/dev/null` -ne 502 ]; then 
-        echo "gateway should be down"
-        exit 1
-    fi
-}
-
-# Check history endpoint request return a specific amount of transactions of 
specific amounts
-# usage: check_delta endpoint nb_txs amount_sequence
-function check_delta() {
-    ALL=`curl -s ${BANK_ENDPOINT}history/$1`
-    PRE=${3:-0.0000}
-    for n in `$2`; do
-        if ! `echo $ALL | grep $CURRENCY:$PRE$n > /dev/null`; then
-            echo -n " missing tx with amount: $CURRENCY:$PRE$n"
-            return 1
-        fi
-    done
-    NB=`echo $ALL | grep -o $CURRENCY:$PRE | wc -l`
-    EXPECTED=`$2 | wc -w`
-    if [ "$EXPECTED" != "$NB" ]; then
-        echo -n " expected: $EXPECTED txs found $NB"
-        return 1
-    fi
-}
diff --git a/test/eth/analysis.sh b/test/eth/analysis.sh
deleted file mode 100755
index bc1898b..0000000
--- a/test/eth/analysis.sh
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/bin/bash
-
-## Test eth-wire ability to learn and protect itself from blockchain behavior
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_eth.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start ethereum node"
-init_eth --miner.gasprice 0
-echo "Start second ethereum node"
-init_eth2 --miner.gasprice 0
-echo "Start eth-wire"
-eth_wire
-echo "Start gateway"
-gateway
-echo ""
-
-echo  "----- Learn from reorg -----"
-
-echo "Loose second ethereum node"
-eth_deco
-
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS credit $CLIENT $WIRE 0.00 42
-next_eth # Trigger eth-wire
-check_balance_eth 999580000 420000
-echo " OK"
-
-echo -n "Perform fork and check eth-wire hard error:"
-gateway_up
-eth_fork 6
-check_balance_eth 1000000000 0
-gateway_down
-echo " OK"
-
-echo -n "Recover orphaned transactions:"
-next_eth 6 # More block needed to confirm
-check_balance_eth 999580000 420000
-gateway_up
-echo " OK"
-
-echo "Loose second bitcoin node"
-eth_deco
-
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS credit $CLIENT $WIRE 0.00 42
-next_eth # Trigger eth-wire
-check_balance_eth 999160000 840000
-echo " OK"
-
-echo -n "Perform fork and check eth-wire learned from previous attack:"
-gateway_up
-eth_fork 10
-check_balance_eth 999580000 420000
-gateway_up
-echo " OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/eth/bumpfee.sh b/test/eth/bumpfee.sh
deleted file mode 100755
index 16e1952..0000000
--- a/test/eth/bumpfee.sh
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/bin/bash
-
-## Test eth-wire ability to handle stuck transaction correctly
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_eth_bump.conf
-
-echo "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start ethereum node"
-init_eth --miner.gasprice 0
-echo "Start second ethereum node"
-init_eth2 --miner.gasprice 0
-echo "Start eth-wire"
-eth_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 20"
-
-echo -n "Making wire transfer to exchange: "
-$WIRE_UTILS credit $CLIENT $WIRE 0.000 `$SEQ`
-sleep 1
-mine_eth # Trigger eth-wire
-check_balance_eth 999835000 165000
-echo "OK"
-
-echo  "----- Bump fee -----"
-
-echo -n "Making wire transfer from exchange: "
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://ethereum/$CLIENT \
-        -a $CURRENCY:0.0000$n > /dev/null
-done
-sleep 1
-echo "OK"
-
-echo -n "Bump miner fee:"
-restart_eth --miner.gasprice 1000
-sleep 5
-echo "OK"
-
-echo -n "Check bump: "
-sleep 1
-mine_eth # Mine transactions
-check_balance_eth 999851500 148499
-echo "OK"
-
-echo  "----- Bump fee reorg -----"
-
-echo "Loose second ethereum node"
-eth_deco
-
-echo -n "Making wire transfer from exchange: "
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://ethereum/$CLIENT \
-        -a $CURRENCY:0.0000$n > /dev/null
-done
-sleep 1
-echo "OK"
-
-echo -n "Perform fork and bump miner fee:"
-eth_fork 10
-restart_eth --miner.gasprice 2000
-sleep 5
-echo "OK"
-
-echo -n "Check bump: "
-sleep 1
-mine_eth # Mine transactions
-check_balance_eth 999868000 131999
-echo "OK"
-
-echo "----- Bump fee stress -----"
-
-echo -n "Replace btc-wire with stressed btc-wire"
-kill $WIRE_PID
-stress_eth_wire
-echo " OK"
-
-echo -n "Making wire transfer from exchange: "
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://ethereum/$CLIENT \
-        -a $CURRENCY:0.0000$n > /dev/null
-done
-sleep 1
-echo "OK"
-
-echo -n "Bump miner fee:"
-restart_eth --miner.gasprice 3000
-sleep 5
-echo "OK"
-
-echo -n "Check bump: "
-sleep 1
-mine_eth # Mine transactions
-check_balance_eth 999884500 115499
-echo "OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/eth/hell.sh b/test/eth/hell.sh
deleted file mode 100755
index d3aa97c..0000000
--- a/test/eth/hell.sh
+++ /dev/null
@@ -1,107 +0,0 @@
-#!/bin/bash
-
-## Test eth-wire correctness when a blockchain reorganization occurs leading 
to past incoming transaction conflict
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_eth.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start ethereum node"
-init_eth --miner.gasprice 0
-echo "Start second ethereum node"
-init_eth2 --miner.gasprice 0
-echo "Start eth-wire"
-eth_wire
-echo "Start gateway"
-gateway
-echo ""
-
-echo  "----- Handle reorg conflicting incoming credit -----"
-
-echo "Loose second ethereum node"
-eth_deco
-
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS credit $CLIENT $WIRE 0.00 42
-next_eth # Trigger eth-wire
-check_balance_eth 999580000 420000
-echo " OK"
-
-echo -n "Perform fork and check eth-wire hard error:"
-gateway_up
-eth_fork 10
-check_balance_eth 1000000000 0
-gateway_down
-echo " OK"
-
-echo -n "Generate conflict:"
-$WIRE_UTILS abandon $CLIENT
-next_eth 5
-check_balance_eth 999999999 0
-echo " OK"
-
-echo -n "Check eth-wire suspend function:"
-gateway_down
-$WIRE_UTILS send $CLIENT $WIRE 0.000 42
-next_eth 6
-sleep 1
-check_balance_eth 999957999 42000 # Not bounced
-echo " OK"
-
-# Recover by paying for the customer ?
-
-echo  "----- Reset -----"
-echo "Cleanup"
-cleanup
-source "${BASH_SOURCE%/*}/../common.sh"
-echo "Load config file"
-load_config
-echo "Start ethereum node"
-init_eth --miner.gasprice 0
-echo "Start second ethereum node"
-init_eth2 --miner.gasprice 0
-echo "Start eth-wire"
-eth_wire
-echo "Start gateway"
-gateway
-echo ""
-
-echo  "----- Handle reorg conflicting incoming bounce -----"
-
-echo "Loose second ethereum node"
-eth_deco
-
-echo -n "Bounce:"
-$WIRE_UTILS send $CLIENT $WIRE 0.00 42
-next_eth 6
-sleep 1
-check_balance_eth 999999000 1000
-echo " OK"
-
-echo -n "Perform fork and check eth-wire hard error:"
-gateway_up
-eth_fork 10
-check_balance_eth 1000000000 0
-gateway_down
-echo " OK"
-
-echo -n "Generate conflict:"
-$WIRE_UTILS abandon $CLIENT
-next_eth 5
-check_balance_eth 999999999 0
-echo " OK"
-
-echo -n "Check eth-wire suspend function:"
-$WIRE_UTILS send $CLIENT $WIRE 0.000 42
-next_eth 6
-sleep 1
-gateway_down
-check_balance_eth 999957999 42000 # Not bounced
-echo " OK"
-
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/eth/lifetime.sh b/test/eth/lifetime.sh
deleted file mode 100755
index 4c2c47c..0000000
--- a/test/eth/lifetime.sh
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/bash
-
-## Check eth-wire and wire-gateway correctly stop when a lifetime limit is 
configured
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_eth_lifetime.conf
-
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start ethereum node"
-init_eth --miner.gasprice 0
-echo "Start eth-wire"
-eth_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 20"
-
-echo "---- Check lifetime -----"
-
-echo -n "Check up:"
-check_up $WIRE_PID eth-wire
-check_up $GATEWAY_PID wire-gateway
-echo " OK"
-
-echo -n "Do some work:"
-$WIRE_UTILS credit $CLIENT $WIRE 0.000 `$SEQ` > /dev/null
-next_eth # Trigger eth-wire
-check_balance_eth 999835000 165000
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://ethereum/$CLIENT \
-        -a $CURRENCY:0.0000$n &> /dev/null || break;
-done
-sleep 1
-echo " OK"
-
-echo -n "Check down:"
-check_down $WIRE_PID eth-wire
-check_down $GATEWAY_PID wire-gateway
-echo " OK"
-
-echo "All tests passed!"
diff --git a/test/eth/maxfee.sh b/test/eth/maxfee.sh
deleted file mode 100755
index 556ce4f..0000000
--- a/test/eth/maxfee.sh
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/bin/bash
-
-## Test eth-wire handle transaction fees exceeding limits
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_eth.conf
-
-echo "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start ethereum node"
-init_eth --miner.gasprice 0
-echo "Start eth-wire"
-eth_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 20"
-
-echo -n "Making wire transfer to exchange: "
-$WIRE_UTILS credit $CLIENT $WIRE 0.000 `$SEQ`
-next_eth # Trigger eth-wire
-sleep 1
-check_delta "incoming?delta=-100" "$SEQ" "0.000"
-check_balance_eth 999835000 165000
-echo "OK"
-
-
-echo  "----- Too high fees -----"
-
-echo -n "Set up node: "
-restart_eth --rpc.txfeecap 0.00001
-echo "OK"
-
-echo -n "Making wire transfer from exchange: "
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://ethereum/$CLIENT \
-        -a $CURRENCY:0.0000$n > /dev/null
-done
-sleep 1
-mine_eth # Mine transactions
-echo "OK"
-
-echo -n "Check no transaction have been made: "
-check_balance_eth 999835000 165000
-echo "OK"
-
-echo "----- Good fees -----"
-
-echo -n "Set up node: "
-restart_eth --miner.gasprice 0
-echo "OK"
-
-echo -n "Check transaction have been made: "
-sleep 5
-mine_eth # Mine transactions
-check_balance_eth 999851500 148500
-echo "OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/eth/reconnect.sh b/test/eth/reconnect.sh
deleted file mode 100755
index 0f21568..0000000
--- a/test/eth/reconnect.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/bin/bash
-
-## Check the capacity of wire-gateway and eth-wire to recover from database 
and node loss
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_eth.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start ethereum node"
-init_eth --miner.gasprice 0
-echo "Start eth-wire"
-eth_wire
-echo "Start gateway"
-gateway
-echo ""
-
-echo "----- With DB -----"
-
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS credit $CLIENT $WIRE 0.0000 42
-next_eth # Trigger eth-wire
-check_balance_eth 999995800 4200
-echo " OK"
-
-echo -n "Requesting exchange incoming transaction list:"
-check_delta "incoming?delta=-100" "echo 42"
-echo " OK"
-
-echo  "----- Without DB -----"
-
-echo "Stop database"
-stop_db
-echo "Making incomplete wire transfer to exchange"
-$WIRE_UTILS send $CLIENT $WIRE 0.0000 42
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS credit $CLIENT $WIRE 0.0000 4
-next_eth
-check_balance_eth 999987600 12400
-echo "OK"
-echo "Stop ethereum node"
-stop_node
-echo -n "Requesting exchange incoming transaction list:"
-taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -i 2>&1 | grep -q "504" 
&& echo " OK" || echo " Failed"
-
-echo "----- Reconnect DB -----"
-
-echo "Start database"
-start_db
-echo "Resume ethereum node"
-start_eth --miner.gasprice 0
-sleep 6 # Wait for connection to be available
-echo -n "Making wire transfer from exchange:"
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://ethereum/$CLIENT \
-        -a $CURRENCY:0.00002 > /dev/null
-sleep 1
-mine_eth # Mine transactions
-check_balance_eth 999992800 7200
-echo " OK"
-
-echo -n "Requesting exchange's outgoing transaction list:"
-check_delta "outgoing?delta=-100" "echo 2"
-echo " OK"
-
-echo  "----- Recover DB -----"
-
-echo "Reset database"
-reset_db
-mine_eth 1 # Trigger worker
-sleep 2
-
-echo -n "Checking recover incoming transactions:"
-check_delta "incoming?delta=-100" "echo 42 4"
-echo " OK"
-
-echo -n "Requesting exchange's outgoing transaction list:"
-check_delta "outgoing?delta=-100" "echo 2"
-echo " OK"
-
-echo -n "Balance should not have changed:"
-check_balance_eth 999992800 7200
-echo " OK"
-
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/eth/reorg.sh b/test/eth/reorg.sh
deleted file mode 100755
index 220b687..0000000
--- a/test/eth/reorg.sh
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/bin/bash
-
-## Test eth-wire correctness when a blockchain reorganization occurs
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_eth.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start ethereum node"
-init_eth --miner.gasprice 0
-echo "Start second ethereum node"
-init_eth2 --miner.gasprice 0
-echo "Start eth-wire"
-eth_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 20"
-
-echo  "----- Handle reorg incoming transactions -----"
-
-echo "Loose second ethereum node"
-eth_deco
-
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS credit $CLIENT $WIRE 0.000 `$SEQ`
-next_eth # Trigger eth-wire
-check_delta "incoming?delta=-100" "$SEQ" "0.000"
-check_balance_eth 999835000 165000
-echo " OK"
-
-echo -n "Perform fork and check eth-wire hard error:"
-gateway_up
-eth_fork 10
-check_balance_eth 1000000000 0
-gateway_down
-echo " OK"
-
-echo -n "Recover orphaned transactions:"
-next_eth 6 # More block needed to confirm
-check_balance_eth 999835000 165000
-gateway_up
-echo " OK"
-
-echo "----- Handle reorg outgoing transactions -----"
-
-echo "Loose second ethereum node"
-eth_deco
-
-echo -n "Making wire transfer from exchange:"
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://ethereum/$CLIENT \
-        -a $CURRENCY:0.0000$n > /dev/null
-done
-sleep 1
-mine_eth # Mine transactions
-check_delta "outgoing?delta=-100" "$SEQ"
-check_balance_eth 999851500 148500
-echo " OK"
-
-echo -n "Perform fork and check eth-wire still up:"
-gateway_up
-eth_fork 10
-check_balance_eth 999835000 165000
-gateway_up
-echo " OK"
-
-echo -n "Recover orphaned transactions:"
-next_eth 6 # More block needed to confirm
-check_balance_eth 999851500 148500
-echo " OK"
-
-echo "----- Handle reorg bounce -----"
-
-echo "Loose second ethereum node"
-eth_deco
-
-echo -n "Bounce:"
-$WIRE_UTILS send $CLIENT $WIRE 0.000 `$SEQ`
-sleep 1
-next_eth 6
-check_balance_eth 999840500 159500
-echo " OK"
-
-echo -n "Perform fork and check eth-wire hard error:"
-gateway_up
-eth_fork 10
-check_balance_eth 999851500 148500
-sleep 5 # Wait for reconnect
-gateway_down
-echo " OK"
-
-echo -n "Recover orphaned transactions:"
-next_eth 6 # More block needed to confirm
-check_balance_eth 999840500 159500
-gateway_up
-echo " OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/eth/stress.sh b/test/eth/stress.sh
deleted file mode 100755
index d36aea2..0000000
--- a/test/eth/stress.sh
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/bin/bash
-
-## Test eth-wire ability to recover from errors in correctness critical paths 
and prevent concurrent sending
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_eth.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start ethereum node"
-init_eth --miner.gasprice 0
-echo "Start stressed eth-wire"
-stress_eth_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 30"
-
-echo  "----- Handle incoming -----"
-
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS credit $CLIENT $WIRE 0.000 `$SEQ`
-next_eth # Trigger eth-wire
-echo " OK"
-
-echo -n "Requesting exchange incoming transaction list:"
-check_delta "incoming?delta=-100" "$SEQ" "0.000"
-echo " OK"
-
-echo -n "Check balance:"
-check_balance_eth 999580000 420000
-echo " OK"
-
-echo  "----- Handle outgoing -----"
-
-echo -n "Making wire transfer from exchange:"
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://ethereum/$CLIENT \
-        -a $CURRENCY:0.0000$n > /dev/null
-done
-sleep 1
-next_eth # Mine transactions
-echo " OK"
-
-echo -n "Requesting exchange's outgoing transaction list:"
-check_delta "outgoing?delta=-100" "$SEQ"
-echo " OK"
-
-echo -n "Check balance:"
-check_balance_eth 999622000 378000
-echo " OK"
-
-echo "----- Recover DB -----"
-
-echo "Reset database"
-reset_db
-mine_eth 1 # Trigger worker
-sleep 10
-
-echo -n "Requesting exchange incoming transaction list:"
-check_delta "incoming?delta=-100" "$SEQ" "0.000"
-echo " OK"
-
-echo -n "Requesting exchange outgoing transaction list:"
-check_delta "outgoing?delta=-100" "$SEQ"
-echo " OK"
-
-echo -n "Balance have not changed:"
-check_balance_eth 999622000 378000
-echo " OK"
-
-echo  "----- Handle bounce -----"
-
-echo -n "Bounce:"
-$WIRE_UTILS send $CLIENT $WIRE 0.000 `$SEQ`
-sleep 1
-next_eth
-echo " OK"
-
-echo -n "Check balance:"
-check_balance_eth 999601000 399000
-echo " OK"
-
-echo "----- Recover DB -----"
-
-echo "Reset database"
-reset_db
-mine_eth 1 # Trigger worker
-sleep 10
-
-echo -n "Requesting exchange incoming transaction list:"
-check_delta "incoming?delta=-100" "$SEQ" "0.000"
-echo " OK"
-
-echo -n "Requesting exchange outgoing transaction list:"
-check_delta "outgoing?delta=-100" "$SEQ"
-echo " OK"
-
-echo -n "Balance have not changed:"
-check_balance_eth 999601000 399000
-echo " OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/eth/test.sh b/test/eth/test.sh
deleted file mode 100755
index 021f2f8..0000000
--- a/test/eth/test.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_eth.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start ethereum node"
-init_eth --miner.gasprice 0
-echo ""
-
-echo "----- Test -----"
-cargo run --bin eth-test --release -- $CONF
\ No newline at end of file
diff --git a/test/eth/wire.sh b/test/eth/wire.sh
deleted file mode 100755
index 8533807..0000000
--- a/test/eth/wire.sh
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/bash
-
-## Test eth-wire correctly receive and send transactions on the blockchain
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_eth.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start ethereum node"
-init_eth --miner.gasprice 0
-echo "Start eth-wire"
-eth_wire
-echo "Start gateway"
-gateway
-echo ""
-
-SEQ="seq 10 99"
-
-echo  "----- Receive -----"
-
-echo -n "Making wire transfer to exchange:"
-$WIRE_UTILS credit $CLIENT $WIRE 0.000 `$SEQ`
-next_eth # Trigger eth-wire
-check_balance_eth 995095000 4905000
-echo " OK"
-
-echo -n "Requesting exchange incoming transaction list:"
-check_delta "incoming?delta=-100" "$SEQ" "0.000"
-echo " OK"
-
-echo  "----- Send -----"
-
-echo -n "Making wire transfer from exchange:"
-for n in `$SEQ`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -C payto://ethereum/$CLIENT \
-        -a $CURRENCY:0.0000$n > /dev/null
-done
-sleep 1
-mine_eth # Mine transactions
-check_balance_eth 995585500 4414500
-echo " OK"
-
-echo -n "Requesting exchange's outgoing transaction list:"
-check_delta "outgoing?delta=-100" "$SEQ"
-echo " OK"
-
-echo  "----- Bounce -----"
-
-echo -n "Bounce:"
-$WIRE_UTILS send $CLIENT $WIRE 0.000 `seq 10 40`
-sleep 1
-next_eth
-check_balance_eth 995554500 4445500
-echo " OK"
-
-echo "All tests passed!"
\ No newline at end of file
diff --git a/test/gateway/api.sh b/test/gateway/api.sh
deleted file mode 100755
index f81b7e4..0000000
--- a/test/gateway/api.sh
+++ /dev/null
@@ -1,133 +0,0 @@
-#!/bin/bash
-
-## Test wire-gateway conformance to documentation and its security
-
-set -eu
-
-# Create temp file
-TEMP_FILE=$(mktemp)
-
-# Cleanup to run whenever we exit
-function cleanup() {
-    rm -f $TEMP_FILE
-    wait
-}
-
-# Install cleanup handler (except for kill -9)
-trap cleanup EXIT
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start gateway"
-gateway
-echo ""
-
-echo "----- Gateway API -----"
-
-echo -n "Making wire transfer to exchange:"
-for n in `seq 1 9`; do
-    taler-exchange-wire-gateway-client \
-        -b $BANK_ENDPOINT \
-        -D payto://bitcoin/$CLIENT \
-        -a $CURRENCY:0.0000$n > /dev/null
-done
-echo " OK"
-
-echo -n "Requesting exchange incoming transaction list:"
-ALL=`taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -i`
-for n in `seq 1 9`; do
-    echo $ALL | grep $CURRENCY:0.0000$n > /dev/null
-done
-echo " OK"
-
-echo -n "Making wire transfer from exchange:"
-for n in `seq 1 9`; do
-   taler-exchange-wire-gateway-client \
-    -b $BANK_ENDPOINT \
-    -C payto://bitcoin/$CLIENT \
-    -a $CURRENCY:0.0000$n > /dev/null
-done
-
-echo " OK"
-
-echo -n "Requesting exchange's outgoing transaction list:"
-ALL=`taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -o`
-for n in `seq 1 9`; do
-    echo $ALL | grep $CURRENCY:0.0000$n > /dev/null
-done
-echo " OK"
-
-echo  "----- Endpoint & Method -----"
-
-echo -n "Unknown endpoint:"
-test `curl -w %{http_code} -s -o /dev/null ${BANK_ENDPOINT}test` -eq 404 && 
echo " OK" || echo " Failed"
-
-echo -n "Method not allowed:"
-test `curl -w %{http_code} -s -o /dev/null ${BANK_ENDPOINT}transfer` -eq 405 
&& echo " OK" || echo " Failed"
-
-echo "----- Request format -----"
-
-echo -n "Bad payto url:"
-for bad_payto in http://bitcoin/$CLIENT payto://btc/$CLIENT 
payto://bitcoin/$CLIENT?id=admin payto://bitcoin/$CLIENT#admin; do
-   taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C $bad_payto -a 
$CURRENCY:0.00042 2>&1 | grep -q "(400/24)" && echo -n " OK" || echo " Failed"
-done
-echo ""
-
-echo -n "Bad bitcoin address:"
-taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C 
payto://bitcoin/42$CLIENT -a $CURRENCY:0.00042 2>&1 | grep -q "(400/24)" && 
echo " OK" || echo " Failed"
-
-echo -n "Bad transaction amount:"
-taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C 
payto://bitcoin/$CLIENT -a ATC:0.00042 2>&1 | grep -q "(400/26)" && echo " OK" 
|| echo " Failed"
-
-echo -n "Bad history delta:"
-for bad_delta in incoming outgoing incoming?delta=0 outgoing?delta=0; do
-    test `curl -w %{http_code} -s -o /dev/null 
"${BANK_ENDPOINT}history/$bad_delta"` -eq 400 && echo -n " OK" || echo -n " 
Failed"
-done
-echo ""
-
-echo "----- History delta -----"
-
-for endpoint in incoming outgoing; do
-    echo -n "History $endpoint:"
-    check_delta ${endpoint}?delta=-9 "seq 1 9" && echo -n " OK" || echo -n " 
Failed"
-    check_delta ${endpoint}?delta=9 "seq 1 9" && echo -n " OK" || echo -n " 
Failed"
-    check_delta ${endpoint}?delta=-4 "seq 6 9" && echo -n " OK" || echo -n " 
Failed"
-    check_delta ${endpoint}?delta=4 "seq 1 4" && echo -n " OK" || echo -n " 
Failed"
-    check_delta "${endpoint}?delta=-3&start=5" "seq 2 4" && echo -n " OK" || 
echo -n " Failed"
-    check_delta "${endpoint}?delta=3&start=4" "seq 5 7" && echo -n " OK" || 
echo -n " Failed"
-    echo ""
-done
-
-echo "----- Transfer idempotence -----"
-DATA="{\"request_uid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"amount\":\"$CURRENCY:0.000034\",\"exchange_base_url\":\"$BASE_URL\",\"wtid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"credit_account\":\"payto://bitcoin/$CLIENT\"}"
-echo -n "Same:"
-test `curl -w %{http_code} -s -o /dev/null -H "Content-Type: application/json" 
-d $DATA ${BANK_ENDPOINT}transfer` -eq 200 && echo -n " OK" || echo -n " Failed"
-test `curl -w %{http_code} -s -o /dev/null -H "Content-Type: application/json" 
-d $DATA ${BANK_ENDPOINT}transfer` -eq 200 && echo " OK" || echo " Failed"
-echo -n "Collision:"
-DATA="{\"request_uid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"amount\":\"$CURRENCY:0.000042\",\"exchange_base_url\":\"$BASE_URL\",\"wtid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"credit_account\":\"payto://bitcoin/$CLIENT\"}"
-test `curl -w %{http_code} -s -o /dev/null -H "Content-Type: application/json" 
-d $DATA ${BANK_ENDPOINT}transfer` -eq 409 && echo " OK" || echo " Failed"
-
-echo "----- Security -----"
-
-# Generate big random file
-printf 'HelloWorld%s' {1..1000} > $TEMP_FILE
-
-echo -n "Handle huge body:"
-test `curl -w %{http_code} -X POST -s -o /dev/null -d @$TEMP_FILE 
${BANK_ENDPOINT}transfer` -eq 400 && echo " OK" || echo " Failed"
-
-echo -n "Handle body length liar:"
-test `curl -w %{http_code} -X POST -H"Content-Length:1024" -s -o /dev/null -d 
@$TEMP_FILE ${BANK_ENDPOINT}transfer` -eq 400 && echo " OK" || echo " Failed"
-
-# Generate compression bomb 
-printf 'HelloWorld%s' {1..1000} | pigz -z9 > $TEMP_FILE
-
-echo -n "Handle compression bomb:"
-test `curl -w %{http_code} -X POST -H"Content-Encoding:deflate" -s -o 
/dev/null --data-binary @$TEMP_FILE ${BANK_ENDPOINT}transfer` -eq 400 && echo " 
OK" || echo " Failed"
-
-echo "All tests passed!"
diff --git a/test/gateway/auth.sh b/test/gateway/auth.sh
deleted file mode 100755
index 240f22e..0000000
--- a/test/gateway/auth.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-
-## Test wire-gateway authentication
-
-set -eu
-
-source "${BASH_SOURCE%/*}/../common.sh"
-CONFIG=taler_btc_auth.conf
-
-echo  "----- Setup -----"
-echo "Load config file"
-load_config
-echo "Start bitcoin node"
-init_btc
-echo "Start gateway"
-gateway
-echo ""
-
-echo "----- Authentication -----"
-
-echo -n "Check 401:"
-test `curl -w %{http_code} -s -o /dev/null ${BANK_ENDPOINT}history/outgoing` 
-eq 401 && echo " OK" || echo " Failed"
-
-echo -n "Check auth:"
-taler-exchange-wire-gateway-client \
-    --config $CONF -s exchange-accountcredentials-admin \
-    -C payto://bitcoin/$CLIENT \
-    -a $CURRENCY:0.0000$n > /dev/null
-echo " OK"
-
-echo "All tests passed!"
diff --git a/uri-pack/Cargo.toml b/uri-pack/Cargo.toml
index 28b46db..b94ce68 100644
--- a/uri-pack/Cargo.toml
+++ b/uri-pack/Cargo.toml
@@ -8,16 +8,16 @@ license = "AGPL-3.0-or-later"
 
 [dependencies]
 # Error macros
-thiserror = "1.0.30"
+thiserror = "1.0.31"
 csv = "1.1.6"
 
 [dev-dependencies]
 # Json parser
-serde_json = "1.0"
+serde_json = "1.0.82"
 # Url parser
 url = "2.2.2"
 # statistics-driven micro-benchmarks
-criterion = "0.3.5"
+criterion = "0.3.6"
 # Fast insecure random
 fastrand = "1.7.0"
 # Fuzzing test
diff --git a/wire-gateway/Cargo.toml b/wire-gateway/Cargo.toml
index bbb27f6..d8cc4dd 100644
--- a/wire-gateway/Cargo.toml
+++ b/wire-gateway/Cargo.toml
@@ -7,36 +7,36 @@ rust-version = "1.56.1"
 
 [dependencies]
 # Http library
-hyper = { version = "0.14.17", features = ["http1", "server", "runtime"] }
+hyper = { version = "0.14.20", features = ["http1", "server", "runtime"] }
 # Hyper compat lib for unix domain socket
 hyperlocal = "0.8.0"
 # Async runtime
-tokio = { version = "1.17.0", features = ["net", "macros", "rt-multi-thread"] }
+tokio = { version = "1.20.0", features = ["net", "macros", "rt-multi-thread"] }
 # Serialization framework
-serde = { version = "1.0.136", features = ["derive"] }
+serde = { version = "1.0.140", features = ["derive"] }
 # Serialization helper
-serde_with = "1.12.0"
+serde_with = "2.0.0"
 # JSON serialization
-serde_json = "1.0.79"
+serde_json = "1.0.82"
 # Url query serialization
 serde_urlencoded = "0.7.1"
 # Error macros
-thiserror = "1.0.30"
+thiserror = "1.0.31"
 # Deflate compression
-miniz_oxide = "0.5.1"
+miniz_oxide = "0.5.3"
 # Async postgres client
-tokio-postgres = { version = "0.7.5" }
-deadpool-postgres = "0.10.1"
+tokio-postgres = { version = "0.7.6" }
+deadpool-postgres = "0.10.2"
 # Socket activation
-listenfd = "0.5.0"
+listenfd = "1.0.0"
 # Common lib
 common = { path = "../common" }
 # Bitcoin types
-bitcoin = { version = "0.27.1" }
+bitcoin = { version = "0.28.1" }
 # Euthereum types
 ethereum-types = { version = "0.13.1", default-features = false }
 # Cli args parser
-clap = { version = "3.1.5", features = ["derive"] }
+clap = { version = "3.2.13", features = ["derive"] }
 
 [features]
 # Enable test admin endpoint
diff --git a/wire-gateway/src/error.rs b/wire-gateway/src/error.rs
index a92210d..9a6fc93 100644
--- a/wire-gateway/src/error.rs
+++ b/wire-gateway/src/error.rs
@@ -1,128 +1,128 @@
-/*
-  This file is part of TALER
-  Copyright (C) 2022 Taler Systems SA
-
-  TALER is free software; you can redistribute it and/or modify it under the
-  terms of the GNU Affero General Public License as published by the Free 
Software
-  Foundation; either version 3, or (at your option) any later version.
-
-  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
-
-  You should have received a copy of the GNU Affero General Public License 
along with
-  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
-*/
-use hyper::{header, Body, Response, StatusCode};
-use common::{api_common::ErrorDetail, error_codes::ErrorCode};
-
-/// Generic http error
-#[derive(Debug)]
-pub struct ServerError {
-    pub status: StatusCode,
-    content: Content,
-    pub msg: String,
-}
-
-#[derive(Debug)]
-enum Content {
-    None,
-    Json(Vec<u8>),
-}
-
-impl ServerError {
-    fn new(status: StatusCode, content: Content, msg: String) -> Self {
-        Self {
-            status,
-            content,
-            msg,
-        }
-    }
-
-    pub fn response(self) -> (Response<Body>, String) {
-        let builder = Response::builder().status(self.status);
-        let result = match self.content {
-            Content::None => builder.body(Body::empty()),
-            Content::Json(it) => builder
-                .header(header::CONTENT_TYPE, "application/json")
-                .body(Body::from(it)),
-        };
-        (result.unwrap(), self.msg)
-    }
-
-    pub fn unexpected<E: std::error::Error>(e: E) -> Self {
-        Self::new(
-            StatusCode::INTERNAL_SERVER_ERROR,
-            Content::None,
-            format!("unexpected: {}", e),
-        )
-    }
-
-    fn detail(status: StatusCode, code: ErrorCode, msg: String) -> Self {
-        let detail = ErrorDetail {
-            code: code as i64,
-            hint: None,
-            detail: None,
-            parameter: None,
-            path: None,
-            offset: None,
-            index: None,
-            object: None,
-            currency: None,
-            type_expected: None,
-            type_actual: None,
-        };
-        match serde_json::to_vec(&detail) {
-            Ok(json) => Self::new(status, Content::Json(json), msg),
-            Err(e) => Self::unexpected(e),
-        }
-    }
-
-    pub fn status(status: StatusCode) -> Self {
-        Self::new(
-            status,
-            Content::None,
-            status.canonical_reason().unwrap_or("").to_string(),
-        )
-    }
-
-    pub fn code(status: StatusCode, code: ErrorCode) -> Self {
-        Self::detail(
-            status,
-            code,
-            format!(
-                "standard {}: {}",
-                code as i64,
-                status.canonical_reason().unwrap_or("")
-            ),
-        )
-    }
-
-    pub fn catch_code<E: std::error::Error>(e: E, status: StatusCode, code: 
ErrorCode) -> Self {
-        Self::detail(status, code, format!("standard {}: {}", code as i64, e))
-    }
-}
-
-impl From<tokio_postgres::Error> for ServerError {
-    fn from(e: tokio_postgres::Error) -> Self {
-        ServerError::catch_code(
-            e,
-            StatusCode::BAD_GATEWAY,
-            ErrorCode::GENERIC_DB_FETCH_FAILED,
-        )
-    }
-}
-pub trait CatchResult<T: Sized> {
-    fn unexpected(self) -> Result<T, ServerError>;
-    fn catch_code(self, status: StatusCode, code: ErrorCode) -> Result<T, 
ServerError>;
-}
-
-impl<T, E: std::error::Error> CatchResult<T> for Result<T, E> {
-    fn unexpected(self) -> Result<T, ServerError> {
-        self.map_err(|e| ServerError::unexpected(e))
-    }
-
-    fn catch_code(self, status: StatusCode, code: ErrorCode) -> Result<T, 
ServerError> {
-        self.map_err(|e| ServerError::catch_code(e, status, code))
-    }
-}
+/*
+  This file is part of TALER
+  Copyright (C) 2022 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+use common::{api_common::ErrorDetail, error_codes::ErrorCode};
+use hyper::{header, Body, Response, StatusCode};
+
+/// Generic http error
+#[derive(Debug)]
+pub struct ServerError {
+    pub status: StatusCode,
+    content: Content,
+    pub msg: String,
+}
+
+#[derive(Debug)]
+enum Content {
+    None,
+    Json(Vec<u8>),
+}
+
+impl ServerError {
+    fn new(status: StatusCode, content: Content, msg: String) -> Self {
+        Self {
+            status,
+            content,
+            msg,
+        }
+    }
+
+    pub fn response(self) -> (Response<Body>, String) {
+        let builder = Response::builder().status(self.status);
+        let result = match self.content {
+            Content::None => builder.body(Body::empty()),
+            Content::Json(it) => builder
+                .header(header::CONTENT_TYPE, "application/json")
+                .body(Body::from(it)),
+        };
+        (result.unwrap(), self.msg)
+    }
+
+    pub fn unexpected<E: std::error::Error>(e: E) -> Self {
+        Self::new(
+            StatusCode::INTERNAL_SERVER_ERROR,
+            Content::None,
+            format!("unexpected: {}", e),
+        )
+    }
+
+    fn detail(status: StatusCode, code: ErrorCode, msg: String) -> Self {
+        let detail = ErrorDetail {
+            code: code as i64,
+            hint: None,
+            detail: None,
+            parameter: None,
+            path: None,
+            offset: None,
+            index: None,
+            object: None,
+            currency: None,
+            type_expected: None,
+            type_actual: None,
+        };
+        match serde_json::to_vec(&detail) {
+            Ok(json) => Self::new(status, Content::Json(json), msg),
+            Err(e) => Self::unexpected(e),
+        }
+    }
+
+    pub fn status(status: StatusCode) -> Self {
+        Self::new(
+            status,
+            Content::None,
+            status.canonical_reason().unwrap_or("").to_string(),
+        )
+    }
+
+    pub fn code(status: StatusCode, code: ErrorCode) -> Self {
+        Self::detail(
+            status,
+            code,
+            format!(
+                "standard {}: {}",
+                code as i64,
+                status.canonical_reason().unwrap_or("")
+            ),
+        )
+    }
+
+    pub fn catch_code<E: std::error::Error>(e: E, status: StatusCode, code: 
ErrorCode) -> Self {
+        Self::detail(status, code, format!("standard {}: {}", code as i64, e))
+    }
+}
+
+impl From<tokio_postgres::Error> for ServerError {
+    fn from(e: tokio_postgres::Error) -> Self {
+        ServerError::catch_code(
+            e,
+            StatusCode::BAD_GATEWAY,
+            ErrorCode::GENERIC_DB_FETCH_FAILED,
+        )
+    }
+}
+pub trait CatchResult<T: Sized> {
+    fn unexpected(self) -> Result<T, ServerError>;
+    fn catch_code(self, status: StatusCode, code: ErrorCode) -> Result<T, 
ServerError>;
+}
+
+impl<T, E: std::error::Error> CatchResult<T> for Result<T, E> {
+    fn unexpected(self) -> Result<T, ServerError> {
+        self.map_err(|e| ServerError::unexpected(e))
+    }
+
+    fn catch_code(self, status: StatusCode, code: ErrorCode) -> Result<T, 
ServerError> {
+        self.map_err(|e| ServerError::catch_code(e, status, code))
+    }
+}

-- 
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]