<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://en.zaoniao.it/index.php?action=history&amp;feed=atom&amp;title=Satoshi_Client_Block_Exchange</id>
	<title>Satoshi Client Block Exchange - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://en.zaoniao.it/index.php?action=history&amp;feed=atom&amp;title=Satoshi_Client_Block_Exchange"/>
	<link rel="alternate" type="text/html" href="http://en.zaoniao.it/index.php?title=Satoshi_Client_Block_Exchange&amp;action=history"/>
	<updated>2026-05-15T09:20:44Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.32.0</generator>
	<entry>
		<id>http://en.zaoniao.it/index.php?title=Satoshi_Client_Block_Exchange&amp;diff=6750&amp;oldid=prev</id>
		<title>Admin: Created page with &quot;==Overview== This article describes how blocks are exchanged between nodes. See Protocol rules for more information on how blocks are validated.  Upon in...&quot;</title>
		<link rel="alternate" type="text/html" href="http://en.zaoniao.it/index.php?title=Satoshi_Client_Block_Exchange&amp;diff=6750&amp;oldid=prev"/>
		<updated>2019-07-10T06:13:52Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;==Overview== This article describes how blocks are exchanged between nodes. See &lt;a href=&quot;/Protocol_rules&quot; title=&quot;Protocol rules&quot;&gt;Protocol rules&lt;/a&gt; for more information on how blocks are &lt;a href=&quot;/Invalid_block&quot; title=&quot;Invalid block&quot;&gt;validated&lt;/a&gt;.  Upon in...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==Overview==&lt;br /&gt;
This article describes how blocks are exchanged between nodes.&lt;br /&gt;
See [[Protocol rules]] for more information on how blocks are [[Invalid block|validated]].&lt;br /&gt;
&lt;br /&gt;
Upon initial connection, if the connection was not inbound[1],&lt;br /&gt;
or in other words, if the connection was initiated by the local node,&lt;br /&gt;
the version message is queued for sending immediately. When the remote node&lt;br /&gt;
receives the version message it replies with its own version message.[2]&lt;br /&gt;
&lt;br /&gt;
When a node receives a &amp;quot;version&amp;quot; message, it may send a &amp;quot;getblocks&amp;quot; request&lt;br /&gt;
to the remote node if EITHER:&lt;br /&gt;
&lt;br /&gt;
# The node has never sent an initial getblocks request to any node yet.&lt;br /&gt;
# Or, this is the only active node connection. Presumably the node had zero connections prior to this connection, so maybe it was disconnected for a long time. So, it will ask for blocks to catch up.&lt;br /&gt;
&lt;br /&gt;
The getblocks message contains multiple block hashes that the requesting&lt;br /&gt;
node already possesses, in order to help the remote note find the latest&lt;br /&gt;
common block between the nodes. The list of hashes starts with the latest&lt;br /&gt;
block and goes back ten and then doubles in an exponential progression&lt;br /&gt;
until the genesis block is reached.[3] Since both nodes are hard coded&lt;br /&gt;
with the genesis block, they are guaranteed to a least start there.&lt;br /&gt;
If that block does not match for some reason, no blocks are exchanged.&lt;br /&gt;
&lt;br /&gt;
== Inventory Messages ==&lt;br /&gt;
&lt;br /&gt;
Note that the node receiving the getblocks request does not actually send&lt;br /&gt;
full blocks in response. The node sends an &amp;quot;inv&amp;quot; message containing just&lt;br /&gt;
the hashes of the series of blocks that fit the request, which verifies&lt;br /&gt;
that the node does indeed have blocks to send that the remote node does&lt;br /&gt;
not have (but does not presume the remote node wants the full blocks yet).&lt;br /&gt;
&lt;br /&gt;
When the local node receives the &amp;quot;inv&amp;quot; message, it will request the actual&lt;br /&gt;
blocks with a &amp;quot;getdata&amp;quot; message. See Below.&lt;br /&gt;
&lt;br /&gt;
But first, here is more detail how the remote node sends the &amp;quot;inv&amp;quot; message&lt;br /&gt;
in response to the &amp;quot;getblocks&amp;quot; request sent by the local node. The remote&lt;br /&gt;
node calls pFrom-&amp;gt;PushInventory which is a method on the CNode instance that&lt;br /&gt;
represents the node that requested the blocks (the local node in this&lt;br /&gt;
walkthrough), and PushInventory adds the block hash to the vInventoryToSend&lt;br /&gt;
variable of the CNode. The SendMessages function in [https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp main.cpp] will take the&lt;br /&gt;
inv items out of vInventoryToSend and add it to a vInv variable which&lt;br /&gt;
means they are really ready for sending.[4]&lt;br /&gt;
The reason for the seperate variable is that some inventory items&lt;br /&gt;
(transactions only right now) may be &amp;quot;trickled&amp;quot; to the remote node,&lt;br /&gt;
which means they may kept from from being sent right away.&lt;br /&gt;
When the vInv variable fills up with 1000 entries, a message is queued&lt;br /&gt;
with those 1000 entries and the loop continues. At the end, any&lt;br /&gt;
remaining entries are sent in a final &amp;quot;inv&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
When the local node receives the &amp;quot;inv&amp;quot; message, it will request the actual&lt;br /&gt;
block with a &amp;quot;getdata&amp;quot; message. To be precise, the node calls pfrom-&amp;gt;AskFor&lt;br /&gt;
to request the block, and that method queues the request for the blocks in&lt;br /&gt;
mapAskFor, and the multipurpose SendMessage() sends the &amp;quot;getdata&amp;quot; requests&lt;br /&gt;
in batches of 1000 entries from the map.[5]&lt;br /&gt;
&lt;br /&gt;
The code attempts to limit redundant requests to every 2 minutes for the&lt;br /&gt;
same block by using a map called mapAlreadyAskedFor to delay the message&lt;br /&gt;
if necessary.[6]&lt;br /&gt;
&lt;br /&gt;
== Block Batching ==&lt;br /&gt;
&lt;br /&gt;
The responding node to a &amp;quot;getblocks&amp;quot; request attempts to limit the response&lt;br /&gt;
to the requestor to 500 blocks.[7]&lt;br /&gt;
&lt;br /&gt;
However, in a peculiar twist, if the requestor appears to have diverged&lt;br /&gt;
from the main branch, the node will send as many blocks as necessary to&lt;br /&gt;
replace the entire bad chain of the requestor, from the lastest common block&lt;br /&gt;
between the nodes, up to the last block the requestor has (on their bad main&lt;br /&gt;
branch). That is in addition to the 500 &amp;quot;catch up&amp;quot; blocks for main branch&lt;br /&gt;
updates that will also be sent.[8]&lt;br /&gt;
&lt;br /&gt;
Note that in addition to a flat limit on the number of blocks queued for&lt;br /&gt;
sending, bitcoind also limits the total size of the blocks that are being&lt;br /&gt;
queued. This is currently limited to half the send buffer size[9], which is&lt;br /&gt;
10MB, for a limit of 5MB of queued blocks for send.[10]&lt;br /&gt;
&lt;br /&gt;
== Batch Continue Mechanism ==&lt;br /&gt;
&lt;br /&gt;
When a node is finished sending a batch of block inventory, it records the&lt;br /&gt;
hash of the last block in the batch.[11] When the node receives a request&lt;br /&gt;
for that full block, it realizes the remove node is done with the current&lt;br /&gt;
batch and directly queues a special &amp;quot;inv&amp;quot; message (bypassing the normal&lt;br /&gt;
SendMessage mechanism) with one block hash entry containing the&lt;br /&gt;
latest block hash.[12] When the remote node receives that &amp;quot;inv&amp;quot; message,&lt;br /&gt;
it will see that it does not have that block and it it will ask for that&lt;br /&gt;
block as described above. However, this time when it receives the block&lt;br /&gt;
and processes it, it will notice that it does not have the previous block,&lt;br /&gt;
so it will record the latest block as an &amp;quot;orphan&amp;quot; block, and will request a&lt;br /&gt;
block update starting with the latest block it has up to the block before&lt;br /&gt;
the orphan [13], in order to fill in the gap. That goes out as a &amp;quot;getblocks&amp;quot;&lt;br /&gt;
request and the whole batch process repeats itself.&lt;br /&gt;
&lt;br /&gt;
However, there is a twist. When the next batch finishes, the remote node&lt;br /&gt;
sending the blocks will send the &amp;quot;inv&amp;quot; with latest block hash as usual, and&lt;br /&gt;
the local node will notice it already has this block in the orphan block&lt;br /&gt;
map this time and so it will skip requesting the block and directly ask&lt;br /&gt;
for a block update.[14] This process will continue until the last&lt;br /&gt;
block prior to the latest block is received. At the end of processing &lt;br /&gt;
that block, it will notice there is an orphan that pointed to this block&lt;br /&gt;
and will process the orphan block, (and any other orphans, recursively)&lt;br /&gt;
thus completing the entire process.[15]&lt;br /&gt;
&lt;br /&gt;
== Stall Recovery ==&lt;br /&gt;
&lt;br /&gt;
If the batching processes is interrupted for some reason, such as the&lt;br /&gt;
remote node failing to honor the &amp;quot;Batch Continue Mechanism&amp;quot; or if a &lt;br /&gt;
disconnection occurs, there is a way for the process to restart. When&lt;br /&gt;
a new block is solved and advertised around[16], any nodes that are&lt;br /&gt;
behind will notice the new block in the &amp;quot;inv&amp;quot; and that will trigger it&lt;br /&gt;
to request a &amp;quot;getblocks&amp;quot; update from the node that sent it the message.&lt;br /&gt;
That will cause blocks to be sent starting from wherever in the block&lt;br /&gt;
chain that the node that is behind is currently at.&lt;br /&gt;
&lt;br /&gt;
== Long Orphan Chains ==&lt;br /&gt;
&lt;br /&gt;
In various tests, it has proven relatively common (say more than one&lt;br /&gt;
in ten) to discover nodes that are significantly behind on the block&lt;br /&gt;
chain, probably because they are in the process of catching up as well.&lt;br /&gt;
Since a well connected node will have at least 8 and up to dozens of&lt;br /&gt;
connections, it is fairly likely that a new node will connect to&lt;br /&gt;
another node that is also catching up.&lt;br /&gt;
&lt;br /&gt;
Nodes that are catching up will advertise the blocks they are processing,&lt;br /&gt;
as they accept blocks into their main chain, to every other node.[16]&lt;br /&gt;
While there is code to prevent advertising old blocks before a certain&lt;br /&gt;
checkpoint, that code also has a clause that does advertise blocks to&lt;br /&gt;
remote nodes if the block height is over the remote node's current best&lt;br /&gt;
height minus 2000 blocks.[17] This appears to allow nodes to &amp;quot;help&amp;quot; other&lt;br /&gt;
nodes catch up, even if they are both processing old blocks.&lt;br /&gt;
&lt;br /&gt;
These advertisements cause the local node to request those blocks&lt;br /&gt;
from the remote node, which could be blocks well into the future compared&lt;br /&gt;
to what has been processed locally. Due to the way blocks are requested,&lt;br /&gt;
the remote node will send a large batch of blocks in response and will&lt;br /&gt;
continue sending blocks to the local node until it reaches the end.&lt;br /&gt;
Note that this is likely to occur at the same time the local node is&lt;br /&gt;
downloading earlier blocks on the main chain from another node. That&lt;br /&gt;
process may eventually catch up with the orphan chain and produce a &lt;br /&gt;
very, very long operation to revalidate and connect up all the orphan&lt;br /&gt;
blocks. Orphan chains over ten thousand blocks long, taking over an hour&lt;br /&gt;
to process are possible.&lt;br /&gt;
&lt;br /&gt;
Therefore, two nodes talking to each other that are both catching up can&lt;br /&gt;
lead to suboptimal interactions, especially when one both are far behind&lt;br /&gt;
and one is far ahead of the other.&lt;br /&gt;
&lt;br /&gt;
== Flood Limit Effects ==&lt;br /&gt;
&lt;br /&gt;
Even with the batching mechanism described above, there are scenarios&lt;br /&gt;
that occur that result in the remote node overflowing the local receive&lt;br /&gt;
buffer while blocks are being exchanged.&lt;br /&gt;
&lt;br /&gt;
For example, if a remote node is &amp;quot;catching up&amp;quot;, it will advertise each block&lt;br /&gt;
it processes to the local node in certain circumstances (see above [17]).&lt;br /&gt;
The local node will request each of those blocks right away. There is no&lt;br /&gt;
protection against the local node requesting too many of these blocks.&lt;br /&gt;
The remote node will send all blocks requested. There is no protection&lt;br /&gt;
against the remote node sending too many blocks before the local node has&lt;br /&gt;
time to process them, in this circumstance.&lt;br /&gt;
&lt;br /&gt;
The local receive buffer can fill up. When the local node notices a receive&lt;br /&gt;
buffer is full, it disconnects that node connection.[18]&lt;br /&gt;
If sets the fDisconnect flag, and once the buffers are empty[19], the&lt;br /&gt;
socket is closed.&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
As of September 1, 2011, on a server class computer circa 2005 running&lt;br /&gt;
Ubuntu with a Comcast cable internet connection takes over 10 hours &lt;br /&gt;
to download and process the block chain. While it is debatable what&lt;br /&gt;
the bottleneck is early in the download process, it is clear from&lt;br /&gt;
the processing of recent blocks that the network is not the bottleneck&lt;br /&gt;
for all but the slowest internet connections.&lt;br /&gt;
&lt;br /&gt;
Blocks are taking over a second, on average, to process once downloaded.[20]&lt;br /&gt;
However, the average size of a block is only around 24 kilobytes&lt;br /&gt;
in August 2011. It certainly does not take 1 second to download 24K.&lt;br /&gt;
Also, testing reveals very large queues of blocks being processed per&lt;br /&gt;
message loop, which is not what you would expect if the thread was&lt;br /&gt;
pulling them out of the queue as they arrive on the sockets. &lt;br /&gt;
&lt;br /&gt;
There are a number of &amp;quot;false signals&amp;quot; that lead one to believe the problem&lt;br /&gt;
is with network performance. The first false signal is that, as of&lt;br /&gt;
August 2011, nearly all of the first 60 or 70% of blocks downloaded are&lt;br /&gt;
very small. Recent average block sizes are around one hundred times bigger!&lt;br /&gt;
So, almost all of a sudden, the block rate goes from very fast to very slow.&lt;br /&gt;
It looks like something went wrong. In reality, if you measure the rate&lt;br /&gt;
of block processing by kilobyte, the rate remains relatively constant.&lt;br /&gt;
&lt;br /&gt;
Another false signal is related to the fact that message queues are&lt;br /&gt;
processed to completion, one at a time per node. This can result in big&lt;br /&gt;
backups of messages from other nodes. So, a long period of increasing&lt;br /&gt;
blocks may freeze for long periods as other nodes are serviced. Consider&lt;br /&gt;
that block downloads typically come from just one remote node (at&lt;br /&gt;
least until a miner or other relaying or downloading node advertises&lt;br /&gt;
a late block and disrupts the process) and so all the work might&lt;br /&gt;
be on one node. Things go fast processing the blocks from a node,&lt;br /&gt;
and then that looks like it stops as &amp;quot;addr&amp;quot; messages are processed from&lt;br /&gt;
other nodes and other work is done. But it looks like something is wrong.&lt;br /&gt;
&lt;br /&gt;
Also, the orphaning effects described above can lead to excessive block&lt;br /&gt;
processing with nothing to show for it until the orphan chain is connected.&lt;br /&gt;
Also, you do ocassionally run into a node that is slow to respond, perhaps&lt;br /&gt;
because they are also processing blocks or because they have a slow machine&lt;br /&gt;
or connection.&lt;br /&gt;
&lt;br /&gt;
All of the above contributes to heavy &amp;quot;jitter&amp;quot; in the block download process,&lt;br /&gt;
and that is a more frustrating user experience than a constant download rate.&lt;br /&gt;
&lt;br /&gt;
==Footnotes==&lt;br /&gt;
1. See pfrom-&amp;gt;fInbound where pfrom is a CNode.&lt;br /&gt;
&lt;br /&gt;
2. See ProcessMessage() in main.cpp where strCommand == &amp;quot;version&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
3. See CBlockLocator in main.h.&lt;br /&gt;
&lt;br /&gt;
4. See Message: inventory in SendMessage in main.cpp.&lt;br /&gt;
&lt;br /&gt;
5. See Message: getdata at the end of SendMessage in main.cpp.&lt;br /&gt;
&lt;br /&gt;
6. See CNode::AskFor in net.h.&lt;br /&gt;
&lt;br /&gt;
7. See ProcessMessage() in main.cpp where strCommand ==&amp;quot;getblocks&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
8. See&lt;br /&gt;
 int nLimit = 500 + locator.GetDistanceBack();&lt;br /&gt;
in ProcessMessage in main.cpp where strCommand ==&amp;quot;getblocks&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
9. See&lt;br /&gt;
 if (--nLimit &amp;lt;= 0 || nBytes &amp;gt;= SendBufferSize()/2)&lt;br /&gt;
in ProcessMessage() in main.cpp where strCommand ==&amp;quot;getblocks&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
10. See&lt;br /&gt;
 inline unsigned int SendBufferSize() {&lt;br /&gt;
 return 1000*GetArg(&amp;quot;-maxsendbuffer&amp;quot;, 10*1000); }&lt;br /&gt;
in net.h.&lt;br /&gt;
&lt;br /&gt;
11. See pfrom-&amp;gt;hashContinue = pindex-&amp;gt;GetBlockHash();&lt;br /&gt;
 in ProcessMessage() in main.cpp where strCommand ==&amp;quot;getblocks&amp;quot;.&lt;br /&gt;
12. See: if (inv.hash == pfrom-&amp;gt;hashContinue)&lt;br /&gt;
 in ProcessMessage() in main.cpp where strCommand ==&amp;quot;getdata&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
13. See:&lt;br /&gt;
 // Ask this guy to fill in what we're missing&lt;br /&gt;
 if (pfrom)&lt;br /&gt;
 pfrom-&amp;gt;PushGetBlocks(pindexBest, GetOrphanRoot(pblock2));&lt;br /&gt;
in ProcessBlock() in main.cpp.&lt;br /&gt;
&lt;br /&gt;
14. See:&lt;br /&gt;
 else if (inv.type == MSG_BLOCK &amp;amp;&amp;amp; mapOrphanBlocks.count(inv.hash))&lt;br /&gt;
 pfrom-&amp;gt;PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));&lt;br /&gt;
in ProcessMessage() in main.cpp where strCommand ==&amp;quot;inv&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
15. See:&lt;br /&gt;
 // Recursively process any orphan blocks that depended on this one&lt;br /&gt;
in ProcessBlock() in main.cpp.&lt;br /&gt;
&lt;br /&gt;
16. See the last block of code in AcceptBlock in main.cpp.&lt;br /&gt;
&lt;br /&gt;
17. See:&lt;br /&gt;
 if (nBestHeight &amp;gt; (pnode-&amp;gt;nStartingHeight != -1 ? pnode-&amp;gt;nStartingHeight - 2000 : 134444))&lt;br /&gt;
 in AcceptBlock() in main.cpp.&lt;br /&gt;
&lt;br /&gt;
18. See:&lt;br /&gt;
 if (nPos &amp;gt; ReceiveBufferSize()) {&lt;br /&gt;
in ThreadSocketHandler2() in net.cpp.&lt;br /&gt;
&lt;br /&gt;
19. See:&lt;br /&gt;
 if (pnode-&amp;gt;fDisconnect ||&lt;br /&gt;
 (pnode-&amp;gt;GetRefCount() &amp;lt;= 0 &amp;amp;&amp;amp; pnode-&amp;gt;vRecv.empty() &amp;amp;&amp;amp; pnode-&amp;gt;vSend.empty()))&lt;br /&gt;
in ThreadSocketHandler2() in net.cpp.&lt;br /&gt;
&lt;br /&gt;
20. This is from the authors experience and also&lt;br /&gt;
 see https://bitcointalk.org/index.php?topic=31376.0.&lt;br /&gt;
&lt;br /&gt;
==Source==&lt;br /&gt;
&lt;br /&gt;
[http://bitcoin.it/ http://bitcoin.it/]&lt;br /&gt;
&lt;br /&gt;
[[Category:Technology]]&lt;br /&gt;
[[Category:Manuals]]&lt;br /&gt;
==See Also on BitcoinWiki==&lt;br /&gt;
* [[Aigo]]&lt;br /&gt;
* [[HeliosCoin]]&lt;br /&gt;
* [[Let It Play]]&lt;br /&gt;
* [[OZEX]]&lt;br /&gt;
* [[OVATO]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
		
	</entry>
</feed>