def test_exercise_2(self): block_hash = bytes.fromhex( '0000000053787814ed9dd8c029d0a0a9af4ab8ec0591dc31bdc4ab31fae88ce9') passphrase = b'Jimmy Song Programming Blockchain' # FILL THIS IN secret = little_endian_to_int(hash256(passphrase)) private_key = PrivateKey(secret=secret) addr = private_key.point.address(testnet=True) filter_size = 30 filter_num_functions = 5 filter_tweak = 90210 # FILL THIS IN h160 = decode_base58(addr) bf = BloomFilter(filter_size, filter_num_functions, filter_tweak) bf.add(h160) node = SimpleNode('tbtc.programmingblockchain.com', testnet=True, logging=False) node.handshake() node.send(bf.filterload()) getdata = GetDataMessage() getdata.add_data(FILTERED_BLOCK_DATA_TYPE, block_hash) node.send(getdata) mb = node.wait_for(MerkleBlock) tx = node.wait_for(Tx) self.assertEqual( tx.serialize().hex(), '0100000002a663815ab2b2ba5f53e442f9a2ea6cc11bbcd98fb1585e48a134bd870dbfbd6a000000006a47304402202151107dc2367cf5a9e2429cde0641c252374501214ce52069fbca1320180aa602201a43b5d4f91e48514c00c01521dc04f02c57f15305adc4eaad01c418f6e7a1180121031dbe3aff7b9ad64e2612b8b15e9f5e4a3130663a526df91abfb7b1bd16de5d6effffffff618b00a343488bd62751cf21f368ce3be76e3a0323fdc594a0d24f27a1155cd2000000006a473044022024c4dd043ab8637c019528b549e0b10333b2dfa83e7ca66776e401ad3fc31b6702207d4d1d73ac8940c59c57c0b7daf084953324154811c10d06d0563947a88f99b20121031dbe3aff7b9ad64e2612b8b15e9f5e4a3130663a526df91abfb7b1bd16de5d6effffffff0280969800000000001976a914ad346f8eb57dee9a37981716e498120ae80e44f788aca0ce6594000000001976a9146e13971913b9aa89659a9f53d327baa8826f2d7588ac00000000' )
def test_exercise_4(self): last_block_hex = '000000000d65610b5af03d73ed67704713c9b734d87cf4b970d39a0416dd80f9' last_block = bytes.fromhex(last_block_hex) secret = little_endian_to_int( hash256(b'Jimmy Song Programming Blockchain')) private_key = PrivateKey(secret=secret) addr = private_key.point.address(testnet=True) h160 = decode_base58(addr) target_address = 'mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv' self.assertEqual(addr, target_address) filter_size = 30 filter_num_functions = 5 filter_tweak = 90210 # FILL THIS IN target_h160 = decode_base58(target_address) target_script = p2pkh_script(target_h160) fee = 5000 # fee in satoshis node = SimpleNode('tbtc.programmingblockchain.com', testnet=True, logging=False) bf = BloomFilter(filter_size, filter_num_functions, filter_tweak) bf.add(h160) node.handshake() node.send(b'filterload', bf.filterload()) getheaders_message = GetHeadersMessage(start_block=last_block) node.send(getheaders_message.command, getheaders_message.serialize()) headers_envelope = node.wait_for_commands([HeadersMessage.command]) stream = headers_envelope.stream() headers = HeadersMessage.parse(stream) get_data_message = GetDataMessage() for block in headers.blocks: self.assertTrue(block.check_pow()) if last_block is not None: self.assertEqual(block.prev_block, last_block) last_block = block.hash() get_data_message.add_data(FILTERED_BLOCK_DATA_TYPE, last_block) node.send(get_data_message.command, get_data_message.serialize()) prev_tx = None while prev_tx is None: envelope = node.wait_for_commands([b'merkleblock', b'tx']) stream = envelope.stream() if envelope.command == b'merkleblock': mb = MerkleBlock.parse(stream) self.assertTrue(mb.is_valid()) else: prev = Tx.parse(stream, testnet=True) for i, tx_out in enumerate(prev.tx_outs): if tx_out.script_pubkey.address(testnet=True) == addr: prev_tx = prev.hash() prev_index = i prev_amount = tx_out.amount break tx_in = TxIn(prev_tx, prev_index) output_amount = prev_amount - fee tx_out = TxOut(output_amount, target_script) tx_obj = Tx(1, [tx_in], [tx_out], 0, testnet=True) tx_obj.sign_input(0, private_key) self.assertEqual( tx_obj.serialize().hex(), '010000000194e631abb9e1079ec72a1616a3aa0111c614e65b96a6a4420e2cc6af9e6cc96e000000006a47304402203cc8c56abe1c0dd043afa9eb125dafbebdde2dd4cd7abf0fb1aae0667a22006e02203c95b74d0f0735bbf1b261d36e077515b6939fc088b9d7c1b7030a5e494596330121021cdd761c7eb1c90c0af0a5963e94bf0203176b4662778d32bd6d7ab5d8628b32ffffffff01f8829800000000001976a914ad346f8eb57dee9a37981716e498120ae80e44f788ac00000000' )
def test_exercise_6(self): last_block_hex = '000000000d65610b5af03d73ed67704713c9b734d87cf4b970d39a0416dd80f9' secret = little_endian_to_int( hash256(b'Jimmy Song Programming Blockchain')) private_key = PrivateKey(secret=secret) addr = private_key.point.address(testnet=True) h160 = decode_base58(addr) target_address = 'mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv' self.assertEqual(addr, target_address) target_h160 = decode_base58(target_address) target_script = p2pkh_script(target_h160) fee = 5000 node = SimpleNode('tbtc.programmingblockchain.com', testnet=True) bf = BloomFilter(30, 5, 90210) bf.add(h160) node.handshake() node.send(bf.filterload()) start_block = bytes.fromhex(last_block_hex) getheaders = GetHeadersMessage(start_block=start_block) node.send(getheaders) headers = node.wait_for(HeadersMessage) last_block = None getdata = GetDataMessage() for b in headers.blocks: if not b.check_pow(): raise RuntimeError('proof of work is invalid') if last_block is not None and b.prev_block != last_block: raise RuntimeError('chain broken') getdata.add_data(FILTERED_BLOCK_DATA_TYPE, b.hash()) last_block = b.hash() node.send(getdata) prev_tx, prev_index, prev_tx_obj = None, None, None while prev_tx is None: message = node.wait_for(MerkleBlock, Tx) if message.command == b'merkleblock': if not message.is_valid(): raise RuntimeError('invalid merkle proof') else: message.testnet = True for i, tx_out in enumerate(message.tx_outs): if tx_out.script_pubkey.address(testnet=True) == addr: prev_tx = message.hash() prev_index = i prev_amount = tx_out.amount self.assertEqual( message.id(), '6ec96c9eafc62c0e42a4a6965be614c61101aaa316162ac79e07e1b9ab31e694' ) self.assertEqual(i, 0) break tx_in = TxIn(prev_tx, prev_index) output_amount = prev_amount - fee tx_out = TxOut(output_amount, target_script) tx_obj = Tx(1, [tx_in], [tx_out], 0, testnet=True) tx_obj.sign_input(0, private_key) self.assertEqual( tx_obj.serialize().hex(), '010000000194e631abb9e1079ec72a1616a3aa0111c614e65b96a6a4420e2cc6af9e6cc96e000000006a47304402203cc8c56abe1c0dd043afa9eb125dafbebdde2dd4cd7abf0fb1aae0667a22006e02203c95b74d0f0735bbf1b261d36e077515b6939fc088b9d7c1b7030a5e494596330121021cdd761c7eb1c90c0af0a5963e94bf0203176b4662778d32bd6d7ab5d8628b32ffffffff01f8829800000000001976a914ad346f8eb57dee9a37981716e498120ae80e44f788ac00000000' )
def test_exercise_10(self): block_hex = '0000000000044b01a9440b34f582fe171c7b8642fedd0ebfccf8fdf6a1810900' block_hash = bytes.fromhex(block_hex) node = SimpleNode('tbtc.programmingblockchain.com', testnet=True) node.handshake() getdata = GetDataMessage() getdata.add_data(BLOCK_DATA_TYPE, block_hash) node.send(getdata) b = node.wait_for(Block) self.assertTrue(b.check_pow()) self.assertTrue(b.validate_merkle_root())
def connect_bitcoin(host, port, tor=False, logging=False, process_name="main"): if tor: if logging: logging.info("[-] Tor connection is requested") logging.info("[-] Connecting to bitcoin node {}:{}".format(host, port)) node = SimpleNode(host, port, logging=log_info, tor=tor, process_name=process_name) if node.tor: if logging: logging.info("[-] SOCKS5 proxy listener on TCP:{}".format(node.socks_port)) node.handshake() else: if logging: logging.info("[-] Connecting to bitcoin node {}:{}".format(host, port)) node = SimpleNode(host, port, logging=log_info, tor=tor) node.handshake() return node
def test_exercise_10(self): block_hex = '0000000000044b01a9440b34f582fe171c7b8642fedd0ebfccf8fdf6a1810900' block_hash = bytes.fromhex(block_hex) node = SimpleNode('tbtc.programmingblockchain.com', testnet=True) node.handshake() getdata = GetDataMessage() getdata.add_data(BLOCK_DATA_TYPE, block_hash) node.send(getdata.command, getdata.serialize()) block_envelope = node.wait_for_commands([b'block']) stream = block_envelope.stream() b = Block.parse(stream) self.assertTrue(b.check_pow()) num_txs = read_varint(stream) tx_hashes = [] for _ in range(num_txs): t = Tx.parse(stream) tx_hashes.append(t.hash()) b.tx_hashes = tx_hashes self.assertTrue(b.validate_merkle_root())
def test_example_5(self): last_block_hex = '00000000000538d5c2246336644f9a4956551afb44ba47278759ec55ea912e19' address = 'mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv' h160 = decode_base58(address) node = SimpleNode('tbtc.programmingblockchain.com', testnet=True, logging=False) bf = BloomFilter(30, 5, 90210) bf.add(h160) node.handshake() node.send(b'filterload', bf.filterload()) start_block = bytes.fromhex(last_block_hex) getheaders_message = GetHeadersMessage(start_block=start_block) node.send(b'getheaders', getheaders_message.serialize()) headers_envelope = node.wait_for_commands({b'headers'}) stream = headers_envelope.stream() headers = HeadersMessage.parse(stream) get_data_message = GetDataMessage() for b in headers.blocks: if not b.check_pow(): raise RuntimeError('proof of work is invalid') get_data_message.add_data(FILTERED_BLOCK_DATA_TYPE, b.hash()) node.send(b'getdata', get_data_message.serialize()) found = False while not found: envelope = node.wait_for_commands({b'merkleblock', b'tx'}) stream = envelope.stream() if envelope.command == b'merkleblock': mb = MerkleBlock.parse(stream) if not mb.is_valid(): raise RuntimeError('invalid merkle proof') else: prev_tx_obj = Tx.parse(stream, testnet=True) for i, tx_out in enumerate(prev_tx_obj.tx_outs): if tx_out.script_pubkey.address(testnet=True) == address: self.assertEqual( prev_tx_obj.id(), 'e3930e1e566ca9b75d53b0eb9acb7607f547e1182d1d22bd4b661cfe18dcddf1' ) self.assertEqual(i, 0) found = True break
def test_exercise_5(self): expected = [ '00000000864b744c5025331036aa4a16e9ed1cbb362908c625272150fa059b29', '000000002e9ccffc999166ccf8d72129e1b2e9c754f6c90ad2f77cab0d9fb4c7', '0000000009b9f0436a9c733e2c9a9d9c8fe3475d383bdc1beb7bfa995f90be70', '000000000a9c9c79f246042b9e2819822287f2be7cd6487aecf7afab6a88bed5', '000000003a7002e1247b0008cba36cd46f57cd7ce56ac9d9dc5644265064df09', '00000000061e01e82afff6e7aaea4eb841b78cc0eed3af11f6706b14471fa9c8', '000000003911e011ae2459e44d4581ac69ba703fb26e1421529bd326c538f12d', '000000000a5984d6c73396fe40de392935f5fc2a8e48eedf38034ce0a3178a60', '000000000786bdc642fa54c0a791d58b732ed5676516fffaeca04492be97c243', '000000001359c49f9618f3ee69afbd1b3196f1832acc47557d42256fcc6b7f48', '00000000270dde98d582af35dff5aed02087dad8529dc5c808c67573d6dabaf4', '00000000425c160908c215c4adf998771a2d1c472051bc58320696f3a5eb0644', '0000000006a5976471986377805d4a148d8822bb7f458138c83f167d197817c9', '000000000318394ea17038ef369f3cccc79b3d7dfda957af6c8cd4a471ffa814', '000000000ad4f9d0b8e86871478cc849f7bc42fb108ebec50e4a795afc284926', '000000000207e63e68f2a7a4c067135883d726fd65e3620142fb9bdf50cce1f6', '00000000003b426d2c12ee66b2eedb4dcc05d5e158685b222240d31e43687762', '00000000017cf6ee86e3d483f9a978ded72be1fa5af37d287a71c5dfb87cdd83', '00000000004b1d9fe16fc0c72cfa0395c98a3e460cd2affb8640e28bca295a4a' ] node = SimpleNode('tbtc.programmingblockchain.com', testnet=True) node.handshake() last_block_hash = TESTNET_GENESIS_BLOCK_HASH count = 1 while count <= 40000: getheaders = GetHeadersMessage(start_block=last_block_hash) node.send(getheaders.command, getheaders.serialize()) headers_envelope = node.wait_for_commands([b'headers']) headers_message = HeadersMessage.parse(headers_envelope.stream()) for b in headers_message.blocks: self.assertTrue(b.check_pow()) if last_block_hash != TESTNET_GENESIS_BLOCK_HASH: print(count) self.assertEqual(b.prev_block, last_block_hash) count += 1 last_block_hash = b.hash() if count % 2016 == 0: self.assertEqual(b.id(), expected.pop(0))
def test_example_2(self): expected = [ '00000000693067b0e6b440bc51450b9f3850561b07f6d3c021c54fbd6abb9763', '00000000f037ad09d0b05ee66b8c1da83030abaf909d2b1bf519c3c7d2cd3fdf', '000000006ce8b5f16fcedde13acbc9641baa1c67734f177d770a4069c06c9de8', '00000000563298de120522b5ae17da21aaae02eee2d7fcb5be65d9224dbd601c', '000000009b0a4b2833b4a0aa61171ee75b8eb301ac45a18713795a72e461a946', '00000000fa8a7363e8f6fdc88ec55edf264c9c7b31268c26e497a4587c750584', '000000008ac55b5cd76a5c176f2457f0e9df5ff1c719d939f1022712b1ba2092', '000000007f0c796631f00f542c0b402d638d3518bc208f8c9e5d29d2f169c084', '00000000ffb062296c9d4eb5f87bbf905d30669d26eab6bced341bd3f1dba5fd', '0000000074c108842c3ec2252bba62db4050bf0dddfee3ddaa5f847076b8822f', '0000000067dc2f84a73fbf5d3c70678ce4a1496ef3a62c557bc79cbdd1d49f22', '00000000dbf06f47c0624262ecb197bccf6bdaaabc2d973708ac401ac8955acc', '000000009260fe30ec89ef367122f429dcc59f61735760f2b2288f2e854f04ac', '00000000f9f1a700898c4e0671af6efd441eaf339ba075a5c5c7b0949473c80b', '000000005107662c86452e7365f32f8ffdc70d8d87aa6f78630a79f7d77fbfe6', '00000000984f962134a7291e3693075ae03e521f0ee33378ec30a334d860034b', '000000005e36047e39452a7beaaa6721048ac408a3e75bb60a8b0008713653ce', '00000000128d789579ffbec00203a371cbb39cee27df35d951fd66e62ed59258', '000000008dde642fb80481bb5e1671cb04c6716de5b7f783aa3388456d5c8a85' ] node = SimpleNode('btc.programmingblockchain.com', testnet=False) node.handshake() last_block_hash = GENESIS_BLOCK_HASH count = 1 for _ in range(20): getheaders = GetHeadersMessage(start_block=last_block_hash) node.send(getheaders.command, getheaders.serialize()) headers_envelope = node.wait_for_commands([b'headers']) headers_message = HeadersMessage.parse(headers_envelope.stream()) for b in headers_message.blocks: self.assertTrue(b.check_pow()) if last_block_hash != GENESIS_BLOCK_HASH: self.assertEqual(b.prev_block, last_block_hash) count += 1 last_block_hash = b.hash() if count % 2016 == 0: self.assertEqual(b.id(), expected.pop(0))
def test_example_1(self): node = SimpleNode('btc.programmingblockchain.com', testnet=False) node.handshake() last_block_hash = GENESIS_BLOCK_HASH first_epoch_block = None expected_bits = None count = 1 want = ('ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', 'ffff001d', '6ad8001d', '28c4001d') for bits in want: getheaders = GetHeadersMessage(start_block=last_block_hash) node.send(getheaders.command, getheaders.serialize()) headers_envelope = node.wait_for_commands([b'headers']) headers_message = HeadersMessage.parse(headers_envelope.stream()) for block in headers_message.blocks: if not block.check_pow(): raise RuntimeError( 'bad proof of work at block {}'.format(count)) if last_block_hash != GENESIS_BLOCK_HASH and block.prev_block != last_block_hash: raise RuntimeError( 'discontinuous block at {}'.format(count)) if expected_bits and block.bits != expected_bits: raise RuntimeError('bad bits at block {} {} vs {}'.format( count, block.bits.hex(), expected_bits.hex())) if first_epoch_block and count % 2016 == 2015: expected_bits = calculate_new_bits( expected_bits, block.timestamp - first_epoch_block.timestamp) self.assertEqual(expected_bits.hex(), bits) elif first_epoch_block is None: expected_bits = block.bits if count % 2016 == 0 or not first_epoch_block: first_epoch_block = block count += 1 last_block_hash = block.hash()
# node.send(getdata) # found = False # while not found: # message = node.wait_for(MerkleBlock, Tx) # if message.command == b'merkleblock': # if not message.is_valid(): # raise RuntimeError('invalid merkle proof') # else: # for i, tx_out in enumerate(message.tx_outs): # if tx_out.script_pubkey.address(testnet=True) == utxo_address: # print('found: {}:{}'.format(message.id(), i)) # found = True # break node.handshake() getdata = GetDataMessage() t = '1ca6b09df876b19f37548986f331a5360a472fc8a3604b19877dda83a6bfe326' t_bytes = bytes.fromhex(t) #getdata.add_data(BLOCK_DATA_TYPE, bytes.fromhex(block_hash_hex)) getdata.add_data(TX_DATA_TYPE, t_bytes) node.send(getdata) received_tx = node.wait_for(Tx) print(received_tx.id() == t_bytes.hex()) # print("Given: ", block_hash_hex) # while not found: # message = node.wait_for(Block) # if message.command == b'block': # received_block_hash = message.hash().hex()
def test_exercise_6(self): last_block_hex = '00000000000538d5c2246336644f9a4956551afb44ba47278759ec55ea912e19' secret = little_endian_to_int( hash256(b'Jimmy Song Programming Blockchain')) private_key = PrivateKey(secret=secret) addr = private_key.point.address(testnet=True) h160 = decode_base58(addr) target_address = 'mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv' self.assertEqual(addr, target_address) target_h160 = decode_base58(target_address) target_script = p2pkh_script(target_h160) fee = 5000 node = SimpleNode('tbtc.programmingblockchain.com', testnet=True) bf = BloomFilter(30, 5, 90210) bf.add(h160) node.handshake() node.send(b'filterload', bf.filterload()) start_block = bytes.fromhex(last_block_hex) getheaders_message = GetHeadersMessage(start_block=start_block) node.send(getheaders_message.command, getheaders_message.serialize()) headers_envelope = node.wait_for_commands({HeadersMessage.command}) stream = headers_envelope.stream() headers = HeadersMessage.parse(stream) last_block = None get_data_message = GetDataMessage() for b in headers.blocks: if not b.check_pow(): raise RuntimeError('proof of work is invalid') if last_block is not None and b.prev_block != last_block: raise RuntimeError('chain broken') get_data_message.add_data(FILTERED_BLOCK_DATA_TYPE, b.hash()) last_block = b.hash() node.send(get_data_message.command, get_data_message.serialize()) prev_tx, prev_index, prev_tx_obj = None, None, None while prev_tx is None: envelope = node.wait_for_commands({b'merkleblock', b'tx'}) stream = envelope.stream() if envelope.command == b'merkleblock': mb = MerkleBlock.parse(stream) if not mb.is_valid(): raise RuntimeError('invalid merkle proof') else: prev_tx_obj = Tx.parse(stream, testnet=True) for i, tx_out in enumerate(prev_tx_obj.tx_outs): if tx_out.script_pubkey.address(testnet=True) == addr: prev_tx = prev_tx_obj.hash() prev_index = i self.assertEqual( prev_tx_obj.id(), 'e3930e1e566ca9b75d53b0eb9acb7607f547e1182d1d22bd4b661cfe18dcddf1' ) self.assertEqual(i, 0) tx_in = TxIn(prev_tx, prev_index, Script([]), 0xffffff) TxFetcher.cache[prev_tx] = prev_tx_obj tx_ins = [tx_in] total = prev_tx_obj.tx_outs[prev_index].amount tx_outs = [TxOut(total - fee, target_script)] tx_obj = Tx(1, tx_ins, tx_outs, 0, testnet=True) tx_obj.sign_input(0, private_key) self.assertEqual( tx_obj.serialize().hex(), '0100000001f1dddc18fe1c664bbd221d2d18e147f50776cb9aebb0535db7a96c561e0e93e3000000006a473044022046a49962540a89e83da0636455b6c81c11c2844b7f3cd414c02e1a13741f4d15022006eed4eeda994d2bfebb9f1a494bfa3c8bab96e7e4c82623f4a29736dfe309e70121021cdd761c7eb1c90c0af0a5963e94bf0203176b4662778d32bd6d7ab5d8628b32ffffff0001a1629ef5000000001976a914ad346f8eb57dee9a37981716e498120ae80e44f788ac00000000' )
def test_handshake(self): node = SimpleNode('testnet.programmingbitcoin.com', testnet=True) node.handshake()