Block chain download: Difference between revisions

From Bitcoin Wiki
Jump to navigation Jump to search
Harding (talk | contribs)
m Added Bitcoin Core documentation navbox
JonathanCross (talk | contribs)
→‎Downloader Behavior: Linking first occurrence of technical terms.
 
Line 5: Line 5:
=== Downloader Behavior ===
=== Downloader Behavior ===


* When receiving an inv
* When receiving an [[Satoshi_Client_Block_Exchange#Inventory_Messages|inv (Inventory Message)]]
** For each block
** For each [[block]]
*** If already have as orphan, send getblocks(locator(chainHead), orphanRoot(block))
*** If already have as [[Orphan_Block|orphan]], send [[Protocol_documentation#getblocks|getblocks]](locator(chainHead), [[Vocabulary#Orphan_root|orphanRoot]](block))
*** If not already have
*** If not already have
**** send getdata(block)
**** send [[Protocol_documentation#getdata|getdata]](block)
*** If already have and this is last block in message NOTE: this triggers specific behavior in peer getdata
*** If already have and this is last block in message (NOTE: this triggers specific behavior in peer getdata)
**** send getdata(block)
**** send getdata(block)


* When receiving a block
* When receiving a block
** If already have, ignore
** If already have, ignore
** Else if have parent not in main chain
** Else if have parent not in [[Vocabulary#Main_Chain|main chain]]
*** store as orphan
*** store as orphan
*** getblocks(locator(chainHead), orphanRoot(block))
*** getblocks(locator(chainHead), orphanRoot(block))
Line 24: Line 24:
* When starting download from a peer
* When starting download from a peer
** getblocks(locator(chainHead), 0)
** getblocks(locator(chainHead), 0)


=== Responder Behavior ===
=== Responder Behavior ===

Latest revision as of 19:43, 26 January 2016

Bitcoin Chain Download

See also Satoshi Client Block Exchange for an overview.

Downloader Behavior

  • When receiving an inv (Inventory Message)
    • For each block
      • If already have as orphan, send getblocks(locator(chainHead), orphanRoot(block))
      • If not already have
      • If already have and this is last block in message (NOTE: this triggers specific behavior in peer getdata)
        • send getdata(block)
  • When receiving a block
    • If already have, ignore
    • Else if have parent not in main chain
      • store as orphan
      • getblocks(locator(chainHead), orphanRoot(block))
    • Else
      • Accept block
      • Accept orphan blocks that depend on this one
  • When starting download from a peer
    • getblocks(locator(chainHead), 0)

Responder Behavior

  • When receiving getdata, for each requested block
    • Send block
    • If block == hashContinue(peer)
      • send inv(chainHead)
      • set hashContinue(peer)=0
  • When receiving getblocks(locator, hashStop)
    • Iterate from locate(locator)->next, going forward in chain
      • If reached hashStop or ran off end of chain, break
      • If reached limit of 500 or buffer limit
        • Set current hashContinue(peer) to current block hash
        • break
      • Send inv for block
  • When receiving getheaders(hashLocator, hashStop)
    • If hashLocator = 0, return block(hashStop)
    • Send up to 2000 block headers, iterating from block(hashLocator) to hashStop

Locator

Downloader: create locator(block)

  • For 1..10
    • block = block->prev
    • add block->hash
  • step = 1
  • Do
    • block = block->prev 'step' times
    • add block->hash
    • step = step * 2
  • add genesis->hash

Responder: locate(locator)

  • Foreach hash in locator
    • If hash exists in main chain, return block
  • Otherwise return genesis block

Analysis

Observations:

  • the locator is dense near downloader chain head, and exponentially sparse as it goes towards the genesis
  • downloading is accomplished in cooperation:
    • downloader sends getblocks with locator based on downloader chain head
    • responder sends invs for first 500 blocks going forward from latest common block (approximate, per locator)
    • downloader sends getdata for blocks it does not have
    • responder sends blocks and a gratuitious inv for reponder chain head
    • downloader incorporates blocks into chain and now has a new chain head
    • downloader sends another getblocks in response to the gratuitious inv with new locator based on new chain head

Here are some cases. dChainHead is the downloader chain head, rChainHead is the responder chain head.

Single Block Case

  • Responder sends an inv for a newly solved block
  • Downloader sends getdata
  • Responder sends block

Small Catchup Case

  • Downloader sends getblocks(locator(dChainHead), 0)
  • Responder sends invs for blocks from dChainHead to rChainHead
  • Downloader sends getdata for each inv
  • Responder sends blocks for each getdata

Large Catchup Case

  • Downloader sends getblocks(locator(dChainHead), 0)
  • Responder sends invs for blocks from dChainHead to dChainHead + 500
  • (getdata / blocks sent by responder / blocks added to chain by downloader)
  • The last getdata triggers an inv(rChainHead)
  • Downloader sends getdata(rChainHead)
  • Responder sends block
  • Downloader puts block on orphan list
  • Downloader sends getblocks(locator(dChainHead), rChainHead)
  • goto step 2

Side Chain Case

  • Downloader sends getblocks(locator(dChainHead), 0)
  • Responder does not have dChainHead in best chain. Responder iterates over locator until it finds a block in common for the two chains.
  • Responder sends invs for blocks from commonBlock to rChainHead
  • Downloader adds the blocks that it did not have and reorganizes

For this to work, the invs must fit the network buffer.

Large Side Chain Case

More invs than fits the network buffer.

If the side chain has blocks than fits in the network buffer this does not seem to work. getblocks(locator(dChainHead), rChainHead) will not return enough blocks for the Downloader to switch chains. If the Downloader does not switch chains, it will send the same getblocks message again.