diff options
Diffstat (limited to 'test/functional/test_framework/messages.py')
-rwxr-xr-x | test/functional/test_framework/messages.py | 226 |
1 files changed, 115 insertions, 111 deletions
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index d008cb39aa..4e496a9275 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -25,7 +25,6 @@ from io import BytesIO import math import random import socket -import struct import time import unittest @@ -47,6 +46,7 @@ MAX_PROTOCOL_MESSAGE_LENGTH = 4000000 # Maximum length of incoming protocol mes MAX_HEADERS_RESULTS = 2000 # Number of headers sent in one getheaders result MAX_INV_SIZE = 50000 # Maximum number of entries in an 'inv' protocol message +NODE_NONE = 0 NODE_NETWORK = (1 << 0) NODE_BLOOM = (1 << 2) NODE_WITNESS = (1 << 3) @@ -75,6 +75,13 @@ MAX_OP_RETURN_RELAY = 83 DEFAULT_MEMPOOL_EXPIRY_HOURS = 336 # hours +MAGIC_BYTES = { + "mainnet": b"\xf9\xbe\xb4\xd9", # mainnet + "testnet3": b"\x0b\x11\x09\x07", # testnet3 + "regtest": b"\xfa\xbf\xb5\xda", # regtest + "signet": b"\x0a\x03\xcf\x40", # signet +} + def sha256(s): return hashlib.sha256(s).digest() @@ -90,24 +97,24 @@ def hash256(s): def ser_compact_size(l): r = b"" if l < 253: - r = struct.pack("B", l) + r = l.to_bytes(1, "little") elif l < 0x10000: - r = struct.pack("<BH", 253, l) + r = (253).to_bytes(1, "little") + l.to_bytes(2, "little") elif l < 0x100000000: - r = struct.pack("<BI", 254, l) + r = (254).to_bytes(1, "little") + l.to_bytes(4, "little") else: - r = struct.pack("<BQ", 255, l) + r = (255).to_bytes(1, "little") + l.to_bytes(8, "little") return r def deser_compact_size(f): - nit = struct.unpack("<B", f.read(1))[0] + nit = int.from_bytes(f.read(1), "little") if nit == 253: - nit = struct.unpack("<H", f.read(2))[0] + nit = int.from_bytes(f.read(2), "little") elif nit == 254: - nit = struct.unpack("<I", f.read(4))[0] + nit = int.from_bytes(f.read(4), "little") elif nit == 255: - nit = struct.unpack("<Q", f.read(8))[0] + nit = int.from_bytes(f.read(8), "little") return nit @@ -272,13 +279,13 @@ class CAddress: """Deserialize from addrv1 format (pre-BIP155)""" if with_time: # VERSION messages serialize CAddress objects without time - self.time = struct.unpack("<I", f.read(4))[0] - self.nServices = struct.unpack("<Q", f.read(8))[0] + self.time = int.from_bytes(f.read(4), "little") + self.nServices = int.from_bytes(f.read(8), "little") # We only support IPv4 which means skip 12 bytes and read the next 4 as IPv4 address. f.read(12) self.net = self.NET_IPV4 self.ip = socket.inet_ntoa(f.read(4)) - self.port = struct.unpack(">H", f.read(2))[0] + self.port = int.from_bytes(f.read(2), "big") def serialize(self, *, with_time=True): """Serialize in addrv1 format (pre-BIP155)""" @@ -286,20 +293,20 @@ class CAddress: r = b"" if with_time: # VERSION messages serialize CAddress objects without time - r += struct.pack("<I", self.time) - r += struct.pack("<Q", self.nServices) + r += self.time.to_bytes(4, "little") + r += self.nServices.to_bytes(8, "little") r += b"\x00" * 10 + b"\xff" * 2 r += socket.inet_aton(self.ip) - r += struct.pack(">H", self.port) + r += self.port.to_bytes(2, "big") return r def deserialize_v2(self, f): """Deserialize from addrv2 format (BIP155)""" - self.time = struct.unpack("<I", f.read(4))[0] + self.time = int.from_bytes(f.read(4), "little") self.nServices = deser_compact_size(f) - self.net = struct.unpack("B", f.read(1))[0] + self.net = int.from_bytes(f.read(1), "little") assert self.net in self.ADDRV2_NET_NAME address_length = deser_compact_size(f) @@ -322,15 +329,15 @@ class CAddress: else: raise Exception(f"Address type not supported") - self.port = struct.unpack(">H", f.read(2))[0] + self.port = int.from_bytes(f.read(2), "big") def serialize_v2(self): """Serialize in addrv2 format (BIP155)""" assert self.net in self.ADDRV2_NET_NAME r = b"" - r += struct.pack("<I", self.time) + r += self.time.to_bytes(4, "little") r += ser_compact_size(self.nServices) - r += struct.pack("B", self.net) + r += self.net.to_bytes(1, "little") r += ser_compact_size(self.ADDRV2_ADDRESS_LENGTH[self.net]) if self.net == self.NET_IPV4: r += socket.inet_aton(self.ip) @@ -348,7 +355,7 @@ class CAddress: r += socket.inet_pton(socket.AF_INET6, self.ip) else: raise Exception(f"Address type not supported") - r += struct.pack(">H", self.port) + r += self.port.to_bytes(2, "big") return r def __repr__(self): @@ -375,12 +382,12 @@ class CInv: self.hash = h def deserialize(self, f): - self.type = struct.unpack("<I", f.read(4))[0] + self.type = int.from_bytes(f.read(4), "little") self.hash = deser_uint256(f) def serialize(self): r = b"" - r += struct.pack("<I", self.type) + r += self.type.to_bytes(4, "little") r += ser_uint256(self.hash) return r @@ -399,12 +406,12 @@ class CBlockLocator: self.vHave = [] def deserialize(self, f): - struct.unpack("<i", f.read(4))[0] # Ignore version field. + int.from_bytes(f.read(4), "little", signed=True) # Ignore version field. self.vHave = deser_uint256_vector(f) def serialize(self): r = b"" - r += struct.pack("<i", 0) # Bitcoin Core ignores version field. Set it to 0. + r += (0).to_bytes(4, "little", signed=True) # Bitcoin Core ignores the version field. Set it to 0. r += ser_uint256_vector(self.vHave) return r @@ -421,12 +428,12 @@ class COutPoint: def deserialize(self, f): self.hash = deser_uint256(f) - self.n = struct.unpack("<I", f.read(4))[0] + self.n = int.from_bytes(f.read(4), "little") def serialize(self): r = b"" r += ser_uint256(self.hash) - r += struct.pack("<I", self.n) + r += self.n.to_bytes(4, "little") return r def __repr__(self): @@ -448,13 +455,13 @@ class CTxIn: self.prevout = COutPoint() self.prevout.deserialize(f) self.scriptSig = deser_string(f) - self.nSequence = struct.unpack("<I", f.read(4))[0] + self.nSequence = int.from_bytes(f.read(4), "little") def serialize(self): r = b"" r += self.prevout.serialize() r += ser_string(self.scriptSig) - r += struct.pack("<I", self.nSequence) + r += self.nSequence.to_bytes(4, "little") return r def __repr__(self): @@ -471,12 +478,12 @@ class CTxOut: self.scriptPubKey = scriptPubKey def deserialize(self, f): - self.nValue = struct.unpack("<q", f.read(8))[0] + self.nValue = int.from_bytes(f.read(8), "little", signed=True) self.scriptPubKey = deser_string(f) def serialize(self): r = b"" - r += struct.pack("<q", self.nValue) + r += self.nValue.to_bytes(8, "little", signed=True) r += ser_string(self.scriptPubKey) return r @@ -575,11 +582,11 @@ class CTransaction: self.wit = copy.deepcopy(tx.wit) def deserialize(self, f): - self.nVersion = struct.unpack("<i", f.read(4))[0] + self.nVersion = int.from_bytes(f.read(4), "little", signed=True) self.vin = deser_vector(f, CTxIn) flags = 0 if len(self.vin) == 0: - flags = struct.unpack("<B", f.read(1))[0] + flags = int.from_bytes(f.read(1), "little") # Not sure why flags can't be zero, but this # matches the implementation in bitcoind if (flags != 0): @@ -592,16 +599,16 @@ class CTransaction: self.wit.deserialize(f) else: self.wit = CTxWitness() - self.nLockTime = struct.unpack("<I", f.read(4))[0] + self.nLockTime = int.from_bytes(f.read(4), "little") self.sha256 = None self.hash = None def serialize_without_witness(self): r = b"" - r += struct.pack("<i", self.nVersion) + r += self.nVersion.to_bytes(4, "little", signed=True) r += ser_vector(self.vin) r += ser_vector(self.vout) - r += struct.pack("<I", self.nLockTime) + r += self.nLockTime.to_bytes(4, "little") return r # Only serialize with witness when explicitly called for @@ -610,11 +617,11 @@ class CTransaction: if not self.wit.is_null(): flags |= 1 r = b"" - r += struct.pack("<i", self.nVersion) + r += self.nVersion.to_bytes(4, "little", signed=True) if flags: dummy = [] r += ser_vector(dummy) - r += struct.pack("<B", flags) + r += flags.to_bytes(1, "little") r += ser_vector(self.vin) r += ser_vector(self.vout) if flags & 1: @@ -624,7 +631,7 @@ class CTransaction: for _ in range(len(self.wit.vtxinwit), len(self.vin)): self.wit.vtxinwit.append(CTxInWitness()) r += self.wit.serialize() - r += struct.pack("<I", self.nLockTime) + r += self.nLockTime.to_bytes(4, "little") return r # Regular serialization is with witness -- must explicitly @@ -703,34 +710,34 @@ class CBlockHeader: self.hash = None def deserialize(self, f): - self.nVersion = struct.unpack("<i", f.read(4))[0] + self.nVersion = int.from_bytes(f.read(4), "little", signed=True) 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.nTime = int.from_bytes(f.read(4), "little") + self.nBits = int.from_bytes(f.read(4), "little") + self.nNonce = int.from_bytes(f.read(4), "little") self.sha256 = None self.hash = None def serialize(self): r = b"" - r += struct.pack("<i", self.nVersion) + r += self.nVersion.to_bytes(4, "little", signed=True) 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) + r += self.nTime.to_bytes(4, "little") + r += self.nBits.to_bytes(4, "little") + r += self.nNonce.to_bytes(4, "little") return r def calc_sha256(self): if self.sha256 is None: r = b"" - r += struct.pack("<i", self.nVersion) + r += self.nVersion.to_bytes(4, "little", signed=True) 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) + r += self.nTime.to_bytes(4, "little") + r += self.nBits.to_bytes(4, "little") + r += self.nNonce.to_bytes(4, "little") self.sha256 = uint256_from_str(hash256(r)) self.hash = hash256(r)[::-1].hex() @@ -874,12 +881,12 @@ class P2PHeaderAndShortIDs: def deserialize(self, f): self.header.deserialize(f) - self.nonce = struct.unpack("<Q", f.read(8))[0] + self.nonce = int.from_bytes(f.read(8), "little") self.shortids_length = deser_compact_size(f) for _ 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.shortids.append(int.from_bytes(f.read(6) + b'\x00\x00', "little")) self.prefilled_txn = deser_vector(f, PrefilledTransaction) self.prefilled_txn_length = len(self.prefilled_txn) @@ -887,11 +894,11 @@ class P2PHeaderAndShortIDs: def serialize(self, with_witness=False): r = b"" r += self.header.serialize() - r += struct.pack("<Q", self.nonce) + r += self.nonce.to_bytes(8, "little") 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] + r += x.to_bytes(8, "little")[0:6] if with_witness: r += ser_vector(self.prefilled_txn, "serialize_with_witness") else: @@ -956,10 +963,10 @@ class HeaderAndShortIDs: def get_siphash_keys(self): header_nonce = self.header.serialize() - header_nonce += struct.pack("<Q", self.nonce) + header_nonce += self.nonce.to_bytes(8, "little") 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] + key0 = int.from_bytes(hash_header_nonce_as_str[0:8], "little") + key1 = int.from_bytes(hash_header_nonce_as_str[8:16], "little") return [ key0, key1 ] # Version 2 compact blocks use wtxid in shortids (rather than txid) @@ -1057,7 +1064,7 @@ class CPartialMerkleTree: self.vBits = [] def deserialize(self, f): - self.nTransactions = struct.unpack("<i", f.read(4))[0] + self.nTransactions = int.from_bytes(f.read(4), "little") self.vHash = deser_uint256_vector(f) vBytes = deser_string(f) self.vBits = [] @@ -1066,7 +1073,7 @@ class CPartialMerkleTree: def serialize(self): r = b"" - r += struct.pack("<i", self.nTransactions) + r += self.nTransactions.to_bytes(4, "little") r += ser_uint256_vector(self.vHash) vBytesArray = bytearray([0x00] * ((len(self.vBits) + 7)//8)) for i in range(len(self.vBits)): @@ -1117,37 +1124,34 @@ class msg_version: self.relay = 0 def deserialize(self, f): - self.nVersion = struct.unpack("<i", f.read(4))[0] - self.nServices = struct.unpack("<Q", f.read(8))[0] - self.nTime = struct.unpack("<q", f.read(8))[0] + self.nVersion = int.from_bytes(f.read(4), "little", signed=True) + self.nServices = int.from_bytes(f.read(8), "little") + self.nTime = int.from_bytes(f.read(8), "little", signed=True) self.addrTo = CAddress() self.addrTo.deserialize(f, with_time=False) self.addrFrom = CAddress() self.addrFrom.deserialize(f, with_time=False) - self.nNonce = struct.unpack("<Q", f.read(8))[0] + self.nNonce = int.from_bytes(f.read(8), "little") self.strSubVer = deser_string(f).decode('utf-8') - self.nStartingHeight = struct.unpack("<i", f.read(4))[0] + self.nStartingHeight = int.from_bytes(f.read(4), "little", signed=True) # Relay field is optional for version 70001 onwards # But, unconditionally check it to match behaviour in bitcoind - try: - self.relay = struct.unpack("<b", f.read(1))[0] - except struct.error: - self.relay = 0 + self.relay = int.from_bytes(f.read(1), "little") # f.read(1) may return an empty b'' def serialize(self): r = b"" - r += struct.pack("<i", self.nVersion) - r += struct.pack("<Q", self.nServices) - r += struct.pack("<q", self.nTime) + r += self.nVersion.to_bytes(4, "little", signed=True) + r += self.nServices.to_bytes(8, "little") + r += self.nTime.to_bytes(8, "little", signed=True) r += self.addrTo.serialize(with_time=False) r += self.addrFrom.serialize(with_time=False) - r += struct.pack("<Q", self.nNonce) + r += self.nNonce.to_bytes(8, "little") r += ser_string(self.strSubVer.encode('utf-8')) - r += struct.pack("<i", self.nStartingHeight) - r += struct.pack("<b", self.relay) + r += self.nStartingHeight.to_bytes(4, "little", signed=True) + r += self.relay.to_bytes(1, "little") return r def __repr__(self): @@ -1393,11 +1397,11 @@ class msg_ping: self.nonce = nonce def deserialize(self, f): - self.nonce = struct.unpack("<Q", f.read(8))[0] + self.nonce = int.from_bytes(f.read(8), "little") def serialize(self): r = b"" - r += struct.pack("<Q", self.nonce) + r += self.nonce.to_bytes(8, "little") return r def __repr__(self): @@ -1412,11 +1416,11 @@ class msg_pong: self.nonce = nonce def deserialize(self, f): - self.nonce = struct.unpack("<Q", f.read(8))[0] + self.nonce = int.from_bytes(f.read(8), "little") def serialize(self): r = b"" - r += struct.pack("<Q", self.nonce) + r += self.nonce.to_bytes(8, "little") return r def __repr__(self): @@ -1557,16 +1561,16 @@ class msg_filterload: def deserialize(self, f): self.data = deser_string(f) - self.nHashFuncs = struct.unpack("<I", f.read(4))[0] - self.nTweak = struct.unpack("<I", f.read(4))[0] - self.nFlags = struct.unpack("<B", f.read(1))[0] + self.nHashFuncs = int.from_bytes(f.read(4), "little") + self.nTweak = int.from_bytes(f.read(4), "little") + self.nFlags = int.from_bytes(f.read(1), "little") def serialize(self): r = b"" r += ser_string(self.data) - r += struct.pack("<I", self.nHashFuncs) - r += struct.pack("<I", self.nTweak) - r += struct.pack("<B", self.nFlags) + r += self.nHashFuncs.to_bytes(4, "little") + r += self.nTweak.to_bytes(4, "little") + r += self.nFlags.to_bytes(1, "little") return r def __repr__(self): @@ -1618,11 +1622,11 @@ class msg_feefilter: self.feerate = feerate def deserialize(self, f): - self.feerate = struct.unpack("<Q", f.read(8))[0] + self.feerate = int.from_bytes(f.read(8), "little") def serialize(self): r = b"" - r += struct.pack("<Q", self.feerate) + r += self.feerate.to_bytes(8, "little") return r def __repr__(self): @@ -1638,13 +1642,13 @@ class msg_sendcmpct: self.version = version def deserialize(self, f): - self.announce = struct.unpack("<?", f.read(1))[0] - self.version = struct.unpack("<Q", f.read(8))[0] + self.announce = bool(int.from_bytes(f.read(1), "little")) + self.version = int.from_bytes(f.read(8), "little") def serialize(self): r = b"" - r += struct.pack("<?", self.announce) - r += struct.pack("<Q", self.version) + r += int(self.announce).to_bytes(1, "little") + r += self.version.to_bytes(8, "little") return r def __repr__(self): @@ -1727,14 +1731,14 @@ class msg_getcfilters: self.stop_hash = stop_hash def deserialize(self, f): - self.filter_type = struct.unpack("<B", f.read(1))[0] - self.start_height = struct.unpack("<I", f.read(4))[0] + self.filter_type = int.from_bytes(f.read(1), "little") + self.start_height = int.from_bytes(f.read(4), "little") self.stop_hash = deser_uint256(f) def serialize(self): r = b"" - r += struct.pack("<B", self.filter_type) - r += struct.pack("<I", self.start_height) + r += self.filter_type.to_bytes(1, "little") + r += self.start_height.to_bytes(4, "little") r += ser_uint256(self.stop_hash) return r @@ -1752,13 +1756,13 @@ class msg_cfilter: self.filter_data = filter_data def deserialize(self, f): - self.filter_type = struct.unpack("<B", f.read(1))[0] + self.filter_type = int.from_bytes(f.read(1), "little") self.block_hash = deser_uint256(f) self.filter_data = deser_string(f) def serialize(self): r = b"" - r += struct.pack("<B", self.filter_type) + r += self.filter_type.to_bytes(1, "little") r += ser_uint256(self.block_hash) r += ser_string(self.filter_data) return r @@ -1777,14 +1781,14 @@ class msg_getcfheaders: self.stop_hash = stop_hash def deserialize(self, f): - self.filter_type = struct.unpack("<B", f.read(1))[0] - self.start_height = struct.unpack("<I", f.read(4))[0] + self.filter_type = int.from_bytes(f.read(1), "little") + self.start_height = int.from_bytes(f.read(4), "little") self.stop_hash = deser_uint256(f) def serialize(self): r = b"" - r += struct.pack("<B", self.filter_type) - r += struct.pack("<I", self.start_height) + r += self.filter_type.to_bytes(1, "little") + r += self.start_height.to_bytes(4, "little") r += ser_uint256(self.stop_hash) return r @@ -1803,14 +1807,14 @@ class msg_cfheaders: self.hashes = hashes def deserialize(self, f): - self.filter_type = struct.unpack("<B", f.read(1))[0] + self.filter_type = int.from_bytes(f.read(1), "little") self.stop_hash = deser_uint256(f) self.prev_header = deser_uint256(f) self.hashes = deser_uint256_vector(f) def serialize(self): r = b"" - r += struct.pack("<B", self.filter_type) + r += self.filter_type.to_bytes(1, "little") r += ser_uint256(self.stop_hash) r += ser_uint256(self.prev_header) r += ser_uint256_vector(self.hashes) @@ -1829,12 +1833,12 @@ class msg_getcfcheckpt: self.stop_hash = stop_hash def deserialize(self, f): - self.filter_type = struct.unpack("<B", f.read(1))[0] + self.filter_type = int.from_bytes(f.read(1), "little") self.stop_hash = deser_uint256(f) def serialize(self): r = b"" - r += struct.pack("<B", self.filter_type) + r += self.filter_type.to_bytes(1, "little") r += ser_uint256(self.stop_hash) return r @@ -1852,13 +1856,13 @@ class msg_cfcheckpt: self.headers = headers def deserialize(self, f): - self.filter_type = struct.unpack("<B", f.read(1))[0] + self.filter_type = int.from_bytes(f.read(1), "little") self.stop_hash = deser_uint256(f) self.headers = deser_uint256_vector(f) def serialize(self): r = b"" - r += struct.pack("<B", self.filter_type) + r += self.filter_type.to_bytes(1, "little") r += ser_uint256(self.stop_hash) r += ser_uint256_vector(self.headers) return r @@ -1876,13 +1880,13 @@ class msg_sendtxrcncl: self.salt = 0 def deserialize(self, f): - self.version = struct.unpack("<I", f.read(4))[0] - self.salt = struct.unpack("<Q", f.read(8))[0] + self.version = int.from_bytes(f.read(4), "little") + self.salt = int.from_bytes(f.read(8), "little") def serialize(self): r = b"" - r += struct.pack("<I", self.version) - r += struct.pack("<Q", self.salt) + r += self.version.to_bytes(4, "little") + r += self.salt.to_bytes(8, "little") return r def __repr__(self): |