2 # Copyright (c) 2017 The Bitcoin Core developers
3 # Distributed under the MIT software license, see the accompanying
4 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 """Test message sending before handshake completion.
7 A node should never send anything other than VERSION/VERACK/REJECT until it's
10 This test connects to a node and sends it a few messages, trying to intice it
11 into sending us something it shouldn't.
14 from test_framework
.mininode
import *
15 from test_framework
.test_framework
import BitcoinTestFramework
16 from test_framework
.util
import *
20 class CLazyNode(NodeConnCB
):
23 self
.unexpected_msg
= False
24 self
.ever_connected
= False
26 def bad_message(self
, message
):
27 self
.unexpected_msg
= True
28 self
.log
.info("should not have received message: %s" % message
.command
)
30 def on_open(self
, conn
):
32 self
.ever_connected
= True
34 def on_version(self
, conn
, message
): self
.bad_message(message
)
35 def on_verack(self
, conn
, message
): self
.bad_message(message
)
36 def on_reject(self
, conn
, message
): self
.bad_message(message
)
37 def on_inv(self
, conn
, message
): self
.bad_message(message
)
38 def on_addr(self
, conn
, message
): self
.bad_message(message
)
39 def on_alert(self
, conn
, message
): self
.bad_message(message
)
40 def on_getdata(self
, conn
, message
): self
.bad_message(message
)
41 def on_getblocks(self
, conn
, message
): self
.bad_message(message
)
42 def on_tx(self
, conn
, message
): self
.bad_message(message
)
43 def on_block(self
, conn
, message
): self
.bad_message(message
)
44 def on_getaddr(self
, conn
, message
): self
.bad_message(message
)
45 def on_headers(self
, conn
, message
): self
.bad_message(message
)
46 def on_getheaders(self
, conn
, message
): self
.bad_message(message
)
47 def on_ping(self
, conn
, message
): self
.bad_message(message
)
48 def on_mempool(self
, conn
): self
.bad_message(message
)
49 def on_pong(self
, conn
, message
): self
.bad_message(message
)
50 def on_feefilter(self
, conn
, message
): self
.bad_message(message
)
51 def on_sendheaders(self
, conn
, message
): self
.bad_message(message
)
52 def on_sendcmpct(self
, conn
, message
): self
.bad_message(message
)
53 def on_cmpctblock(self
, conn
, message
): self
.bad_message(message
)
54 def on_getblocktxn(self
, conn
, message
): self
.bad_message(message
)
55 def on_blocktxn(self
, conn
, message
): self
.bad_message(message
)
57 # Node that never sends a version. We'll use this to send a bunch of messages
58 # anyway, and eventually get disconnected.
59 class CNodeNoVersionBan(CLazyNode
):
60 # send a bunch of veracks without sending a message. This should get us disconnected.
61 # NOTE: implementation-specific check here. Remove if bitcoind ban behavior changes
62 def on_open(self
, conn
):
64 for i
in range(banscore
):
65 self
.send_message(msg_verack())
67 def on_reject(self
, conn
, message
): pass
69 # Node that never sends a version. This one just sits idle and hopes to receive
70 # any message (it shouldn't!)
71 class CNodeNoVersionIdle(CLazyNode
):
75 # Node that sends a version but not a verack.
76 class CNodeNoVerackIdle(CLazyNode
):
78 self
.version_received
= False
81 def on_reject(self
, conn
, message
): pass
82 def on_verack(self
, conn
, message
): pass
83 # When version is received, don't reply with a verack. Instead, see if the
84 # node will give us a message that it shouldn't. This is not an exhaustive
86 def on_version(self
, conn
, message
):
87 self
.version_received
= True
88 conn
.send_message(msg_ping())
89 conn
.send_message(msg_getaddr())
91 class P2PLeakTest(BitcoinTestFramework
):
95 self
.extra_args
= [['-banscore='+str(banscore
)]]
98 no_version_bannode
= CNodeNoVersionBan()
99 no_version_idlenode
= CNodeNoVersionIdle()
100 no_verack_idlenode
= CNodeNoVerackIdle()
103 connections
.append(NodeConn('127.0.0.1', p2p_port(0), self
.nodes
[0], no_version_bannode
, send_version
=False))
104 connections
.append(NodeConn('127.0.0.1', p2p_port(0), self
.nodes
[0], no_version_idlenode
, send_version
=False))
105 connections
.append(NodeConn('127.0.0.1', p2p_port(0), self
.nodes
[0], no_verack_idlenode
))
106 no_version_bannode
.add_connection(connections
[0])
107 no_version_idlenode
.add_connection(connections
[1])
108 no_verack_idlenode
.add_connection(connections
[2])
110 NetworkThread().start() # Start up network handling in another thread
112 assert wait_until(lambda: no_version_bannode
.ever_connected
, timeout
=10)
113 assert wait_until(lambda: no_version_idlenode
.ever_connected
, timeout
=10)
114 assert wait_until(lambda: no_verack_idlenode
.version_received
, timeout
=10)
116 # Mine a block and make sure that it's not sent to the connected nodes
117 self
.nodes
[0].generate(1)
119 #Give the node enough time to possibly leak out a message
122 #This node should have been banned
123 assert not no_version_bannode
.connected
125 [conn
.disconnect_node() for conn
in connections
]
127 # Make sure no unexpected messages came in
128 assert(no_version_bannode
.unexpected_msg
== False)
129 assert(no_version_idlenode
.unexpected_msg
== False)
130 assert(no_verack_idlenode
.unexpected_msg
== False)
132 if __name__
== '__main__':