|
56 | 56 | "regtest": b"\xfa\xbf\xb5\xda", # regtest |
57 | 57 | } |
58 | 58 |
|
59 | | -class NodeConnCB(): |
60 | | - """Callback and helper functions for P2P connection to a bitcoind node. |
61 | | -
|
62 | | - Individual testcases should subclass this and override the on_* methods |
63 | | - if they want to alter message handling behaviour.""" |
64 | | - def __init__(self): |
65 | | - # Track whether we have a P2P connection open to the node |
66 | | - self.connected = False |
67 | | - self.connection = None |
68 | | - |
69 | | - # Track number of messages of each type received and the most recent |
70 | | - # message of each type |
71 | | - self.message_count = defaultdict(int) |
72 | | - self.last_message = {} |
73 | | - |
74 | | - # A count of the number of ping messages we've sent to the node |
75 | | - self.ping_counter = 1 |
76 | | - |
77 | | - # Message receiving methods |
78 | | - |
79 | | - def on_message(self, conn, message): |
80 | | - """Receive message and dispatch message to appropriate callback. |
81 | | -
|
82 | | - We keep a count of how many of each message type has been received |
83 | | - and the most recent message of each type.""" |
84 | | - with mininode_lock: |
85 | | - try: |
86 | | - command = message.command.decode('ascii') |
87 | | - self.message_count[command] += 1 |
88 | | - self.last_message[command] = message |
89 | | - getattr(self, 'on_' + command)(conn, message) |
90 | | - except: |
91 | | - print("ERROR delivering %s (%s)" % (repr(message), |
92 | | - sys.exc_info()[0])) |
93 | | - raise |
94 | | - |
95 | | - # Callback methods. Can be overridden by subclasses in individual test |
96 | | - # cases to provide custom message handling behaviour. |
97 | | - |
98 | | - def on_open(self, conn): |
99 | | - self.connected = True |
100 | | - |
101 | | - def on_close(self, conn): |
102 | | - self.connected = False |
103 | | - self.connection = None |
104 | | - |
105 | | - def on_addr(self, conn, message): pass |
106 | | - def on_block(self, conn, message): pass |
107 | | - def on_blocktxn(self, conn, message): pass |
108 | | - def on_cmpctblock(self, conn, message): pass |
109 | | - def on_feefilter(self, conn, message): pass |
110 | | - def on_getaddr(self, conn, message): pass |
111 | | - def on_getblocks(self, conn, message): pass |
112 | | - def on_getblocktxn(self, conn, message): pass |
113 | | - def on_getdata(self, conn, message): pass |
114 | | - def on_getheaders(self, conn, message): pass |
115 | | - def on_headers(self, conn, message): pass |
116 | | - def on_mempool(self, conn): pass |
117 | | - def on_pong(self, conn, message): pass |
118 | | - def on_reject(self, conn, message): pass |
119 | | - def on_sendcmpct(self, conn, message): pass |
120 | | - def on_sendheaders(self, conn, message): pass |
121 | | - def on_tx(self, conn, message): pass |
122 | | - |
123 | | - def on_inv(self, conn, message): |
124 | | - want = msg_getdata() |
125 | | - for i in message.inv: |
126 | | - if i.type != 0: |
127 | | - want.inv.append(i) |
128 | | - if len(want.inv): |
129 | | - conn.send_message(want) |
130 | | - |
131 | | - def on_ping(self, conn, message): |
132 | | - conn.send_message(msg_pong(message.nonce)) |
133 | | - |
134 | | - def on_verack(self, conn, message): |
135 | | - self.verack_received = True |
136 | | - |
137 | | - def on_version(self, conn, message): |
138 | | - assert message.nVersion >= MIN_VERSION_SUPPORTED, "Version {} received. Test framework only supports versions greater than {}".format(message.nVersion, MIN_VERSION_SUPPORTED) |
139 | | - conn.send_message(msg_verack()) |
140 | | - conn.nServices = message.nServices |
141 | | - |
142 | | - # Connection helper methods |
143 | | - |
144 | | - def add_connection(self, conn): |
145 | | - self.connection = conn |
146 | | - |
147 | | - def wait_for_disconnect(self, timeout=60): |
148 | | - test_function = lambda: not self.connected |
149 | | - wait_until(test_function, timeout=timeout, lock=mininode_lock) |
150 | | - |
151 | | - # Message receiving helper methods |
152 | | - |
153 | | - def wait_for_block(self, blockhash, timeout=60): |
154 | | - test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash |
155 | | - wait_until(test_function, timeout=timeout, lock=mininode_lock) |
156 | | - |
157 | | - def wait_for_getdata(self, timeout=60): |
158 | | - test_function = lambda: self.last_message.get("getdata") |
159 | | - wait_until(test_function, timeout=timeout, lock=mininode_lock) |
160 | | - |
161 | | - def wait_for_getheaders(self, timeout=60): |
162 | | - test_function = lambda: self.last_message.get("getheaders") |
163 | | - wait_until(test_function, timeout=timeout, lock=mininode_lock) |
164 | | - |
165 | | - def wait_for_inv(self, expected_inv, timeout=60): |
166 | | - """Waits for an INV message and checks that the first inv object in the message was as expected.""" |
167 | | - if len(expected_inv) > 1: |
168 | | - raise NotImplementedError("wait_for_inv() will only verify the first inv object") |
169 | | - test_function = lambda: self.last_message.get("inv") and \ |
170 | | - self.last_message["inv"].inv[0].type == expected_inv[0].type and \ |
171 | | - self.last_message["inv"].inv[0].hash == expected_inv[0].hash |
172 | | - wait_until(test_function, timeout=timeout, lock=mininode_lock) |
173 | | - |
174 | | - def wait_for_verack(self, timeout=60): |
175 | | - test_function = lambda: self.message_count["verack"] |
176 | | - wait_until(test_function, timeout=timeout, lock=mininode_lock) |
177 | | - |
178 | | - # Message sending helper functions |
179 | | - |
180 | | - def send_message(self, message): |
181 | | - if self.connection: |
182 | | - self.connection.send_message(message) |
183 | | - else: |
184 | | - logger.error("Cannot send message. No connection to node!") |
185 | | - |
186 | | - def send_and_ping(self, message): |
187 | | - self.send_message(message) |
188 | | - self.sync_with_ping() |
189 | | - |
190 | | - # Sync up with the node |
191 | | - def sync_with_ping(self, timeout=60): |
192 | | - self.send_message(msg_ping(nonce=self.ping_counter)) |
193 | | - test_function = lambda: self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter |
194 | | - wait_until(test_function, timeout=timeout, lock=mininode_lock) |
195 | | - self.ping_counter += 1 |
196 | | - |
197 | 59 | class NodeConn(asyncore.dispatcher): |
198 | 60 | """The actual NodeConn class |
199 | 61 |
|
@@ -376,6 +238,145 @@ def _log_message(self, direction, msg): |
376 | 238 | logger.debug(log_message) |
377 | 239 |
|
378 | 240 |
|
| 241 | +class NodeConnCB(): |
| 242 | + """Callback and helper functions for P2P connection to a bitcoind node. |
| 243 | +
|
| 244 | + Individual testcases should subclass this and override the on_* methods |
| 245 | + if they want to alter message handling behaviour.""" |
| 246 | + def __init__(self): |
| 247 | + # Track whether we have a P2P connection open to the node |
| 248 | + self.connected = False |
| 249 | + self.connection = None |
| 250 | + |
| 251 | + # Track number of messages of each type received and the most recent |
| 252 | + # message of each type |
| 253 | + self.message_count = defaultdict(int) |
| 254 | + self.last_message = {} |
| 255 | + |
| 256 | + # A count of the number of ping messages we've sent to the node |
| 257 | + self.ping_counter = 1 |
| 258 | + |
| 259 | + # Message receiving methods |
| 260 | + |
| 261 | + def on_message(self, conn, message): |
| 262 | + """Receive message and dispatch message to appropriate callback. |
| 263 | +
|
| 264 | + We keep a count of how many of each message type has been received |
| 265 | + and the most recent message of each type.""" |
| 266 | + with mininode_lock: |
| 267 | + try: |
| 268 | + command = message.command.decode('ascii') |
| 269 | + self.message_count[command] += 1 |
| 270 | + self.last_message[command] = message |
| 271 | + getattr(self, 'on_' + command)(conn, message) |
| 272 | + except: |
| 273 | + print("ERROR delivering %s (%s)" % (repr(message), |
| 274 | + sys.exc_info()[0])) |
| 275 | + raise |
| 276 | + |
| 277 | + # Callback methods. Can be overridden by subclasses in individual test |
| 278 | + # cases to provide custom message handling behaviour. |
| 279 | + |
| 280 | + def on_open(self, conn): |
| 281 | + self.connected = True |
| 282 | + |
| 283 | + def on_close(self, conn): |
| 284 | + self.connected = False |
| 285 | + self.connection = None |
| 286 | + |
| 287 | + def on_addr(self, conn, message): pass |
| 288 | + def on_block(self, conn, message): pass |
| 289 | + def on_blocktxn(self, conn, message): pass |
| 290 | + def on_cmpctblock(self, conn, message): pass |
| 291 | + def on_feefilter(self, conn, message): pass |
| 292 | + def on_getaddr(self, conn, message): pass |
| 293 | + def on_getblocks(self, conn, message): pass |
| 294 | + def on_getblocktxn(self, conn, message): pass |
| 295 | + def on_getdata(self, conn, message): pass |
| 296 | + def on_getheaders(self, conn, message): pass |
| 297 | + def on_headers(self, conn, message): pass |
| 298 | + def on_mempool(self, conn): pass |
| 299 | + def on_pong(self, conn, message): pass |
| 300 | + def on_reject(self, conn, message): pass |
| 301 | + def on_sendcmpct(self, conn, message): pass |
| 302 | + def on_sendheaders(self, conn, message): pass |
| 303 | + def on_tx(self, conn, message): pass |
| 304 | + |
| 305 | + def on_inv(self, conn, message): |
| 306 | + want = msg_getdata() |
| 307 | + for i in message.inv: |
| 308 | + if i.type != 0: |
| 309 | + want.inv.append(i) |
| 310 | + if len(want.inv): |
| 311 | + conn.send_message(want) |
| 312 | + |
| 313 | + def on_ping(self, conn, message): |
| 314 | + conn.send_message(msg_pong(message.nonce)) |
| 315 | + |
| 316 | + def on_verack(self, conn, message): |
| 317 | + self.verack_received = True |
| 318 | + |
| 319 | + def on_version(self, conn, message): |
| 320 | + assert message.nVersion >= MIN_VERSION_SUPPORTED, "Version {} received. Test framework only supports versions greater than {}".format(message.nVersion, MIN_VERSION_SUPPORTED) |
| 321 | + conn.send_message(msg_verack()) |
| 322 | + conn.nServices = message.nServices |
| 323 | + |
| 324 | + # Connection helper methods |
| 325 | + |
| 326 | + def add_connection(self, conn): |
| 327 | + self.connection = conn |
| 328 | + |
| 329 | + def wait_for_disconnect(self, timeout=60): |
| 330 | + test_function = lambda: not self.connected |
| 331 | + wait_until(test_function, timeout=timeout, lock=mininode_lock) |
| 332 | + |
| 333 | + # Message receiving helper methods |
| 334 | + |
| 335 | + def wait_for_block(self, blockhash, timeout=60): |
| 336 | + test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash |
| 337 | + wait_until(test_function, timeout=timeout, lock=mininode_lock) |
| 338 | + |
| 339 | + def wait_for_getdata(self, timeout=60): |
| 340 | + test_function = lambda: self.last_message.get("getdata") |
| 341 | + wait_until(test_function, timeout=timeout, lock=mininode_lock) |
| 342 | + |
| 343 | + def wait_for_getheaders(self, timeout=60): |
| 344 | + test_function = lambda: self.last_message.get("getheaders") |
| 345 | + wait_until(test_function, timeout=timeout, lock=mininode_lock) |
| 346 | + |
| 347 | + def wait_for_inv(self, expected_inv, timeout=60): |
| 348 | + """Waits for an INV message and checks that the first inv object in the message was as expected.""" |
| 349 | + if len(expected_inv) > 1: |
| 350 | + raise NotImplementedError("wait_for_inv() will only verify the first inv object") |
| 351 | + test_function = lambda: self.last_message.get("inv") and \ |
| 352 | + self.last_message["inv"].inv[0].type == expected_inv[0].type and \ |
| 353 | + self.last_message["inv"].inv[0].hash == expected_inv[0].hash |
| 354 | + wait_until(test_function, timeout=timeout, lock=mininode_lock) |
| 355 | + |
| 356 | + def wait_for_verack(self, timeout=60): |
| 357 | + test_function = lambda: self.message_count["verack"] |
| 358 | + wait_until(test_function, timeout=timeout, lock=mininode_lock) |
| 359 | + |
| 360 | + # Message sending helper functions |
| 361 | + |
| 362 | + def send_message(self, message): |
| 363 | + if self.connection: |
| 364 | + self.connection.send_message(message) |
| 365 | + else: |
| 366 | + logger.error("Cannot send message. No connection to node!") |
| 367 | + |
| 368 | + def send_and_ping(self, message): |
| 369 | + self.send_message(message) |
| 370 | + self.sync_with_ping() |
| 371 | + |
| 372 | + # Sync up with the node |
| 373 | + def sync_with_ping(self, timeout=60): |
| 374 | + self.send_message(msg_ping(nonce=self.ping_counter)) |
| 375 | + test_function = lambda: self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter |
| 376 | + wait_until(test_function, timeout=timeout, lock=mininode_lock) |
| 377 | + self.ping_counter += 1 |
| 378 | + |
| 379 | + |
379 | 380 | # Keep our own socket map for asyncore, so that we can track disconnects |
380 | 381 | # ourselves (to workaround an issue with closing an asyncore socket when |
381 | 382 | # using select) |
|
0 commit comments