diff --git a/chapters/background/bitcoin.tex b/chapters/background/bitcoin.tex index a78d955..0e2c8b2 100644 --- a/chapters/background/bitcoin.tex +++ b/chapters/background/bitcoin.tex @@ -1,7 +1,7 @@ \section{Bitcoin} -Bitcoin was invented in 2008 by Satoshi Nakamoto~\cite{bitcoin} as a peer-to-peer version of electronic cash, allowing online payments to be sent directly between parties without the need of a intermediary. +Bitcoin was invented in 2008 by Satoshi Nakamoto~\cite{bitcoin} as a peer-to-peer version of electronic cash, allowing online payments to be sent directly between parties without the need of an intermediary. -Bitcoin is pseudonymous: the identity of each user is only their \emph{address}, which corresponds to an ECDSA public key. This address can be used to receive money from other users. Each user can spend money only if they have their corresponding private key. A set of ECDSA keypairs comprises a \emph{wallet}. A user can have multiple addresses. +Bitcoin is pseudonymous: the identity of each user is only their \emph{address}, which corresponds to an ECDSA \dznote{ECDSA citation} public key. This address can be used to receive money from other users. Each user can spend money only if they have their corresponding private key. A user can have multiple addresses. A set of ECDSA keypairs comprises a \emph{wallet}. \begin{figure} \centering @@ -12,6 +12,8 @@ \section{Bitcoin} Transfer of value in Bitcoin happens with transactions. A transaction has inputs and outputs. An output is where the value creation happens for the receiver. An output can be later redeemed by using its designated receiver's private key and turned into an input to be used for another transaction. +\dznote{You need to talk in more detail about the UTXO model here.} + \subsection{Scripts} Bitcoin offers much more than just moving currency around. It allows us to actually move currency conditionally, where the condition can be expressed as a \emph{Bitcoin script}. Bitcoin script is a stack-based language. An example of a Bitcoin script can be seen on Figure~\ref{fig:bitcoin-script}. @@ -27,13 +29,17 @@ \subsection{Scripts} \label{fig:bitcoin-script} \end{figure} -This is an interesting script because it introduces two kinds of operations. First is commands prefixed with \code{OP\_} (called \emph{opcodes}): these perform operations on values (usually the top 1 or 2) on the stack and push the result to the stack. Specifically, \code{OP\_HASH256} calculates the SHA256 hash of the value on the top of the stack (and pushes the result on the stack). \code{OP\_EQUALS} compares the top 2 values on the stack and pushes 1 or 0 if they are indeed equal or not accordingly. Values like \code{6fe...} in hex with no \code{OP\_} prefix are simply pushed to the stack. +\dznote{Start by describing the p2pk script, which is what the reader expects here} + +This is an interesting script because it introduces two kinds of operations. First is commands prefixed with \code{OP\_} (called \emph{opcodes}): these perform operations on values (usually the top 1 or 2) on the stack and push the result to the stack. Specifically, \code{OP\_HASH256} calculates the SHA256 hash of the value at the top of the stack (and pushes the result on the stack). \code{OP\_EQUALS} compares the top 2 values on the stack and pushes 1 or 0 if they are indeed equal or not respectively. Values like \code{6fe...} in hex with no \code{OP\_} prefix are simply pushed to the stack. + +\dznote{This section needs editing. } -So what does this script do? It checks if the value on the stack is the preimage of the given hash. If we do push the correct preimage in the stack before running the script, the result is going to be 1, letting us know that the evaluation was successful. +So what does this script do? It checks if the value on the stack is the preimage of the given hash. If we do push the correct preimage to the stack before running the script, the result is going to be 1, letting us know that the evaluation was successful. -Such a script express our predicate, and is called a \textsf{pubKeyScript}. However the predicate must run on something. In our example above we assumed the preimage was on the stack before the stack ran, and this is how we parameterized our predicate. The way this is done in Bitcoin is running another script before the predicate called \textsf{scriptSig}, to essentially pass the parameters to our predicate. We'll see shortly how these can be leveraged to actually transfer funds. +Such a script express \dznote{?} our predicate \dznote{what predicate?}, and is called a \textsf{pubKeyScript}. However the predicate must run on something. In our example above we assumed the preimage was on the stack before the stack ran, and this is how we parameterized our predicate. The way this is done in Bitcoin is running another script before the predicate called \textsf{scriptSig}, to essentially pass the parameters to our predicate. We'll see shortly how these can be leveraged to actually transfer funds. -It's important to note that there's a third type of opcodes which can fail the script preemptively. These opcodes are usually in the form of \code{OP\_...VERIFY}. An example is \code{OP\_EQUALVERIFY} which fails the script if the top 2 values of the stack are not equal, and is otherwise a no-op. +It's important to note that there's a third type of opcodes which can cause the script to fail preemptively. These opcodes are usually in the form of \code{OP\_...VERIFY}. An example is \code{OP\_EQUALVERIFY} which causes the script to fail if the top 2 values of the stack are not equal, and is otherwise a no-op. Next we'll look at a couple of interesting classes of scripts. @@ -43,15 +49,17 @@ \subsubsection{Anyone-can-spend} \subsubsection{P2PKH} This is the standard script for conventional fund transfer in Bitcoin. Let's say we want to make sure only Bob can satisfy this script. The \textsf{pubKeyScript} is the following: \code{OP\_DUP OP\_HASH160 OP\_EQUALVERIFY OP\_CHECKSIG}. -The \textsf{scriptSig} is then typically \code{ }. Values in \code{<>} are placeholders for actual values, they're not valid script commands. These have to be replaced with concrete values before the above scripts can be valid. +The \textsf{scriptSig} is then typically \code{ }. Values in \code{<>} are placeholders for actual values \dznote{State your conventions in a separate notation chapter in the introduction, prior to here. This is not the place to do this.}, they're \dznote{avoid shortening words such as \emph{they are}} not valid script commands. These have to be replaced with concrete values before the above scripts can be valid. Bob's signature will be on the hash of the transaction (which we'll explore shortly) containing the output. The script will then duplicate his public key, check that it matches the one on the \text{pubKeyScript}, and if it does check that he has provided a valid signature with that public key. If all these checks pass the stack will end up with 1 on top and the execution will be valid, thus the predicate will be satisfied. +\dznote{The above section needs editorial work.} + \subsubsection{OP\_RETURNs} -It frequently is desired to add arbitrary data to the blockchain (e.g. for timestamping). To do this, one can make the arbitrary data part of the \textsf{pubKeyScript}. There's a special opcode for such cases called \code{OP\_RETURN} which can be followed by a series of arbitrary data (in hexadecimal). \code{OP\_RETURN} fails the script preemptively so no \code{scriptSig} can satisfy it. We'll see how based on \code{OP\_RETURN}s we can greatly augment the functionality of Bitcoin later on. +It is frequently desired to add arbitrary data to the blockchain (e.g. for timestamping \dznote{Cite Todd}). To do this, one can make \dznote{\emph{make} needs an object} the arbitrary data part of the \textsf{pubKeyScript}. There's a special opcode for such cases called \code{OP\_RETURN} which can be followed by a series of arbitrary data (in hexadecimal). \code{OP\_RETURN} causes the script to fail preemptively so no \code{scriptSig} can satisfy it. We'll see how based on \code{OP\_RETURN}s we can greatly augment the functionality of Bitcoin later on. \subsection{Outputs} -An \emph{output} is a tuple ({\sf value, pubKeyScript}). The \textsf{value} refers to an amount of Bitcoin in Satoshi (where $\sf 10^8 \, Satoshi = 1 \, Bitcoin$) and \textsf{pubKeyScript} is a script which needs to be run against some stack and return 1 in order for \textsf{value} to be transferable. +An \emph{output} is a tuple ({\sf value, pubKeyScript}). The \textsf{value} refers to an amount of Bitcoin in Satoshi (where $\sf 10^8 \, Satoshi = 1 \, Bitcoin$ \dznote{state the denominations of bitcoin in a small separate section}) and \textsf{pubKeyScript} is a script which needs to be run against some stack and return 1 in order for \textsf{value} to be transferable. \subsection{Inputs} An input is the way an output is redeemed. Specifically, it contains 3 things: @@ -66,11 +74,17 @@ \subsection{Inputs} As a convention, when we talk about the value of an input we mean the value of the output it redeems. \subsection{Transactions} -A \emph{transaction} is a collection of inputs and outputs. It uses the sum of the inputs values' as credit to debit each output accordingly. As it makes sense, a transaction is only valid as long as all its outputs and inputs are valid. It should also be clear that the value of the outputs should not exceed the value of the outputs, otherwise we would be creating value out of thin air with new transactions. Specifically this is expressed as $\sum_{\sf i \in inputs} {\sf i.value} \ge \sum_{\sf o \in outputs} {\sf o.value}$. This is sometimes called the \emph{Law of Conservation}. +\dznote{Reorganize this section in the way we have discussed. Move it prior to the scripts section. Assume initially that every output \textsf{scriptPubKey} is a p2pkh and go from there. Describe the UTXOs and accounts model of Bitcoin and Ethereum respectively. Only after these have been established you can talk about scripting and smart contracts.} + +\dznote{Give a graph-theoretic treatment of the transactions graph. The way it's currently written I find it quite confusing.} + +\dznote{You need a small section on public-key cryptography and its basic properties, as well as a reference to ECDSA.} + +A \emph{transaction} is a collection of inputs and outputs. It uses the sum of the inputs values' as credit to debit each output accordingly. As it makes sense, a transaction is only valid as long as all its outputs and inputs are valid. It should also be clear that the value of the outputs should not exceed the value of the inputs, otherwise we would be creating value out of thin air with new transactions. Specifically this is expressed as $\sum_{\sf i \in inputs} {\sf i.value} \ge \sum_{\sf o \in outputs} {\sf o.value}$. This is sometimes called the \emph{Law of Conservation}. In cases where $\sum_{\sf i \in inputs} {\sf i.value} > \sum_{\sf o \in outputs} {\sf o.value}$ we call $$\sum_{\sf i \in inputs} {\sf i.value} - \sum_{\sf o \in outputs} {\sf o.value}$$ -the \emph{transaction fee}. This is paid to the miner who successfully mines a block containing the transaction. This is one of the two ways Bitcoin uses to incentivize miners. +the \emph{transaction fee}. This is paid to the miner who successfully mines a block containing the transaction. This is one of the two ways Bitcoin uses to incentivize miners \dznote{What is a miner?}. \begin{figure} \centering @@ -80,7 +94,7 @@ \subsection{Transactions} \end{figure} \subsection{Blocks} -A block contains a list of transactions, the first of which is called the \emph{coinbase transaction} which is where value creation happens in Bitcoin. The miner crafts this transaction granting them some amount of Bitcoins and this transaction is going to be valid only if the block turns out valid. This doesn't mean that anyone can generate Bitcoin out of thin air: we'll see shortly how it actually comes at a cost with Proof-of-Work. +A block contains a list of transactions, the first of which \dznote{I don't think it's time to talk about coinbase here. First you must establish what blocks are good for (i.e., consensus). You can talk about incentivization, coinbase etc. later.} is called the \emph{coinbase transaction} which is where value creation happens in Bitcoin. The miner crafts this transaction granting them some amount of Bitcoins and this transaction is going to be valid only if the block turns out valid. This doesn't mean that anyone can generate Bitcoin out of thin air: we'll see shortly how it actually comes at a cost with Proof-of-Work. \begin{figure} \centering @@ -99,31 +113,39 @@ \subsection{Blocks} \end{figure} Once a transaction has been included in a valid block it's called \emph{confirmed}. +\dznote{You need to explain the basic consensus protocol somewhere. This includes adopting the longest chain, mining on top of it, broadcasting blocks found, and verifying received blocks on the network, as well as maintaining a mempool. You also need to state the problems that this solves, including the particular problem of double spending as well as the more generic problems of liveness and persistence. Cite the two backbones, by the way.} It's possible that there are contending chains of blocks. We then say there is a \emph{fork} on the chain. On Figure~\ref{fig:blocks}, the chain has forked on blocks 3 and 6. We call any valid blocks which are not part of our active chain \emph{orphans}. For example, on Figure~\ref{fig:blocks}, blocks 4b, 7a and 8a are orphans. \subsection{Proof-of-Work} -The key to making Bitcoin decentralized is a technique called Proof-of-Work. Proof-of-Work was first invented in 1992 by Dwork et al.~\cite{dwork} as a measure of limiting email spam and denial-of-service attacks and later explored by Back~\cite{hashcash} as Hashcash. +\dznote{My typical approach is to describe PoW prior to blocks. Do you think it would make reading easier?} + +The key to making Bitcoin decentralized is a technique called Proof-of-Work. Proof-of-Work was invented in 1992 by Dwork et al.~\cite{dwork} as a measure of limiting email spam and denial-of-service attacks and later explored by Back~\cite{hashcash} as Hashcash. -We'll examine a simplified model of Hashcash in order to explore the idea. Suppose we want to send an email to someone. In order to prove we've done work, we include a header (like \code{X-Hashcash}), which (very simplistically) includes the receiver's email address, and a nonce. -\footnote{Hashcash headers actually contain 7 different fields which have been omitted here for simplicity. The simplified version explained here is not making the same security guarantees as Hashcash.} +We'll examine a simplified model of Hashcash in order to explore the idea. Suppose we want to send an email to someone. In order to prove we've done work, we include a header (like \code{X-Hashcash}), which (very simplistically) includes the receiver's email address, and a nonce\footnote{Hashcash headers actually contain 7 different fields which have been omitted here for simplicity. The simplified version explained here is not making the same security guarantees as Hashcash.}. The nonce is picked so that the hash of the header $H(email || nonce)$ has its 20 most significant bits be all 0. The only feasible way to find this is by brute-forcing the nonce. Once the sender has found the nonce it's included in the header and sent. +\dznote{Include a code listing for the solution of proof-of-work} -The receiver can then very easily check whether the header hashes to a valid value. If that's so, the email it contains belongs to the receiver and the header is not being reused, then the email can be considered not spam. +The receiver can then very easily check whether the header hashes to a valid value. If so, the email it contains belongs to the receiver and the header is not being reused, then the email can be considered not spam. -To reiterate, the idea is having a series of data to commit to and a hole for the nonce, which is brute-forced to satisfy a necessary predicate on the hash, specifically that its $n$ most significant bits are all zeroes. This is exactly how Bitcoin implements Proof-of-Work. Instead of the hole being on an email header the hole is on the block header. For a block to be valid, its header has to satisfy a predicate like the above. +To reiterate, the idea is having a series of data to commit to and a hole for the nonce, which is brute-forced to satisfy a necessary predicate on the hash, specifically that its $n$ \dznote{I would avoid using $n$ here, as it is reserved for the number of parties in the Backbone model} most significant bits are all zeroes. This is exactly how Bitcoin implements Proof-of-Work. Instead of the hole being on an email header the hole is on the block header. For a block to be valid, its header has to satisfy a predicate like the above. Bitcoin introduces a couple of differences. $n$ varies according to the block generation rate. Specifically, to translate the previous predicate to Bitcoin terminology, the hash of each block header has to satisfy $H({\sf blockHeader}) \le T$ where $T$ is called the \emph{target}. As the target goes up, the probability of being below it goes up and generating a valid block is easier. Conversely, if the target goes down it's harder to generate a valid block. To express this, in Bitcoin $\frac{1}{T}$ is called the \emph{difficulty}. To account for the block generation rate, which Bitcoin tries to keep to 1 block per 10 minutes, every 2016 blocks the target (and subsequently the difficulty) is adjusted accordingly. The target is calculated inside the Bitcoin software and is only as a function of the blocks previously seen (frequently called their \emph{view}), so as long as the Bitcoin nodes agree on the view they'll agree on the target and all consider the same set of incoming blocks as valid. +\dznote{State the target recalculation equation} + +\dznote{The above section needs editorial work.} \subsection{\label{sec:merkle-trees}Merkle Trees} -A Merkle tree~\cite{merkle} is a data structure which allows a party to commit to a set of items using only a single hash, and prove the inclusion of any item in the committed set by providing a logarithmic proof in terms of the cardinality of the set. +\dznote{You need a small section on hashes in the intro. State your desired properties, including collision resistance. Perhaps even state the RO model.} +A Merkle tree~\cite{merkle} is a data structure which allows a party to commit to a set of items using \dznote{Merkle trees \emph{use} more than one hash; only the value of a single hash is sufficient to reveal for commitment} only a single hash, and prove the inclusion of any item in the committed set by providing a logarithmic proof in the cardinality of the set. -More specifically, the hashes of the items consist the leafs of the tree, and the last level. The internal levels are defined recursively as follows: To create level $k-1$ each pair of level $k$ $(A, B)$ is transformed as a node of value $H(A || B)$ which points to both $A$ and $B$. If the number of nodes at level $k$ is odd, the last node at that level is paired with itself. -\footnote{This specific construction is the one Bitcoin implements. There are various other constructions which are not inside the scope of this paper.} +More specifically, the hashes of the items consist the leafs of the tree, and the last level. The internal levels are defined recursively as follows: To create level $k-1$ each pair of level $k$ $(A, B)$ is transformed as a node of value $H(A || B)$ which points to both $A$ and $B$. If the number of nodes at level $k$ is odd, the last node at that level is paired with itself\footnote{This specific construction is the one Bitcoin implements. There are various other constructions which are not inside the scope of this paper.}. + +\dznote{The above couple of paragraphs need some editorial work.} Merkle trees are useful in Bitcoin in order to commit to a set of transactions to be included in a block while keeping the block header of a constant size. @@ -148,7 +170,7 @@ \subsection{\label{sec:merkle-trees}Merkle Trees} \end{algorithmic} \end{algorithm} -An example of a Bitcoin Merkle tree, along with a proof of inclusion for $K$ can be seen on Figure~\ref{fig:merkletree}. +An example of a Bitcoin Merkle tree, along with a proof of inclusion for $K$ can be seen on Figure~\ref{fig:merkletree}. \dznote{Explain the example.} \begin{figure} \centering @@ -158,7 +180,11 @@ \subsection{\label{sec:merkle-trees}Merkle Trees} \end{figure} \subsection{Simplified Payment Verification} -The size of the blockchain has reached 185GB by September 2018, which makes it a very time consuming or even infeasible process to synchronise a full node. Fortunately, a solution was proposed in the original whitepaper ~\cite{bitcoin}, which allows the creation of so-called \textit{lite nodes}. Lite nodes only know the headers of the entire blockchain, which are constant-size for each block (80 bytes). At the time of writing of this paper, the size of all block headers was $\sim$42MB. The lite node then asks the network for transactions concerning it (e.g.\ transactions concerning a specific public key). Full nodes of the network find such transactions and return them to the requester. For each transaction, the block header of the block it's included in is returned, along with a Merkle tree proof of inclusion which the lite node can then verify. This protocol is reliable as long as an adversary does not control the network of a lite node. +The size of the \dznote{which?} blockchain has reached 185GB by September 2018, which makes it a very time consuming or even infeasible process to synchronise a full node. Fortunately, a solution was proposed in the original whitepaper~\cite{bitcoin}, which allows the creation of so-called \textit{lite nodes}. Lite nodes only know the headers of the entire blockchain, which are constant-size for each block (80 bytes). At the time of writing of this paper, the size of all block headers was $\sim$42MB. The lite node then asks the network for transactions concerning it (e.g.\ transactions concerning a specific public key). Full nodes of the network find such transactions and return them to the requester. For each transaction, the block header of the block it's included in is returned, along with a Merkle tree proof of inclusion which the lite node can then verify. This protocol is reliable \dznote{You should include a sketch argument why this is somehow secure and not relying on a TPP for security.} as long as an adversary does not control the network of a lite node \dznote{Exposition of this assumption is uncalled for at this point. It makes the reader think that this assumption is particular to SPV, while it is also an assumption in the full node case. I would prefer a separate \emph{network} section where you will articular these assumptions. You can even cite the Bitcoin Eclipse papers from ETH.}. + +\dznote{At this point, I haven't yet seen an exposition of the three main node types in Bitcoin: Miners, Full nodes, SPV nodes. It would be nice to state these clearly and contrast them.} \subsection{Bitcoin Cash} -In 2017 Bitcoin faced severe scalability issues~\cite{onscaling}. Its limited 1MB block size meant that it could only support a maximum of 7 transactions per second. As Bitcoin's popularity had exploded at the time, the problem was hugely exacerbated. The most prominently proposed solution for this was a block size increase, however no consensus was reached. The discussions ended with a fork of the main Bitcoin chain which allowed for 8MB blocks, called Bitcoin Cash. +In 2017 Bitcoin faced severe scalability issues~\cite{onscaling}. Its limited 1MB block size meant that it could only support a maximum of 7 transactions per second. As Bitcoin's popularity had exploded at the time, the problem was hugely exacerbated. The most prominently proposed solution for this was a block size increase, however no consensus was reached. The discussions ended with a fork \dznote{What is a fork?} of the main Bitcoin chain which allowed for 8MB blocks, called Bitcoin Cash. + +\dznote{You need a background section on ethereum, smart contracts, accounts etc.} diff --git a/chapters/background/nipopows.tex b/chapters/background/nipopows.tex index c3d7c28..7a49da1 100644 --- a/chapters/background/nipopows.tex +++ b/chapters/background/nipopows.tex @@ -4,9 +4,9 @@ \section{Non-Interactive Proofs of Proofs of Work} % cite backbone model (proven secure in) TODO \subsection{The Prover-Verifier Model} -Before we talk about the specifics of proofs we first have to define our setting. In our setting we have two kinds of actors, \emph{provers} and \emph{verifiers}. +Before we talk about the specifics of proofs \dznote{What proofs?} we first have to define our setting. In our setting we have two kinds of actors, \emph{provers} and \emph{verifiers}. -A verifier is a party who wishes to know something about our blockchain. It's assumed it doesn't have network access (i.e. it can't be a full node). A verifier can be thought of as a Turing Machine which takes one or more proofs as input, and then determines whether a predicate is true or not. +A verifier is a party who wishes to know something about our blockchain. It's \dznote{Avoid using \emph{it's} for \emph{it is}, \emph{doesn't} for \emph{does not}, and \emph{can't} for \emph{can not} here and throughout the text.} assumed it doesn't have network access (i.e. it can't be a full node). A verifier can be thought of as a Turing Machine which takes one or more proofs as input, and then determines whether a predicate \dznote{What predicate? You seem to be implying that these are chain predicates, but the reader does not know this.} is true or not. Provers are parties with access to our blockchain's network, who wish to communicate to the verifier and convince them about a predicate. @@ -36,7 +36,7 @@ \subsection{Assumptions} In the next section we'll look at how we sidestep all those issues. \subsection{Levels} -At the heart of the primitive lies the separation of blocks into levels. The level of a block is defined as $\textit{level}(B) = \left \lfloor \log(T) - \log(\sf{id}(B)) \right \rfloor$, where $T$ is the constant difficulty of the blockchain. The genesis block is an exception to this rule as $\textit{level}(Gen) = \infty$. We call a block of level $\mu$ a $\mu$-superblock. +At the heart of the primitive lies the separation of blocks into levels. The level of a block is defined as $\textit{level}(B) = \left \lfloor \log(T) - \log(\sf{id}(B)) \right \rfloor$, where $T$ is the constant difficulty of the blockchain. The genesis block is an exception to this rule as \dznote{we define} $\textit{level}(Gen) = \infty$. We call a block of level $\mu$ a $\mu$-superblock. Intuitively, the level of a block is the number of leading zeros of the binary representation of the block id when left padded to the length of $T$. An example of this can be seen on Table~\ref{table:level-counting}. @@ -53,7 +53,7 @@ \subsection{Levels} \label{table:level-counting} \end{table} -Figure~\ref{fig:hierarchy} shows an example the implied blockchain created from the superblocks. +Figure~\ref{fig:hierarchy} shows an example \dznote{of} the implied blockchain created from the superblocks. \begin{figure} \centering @@ -66,16 +66,16 @@ \subsection{Notation} The NIPoPoWs paper introduces some notation for talking about blockchains with levels which we'll be using extensively. The notation is widely influenced by Python. Specifically: \begin{itemize} - \item $\chain$ denotes a blockchain, with $\chain[0]$ being the genesis block, $\chain[k]$ being the $k$-th first block and $\chain[-k]$ being the $k$-th last block. + \item $\chain$ denotes a blockchain, with $\chain[0]$ being the genesis block, $\chain[k]$ being the $k$-th block from the beginning and $\chain[-k]$ being the $k$-th last block. \item $\chain[k:]$ denotes the sub-blockchain starting from the $k$-th block, $\chain[-k:]$ denotes the sub-blockchain starting from the $k$-th last block. \item $\chain[:k]$ denotes the sub-blockchain ending before the $k$-th block, $\chain[:-k]$ denotes the sub-blockchain ending before the $k$-th last block. \item $\chain[i:j]$ denotes the sub-blockchain starting from the $i$-th block and ending at the $j$-th block. $i$ and $j$ can also be negative numbers similar to above. - \item $\chain\{B:\}$ denotes the sub-blockchain starting from the block with block id $B$. - \item $\chain\upchain^\mu$ denotes the sub-blockchain of $\chain$ where all blocks are of level $\mu$ or higher. + \item $\chain\{B:\}$ denotes the sub-blockchain starting from the block with block id $B$. \dznote{I did not intend to use $B$ as a blockid here; rather, it is literally a \emph{block}, the mathematical object.} + \item $\chain\upchain^\mu$ denotes the sub-blockchain of $\chain$ where all blocks are of level $\mu$ or higher. \dznote{Here you should state that intermediate blocks could have been skipped.} \end{itemize} \subsection{Interlink} -Instead of keeping only the hash of the previous block inside the block header, for every superblock level we keep a pointer to the most recent superblock of that level. The structure containing these pointers is called the interlink. Bitcoin does not support such a structure in the block header but we will study how to sidestep this issue by velvet forking in a few sections. +Instead of keeping only the hash of the previous block inside the block header, for every superblock level we keep a pointer to the most recent superblock of that level. The structure containing these pointers is called the \emph{interlink}. Bitcoin does not support such a structure in the block header but we will study how to sidestep this issue by velvet forking in a few sections. \begin{table} \centering @@ -96,7 +96,7 @@ \subsection{Interlink} It's important to note that the interlink can be encoded as a series of block ids, starting from $0$ up to $\infty$. It can also be compressed by using this series as the leafs of a Merkle tree and taking the Merkle tree root. -Suppose we have a block $B'$ with an interlink stored as $B'.{\sf interlink}$. In order to produce the interlink for a block after $B'$ we make sure to change all pointers from level $0$ up to $level(B')$ to point to $B'$, as $B'$ will be the most recent block at these levels (remember that a block of level $\mu$ is also of level $\mu-1$). We call this procedure {\sf updateInterlink}, which can be seen in detail on Algorithm~\ref{alg.nipopow-interlink}. +Suppose we have a block $B'$ with an interlink stored as $B'.{\sf interlink}$. In order to produce the interlink for the block after $B'$ we make sure to change all pointers from level $0$ up to $level(B')$ to point to $B'$, as $B'$ will be the most recent block at these levels (remember that a block of level $\mu$ is also of level $\mu-1$ \dznote{this is not clear from your definition above}). We call this procedure {\sf updateInterlink}, which can be seen in detail on Algorithm~\ref{alg.nipopow-interlink}. \input{algorithms/alg.nipopow-interlink.tex} @@ -107,7 +107,7 @@ \subsection{Suffix Proofs} The process for constructing $\pi$ is a little more convoluted. First we have to find the first level $\mu$ where $|\chain\upchain^\mu| \ge m$. We call this level $max\mu$. For this level we take all its blocks except for the last $m$: $\pi_{max\mu} = \chain\upchain^\mu[:-m]$. Then for every level $\mu$ from $max\mu - 1$ to $0$, we take blocks $\pi_\mu = \chain\upchain^\mu [:-m]\{\chain\upchain^{\mu+1}[-m]:\}$. -$\pi$ is then evaluated as the concatenation of all those chains starting from the oldest block: +$\pi$ is then evaluated as the concatenation \dznote{Given the fact that in the expression below there are block duplicates, I do not think that it produces a chain.} of all those chains starting from the oldest block: $$ \pi = \pi_{max\mu} || \pi_{max\mu-1} || \ldots || \pi_0 $$ @@ -118,10 +118,12 @@ \subsection{Suffix Proofs} \label{fig:suffix-proof} \end{figure} -It's important to notice that the chain provided to the verifier is an actual chain: one can start at the end and traverse it until the genesis block by utilizing the interlink of each block, similar to how they would do that on a conventional blockchain by using each block's $\sf previd$. +It's important to notice that the chain provided to the verifier is an actual chain: one can start at the end and traverse it until the genesis block by utilizing the interlink of each block, similar to the way they would process a conventional blockchain by using each block's $\sf previd$. + +\dznote{Include the suffix prover algorithm here, or your rendition of it.} \subsection{Infix Proofs} -For the verifier to be able to determine a predicate on one or more blocks ($\chain' \subseteq \chain$) of our chain, we have to make sure we include them in a proof. A suffix proof is not guaranteed to include all blocks of interest in $\chain'$. In order to include these we have to make sure they are linked to the proof, e.g. that the proof chain is a traversable. To this end, let's assume some arbitrary block $B \in \chain'$. Let's also assume an existing suffix proof $\pi\chi$. We find blocks $E'$ and $E$ on the suffix proof, such that: +For the verifier to be able to determine a predicate on one or more blocks ($\chain' \subseteq \chain$) of our chain, we have to make sure we include them in a proof. A suffix proof is not guaranteed to include all blocks of interest in $\chain'$. In order to include these we have to make sure they are linked to the proof, e.g. that the proof chain is a traversable. To this end, let $B \in \chain'$ be an arbitrary block. Let $\pi\chi$ be an existing suffix proof \dznote{You are not \emph{assuming} anything, you are \emph{letting} your variables, so do not use the word \emph{assume}}. We find blocks $E'$ and $E$ on the suffix proof, such that: \begin{itemize} \item $E$ is the next block after $E'$ on the proof @@ -146,11 +148,15 @@ \subsection{Infix Proofs} \subsection{Proof Verification} \subsection{Velvet Forks} +\dznote{Velvet forks are a central point of your thesis. You must expand and discuss this a lot. See Buterin's blog post on soft, hard, and bilateral hard forks. I would expect to see something similar in your introduction. You definitely have to go into details about what a soft fork is, what hard fork is, and what a velvet fork is, as well as include a few venn diagrams. See also the slides of my 6-hour lecture on NIPoPoWs where similar diagrams are included, as well as Vitalik's diagrams.} + Velvet forks~\cite{nipopows,velvet} describe a formalization of adding arbitrary data inside blocks in order to allow potential applications without sacrificing the backwards compatibility of the blockchain. -Miners who are willing to contribute to the fork can add data of interest in the form of coinbase transaction data. +Miners who are willing to contribute to the fork can add data of interest in the form of coinbase transaction data. + +Backwards compatibility is achieved by not changing the consensus rules, meaning that set of acceptable blocks does not change. So any block that was acceptable remains acceptable even if it does not contain any data concerning the fork, or if it contains invalid data. \dznote{Here it is best to talk about some sort of \emph{validity language}, although you can avoid the formalities of the PoS sidechains paper.} -Backwards compatibility is achieved by not changing the consensus rules, meaning that set of acceptable blocks does not change. So any block that was acceptable remains acceptable even if it does not contain any data concerning the fork, or if it contains invalid data. +\dznote{You should speak about how upgraded miners accept blocks that have incorrect velvet data, and how this is not a threat to security.} \subsection{User-Activated Velvet Forks} In case miners aren't interested in including such data, users can also create such a fork by making a kind of transaction called velvet transaction. In a velvet transaction a user includes any data of interest in unspendable transaction outputs (like OP\_RETURN). @@ -159,4 +165,4 @@ \subsection{User-Activated Velvet Forks} Such forks come at the cost of making such transactions, because the user who makes the fork needs to pay transaction fees every time they wish to add data to the blockchain. -For our application, we implemented a User-Activated Velvet Fork in order to add the interlink data structure to Bitcoin Cash blocks. Since Bitcoin Cash has very low fees, a projection of running such a fork comes at around 10€/month. +For our application, we implemented a User-Activated Velvet Fork in order to add the interlink data structure to Bitcoin Cash blocks. Since Bitcoin Cash has very low fees; a projection of running such a fork comes at around 10€/month. diff --git a/chapters/interlinker.tex b/chapters/interlinker.tex index 52c1c5d..51657ce 100644 --- a/chapters/interlinker.tex +++ b/chapters/interlinker.tex @@ -1,36 +1,42 @@ \chapter{Velvet Fork Implementation} -Now that we have seen how NIPoPoWs work and what options we have in our disposal to deploy them to existing blockchains, we will investigate how we implemented NIPoPoWs on Bitcoin Cash. +\dznote{I think you should state, ideally in a separate section, an overview (in the form of a list) of what you will be presenting that is your own creation, stating the purpose of each part of the architecture. You should provide an architectural diagram. You should also clearly state some metrics about your code (in terms of lines of code) and state that you will only be presenting some of the more interesting parts of the code, in a simplified format for exposition, and that the interested reader can refer to your repositories. Finally you should state what open source license you have used and include your GitHub URLs.} + +Now that we have seen how NIPoPoWs work and what options we have at our disposal to deploy them to existing blockchains, we will investigate how we implemented NIPoPoWs on Bitcoin Cash. \pdffigure{blocks-with-their-interlinks}{Example of blocks with their corresponding interlinks for $T = 100000$. Note that for the upcoming block marked with \textbf{?} we can produce its interlink without knowing its hash.} -Since Bitcoin Cash blocks don't contain the interlink we have to utilize a velvet fork. We could choose a regular velvet fork. A regular velvet fork would require for a miner minority to exist and run code which would add the interlink inside the coinbase transaction. Finding and contacting miners would require a lot of non-technical work and persuasion. It would also mean that probably only a minority of the blocks would be validly interlinked. Seeing that persuading miners would require a lot of work and would not bring an ideal outcome we decided to implement a User-Activated Velvet Fork instead. +Since Bitcoin Cash blocks don't contain the interlink, we have to utilize a velvet fork. We could choose a regular velvet fork. A regular velvet fork would require for a miner minority to exist and run code which would add the interlink inside the coinbase transaction. Finding and contacting miners would require a lot of non-technical work and persuasion. It would also mean that probably only a minority of the blocks would be validly interlinked. Seeing that persuading miners would require a lot of work and would not bring an ideal outcome we decided to implement a User-Activated Velvet Fork instead. To this end, we need to make sure that a transaction is included in every single block containing its implied interlink. We do this by implementing a service which for every new block, calculates the expected interlink of the upcoming block and sends a transaction including this interlink in hopes that it will be included in the upcoming block. If this is indeed achieved then that block will indeed contain its valid interlink. We henceforth call the service which does this an \emph{interlinker}. An example of blocks and their corresponding interlinks can be seen on Figure~\ref{fig:blocks-with-their-interlinks}. \section{Picking a Velvet Genesis} -Naturally one would expect the interlink to start from the real blockchain genesis as it would enable proofs for any already existing block of that blockchain. However, for older blocks there can be no improvement. There is no other option than providing the full chain as a proof since no older blocks contain any interlinks. Thus in order to avoid accounting in our interlink for blocks in the past that can only be connected to the real genesis by supplying the full chain we choose a new genesis called the \emph{velvet genesis}. For our purposes in Bitcoin Cash testnet we chose the block with height 1257603 as our velvet genesis. +Naturally one would expect the interlink to start from the real blockchain genesis as it would enable proofs for any already existing block of that blockchain. However, for older blocks there can be no improvement \dznote{why?}. There is no other option than providing the full chain as a proof since no older blocks contain any interlinks. Thus in order to avoid accounting in our interlink for blocks in the past that can only be connected to the real genesis by supplying the full chain we choose a new genesis called the \emph{velvet genesis}. For our purposes in Bitcoin Cash testnet we chose the block with height 1257603 as our velvet genesis. + +\dznote{Expand a bit on the above section.} \section{Interlink encoding} -We now have to consider our options for representing the interlink. -Bitcoin Cash uses SHA-256 for the block hashes, meaning that each block id consists of 32 bytes. -A naive encoding would be one where each 32-byte block hash from level $0$ up to $\infty$ is concatenated, with the $\infty$ pointer always pointing to the genesis block.. +We now have to consider our options for representing the interlink. +Bitcoin Cash uses SHA-256 for the block hashes \dznote{you can state this in the introduction, with an appropriate SHA-256 citation}, meaning that each block id consists of 32 bytes. +A naive encoding would be one where each 32-byte block hash from level $0$ up to $\infty$ is concatenated, with the $\infty$ pointer always pointing to the genesis block. For 35 levels, which according to Figure~\ref{fig:bitcoin-cash-testnet-levels-after-velvet-genesis} is a reasonable figure, this encoding would take approximately 1.12KB. Considering that \code{OP\_RETURN} scripts are limited in size to 223 bytes, this would only allow us to include up to 6 pointers at best. -\pdffigure{bitcoin-cash-testnet-levels-after-velvet-genesis}{Number of levels assuming our selected velvet genesis.} +\pdffigure{bitcoin-cash-testnet-levels-after-velvet-genesis}{Number of levels assuming our selected velvet genesis. \dznote{Redo your figure using LaTeX fonts. See my figure in the Egalitarianism paper for the respective matplotlib code. Also consider usingn log-scale in the horizontal axis.}} Putting this limitation aside, the fee of the transaction is proportional to the transaction size, and since we're going to be sending a transaction for every block (which is mined approximately every 10 minutes), it is important that the fee is minimized. Thus in order to save space, we only include a commitment to the interlink in our transactions. Specifically, we take the Merkle Tree root of the Merkle Tree with leafs the block hashes starting from level $0$ up to $\infty$. This way, our interlink encoding is constant size and we can easily provide compact proofs for any of the levels. +\dznote{Expand on the above section. This is a central piece of your thesis. Show an example of an interlink merkle tree and a proof. Also discuss your proposed improvement as a set instead of a list. This is your invention and you should state it as your contribution. You should also clearly state that you are the first to provide a practical implementation of interlinking also in the \emph{Our contributions} section of your introduction.} + \section{Discoverability} -We've talked about how just including the interlink somewhere on a block is what really matters but it is crucial that we make this information easy to discover. We achieve this in two ways. First, we include the interlink commitment inside a special \code{OP\_RETURN} output. Such outputs are already being used for storing arbitrary data in blocks~\cite{arbitrary-data} therefore we adopt this method for storing our interlinks. Second, we aim to make this interlink discoverable for lite nodes, so we don't require our users to download a whole block in order to look into it. We achieve this by utilizing a method called \emph{SPV tagged outputs}~\cite{spv-tagged}. +We've talked about how just including the interlink somewhere on a block is what really matters \dznote{have you?} but it is crucial that we make this information easy to discover. We achieve this in two ways. First, we include the interlink commitment inside a special \code{OP\_RETURN} output. Such outputs are already being used for storing arbitrary data in blocks~\cite{arbitrary-data} therefore we adopt this method for storing our interlinks. Second, we aim to make this interlink discoverable for lite nodes, so we don't require our users to download a whole block in order to look into it \dznote{This is an important contribution and you should not downplay it. Expand a bit on this section. Show the transaction graph of the example transaction. Also make sure the reader understands that the PROVER is a lite node and not a full node, which is an important achievement! You should also state that you are not only the first work to deploy a velvet interlinker, but also the first to do it with a lite prover; you should also state that this was not anticipated in the original papers and it is your own invention, even though it is a combination of prior ideas}. We achieve this by utilizing a method called \emph{SPV tagged outputs}~\cite{spv-tagged}. -SPV tagged outputs are outputs that are tagged so that they can be discovered by SPV nodes who add the ``tag'' to the filter. Specifically, we form outputs of the form \code{OP\_RETURN baba deadbeef}, where \code{baba} is our tag and \code{deadbeef} is our payload (in our case, the interlink commitment). A bloom filter for \code{baba} will then match this output and subsequently the transaction that contains it and this is how our specialized SPV nodes can discover our outputs. The full nodes forwarding the velvet transactions to the SPV nodes don't have any knowledge of what a velvet fork even is, let alone that they are forwarding its transactions. +SPV tagged outputs are outputs that are tagged so that they can be discovered by SPV nodes who add the ``tag'' to the filter. Specifically, we form outputs of the form \code{OP\_RETURN baba deadbeef}, where \code{baba} is our tag and \code{deadbeef} is our payload (in our case, the interlink commitment). A bloom filter \dznote{what is a bloom filter?} for \code{baba} will then match this output \dznote{do SPV nodes use bloom filters for matching?} and subsequently the transaction that contains it and this is how our specialized SPV nodes can discover our outputs. The full nodes forwarding the velvet transactions to the SPV nodes don't have any knowledge of what a velvet fork even is, let alone that they are forwarding its transactions. The tag we use for our transactions is \code{696e7465726c696e6b}, which is the ASCII encoding of \code{interlink}. An example of such a real-world velvet transaction created by our deployed interlinker on the Bitcoin Cash testnet can be seen on Figure~\ref{fig:actual-velvet-tx}. -\pngfigure{actual-velvet-tx}{An actual velvet fork transaction.} +\pngfigure{actual-velvet-tx}{An actual velvet fork transaction. \dznote{Some of the text is unreadable. Ideally you want the smallest text in the figure to be equal in size to your main body text. You already have paddings in this figure that you can remove to make it slightly larger. See if you can also repeat the outputs in the main text and explain them in detail.}} \section{Fault Tolerance} It is important to note that the interlinker works on a best-effort basis. Due to the nature of Velvet Forks though, no failure is fatal. The types of failures are as follows: @@ -43,12 +49,12 @@ \section{Fault Tolerance} \item \textbf{Arbitrary failure}: The interlinker pushes a transaction before a new block is seen or pushes a duplicate for a specific upcoming block twice. \end{itemize} -We will study how these failures can be mitigated in the next section. +We will study how these failures can be mitigated in the next section. \dznote{You should state that you are the first to do an interlinker failure analysis using a traditional systems approach.} \section{Viability} -Making the operation of the interlinker affordable is key in order to allow many parties to run it. We will estimate the cost of operation now. +Making the operation of the interlinker affordable is key in order to allow many parties to run it. We will estimate the cost of operation now. \dznote{You should say that you are the first to give such estimated (or if Glou did, compare against him)} -Our transaction size ($\sf txBytes$) is constant at exactly 244 bytes. The median Bitcoin Cash fee per byte ($\sf feePerByte$) at the time of writing (November 2018) is 1 satoshi. Multiplied by our transaction size this gives us a transaction fee ($\sf txFee = txBytes * feePerByte$) of 244 satoshis. Our complete estimations based on the current price of Bitcoin Cash can be seen on Table~\ref{tbl:cost-analysis}. +Our transaction size ($\sf txBytes$) is constant at exactly 244 bytes. The median Bitcoin Cash fee per byte ($\sf feePerByte$) at the time of writing (November 2018) is 1 satoshi. Multiplied by our transaction size this gives us a transaction fee ($\sf txFee = txBytes * feePerByte$) of 244 satoshis. Our complete estimations based on the current price of Bitcoin Cash can be seen on Table~\ref{tbl:cost-analysis}. \dznote{State here that you aim to have one transaction per block. Show the trade-off as you decreased the velvet $g$ value in a graph. For example, what happens if you have one velvet block per ten regular blocks?} \begin{table} \centering @@ -65,10 +71,10 @@ \section{Viability} \label{tbl:cost-analysis} \end{table} -We provide two implementations of an interlinker which both run in production. We'll now look at the pros and cons of each. +We provide \dznote{You are downplaying your work. You should state it much more proudly. For example: In the scope of this work, we have developed two separate production implementations of an interlinker. These are also the first interlinkers to have ever been developed and deploying on any blockchain network. We have been running both implementations as a service to the community with an uptime of such and such...} two implementations of an interlinker which both run in production. We'll now look at the pros and cons of each. \section{Python implementation with Bitcoin-ABC} -Our first implementation is built on top of Bitcoin-ABC. Bitcoin-ABC is the reference implementation for Bitcoin Cash in C++. It is a fork of the original Bitcoin codebase (now Bitcoin Core), and it was the first ever implementation to support Bitcoin Cash. It has a very active community of developers and users. Due to its heritage from Bitcoin Core the code is very well written and tested, and any new feature for the Bitcoin Cash chain appears on Bitcoin-ABC first. +Our first implementation is built on top of Bitcoin-ABC \dznote{cite?}. Bitcoin-ABC is the reference implementation for Bitcoin Cash in C++. It is a fork of the original Bitcoin codebase (now Bitcoin Core), and it was the first ever implementation to support Bitcoin Cash. It has a very active community of developers and users. Due to its heritage from Bitcoin Core the code is very well written and tested, and any new feature for the Bitcoin Cash chain appears on Bitcoin-ABC first. We run Bitcoin-ABC as a full node and interface with it using JSON-RPC. The interlinker is a Python module which knows (a) the location and credentials to connect with the full node and (b) the velvet fork genesis block id. We use the python-bitcoinrpc library~\cite{python-bitcoinrpc} for the JSON-RPC communication. @@ -90,6 +96,8 @@ \subsection{Block Discovery} tip_id = possibly_new_tip_id \end{lstlisting} +\dznote{The above section is well written.} + \subsection{Reaction to a New Block} When there is a new block, the interlinker computes the correct interlink for it, by updating the interlink with all the intermediate blocks from the velvet fork genesis up to and including the new block. It then computes the Merkle Tree root and includes it in an SPV tagged output. Subsequently it wraps the output inside a change transaction and sends it to the network. @@ -105,9 +113,11 @@ \subsection{Reaction to a New Block} logger.info('velvet tx "%s"', send_velvet_tx(new_interlink.hash())) \end{lstlisting} +\dznote{The above section is well written.} + \subsection{Calculating the Interlink} -The naive way to calculate the interlink would be starting from the velvet genesis block to keep a running interlink and sequentially update it. Considering that between the tip and the velvet genesis there could be millions of blocks, and for each block we need to issue a JSON-RPC call to get its block hash by using \code{getblockhash}. We experimentally found this method to take upwards of 15 seconds for approximately 15000 blocks, averaging at 1000 blocks/second. +The naive way to calculate the interlink would be starting from the velvet genesis block to keep a running interlink and sequentially update it \dznote{what?}. Considering that between the tip and the velvet genesis there could be millions of blocks, and for each block we need to issue a JSON-RPC call to get its block hash by using \code{getblockhash} \dznote{this sentence no verb}. We experimentally found this method to take upwards of 15 seconds for approximately 15000 blocks, averaging at 1000 blocks/second. To make this process faster we cache all interlinks we compute. This caching happens inside the \code{store} shown in the code below. \code{store} is a dictionary which maps block ids to their corresponding interlinks. In order to compute an interlink for a given tip we traverse the blockchain from the tip until we end up at a block for which the interlink is already available. We always ensure the cache contains at least the interlink for the velvet genesis which is empty and only contains the genesis pointer (of level $\infty$). We keep the block ids between the tip and the block with the cached interlink and then proceed to update the interlink that was found with each intermediate block id, in order. In doing so we also save each interlink we compute to its corresponding block id in the store, so that it will be available if we ever need it again. After the interlink has been updated with all blocks we are done and we can return it as the final result. @@ -155,6 +165,7 @@ \subsection{Interlink} blocks.append(block_id) return Interlink(genesis=self.genesis, blocks=blocks) \end{lstlisting} +\dznote{An example of the interlink construtor over multiple invocations would be in place.} The commitment is generated by the \code{hash} method defined on \code{Interlink}, which after getting the representation of the interlink as an array, including the velvet genesis as the last element, then calculates the Merkle Tree root (abbreviated as \code{mtr}) of a tree with the elements of this array as leaves. @@ -166,11 +177,13 @@ \subsection{Interlink} return mtr(self.as_array()) \end{lstlisting} +\dznote{The above section is good.} + \subsection{Bitcoin-style Merkle Trees} For implementing the \code{mtr} function seen above we searched for existing Python libraries offering this functionality. While some libraries came up, none of them implemented the Bitcoin-style Merkle Trees we were after. This functionality is definitely implemented in some of more general Python Bitcoin libraries we make use of however it isn't exposed. This led us to write our own implementation of Bitcoin-style Merkle Trees. -We only implement the root calculation as described in Section~\ref{sec:merkle-trees} in \code{mtr}. \code{mtr} accepts an array of leafs. The function works by taking a level of the tree (initially the leafs) and repeatedly generating the upper level. This process continues until the level reached only has one element, where it's declared the root and is returned as the result. The function for generating the upper level, \code{next\_level} uses many Python idioms and this requires an explanation. It starts by taking a level and then pairing its element with its adjacent. This happens with \code{zip\_longest} which takes 2 lists and "zips" them together like so: \code{zip\_longest([1, 2, 3], [4, 5, 6]) = [(1, 4), (2, 5), (3, 6)]}. For the uninitiated we provide a Haskell implementation below. +We only implement the root calculation as described in Section~\ref{sec:merkle-trees} in \code{mtr}. \code{mtr} accepts an array of leafs. The function works by taking a level of the tree (initially the leafs) and repeatedly generating the upper level. This process continues until the level reached only has one element, where it's declared the root and is returned as the result. The function for generating the upper level, \code{next\_level} uses many Python idioms and this requires an explanation. It starts by taking a level and then pairing its element with its adjacent. This happens with \code{zip\_longest} which takes 2 lists and ``zips'' them together like so: \code{zip\_longest([1, 2, 3], [4, 5, 6]) = [(1, 4), (2, 5), (3, 6)]}. For the uninitiated we provide a Haskell implementation below. \begin{lstlisting}[language=Haskell] zip_longest :: [a] -> [a] -> a -> [a] @@ -199,6 +212,7 @@ \subsection{Bitcoin-style Merkle Trees} h2.update(h1.digest()) return h2.digest() \end{lstlisting} +\dznote{This seems to be hashing the value of \texttt{l} with the hash of \texttt{r}, i.e. $H(l || H(r))$. Is this what you wanted?} This setup makes our Merkle Tree root calculation very straightforward. @@ -211,6 +225,8 @@ \subsection{Bitcoin-style Merkle Trees} return level[0] \end{lstlisting} +\dznote{The above is well written.} + \subsection{Velvet Transactions} For creating the SPV tagged outputs we utilize the python-bitcoinlib library~\cite{python-bitcoinlib}. We construct the outputs array including a single script with the \code{OP\_RETURN}, our SPV tag which is the ASCII encoding for \code{interlink} and our payload which we expect to be our interlink commitment. We then serialize a transaction with this output. @@ -223,8 +239,9 @@ \subsection{Velvet Transactions} tx = CMutableTransaction([], digest_outs) return tx.serialize().hex() \end{lstlisting} +\dznote{You need to fix your single quotes in your code listings.} -The next stage is to actually send the transaction. Of course a transaction with only one output is incomplete and invalid. In order to fill it in with the appropriate inputs and change output we turn to our Bitcoin-ABC node. We use the \code{fundrawtransaction} JSON-RPC method in order to do all the above. We then only have to sign and send the transaction out in the network. +The next stage is to actually send the transaction. Of course a transaction with only one output is incomplete and invalid \dznote{no it is not}. In order to fill it in with the appropriate inputs and change output we turn to our Bitcoin-ABC node. We use the \code{fundrawtransaction} JSON-RPC method in order to do all the above. We then only have to sign and send the transaction out in the network. \begin{lstlisting}[language=Python] def send_velvet_tx(payload_buf): @@ -297,13 +314,14 @@ \subsection{Testing} mtr([]) \end{lstlisting} +\dznote{Include some testing coverage metrics here. Also talk about your continuous integration.} + \subsection{Distribution} -Our software is production-grade and we release it under the open source MIT license. -\footnote{The code is available at \url{https://github.com/decrypto-org/bch-interlinker}}. +Our software is production-grade and we release it under the open source MIT license\footnote{The code is available at \url{https://github.com/decrypto-org/bch-interlinker}}. \section{JavaScript implementation with bcash} -The second implementation is build on top of the bcash JavaScript library. bcash implements a full node and wallet functionality exclusively in JavaScript without being based on the Bitcoin C++ codebase as did most previous solutions. A major advantage of bcash is that it implements an SPV node too, which is very useful since the interlinker only needs the block ids of the chain but doesn't need to know about the block contents, so requiring a full node to run it would be a waste of space and bandwidth. +The second implementation is build on top of the bcash \dznote{cite} JavaScript library. bcash implements a full node and wallet functionality exclusively in JavaScript without being based on the Bitcoin C++ codebase as did most previous solutions. A major advantage of bcash is that it implements an SPV node too, which is very useful since the interlinker only needs the block ids of the chain but doesn't need to know about the block contents, so requiring a full node to run it would be a waste of space and bandwidth. \subsection{Architecture} The bcash architecture is a departure from the JSON-RPC paradigm described above and requires some explanation. One major difference is that this implementation doesn't require an external node: the interlinker is a standalone program which due to the bcash library is also an SPV node. bcash offers Node classes which are standalone nodes. Apart from SPV it also offers a \code{FullNode} class. @@ -352,6 +370,8 @@ \subsection{Synchronization} } \end{lstlisting} +\dznote{Why do you need that \texttt{.then()}?} + \subsection{Reaction to a New Block} Whenever a new block occurs we calculate the interlink and send a transaction with its commitment just as before. This code looks almost identical in form to the previous implementation: we compute the interlink, calculate the commitment, create a transaction with a tagged SPV output and send it. Here \code{wallet.send} additionally takes care of the funding we saw in the previous implementation. @@ -376,8 +396,10 @@ \subsection{Reaction to a New Block} } \end{lstlisting} +\dznote{Would you like to write here a few words about the change addresses and other details?} + \subsection{Calculating the Interlink} -Here we implement the naive approach that we discussed in the previous implementation for calculating the interlink. We can safely do this as there are no speed concerns, seeing that we have direct access to our chain and no JSON-RPC calls need to transpire here. This makes this procedure almost instant. +Here we implement the naive approach that we discussed in the previous implementation for calculating the interlink. We can safely do this as there are no speed concerns, seeing that we have direct access to our chain and no JSON-RPC calls need to transpire here. This makes the procedure almost instant. \begin{lstlisting}[language=js] async getInterlinkSinceBlock(blockId) { @@ -398,7 +420,7 @@ \subsection{Calculating the Interlink} \end{lstlisting} \subsection{Interlink Representation} -In similar fashion to the previous implementation we represent the interlink as a Plain Old JavaScript Object. Note that here our \code{update} is destructive in contrast as we don't utilize the immutability for caching. +In similar fashion to the previous implementation we represent the interlink as a Plain Old JavaScript Object. Note that here, in contrast, our \code{update} is destructive as we don't utilize the immutability for caching. \begin{lstlisting}[language=js] class Interlink { @@ -418,7 +440,9 @@ \subsection{Interlink Representation} } \end{lstlisting} -Calculating the commitment here is much easier here, as bcash provides as with a good API for creating and manipulating Bitcoin-style Merkle Trees. +\dznote{Maybe you can give an example of how the \texttt{update} function would work over multiple invocations. It's not clear at first sight.} + +Calculating the commitment is much easier here, as bcash provides us with a good API for creating and manipulating Bitcoin-style Merkle Trees. \begin{lstlisting}[language=js] hash() { @@ -445,8 +469,7 @@ \subsection{Velvet Transactions} \subsection{Distribution} -Our software is production-grade and we release it under the open source MIT license. -\footnote{The code is available at \url{https://github.com/gtklocker/bcash-interlinker-js}}. +Our software is production-grade and we release it under the open source MIT license\footnote{The code is available at \url{https://github.com/gtklocker/bcash-interlinker-js}}. \section{Deployment} At the time of writing of this thesis, both implementations run in production on the Bitcoin Cash testnet chain and have been running for over 3 months. We started with our first deployment late September 2018, with the first prototype of our Python interlinker. This gave us a chance to catch bugs that only appear on long running processes and make sure our software is resilient to network and other library failures. As new features and bug fixes kept rolling in our software we continuously updated the deployments. @@ -457,17 +480,25 @@ \subsection{Docker} We provide \code{Dockerfile}s for both our implementations. +\dznote{List (parts of) your docker files. If they're long, put them in the appendix.} + \subsection{docker-compose} We also rely on docker-compose~\cite{docker-compose} in order to make deployments easy, having a single configuration which describes for example how the ABC node and our Python interlinker should be wired together in order to work well. All in all, this makes for a very quick and painless deployment process, allowing any interested party to run the interlinker on their own. docker-compose was especially invaluable in painlessly keeping our deployment in sync with our continuously changing codebases. We provide reference \code{docker-compose.yml} files for both our implementations. +\dznote{List your docker-compose files, here or in the appendix. Also say that they are included in the respective repositories.} + \section{Experimental Data} \pdffigure{testnet-deployment-reliability}{Reliability of our testnet deployment.} -We will now examine real-world data gathered from our Bitcoin Cash testnet deployment. On Figure~\ref{fig:testnet-deployment-reliability} we can look at the reliability of our interlinker deployment. We can see that about 60\% of the blocks have been correctly interlinked with our velvet transactions, and about 10\% of them only have 1 interlink pointer missing, which makes them potentially usable. With $\infty$ we denote the case where all pointers are missing due to a block only having incorrect interlinks or no interlinks at all. +We now examine real-world data gathered from our Bitcoin Cash testnet deployment. On Figure~\ref{fig:testnet-deployment-reliability} we present the reliability of our interlinker deployment. We see that about 60\% of the blocks have been correctly interlinked with our velvet transactions, and about 10\% of them only have 1 interlink pointer missing, which makes them potentially usable. With $\infty$ we denote the case where all pointers are missing due to a block only having incorrect interlinks or no interlinks at all. \pdffigure{bitcoin-cash-testnet-levels}{Level distribution on Bitcoin Cash testnet.} +\dznote{Consider log-scale.} + On Figure~\ref{fig:bitcoin-cash-testnet-levels} we see the level distribution on the Bitcoin Cash testnet. As expected, the level growth is logarithmic compared to the chain length. + +\dznote{I'm happy with this whole chapter. I think some more details can be added, but overall it is good.} diff --git a/chapters/introduction.tex b/chapters/introduction.tex index b850ada..86db712 100644 --- a/chapters/introduction.tex +++ b/chapters/introduction.tex @@ -11,13 +11,19 @@ \section{Motivation} New cryptocurrencies with interesting features pop up all the time. There's long been an interest in implementing sidechains~\cite{sidechains}, as a way to interoperate between two blockchains. One should be able to trustlessly transfer his Bitcoin to another chain and use it there (a \emph{one-way peg}), and transfer it back if he so desires (a \emph{two-way peg}). One-way pegs have been implemented by having a smart contract on a cryptocurrency like Ethereum which knows the full state of the other blockchain, much like a full node. However storage comes at a huge cost, which makes the hundreds of GBs of most blockchains infeasible to maintain. -There's also the issue of user experience: even using a lite node at this point is too slow. Lite nodes use a protocol called \emph{SPV} which we'll look into detail shortly. SPV works by relaying only the block headers (which are of constant size) to the lite nodes and specifically any transactions they might suspect will interest them. Even so, the Dogecoin blockchain headers come up to 188MB. On an Android phone using the Dogecoin app, it takes about an hour before the app can be used, and this is assuming good network conditions. Trying to use such clients on a data plan could potentially make them completely unusable. +\dznote{The above is well written.} -\emph{NIPoPoWs}~\cite{nipopows} are a recent blockchain primitive allowing proofs on the blockchain of only logarithmic size instead of linear. These succinct proofs turn out to be key in solving problems like the above. One-way pegged contracts don't need to know about the whole blockchain, and lite nodes don't need to know all block headers to have the same security assurances. +There's also the issue of user experience: even using a lite node at this point is too slow. Lite nodes use a protocol called \emph{SPV} which we'll look into in detail shortly. SPV works by relaying only the block headers (which are of constant size \dznote{isn't the size of the headers linear in the blockchain size? what are they constant in? transaction count?}) to the lite nodes and specifically any transactions they might suspect will interest them. Even so, the Dogecoin blockchain headers come up to 188MB. On an Android phone using the Dogecoin app, it takes about an hour before the app can be used, and this is assuming good network conditions. Trying to use such clients on a data plan could potentially make them completely unusable. + +\emph{NIPoPoWs}~\cite{nipopows} are a recent \dznote{recently invented?} blockchain primitive allowing proofs on the blockchain of only logarithmic size instead of linear. These succinct proofs turn out to be key in solving problems like the above. One-way pegged contracts don't need to know about the whole blockchain, and lite nodes don't need to know all block headers to have the same security assurances. \section{Related Work} +\dznote{Reference Glou's work} + \section{Objectives} \section{Structure} +\dznote{You need to have a contributions section stating exactly what are your contributions and what you have build anew. Otherwise your thesis will be interpreted as a bibliographic review, which would be extremely unfair.} + % why bitcoin cash TODO % why python TODO diff --git a/chapters/prover.tex b/chapters/prover.tex index 1d663ae..fb87475 100644 --- a/chapters/prover.tex +++ b/chapters/prover.tex @@ -1,7 +1,7 @@ \chapter{NIPoPoW Velvet Fork Prover} Now that we've established a fork on the Bitcoin Cash chain, we show how our fork can be put to use by creating proofs. We introduce a kind of client called a \emph{prover} which can create all kinds of NIPoPoW proofs on demand. -Let's assume we have an SPV node. We set the bloom filter to our velvet fork tag in order to get all blocks containing only the transactions of the fork. It's possible to then extract from each transaction the payload, which should be the interlink commitment. Since anyone can post such transactions on the blockchain, we have to make sure that the commitment is actually true before we can use it. In order to do that we maintain our own version of the interlink for each block (similar to how the interlinker does) which we know is correct called $\sf realLink$. Then for every block, we compare its commitments (there may be many) with the Merkle Tree root of our $\sf realLink$. If there is a valid commitment we say that the block has a valid interlink. We store the full interlink as $\sf realLink[id(block)]$. +Let's assume we have an SPV node. We set the bloom filter to our velvet fork tag in order to get all blocks containing only the transactions of the fork. It's possible to then extract from each transaction the payload, which should be the interlink commitment. Since anyone can post such transactions on the blockchain, we have to make sure that the commitment is actually truthful before we can use it. In order to do that we maintain our own version of the interlink for each block (similar to how the interlinker does) which we know is correct called $\sf realLink$. Then for every block, we compare its commitments (there may be many) with the Merkle Tree root of our $\sf realLink$. If there is a valid commitment we say that the block has a valid interlink. We store the full interlink as $\sf realLink[id(block)]$. When we talked about NIPoPoWs we mentioned how it's essential that our proof forms a blockchain that can be traversed from start to end. In order to make our proof traversable, whenever we include a block we have to make sure it connects validly to the previous one either by (a) using the regular $\sf previd$ inside the block or (b) using a valid interlink. If we use the $\sf previd$ to link back to the previous block then all the information someone needs to verify the traversability is already there and we don't need to add anything extra. In the case we use the interlink however, we need to provide the Merkle Tree proofs for: @@ -23,6 +23,7 @@ \subsection{\sf followUp} $\sf followUp$ takes a block $b$ and a level $\mu$ as parameters. Starting from $b$ it traverses the chain until it reaches another block of level $\mu$ called $B$. In doing so, it is only allowed to use valid pointers. It will only follow a pointer from a block's interlink at level $\mu$ if there is a valid interlink in that block. Otherwise, the only option is to follow the previous block pointer ($\sf previd$). Once $B$ is reached, it is returned alongside the blocks that were traversed as a blockset called $\sf aux$. \input{algorithms/alg.nipopow-velvet-follow.tex} +\dznote{I think you need a \emph{Source} here too, unless you modified this from KMZ?} %TODO figure with straight and dropdown cases @@ -30,16 +31,21 @@ \subsection{$\sf find \chain\upchain^\mu$} Now that we have a way to go back on a level, we can utilize it to construct the entire traversable level $\mu$ up to block $b$, starting from the end of the chain $\chain[-1]$: this is what ${\sf find \chain\upchain^\mu}(b)$ accomplishes. It works by repeatedly calling $\sf followUp$ on the oldest block it has and including the result in its final chain. \input{algorithms/alg.nipopow-velvet-upchain.tex} +\dznote{Source?} \section{Velvet Infix Proofs} +\dznote{You need some description on this and a comparison to the algorithm described in KMZ, since you have improved upon it.} + +\dznote{The three subsections above seem empty and need some more careful descriptions. Perhaps you can even move them to the background section with more detailed explanations.} + \input{algorithms/alg.nipopow-velvet-infix-go-back.tex} \section{JavaScript implementation with bcash} bcash, also used for the interlinker earlier, turns out the be the only option for an SPV node on Bitcoin Cash, making it the obvious choice for the prover. \subsection{Overview} -Our prover works as follows. We expect a user to run the prover, passing as a parameter if they want a suffix or infix proof. If they desire an infix proof they have to provide the block of interest. Once they do that the prover runs and syncs with the Bitcoin Cash blockchain via SPV. It does some similar work to the work that an interlinker does: it knows what the correct interlink is for each block. It then checks the included commitments on each block and keeps a valid commitment for each block if found. A block containing a valid commitment is called a \emph{valid velvet}. Interlink pointers can only be used on valid velvets. Once the chain is synced and the prover knows the valid velvets along with the whole blockchain it creates a proof of the requested type and outputs it in JSON format. +Our prover works as follows. We expect a user to run the prover, passing as a parameter if they want a suffix or infix proof. If they desire an infix proof they have to provide the block of interest. Once they do that the prover runs and syncs with the Bitcoin Cash blockchain via SPV. It does some similar work to the work that an interlinker does: it knows what the correct interlink is for each block. It then checks the included commitments on each block and keeps a valid commitment for each block if found. A block containing a valid commitment is called a \emph{valid velvet}\dznote{ or \emph{velvet block}?}. Interlink pointers can only be used on valid velvets. Once the chain is synced and the prover knows the valid velvets along with the whole blockchain it creates a proof of the requested type and outputs it in JSON format. \subsection{Interlink Implementation} Implementing an interlink structure is something we've already covered many times. Our implementation here is based on immutable value objects holding the interlink. Updating an interlink is done in the usual manner and creates a new interlink. What's different here is that we have a \code{proof} method: we use this method to generate a proof of inclusion of a specific pointer in the interlink commitment. We also need a way to be able to get a pointer from a specific level on the interlink and this is accomplished with the \code{at} method. Note that \code{at} can be asked for a level higher than the size of the interlink, in which case the velvet genesis is returned as it's assumed to be a block of level $\infty$. @@ -85,6 +91,8 @@ \subsection{Interlink Implementation} } \end{lstlisting} +\dznote{Suddenly flow. Perhaps that's worth mentioning that, even though you have a separate section later.} + \subsection{Locating Velvet Transactions} Locating the velvet transactions is very easy considering that all our velvet transactions are SPV tagged. The only thing we have to do is add the SPV tag in our bloom filter. We do this right before connecting to the network. @@ -100,7 +108,7 @@ \subsection{Locating Velvet Transactions} \end{lstlisting} \subsection{Extracting Interlink Commitments} -we have to check that the transaction the valid form described earlier (\code{OP\_RETURN }). In order to do that we look at the outputs of each transaction and only keep any outputs of our form. If some output matches then we extract the script's third element which is the commitment. +We have to check that the transaction is of the form described earlier (\code{OP\_RETURN }). In order to do that we look at the outputs of each transaction and only keep any outputs of our form. If some output matches then we extract the script's third element which is the commitment. \begin{lstlisting}[language=Javascript] const extractInterlinkHashes = compose( @@ -122,10 +130,12 @@ \subsection{Extracting Interlink Commitments} ); \end{lstlisting} +\dznote{Worth mentioning the idiomatic use of functional JS here. Also a walkthrough on the code step-by-step wouldn't hurt (you can do this for all code listings)} + \subsection{Handling Merkle Blocks} -When a block or transaction of a block matches our bloom filter, the block is relayed by full nodes as a \code{merkleblock} message. MerkleBlocks contain the header of the actual block as well as the transactions ids that matched. It also contains a proof of inclusion for all the transactions ids provided. One can check this proof of inclusion with accordance to the \code{merkleRoot} inside the block header. The transactions are included in subsequent \code{tx} messages. bcash hides this process from the user: on a new block event a MerkleBlock is provided and it contains a \code{txs} record, where the transactions that matched are included in full. +When a block or transaction of a block matches our bloom filter, the block is relayed by full nodes as a \code{merkleblock} message. MerkleBlocks \dznote{cite BTC developer guide?} contain the header of the actual block as well as the transactions ids that matched. It also contains a proof of inclusion for all the transactions ids \dznote{what is a transaction id?} provided. One can check this proof of inclusion with accordance to the \code{merkleRoot} inside the block header. The transactions are included in subsequent \code{tx} messages. bcash hides this process from the user: on a new block event a MerkleBlock is provided and it contains a \code{txs} record, where the transactions that matched are included in full. -In order to check if we have matched transactions in a block all we have to do is check if its \code{.txs} array is non-empty. If it is not then this block is definitely not a valid velvet. If it is not, then we have to ensure a correct form and extract the commitment, also saving it. We utilize the method \code{extractInterlinkHashes} and map it over all transactions in the block. +In order to check if we have matched transactions in a block all we have to do is check if its \code{.txs} array is non-empty. If it is not then this block is definitely not a valid velvet. If it is not \dznote{not not non-empty?}, then we have to ensure a correct form and extract the commitment, also saving it. We utilize the method \code{extractInterlinkHashes} and map it over all transactions in the block. \begin{lstlisting}[language=Javascript] const extractInterlinkHashesFromMerkleBlock = compose( @@ -136,7 +146,9 @@ \subsection{Handling Merkle Blocks} \end{lstlisting} \subsection{RealLink \& Verifying Interlink Commitments} -We extend the \code{realLink} discussed earlier. Other than allowing us to get the interlink of any block it also allows us to check if a block is a valid velvet. It is able to do that as it gets notified for every new block seen during the synchronisation. When a new block appears, it gets informed about the block id and the interlinks included in the block. It keeps a running interlink in the same fashion the interlinker does so because the blocks events happen in-order it can check whether its running interlink matches the ones included in the block. In case there's a match the block is marked as a valid velvet and the running interlink is updated so that RealLink can be ready to process the next block. +We extend the \code{realLink} discussed earlier. Other than allowing us to get the interlink of any block it also allows us to check if a block is a valid velvet. It is able to do that as it \dznote{who?} gets notified for every new block seen during the synchronisation. When a new block appears, it gets informed about the block id \dznote{what is a block id?} and the interlinks included in the block. It keeps a running interlink in the same fashion the interlinker does, so, because the blocks events happen in-order, it can check whether its running interlink matches the ones included in the block. In case there's a match, the block is marked as a valid velvet and the running interlink is updated so that RealLink can be ready to process the next block. \dznote{You could also give some code listing line number references with \texttt{\textbackslash ref} and \texttt{\textbackslash label}.} + +\dznote{Throughout this work you are skipping many needed commas that would make your text more readable.} \begin{lstlisting}[language=Javascript] module.exports = class RealLink { @@ -219,7 +231,10 @@ \subsection{Type Safety} One is that our source files are not valid JavaScript anymore. In order to run our code we need to pass it through a pre-processor like Babel which emits clean JavaScript that then Node can run. -Another is that all the external libraries we use, including bcash are not written including Flow types. Flow does provide a repository with type definitions for popular packages, however due to the niche category of our dependencies only a few were covered. This meant that the burden was on us to write type definitions for our dependencies. We had to manually write type definitions for bcash and buffer-map. Thankfully, there is previous work~\footnote{Available at \url{https://github.com/OrfeasLitos/TrustIsRisk.js/blob/247c8b182f5bb4bed11df0d3b9136a3e27848798/flow-typed/npm/bcoin_vx.x.x.js}} on type definitions for bcoin which we were able to utilize and extend since the APIs are really similar as bcash is a fork of bcoin. +Another is that all the external libraries we use, including bcash are not written including Flow types. Flow does provide a repository with type definitions for popular packages, however due to the niche category of our dependencies only a few were covered. This meant that the burden was on us to write type definitions for our dependencies. We had to manually write type definitions for bcash and buffer-map. Thankfully, there is previous work\footnote{Available at \url{https://github.com/OrfeasLitos/TrustIsRisk.js/blob/247c8b182f5bb4bed11df0d3b9136a3e27848798/flow-typed/npm/bcoin_vx.x.x.js}} on type definitions for bcoin which we were able to utilize and extend since the APIs are really similar as bcash is a fork of bcoin. \subsection{Testing} -Due to the real-time and asynchronous nature of the prover it's important that our implementation is resilient and bug-free. In order to assert that the code has been thoroughly unit tested, boasting a code coverage of >90\%. The tests are written and run with Jest~\cite{jest}. There are also integration tests using real-world data. +Due to the real-time and asynchronous nature of the prover it's important that our implementation is resilient and bug-free. In order to assert that the code has been thoroughly unit tested, boasting a code coverage of $>90\%$. The tests are written and run with Jest~\cite{jest}. There are also integration tests using real-world data. + +\dznote{Show some code listings of tests.} +\dznote{Show some coverage graphs.} diff --git a/paper.tex b/paper.tex index 6ef45cd..240c4d6 100644 --- a/paper.tex +++ b/paper.tex @@ -21,6 +21,8 @@ \newpage More detailed title page. +\dznote{Fill in title page.} + \thispagestyle{empty} \newpage @@ -32,6 +34,8 @@ \begin{abstract} In this work we examine the real-world applications of the recent blockchain primitive called Non Interactive Proofs of Proof of Work (NIPoPoWs). We enable the use of the primitive on Bitcoin Cash by implementing the first known velvet fork on a blockchain. We provide concrete implementations for creating a velvet fork, and generating proofs on a blockchain that has been forked in this way. +\dznote{Spell NIPoPoWs as ``Non-Interactive Proofs of Proof-of-Work,'' as in the original paper.} +\dznote{Expand abstract.} \end{abstract} \newpage diff --git a/preamble.sty b/preamble.sty index 245a7dc..00dfeb3 100644 --- a/preamble.sty +++ b/preamble.sty @@ -58,9 +58,7 @@ \usepackage[]{xcolor} \usepackage{color} -\newcommand{\anote}[1]{{\color{magenta}[Andrew:{#1}]}} -\newcommand{\aknote}[1]{{\color{magenta}[Aggelos:{#1}]}} -\newcommand{\dznote}[1]{{\color{magenta}[Dionysis: {#1}]}} +\newcommand{\dznote}[1]{{\color{red}{#1}}} \newcommand{\ignore}[1]{} \newcommand{\upchain}{\negthickspace\uparrow} @@ -113,61 +111,61 @@ \definecolor{backgroundColour}{rgb}{0.95,0.95,0.92} \lstdefinestyle{CStyle}{ - backgroundcolor=\color{backgroundColour}, + backgroundcolor=\color{backgroundColour}, commentstyle=\color{mGreen}, keywordstyle=\color{magenta}, numberstyle=\tiny\color{mGray}, stringstyle=\color{mPurple}, basicstyle=\footnotesize\ttfamily, - breakatwhitespace=false, - breaklines=true, - captionpos=b, - keepspaces=true, - numbers=left, - numbersep=5pt, - showspaces=false, + breakatwhitespace=false, + breaklines=true, + captionpos=b, + keepspaces=true, + numbers=left, + numbersep=5pt, + showspaces=false, showstringspaces=false, - showtabs=false, + showtabs=false, tabsize=2, language=C } \lstdefinestyle{PyStyle}{ - backgroundcolor=\color{backgroundColour}, + backgroundcolor=\color{backgroundColour}, commentstyle=\color{mGreen}, keywordstyle=\color{magenta}, numberstyle=\tiny\color{mGray}, stringstyle=\color{mPurple}, basicstyle=\footnotesize\ttfamily, - breakatwhitespace=false, - breaklines=true, - captionpos=b, - keepspaces=true, - numbers=left, - numbersep=5pt, - showspaces=false, + breakatwhitespace=false, + breaklines=true, + captionpos=b, + keepspaces=true, + numbers=left, + numbersep=5pt, + showspaces=false, showstringspaces=false, - showtabs=false, + showtabs=false, tabsize=2, language=Python } \lstdefinestyle{JsStyle}{ - backgroundcolor=\color{backgroundColour}, + backgroundcolor=\color{backgroundColour}, commentstyle=\color{mGreen}, keywordstyle=\color{magenta}, numberstyle=\tiny\color{mGray}, stringstyle=\color{mPurple}, basicstyle=\footnotesize\ttfamily, - breakatwhitespace=false, - breaklines=true, - captionpos=b, - keepspaces=true, - numbers=left, - numbersep=5pt, - showspaces=false, + breakatwhitespace=false, + breaklines=true, + captionpos=b, + keepspaces=true, + numbers=left, + numbersep=5pt, + showspaces=false, showstringspaces=false, - showtabs=false, + showtabs=false, tabsize=2, language=Java }