Skip to content

Commit

Permalink
Allow block announcements with headers
Browse files Browse the repository at this point in the history
This replaces using inv messages to announce new blocks, when a peer requests
(via the new "sendheaders" message) that blocks be announced with headers
instead of inv's.

Since headers-first was introduced, peers send getheaders messages in response
to an inv, which requires generating a block locator that is large compared to
the size of the header being requested, and requires an extra round-trip before
a reorg can be relayed.  Save time by tracking headers that a peer is likely to
know about, and send a headers chain that would connect to a peer's known
headers, unless the chain would be too big, in which case we revert to sending
an inv instead.

Based off of @sipa's commit to announce all blocks in a reorg via inv,
which has been squashed into this commit.

Rebased-by: Pieter Wuille
  • Loading branch information
sdaftuar authored and sipa committed Nov 29, 2015
1 parent c894fbb commit 50262d8
Show file tree
Hide file tree
Showing 8 changed files with 781 additions and 14 deletions.
1 change: 1 addition & 0 deletions qa/pull-tester/rpc-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
'p2p-fullblocktest.py',
'blockchain.py',
'disablewallet.py',
'sendheaders.py',
]
testScriptsExt = [
'bip65-cltv.py',
Expand Down
519 changes: 519 additions & 0 deletions qa/rpc-tests/sendheaders.py

Large diffs are not rendered by default.

32 changes: 29 additions & 3 deletions qa/rpc-tests/test_framework/mininode.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,8 +751,8 @@ def __repr__(self):
class msg_getdata(object):
command = "getdata"

def __init__(self):
self.inv = []
def __init__(self, inv=None):
self.inv = inv if inv != None else []

def deserialize(self, f):
self.inv = deser_vector(f, CInv)
Expand Down Expand Up @@ -905,6 +905,20 @@ def serialize(self):
def __repr__(self):
return "msg_mempool()"

class msg_sendheaders(object):
command = "sendheaders"

def __init__(self):
pass

def deserialize(self, f):
pass

def serialize(self):
return ""

def __repr__(self):
return "msg_sendheaders()"

# getheaders message has
# number of entries
Expand Down Expand Up @@ -990,6 +1004,17 @@ class NodeConnCB(object):
def __init__(self):
self.verack_received = False

# Spin until verack message is received from the node.
# Tests may want to use this as a signal that the test can begin.
# This can be called from the testing thread, so it needs to acquire the
# global lock.
def wait_for_verack(self):
while True:
with mininode_lock:
if self.verack_received:
return
time.sleep(0.05)

# Derived classes should call this function once to set the message map
# which associates the derived classes' functions to incoming messages
def create_callback_map(self):
Expand Down Expand Up @@ -1084,7 +1109,7 @@ class NodeConn(asyncore.dispatcher):
"regtest": "\xfa\xbf\xb5\xda" # regtest
}

def __init__(self, dstaddr, dstport, rpc, callback, net="regtest"):
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=1):
asyncore.dispatcher.__init__(self, map=mininode_socket_map)
self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport))
self.dstaddr = dstaddr
Expand All @@ -1102,6 +1127,7 @@ def __init__(self, dstaddr, dstport, rpc, callback, net="regtest"):

# stuff version msg into sendbuf
vt = msg_version()
vt.nServices = services
vt.addrTo.ip = self.dstaddr
vt.addrTo.port = self.dstport
vt.addrFrom.ip = "0.0.0.0"
Expand Down
3 changes: 3 additions & 0 deletions src/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
}

const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
if (pindex == NULL) {
return NULL;
}
if (pindex->nHeight > Height())
pindex = pindex->GetAncestor(Height());
while (pindex && !Contains(pindex))
Expand Down
Loading

0 comments on commit 50262d8

Please sign in to comment.