2016-03-19 20:58:06 +01:00
#!/usr/bin/env python3
# Copyright (c) 2010 ArtForz -- public domain half-a-node
# Copyright (c) 2012 Jeff Garzik
# Copyright (c) 2010-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
2015-04-28 18:36:15 +02:00
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-01-18 00:34:40 +01:00
""" Bitcoin P2P network half-a-node.
This python code was modified from ArtForz ' public domain half-a-node, as
found in the mini - node branch of http : / / github . com / jgarzik / pynode .
NodeConn : an object which manages p2p connectivity to a bitcoin node
NodeConnCB : a base class that describes the interface for receiving
callbacks with network messages from a NodeConn
CBlock , CTransaction , CBlockHeader , CTxIn , CTxOut , etc . . . . :
data structures that should map to corresponding structures in
bitcoin / primitives
msg_block , msg_tx , msg_headers , etc . :
data structures that represent network messages
ser_ * , deser_ * : functions that handle serialization / deserialization
"""
2015-04-28 18:36:15 +02:00
import asyncore
2016-03-19 21:36:32 +01:00
from codecs import encode
2017-03-29 20:07:39 +02:00
from collections import defaultdict
import copy
2015-04-28 18:36:15 +02:00
import hashlib
2017-03-29 20:07:39 +02:00
from io import BytesIO
2015-04-28 18:36:15 +02:00
import logging
2017-03-29 20:07:39 +02:00
import random
import socket
import struct
import sys
import time
from threading import RLock , Thread
2016-07-12 22:04:38 +02:00
from test_framework . siphash import siphash256
2017-08-16 18:17:34 +02:00
from test_framework . util import hex_str_to_bytes , bytes_to_hex_str , wait_until
2015-04-28 18:36:15 +02:00
2017-10-17 16:59:20 +02:00
MIN_VERSION_SUPPORTED = 60001
2016-07-12 22:04:38 +02:00
MY_VERSION = 70014 # past bip-31 for ping/pong
2016-03-19 20:58:06 +01:00
MY_SUBVERSION = b " /python-mininode-tester:0.0.3/ "
2016-10-05 20:24:36 +02:00
MY_RELAY = 1 # from version 70001 onwards, fRelay should be appended to version messages (BIP37)
2015-04-28 18:36:15 +02:00
MAX_INV_SZ = 50000
2016-11-21 22:29:22 +01:00
MAX_BLOCK_BASE_SIZE = 1000000
2015-04-28 18:36:15 +02:00
2016-03-19 20:58:06 +01:00
COIN = 100000000 # 1 btc in satoshis
2015-12-22 10:43:46 +01:00
2016-04-09 03:02:24 +02:00
NODE_NETWORK = ( 1 << 0 )
2017-07-20 23:10:37 +02:00
# NODE_GETUTXO = (1 << 1)
# NODE_BLOOM = (1 << 2)
2016-04-09 03:02:24 +02:00
NODE_WITNESS = ( 1 << 3 )
2017-08-07 17:37:49 +02:00
NODE_UNSUPPORTED_SERVICE_BIT_5 = ( 1 << 5 )
NODE_UNSUPPORTED_SERVICE_BIT_7 = ( 1 << 7 )
2016-04-09 03:02:24 +02:00
2017-02-15 18:21:22 +01:00
logger = logging . getLogger ( " TestFramework.mininode " )
2015-04-30 22:40:22 +02:00
# Keep our own socket map for asyncore, so that we can track disconnects
2016-07-12 22:04:38 +02:00
# ourselves (to workaround an issue with closing an asyncore socket when
2015-04-30 22:40:22 +02:00
# using select)
mininode_socket_map = dict ( )
2015-05-01 20:47:21 +02:00
# One lock for synchronizing all data access between the networking thread (see
# NetworkThread below) and the thread running the test logic. For simplicity,
2017-06-20 00:57:31 +02:00
# NodeConn acquires this lock whenever delivering a message to a NodeConnCB,
2015-05-01 20:47:21 +02:00
# and whenever adding anything to the send buffer (in send_message()). This
# lock should be acquired in the thread running the test logic to synchronize
# access to any data shared with the NodeConnCB or NodeConn.
mininode_lock = RLock ( )
2015-04-28 18:36:15 +02:00
# Serialization/deserialization tools
def sha256 ( s ) :
return hashlib . new ( ' sha256 ' , s ) . digest ( )
2016-04-09 03:02:24 +02:00
def ripemd160 ( s ) :
return hashlib . new ( ' ripemd160 ' , s ) . digest ( )
2015-04-28 18:36:15 +02:00
def hash256 ( s ) :
return sha256 ( sha256 ( s ) )
2016-06-18 03:17:25 +02:00
def ser_compact_size ( l ) :
r = b " "
if l < 253 :
r = struct . pack ( " B " , l )
elif l < 0x10000 :
r = struct . pack ( " <BH " , 253 , l )
elif l < 0x100000000 :
r = struct . pack ( " <BI " , 254 , l )
else :
r = struct . pack ( " <BQ " , 255 , l )
return r
2015-04-28 18:36:15 +02:00
2016-06-18 03:17:25 +02:00
def deser_compact_size ( f ) :
2015-04-28 18:36:15 +02:00
nit = struct . unpack ( " <B " , f . read ( 1 ) ) [ 0 ]
if nit == 253 :
nit = struct . unpack ( " <H " , f . read ( 2 ) ) [ 0 ]
elif nit == 254 :
nit = struct . unpack ( " <I " , f . read ( 4 ) ) [ 0 ]
elif nit == 255 :
nit = struct . unpack ( " <Q " , f . read ( 8 ) ) [ 0 ]
2016-06-18 03:17:25 +02:00
return nit
def deser_string ( f ) :
nit = deser_compact_size ( f )
2015-04-28 18:36:15 +02:00
return f . read ( nit )
def ser_string ( s ) :
2016-06-18 03:17:25 +02:00
return ser_compact_size ( len ( s ) ) + s
2015-04-28 18:36:15 +02:00
def deser_uint256 ( f ) :
2016-03-19 20:58:06 +01:00
r = 0
for i in range ( 8 ) :
2015-04-28 18:36:15 +02:00
t = struct . unpack ( " <I " , f . read ( 4 ) ) [ 0 ]
r + = t << ( i * 32 )
return r
def ser_uint256 ( u ) :
2016-04-23 14:35:52 +02:00
rs = b " "
2016-03-19 20:58:06 +01:00
for i in range ( 8 ) :
rs + = struct . pack ( " <I " , u & 0xFFFFFFFF )
2015-04-28 18:36:15 +02:00
u >> = 32
return rs
def uint256_from_str ( s ) :
2016-03-19 20:58:06 +01:00
r = 0
2015-04-28 18:36:15 +02:00
t = struct . unpack ( " <IIIIIIII " , s [ : 32 ] )
2016-03-19 20:58:06 +01:00
for i in range ( 8 ) :
2015-04-28 18:36:15 +02:00
r + = t [ i ] << ( i * 32 )
return r
def uint256_from_compact ( c ) :
nbytes = ( c >> 24 ) & 0xFF
2016-03-19 20:58:06 +01:00
v = ( c & 0xFFFFFF ) << ( 8 * ( nbytes - 3 ) )
2015-04-28 18:36:15 +02:00
return v
def deser_vector ( f , c ) :
2016-06-18 03:17:25 +02:00
nit = deser_compact_size ( f )
2015-04-28 18:36:15 +02:00
r = [ ]
2016-03-19 20:58:06 +01:00
for i in range ( nit ) :
2015-04-28 18:36:15 +02:00
t = c ( )
t . deserialize ( f )
r . append ( t )
return r
2016-04-09 03:02:24 +02:00
# ser_function_name: Allow for an alternate serialization function on the
# entries in the vector (we use this for serializing the vector of transactions
# for a witness block).
def ser_vector ( l , ser_function_name = None ) :
2016-06-18 03:17:25 +02:00
r = ser_compact_size ( len ( l ) )
2015-04-28 18:36:15 +02:00
for i in l :
2016-04-09 03:02:24 +02:00
if ser_function_name :
r + = getattr ( i , ser_function_name ) ( )
else :
r + = i . serialize ( )
2015-04-28 18:36:15 +02:00
return r
def deser_uint256_vector ( f ) :
2016-06-18 03:17:25 +02:00
nit = deser_compact_size ( f )
2015-04-28 18:36:15 +02:00
r = [ ]
2016-03-19 20:58:06 +01:00
for i in range ( nit ) :
2015-04-28 18:36:15 +02:00
t = deser_uint256 ( f )
r . append ( t )
return r
def ser_uint256_vector ( l ) :
2016-06-18 03:17:25 +02:00
r = ser_compact_size ( len ( l ) )
2015-04-28 18:36:15 +02:00
for i in l :
r + = ser_uint256 ( i )
return r
def deser_string_vector ( f ) :
2016-06-18 03:17:25 +02:00
nit = deser_compact_size ( f )
2015-04-28 18:36:15 +02:00
r = [ ]
2016-03-19 20:58:06 +01:00
for i in range ( nit ) :
2015-04-28 18:36:15 +02:00
t = deser_string ( f )
r . append ( t )
return r
def ser_string_vector ( l ) :
2016-06-18 03:17:25 +02:00
r = ser_compact_size ( len ( l ) )
2015-04-28 18:36:15 +02:00
for sv in l :
r + = ser_string ( sv )
return r
def deser_int_vector ( f ) :
2016-06-18 03:17:25 +02:00
nit = deser_compact_size ( f )
2015-04-28 18:36:15 +02:00
r = [ ]
2016-03-19 20:58:06 +01:00
for i in range ( nit ) :
2015-04-28 18:36:15 +02:00
t = struct . unpack ( " <i " , f . read ( 4 ) ) [ 0 ]
r . append ( t )
return r
def ser_int_vector ( l ) :
2016-06-18 03:17:25 +02:00
r = ser_compact_size ( len ( l ) )
2015-04-28 18:36:15 +02:00
for i in l :
r + = struct . pack ( " <i " , i )
return r
2015-12-08 23:25:28 +01:00
# Deserialize from a hex string representation (eg from RPC)
def FromHex ( obj , hex_string ) :
2016-04-09 03:02:24 +02:00
obj . deserialize ( BytesIO ( hex_str_to_bytes ( hex_string ) ) )
2015-12-08 23:25:28 +01:00
return obj
# Convert a binary-serializable object to hex (eg for submission via RPC)
def ToHex ( obj ) :
2016-04-09 03:02:24 +02:00
return bytes_to_hex_str ( obj . serialize ( ) )
2015-04-28 18:36:15 +02:00
# Objects that map to bitcoind objects, which can be serialized/deserialized
2017-10-17 03:46:23 +02:00
class CAddress ( ) :
2015-04-28 18:36:15 +02:00
def __init__ ( self ) :
self . nServices = 1
2016-04-10 16:54:28 +02:00
self . pchReserved = b " \x00 " * 10 + b " \xff " * 2
2015-04-28 18:36:15 +02:00
self . ip = " 0.0.0.0 "
self . port = 0
def deserialize ( self , f ) :
self . nServices = struct . unpack ( " <Q " , f . read ( 8 ) ) [ 0 ]
self . pchReserved = f . read ( 12 )
self . ip = socket . inet_ntoa ( f . read ( 4 ) )
self . port = struct . unpack ( " >H " , f . read ( 2 ) ) [ 0 ]
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = struct . pack ( " <Q " , self . nServices )
r + = self . pchReserved
r + = socket . inet_aton ( self . ip )
r + = struct . pack ( " >H " , self . port )
return r
def __repr__ ( self ) :
return " CAddress(nServices= %i ip= %s port= %i ) " % ( self . nServices ,
self . ip , self . port )
2016-04-09 03:02:24 +02:00
MSG_WITNESS_FLAG = 1 << 30
2015-04-28 18:36:15 +02:00
2017-10-17 03:46:23 +02:00
class CInv ( ) :
2015-04-28 18:36:15 +02:00
typemap = {
0 : " Error " ,
1 : " TX " ,
2016-04-09 03:02:24 +02:00
2 : " Block " ,
1 | MSG_WITNESS_FLAG : " WitnessTx " ,
2016-07-12 22:04:38 +02:00
2 | MSG_WITNESS_FLAG : " WitnessBlock " ,
4 : " CompactBlock "
2016-04-09 03:02:24 +02:00
}
2015-04-28 18:36:15 +02:00
2016-03-19 20:58:06 +01:00
def __init__ ( self , t = 0 , h = 0 ) :
2015-04-28 18:36:15 +02:00
self . type = t
self . hash = h
def deserialize ( self , f ) :
self . type = struct . unpack ( " <i " , f . read ( 4 ) ) [ 0 ]
self . hash = deser_uint256 ( f )
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = struct . pack ( " <i " , self . type )
r + = ser_uint256 ( self . hash )
return r
def __repr__ ( self ) :
return " CInv(type= %s hash= %064x ) " \
% ( self . typemap [ self . type ] , self . hash )
2017-10-17 03:46:23 +02:00
class CBlockLocator ( ) :
2015-04-28 18:36:15 +02:00
def __init__ ( self ) :
self . nVersion = MY_VERSION
self . vHave = [ ]
def deserialize ( self , f ) :
self . nVersion = struct . unpack ( " <i " , f . read ( 4 ) ) [ 0 ]
self . vHave = deser_uint256_vector ( f )
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = struct . pack ( " <i " , self . nVersion )
r + = ser_uint256_vector ( self . vHave )
return r
def __repr__ ( self ) :
return " CBlockLocator(nVersion= %i vHave= %s ) " \
% ( self . nVersion , repr ( self . vHave ) )
2017-10-17 03:46:23 +02:00
class COutPoint ( ) :
2015-04-28 18:36:15 +02:00
def __init__ ( self , hash = 0 , n = 0 ) :
self . hash = hash
self . n = n
def deserialize ( self , f ) :
self . hash = deser_uint256 ( f )
self . n = struct . unpack ( " <I " , f . read ( 4 ) ) [ 0 ]
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = ser_uint256 ( self . hash )
r + = struct . pack ( " <I " , self . n )
return r
def __repr__ ( self ) :
return " COutPoint(hash= %064x n= %i ) " % ( self . hash , self . n )
2017-10-17 03:46:23 +02:00
class CTxIn ( ) :
2016-04-10 16:54:28 +02:00
def __init__ ( self , outpoint = None , scriptSig = b " " , nSequence = 0 ) :
2015-04-28 18:36:15 +02:00
if outpoint is None :
self . prevout = COutPoint ( )
else :
self . prevout = outpoint
self . scriptSig = scriptSig
self . nSequence = nSequence
def deserialize ( self , f ) :
self . prevout = COutPoint ( )
self . prevout . deserialize ( f )
self . scriptSig = deser_string ( f )
self . nSequence = struct . unpack ( " <I " , f . read ( 4 ) ) [ 0 ]
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = self . prevout . serialize ( )
r + = ser_string ( self . scriptSig )
r + = struct . pack ( " <I " , self . nSequence )
return r
def __repr__ ( self ) :
return " CTxIn(prevout= %s scriptSig= %s nSequence= %i ) " \
2016-04-09 03:02:24 +02:00
% ( repr ( self . prevout ) , bytes_to_hex_str ( self . scriptSig ) ,
2015-04-28 18:36:15 +02:00
self . nSequence )
2017-10-17 03:46:23 +02:00
class CTxOut ( ) :
2016-04-10 16:54:28 +02:00
def __init__ ( self , nValue = 0 , scriptPubKey = b " " ) :
2015-04-28 18:36:15 +02:00
self . nValue = nValue
self . scriptPubKey = scriptPubKey
def deserialize ( self , f ) :
self . nValue = struct . unpack ( " <q " , f . read ( 8 ) ) [ 0 ]
self . scriptPubKey = deser_string ( f )
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = struct . pack ( " <q " , self . nValue )
r + = ser_string ( self . scriptPubKey )
return r
def __repr__ ( self ) :
return " CTxOut(nValue= %i . %08i scriptPubKey= %s ) " \
2015-12-22 10:43:46 +01:00
% ( self . nValue / / COIN , self . nValue % COIN ,
2016-04-09 03:02:24 +02:00
bytes_to_hex_str ( self . scriptPubKey ) )
2017-10-17 03:46:23 +02:00
class CScriptWitness ( ) :
2016-04-09 03:02:24 +02:00
def __init__ ( self ) :
# stack is a vector of strings
self . stack = [ ]
def __repr__ ( self ) :
return " CScriptWitness( %s ) " % \
( " , " . join ( [ bytes_to_hex_str ( x ) for x in self . stack ] ) )
def is_null ( self ) :
if self . stack :
return False
return True
2017-10-17 03:46:23 +02:00
class CTxInWitness ( ) :
2016-04-09 03:02:24 +02:00
def __init__ ( self ) :
self . scriptWitness = CScriptWitness ( )
def deserialize ( self , f ) :
self . scriptWitness . stack = deser_string_vector ( f )
def serialize ( self ) :
return ser_string_vector ( self . scriptWitness . stack )
def __repr__ ( self ) :
return repr ( self . scriptWitness )
def is_null ( self ) :
return self . scriptWitness . is_null ( )
2017-10-17 03:46:23 +02:00
class CTxWitness ( ) :
2016-04-09 03:02:24 +02:00
def __init__ ( self ) :
self . vtxinwit = [ ]
def deserialize ( self , f ) :
for i in range ( len ( self . vtxinwit ) ) :
self . vtxinwit [ i ] . deserialize ( f )
def serialize ( self ) :
r = b " "
# This is different than the usual vector serialization --
# we omit the length of the vector, which is required to be
# the same length as the transaction's vin vector.
for x in self . vtxinwit :
r + = x . serialize ( )
return r
def __repr__ ( self ) :
return " CTxWitness( %s ) " % \
( ' ; ' . join ( [ repr ( x ) for x in self . vtxinwit ] ) )
def is_null ( self ) :
for x in self . vtxinwit :
if not x . is_null ( ) :
return False
return True
2015-04-28 18:36:15 +02:00
2017-10-17 03:46:23 +02:00
class CTransaction ( ) :
2015-04-28 18:36:15 +02:00
def __init__ ( self , tx = None ) :
if tx is None :
self . nVersion = 1
self . vin = [ ]
self . vout = [ ]
2016-04-09 03:02:24 +02:00
self . wit = CTxWitness ( )
2015-04-28 18:36:15 +02:00
self . nLockTime = 0
self . sha256 = None
self . hash = None
else :
self . nVersion = tx . nVersion
self . vin = copy . deepcopy ( tx . vin )
self . vout = copy . deepcopy ( tx . vout )
self . nLockTime = tx . nLockTime
2016-04-09 03:02:24 +02:00
self . sha256 = tx . sha256
self . hash = tx . hash
self . wit = copy . deepcopy ( tx . wit )
2015-04-28 18:36:15 +02:00
def deserialize ( self , f ) :
self . nVersion = struct . unpack ( " <i " , f . read ( 4 ) ) [ 0 ]
self . vin = deser_vector ( f , CTxIn )
2016-04-09 03:02:24 +02:00
flags = 0
if len ( self . vin ) == 0 :
flags = struct . unpack ( " <B " , f . read ( 1 ) ) [ 0 ]
# Not sure why flags can't be zero, but this
# matches the implementation in bitcoind
if ( flags != 0 ) :
self . vin = deser_vector ( f , CTxIn )
self . vout = deser_vector ( f , CTxOut )
else :
self . vout = deser_vector ( f , CTxOut )
if flags != 0 :
2016-09-18 04:11:00 +02:00
self . wit . vtxinwit = [ CTxInWitness ( ) for i in range ( len ( self . vin ) ) ]
2016-04-09 03:02:24 +02:00
self . wit . deserialize ( f )
2015-04-28 18:36:15 +02:00
self . nLockTime = struct . unpack ( " <I " , f . read ( 4 ) ) [ 0 ]
self . sha256 = None
self . hash = None
2016-04-09 03:02:24 +02:00
def serialize_without_witness ( self ) :
r = b " "
r + = struct . pack ( " <i " , self . nVersion )
r + = ser_vector ( self . vin )
r + = ser_vector ( self . vout )
r + = struct . pack ( " <I " , self . nLockTime )
return r
# Only serialize with witness when explicitly called for
def serialize_with_witness ( self ) :
flags = 0
if not self . wit . is_null ( ) :
flags | = 1
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = struct . pack ( " <i " , self . nVersion )
2016-04-09 03:02:24 +02:00
if flags :
dummy = [ ]
r + = ser_vector ( dummy )
r + = struct . pack ( " <B " , flags )
2015-04-28 18:36:15 +02:00
r + = ser_vector ( self . vin )
r + = ser_vector ( self . vout )
2016-04-09 03:02:24 +02:00
if flags & 1 :
if ( len ( self . wit . vtxinwit ) != len ( self . vin ) ) :
# vtxinwit must have the same length as vin
self . wit . vtxinwit = self . wit . vtxinwit [ : len ( self . vin ) ]
for i in range ( len ( self . wit . vtxinwit ) , len ( self . vin ) ) :
2016-07-07 01:46:46 +02:00
self . wit . vtxinwit . append ( CTxInWitness ( ) )
2016-04-09 03:02:24 +02:00
r + = self . wit . serialize ( )
2015-04-28 18:36:15 +02:00
r + = struct . pack ( " <I " , self . nLockTime )
return r
2016-04-09 03:02:24 +02:00
# Regular serialization is without witness -- must explicitly
# call serialize_with_witness to include witness data.
def serialize ( self ) :
return self . serialize_without_witness ( )
# Recalculate the txid (transaction hash without witness)
2015-04-28 18:36:15 +02:00
def rehash ( self ) :
self . sha256 = None
self . calc_sha256 ( )
2016-04-09 03:02:24 +02:00
# We will only cache the serialization without witness in
# self.sha256 and self.hash -- those are expected to be the txid.
def calc_sha256 ( self , with_witness = False ) :
if with_witness :
# Don't cache the result, just return it
return uint256_from_str ( hash256 ( self . serialize_with_witness ( ) ) )
2015-04-28 18:36:15 +02:00
if self . sha256 is None :
2016-04-09 03:02:24 +02:00
self . sha256 = uint256_from_str ( hash256 ( self . serialize_without_witness ( ) ) )
2016-04-10 16:54:28 +02:00
self . hash = encode ( hash256 ( self . serialize ( ) ) [ : : - 1 ] , ' hex_codec ' ) . decode ( ' ascii ' )
2015-04-28 18:36:15 +02:00
def is_valid ( self ) :
self . calc_sha256 ( )
for tout in self . vout :
2015-12-22 10:43:46 +01:00
if tout . nValue < 0 or tout . nValue > 21000000 * COIN :
2015-04-28 18:36:15 +02:00
return False
return True
def __repr__ ( self ) :
2016-09-18 04:11:00 +02:00
return " CTransaction(nVersion= %i vin= %s vout= %s wit= %s nLockTime= %i ) " \
% ( self . nVersion , repr ( self . vin ) , repr ( self . vout ) , repr ( self . wit ) , self . nLockTime )
2015-04-28 18:36:15 +02:00
2017-10-17 03:46:23 +02:00
class CBlockHeader ( ) :
2015-04-28 18:36:15 +02:00
def __init__ ( self , header = None ) :
if header is None :
self . set_null ( )
else :
self . nVersion = header . nVersion
self . hashPrevBlock = header . hashPrevBlock
self . hashMerkleRoot = header . hashMerkleRoot
self . nTime = header . nTime
self . nBits = header . nBits
self . nNonce = header . nNonce
self . sha256 = header . sha256
self . hash = header . hash
self . calc_sha256 ( )
def set_null ( self ) :
self . nVersion = 1
self . hashPrevBlock = 0
self . hashMerkleRoot = 0
self . nTime = 0
self . nBits = 0
self . nNonce = 0
self . sha256 = None
self . hash = None
def deserialize ( self , f ) :
self . nVersion = struct . unpack ( " <i " , f . read ( 4 ) ) [ 0 ]
self . hashPrevBlock = deser_uint256 ( f )
self . hashMerkleRoot = deser_uint256 ( f )
self . nTime = struct . unpack ( " <I " , f . read ( 4 ) ) [ 0 ]
self . nBits = struct . unpack ( " <I " , f . read ( 4 ) ) [ 0 ]
self . nNonce = struct . unpack ( " <I " , f . read ( 4 ) ) [ 0 ]
self . sha256 = None
self . hash = None
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = struct . pack ( " <i " , self . nVersion )
r + = ser_uint256 ( self . hashPrevBlock )
r + = ser_uint256 ( self . hashMerkleRoot )
r + = struct . pack ( " <I " , self . nTime )
r + = struct . pack ( " <I " , self . nBits )
r + = struct . pack ( " <I " , self . nNonce )
return r
def calc_sha256 ( self ) :
if self . sha256 is None :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = struct . pack ( " <i " , self . nVersion )
r + = ser_uint256 ( self . hashPrevBlock )
r + = ser_uint256 ( self . hashMerkleRoot )
r + = struct . pack ( " <I " , self . nTime )
r + = struct . pack ( " <I " , self . nBits )
r + = struct . pack ( " <I " , self . nNonce )
self . sha256 = uint256_from_str ( hash256 ( r ) )
2016-04-10 16:54:28 +02:00
self . hash = encode ( hash256 ( r ) [ : : - 1 ] , ' hex_codec ' ) . decode ( ' ascii ' )
2015-04-28 18:36:15 +02:00
def rehash ( self ) :
self . sha256 = None
self . calc_sha256 ( )
return self . sha256
def __repr__ ( self ) :
return " CBlockHeader(nVersion= %i hashPrevBlock= %064x hashMerkleRoot= %064x nTime= %s nBits= %08x nNonce= %08x ) " \
% ( self . nVersion , self . hashPrevBlock , self . hashMerkleRoot ,
time . ctime ( self . nTime ) , self . nBits , self . nNonce )
class CBlock ( CBlockHeader ) :
def __init__ ( self , header = None ) :
super ( CBlock , self ) . __init__ ( header )
self . vtx = [ ]
def deserialize ( self , f ) :
super ( CBlock , self ) . deserialize ( f )
self . vtx = deser_vector ( f , CTransaction )
2016-04-09 03:02:24 +02:00
def serialize ( self , with_witness = False ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = super ( CBlock , self ) . serialize ( )
2016-04-09 03:02:24 +02:00
if with_witness :
r + = ser_vector ( self . vtx , " serialize_with_witness " )
else :
r + = ser_vector ( self . vtx )
2015-04-28 18:36:15 +02:00
return r
2016-04-09 03:02:24 +02:00
# Calculate the merkle root given a vector of transaction hashes
2017-04-17 18:23:44 +02:00
@classmethod
def get_merkle_root ( cls , hashes ) :
2015-04-28 18:36:15 +02:00
while len ( hashes ) > 1 :
newhashes = [ ]
2016-03-19 20:58:06 +01:00
for i in range ( 0 , len ( hashes ) , 2 ) :
2015-04-28 18:36:15 +02:00
i2 = min ( i + 1 , len ( hashes ) - 1 )
newhashes . append ( hash256 ( hashes [ i ] + hashes [ i2 ] ) )
hashes = newhashes
return uint256_from_str ( hashes [ 0 ] )
2016-04-09 03:02:24 +02:00
def calc_merkle_root ( self ) :
hashes = [ ]
for tx in self . vtx :
tx . calc_sha256 ( )
hashes . append ( ser_uint256 ( tx . sha256 ) )
return self . get_merkle_root ( hashes )
def calc_witness_merkle_root ( self ) :
# For witness root purposes, the hash of the
# coinbase, with witness, is defined to be 0...0
hashes = [ ser_uint256 ( 0 ) ]
for tx in self . vtx [ 1 : ] :
# Calculate the hashes with witness data
hashes . append ( ser_uint256 ( tx . calc_sha256 ( True ) ) )
return self . get_merkle_root ( hashes )
2015-04-28 18:36:15 +02:00
def is_valid ( self ) :
self . calc_sha256 ( )
target = uint256_from_compact ( self . nBits )
if self . sha256 > target :
return False
for tx in self . vtx :
if not tx . is_valid ( ) :
return False
if self . calc_merkle_root ( ) != self . hashMerkleRoot :
return False
return True
def solve ( self ) :
2016-02-04 20:36:11 +01:00
self . rehash ( )
2015-04-28 18:36:15 +02:00
target = uint256_from_compact ( self . nBits )
while self . sha256 > target :
self . nNonce + = 1
self . rehash ( )
def __repr__ ( self ) :
return " CBlock(nVersion= %i hashPrevBlock= %064x hashMerkleRoot= %064x nTime= %s nBits= %08x nNonce= %08x vtx= %s ) " \
% ( self . nVersion , self . hashPrevBlock , self . hashMerkleRoot ,
time . ctime ( self . nTime ) , self . nBits , self . nNonce , repr ( self . vtx ) )
2017-10-17 03:46:23 +02:00
class PrefilledTransaction ( ) :
2016-07-12 22:04:38 +02:00
def __init__ ( self , index = 0 , tx = None ) :
self . index = index
self . tx = tx
def deserialize ( self , f ) :
self . index = deser_compact_size ( f )
self . tx = CTransaction ( )
self . tx . deserialize ( f )
def serialize ( self , with_witness = False ) :
r = b " "
r + = ser_compact_size ( self . index )
if with_witness :
r + = self . tx . serialize_with_witness ( )
else :
r + = self . tx . serialize_without_witness ( )
return r
2016-09-15 03:00:29 +02:00
def serialize_with_witness ( self ) :
return self . serialize ( with_witness = True )
2016-07-12 22:04:38 +02:00
def __repr__ ( self ) :
return " PrefilledTransaction(index= %d , tx= %s ) " % ( self . index , repr ( self . tx ) )
# This is what we send on the wire, in a cmpctblock message.
2017-10-17 03:46:23 +02:00
class P2PHeaderAndShortIDs ( ) :
2016-07-12 22:04:38 +02:00
def __init__ ( self ) :
self . header = CBlockHeader ( )
self . nonce = 0
self . shortids_length = 0
self . shortids = [ ]
self . prefilled_txn_length = 0
self . prefilled_txn = [ ]
def deserialize ( self , f ) :
self . header . deserialize ( f )
self . nonce = struct . unpack ( " <Q " , f . read ( 8 ) ) [ 0 ]
self . shortids_length = deser_compact_size ( f )
for i in range ( self . shortids_length ) :
# shortids are defined to be 6 bytes in the spec, so append
# two zero bytes and read it in as an 8-byte number
self . shortids . append ( struct . unpack ( " <Q " , f . read ( 6 ) + b ' \x00 \x00 ' ) [ 0 ] )
self . prefilled_txn = deser_vector ( f , PrefilledTransaction )
self . prefilled_txn_length = len ( self . prefilled_txn )
2016-09-15 03:00:29 +02:00
# When using version 2 compact blocks, we must serialize with_witness.
2016-07-12 22:04:38 +02:00
def serialize ( self , with_witness = False ) :
r = b " "
r + = self . header . serialize ( )
r + = struct . pack ( " <Q " , self . nonce )
r + = ser_compact_size ( self . shortids_length )
for x in self . shortids :
# We only want the first 6 bytes
r + = struct . pack ( " <Q " , x ) [ 0 : 6 ]
2016-09-15 03:00:29 +02:00
if with_witness :
r + = ser_vector ( self . prefilled_txn , " serialize_with_witness " )
else :
r + = ser_vector ( self . prefilled_txn )
2016-07-12 22:04:38 +02:00
return r
def __repr__ ( self ) :
return " P2PHeaderAndShortIDs(header= %s , nonce= %d , shortids_length= %d , shortids= %s , prefilled_txn_length= %d , prefilledtxn= %s " % ( repr ( self . header ) , self . nonce , self . shortids_length , repr ( self . shortids ) , self . prefilled_txn_length , repr ( self . prefilled_txn ) )
2016-09-15 03:00:29 +02:00
# P2P version of the above that will use witness serialization (for compact
# block version 2)
class P2PHeaderAndShortWitnessIDs ( P2PHeaderAndShortIDs ) :
def serialize ( self ) :
return super ( P2PHeaderAndShortWitnessIDs , self ) . serialize ( with_witness = True )
2016-07-12 22:04:38 +02:00
# Calculate the BIP 152-compact blocks shortid for a given transaction hash
def calculate_shortid ( k0 , k1 , tx_hash ) :
expected_shortid = siphash256 ( k0 , k1 , tx_hash )
expected_shortid & = 0x0000ffffffffffff
return expected_shortid
# This version gets rid of the array lengths, and reinterprets the differential
# encoding into indices that can be used for lookup.
2017-10-17 03:46:23 +02:00
class HeaderAndShortIDs ( ) :
2016-07-12 22:04:38 +02:00
def __init__ ( self , p2pheaders_and_shortids = None ) :
self . header = CBlockHeader ( )
self . nonce = 0
self . shortids = [ ]
self . prefilled_txn = [ ]
2016-09-15 03:00:29 +02:00
self . use_witness = False
2016-07-12 22:04:38 +02:00
if p2pheaders_and_shortids != None :
self . header = p2pheaders_and_shortids . header
self . nonce = p2pheaders_and_shortids . nonce
self . shortids = p2pheaders_and_shortids . shortids
last_index = - 1
for x in p2pheaders_and_shortids . prefilled_txn :
self . prefilled_txn . append ( PrefilledTransaction ( x . index + last_index + 1 , x . tx ) )
last_index = self . prefilled_txn [ - 1 ] . index
def to_p2p ( self ) :
2016-09-15 03:00:29 +02:00
if self . use_witness :
ret = P2PHeaderAndShortWitnessIDs ( )
else :
ret = P2PHeaderAndShortIDs ( )
2016-07-12 22:04:38 +02:00
ret . header = self . header
ret . nonce = self . nonce
ret . shortids_length = len ( self . shortids )
ret . shortids = self . shortids
ret . prefilled_txn_length = len ( self . prefilled_txn )
ret . prefilled_txn = [ ]
last_index = - 1
for x in self . prefilled_txn :
ret . prefilled_txn . append ( PrefilledTransaction ( x . index - last_index - 1 , x . tx ) )
last_index = x . index
return ret
def get_siphash_keys ( self ) :
header_nonce = self . header . serialize ( )
header_nonce + = struct . pack ( " <Q " , self . nonce )
hash_header_nonce_as_str = sha256 ( header_nonce )
key0 = struct . unpack ( " <Q " , hash_header_nonce_as_str [ 0 : 8 ] ) [ 0 ]
key1 = struct . unpack ( " <Q " , hash_header_nonce_as_str [ 8 : 16 ] ) [ 0 ]
return [ key0 , key1 ]
2016-09-15 03:00:29 +02:00
# Version 2 compact blocks use wtxid in shortids (rather than txid)
def initialize_from_block ( self , block , nonce = 0 , prefill_list = [ 0 ] , use_witness = False ) :
2016-07-12 22:04:38 +02:00
self . header = CBlockHeader ( block )
self . nonce = nonce
self . prefilled_txn = [ PrefilledTransaction ( i , block . vtx [ i ] ) for i in prefill_list ]
self . shortids = [ ]
2016-09-15 03:00:29 +02:00
self . use_witness = use_witness
2016-07-12 22:04:38 +02:00
[ k0 , k1 ] = self . get_siphash_keys ( )
for i in range ( len ( block . vtx ) ) :
if i not in prefill_list :
2016-09-15 03:00:29 +02:00
tx_hash = block . vtx [ i ] . sha256
if use_witness :
tx_hash = block . vtx [ i ] . calc_sha256 ( with_witness = True )
self . shortids . append ( calculate_shortid ( k0 , k1 , tx_hash ) )
2016-07-12 22:04:38 +02:00
def __repr__ ( self ) :
return " HeaderAndShortIDs(header= %s , nonce= %d , shortids= %s , prefilledtxn= %s " % ( repr ( self . header ) , self . nonce , repr ( self . shortids ) , repr ( self . prefilled_txn ) )
2017-10-17 03:46:23 +02:00
class BlockTransactionsRequest ( ) :
2016-07-12 22:04:38 +02:00
def __init__ ( self , blockhash = 0 , indexes = None ) :
self . blockhash = blockhash
self . indexes = indexes if indexes != None else [ ]
def deserialize ( self , f ) :
self . blockhash = deser_uint256 ( f )
indexes_length = deser_compact_size ( f )
for i in range ( indexes_length ) :
self . indexes . append ( deser_compact_size ( f ) )
def serialize ( self ) :
r = b " "
r + = ser_uint256 ( self . blockhash )
r + = ser_compact_size ( len ( self . indexes ) )
for x in self . indexes :
r + = ser_compact_size ( x )
return r
# helper to set the differentially encoded indexes from absolute ones
def from_absolute ( self , absolute_indexes ) :
self . indexes = [ ]
last_index = - 1
for x in absolute_indexes :
self . indexes . append ( x - last_index - 1 )
last_index = x
def to_absolute ( self ) :
absolute_indexes = [ ]
last_index = - 1
for x in self . indexes :
absolute_indexes . append ( x + last_index + 1 )
last_index = absolute_indexes [ - 1 ]
return absolute_indexes
def __repr__ ( self ) :
return " BlockTransactionsRequest(hash= %064x indexes= %s ) " % ( self . blockhash , repr ( self . indexes ) )
2017-10-17 03:46:23 +02:00
class BlockTransactions ( ) :
2016-07-12 22:04:38 +02:00
def __init__ ( self , blockhash = 0 , transactions = None ) :
self . blockhash = blockhash
self . transactions = transactions if transactions != None else [ ]
def deserialize ( self , f ) :
self . blockhash = deser_uint256 ( f )
self . transactions = deser_vector ( f , CTransaction )
def serialize ( self , with_witness = False ) :
r = b " "
r + = ser_uint256 ( self . blockhash )
if with_witness :
r + = ser_vector ( self . transactions , " serialize_with_witness " )
else :
r + = ser_vector ( self . transactions )
return r
def __repr__ ( self ) :
return " BlockTransactions(hash= %064x transactions= %s ) " % ( self . blockhash , repr ( self . transactions ) )
2015-04-28 18:36:15 +02:00
# Objects that correspond to messages on the wire
2017-10-17 03:46:23 +02:00
class msg_version ( ) :
2016-04-10 16:54:28 +02:00
command = b " version "
2015-04-28 18:36:15 +02:00
def __init__ ( self ) :
self . nVersion = MY_VERSION
2017-10-12 05:25:18 +02:00
self . nServices = NODE_NETWORK | NODE_WITNESS
2016-03-20 18:18:32 +01:00
self . nTime = int ( time . time ( ) )
2015-04-28 18:36:15 +02:00
self . addrTo = CAddress ( )
self . addrFrom = CAddress ( )
self . nNonce = random . getrandbits ( 64 )
self . strSubVer = MY_SUBVERSION
self . nStartingHeight = - 1
2016-10-05 20:24:36 +02:00
self . nRelay = MY_RELAY
2015-04-28 18:36:15 +02:00
def deserialize ( self , f ) :
self . nVersion = struct . unpack ( " <i " , f . read ( 4 ) ) [ 0 ]
if self . nVersion == 10300 :
self . nVersion = 300
self . nServices = struct . unpack ( " <Q " , f . read ( 8 ) ) [ 0 ]
self . nTime = struct . unpack ( " <q " , f . read ( 8 ) ) [ 0 ]
self . addrTo = CAddress ( )
self . addrTo . deserialize ( f )
2016-10-05 20:24:36 +02:00
2015-04-28 18:36:15 +02:00
if self . nVersion > = 106 :
self . addrFrom = CAddress ( )
self . addrFrom . deserialize ( f )
self . nNonce = struct . unpack ( " <Q " , f . read ( 8 ) ) [ 0 ]
self . strSubVer = deser_string ( f )
else :
self . addrFrom = None
self . nNonce = None
self . strSubVer = None
self . nStartingHeight = None
2016-10-05 20:24:36 +02:00
if self . nVersion > = 209 :
self . nStartingHeight = struct . unpack ( " <i " , f . read ( 4 ) ) [ 0 ]
else :
self . nStartingHeight = None
if self . nVersion > = 70001 :
# Relay field is optional for version 70001 onwards
try :
self . nRelay = struct . unpack ( " <b " , f . read ( 1 ) ) [ 0 ]
except :
self . nRelay = 0
else :
self . nRelay = 0
2015-04-28 18:36:15 +02:00
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = struct . pack ( " <i " , self . nVersion )
r + = struct . pack ( " <Q " , self . nServices )
r + = struct . pack ( " <q " , self . nTime )
r + = self . addrTo . serialize ( )
r + = self . addrFrom . serialize ( )
r + = struct . pack ( " <Q " , self . nNonce )
r + = ser_string ( self . strSubVer )
r + = struct . pack ( " <i " , self . nStartingHeight )
2016-10-05 20:24:36 +02:00
r + = struct . pack ( " <b " , self . nRelay )
2015-04-28 18:36:15 +02:00
return r
def __repr__ ( self ) :
2016-10-05 20:24:36 +02:00
return ' msg_version(nVersion= %i nServices= %i nTime= %s addrTo= %s addrFrom= %s nNonce=0x %016X strSubVer= %s nStartingHeight= %i nRelay= %i ) ' \
2015-04-28 18:36:15 +02:00
% ( self . nVersion , self . nServices , time . ctime ( self . nTime ) ,
repr ( self . addrTo ) , repr ( self . addrFrom ) , self . nNonce ,
2016-10-05 20:24:36 +02:00
self . strSubVer , self . nStartingHeight , self . nRelay )
2015-04-28 18:36:15 +02:00
2017-10-17 03:46:23 +02:00
class msg_verack ( ) :
2016-04-10 16:54:28 +02:00
command = b " verack "
2015-04-28 18:36:15 +02:00
def __init__ ( self ) :
pass
def deserialize ( self , f ) :
pass
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
return b " "
2015-04-28 18:36:15 +02:00
def __repr__ ( self ) :
return " msg_verack() "
2017-10-17 03:46:23 +02:00
class msg_addr ( ) :
2016-04-10 16:54:28 +02:00
command = b " addr "
2015-04-28 18:36:15 +02:00
def __init__ ( self ) :
self . addrs = [ ]
def deserialize ( self , f ) :
self . addrs = deser_vector ( f , CAddress )
def serialize ( self ) :
return ser_vector ( self . addrs )
def __repr__ ( self ) :
return " msg_addr(addrs= %s ) " % ( repr ( self . addrs ) )
2017-10-17 03:46:23 +02:00
class msg_inv ( ) :
2016-04-10 16:54:28 +02:00
command = b " inv "
2015-04-28 18:36:15 +02:00
def __init__ ( self , inv = None ) :
if inv is None :
self . inv = [ ]
else :
self . inv = inv
def deserialize ( self , f ) :
self . inv = deser_vector ( f , CInv )
def serialize ( self ) :
return ser_vector ( self . inv )
def __repr__ ( self ) :
return " msg_inv(inv= %s ) " % ( repr ( self . inv ) )
2017-10-17 03:46:23 +02:00
class msg_getdata ( ) :
2016-04-10 16:54:28 +02:00
command = b " getdata "
2015-04-28 18:36:15 +02:00
2014-11-18 22:16:32 +01:00
def __init__ ( self , inv = None ) :
self . inv = inv if inv != None else [ ]
2015-04-28 18:36:15 +02:00
def deserialize ( self , f ) :
self . inv = deser_vector ( f , CInv )
def serialize ( self ) :
return ser_vector ( self . inv )
def __repr__ ( self ) :
return " msg_getdata(inv= %s ) " % ( repr ( self . inv ) )
2017-10-17 03:46:23 +02:00
class msg_getblocks ( ) :
2016-04-10 16:54:28 +02:00
command = b " getblocks "
2015-04-28 18:36:15 +02:00
def __init__ ( self ) :
self . locator = CBlockLocator ( )
2016-03-19 20:58:06 +01:00
self . hashstop = 0
2015-04-28 18:36:15 +02:00
def deserialize ( self , f ) :
self . locator = CBlockLocator ( )
self . locator . deserialize ( f )
self . hashstop = deser_uint256 ( f )
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = self . locator . serialize ( )
r + = ser_uint256 ( self . hashstop )
return r
def __repr__ ( self ) :
return " msg_getblocks(locator= %s hashstop= %064x ) " \
% ( repr ( self . locator ) , self . hashstop )
2017-10-17 03:46:23 +02:00
class msg_tx ( ) :
2016-04-10 16:54:28 +02:00
command = b " tx "
2015-04-28 18:36:15 +02:00
def __init__ ( self , tx = CTransaction ( ) ) :
self . tx = tx
def deserialize ( self , f ) :
self . tx . deserialize ( f )
def serialize ( self ) :
2016-04-09 03:02:24 +02:00
return self . tx . serialize_without_witness ( )
2015-04-28 18:36:15 +02:00
def __repr__ ( self ) :
return " msg_tx(tx= %s ) " % ( repr ( self . tx ) )
2016-04-09 03:02:24 +02:00
class msg_witness_tx ( msg_tx ) :
def serialize ( self ) :
return self . tx . serialize_with_witness ( )
2015-04-28 18:36:15 +02:00
2017-10-17 03:46:23 +02:00
class msg_block ( ) :
2016-04-10 16:54:28 +02:00
command = b " block "
2015-04-28 18:36:15 +02:00
def __init__ ( self , block = None ) :
if block is None :
self . block = CBlock ( )
else :
self . block = block
def deserialize ( self , f ) :
self . block . deserialize ( f )
def serialize ( self ) :
return self . block . serialize ( )
def __repr__ ( self ) :
return " msg_block(block= %s ) " % ( repr ( self . block ) )
2016-05-31 20:21:40 +02:00
# for cases where a user needs tighter control over what is sent over the wire
# note that the user must supply the name of the command, and the data
2017-10-17 03:46:23 +02:00
class msg_generic ( ) :
2016-05-31 20:21:40 +02:00
def __init__ ( self , command , data = None ) :
self . command = command
self . data = data
def serialize ( self ) :
return self . data
def __repr__ ( self ) :
return " msg_generic() "
2015-04-28 18:36:15 +02:00
2016-04-09 03:02:24 +02:00
class msg_witness_block ( msg_block ) :
def serialize ( self ) :
r = self . block . serialize ( with_witness = True )
return r
2017-10-17 03:46:23 +02:00
class msg_getaddr ( ) :
2016-04-10 16:54:28 +02:00
command = b " getaddr "
2015-04-28 18:36:15 +02:00
def __init__ ( self ) :
pass
def deserialize ( self , f ) :
pass
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
return b " "
2015-04-28 18:36:15 +02:00
def __repr__ ( self ) :
return " msg_getaddr() "
2017-10-17 03:46:23 +02:00
class msg_ping ( ) :
2016-04-10 16:54:28 +02:00
command = b " ping "
2015-04-28 18:36:15 +02:00
2016-03-19 20:58:06 +01:00
def __init__ ( self , nonce = 0 ) :
2015-04-28 18:36:15 +02:00
self . nonce = nonce
def deserialize ( self , f ) :
self . nonce = struct . unpack ( " <Q " , f . read ( 8 ) ) [ 0 ]
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = struct . pack ( " <Q " , self . nonce )
return r
def __repr__ ( self ) :
return " msg_ping(nonce= %08x ) " % self . nonce
2017-10-17 03:46:23 +02:00
class msg_pong ( ) :
2016-04-10 16:54:28 +02:00
command = b " pong "
2015-04-28 18:36:15 +02:00
2016-04-10 16:54:28 +02:00
def __init__ ( self , nonce = 0 ) :
2015-04-28 18:36:15 +02:00
self . nonce = nonce
def deserialize ( self , f ) :
self . nonce = struct . unpack ( " <Q " , f . read ( 8 ) ) [ 0 ]
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = struct . pack ( " <Q " , self . nonce )
return r
def __repr__ ( self ) :
return " msg_pong(nonce= %08x ) " % self . nonce
2017-10-17 03:46:23 +02:00
class msg_mempool ( ) :
2016-04-10 16:54:28 +02:00
command = b " mempool "
2015-04-28 18:36:15 +02:00
def __init__ ( self ) :
pass
def deserialize ( self , f ) :
pass
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
return b " "
2015-04-28 18:36:15 +02:00
def __repr__ ( self ) :
return " msg_mempool() "
2017-10-17 03:46:23 +02:00
class msg_sendheaders ( ) :
2016-04-10 16:54:28 +02:00
command = b " sendheaders "
2014-11-18 22:16:32 +01:00
def __init__ ( self ) :
pass
def deserialize ( self , f ) :
pass
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
return b " "
2014-11-18 22:16:32 +01:00
def __repr__ ( self ) :
return " msg_sendheaders() "
2015-04-28 18:36:15 +02:00
2016-04-09 03:02:24 +02:00
2015-04-28 18:36:15 +02:00
# getheaders message has
# number of entries
# vector of hashes
# hash_stop (hash of last desired block header, 0 to get as many as possible)
2017-10-17 03:46:23 +02:00
class msg_getheaders ( ) :
2016-04-10 16:54:28 +02:00
command = b " getheaders "
2015-04-28 18:36:15 +02:00
def __init__ ( self ) :
self . locator = CBlockLocator ( )
2016-03-19 20:58:06 +01:00
self . hashstop = 0
2015-04-28 18:36:15 +02:00
def deserialize ( self , f ) :
self . locator = CBlockLocator ( )
self . locator . deserialize ( f )
self . hashstop = deser_uint256 ( f )
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2015-04-28 18:36:15 +02:00
r + = self . locator . serialize ( )
r + = ser_uint256 ( self . hashstop )
return r
def __repr__ ( self ) :
return " msg_getheaders(locator= %s , stop= %064x ) " \
% ( repr ( self . locator ) , self . hashstop )
# headers message has
# <count> <vector of block headers>
2017-10-17 03:46:23 +02:00
class msg_headers ( ) :
2016-04-10 16:54:28 +02:00
command = b " headers "
2015-04-28 18:36:15 +02:00
2017-08-25 02:06:42 +02:00
def __init__ ( self , headers = None ) :
self . headers = headers if headers is not None else [ ]
2015-04-28 18:36:15 +02:00
def deserialize ( self , f ) :
# comment in bitcoind indicates these should be deserialized as blocks
blocks = deser_vector ( f , CBlock )
for x in blocks :
self . headers . append ( CBlockHeader ( x ) )
def serialize ( self ) :
blocks = [ CBlock ( x ) for x in self . headers ]
return ser_vector ( blocks )
def __repr__ ( self ) :
return " msg_headers(headers= %s ) " % repr ( self . headers )
2017-10-17 03:46:23 +02:00
class msg_reject ( ) :
2016-04-10 16:54:28 +02:00
command = b " reject "
2016-04-19 22:18:38 +02:00
REJECT_MALFORMED = 1
2015-04-28 18:36:15 +02:00
def __init__ ( self ) :
2016-04-10 16:54:28 +02:00
self . message = b " "
2016-03-20 18:18:32 +01:00
self . code = 0
2016-04-23 14:35:52 +02:00
self . reason = b " "
2016-03-19 20:58:06 +01:00
self . data = 0
2015-04-28 18:36:15 +02:00
def deserialize ( self , f ) :
self . message = deser_string ( f )
self . code = struct . unpack ( " <B " , f . read ( 1 ) ) [ 0 ]
self . reason = deser_string ( f )
2016-04-19 22:18:38 +02:00
if ( self . code != self . REJECT_MALFORMED and
( self . message == b " block " or self . message == b " tx " ) ) :
2015-04-28 18:36:15 +02:00
self . data = deser_uint256 ( f )
def serialize ( self ) :
r = ser_string ( self . message )
r + = struct . pack ( " <B " , self . code )
r + = ser_string ( self . reason )
2016-04-19 22:18:38 +02:00
if ( self . code != self . REJECT_MALFORMED and
( self . message == b " block " or self . message == b " tx " ) ) :
2015-04-28 18:36:15 +02:00
r + = ser_uint256 ( self . data )
return r
def __repr__ ( self ) :
return " msg_reject: %s %d %s [ %064x ] " \
% ( self . message , self . code , self . reason , self . data )
2017-10-17 03:46:23 +02:00
class msg_feefilter ( ) :
2016-04-10 16:54:28 +02:00
command = b " feefilter "
2016-03-04 22:11:49 +01:00
2016-03-19 20:58:06 +01:00
def __init__ ( self , feerate = 0 ) :
2016-03-04 22:11:49 +01:00
self . feerate = feerate
def deserialize ( self , f ) :
self . feerate = struct . unpack ( " <Q " , f . read ( 8 ) ) [ 0 ]
def serialize ( self ) :
2016-04-10 16:54:28 +02:00
r = b " "
2016-03-04 22:11:49 +01:00
r + = struct . pack ( " <Q " , self . feerate )
return r
def __repr__ ( self ) :
return " msg_feefilter(feerate= %08x ) " % self . feerate
2017-10-17 03:46:23 +02:00
class msg_sendcmpct ( ) :
2016-07-12 22:04:38 +02:00
command = b " sendcmpct "
def __init__ ( self ) :
self . announce = False
self . version = 1
def deserialize ( self , f ) :
self . announce = struct . unpack ( " <? " , f . read ( 1 ) ) [ 0 ]
self . version = struct . unpack ( " <Q " , f . read ( 8 ) ) [ 0 ]
def serialize ( self ) :
r = b " "
r + = struct . pack ( " <? " , self . announce )
r + = struct . pack ( " <Q " , self . version )
return r
def __repr__ ( self ) :
return " msg_sendcmpct(announce= %s , version= %lu ) " % ( self . announce , self . version )
2017-10-17 03:46:23 +02:00
class msg_cmpctblock ( ) :
2016-07-12 22:04:38 +02:00
command = b " cmpctblock "
def __init__ ( self , header_and_shortids = None ) :
self . header_and_shortids = header_and_shortids
def deserialize ( self , f ) :
self . header_and_shortids = P2PHeaderAndShortIDs ( )
self . header_and_shortids . deserialize ( f )
def serialize ( self ) :
r = b " "
r + = self . header_and_shortids . serialize ( )
return r
def __repr__ ( self ) :
return " msg_cmpctblock(HeaderAndShortIDs= %s ) " % repr ( self . header_and_shortids )
2017-10-17 03:46:23 +02:00
class msg_getblocktxn ( ) :
2016-07-12 22:04:38 +02:00
command = b " getblocktxn "
def __init__ ( self ) :
self . block_txn_request = None
def deserialize ( self , f ) :
self . block_txn_request = BlockTransactionsRequest ( )
self . block_txn_request . deserialize ( f )
def serialize ( self ) :
r = b " "
r + = self . block_txn_request . serialize ( )
return r
def __repr__ ( self ) :
return " msg_getblocktxn(block_txn_request= %s ) " % ( repr ( self . block_txn_request ) )
2017-10-17 03:46:23 +02:00
class msg_blocktxn ( ) :
2016-07-12 22:04:38 +02:00
command = b " blocktxn "
def __init__ ( self ) :
self . block_transactions = BlockTransactions ( )
def deserialize ( self , f ) :
self . block_transactions . deserialize ( f )
def serialize ( self ) :
r = b " "
r + = self . block_transactions . serialize ( )
return r
def __repr__ ( self ) :
return " msg_blocktxn(block_transactions= %s ) " % ( repr ( self . block_transactions ) )
2016-09-15 03:00:29 +02:00
class msg_witness_blocktxn ( msg_blocktxn ) :
def serialize ( self ) :
r = b " "
r + = self . block_transactions . serialize ( with_witness = True )
return r
2017-10-17 03:46:23 +02:00
class NodeConnCB ( ) :
2017-03-29 20:07:39 +02:00
""" Callback and helper functions for P2P connection to a bitcoind node.
Individual testcases should subclass this and override the on_ * methods
2017-10-17 04:31:18 +02:00
if they want to alter message handling behaviour . """
2015-04-28 18:36:15 +02:00
def __init__ ( self ) :
2017-03-29 20:07:39 +02:00
# Track whether we have a P2P connection open to the node
self . connected = False
self . connection = None
# Track number of messages of each type received and the most recent
# message of each type
self . message_count = defaultdict ( int )
self . last_message = { }
# A count of the number of ping messages we've sent to the node
self . ping_counter = 1
# Message receiving methods
2014-11-18 22:16:32 +01:00
2015-04-28 18:36:15 +02:00
def deliver ( self , conn , message ) :
2017-03-29 20:07:39 +02:00
""" Receive message and dispatch message to appropriate callback.
We keep a count of how many of each message type has been received
2017-10-17 04:31:18 +02:00
and the most recent message of each type . """
2015-05-01 20:47:21 +02:00
with mininode_lock :
2015-04-28 18:36:15 +02:00
try :
2017-03-29 20:07:39 +02:00
command = message . command . decode ( ' ascii ' )
self . message_count [ command ] + = 1
self . last_message [ command ] = message
getattr ( self , ' on_ ' + command ) ( conn , message )
2015-04-28 18:36:15 +02:00
except :
2017-03-29 20:07:39 +02:00
print ( " ERROR delivering %s ( %s ) " % ( repr ( message ) ,
sys . exc_info ( ) [ 0 ] ) )
2017-09-13 15:17:15 +02:00
raise
2015-04-28 18:36:15 +02:00
2017-03-29 20:07:39 +02:00
# Callback methods. Can be overridden by subclasses in individual test
# cases to provide custom message handling behaviour.
def on_open ( self , conn ) :
self . connected = True
def on_close ( self , conn ) :
self . connected = False
self . connection = None
2017-03-28 19:41:22 +02:00
def on_addr ( self , conn , message ) : pass
def on_block ( self , conn , message ) : pass
def on_blocktxn ( self , conn , message ) : pass
def on_cmpctblock ( self , conn , message ) : pass
def on_feefilter ( self , conn , message ) : pass
def on_getaddr ( self , conn , message ) : pass
def on_getblocks ( self , conn , message ) : pass
def on_getblocktxn ( self , conn , message ) : pass
def on_getdata ( self , conn , message ) : pass
def on_getheaders ( self , conn , message ) : pass
def on_headers ( self , conn , message ) : pass
def on_mempool ( self , conn ) : pass
2017-03-29 20:07:39 +02:00
def on_pong ( self , conn , message ) : pass
2017-03-28 19:41:22 +02:00
def on_reject ( self , conn , message ) : pass
def on_sendcmpct ( self , conn , message ) : pass
def on_sendheaders ( self , conn , message ) : pass
def on_tx ( self , conn , message ) : pass
2015-04-28 18:36:15 +02:00
def on_inv ( self , conn , message ) :
want = msg_getdata ( )
for i in message . inv :
if i . type != 0 :
want . inv . append ( i )
if len ( want . inv ) :
conn . send_message ( want )
def on_ping ( self , conn , message ) :
2017-10-17 13:57:37 +02:00
conn . send_message ( msg_pong ( message . nonce ) )
2015-04-28 18:36:15 +02:00
2017-03-28 19:41:22 +02:00
def on_verack ( self , conn , message ) :
conn . ver_recv = conn . ver_send
self . verack_received = True
def on_version ( self , conn , message ) :
2017-10-17 16:59:20 +02:00
assert message . nVersion > = MIN_VERSION_SUPPORTED , " Version {} received. Test framework only supports versions greater than {} " . format ( message . nVersion , MIN_VERSION_SUPPORTED )
conn . send_message ( msg_verack ( ) )
2017-03-28 19:41:22 +02:00
conn . nServices = message . nServices
2017-03-29 20:07:39 +02:00
# Connection helper methods
2016-03-04 21:08:10 +01:00
def add_connection ( self , conn ) :
self . connection = conn
2017-03-29 20:07:39 +02:00
def wait_for_disconnect ( self , timeout = 60 ) :
test_function = lambda : not self . connected
2017-08-16 18:17:34 +02:00
wait_until ( test_function , timeout = timeout , lock = mininode_lock )
2017-03-29 20:07:39 +02:00
# Message receiving helper methods
def wait_for_block ( self , blockhash , timeout = 60 ) :
test_function = lambda : self . last_message . get ( " block " ) and self . last_message [ " block " ] . block . rehash ( ) == blockhash
2017-08-16 18:17:34 +02:00
wait_until ( test_function , timeout = timeout , lock = mininode_lock )
2017-03-29 20:07:39 +02:00
def wait_for_getdata ( self , timeout = 60 ) :
test_function = lambda : self . last_message . get ( " getdata " )
2017-08-16 18:17:34 +02:00
wait_until ( test_function , timeout = timeout , lock = mininode_lock )
2017-03-29 20:07:39 +02:00
def wait_for_getheaders ( self , timeout = 60 ) :
test_function = lambda : self . last_message . get ( " getheaders " )
2017-08-16 18:17:34 +02:00
wait_until ( test_function , timeout = timeout , lock = mininode_lock )
2017-03-29 20:07:39 +02:00
def wait_for_inv ( self , expected_inv , timeout = 60 ) :
2017-05-02 22:34:44 +02:00
""" Waits for an INV message and checks that the first inv object in the message was as expected. """
if len ( expected_inv ) > 1 :
raise NotImplementedError ( " wait_for_inv() will only verify the first inv object " )
test_function = lambda : self . last_message . get ( " inv " ) and \
self . last_message [ " inv " ] . inv [ 0 ] . type == expected_inv [ 0 ] . type and \
self . last_message [ " inv " ] . inv [ 0 ] . hash == expected_inv [ 0 ] . hash
2017-08-16 18:17:34 +02:00
wait_until ( test_function , timeout = timeout , lock = mininode_lock )
2017-03-29 20:07:39 +02:00
def wait_for_verack ( self , timeout = 60 ) :
test_function = lambda : self . message_count [ " verack " ]
2017-08-16 18:17:34 +02:00
wait_until ( test_function , timeout = timeout , lock = mininode_lock )
2017-03-29 20:07:39 +02:00
# Message sending helper functions
2016-03-04 21:08:10 +01:00
def send_message ( self , message ) :
2017-03-29 20:07:39 +02:00
if self . connection :
self . connection . send_message ( message )
else :
logger . error ( " Cannot send message. No connection to node! " )
2016-03-04 21:08:10 +01:00
2016-07-12 22:04:38 +02:00
def send_and_ping ( self , message ) :
self . send_message ( message )
self . sync_with_ping ( )
2016-03-04 21:08:10 +01:00
# Sync up with the node
2017-03-29 17:37:00 +02:00
def sync_with_ping ( self , timeout = 60 ) :
2016-03-04 21:08:10 +01:00
self . send_message ( msg_ping ( nonce = self . ping_counter ) )
2017-03-29 20:07:39 +02:00
test_function = lambda : self . last_message . get ( " pong " ) and self . last_message [ " pong " ] . nonce == self . ping_counter
2017-08-16 18:17:34 +02:00
wait_until ( test_function , timeout = timeout , lock = mininode_lock )
2016-03-04 21:08:10 +01:00
self . ping_counter + = 1
2017-03-28 19:41:22 +02:00
2015-04-28 18:36:15 +02:00
class NodeConn ( asyncore . dispatcher ) :
2017-10-17 04:31:18 +02:00
""" The actual NodeConn class
This class provides an interface for a p2p connection to a specified node . """
2015-04-28 18:36:15 +02:00
messagemap = {
2016-04-10 16:54:28 +02:00
b " version " : msg_version ,
b " verack " : msg_verack ,
b " addr " : msg_addr ,
b " inv " : msg_inv ,
b " getdata " : msg_getdata ,
b " getblocks " : msg_getblocks ,
b " tx " : msg_tx ,
b " block " : msg_block ,
b " getaddr " : msg_getaddr ,
b " ping " : msg_ping ,
b " pong " : msg_pong ,
b " headers " : msg_headers ,
b " getheaders " : msg_getheaders ,
b " reject " : msg_reject ,
b " mempool " : msg_mempool ,
2016-04-09 03:02:24 +02:00
b " feefilter " : msg_feefilter ,
2016-07-12 22:04:38 +02:00
b " sendheaders " : msg_sendheaders ,
b " sendcmpct " : msg_sendcmpct ,
b " cmpctblock " : msg_cmpctblock ,
b " getblocktxn " : msg_getblocktxn ,
b " blocktxn " : msg_blocktxn
2015-04-28 18:36:15 +02:00
}
MAGIC_BYTES = {
2016-04-10 16:54:28 +02:00
" mainnet " : b " \xf9 \xbe \xb4 \xd9 " , # mainnet
" testnet3 " : b " \x0b \x11 \x09 \x07 " , # testnet3
2016-04-09 03:02:24 +02:00
" regtest " : b " \xfa \xbf \xb5 \xda " , # regtest
2015-04-28 18:36:15 +02:00
}
2017-10-12 05:25:18 +02:00
def __init__ ( self , dstaddr , dstport , rpc , callback , net = " regtest " , services = NODE_NETWORK | NODE_WITNESS , send_version = True ) :
2015-04-30 22:40:22 +02:00
asyncore . dispatcher . __init__ ( self , map = mininode_socket_map )
2015-04-28 18:36:15 +02:00
self . dstaddr = dstaddr
self . dstport = dstport
self . create_socket ( socket . AF_INET , socket . SOCK_STREAM )
2017-09-13 19:24:38 +02:00
self . socket . setsockopt ( socket . IPPROTO_TCP , socket . TCP_NODELAY , 1 )
2016-04-10 16:54:28 +02:00
self . sendbuf = b " "
self . recvbuf = b " "
2015-04-28 18:36:15 +02:00
self . ver_send = 209
self . ver_recv = 209
self . last_sent = 0
self . state = " connecting "
self . network = net
self . cb = callback
self . disconnect = False
2016-04-09 03:02:24 +02:00
self . nServices = 0
2015-04-28 18:36:15 +02:00
2017-02-07 23:35:57 +01:00
if send_version :
# 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 "
vt . addrFrom . port = 0
self . send_message ( vt , True )
2017-02-15 18:21:22 +01:00
logger . info ( ' Connecting to Bitcoin Node: %s : %d ' % ( self . dstaddr , self . dstport ) )
2015-04-28 18:36:15 +02:00
try :
self . connect ( ( dstaddr , dstport ) )
except :
self . handle_close ( )
self . rpc = rpc
def handle_connect ( self ) :
2017-02-07 23:35:57 +01:00
if self . state != " connected " :
2017-02-15 18:21:22 +01:00
logger . debug ( " Connected & Listening: %s : %d " % ( self . dstaddr , self . dstport ) )
2017-02-07 23:35:57 +01:00
self . state = " connected "
2017-02-07 23:40:28 +01:00
self . cb . on_open ( self )
2015-04-28 18:36:15 +02:00
def handle_close ( self ) :
2017-02-15 18:21:22 +01:00
logger . debug ( " Closing connection to: %s : %d " % ( self . dstaddr , self . dstport ) )
2015-04-28 18:36:15 +02:00
self . state = " closed "
2016-04-10 16:54:28 +02:00
self . recvbuf = b " "
self . sendbuf = b " "
2015-04-28 18:36:15 +02:00
try :
self . close ( )
except :
pass
self . cb . on_close ( self )
def handle_read ( self ) :
2017-09-13 15:17:15 +02:00
t = self . recv ( 8192 )
if len ( t ) > 0 :
self . recvbuf + = t
self . got_data ( )
2015-04-28 18:36:15 +02:00
def readable ( self ) :
return True
def writable ( self ) :
2015-05-01 20:47:21 +02:00
with mininode_lock :
2017-02-07 23:35:57 +01:00
pre_connection = self . state == " connecting "
2015-05-01 20:47:21 +02:00
length = len ( self . sendbuf )
2017-02-07 23:35:57 +01:00
return ( length > 0 or pre_connection )
2015-04-28 18:36:15 +02:00
def handle_write ( self ) :
2015-05-01 20:47:21 +02:00
with mininode_lock :
2017-02-07 23:35:57 +01:00
# asyncore does not expose socket connection, only the first read/write
# event, thus we must check connection manually here to know when we
# actually connect
if self . state == " connecting " :
self . handle_connect ( )
if not self . writable ( ) :
return
2015-05-01 20:47:21 +02:00
try :
sent = self . send ( self . sendbuf )
except :
self . handle_close ( )
return
self . sendbuf = self . sendbuf [ sent : ]
2015-04-28 18:36:15 +02:00
def got_data ( self ) :
2016-03-31 18:33:15 +02:00
try :
while True :
if len ( self . recvbuf ) < 4 :
2015-04-28 18:36:15 +02:00
return
2016-03-31 18:33:15 +02:00
if self . recvbuf [ : 4 ] != self . MAGIC_BYTES [ self . network ] :
raise ValueError ( " got garbage %s " % repr ( self . recvbuf ) )
2017-10-17 16:59:20 +02:00
if len ( self . recvbuf ) < 4 + 12 + 4 + 4 :
return
command = self . recvbuf [ 4 : 4 + 12 ] . split ( b " \x00 " , 1 ) [ 0 ]
msglen = struct . unpack ( " <i " , self . recvbuf [ 4 + 12 : 4 + 12 + 4 ] ) [ 0 ]
checksum = self . recvbuf [ 4 + 12 + 4 : 4 + 12 + 4 + 4 ]
if len ( self . recvbuf ) < 4 + 12 + 4 + 4 + msglen :
return
msg = self . recvbuf [ 4 + 12 + 4 + 4 : 4 + 12 + 4 + 4 + msglen ]
th = sha256 ( msg )
h = sha256 ( th )
if checksum != h [ : 4 ] :
raise ValueError ( " got bad checksum " + repr ( self . recvbuf ) )
self . recvbuf = self . recvbuf [ 4 + 12 + 4 + 4 + msglen : ]
if command not in self . messagemap :
raise ValueError ( " Received unknown command from %s : %d : ' %s ' %s " % ( self . dstaddr , self . dstport , command , repr ( msg ) ) )
f = BytesIO ( msg )
t = self . messagemap [ command ] ( )
t . deserialize ( f )
self . got_message ( t )
2016-03-31 18:33:15 +02:00
except Exception as e :
2017-10-17 16:59:20 +02:00
logger . exception ( ' Error reading message: ' , repr ( e ) )
2017-09-13 15:17:15 +02:00
raise
2015-04-28 18:36:15 +02:00
def send_message ( self , message , pushbuf = False ) :
if self . state != " connected " and not pushbuf :
2016-05-22 11:37:42 +02:00
raise IOError ( ' Not connected, no pushbuf ' )
2017-03-31 22:44:41 +02:00
self . _log_message ( " send " , message )
2015-04-28 18:36:15 +02:00
command = message . command
data = message . serialize ( )
tmsg = self . MAGIC_BYTES [ self . network ]
tmsg + = command
2016-04-10 16:54:28 +02:00
tmsg + = b " \x00 " * ( 12 - len ( command ) )
2015-04-28 18:36:15 +02:00
tmsg + = struct . pack ( " <I " , len ( data ) )
2017-10-17 16:59:20 +02:00
th = sha256 ( data )
h = sha256 ( th )
tmsg + = h [ : 4 ]
2015-04-28 18:36:15 +02:00
tmsg + = data
2015-05-01 20:47:21 +02:00
with mininode_lock :
2017-09-13 19:24:38 +02:00
if ( len ( self . sendbuf ) == 0 and not pushbuf ) :
try :
sent = self . send ( tmsg )
self . sendbuf = tmsg [ sent : ]
except BlockingIOError :
self . sendbuf = tmsg
else :
self . sendbuf + = tmsg
2015-05-01 20:47:21 +02:00
self . last_sent = time . time ( )
2015-04-28 18:36:15 +02:00
def got_message ( self , message ) :
if self . last_sent + 30 * 60 < time . time ( ) :
2016-04-10 16:54:28 +02:00
self . send_message ( self . messagemap [ b ' ping ' ] ( ) )
2017-03-31 22:44:41 +02:00
self . _log_message ( " receive " , message )
2015-04-28 18:36:15 +02:00
self . cb . deliver ( self , message )
2017-03-31 22:44:41 +02:00
def _log_message ( self , direction , msg ) :
if direction == " send " :
log_message = " Send message to "
elif direction == " receive " :
log_message = " Received message from "
log_message + = " %s : %d : %s " % ( self . dstaddr , self . dstport , repr ( msg ) [ : 500 ] )
if len ( log_message ) > 500 :
log_message + = " ... (msg truncated) "
logger . debug ( log_message )
2015-04-28 18:36:15 +02:00
def disconnect_node ( self ) :
self . disconnect = True
class NetworkThread ( Thread ) :
def run ( self ) :
2015-04-30 22:40:22 +02:00
while mininode_socket_map :
# We check for whether to disconnect outside of the asyncore
# loop to workaround the behavior of asyncore when using
# select
disconnected = [ ]
for fd , obj in mininode_socket_map . items ( ) :
if obj . disconnect :
disconnected . append ( obj )
[ obj . handle_close ( ) for obj in disconnected ]
asyncore . loop ( 0.1 , use_poll = True , map = mininode_socket_map , count = 1 )
2017-08-17 17:35:45 +02:00
logger . debug ( " Network thread closing " )