depolymerization

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

commit bf2bbaeb5e501a1639779152b3fae95c8adcee32
parent 77018cb9ffa12d861b127b6b16564357958ed6dd
Author: Antoine A <>
Date:   Mon, 21 Mar 2022 12:13:14 +0100

Move report to repo

Diffstat:
MCargo.lock | 46++++++++++++++++++++++++++--------------------
Mbtc-wire/src/loops/worker.rs | 9+++++----
Adocs/report.tex | 350+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Meth-wire/src/loops/worker.rs | 13+++++++------
4 files changed, 388 insertions(+), 30 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -270,9 +270,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" dependencies = [ "libc", ] @@ -324,9 +324,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbfe11fe19ff083c48923cf179540e8cd0535903dc35e178a1fdeeb59aef51f" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" dependencies = [ "cfg-if", "crossbeam-utils", @@ -741,6 +741,12 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" dependencies = [ "ahash", ] @@ -878,7 +884,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.11.2", ] [[package]] @@ -943,9 +949,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.120" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad5c14e80759d0939d013e6ca49930e59fc53dd8e5009132f76240c179380c09" +checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "listenfd" @@ -1027,9 +1033,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba42135c6a5917b9db9cd7b293e5409e1c6b041e6f9825e92e55a894c63b6f8" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" dependencies = [ "libc", "log", @@ -1088,9 +1094,9 @@ dependencies = [ [[package]] name = "num_threads" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c539a50b93a303167eded6e8dff5220cd39447409fb659f4cd24b1f72fe4f133" +checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" dependencies = [ "libc", ] @@ -1109,12 +1115,12 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "ordered-multimap" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b476c5fc0aad16f8b8d74e7df9da1813731fae300f7a923713c4c591905ff50" +checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" dependencies = [ "dlv-list", - "hashbrown", + "hashbrown 0.12.0", ] [[package]] @@ -1352,9 +1358,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57" dependencies = [ "proc-macro2", ] @@ -1728,9 +1734,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd69e719f31e88618baa1eaa6ee2de5c9a1c004f1e9ecdb58e8352a13f20a01" +checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" dependencies = [ "proc-macro2", "quote", @@ -2210,6 +2216,6 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.5.3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50344758e2f40e3a1fcfc8f6f91aa57b5f8ebd8d27919fe6451f15aaaf9ee608" +checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317" diff --git a/btc-wire/src/loops/worker.rs b/btc-wire/src/loops/worker.rs @@ -158,7 +158,8 @@ fn sync_chain( ) -> LoopResult<Option<Vec<Txid>>> { // Get stored last_hash let last_hash = last_hash(db)?; - let min_confirmations = state.confirmation.load(Ordering::SeqCst); + // Use the same confirmation delay for this sync + let conf_delay = state.confirmation.load(Ordering::SeqCst); // Get a set of transactions ids to parse let (txs, removed, lastblock): ( @@ -167,7 +168,7 @@ fn sync_chain( BlockHash, ) = { // Get all transactions made since this block - let list = rpc.list_since_block(Some(&last_hash), min_confirmations)?; + let list = rpc.list_since_block(Some(&last_hash), conf_delay)?; // Only keep ids and category let txs = list .transactions @@ -183,7 +184,7 @@ fn sync_chain( }; // Check if a confirmed incoming transaction have been removed by a blockchain reorganisation - let new_status = sync_chain_removed(&txs, &removed, rpc, db, min_confirmations as i32)?; + let new_status = sync_chain_removed(&txs, &removed, rpc, db, conf_delay as i32)?; // Sync status with database if *status != new_status { @@ -212,7 +213,7 @@ fn sync_chain( stuck.push(id); } } - Category::Receive if confirmations >= min_confirmations as i32 => { + Category::Receive if confirmations >= conf_delay as i32 => { sync_chain_incoming_confirmed(&id, rpc, db, state)? } _ => { diff --git a/docs/report.tex b/docs/report.tex @@ -0,0 +1,350 @@ +\documentclass[12pt]{article} +\usepackage[tmargin=1in,bmargin=1in,lmargin=1.25in,rmargin=1.25in]{geometry} +\usepackage[utf8]{inputenc} +\usepackage{bytefield} +\usepackage{graphics} +\usepackage{parskip} +\usepackage{tikz} +\usepackage{float} +\usepackage{authblk} + +\usetikzlibrary{positioning,fit} + +\title{Depolymerization \\ Integrating GNU Taler with blockchain-based cryptocurrencies} +\author{Antoine d'Aligny} +\affil{Bern University of Applied Sciences} +\date{\today} + +\begin{document} + +\maketitle + +\clearpage + +\tableofcontents + +\clearpage + +\section{Taler} + +% TODO + +% Briefly presenting Taler +% Settlement layer -> blockchain-based cryptocurrency + +\section{Blockchain-based cryptocurrencies} + +A cryptocurrency is a digital currency that relies on code and especially cryptography to secure transactions without a central authority. It is important to understand the basis of how they work and their limitations to understand the integration challenges they pose. For this project, only the two most famous, Bitcoin and Ethereum, were integrated. While other blockchain-based cryptocurrencies may work differently, we are only interested in the specific similarities between these two. + +\subsubsection*{Bitcoin} + +Bitcoin is the first cryptocurrency to achieve a successful public rollout. Invented by an unknown person or group of people working under the name of Satoshi Nakamoto, it was first mentioned in his white paper published the 31 October 2009 \cite{nakamoto2008bitcoin}. Bitcoin assembled the technological foundation for many of the cryptocurrencies in use today. + +\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. + +\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. Transactions are stored inside those blocks. + +\subsection{Consensus} + +The blockchain itself is just a storage system. To make it a distributed ledger, 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 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. + +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. + +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. The difficulty algorithm is used to keep the block time close to a constant. On Ethereum, the block time is 12 to 14 seconds \footnote{https://ethereum.org/en/developers/docs/blocks/\#block-time}. On Bitcoin, the block time is about 10 minutes. + +\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 founded, we have a blockchain fork. 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. + +\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 currency is to attacks. 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. +\end{itemize} + +\subsection{Blockchain-based cryptocurrencies limitations} + +As we have seen, blockchain-based cryptocurrencies have certain limitations by design. Block time adds a significant delay to each transaction, and the block size limits the number of possible transactions per second. High transaction fees are required to cover the cost of an expensive mining process. Because the transaction fee is an unpredictable market-based value, transactions can get stuck. Finally, the redundant computational work of all miners has a significant ecological impact. + +\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. + +\subsection{Solving chain reorganisation} + +Taler expects deposit transactions to be final. If a deposit transaction disappears from the blockchain, an irrevocable withdrawal transaction 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. + +\begin{figure}[H] + \begin{center} + \input{figures/conf_delay.tex} + \end{center} + \caption{Reorganisation mitigation using confirmation 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. + +\begin{figure}[H] + \begin{center} + \input{figures/harmless_reorg.tex} + \end{center} + \caption{Harmless reorganisation} +\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. + +\begin{figure}[H] + \begin{center} + \input{figures/conflict.tex} + \end{center} + \caption{Reorganisation with conflicting transaction} +\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. + +\begin{figure}[H] + \begin{center} + \input{figures/analysis.tex} + \end{center} + \caption{Adaptive confirmation} +\end{figure} + +\subsection{Solving stuck transaction} + +We know that transactions can get stuck for a long time, which can be problematic when we are expecting transactions to be executed in a timely manner. Depolymerizer keeps track of pending transactions and finds those that are taking an excessive amount of time to mine. Then, it increases the fee for these transactions to bump their mining priority. Since the process of replacing transactions is expensive, this feature is optional and configurable. + +\section{Architecture} + +Use existing official client. + +\clearpage + +\section{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. + +\subsection{Metadata format} + +The goal of our metadata format is to be simple to parse and versioned for future extensions. + +\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. + +\begin{figure}[H] + \begin{center} + \begin{bytefield}{33} + \bitheader{0,1,32} \\ + \bitbox{1}{\tiny 0} & \bitbox{32}{Key Hash} + \end{bytefield} + \end{center} + \caption{Incoming metadata format} +\end{figure} + +\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. + + +\begin{figure}[H] + \begin{center} + \begin{bytefield}[rightcurly=., rightcurlyspace=0pt]{33} + \bitheader{0,1,32,33} \\ + \begin{rightwordgroup}{Credit} + \bitbox{1}{\tiny 0} & \bitbox{32}{Transfer ID} & \bitbox{10}{Base URL} + \end{rightwordgroup} \\ \\ + \begin{rightwordgroup}{Bounce} + \bitbox{1}{\tiny \rotatebox{90}{255}} & \bitbox{32}{Transaction ID} + \end{rightwordgroup} + \end{bytefield} + \end{center} + \caption{Outgoing metadata format} +\end{figure} + +\subsection{Bitcoin} + +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, and the reserve pub key is 32B. 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 the 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} + \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. + +\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. + +\clearpage + +\section{Implementation specific issues} + +\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 108 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. 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. + +\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. + +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 DOS attack. + +\clearpage + +\section{Uri packing, a compression side quest} + +\subsection*{The need for compact URI} + +As discussed in the previous chapter, 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 withdraw id (32B) + \item Base uri (withdraw only, variable) +\end{itemize} + +The only variable and so problematic part is the base url. Those url 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. + +\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 only 5 bits. + +\begin{center} + \begin{tabular}{l l l} + code & meaning \\ + \hline + 0..30 & common character: a-z . / - \% \\ + 30 0..64 & extended character, remaining graphic ascii \\ + 31 & end of encoded string \\ + \end{tabular} +\end{center} + +Using this encoding format on all domains on the +majestic-million\footnote{https://majestic.com/reports/majestic-million} +database, $98.77\%$ of the domain name where smaller, going from an average encoded +size of 14B in ASCII to 10B using our format. + +\subsection*{Uri in metadata} + +To further optimize metadata size we chose to encode the URI scheme into the +version and identity metadata byte and the remaining domain and path using our +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. + +\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. My first task was to implement a server in Rust to link the depolymerizer implementation to the Taler system. As the API can be exposed on the Internet it has to be resistant to easy 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. + +\subsection*{OOS 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. + +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. + +\clearpage + +\section{Future work} + +\subsection*{Paying for reorganisation loss} + +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. + +\subsection*{Smarter analysis} + +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. + +\clearpage + +\bibliographystyle{alpha} +\bibliography{literature} + +\end{document} diff --git a/eth-wire/src/loops/worker.rs b/eth-wire/src/loops/worker.rs @@ -129,12 +129,13 @@ fn sync_chain( state: &WireState, status: &mut bool, ) -> LoopResult<bool> { + // Get stored sync state let row = db.query_one("SELECT value FROM state WHERE name='sync'", &[])?; - let slice: &[u8] = row.get(0); - let block = SyncState::from_bytes(slice.try_into().unwrap()); - let min_confirmations = state.confirmation.load(Ordering::SeqCst); + let sync_state = SyncState::from_bytes(&sql_array(&row, 0)); + // Use the same confirmation delay for this sync + let conf_delay = state.confirmation.load(Ordering::SeqCst); - let list = rpc.list_since_sync(&state.address, block, min_confirmations)?; + 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 let new_status = sync_chain_removed( @@ -142,7 +143,7 @@ fn sync_chain( &list.removed, db, &state.address, - min_confirmations, + conf_delay, )?; // Sync status with database @@ -165,7 +166,7 @@ fn sync_chain( for sync_tx in list.txs { let tx = &sync_tx.tx; - if tx.to == Some(state.address) && sync_tx.confirmations >= min_confirmations { + if tx.to == Some(state.address) && sync_tx.confirmations >= conf_delay { sync_chain_incoming_confirmed(tx, db, state)?; } else if tx.from == Some(state.address) { sync_chain_outgoing(&sync_tx, db, state)?;