def test_block(): transactions = [] for x in range(10): tx_in = TxIn( prevout=OutPoint(), scriptSig=script.serialize([f"{x}{x}"]), sequence=0xFFFFFFFF, txinwitness=[], ) tx_out = TxOut( value=50 * 10**8, scriptPubKey=script.serialize([f"{x}{x}"]), ) tx = TxData( version=1, locktime=0, vin=[tx_in], vout=[tx_out], ) transactions.append(tx) header = BlockHeader( version=1, previousblockhash="00" * 32, merkleroot="00" * 32, time=1, bits=b"\x23\x00\x00\x01", nonce=1, ) header.merkleroot = _generate_merkle_root(transactions) msg = Block(BlockData(header, transactions)) msg_bytes = bytes.fromhex("00" * 4) + msg.serialize() assert msg == Block.deserialize(get_payload(msg_bytes)[1])
def test_only_79_bytes() -> None: fname = "block_1.bin" filename = path.join(path.dirname(__file__), "test_data", fname) header_bytes = open(filename, "rb").read() header_bytes = header_bytes[:70] with pytest.raises(IndexError): BlockHeader.deserialize(header_bytes)
def deserialize(cls, data): stream = bytesio_from_binarydata(data) header = BlockHeader.deserialize(stream) index = varint.decode(stream) status = BlockStatus.from_bytes(stream.read(1), "little") downloaded = bool(int.from_bytes(stream.read(1), "little")) return cls(header, index, status, downloaded)
def test_dataclasses_json_dict() -> None: fname = "block_481824.bin" filename = path.join(path.dirname(__file__), "test_data", fname) block = open(filename, "rb").read() # dataclass block_data = Block.deserialize(block) assert isinstance(block_data, Block) # str block_json_str = block_data.to_json() assert isinstance(block_json_str, str) assert block_data == Block.from_json(block_json_str) # dict block_dict = block_data.to_dict() assert isinstance(block_dict, dict) assert block_data == Block.from_dict(block_dict) import json datadir = path.join(path.dirname(__file__), "generated_files") filename = path.join(datadir, "block_481824.json") with open(filename, "w") as f: json.dump(block_dict, f, indent=True) block_header = block_data.header.serialize() # dataclass block_header_data = BlockHeader.deserialize(block_header) assert isinstance(block_header_data, BlockHeader) # str block_header_s = block_header_data.to_json() assert isinstance(block_header_s, str) assert block_header_data == BlockHeader.from_json(block_header_s) # dict block_header_d = block_header_data.to_dict() assert isinstance(block_header_d, dict) assert block_header_data == BlockHeader.from_dict(block_header_d) filename = path.join(datadir, "block_header_481824.json") with open(filename, "w") as f: json.dump(block_header_d, f, indent=True)
def deserialize(cls, data): stream = bytesio_from_binarydata(data) headers_num = varint.decode(stream) headers = [] for x in range(headers_num): header = BlockHeader.deserialize(stream) stream.read(1) headers.append(header) return cls(headers)
def generate_random_chain(length, start): # random.seed(42) chain = [] for x in range(length): previous_block_hash = chain[-1].header.hash if chain else start coinbase_in = TxIn( prevout=OutPoint(), scriptSig=script.serialize( [random.randrange(256**32).to_bytes(32, "big").hex()]), sequence=0xFFFFFFFF, txinwitness=[], ) coinbase_out = TxOut( value=50 * 10**8, scriptPubKey=script.serialize( [random.randrange(256**32).to_bytes(32, "big").hex()]), ) coinbase = Tx( version=1, locktime=0, vin=[coinbase_in], vout=[coinbase_out], ) transactions = [coinbase] if chain: tx_in = TxIn( prevout=OutPoint(chain[x - 1].transactions[0].txid, 0), scriptSig=script.serialize( [random.randrange(256**32).to_bytes(32, "big").hex()]), sequence=0xFFFFFFFF, txinwitness=[], ) tx_out = TxOut( value=50 * 10**8, scriptPubKey=script.serialize( [random.randrange(256**32).to_bytes(32, "big").hex()]), ) tx = Tx( version=1, locktime=0, vin=[tx_in], vout=[tx_out], ) transactions.append(tx) header = BlockHeader( version=70015, previousblockhash=previous_block_hash, merkleroot=_generate_merkle_root(transactions), time=1, bits=b"\x23\x00\x00\x01", nonce=1, ) block = Block(header, transactions) chain.append(block) return chain
def test_block_info_serialization(): header = BlockHeader(1, "00" * 32, "00" * 32, 1, b"\x23\x00\x00\x01", 1) for status in BlockStatus: for downloaded in (True, False): for x in range(1, 64): block_info = BlockInfo( header=header, index=x ** 2 - 1, status=status, downloaded=downloaded, ) assert block_info == BlockInfo.deserialize(block_info.serialize())
def create_genesis(time, nonce, difficulty, version, reward): script_sig = script.serialize( [ "FFFF001D", b"\x04", "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks".encode(), ] ) script_pub_key = script.serialize( [ "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f", "OP_CHECKSIG", ] ) tx_in = TxIn( prevout=OutPoint(), scriptSig=script_sig, sequence=0xFFFFFFFF, txinwitness=[], ) tx_out = TxOut( value=reward, scriptPubKey=script_pub_key, ) tx = Tx( version=1, locktime=0, vin=[tx_in], vout=[tx_out], ) header = BlockHeader( version=version, previousblockhash="00" * 32, merkleroot="00" * 32, time=time, bits=difficulty.to_bytes(4, "big"), nonce=nonce, ) header.merkleroot = _generate_merkle_root([tx]) return header
def test_headers(): headers = [] for x in range(10): headers.append( BlockHeader( version=70015, previousblockhash=f"{x}{x}" * 32, merkleroot="00" * 32, time=1, bits=b"\x23\x00\x00\x01", nonce=1, )) msg = Headers(headers) msg_bytes = bytes.fromhex("00" * 4) + msg.serialize() assert msg == Headers.deserialize(get_payload(msg_bytes)[1])
def generate_random_header_chain(length, start): # random.seed(42) chain = [] for x in range(length): if chain: previousblockhash = chain[-1].hash else: previousblockhash = start chain.append( BlockHeader( version=70015, previousblockhash=previousblockhash, merkleroot=random.randrange(256**32).to_bytes(32, "big").hex(), time=1, bits=b"\x23\x00\x00\x01", nonce=1, )) return chain
def deserialize(cls, data): stream = bytesio_from_binarydata(data) header = BlockHeader.deserialize(stream) nonce = int.from_bytes(stream.read(8), "little") short_ids = [] short_ids_length = varint.decode(stream) for x in range(short_ids_length): short_ids.append(stream.read(6)[::-1].hex()) prefilled_tx_list = [] prefilled_tx_num = varint.decode(stream) for x in range(prefilled_tx_num): tx_index = varint.decode(stream) tx = Tx.deserialize(stream) prefilled_tx_list.append((tx_index, tx)) return cls( header=header, nonce=nonce, short_ids=short_ids, prefilled_tx_list=prefilled_tx_list, )
def test_calculate_work(): header = BlockHeader(1, "00" * 32, "00" * 32, 1, b"\x23\x00\x00\x01", 1) assert calculate_work(header) == 1