depolymerization

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

commit 030cdd268d53235980bef1228e499fb0941a36f3
parent 7e21b985ebb1e4c68e459e3f4a49e1202c0a0f7b
Author: Emmanuel Benoist <emmanuel.benoist@bfh.ch>
Date:   Thu,  2 Jun 2022 01:58:48 +0200

Merge branch 'master' of ssh://git.taler.net/depolymerization

Diffstat:
M.gitignore | 1+
MCargo.lock | 24++++++++++++------------
MREADME.md | 48++++++++++++++++++++++++++----------------------
Mbtc-wire/README.md | 2+-
Mbtc-wire/src/bin/segwit-demo.rs | 37++++++++++++++++++++++++++++---------
Mbtc-wire/src/loops/worker.rs | 2+-
Mbtc-wire/src/main.rs | 2++
Mbtc-wire/src/rpc.rs | 2+-
Mcommon/src/metadata.rs | 2+-
Adocs/figures/reorg.tex | 35+++++++++++++++++++++++++++++++++++
Mdocs/figures/settlement_layer.tex | 4++++
Mdocs/literature.bib | 19+++++++++++++++++--
Mdocs/presentation.tex | 14+++++++-------
Mdocs/report.tex | 307+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Adocs/tables/5-11.tex | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Meth-wire/src/bin/eth-wire-utils.rs | 45+++++++--------------------------------------
Meth-wire/src/loops/worker.rs | 2+-
Meth-wire/src/rpc.rs | 24++++++++----------------
Minstrumentation/README.md | 5+++--
Mtest/btc/analysis.sh | 0
Mtest/btc/bumpfee.sh | 0
Mtest/btc/config.sh | 0
Mtest/btc/conflict.sh | 0
Mtest/btc/hell.sh | 2+-
Mtest/btc/lifetime.sh | 0
Mtest/btc/maxfee.sh | 0
Mtest/btc/reconnect.sh | 0
Mtest/btc/reorg.sh | 2+-
Mtest/btc/stress.sh | 0
Mtest/btc/wire.sh | 0
Mtest/common.sh | 30+++++++++++++++++-------------
Mtest/conf/bitcoin.conf | 0
Mtest/conf/bitcoin2.conf | 0
Mtest/conf/bitcoin_auth0.conf | 0
Mtest/conf/bitcoin_auth1.conf | 0
Mtest/conf/bitcoin_auth2.conf | 0
Mtest/conf/bitcoin_auth3.conf | 0
Mtest/conf/bitcoin_auth4.conf | 0
Mtest/conf/bitcoin_auth5.conf | 0
Mtest/conf/taler_btc.conf | 0
Mtest/conf/taler_btc_auth.conf | 0
Mtest/conf/taler_btc_bump.conf | 0
Mtest/conf/taler_btc_lifetime.conf | 0
Mtest/conf/taler_eth.conf | 0
Mtest/conf/taler_eth_bump.conf | 0
Mtest/conf/taler_eth_lifetime.conf | 0
Mtest/eth/analysis.sh | 0
Mtest/eth/bumpfee.sh | 0
Mtest/eth/hell.sh | 2+-
Mtest/eth/lifetime.sh | 0
Mtest/eth/maxfee.sh | 0
Mtest/eth/reconnect.sh | 0
Mtest/eth/reorg.sh | 2+-
Mtest/eth/stress.sh | 0
Mtest/eth/test.sh | 0
Mtest/eth/wire.sh | 0
Mtest/gateway/api.sh | 0
Mtest/gateway/auth.sh | 0
Mwire-gateway/README.md | 4++--
Mwire-gateway/src/main.rs | 2+-
60 files changed, 477 insertions(+), 263 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -8,5 +8,6 @@ log !/docs/*.bib !/docs/media !/docs/figures +!/docs/tables /tmp taler.conf \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock @@ -454,9 +454,9 @@ dependencies = [ [[package]] name = "deadpool-postgres" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46ff1451a33b8b31b15eedcf5401dbbb28606caed4fa94d20487eb3fac2ebd04" +checksum = "c668a58063c6331e3437e3146970943ad82b1b36169fd979bb2645ac2088209a" dependencies = [ "deadpool", "log", @@ -817,9 +817,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.17" +version = "0.14.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd" +checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" dependencies = [ "bytes", "futures-channel", @@ -975,9 +975,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" dependencies = [ "cfg-if", ] @@ -1422,9 +1422,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0" dependencies = [ "bitflags", ] @@ -1789,9 +1789,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" dependencies = [ "itoa 1.0.1", "libc", @@ -1801,9 +1801,9 @@ dependencies = [ [[package]] name = "time-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" [[package]] name = "tiny-keccak" diff --git a/README.md b/README.md @@ -45,12 +45,14 @@ Depolymerizer require: ### Initialization -We expect you to have already have written a [configuration](#configuration) and +We expect you to already have written a [configuration](#configuration) and that PostgreSQL and the node (bitcoind or geth) is configured and running. -We will use `btc-wire` in command, but you can use `eth-wire` interchangeably to depolymerize Ethereum. +We will use `btc-wire` in command, but you can use `eth-wire` interchangeably to +depolymerize Ethereum. -If you want to use a specific configuration file, you can add `-c CONF_PATH` to every command. +If you want to use a specific configuration file, you can add `-c CONF_PATH` to +every command. #### Database initialization @@ -60,13 +62,15 @@ btc-wire initdb #### Wallet initialization -Depolymerization uses an encrypted wallet, so you need to provide a password in the environment variable `PASSWORD`. +Depolymerization uses an encrypted wallet, so you need to provide a password in +the environment variable `PASSWORD`. ``` btc-wire initwallet ``` -You then need to update your configuration with the provided `PAYTO` config value. +You then need to update your configuration with the provided `PAYTO` config +value. #### Start depolymerization @@ -74,7 +78,8 @@ You then need to update your configuration with the provided `PAYTO` config valu btc-wire ``` -You also need to run the wire gateway `wire-gateway`. It can run from another user as long it can access the database and the configuration file. +You also need to run the wire gateway `wire-gateway`. It can run from another +user as long it can access the database and the configuration file. ## Configuration @@ -133,7 +138,7 @@ to connect to the RPC server. Two flags are mandatory: - `maxtxfee=?`: bitcoin transactions fees can exceed taler wire fees, putting your wire in bankruptcy. You must specify an acceptable transaction fee cap. -It is also recommanded to disable RPC client timeout with `rpcservertimeout=0` +It is also recommended to disable RPC client timeout with `rpcservertimeout=0` or to set a timeout delay superior than the block delay (e.g `rpcservertimeout=720`) to prevent recurrent "Broken pipe" errors. @@ -203,15 +208,15 @@ BUMP_DELAY = 0 ## Security -Depolymerizer only use an encrypted wallet and provide an easy way to create -them. It is the administrator's responsibility to back up its wallet and +Depolymerizer only use an encrypted wallet and provides an easy way to create +them. It is the administrator's responsibility to back up his wallet and password. -Only the wire adapter need to have the password stored in its environment. +Only the wire adapter needs to have the password stored in its environment. ## Log format -Wire log use an ASCII code for transaction logs: +Wire logs use an ASCII code for transaction logs: - `<<` for a credit - `>>` for a debit @@ -219,21 +224,20 @@ Wire log use an ASCII code for transaction logs: You can have an additional context: -- `bump ` stuck transaction have been bumped -- `conflict ` transaction have been canceled by a conflicting blockchain +- `bump ` a stuck transaction has been bumped +- `conflict ` a transaction has been canceled by a conflicting blockchain transaction -- `recovered ` successful transaction that we failed to register in the local - database have been found in the blockchain -- `onchain ` unknown transaction have been found in the blockchain +- `recovered ` a successful transaction that we failed to register in the local + database has been found in the blockchain +- `onchain ` an unknown transaction has been found in the blockchain ## Test -Instrumentation test documentation can be founded in the -[instrumentation](instrumentation/README.md) directory. +Instrumentation test documentation can be founded in the [instrumentation](instrumentation/README.md) directory. -### Unit test +### Local testing -Unit test require additional binaries. The following binaries must be in the +Local tests require additional binaries. The following binaries must be in the local user PATH: - `pg_ctl` and `psql` from PostgreSQL @@ -243,8 +247,8 @@ local user PATH: - `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 downloads and extract -blockchain binaries and find the path of the local postgres installation. +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 | diff --git a/btc-wire/README.md b/btc-wire/README.md @@ -63,7 +63,7 @@ Make sure the amount show 0.10000588 BTC, else you have to change the base unit ### Stuck transaction -We resolve stuck transaction by always sending replaceable transaction using +We resolve stuck transactions by always sending replaceable transactions using [BIP 125](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki). TODO diff --git a/btc-wire/src/bin/segwit-demo.rs b/btc-wire/src/bin/segwit-demo.rs @@ -1,14 +1,17 @@ -use bitcoin::Amount; +use std::str::FromStr; + +use bitcoin::{Address, Amount, Network}; use btc_wire::{rpc_utils, segwit::encode_segwit_addr}; +use btc_wire::{segwit::decode_segwit_msg}; use common::{ base32::{self, Alphabet}, rand_slice, }; pub fn main() { - let address = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"; - let amount = Amount::from_sat(10000000); - let reserve_pub = "0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00"; + let address = Address::from_str("tb1qhxrhccqexg0dv4nltgkuw4fg2ce7muplmjsn0v").unwrap(); + let amount = Amount::from_sat(5000000); + let reserve_pub = "54ZN9AMVN1R0YZ68ZPVHHQA4KZE1V037M05FNMYH4JQ596YAKJEG"; let btc = amount.as_btc(); println!("Ⅰ - Parse payto uri"); @@ -49,8 +52,13 @@ pub fn main() { hex::encode(&second_half) ); // bech32: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki - let first = encode_segwit_addr("bc", first_half[..].try_into().unwrap()); - let second = encode_segwit_addr("bc", second_half[..].try_into().unwrap()); + let hrp = match address.network { + Network::Bitcoin => "bc", + Network::Testnet | Network::Signet => "tb", + Network::Regtest => "bcrt", + }; + let first = encode_segwit_addr(hrp, first_half[..].try_into().unwrap()); + let second = encode_segwit_addr(hrp, second_half[..].try_into().unwrap()); println!( "Encode each half using bech32 to generate a segwit address:\n{}\n{}", first, second @@ -60,14 +68,25 @@ pub fn main() { let minimum = rpc_utils::segwit_min_amount().as_btc(); println!("Send a single bitcoin transaction with the three addresses as recipient as follow:"); println!("\nIn bitcoincore wallet use 'Add Recipient' button to add two additional recipient and copy adresses and amounts"); - for (address, amount) in [(address, btc), (&first, minimum), (&second, minimum)] { + let first = Address::from_str(&first).unwrap(); + let second = Address::from_str(&second).unwrap(); + for (address, amount) in [(&address, btc), (&first, minimum), (&second, minimum)] { println!("{} {:.8} BTC", address, amount); } println!("\nIn Electrum wallet paste the following three lines in 'Pay to' field :"); - for (address, amount) in [(address, btc), (&first, minimum), (&second, minimum)] { + for (address, amount) in [(&address, btc), (&first, minimum), (&second, minimum)] { println!("{},{:.8}", address, amount); } println!( "Make sure the amount show 0.10000588 BTC, else you have to change the base unit to BTC" - ) + ); + + + 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()[..])); } diff --git a/btc-wire/src/loops/worker.rs b/btc-wire/src/loops/worker.rs @@ -186,7 +186,7 @@ fn sync_chain( (txs, removed, list.lastblock) }; - // Check if a confirmed incoming transaction have been removed by a blockchain reorganisation + // Check if a confirmed incoming transaction have been removed by a blockchain reorganization let new_status = sync_chain_removed(&txs, &removed, rpc, db, conf_delay as i32)?; // Sync status with database diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs @@ -110,6 +110,7 @@ fn init(config: Option<PathBuf>, init: Init) -> LoopResult<()> { rpc.load_wallet(WIRE_WALLET_NAME).ok(); // Load previous address + // TODO Use address label instead of the database ? let prev_addr = db.query_opt("SELECT value FROM state WHERE name = 'addr'", &[])?; let addr = if let Some(row) = prev_addr { sql_addr(&row, 0) @@ -158,6 +159,7 @@ fn run(config: Option<PathBuf>) { Network::Regtest => "regtest", }; info!("Running on {} chain", chain_name); + // TODO Check wire wallet own config PAYTO address let rpc_watcher = auto_rpc_common(state.btc_config.clone()); let rpc_analysis = auto_rpc_common(state.btc_config.clone()); diff --git a/btc-wire/src/rpc.rs b/btc-wire/src/rpc.rs @@ -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()?; diff --git a/common/src/metadata.rs b/common/src/metadata.rs @@ -62,7 +62,7 @@ impl OutMetadata { } OutMetadata::Bounce { bounced } => { buffer.push(BOUNCE_BYTE); - buffer.extend_from_slice(bounced.as_slice()); + buffer.extend_from_slice(bounced.as_ref()); } } return Ok(buffer); diff --git a/docs/figures/reorg.tex b/docs/figures/reorg.tex @@ -0,0 +1,34 @@ +\begin{tikzpicture}[ + block/.style={rectangle,draw=black,fill=black!10,minimum size=7mm}, + conf/.style={draw=black!60!green,fill=black!60!green!10}, + ar/.style={-stealth} + ] + % Common + \node[block](1){}; + \node[block,right=5mm of 1](2){}; + \node[block,right=5mm of 2](3){}; + \draw[ar] (1) -- (2); + \draw[ar] (2) -- (3); + + % Current + \node[block,right=5mm of 3](4){}; + \node[block,right=5mm of 4](5){}; + \node[block,right=5mm of 5](6){}; + \draw[ar] (3) -- (4); + \draw[ar] (4) -- (5); + \draw[ar] (5) -- (6); + + % Fork + \node[block,above=7mm of 4](4p){}; + \node[block,right=5mm of 4p](5p){}; + \node[block,right=5mm of 5p](6p){}; + \node[block,right=5mm of 6p](7p){}; + \draw[ar] (3.east) -- (4p.west); + \draw[ar] (4p) -- (5p); + \draw[ar] (5p) -- (6p); + \draw[ar] (6p) -- (7p); + + % Indication + \node [right=5mm of 7p]{\emph{fork}}; + \node [right=17mm of 6]{\emph{active}}; +\end{tikzpicture} +\ No newline at end of file diff --git a/docs/figures/settlement_layer.tex b/docs/figures/settlement_layer.tex @@ -45,4 +45,8 @@ \node[right=50mm of D] {\small{Debit}}; \draw[dashed,-stealth] (1.north) |- (off.west); \draw[dashed,-stealth] (off.east) -| (6.north); + + %% Separation + \draw[dotted] (-2.1,-1.4) -- (9,-1.4); + \draw[dotted] (-2.1,-2.6) -- (9,-2.6); \end{tikzpicture} \ No newline at end of file diff --git a/docs/literature.bib b/docs/literature.bib @@ -56,4 +56,20 @@ pages = {3--22}, year = {2019}, publisher = {Springer} -} -\ No newline at end of file +} + +@phdthesis{dold2019gnu, + title = {The GNU Taler system: practical and provably secure electronic payments}, + author = {Dold, Florian}, + year = {2019}, + school = {Universit{\'e} Rennes 1} +} + +@inproceedings{burdges2016enabling, + title = {Enabling secure web payments with GNU Taler}, + author = {Burdges, Jeffrey and Dold, Florian and Grothoff, Christian and Stanisci, Marcello}, + booktitle = {International Conference on Security, Privacy, and Applied Cryptography Engineering}, + pages = {251--270}, + year = {2016}, + organization = {Springer} +} diff --git a/docs/presentation.tex b/docs/presentation.tex @@ -168,7 +168,7 @@ \end{block} \end{frame} -\begin{frame}{Blockchain challenges}{Chain reorganisation} +\begin{frame}{Blockchain challenges}{Chain reorganization} \begin{center} \begin{tikzpicture}[ block/.style={rectangle,draw=black,fill=black!10,minimum size=7mm}, @@ -206,7 +206,7 @@ \end{center} A fork is when concurrent blockchain states coexist. Nodes will follow the longest chain, replacing recent blocks if necessary during a - blockchain reorganisation. If a deposit transaction disappears from the + blockchain reorganization. If a deposit transaction disappears from the blockchain, an irrevocable withdraw transactions would no longer be backed by credit. \end{frame} @@ -301,7 +301,7 @@ \end{block} \end{frame} -\begin{frame}{Handling blockchain reorganisation} +\begin{frame}{Handling blockchain reorganization} \begin{center} \begin{tikzpicture}[ block/.style={rectangle,draw=black,fill=black!10,minimum size=7mm}, @@ -350,9 +350,9 @@ \node [right=17mm of 6]{\emph{active}}; \end{tikzpicture} \end{center} - \only<1>{As small reorganisations are common, Satoshi already recommended to + \only<1>{As small reorganizations are common, Satoshi already recommended to apply a confirmation delay to handle most disturbances and attacks.} - \only<2>{If a reorganisation longer than the confirmation delay happens, + \only<2>{If a reorganization longer than the confirmation delay happens, but it did not remove credits, Depolymerizer is safe and automatically resumes.} \only<3>{If a fork removed a confirmed debit, an attacker may create a @@ -415,8 +415,8 @@ \draw[confl,thick,dotted](I) -- (Ip); \end{tikzpicture} \end{center} - If we experience a reorganisation once, its dangerously likely for another - one of a similar scope to happen again. Depolymerizer learns from reorganisations + If we experience a reorganization once, its dangerously likely for another + one of a similar scope to happen again. Depolymerizer learns from reorganizations by increasing its confirmation delay. \end{frame} diff --git a/docs/report.tex b/docs/report.tex @@ -16,14 +16,30 @@ \affil{Bern University of Applied Sciences} \date{\today} -\DeclareAcronym{dlt}{ +\DeclareAcronym{DLT}{ short=DLT, long=Distributed Ledger, } -\DeclareAcronym{dos}{ +\DeclareAcronym{DOS}{ short=DOS, long=Denial of service, } +\DeclareAcronym{BIP}{ + short=BIP, + long=Bitcoin Improvement Proposal, +} +\DeclareAcronym{RPC}{ + short=RPC, + long=Remote Procedure Call +} +\DeclareAcronym{API}{ + short=API, + long=Application programming interface +} +\DeclareAcronym{HTTP}{ + short=HTTP, + long=Hypertext Transfer Protocol +} \begin{document} @@ -33,13 +49,17 @@ \subsection*{Abstract} -GNU Taler is an electronic payment system implemented as free software. The goal of this project is to enable payment with blockchain-based cryptocurrency in GNU Taler. +GNU Taler is an electronic payment system implemented as free software. The goal of this project is to enable payment with blockchain-based cryptocurrencies. -By proving that blockchains can be used as a settlement layer for GNU Taler, we show that it is not only capable of handling bank money, but also widely used cryptocurrencies. +To achieve this goal, we need to understand how the distributed ledgers of blockchain-based cryptocurrencies work, what their limitations are, and how to mitigate them so that they can serve as a settlement layer. Key challenges include finding a reliable way to write metadata to the blockchain, handling blockchain reorganization, and resolving stuck transactions. + +Blockchain reorganization prevents the finality of blockchain transactions, which is unacceptable for a settlement layer. By using a confirmation delay, we can create a semblance of finality. However, we still have to handle extreme cases where our delay is insufficient by suspending operations and gracefully recovering when possible. -For cryptocurrencies owners, this integration offers a new solution for instant and low-cost payments that can scale beyond blockchains limitations while preserving or enhancing privacy. +We have created a depolymerizer, which acts as an adapter between GNU Taler and a \ac{DLT}, allowing their use as a settlement layer. By using official DLT clients, and separating Taler specific components from \ac{DLT} specific components, we achieved a simple and maintainable design. -To achieve this goal, we need to understand how blockchain-based cryptocurrencies work, what their limitations are, and how to mitigate them so that they can serve as a settlement layer. +By proving that blockchains can be used as a settlement layer for GNU Taler, we show that it is not only capable of handling bank money, but also widely used cryptocurrencies. + +For cryptocurrencies owners, this integration offers a new solution for instant and low-cost payments that can scale beyond \ac{DLT} limitations while preserving or enhancing privacy. \subsection*{Acknowledgement} @@ -61,48 +81,56 @@ Bitcoin is the first cryptocurrency to achieve a successful public rollout. Inve \subsubsection*{Ethereum} -Bitcoin is focused on currency transfer transactions and some people wanted to do more with cryptocurrencies, to be able to execute smart contracts (programs) with the same guarantee as a currency transfer transaction. Ethereum is that cryptocurrency. After eighteen months of crowdfunded development, Ethereum launched in July 2015. +Bitcoin is focused on currency transfer transactions and some people wanted to do more with cryptocurrencies, to be able to run smart contracts (programs) with the same guarantee as a currency transfer transaction. Ethereum is built to meet this expectation. After eighteen months of crowdfunding-funded development, Ethereum was launched in July 2015. \subsection{Blockchain} -At the heart of these currencies is a blockchain. A blockchain is an append-only database composed of a list of linked records called blocks. The content of each block, except the genesis block (the first block), depends on the content of its parent block. This chained dependency enforces the immutability of the database, preventing retroactive modification whiteout altering all subsequent blocks. Cryptocurrency transactions takes effect when they are stored inside those blocks. +At the heart of these currencies is a blockchain. A blockchain is an append-only database composed of a list of linked records called blocks. The content of each block, except the genesis block (the first block), depends on the content of its parent block. This chained dependency enforces the immutability of the database, preventing retroactive modification without altering all subsequent blocks. Cryptocurrency transactions take effect when they are stored inside those blocks. \subsection{Consensus} -The blockchain itself is just a storage system. To make it a \acf{dlt}, it needs a peer-to-peer network to share its changes. But also a way for participants (nodes) to agree on a single state of the chain, to reach consensus in a network where nodes can be malicious and have an economic interest in deceiving others. There are many ways to create such consensus, but only two of them interest us: proof of work and proof of stake. - -% DLT definition ? +The blockchain itself is just a storage system. To make it a \ac{DLT}, it needs a peer-to-peer network to share its changes. But also a way for participants (nodes) to agree on a single state of the chain, to reach consensus in a network where nodes can be malicious and have an economic interest in deceiving others. There are many ways to create such consensus, but only two of them interest us: proof of work and proof of stake. \subsubsection*{Proof of work} This mechanism consists in making the process of appending a block to the blockchain heavy in computation (mining) by requiring brute force hashing for example. Nodes willing to invest their computation power (miners), work to extend the chain they consider the current state. Over time, the longest chain will be the one where the majority of computing power has been invested, which means that it is the one followed by the majority of miners. -This falls short as soon as one node control significantly more computation power than others, the so-called 51\% attacks. This node will not be able to create invalid blocks, because the other nodes will reject them, but will be able to rewrite the past and control the mining of future transactions. +This falls short as soon as one node control significantly more computation power than others. This node will not be able to create invalid blocks, because the other nodes will reject them, but will be able to revise transaction history and control the mining of future transactions. This is a majority attack also known as the 51\% attack. Another problem is that miners are incentivized to invest more and more computing power, which leads to ever-increasing energy consumption and ecological impact. These problems have motivated the search for another mechanism: proof of stake. \subsubsection*{Proof of stake} -This mechanism replaces the use of computing power with the stacking of money. Validators (who replace miners) stake large sums of money to be randomly selected to validate blocks. In case of malicious behavior, the stacked money is burned by other validators. +This mechanism replaces the use of computing power with the stacking of money. Validators (who replace miners) stake large sums of money to be allowed to verify blocks and be randomly selected to propose them. In case of malicious behaviour, the stacked money is burned by other validators. The effectiveness and security of this mechanism have yet to be proven, but Ethereum plans to adopt it in the summer of 2022. \subsubsection*{Block time} -Achieving consensus within the peer-to-peer network requires broadcasting the state of the blockchain to most nodes. This coordination takes some time and we do not want blocks to be mined faster than the network can keep up. An adaptive difficulty algorithm is used to keep the block time close to a constant, by changing the amount of computation required to mine a block. On Ethereum, the block time is about 12 to 14 seconds \footnote{https://ethereum.org/en/developers/docs/blocks/\#block-time}. On Bitcoin, the block time is about 10 minutes. +Achieving consensus within the peer-to-peer network requires broadcasting the state of the blockchain to most nodes. This coordination takes some time, and we do not want blocks to be mined faster than the network can keep up. An adaptive difficulty algorithm is used to keep the block time close to a constant, by changing the amount of computation required to mine a block. On Ethereum, the block time is about 12 to 14 seconds\footnote{https://ethereum.org/en/developers/docs/blocks/\#block-time}. On Bitcoin, the block time is about 10 minutes. This limitation combined with a block size limit, creates a transaction rate and a blockchain size growth limit that is difficult to change without disrupting the security of the system. + +\subsubsection*{Reorganization} -\subsubsection*{Reorganisation} +These decentralized consensus mechanisms lead to the creation of competing blockchain states. When two miners broadcast a new valid block in a short period of time, one part of the network may receive them in a different order than another part. As nodes will follow the first valid block they found, we have a blockchain fork where two different blockchain states are followed in the network (Figure~\ref{fig:reorg}). + +\begin{figure}[H] + \begin{center} + \input{figures/reorg.tex} + \end{center} + \caption{Blockchain fork} + \label{fig:reorg} +\end{figure} -These decentralized consensus mechanisms lead to the creation of competing blockchain states. When two miners broadcast a new valid block in a short period of time, one part of the network may receive them in a different order than another part. As nodes will follow the first valid block they found, we have a blockchain fork where two different blokchain state are followed in the network. Over time, one fork will become longer than the other, and nodes will follow the longer chain. They will replace recent blocks as necessary during a reorganization of the blockchain. A reorganization can cause a transaction previously considered mined by a node to no longer be mined. Therefore, blockchain transactions lack finality. +Over time, one fork will become longer than the other, and nodes will follow the longest chain. They will replace recent blocks as necessary during a reorganization of the blockchain. Those reorganizations can cause a transaction previously considered mined by a node to no longer be mined. Therefore, blockchain transactions lack finality. \subsection{Mining incentive} -A minimum amount of mining power is required for the cryptocurrency to work. Without new blocks, there can be no new transaction. The more mining power and diversity (different miners), the more resistant the \ac{dlt} is to attacks. Since mining is an expensive process, cryptocurrencies must incentivize it by offering rewards to miners. +A minimum amount of mining power is required for the cryptocurrency to work. Without new blocks, there can be no new transaction. The more mining power and diversity (different miners), the harder it is to attack the \ac{DLT}. Since mining is an expensive process, cryptocurrencies must incentivize it by offering rewards to miners. Rewards are of two kinds: \begin{itemize} \item \textbf{Coin generation} While mining a block, the miner creates money in it that he can use as he pleases. Bitcoins use this type of reward but to reach a constant amount of 21 million bitcoins, this reward decreases over time. - \item \textbf{Transaction fee} Transactions may contain a tip for the miner to encourage mining. Miners will not mine transactions that cost them money and will mine the most profitable transaction first. Transaction fees are then market-based values, the more transactions that are waiting to be mined, the higher the fee you have to pay to in the next block. When a transaction is sent with a fee too small, it may not be mined in a timely fashion. Since transaction fees are unpredictable, it is possible to create stuck transactions. + \item \textbf{Transaction fee} Transactions may contain a tip for the miner to encourage mining. Miners will not mine transactions that cost them money and will mine the most profitable transaction first. Transaction fees are then market-based values, the more transactions there are waiting to be extracted, the higher the fee to be paid to be included in the next block. When a transaction is sent with a fee too small, it may not be mined in a timely fashion. Since transaction fees are unpredictable, transactions sometimes end being stuck for a long time. \end{itemize} \subsection{Blockchain-based cryptocurrencies limitations} @@ -113,99 +141,102 @@ As we have seen, blockchain-based cryptocurrencies have certain limitations by d \section{GNU Taler} -GNU Taler is an electronic payment system implemented as free software. We provide only a superficial overview of GNU Taler necessary to understand how Depolymerization fits into the system. More information can be found in the project documentation and repository. +GNU Taler is an anonymous, taxable payment system implemented as free software and inspired by David Chaum's Ecash \cite{burdges2016enabling} \cite{dold2019gnu}. Taler does not rely on a \ac{DLT}. Taler payments are made using digital form of traditional money anonymized using blind signatures. We provide only a superficial overview of GNU Taler necessary to understand how Depolymerization fits into the system. More information can be found in the project documentation and repository. \subsection{Overview} \begin{figure}[hb] \begin{center} - \input{figures/taler_arch.tex} + \scalebox{1.2}{\input{figures/taler_arch.tex}} \end{center} \caption{GNU Taler overview} \end{figure} -\subsubsection*{Exchange} +\paragraph*{Exchange} The exchange is the payment service provider for financial transactions between customers and merchants. The exchange holds money as a reserve for anonymous digital coins. -\subsubsection*{Customer} -A customer can withdraw coins from the exchange and store them in his electronic wallet. These coins can then be spent at a merchant. +\paragraph*{Customer} +Customers can withdraw coins from the exchange and store them in their electronic wallets. These coins can then be spent at a merchant. -\subsubsection*{Merchant} -A merchant accepts coins in exchange for goods and services. The merchant can then deposit these coins at the exchange to receive money in return. +\paragraph*{Merchant} +Merchants accept coins in exchange for goods and services. They can then deposit these coins at the exchange to receive money in return. -\subsubsection*{Auditor} +\paragraph*{Auditor} Auditors monitor the behaviour of the exchanges to ensure that exchanges operate correctly. They are typically operated by financial regulators. -\subsubsection*{Settlement layer} -The settlement layer provides finality for wire transfers that allow customers to deposit money and merchant to withdraw money from Taler. It is typically provided by banks. The goal of this project is to use blockchains as a settlement layer to support blockchain-based cryptocurrencies. +\paragraph*{Settlement layer} +The settlement layer provides finality for wire transfers that allow customers to deposit money and merchant to withdraw money from Taler. It is typically provided by banks. The goal of this project is to use DLT as a settlement layer to support blockchain-based cryptocurrencies. -\subsection{Blockchain settlement layer} +\subsection{DLT settlement layer} -\begin{figure}[hb] +\begin{figure}[h] \begin{center} + \vspace{0.5em} \input{figures/settlement_layer.tex} \end{center} - \caption{Blockchain settlement layer with Depolymerizer} + \caption{DLT settlement layer with Depolymerizer} + \label{fig:DltSettlement} \end{figure} -Depolymerizer serves as a middleware between GNU taler and cryptocurrencies \ac{dlt}. Customers can send money to the Depolymerizer using an on-chain transaction to get coins that they can use in off-chain transactions. Using the Depolymerizer, Taler exchanges can materialize coins back into the blockchain. +Depolymerizer serves as a middleware between GNU Taler and cryptocurrencies \ac{DLT} (Figure \ref{fig:DltSettlement}). Customers can send money to the Depolymerizer via a credit transaction, to obtain coins that they can use in GNU Taler transactions. Using the Depolymerizer, Taler exchanges can materialize the coins back into the DLT via a debit transaction. -Off-chain transactions have many advantages over on-chain transactions. At the cost of putting trust in exchange operators or auditors, you can have fast and low cost transactions with instant confirmation (ms). GNU Taler offers linear scalability that can solve blockchain throughput limitation and, by not relying on Proof of Work, has a much lower ecological impact. GNU Taler does not sacrifice privacy either; it provides privacy when it can and transparency when it has to (regulation: avoid tax evasion and money laundering). +Off-chain transactions have many advantages over on-chain transactions. At the cost of putting trust in exchange operators or auditors, you can have fast and low cost transactions with instant confirmation (ms). GNU Taler offers linear scalability that can solve DLT throughput limitation and, by not relying on Proof of Work, has a much lower ecological impact. GNU Taler does not sacrifice privacy either; it provides privacy when it can and transparency when it has to (regulation: avoid tax evasion and money laundering). \clearpage \section{Resolving blockchain challenges} -Some properties of blockchain-based cryptocurrencies are problematic for their use as a Taler settlement layer. The two main issues are blockchain reorganisations and stuck transactions. +Some properties of blockchain-based cryptocurrencies are problematic for their use as a Taler settlement layer. The two main issues are blockchain reorganizations and stuck transactions. -\subsection{Solving chain reorganisation} +\subsection{Solving chain reorganization} -Taler expects credits to be final. If a credit disappears from the blockchain, an irrevocable debit would no longer be backed by credit. This problem is well known and already mentioned in the Bitcoin white paper \cite{nakamoto2008bitcoin}. The solution is to wait until a block has a certain amount of blocks linked to it, before considering its transactions final. - -\begin{figure}[H] - \begin{center} - \input{figures/fork.tex} - \end{center} - \caption{Blockchain fork} -\end{figure} - -The choice of this confirmation delay is a compromise between speed and security. The longer you wait, the more resistant you are to attack. But since small reorganisations are common by design, a minimal delay is necessary for proper operation. To be resistant to an adversary with $30\%$ of the total mining power, we need to wait for 6 blocks in Bitcoin ($\approx$ 1h) and 37 blocks in Ethereum ($\approx$ 8min) \cite{gervais2016security}. These are the default values but are configurable. +Taler expects credits to be final. If a credit disappears from the blockchain, an irrevocable debit would no longer be backed by credit. A malicious actor able to rearrange the blockchain at will could use his Taler coins while removing the credit that created those coins and thus get his cryptocurrencies coins back, allowing for double spending. This problem is well known and already mentioned in the Bitcoin white paper \cite{nakamoto2008bitcoin}. The deeper a block is in the blockchain, the harder it is to replace. The depth of a block determines its probability of persistence. The solution is therefore to wait until a block has a certain number of blocks linked to it before considering its transactions as final (Figure \ref{fig:conf_delay}). \begin{figure}[H] \begin{center} + \vspace{0.5em} \input{figures/conf_delay.tex} \end{center} - \caption{Reorganisation mitigation using confirmation delay} + \caption{Reorganization mitigation using confirmation delay} + \label{fig:conf_delay} \end{figure} -Using a confirmation delay does not solve the problem, it only mitigates it. We still have to deal with a potential reorganisation that is longer than our delay. When this happens, we look for any missing confirmed credits, if there are none, we can ignore that reorganisation. +The choice of this confirmation delay is a compromise between speed and security. As small reorganizations are common by design, a minimal delay is necessary for proper operation. To be resistant to an adversary with $30\%$ of the total mining power, we need to wait for 6 blocks in Bitcoin ($\approx$ 1h) and 37 blocks in Ethereum ($\approx$ 8min) \cite{gervais2016security}. + +Using a confirmation delay does not solve the problem, it only mitigates it. We still have to deal with a potential reorganization that is longer than our delay. When this happens, we look for any missing confirmed credits, if there are none, we can ignore that reorganization (Figure \ref{fig:harmless_reorg}). \begin{figure}[H] \begin{center} + \vspace{0.5em} \input{figures/harmless_reorg.tex} \end{center} - \caption{Harmless reorganisation} + \caption{Harmless reorganization} + \label{fig:harmless_reorg} \end{figure} -If confirmed credits have been removed, we will suspend operations. If we are not targeted by an attack and the blockchain network is behaving well, the credits will be mined again and we can wait for them to be confirmed again to resume operations. If the missing credits have been maliciously replaced, we will never be able to resume operation. +If confirmed credits have been removed, we will suspend operations. If we are not targeted by an attack and the DLT network is behaving well, the credits will be mined again, and we can wait for them to be confirmed again to resume operations. In the case where the missing credits have been maliciously replaced (Figure \ref{fig:conflict}) we never resume operation. \begin{figure}[H] \begin{center} + \vspace{0.5em} \input{figures/conflict.tex} \end{center} - \caption{Reorganisation with conflicting transaction} + \caption{Reorganization with conflicting transaction} + \label{fig:conflict} \end{figure} \subsection{Adaptive confirmation} -If we experience a reorganisation once, it is dangerously likely that another one of the same magnitudes will occur again. Depolymerizer learns from reorganisations by increasing its confirmation time. Since we understand that a longer delay can also be counterproductive, we limit the delay adjustment to twice the configured one. +If we experience a reorganization once, it is dangerously likely that another one of the same magnitudes will occur again. Depolymerizer learns from reorganizations by increasing its confirmation time (Figure \ref{fig:analysis}). Since we understand that a longer delay can also be counterproductive, we also want to limit the delay adjustment. \begin{figure}[H] \begin{center} + \vspace{0.5em} \input{figures/analysis.tex} \end{center} \caption{Adaptive confirmation} + \label{fig:analysis} \end{figure} \subsection{Solving stuck transaction} @@ -214,9 +245,9 @@ We know that transactions can get stuck for a long time, which can be problemati \clearpage -\section{Metadata} +\section{Metadata} \label{metadata} -Metadata is needed to link a wallet to credits and allow merchants to link deposits to debits. Metadata is stored alongside transactions in the blockchain, so it is possible to recover the full transaction history of any depolymerizer from it. +GNU Taler need additional metadata to link a wallet to credits and allow merchants to link deposits to debits. Metadata need to be stored alongside transactions in the blockchain, so it is possible to recover the full transaction history of any depolymerizer from it. \subsection{Metadata format} @@ -224,9 +255,9 @@ The goal of our metadata format is to be simple to parse and versioned for futur \subsubsection*{Incoming transaction} -Incoming transaction metadata contains a reserve public key, which is a 32B hash of a Curve25519 public key. We juste prepend a versioning byte to allow future extension. +Incoming transaction metadata contains a reserve public key, which is a 32B hash of a public key. We just prepend a versioning byte to allow future extension. -\begin{figure}[H] +\begin{figure}[h] \begin{center} \begin{bytefield}{33} \bitheader{0,1,32} \\ @@ -238,10 +269,10 @@ Incoming transaction metadata contains a reserve public key, which is a 32B hash \subsubsection*{Outgoing transaction} -Outgoing transactions can be of two types credit or bounce. Credit metadata contains the wire transfer id which is a 32B hash and the exchange base URL which is of variable size. Bounce metadata contains the bounced transaction id which is implementation-dependent but is 32B for Bitcoin and Ethereum. A prepended versioning byte differentiates the two types, 0 being a credit and 254 a bounce. +Outgoing transactions can be of two types: credit or bounce. Credit metadata contains the wire transfer ID which is a 32B hash and the exchange base URL which is of variable size and encoded using uri-packing (Section \ref{uri-packing}). Bounce metadata contains the bounced transaction ID which is implementation-dependent but is 32B for Bitcoin and Ethereum. A prepended versioning byte differentiates the two types, 0 being a credit and 254 a bounce. -\begin{figure}[H] +\begin{figure}[h] \begin{center} \begin{bytefield}[rightcurly=., rightcurlyspace=0pt]{33} \bitheader{0,1,32,33} \\ @@ -260,60 +291,61 @@ Outgoing transactions can be of two types credit or bounce. Credit metadata cont There are many documented ways to encode metadata in a bitcoin transaction \cite{bartoletti2019journey}. In the early days of this cryptocurrency, users abused the transaction format to store metadata, and some of these techniques result in ecosystem pollution. For example, bitcoin clients keep a list of all addresses that currently have money to spend (UTXO), with fake addresses wasting space there indefinitely. To allow storage of a reasonable amount of metadata without polluting the blockchain, a new opcode script OP\_RETURN was created, allowing up to 80B of storage per transaction. -Debits are performed from code using OP\_RETURN to store metadata, but credits are done from common wallet clients and they do not yet support custom metadata. We had to find another format using fake addresses. - -We use the latest address type, segwit addresses, which can contain 20B of chosen data. The reserve pub key being 32B, we need two addresses. Therefore, we use two fake addresses consisting of the two key halves prepended with the same random pattern, except for the first bit, which must be 0 for the first half and 1 for the second. We then send a single transaction with three addresses as recipients. - -\begin{figure}[H] - \begin{center} - \begin{bytefield}[rightcurly=., rightcurlyspace=0pt]{20} - \bitheader{0,3,4,19} \\ - \begin{rightwordgroup}{Address} - \bitbox{4}{ID} & \bitbox{16}{Half} - \end{rightwordgroup} - \end{bytefield} - - \end{center} - \begin{center} - \begin{bytefield}[rightcurly=., rightcurlyspace=0pt]{32} - \bitheader{0,1,31} \\ - \begin{rightwordgroup}{First ID} - \bitbox{1}{\tiny 0} & \bitbox{31}{Random ID} - \end{rightwordgroup} \\ \\ - \begin{rightwordgroup}{Second ID} - \bitbox{1}{\tiny 1} & \bitbox{31}{Random ID} - \end{rightwordgroup} - \end{bytefield} - \end{center} +Debits are performed from our code using OP\_RETURN to store metadata, but credits are done from common wallet clients, and they do not yet support custom metadata. We had to find another format using fake addresses. + +We use the latest address type, segwit addresses \cite{BIP173}, where we can embed 20B of chosen data. Since the reserve pub key is a 32B hash, we need two addresses. Therefore, we use two fake addresses each containing one half of the key prepended by a common random prefix, except for the first bit, which must be 0 for the first half and 1 for the second. We then send a single transaction with three addresses (the exchange address and the two fake) as recipients. + +\begin{figure}[h] + \centering + \begin{tikzpicture} + \draw[dotted,thick] (-6.33,1.13) -- (-6.33,0.185); + \draw[dotted,thick] (-5,1.13) -- (4.3,0.185); + \node { + \begin{bytefield}[rightcurly=., rightcurlyspace=0pt]{32} + \bitheader{0,3,4,19} \\ + \begin{rightwordgroup}{Address} + \bitbox{4}{ID} & \bitbox{16}{Half} + \end{rightwordgroup} \\ \\ + \bitheader{0,1,31} \\ + \begin{rightwordgroup}{First ID} + \bitbox{1}{\tiny 0} & \bitbox{31}{Common random prefix} + \end{rightwordgroup} \\ + \bitbox[]{32}{or} \\ + \begin{rightwordgroup}{Second ID} + \bitbox{1}{\tiny 1} & \bitbox{31}{Common random prefix} + \end{rightwordgroup} + \end{bytefield} + }; + \end{tikzpicture} \caption{Outgoing metadata format} \end{figure} -Having a common random ID allows us to distinguish real addresses from fake ones. The first bit then allows us to rearrange the two halves, the order of the addresses being randomized on purpose by the clients to improve privacy. +Having a common random prefix allows us to distinguish real addresses from fake ones, since it is very unlikely that two addresses share the same 32 bits. Since the Bitcoin client randomizes the order of the addresses for privacy reasons, the first bit allows us to distinguish the first half of the key from the second. \subsection{Ethereum} -Ethereum is designed around the concept of smart contracts. Logging inside a smart contract is the recommended way to add metadata, but it is expensive (additional storage and execution costs) and adds an avoidable attack surface. We chose to use the transaction field typically used to call smart contracts to store our raw metadata. +Ethereum is designed around the concept of smart contracts. Logging inside a smart contract is the recommended way to add metadata\footnote{https://ethereum.org/en/developers/docs/smart-contracts/anatomy/\#events-and-logs}, but it is expensive (additional storage and execution costs) and adds an avoidable attack surface. We chose to use the transaction field typically used to call smart contracts to store our raw metadata. -\subsection{Friendly behavior on format error} +\subsection{Friendly behaviour on format error} -When we receive a transaction without any metadata or with an incompatible format (bogus wallet), we want to return the money to its owner (bounce). However, this is dangerous because we have created a potential attack loophole as anyone can now make Depolymerizer do a transaction, by sending a malformed transaction. Depolymerizer takes a bounce fee to make a potential \acs{dos} attack too costly and charges the recipient the transaction fee to ensure it can not lose money on a bounce. +When we receive a transaction without any metadata or with an incompatible format (bogus wallet), we want to return the money to its owner (bounce). However, this can be dangerous because it creates a potential attack loophole as anyone can now make Depolymerizer do a transaction, by sending a malformed transaction. Depolymerizer takes a bounce fee to make a potential \ac{DOS} attack too costly. There is another issue, making a transaction has a cost, and if the transaction fee is higher than our bounce fee, malicious bounces could bankrupt us. We also need to charge the recipient the transaction fee to ensure we never lose money on a bounce. \clearpage \section{Architecture} -Each cryptocurrency uses a different \ac{dlt} with its own format and rules, which evolve over time. We do not want to manage the \ac{dlt} logic ourselves, nor do we want to rely on third-party dependencies to implement their support properly and be maintained. The simplest solution is to rely on the official clients and communicate with them via RPC. +Each cryptocurrency uses a different \ac{DLT} with its own format and rules, which evolve over time. We do not want to manage the \ac{DLT} logic ourselves, nor do we want to rely on third-party dependencies to implement their support properly and be maintained. The simplest solution is to rely on the official clients and communicate with them via \ac{RPC}. -\begin{figure}[hb] +\begin{figure}[h] \begin{center} \input{figures/depolymerizer_arch.tex} \end{center} \caption{Depolymerizer architecture} \end{figure} -While some parts of Depolymerizer are \ac{dlt} specific, much of the logic is common and we want to reuse it. We have a Wire Gateway component that implements the Taler HTTP API to enable communication with Taler exchanges. Each supported cryptocurrency has its specific adapter to communicate with the official full node client via RPC. The Wire Gateway module and the \ac{dlt} adapter use a common database to store transactions and communicate with notifications. +While some parts of Depolymerizer are \ac{DLT} specific, much of the logic is common, and we want to reuse it. We have a Wire Gateway component that implements the Taler \ac{HTTP} \ac{API} to enable communication with Taler exchanges. Each supported cryptocurrency has its specific adapter to communicate with the official full node client via \ac{RPC}. The Wire Gateway module and the \ac{DLT} adapter use a common database to store transactions and communicate with notifications. -\subsection{\acs{dlt} adapter} +\subsection{DLT adapter} The DTL adapter uses an event-based architecture with three distinct loops. @@ -323,25 +355,25 @@ The watcher loop looks for new incoming blocks and notifies the other loops of t \paragraph*{Analysis} -The analysis loop waits for new blocks and then analyzes the behavior of the blockchain network. If a dangerous reorganization occurs, it is responsible for updating the confirmation delay. +The analysis loop waits for new blocks and then analyzes the behavior of the DLT network. If a dangerous reorganization occurs, it is responsible for updating the confirmation delay. \paragraph*{Worker} -The worker loop waits for new blocks or transaction requests (from the Wire Gateway API). When one of these events occurs, it first reconciles the local database with the \ac{dlt}, then triggers requested debits, re-issues blocked debits and bounces malformed credits. +The worker loop waits for new blocks or transaction requests (from the Wire Gateway \ac{API}). When one of these events occurs, it first reconciles the local database with the \ac{DLT}, then triggers requested debits, re-issues blocked debits and bounces malformed credits. \subsection{Worker loop in detail} -\subsubsection*{\acs{dlt} reconciliation} +\subsubsection*{DLT reconciliation} -During a \ac{dlt} reconciliation, we first list all new transactions and any transactions that have been removed in a reorganization since the last reconciliation. If any previously confirmed debits have been removed without being reinserted into another block, we notify the Wire Gateway to cease activity and wait for the next block in hopes of recovering them. All newly confirmed debits and successful credits are registered in the database. +During a \ac{DLT} reconciliation, we first list all new transactions and any transactions that have been removed in a reorganization since the last reconciliation. If any previously confirmed debits have been removed without being reinserted into another block, we notify the Wire Gateway to cease activity and wait for the next block in hopes of recovering them. All newly confirmed debits and successful credits are registered in the database. \subsubsection*{Reconciliation inconsistency} -When we issue a transaction (debit or bounce), it is possible for the database or \ac{dlt} request to fail. Since a \ac{dlt} request does not mean that the cryptocurrency transaction was not successful, and since the database may not record a successful transaction, it is possible to have an inconsistency between the DLT and the database where a successful transaction is not recorded as such. This is very problematic because we must perform each transaction once. +When we issue a transaction (debit or bounce), it is possible for the database or \ac{DLT} \ac{RPC} request to fail. Since a \ac{DLT} \ac{RPC} request error does not mean that the cryptocurrency transaction was not successful, and since the database may not record a successful transaction, it is possible to have an inconsistency between the DLT and the database where a successful transaction is not recorded as such. This is very problematic because we must perform each transaction only once. -This is also problematic because, even if we used a status machine state in the database to detect this inconsistency, the only way to resolve it is to make another \ac{dlt} reconciliation, which is slow and does not play well with database locking. +This is also problematic because, even if we used a status machine state in the database to detect this inconsistency, the only way to resolve it is to make another \ac{DLT} reconciliation, which is slow and does not play well with database locking. -Since we know that blockchain-based cryptocurrencies have low throughput, we do not need parallel worker loops to stay synchronized. Therefore, we can use a cross-process locking mechanism to ensure that only one working loop is running at a time. Then, when a database or \ac{dlt} request error occurs, we can restart the loop, which will start by performing a \ac{dlt} reconciliation that will recover all successful unregistered transactions. +Since we know that blockchain-based cryptocurrencies have low throughput, we do not need parallel worker loops to stay synchronized. Therefore, we can use a cross-process locking mechanism to ensure that only one working loop is running at a time. Then, when a database or \ac{DLT} request error occurs, we can restart the loop, which will start by performing a \ac{DLT} reconciliation that will recover all successful unregistered transactions. \clearpage @@ -349,58 +381,57 @@ Since we know that blockchain-based cryptocurrencies have low throughput, we do \subsection*{Ethereum amount precision} -The Taler amount format comes from RFC 8905 \cite{RFC8905}. It allows up to $2^{53}$ unit and 8 decimal digits. This format is perfectly suited for Bitcoin where the maximal amount is 21 million bitcoins and the minimum amount is the satoshi, one satoshi being worth $10^{8}$ bitcoin. However, the minimum amount of Ethereum is the wei, with one ether being worth $10^{18}$ wei. The amount of ether in circulation continues to grow without a cap, with over 119.000.000 ether in circulation at the time of writing those lines. Therefore, it is not possible to represent all Ethereum amounts with the current format. +The Taler amount format comes from RFC 8905 \cite{RFC8905}. It allows up to $2^{53}$ unit and 8 decimal digits. This format is perfectly suited for Bitcoin where the maximal amount is 21 million bitcoins and the minimum amount is the satoshi, one satoshi being worth $10^{8}$ bitcoin. However, the minimum amount of Ethereum is the wei, with one ether being worth $10^{18}$ wei. The amount of ether in circulation continues to grow without a cap, with over 119,000,000 ether in circulation at the time of writing those lines. Therefore, it is not possible to represent all Ethereum amounts with the current format. -A standard Ethereum transaction requires 21 000 units of gas \footnote{https://ethereum.org/en/developers/docs/gas/\#post-london}. The average gas price is currently around 30 Gwei. Therefore, a standard transaction cost about $63.10^{18}$ wei in transaction fees. Since the transaction fee is so high, even if we truncate Ethereum value to its 8 first decimal, we can still represent any amount you can send whiteout losing money on the transaction fee. +A standard Ethereum transaction requires 21 000 units of gas\footnote{https://ethereum.org/en/developers/docs/gas/\#post-london}. The average gas price is currently around 30 Gwei. Therefore, a standard transaction cost about $63.10^{18}$ wei in transaction fees. Since the transaction fee is so high, even if we truncate Ethereum value to $10^{-8}$ eth ($10^{10}$ wei), we can still represent any amount you can send without losing money on the transaction fee. In Depolymerizer, all Ethereum amounts are truncated as such. \subsection*{Replaceable bitcoin transaction} When some merchants wanted to allow instant payments with Bitcoin, they chose to consider a transaction final when it is announced. Although wrong, this choice works most of the time because many nodes do not accept conflicting transactions in their mempool, making it difficult to replace or cancel a transaction that has already been announced. -This becomes problematic when you want to make a legitimate replacement, to unstuck a transaction by increasing its transaction fee for example. At the same time, it is always dangerous to give an easy way to attackers and scammers to change the content of a pending transaction. +This becomes problematic when you want to make a legitimate replacement, to unstuck a transaction by increasing its transaction fee for example. At the same time, it is dangerous to give an easy way to attackers and scammers to change the content of announced transaction. -A solution has been adopted in BIP 125 \cite{BIP125}. It is now possible to encode the replaceability of a bitcoin transaction when creating it. This allows it to be replaced by a new transaction within certain rules: you cannot send less money to existing recipients and you must pay a replacement fee as a countermeasure to a \acs{dos} attack. +We use the solution has been adopted in \ac{BIP} 125 \cite{BIP125}, adding the possibility to encode the replaceability of a bitcoin transaction at its creation. It can thus be replaced by a new transaction within certain rules: you cannot send less money to existing recipients, and you must pay a replacement fee as a countermeasure to a \ac{DOS} attack. \clearpage -\section{Uri packing, a compression side quest} +\section{URI packing, a compression side quest}\label{uri-packing} \subsection*{The need for compact URI} -As discussed previously, storing metadata in blockchain is +As discussed previously in section \ref{metadata}, storing metadata in blockchain is expensive and limited. Therefore, we want our metadata to be as small as possible. \noindent Transactions metadata are composed of three parts: \begin{itemize} \item Version and identity metadata ($\sim$ 1B) - \item Reserve public key or wire transfer id (32B) - \item Base url (debit only, variable) + \item Reserve public key or wire transfer ID (32B) + \item Base URL (debit only, variable) \end{itemize} -The only variable, and so problematic, part is the base url. Those url have some +The only variable, and so problematic, part is the base URL. Those URLs have some property in common, they always use a few different scheme (http or https) and are composed of a domain and a small path. -We would normally encode the url using ASCII, but we known only a few ASCII -character are actually used. +We would normally encode the URL using ASCII, but we knew only a few ASCII characters are actually used, and we can take advantage of that. \subsection*{5 or 11 encoding} -Our idea is to encode the most commonly used characters using five bits, and the -remaining characters using eleven bits. As an ASCII character take eights bits -we gain on size if more than half of the characters composing the uri are -encodable using less bits. +Our idea is to encode the most commonly used characters using five bits, and the remaining characters using eleven bits. As ASCII characters are seven bits wide and are commonly encoded using height, we gain on size if more than half of the characters composing the URI are encodable using fewer bits (Table~\ref{table:uri-packing}). You can find the detailed encoding table in appending \ref{5-11}. -\begin{center} - \begin{tabular}{l l l} - code & meaning \\ +\begin{table}[h] + \centering + \begin{tabular}{ll} + value & encoding \\ \hline 0..30 & common character: a-z . / - \% \\ 30 0..64 & extended character, remaining graphic ascii \\ 31 & end of encoded string \\ \end{tabular} -\end{center} + \caption{URI packing encoding} + \label{table:uri-packing} +\end{table} Using this encoding format on all domains on the majestic-million\footnote{https://majestic.com/reports/majestic-million} @@ -414,42 +445,50 @@ custom format. For example, for bitcoin the maximum amount of data than is accepted in OP\_RETURN is currently 80 bytes, leaving us 47 bytes to store the URI. With our -encoding we can encode in the best case 74 characters instead of 47 which is more -enough for our use case. +encoding we can encode in the best case 74 characters instead of 47 which is more than enough for our use case. \clearpage \section{Taler Wire Gateway HTTP API} -Taler is a modular project where each module communicates through HTTP API. The Wire Gateway API allows the exchange to communicate to wire adaptors. The Wire Gateway module allow Depolymerizer to communicate with Taler exchanges. As the API can be exposed on the Internet it has to be resistant to easy attacks. +Taler is a modular project where each module communicates through \ac{HTTP} \ac{API}. The Wire Gateway \ac{API} allows the exchange to communicate to wire adaptors. The Wire Gateway module allow Depolymerizer to communicate with Taler exchanges. As the \ac{API} can be exposed on the Internet it has to be resistant to most of the known attacks. \subsection*{HTTP Authentication} -The wire API only supports the Basic HTTP Authentication method and it has to be optional. Making it optional can lead to security issues by misconfiguration. If the default behavior in case of missing configuration is to deactivate authentication, a typo could lead to an exposed API. We made the authentication method configuration mandatory to make its deactivation explicit. +The wire \ac{API} only supports the Basic \ac{HTTP} Authentication method and it has to be optional. Making it optional can lead to security issues by misconfiguration. If the default behavior in case of missing configuration is to deactivate authentication, a typo could lead to an exposed \ac{API}. We made the authentication method configuration mandatory to make its deactivation explicit. -\subsection*{OOM \acs{dos}} +\subsection*{OOM DOS} -A common Denial Of Service attack consists of sending many requests with huge bodies to saturate a server memory and, in the worst case, create an Out Of Memory error. To be resilient against such attacks we only read body after request authentication, to prevent any person without authorization to access the API to perform such attacks. +A common Denial Of Service attack consists of sending many requests with huge bodies to saturate a server memory and, in the worst case, create an Out Of Memory error. To be resilient against such attacks we only read body after request authentication, to prevent any person without authorization to access the \ac{API} to perform such attacks. Then we chose an aggressive memory budget of 4kB, as all request bodies should be very small, and we only read and parse them under this budget. In the case of compressed bodies, we also apply this budget to the decompression process to protect ourselves against decompression bombs. \subsection*{Testing} -% Move testing to its own section - -The taler exchange has a taler-exchange-wire-gateway-client CLI that allowed me to test that my implementation not only conforms to the API documentation but also with how the official client handles it. I found confusion in the documentation where it was specified that timestamp should consist of time in milliseconds in epoch but the client will reject timestamps that are not rounded to second. +The Taler exchange has a taler-exchange-wire-gateway-client CLI that allowed me to test that my implementation not only conforms to the \ac{API} documentation but also with how the official client handles it. I found confusion in the documentation where it was specified that timestamp should consist of time in milliseconds since epoch, but the client will reject timestamps that are not rounded to second. \clearpage -\section{Future work} +\section{Conclusion} + +\subsection*{Summary} + +We have shown that is it possible to use Bitcoin and Ethereum \ac{DLT} as a settlement layer for GNU Taler enabling payment with blockchain-based cryptocurrencies using Depolymerization. Depolymerization act as a middleware between Taler exchange and a \ac{DLT} mitigating their inconsistency especially chain reorganization and stuck transactions. + +In this project, we have not addressed the legal challenges of running GNU Taler with Depolymerization. In some countries, the use of cryptocurrencies is prohibited or restricted, and in most countries, payment systems are regulated and may require a licence. We therefore advise against deploying it without checking that you are authorized to do so. + +Depolymerization has many attractive features for cryptocurrency users at one cost, the centralization of trust in the exchange. This problem is partially solved with the use of auditors that federate trust. In contrast, blockchain-based cryptocurrencies are generally public, with their entire state subject to public scrutiny. For GNU Taler to convince users who expect this level of openness, we would have to find a way to make enough information public that any client could do the auditors' job. + -\subsection*{Paying for reorganisation loss} +\subsection*{Future work} -We could allow the administrator to pay for the missing transactions to resume operations, as sometimes the loss caused by the non-functioning depolymerizer exceeds the cost of the missing transactions. +\subsubsection*{Paying for reorganization loss} -\subsection*{Smarter analysis} +When a reorganization removes a confirmed credit indefinitely (conflicting transaction) we suspend operation indefinitely. We could allow exchange administrators to pay for the missing transactions to resume operations, as sometimes the loss caused by the non-functioning Depolymerizer exceeds the cost of the missing transactions. -There is an opportunity for a more intelligent analysis of network behaviours to adjust the confirmation delay to an estimated risk factor. For example, a brute force attack on a blockchain is very expensive, when we receive an important credit, we could apply a longer delay to it to make attacks harder to sustain. +\subsubsection*{Smarter analysis} + +More intelligent analysis of network behaviors can be performed to tailor the confirmation time to an estimated risk factor. Brute force attacks on a DLT are very expensive, and one can expect that attackers have an economic incentive to attack through double spending for example. When we receive a large credit or when a considerable amount of currency is exchanged on the network, this can be the preparation for such attacks. We could monitor these indicators, and we could apply a longer temporary delay to make the attacks harder to sustain. \clearpage @@ -460,4 +499,12 @@ There is an opportunity for a more intelligent analysis of network behaviours to \printacronyms +\clearpage + +\appendix + +\section*{5-11 encoding table}\label{5-11} + +\input{tables/5-11.tex} + \end{document} diff --git a/docs/tables/5-11.tex b/docs/tables/5-11.tex @@ -0,0 +1,121 @@ + +\begin{table}[H] + \begin{minipage}{.5\linewidth} + \centering + \begin{tabular}{rl} + value & encoding \\ + \hline + 0 & a \\ + 1 & b \\ + 2 & c \\ + 3 & d \\ + 4 & e \\ + 5 & f \\ + 6 & g \\ + 7 & h \\ + 8 & i \\ + 9 & j \\ + 10 & k \\ + 11 & l \\ + 12 & m \\ + 13 & n \\ + 14 & o \\ + 15 & p \\ + 16 & q \\ + 17 & r \\ + 18 & s \\ + 19 & t \\ + 20 & u \\ + 21 & v \\ + 22 & w \\ + 23 & x \\ + 24 & y \\ + 25 & z \\ + 26 & . \\ + 27 & / \\ + 28 & - \\ + 29 & \% \\ + 30 & EXTENDED \\ + 31 & EOF \\ + \end{tabular} + \caption{5 bit simple encoding} + \end{minipage} + \begin{minipage}{.5\linewidth} + \centering + \begin{tabular}{rl} + value & encoding \\ + \hline + 0 & \_ \\ + 1 & A \\ + 2 & B \\ + 3 & C \\ + 4 & D \\ + 5 & E \\ + 6 & F \\ + 7 & G \\ + 8 & H \\ + 9 & I \\ + 10 & J \\ + 11 & K \\ + 12 & L \\ + 13 & M \\ + 14 & N \\ + 15 & O \\ + 16 & P \\ + 17 & Q \\ + 18 & R \\ + 19 & S \\ + 20 & T \\ + 21 & U \\ + 22 & V \\ + 23 & W \\ + 24 & X \\ + 25 & Y \\ + 26 & Z \\ + 27 & 0 \\ + 28 & 1 \\ + 29 & 2 \\ + 30 & 3 \\ + 31 & 4 \\ + \end{tabular} + \quad + \begin{tabular}{rl} + value & encoding \\ + \hline + 32 & 5 \\ + 33 & 6 \\ + 34 & 7 \\ + 35 & 8 \\ + 36 & 9 \\ + 37 & ! \\ + 38 & " \\ + 39 & \# \\ + 40 & \$ \\ + 41 & \& \\ + 42 & ' \\ + 43 & ( \\ + 44 & ) \\ + 45 & * \\ + 46 & + \\ + 47 & , \\ + 48 & : \\ + 49 & ; \\ + 50 & \textless \\ + 51 & = \\ + 52 & \textgreater \\ + 53 & ? \\ + 54 & @ \\ + 55 & $[$ \\ + 56 & \textbackslash \\ + 57 & $]$ \\ + 58 & \textasciicircum \\ + 59 & $`$ \\ + 60 & \{ \\ + 61 & \textbar \\ + 62 & \} \\ + 63 & \textasciitilde \\ + \end{tabular} + + \caption{11 bit extended encoding} + \end{minipage} +\end{table} diff --git a/eth-wire/src/bin/eth-wire-utils.rs b/eth-wire/src/bin/eth-wire-utils.rs @@ -84,21 +84,14 @@ enum Cmd { wire_addr: String, wire: u64, }, - /// Add a peer - Connect { - /// peer datadir - datadir: PathBuf, - }, - /// Remove a peer - Disconnect { - /// peer datadir - datadir: PathBuf, - }, /// Abandon all unconfirmed transaction Abandon { /// sender address from: String, }, + Export { + path: String, + }, } fn main() { @@ -216,34 +209,6 @@ fn main() { } } } - Cmd::Connect { datadir } => { - let mut peer = Rpc::new(datadir).unwrap(); - let mut enode = peer.node_info().unwrap().enode; - // Replace ip with localhost because it is broken - enode.set_host(Some("127.0.0.1")).unwrap(); - assert!(rpc.add_peer(&enode).unwrap()); - let start = Instant::now(); - while rpc.count_peer().unwrap() == 0 { - if start.elapsed() > Duration::from_secs(60) { - panic!("Connect timeout"); - } - std::thread::sleep(Duration::from_secs(5)) - } - } - Cmd::Disconnect { datadir } => { - let mut peer = Rpc::new(datadir).unwrap(); - let mut enode = peer.node_info().unwrap().enode; - // Replace ip with localhost because it is broken - enode.set_host(Some("127.0.0.1")).unwrap(); - assert!(rpc.remove_peer(&enode).unwrap()); - let start = Instant::now(); - while rpc.count_peer().unwrap() != 0 { - if start.elapsed() > Duration::from_secs(60) { - panic!("Disconnect timeout"); - } - std::thread::sleep(Duration::from_secs(5)) - } - } Cmd::Abandon { from } => { let from = H160::from_str(&from).unwrap(); rpc.unlock_account(&from, &passwd).ok(); @@ -261,5 +226,9 @@ fn main() { .unwrap(); } } + Cmd::Export { path } => { + std::fs::remove_file(&path).ok(); + assert!(rpc.export_chain(&path).unwrap()) + } } } diff --git a/eth-wire/src/loops/worker.rs b/eth-wire/src/loops/worker.rs @@ -137,7 +137,7 @@ fn sync_chain( let list = rpc.list_since_sync(&state.address, sync_state, conf_delay)?; - // Check if a confirmed incoming transaction have been removed by a blockchain reorganisation + // Check if a confirmed incoming transaction have been removed by a blockchain reorganization let new_status = sync_chain_removed(&list.txs, &list.removed, db, &state.address, conf_delay)?; // Sync status with database diff --git a/eth-wire/src/rpc.rs b/eth-wire/src/rpc.rs @@ -316,7 +316,7 @@ pub trait RpcClient { /* ----- Account management ----- */ - /// List registered acount + /// List registered account fn list_accounts(&mut self) -> Result<Vec<Address>> { self.call("personal_listAccounts", &EMPTY) } @@ -326,7 +326,7 @@ pub trait RpcClient { self.call("personal_newAccount", &[passwd]) } - /// Unlock an existinf acount + /// Unlock an existing account fn unlock_account(&mut self, account: &Address, passwd: &str) -> Result<bool> { self.call("personal_unlockAccount", &(account, passwd, 0)) } @@ -348,7 +348,7 @@ pub trait RpcClient { r => r, } } - + /// Get block by hash fn block(&mut self, hash: &H256) -> Result<Option<Block>> { match self.call("eth_getBlockByHash", &(hash, &true)) { @@ -361,7 +361,7 @@ pub trait RpcClient { fn pending_transactions(&mut self) -> Result<Vec<Transaction>> { self.call("eth_pendingTransactions", &EMPTY) } - + /// Get latest block fn latest_block(&mut self) -> Result<Block> { self.call("eth_getBlockByNumber", &("latest", &true)) @@ -414,20 +414,12 @@ pub trait RpcClient { /* ----- Peer management ----- */ - /// Add peer to the peer list - fn add_peer(&mut self, url: &Url) -> Result<bool> { - self.call("admin_addPeer", &[url]) - } - - /// Remove a peer to the peer list - fn remove_peer(&mut self, url: &Url) -> Result<bool> { - self.call("admin_removePeer", &[url]) + fn export_chain(&mut self, path: &str) -> Result<bool> { + self.call("admin_exportChain", &[path]) } - /// Get peer count - fn count_peer(&mut self) -> Result<u32> { - let peers: U64 = self.call("net_peerCount", &EMPTY)?; - Ok(peers.as_u32()) + fn import_chain(&mut self, path: &str) -> Result<bool> { + self.call("admin_importChain", &[path]) } } diff --git a/instrumentation/README.md b/instrumentation/README.md @@ -1,6 +1,6 @@ # Depolymerizer instrumentation test -Unit tests running on a private development network are meant to test the good +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. @@ -17,4 +17,4 @@ tested blockchain will be determined based on the taler configuration. 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 -unit tests. +local tests. +\ No newline at end of file diff --git a/test/btc/analysis.sh b/test/btc/analysis.sh diff --git a/test/btc/bumpfee.sh b/test/btc/bumpfee.sh diff --git a/test/btc/config.sh b/test/btc/config.sh diff --git a/test/btc/conflict.sh b/test/btc/conflict.sh diff --git a/test/btc/hell.sh b/test/btc/hell.sh @@ -1,6 +1,6 @@ #!/bin/bash -## Test btc-wire correctness when a blockchain reorganisation occurs leading to past incoming transaction conflict +## Test btc-wire correctness when a blockchain reorganization occurs leading to past incoming transaction conflict set -eu diff --git a/test/btc/lifetime.sh b/test/btc/lifetime.sh diff --git a/test/btc/maxfee.sh b/test/btc/maxfee.sh diff --git a/test/btc/reconnect.sh b/test/btc/reconnect.sh diff --git a/test/btc/reorg.sh b/test/btc/reorg.sh @@ -1,6 +1,6 @@ #!/bin/bash -## Test btc-wire correctness when a blockchain reorganisation occurs +## Test btc-wire correctness when a blockchain reorganization occurs set -eu diff --git a/test/btc/stress.sh b/test/btc/stress.sh diff --git a/test/btc/wire.sh b/test/btc/wire.sh diff --git a/test/common.sh b/test/common.sh @@ -274,29 +274,35 @@ function init_eth() { echo -e "PAYTO = payto://ethereum/$WIRE" >> $CONF } -# Start a seconf geth dev node connected to the first one +# Initialize a second geth dev node function init_eth2() { # Initialize blockchain $ETH_CLI2 init $DIR/genesis.json &>> log/node2.log - # Start node - $ETH_CLI2 --port 30305 $* &>> log/node2.log & - sleep 1 - # Create etherbase account for mining $ETH_CLI2 account new --password <(echo $PASSWORD) &> /dev/null - # Connect nodes - $WIRE_UTILS connect $WIRE_DIR2 } +# 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 disconnect $WIRE_DIR2 + $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() { - sleep 2 # Sync before fork + $ETH_CLI2 --port 30305 --miner.gasprice 0 &>> log/node2.log & + NODE2_PID="$!" + sleep 1 $WIRE_UTILS2 mine $RESERVE ${1:-} - $WIRE_UTILS connect $WIRE_DIR2 + $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 @@ -304,9 +310,7 @@ function start_eth() { # Start node $ETH_CLI $* &>> log/node.log & NODE_PID="$!" - sleep 1 - # Try to connect nodes - $WIRE_UTILS connect $WIRE_DIR2 &> /dev/null || true + sleep 2 } function restart_eth() { diff --git a/test/conf/bitcoin.conf b/test/conf/bitcoin.conf diff --git a/test/conf/bitcoin2.conf b/test/conf/bitcoin2.conf diff --git a/test/conf/bitcoin_auth0.conf b/test/conf/bitcoin_auth0.conf diff --git a/test/conf/bitcoin_auth1.conf b/test/conf/bitcoin_auth1.conf diff --git a/test/conf/bitcoin_auth2.conf b/test/conf/bitcoin_auth2.conf diff --git a/test/conf/bitcoin_auth3.conf b/test/conf/bitcoin_auth3.conf diff --git a/test/conf/bitcoin_auth4.conf b/test/conf/bitcoin_auth4.conf diff --git a/test/conf/bitcoin_auth5.conf b/test/conf/bitcoin_auth5.conf diff --git a/test/conf/taler_btc.conf b/test/conf/taler_btc.conf diff --git a/test/conf/taler_btc_auth.conf b/test/conf/taler_btc_auth.conf diff --git a/test/conf/taler_btc_bump.conf b/test/conf/taler_btc_bump.conf diff --git a/test/conf/taler_btc_lifetime.conf b/test/conf/taler_btc_lifetime.conf diff --git a/test/conf/taler_eth.conf b/test/conf/taler_eth.conf diff --git a/test/conf/taler_eth_bump.conf b/test/conf/taler_eth_bump.conf diff --git a/test/conf/taler_eth_lifetime.conf b/test/conf/taler_eth_lifetime.conf diff --git a/test/eth/analysis.sh b/test/eth/analysis.sh diff --git a/test/eth/bumpfee.sh b/test/eth/bumpfee.sh diff --git a/test/eth/hell.sh b/test/eth/hell.sh @@ -1,6 +1,6 @@ #!/bin/bash -## Test eth-wire correctness when a blockchain reorganisation occurs leading to past incoming transaction conflict +## Test eth-wire correctness when a blockchain reorganization occurs leading to past incoming transaction conflict set -eu diff --git a/test/eth/lifetime.sh b/test/eth/lifetime.sh diff --git a/test/eth/maxfee.sh b/test/eth/maxfee.sh diff --git a/test/eth/reconnect.sh b/test/eth/reconnect.sh diff --git a/test/eth/reorg.sh b/test/eth/reorg.sh @@ -1,6 +1,6 @@ #!/bin/bash -## Test eth-wire correctness when a blockchain reorganisation occurs +## Test eth-wire correctness when a blockchain reorganization occurs set -eu diff --git a/test/eth/stress.sh b/test/eth/stress.sh diff --git a/test/eth/test.sh b/test/eth/test.sh diff --git a/test/eth/wire.sh b/test/eth/wire.sh diff --git a/test/gateway/api.sh b/test/gateway/api.sh diff --git a/test/gateway/auth.sh b/test/gateway/auth.sh diff --git a/wire-gateway/README.md b/wire-gateway/README.md @@ -5,8 +5,8 @@ Rust server for ## Database schema -The server is wire implementation agnostic, it only require an postgres database -with following schema: +The server is wire implementation agnostic, it only requires a Postgres database +with the following schema: ```sql -- Key value state diff --git a/wire-gateway/src/main.rs b/wire-gateway/src/main.rs @@ -125,7 +125,7 @@ async fn main() { .iter() .map(|it| match it { Host::Tcp(it) => it.to_string(), - #[cfg(target_os = "linux")] + #[cfg(unix)] Host::Unix(it) => it.to_str().unwrap().to_string(), }) .collect(),