Changeset View
Changeset View
Standalone View
Standalone View
qa/rpc-tests/test_framework/mininode.py
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
COIN = 100000000 # 1 btc in satoshis | COIN = 100000000 # 1 btc in satoshis | ||||
NODE_NETWORK = (1 << 0) | NODE_NETWORK = (1 << 0) | ||||
NODE_GETUTXO = (1 << 1) | NODE_GETUTXO = (1 << 1) | ||||
NODE_BLOOM = (1 << 2) | NODE_BLOOM = (1 << 2) | ||||
NODE_WITNESS = (1 << 3) | NODE_WITNESS = (1 << 3) | ||||
# Howmuch data will be read from the network at once | |||||
READ_BUFFER_SIZE = 8192 | |||||
# Keep our own socket map for asyncore, so that we can track disconnects | # Keep our own socket map for asyncore, so that we can track disconnects | ||||
# ourselves (to workaround an issue with closing an asyncore socket when | # ourselves (to workaround an issue with closing an asyncore socket when | ||||
# using select) | # using select) | ||||
mininode_socket_map = dict() | mininode_socket_map = dict() | ||||
# One lock for synchronizing all data access between the networking thread (see | # One lock for synchronizing all data access between the networking thread (see | ||||
# NetworkThread below) and the thread running the test logic. For simplicity, | # NetworkThread below) and the thread running the test logic. For simplicity, | ||||
# NodeConn acquires this lock whenever delivering a message to to a NodeConnCB, | # NodeConn acquires this lock whenever delivering a message to to a NodeConnCB, | ||||
▲ Show 20 Lines • Show All 1,540 Lines • ▼ Show 20 Lines | messagemap = { | ||||
b"mempool": msg_mempool, | b"mempool": msg_mempool, | ||||
b"feefilter": msg_feefilter, | b"feefilter": msg_feefilter, | ||||
b"sendheaders": msg_sendheaders, | b"sendheaders": msg_sendheaders, | ||||
b"sendcmpct": msg_sendcmpct, | b"sendcmpct": msg_sendcmpct, | ||||
b"cmpctblock": msg_cmpctblock, | b"cmpctblock": msg_cmpctblock, | ||||
b"getblocktxn": msg_getblocktxn, | b"getblocktxn": msg_getblocktxn, | ||||
b"blocktxn": msg_blocktxn | b"blocktxn": msg_blocktxn | ||||
} | } | ||||
MAGIC_BYTES = { | MAGIC_BYTES = { | ||||
"mainnet": b"\xf9\xbe\xb4\xd9", # mainnet | "mainnet": b"\xf9\xbe\xb4\xd9", # mainnet | ||||
"testnet3": b"\x0b\x11\x09\x07", # testnet3 | "testnet3": b"\x0b\x11\x09\x07", # testnet3 | ||||
"regtest": b"\xfa\xbf\xb5\xda", # regtest | "regtest": b"\xfa\xbf\xb5\xda", # regtest | ||||
} | } | ||||
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK, send_version=True): | def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK, send_version=True): | ||||
asyncore.dispatcher.__init__(self, map=mininode_socket_map) | asyncore.dispatcher.__init__(self, map=mininode_socket_map) | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | def handle_close(self): | ||||
try: | try: | ||||
self.close() | self.close() | ||||
except: | except: | ||||
pass | pass | ||||
self.cb.on_close(self) | self.cb.on_close(self) | ||||
def handle_read(self): | def handle_read(self): | ||||
try: | try: | ||||
t = self.recv(8192) | with mininode_lock: | ||||
t = self.recv(READ_BUFFER_SIZE) | |||||
if len(t) > 0: | if len(t) > 0: | ||||
self.recvbuf += t | self.recvbuf += t | ||||
self.got_data() | |||||
except: | except: | ||||
pass | pass | ||||
while True: | |||||
msg = self.got_data() | |||||
if msg == None: | |||||
break | |||||
self.got_message(msg) | |||||
def readable(self): | def readable(self): | ||||
return True | return True | ||||
def writable(self): | def writable(self): | ||||
with mininode_lock: | with mininode_lock: | ||||
pre_connection = self.state == "connecting" | pre_connection = self.state == "connecting" | ||||
length = len(self.sendbuf) | length = len(self.sendbuf) | ||||
return (length > 0 or pre_connection) | return (length > 0 or pre_connection) | ||||
Show All 12 Lines | def handle_write(self): | ||||
sent = self.send(self.sendbuf) | sent = self.send(self.sendbuf) | ||||
except: | except: | ||||
self.handle_close() | self.handle_close() | ||||
return | return | ||||
self.sendbuf = self.sendbuf[sent:] | self.sendbuf = self.sendbuf[sent:] | ||||
def got_data(self): | def got_data(self): | ||||
try: | try: | ||||
while True: | with mininode_lock: | ||||
if len(self.recvbuf) < 4: | if len(self.recvbuf) < 4: | ||||
return | return None | ||||
if self.recvbuf[:4] != self.MAGIC_BYTES[self.network]: | if self.recvbuf[:4] != self.MAGIC_BYTES[self.network]: | ||||
raise ValueError("got garbage %s" % repr(self.recvbuf)) | raise ValueError("got garbage %s" % repr(self.recvbuf)) | ||||
if self.ver_recv < 209: | if self.ver_recv < 209: | ||||
if len(self.recvbuf) < 4 + 12 + 4: | if len(self.recvbuf) < 4 + 12 + 4: | ||||
return | return None | ||||
command = self.recvbuf[4:4+12].split(b"\x00", 1)[0] | command = self.recvbuf[4:4+12].split(b"\x00", 1)[0] | ||||
msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0] | msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0] | ||||
checksum = None | checksum = None | ||||
if len(self.recvbuf) < 4 + 12 + 4 + msglen: | if len(self.recvbuf) < 4 + 12 + 4 + msglen: | ||||
return | return None | ||||
msg = self.recvbuf[4+12+4:4+12+4+msglen] | msg = self.recvbuf[4+12+4:4+12+4+msglen] | ||||
self.recvbuf = self.recvbuf[4+12+4+msglen:] | self.recvbuf = self.recvbuf[4+12+4+msglen:] | ||||
else: | else: | ||||
if len(self.recvbuf) < 4 + 12 + 4 + 4: | if len(self.recvbuf) < 4 + 12 + 4 + 4: | ||||
return | return None | ||||
command = self.recvbuf[4:4+12].split(b"\x00", 1)[0] | command = self.recvbuf[4:4+12].split(b"\x00", 1)[0] | ||||
msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0] | msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0] | ||||
checksum = self.recvbuf[4+12+4:4+12+4+4] | checksum = self.recvbuf[4+12+4:4+12+4+4] | ||||
if len(self.recvbuf) < 4 + 12 + 4 + 4 + msglen: | if len(self.recvbuf) < 4 + 12 + 4 + 4 + msglen: | ||||
return | return None | ||||
msg = self.recvbuf[4+12+4+4:4+12+4+4+msglen] | msg = self.recvbuf[4+12+4+4:4+12+4+4+msglen] | ||||
th = sha256(msg) | h = sha256(sha256(msg)) | ||||
h = sha256(th) | |||||
if checksum != h[:4]: | if checksum != h[:4]: | ||||
raise ValueError("got bad checksum " + repr(self.recvbuf)) | raise ValueError("got bad checksum " + repr(self.recvbuf)) | ||||
self.recvbuf = self.recvbuf[4+12+4+4+msglen:] | self.recvbuf = self.recvbuf[4+12+4+4+msglen:] | ||||
if command in self.messagemap: | if command not in self.messagemap: | ||||
f = BytesIO(msg) | |||||
t = self.messagemap[command]() | |||||
t.deserialize(f) | |||||
self.got_message(t) | |||||
else: | |||||
self.show_debug_msg("Unknown command: '" + command + "' " + | self.show_debug_msg("Unknown command: '" + command + "' " + | ||||
repr(msg)) | repr(msg)) | ||||
return None | |||||
f = BytesIO(msg) | |||||
m = self.messagemap[command]() | |||||
m.deserialize(f) | |||||
return m | |||||
except Exception as e: | except Exception as e: | ||||
print('got_data:', repr(e)) | print('got_data:', repr(e)) | ||||
# import traceback | # import traceback | ||||
# traceback.print_tb(sys.exc_info()[2]) | # traceback.print_tb(sys.exc_info()[2]) | ||||
def send_message(self, message, pushbuf=False): | def send_message(self, message, pushbuf=False): | ||||
if self.state != "connected" and not pushbuf: | if self.state != "connected" and not pushbuf: | ||||
raise IOError('Not connected, no pushbuf') | raise IOError('Not connected, no pushbuf') | ||||
▲ Show 20 Lines • Show All 51 Lines • Show Last 20 Lines |