All: update images for reviewer feedback
Special thanks to Murchandamus who provided most of the feedback
@ -806,7 +806,6 @@ key can produce a public key expressed in two different formats
|
||||
addresses. However, the private key is identical for both Bitcoin
|
||||
addresses.
|
||||
|
||||
//FIXME:misaligned text, see Murch CH04 feedback
|
||||
[[pubkey_compression]]
|
||||
[role="smallerseventy"]
|
||||
.Public key compression
|
||||
|
@ -366,7 +366,6 @@ header and summarizes all the data in all four transactions.
|
||||
<<simple_merkle>> shows how the root is calculated by pair-wise hashes
|
||||
of the nodes.
|
||||
|
||||
//FIXME: s/+/||/
|
||||
[[simple_merkle]]
|
||||
.Calculating the nodes in a merkle tree
|
||||
image::images/mbc2_0902.png["merkle_tree"]
|
||||
@ -379,7 +378,6 @@ shown in <<merkle_tree_odd>>, where transaction C is duplicated.
|
||||
Similarly, if there are an odd number of hashes to process at any level,
|
||||
the last hash is duplicated.
|
||||
|
||||
//FIXME: s/+/||/
|
||||
[[merkle_tree_odd]]
|
||||
.Duplicating one data element achieves an even number of data elements
|
||||
image::images/mbc2_0903.png["merkle_tree_odd"]
|
||||
@ -403,18 +401,11 @@ is unusual in Merkle trees). This results in certain sequences of
|
||||
transactions leading to the same merkle root. For example, these two
|
||||
trees:
|
||||
|
||||
//FIXME:replace with image to fix italics in code text
|
||||
----
|
||||
A A
|
||||
/ \ / \
|
||||
B C B C
|
||||
/ \ | / \ / \
|
||||
D E F D E F F
|
||||
/ \ / \ / \ / \ / \ / \ / \
|
||||
1 2 3 4 5 6 1 2 3 4 5 6 5 6
|
||||
----
|
||||
[[cve_tree]]
|
||||
.Two Bitcoin-style merkle tree with the same root but a different number of leaves
|
||||
image::images/cve-2012-2459.dot.png["Two Bitcoin-style merkle tree with the same root but a different number of leaves"]
|
||||
|
||||
for transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and
|
||||
For transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and
|
||||
6 are repeated) result in the same root hash A (because the hash of both
|
||||
of (F) and (F,F) is C).
|
||||
|
||||
@ -475,28 +466,12 @@ diagram).
|
||||
image::images/mbc2_0905.png["merkle_tree_path"]
|
||||
|
||||
The efficiency of merkle trees becomes obvious as the scale increases.
|
||||
<<block_structure2>> shows the amount of data that needs to be exchanged
|
||||
as a merkle path to prove that a transaction is part of a block.
|
||||
|
||||
//FIXME: replace with a plot of size per txes: plot [0:16000] ceil(log2(x))
|
||||
[[block_structure2]]
|
||||
.Merkle tree efficiency
|
||||
[options="header"]
|
||||
|=======
|
||||
|Number of transactions| Approx. size of block | Path size (hashes) | Path size (bytes)
|
||||
| 16 transactions | 4 kilobytes | 4 hashes | 128 bytes
|
||||
| 512 transactions | 128 kilobytes | 9 hashes | 288 bytes
|
||||
| 2048 transactions | 512 kilobytes | 11 hashes | 352 bytes
|
||||
| 65,535 transactions | 16 megabytes | 16 hashes | 512 bytes
|
||||
|=======
|
||||
|
||||
With merkle trees, a node can download just the block headers (80
|
||||
bytes per block) and still be able to identify a transaction's inclusion
|
||||
in a block by retrieving a small merkle path from a full node, without
|
||||
storing or transmitting the vast majority of the blockchain.
|
||||
Clients that do not fully validate transactions, called lightweight
|
||||
clients, use merkle paths to verify transactions without downloading
|
||||
full blocks.
|
||||
The largest possible block can hold almost 16,000 transactions in 4,000,000
|
||||
bytes, but proving any particular one of those sixteen thousand transactions
|
||||
is a part of that block only requires a copy of the transaction, a copy
|
||||
of the 80-byte block header, and 448 bytes for the merkle proof. That
|
||||
makes the largest possible proof almost 10,000 times smaller than the
|
||||
largest possible Bitcoin block.
|
||||
|
||||
=== Merkle Trees and Lightweight Clients
|
||||
|
||||
|
148
ch10.asciidoc
@ -1205,11 +1205,11 @@ selection of the chain with the most Proof-of-Work.
|
||||
A _best blockchain_ is whichever valid chain of blocks has
|
||||
the most cumulative Proof-of-Work associated with it.
|
||||
The
|
||||
best chain will also have branches with blocks that are "siblings" to
|
||||
best chain may also have branches with blocks that are "siblings" to
|
||||
the blocks on the best chain. These blocks are valid but not part of the
|
||||
best chain. They are kept for future reference, in case one of those
|
||||
chains is extended and becomes the new best chain. In the next section
|
||||
(<<forks>>), we will see how secondary chains occur as a result of an
|
||||
many secondary chains later becomes primary. When sibling blocks occur,
|
||||
they're usually the result of an
|
||||
almost simultaneous mining of blocks at the same height.
|
||||
|
||||
When a new block is received, a node will try to add it onto the
|
||||
@ -1219,7 +1219,7 @@ node will attempt to find that parent in the existing blockchain. Most
|
||||
of the time, the parent will be the "tip" of the best chain, meaning
|
||||
this new block extends the best chain.
|
||||
|
||||
Sometimes, as we will see in <<forks>>, the new block does not extend
|
||||
Sometimes the new block does not extend
|
||||
the best chain. In that case, the node will attach the new block to a
|
||||
secondary chain and then compare the work of the secondary chain to the
|
||||
previous best chain. If the secondary chain is now the best chain, the
|
||||
@ -1239,138 +1239,8 @@ result of transmission delays in the global network. We will also look
|
||||
at deliberately induced forks later in this chapter.
|
||||
====
|
||||
|
||||
In the next few diagrams, we follow the progress of a "fork" event
|
||||
across the network. The diagram is a simplified representation of the
|
||||
Bitcoin network. For illustration purposes, different blocks are shown
|
||||
as different shapes (star, triangle, upside-down triangle, rhombus),
|
||||
spreading across the network. Each node in the network is represented as
|
||||
a circle.
|
||||
|
||||
For
|
||||
illustration purposes, each node contains a shape that represents the
|
||||
block that it believes is currently the tip of the best chain. So, if
|
||||
you see a star shape in the node, that means that the star block is the
|
||||
tip of the best chain, as far as that node is concerned.
|
||||
|
||||
In the first diagram (<<fork1>>), the network has a unified perspective
|
||||
of the blockchain, with the star block as the tip of the best chain.
|
||||
|
||||
[[fork1]]
|
||||
[role="smallereighty"]
|
||||
.Before the fork—all nodes have the same perspective
|
||||
image::images/mbc2_1002.png["Before the fork - all nodes have the same perspective"]
|
||||
|
||||
In <<fork2>>, we see two miners (Node X and Node Y) who mine two
|
||||
different blocks almost simultaneously. Both of these blocks are
|
||||
children of the star block, and extend the chain by building on top of
|
||||
the star block. To help us track it, one is visualized as a triangle
|
||||
block originating from Node X, and the other is shown as an upside-down
|
||||
triangle block originating from Node Y.
|
||||
|
||||
[[fork2]]
|
||||
[role="smallersixty"]
|
||||
.Visualization of a blockchain fork event: two blocks found simultaneously
|
||||
image::images/mbc2_1003.png["Visualization of a blockchain fork event: two blocks found simultaneously"]
|
||||
|
||||
Let's assume, for example, that a miner Node X finds a Proof-of-Work
|
||||
solution for a block "triangle" that extends the blockchain, building on
|
||||
top of the parent block "star." Almost simultaneously, the miner Node Y
|
||||
who was also extending the chain from block "star" finds a solution for
|
||||
block "upside-down triangle," his candidate block. Now, there are two
|
||||
possible blocks; one we call "triangle," originating in Node X; and one
|
||||
we call "upside-down triangle," originating in Node Y. Both blocks are
|
||||
valid, both blocks contain a valid solution to the Proof-of-Work, and
|
||||
both blocks extend the same parent (block "star"). Both blocks likely
|
||||
contain most of the same transactions, with only perhaps a few
|
||||
differences in the order of transactions.
|
||||
|
||||
As the two blocks propagate, some nodes receive block "triangle" first
|
||||
and some receive block "upside-down triangle" first. As shown in
|
||||
<<fork3>>, the network splits into two different perspectives of the
|
||||
blockchain; one side topped with a triangle block, the other with the
|
||||
upside-down-triangle block.
|
||||
|
||||
//FIXME:node X won't receive upside down triangle because it's not
|
||||
//connected to a peer with that block. Same problem for Node Y
|
||||
[[fork3]]
|
||||
[role="smallersixty"]
|
||||
.Visualization of a blockchain fork event: two blocks propagate, splitting the network
|
||||
image::images/mbc2_1004.png["Visualization of a blockchain fork event: two blocks propagate, splitting the network"]
|
||||
|
||||
In the diagram, a randomly chosen "Node X" received the triangle block
|
||||
first and extended the star chain with it. Node X selected the chain
|
||||
with "triangle" block as the best chain. Later, Node X also received the
|
||||
"upside-down triangle" block. Since it was received second, it is
|
||||
assumed to have "lost" the race. Yet, the "upside-down triangle" block
|
||||
is not discarded. It is linked to the "star" block parent and forms a
|
||||
secondary chain. While Node X assumes it has correctly selected the
|
||||
winning chain, it keeps the "losing" chain so that it has the
|
||||
information needed to reorganize if the "losing" chain ends up
|
||||
"winning."
|
||||
|
||||
On the other side of the network, Node Y constructs a blockchain based
|
||||
on its own perspective of the sequence of events. It received
|
||||
"upside-down triangle" first and elected that chain as the "winner."
|
||||
When it later received "triangle" block, it connected it to the "star"
|
||||
block parent as a secondary chain.
|
||||
|
||||
Neither side is "correct," or "incorrect." Both are valid perspectives
|
||||
of the blockchain. Only in hindsight will one prevail, based on how
|
||||
these two competing chains are extended by additional work.
|
||||
|
||||
Mining nodes whose perspective resembles Node X will immediately begin
|
||||
mining a candidate block that extends the chain with "triangle" as its
|
||||
tip. By linking "triangle" as the parent of their candidate block, they
|
||||
are using their hashing power to build on that chain.
|
||||
|
||||
Any mining node whose perspective resembles Node Y will start building a
|
||||
candidate node with "upside-down triangle" as its parent, extending the
|
||||
chain that they believe is the best chain. And so, the race begins
|
||||
again.
|
||||
|
||||
Forks are almost always resolved within one block. While part of the
|
||||
network's hashing power is dedicated to building on top of "triangle" as
|
||||
the parent, another part of the hashing power is focused on building on
|
||||
top of "upside-down triangle." Even if the hashing power is almost
|
||||
evenly split, it is likely that one set of miners will find a solution
|
||||
and propagate it before the other set of miners have found any
|
||||
solutions. Let's say, for example, that the miners building on top of
|
||||
"triangle" find a new block "rhombus" that extends the chain (e.g.,
|
||||
star-triangle-rhombus). They immediately propagate this new block and
|
||||
the entire network sees it as a valid solution as shown in <<fork4>>.
|
||||
|
||||
[[fork4]]
|
||||
[role="smallereighty"]
|
||||
.Visualization of a blockchain fork event: a new block extends one fork, reorganizing the network
|
||||
image::images/mbc2_1005.png["Visualization of a blockchain fork event: a new block extends one fork"]
|
||||
|
||||
All nodes that had chosen "triangle" as the winner in the previous round
|
||||
will simply extend the chain one more block. The nodes that chose
|
||||
"upside-down triangle" as the winner, however, will now see two chains:
|
||||
star-triangle-rhombus and star-upside-down-triangle. The chain
|
||||
star-triangle-rhombus now has more cumulative work than the
|
||||
other chain. As a result, those nodes will set the chain
|
||||
star-triangle-rhombus as the best chain and change the
|
||||
star-upside-down-triangle chain to a secondary chain, as shown in
|
||||
<<fork5>>. This is a chain reorganization, because those nodes are forced
|
||||
to revise their view of the blockchain to incorporate the new evidence
|
||||
of a longer chain. Any miners working on extending the chain
|
||||
star-upside-down-triangle will now stop that work because their
|
||||
block is "stale," as its parent "upside-down-triangle" is
|
||||
no longer on the best chain. The transactions within
|
||||
"upside-down-triangle" that are not within "triangle" are re-inserted in
|
||||
the mempool for inclusion in the next block to become a part of the best
|
||||
chain. The entire network converges on a single blockchain
|
||||
star-triangle-rhombus, with "rhombus" as the last block in the chain.
|
||||
All miners immediately start working on candidate blocks that reference
|
||||
"rhombus" as their parent to extend the star-triangle-rhombus chain.
|
||||
|
||||
[[fork5]]
|
||||
[role="smallereighty"]
|
||||
.Visualization of a blockchain fork event: the network reorganizes on a new longest chain
|
||||
image::images/mbc2_1006.png["Visualization of a blockchain fork event: the network reorganizes on a new longest chain"]
|
||||
|
||||
It is possible for a fork to extend to two blocks, if two
|
||||
Forks are almost always resolved within one block.
|
||||
It is possible for an accidental fork to extend to two blocks if both
|
||||
blocks are found almost simultaneously by miners on opposite "sides" of
|
||||
a previous fork. However, the chance of that happening is low.
|
||||
|
||||
@ -1856,13 +1726,9 @@ height 4, a one-block fork occurs. This is the type of spontaneous fork
|
||||
we saw in <<forks>>. With the mining of block 5, the network converges
|
||||
on one chain and the fork is resolved.
|
||||
|
||||
//FIXME:"The blocks following the new rules should have a unique color. I would have expected the "b-fork" to follow the old rules based on the colors."
|
||||
// I was looking here where the other block was created, because I assumed that the enumeration would start with a) and then progress to b).
|
||||
//
|
||||
// Perhaps call this chain "7F–11F" to indicate the new Foocoin rules?
|
||||
[[blockchainwithforks]]
|
||||
.A blockchain with forks
|
||||
image::images/mbc2_1009.png[A blockchain with forks]
|
||||
image::images/fork.dot.png[A blockchain with forks]
|
||||
|
||||
Later, however, at block height 6,
|
||||
a new implementation of the client is released with a change in the
|
||||
|
@ -634,7 +634,6 @@ blocks before commitment transaction #1 becomes valid.
|
||||
shorter timelock, allowing it to be spent before the previous
|
||||
commitments become valid.
|
||||
|
||||
//FIXME: s/3720/3721/
|
||||
[[timelocked_commitments]]
|
||||
.Each commitment sets a shorter timelock, allowing it to be spent before the previous commitments become valid
|
||||
image::images/mbc2_1207.png["Each commitment sets a shorter timelock, allowing it to be spent before the previous commitments become valid"]
|
||||
|
@ -132,7 +132,6 @@ payment to a public key hash), showing the combined script resulting
|
||||
from the concatenation of the scripts prior to
|
||||
validation.
|
||||
|
||||
//FIXME: revise to use "output script" and "input script" from chap 6
|
||||
[[input_and_output_scripts_legacy]]
|
||||
.Combining input and output scripts to evaluate a transaction script
|
||||
image::../images/mbc2_0603.png["input_and_output_scripts"]
|
||||
@ -1710,7 +1709,6 @@ his partners to spend their money frequently; the time delayed
|
||||
conditions only exist in case something goes wrong. We can re-structure
|
||||
our tree with this knowledge in <<diagram_mast3>>.
|
||||
|
||||
//FIXME: keep leaves in the same order, see Murch feedback chapter 7
|
||||
[[diagram_mast3]]
|
||||
.A MAST with the most-expected script in the best position
|
||||
image::../images/mast3.dot.png["A MAST with the most-expected script in the best position"]
|
||||
|
72
images/cve-2012-2459.dot
Normal file
@ -0,0 +1,72 @@
|
||||
// A A
|
||||
// / \ / \
|
||||
// B C B C
|
||||
// / \ | / \ / \
|
||||
// D E F D E F F
|
||||
// / \ / \ / \ / \ / \ / \ / \
|
||||
// 1 2 3 4 5 6 1 2 3 4 5 6 5 6
|
||||
|
||||
digraph MerkleTrees {
|
||||
// General settings
|
||||
rankdir=TB;
|
||||
//node [shape=none, style=filled, color=lightblue];
|
||||
node [shape=box, width=0, height=0];
|
||||
ranksep=0.3;
|
||||
nodesep=0.1
|
||||
|
||||
subgraph cluster_x {
|
||||
// Merkle Tree 1
|
||||
A1 [label="A"];
|
||||
B1 [label="B"];
|
||||
C1 [label="C"];
|
||||
D1 [label="D"];
|
||||
E1 [label="E"];
|
||||
F1 [label="F"];
|
||||
x1 [label="1"];
|
||||
x2 [label="2"];
|
||||
x3 [label="3"];
|
||||
x4 [label="4"];
|
||||
x5 [label="5"];
|
||||
x6 [label="6"];
|
||||
|
||||
A1 -> B1;
|
||||
A1 -> C1;
|
||||
B1 -> D1;
|
||||
B1 -> E1;
|
||||
C1 -> F1;
|
||||
D1 -> {x1, x2};
|
||||
E1 -> {x3, x4};
|
||||
F1 -> {x5, x6};
|
||||
}
|
||||
|
||||
|
||||
subgraph cluster_y {
|
||||
// Merkle Tree 2
|
||||
A2 [label="A"];
|
||||
B2 [label="B"];
|
||||
C2 [label="C"];
|
||||
D2 [label="D"];
|
||||
E2 [label="E"];
|
||||
F2 [label="F"];
|
||||
F2_dup [label = "F" ];
|
||||
y1 [label="1"];
|
||||
y2 [label="2"];
|
||||
y3 [label="3"];
|
||||
y4 [label="4"];
|
||||
y5 [label="5"];
|
||||
y6 [label="6"];
|
||||
y5_dup [label="5"];
|
||||
y6_dup [label="6"];
|
||||
|
||||
A2 -> B2;
|
||||
A2 -> C2;
|
||||
B2 -> D2;
|
||||
B2 -> E2;
|
||||
C2 -> {F2, F2_dup};
|
||||
D2 -> {y1, y2};
|
||||
E2 -> {y3, y4};
|
||||
F2 -> {y5, y6};
|
||||
F2_dup -> {y5_dup, y6_dup};
|
||||
}
|
||||
}
|
||||
|
BIN
images/cve-2012-2459.dot.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
38
images/fork.dot
Normal file
@ -0,0 +1,38 @@
|
||||
digraph G {
|
||||
rankdir=LR; // Left to Right direction
|
||||
node [shape=box];
|
||||
|
||||
block1 [label="1"];
|
||||
block2 [label="2"];
|
||||
block3 [label="3"];
|
||||
block4a [label="4a"];
|
||||
block4b [label="4b"];
|
||||
block5 [label="5"];
|
||||
block6 [label="7"];
|
||||
block7a [label="7a"];
|
||||
block8a [label="8a"];
|
||||
|
||||
subgraph cluster_foocoin {
|
||||
block7b [label="7b"];
|
||||
block8b [label="8b"];
|
||||
block9 [label="9"];
|
||||
block10 [label="10"];
|
||||
block11 [label="11"];
|
||||
|
||||
labelloc = "t"
|
||||
label = "Using new rules"
|
||||
}
|
||||
|
||||
block1 -> block2 [dir=back];
|
||||
block2 -> block3 [dir=back];
|
||||
block3 -> {block4a,block4b} [dir=back];
|
||||
block4a -> block5 [dir=back];
|
||||
block5 -> block6 [dir=back];
|
||||
block6 -> {block7a,block7b} [dir=back];
|
||||
block7a -> block8a [dir=back];
|
||||
block7b -> block8b [dir=back];
|
||||
block8b -> block9 [dir=back];
|
||||
block9 -> block10 [dir=back];
|
||||
block10 -> block11 [dir=back];
|
||||
}
|
||||
|
BIN
images/fork.dot.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
@ -2,20 +2,20 @@ digraph merkle_tree {
|
||||
splines=ortho;
|
||||
node [shape=box, style="filled", color="black", fontcolor="black", fillcolor="white"];
|
||||
|
||||
"Merkle Root" -> "Hash AB";
|
||||
"Merkle Root" -> "Hash C";
|
||||
"Hash AB" -> "Hash A";
|
||||
"Hash AB" -> "Hash B";
|
||||
"Hash A" -> "A";
|
||||
"Merkle Root" -> "Hash A";
|
||||
"Merkle Root" -> "Hash BC";
|
||||
"Hash BC" -> "Hash B";
|
||||
"Hash BC" -> "Hash C";
|
||||
"Hash A" -> "A" [minlen = 2];
|
||||
"Hash B" -> "B";
|
||||
"Hash C" -> "C" [minlen = 2];
|
||||
"Hash C" -> "C";
|
||||
|
||||
"Merkle Root" [label="Merkle Root"];
|
||||
"Hash AB" [label="Hash AB"];
|
||||
"Hash BC" [label="Hash BC"];
|
||||
"Hash A" [label="Hash A"];
|
||||
"Hash B" [label="Hash B"];
|
||||
"Hash C" [label="Hash C"];
|
||||
"C" [label="2 <M> <S> <Z> 3 OP_CHECKMULTISIG", style="filled", fillcolor="silver"];
|
||||
"A" [label="2 <M> <S> <Z> 3 OP_CHECKMULTISIG", style="filled", fillcolor="silver"];
|
||||
"B" [label="<30 days> OP_CSV OP_DROP\n<Lawyer> OP_CHECKSIGVERIFY\n1 <M> <S> <Z> 3 OP_CHECKMULTISIG"];
|
||||
"A" [label="<90 days> OP_CSV OP_DROP\n<Lawyer> OP_CHECKSIG"];
|
||||
"C" [label="<90 days> OP_CSV OP_DROP\n<Lawyer> OP_CHECKSIG"];
|
||||
}
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 97 KiB |