def test_exercise_4(self): prev_tx = bytes.fromhex( '75a1c4bc671f55f626dda1074c7725991e6f68b8fcefcfca7b64405ca3b45f1c') prev_index = 1 target_address = 'miKegze5FQNCnGw6PKyqUbYUeBa4x2hFeM' target_amount = 0.01 change_address = 'mzx5YhAH9kNHtcN481u6WkjeHjYtVeKVh2' change_amount = 0.009 secret = 8675309 priv = PrivateKey(secret=secret) tx_ins = [] tx_ins.append(TxIn(prev_tx, prev_index, Script([]), 0xffffffff)) tx_outs = [] h160 = decode_base58(target_address) script_pubkey = p2pkh_script(h160) target_satoshis = int(target_amount * 100000000) tx_outs.append(TxOut(target_satoshis, script_pubkey)) h160 = decode_base58(change_address) script_pubkey = p2pkh_script(h160) change_satoshis = int(change_amount * 100000000) tx_outs.append(TxOut(change_satoshis, script_pubkey)) tx_obj = Tx(1, tx_ins, tx_outs, 0, testnet=True) self.assertTrue(tx_obj.sign_input(0, priv)) self.assertTrue(tx_obj.verify()) want = '01000000011c5fb4a35c40647bcacfeffcb8686f1e9925774c07a1dd26f6551f67bcc4a175010000006b483045022100a08ebb92422b3599a2d2fcdaa11f8f807a66ccf33e7f4a9ff0a3c51f1b1ec5dd02205ed21dfede5925362b8d9833e908646c54be7ac6664e31650159e8f69b6ca539012103935581e52c354cd2f484fe8ed83af7a3097005b2f9c60bff71d35bd795f54b67ffffffff0240420f00000000001976a9141ec51b3654c1f1d0f4929d11a1f702937eaf50c888ac9fbb0d00000000001976a914d52ad7ca9b3d096a38e752c2018e6fbc40cdf26f88ac00000000' self.assertEqual(tx_obj.serialize().hex(), want)
def test_sign_input(self): private_key = PrivateKey(secret=8675309) tx_ins = [] prev_tx = bytes.fromhex( '0025bc3c0fa8b7eb55b9437fdbd016870d18e0df0ace7bc9864efc38414147c8') tx_ins.append( TxIn( prev_tx=prev_tx, prev_index=0, script_sig=Script([]), sequence=0xffffffff, )) tx_outs = [] h160 = decode_base58('mzx5YhAH9kNHtcN481u6WkjeHjYtVeKVh2') tx_outs.append( TxOut(amount=int(0.99 * 100000000), script_pubkey=p2pkh_script(h160))) h160 = decode_base58('mnrVtF8DWjMu839VW3rBfgYaAfKk8983Xf') tx_outs.append( TxOut(amount=int(0.1 * 100000000), script_pubkey=p2pkh_script(h160))) tx = Tx( version=1, tx_ins=tx_ins, tx_outs=tx_outs, locktime=0, testnet=True, ) self.assertTrue(tx.sign_input(0, private_key, SIGHASH_ALL))
def test_example_6(self): tx_ins = [] prev_tx = bytes.fromhex( '0d6fe5213c0b3291f208cba8bfb59b7476dffacc4e5cb66f6eb20a080843a299') prev_index = 13 tx_ins.append(TxIn(prev_tx, prev_index, Script([]), 0xffffffff)) tx_outs = [] change_amount = int(0.33 * 100000000) change_h160 = decode_base58('mzx5YhAH9kNHtcN481u6WkjeHjYtVeKVh2') change_script = p2pkh_script(change_h160) tx_outs.append(TxOut(amount=change_amount, script_pubkey=change_script)) target_amount = int(0.1 * 100000000) target_h160 = decode_base58('mnrVtF8DWjMu839VW3rBfgYaAfKk8983Xf') target_script = p2pkh_script(target_h160) tx_outs.append(TxOut(amount=target_amount, script_pubkey=target_script)) transaction = Tx(1, tx_ins, tx_outs, 0, testnet=True) z = transaction.sig_hash(0) private_key = PrivateKey(secret=8675309) der = private_key.sign(z).der() sig = der + SIGHASH_ALL.to_bytes(1, 'big') sec = private_key.point.sec() transaction.tx_ins[0].script_sig = Script([sig, sec]) want = '010000000199a24308080ab26e6fb65c4eccfadf76749bb5bfa8cb08f291320b3c21e56f0d0d0000006b4830450221008ed46aa2cf12d6d81065bfabe903670165b538f65ee9a3385e6327d80c66d3b502203124f804410527497329ec4715e18558082d489b218677bd029e7fa306a72236012103935581e52c354cd2f484fe8ed83af7a3097005b2f9c60bff71d35bd795f54b67ffffffff02408af701000000001976a914d52ad7ca9b3d096a38e752c2018e6fbc40cdf26f88ac80969800000000001976a914507b27411ccf7f16f10297de6cef3f291623eddf88ac00000000' self.assertEqual(transaction.serialize().hex(), want)
def new_commitment_tx(node, current_channel, cost, secret_hash): remote_peer = current_channel.peer # Create input using the output from the funding tx tx_in = TxIn(bytes.fromhex(current_channel.funding_tx.id()), 0) # Create 3 outputs. 1 to nodeA and 1 to nodeB and 1 to an HTLC script script_1 = p2pkh_script(decode_base58(node.address)) tx_out_1 = TxOut(amount=current_channel.local_amt - cost, script_pubkey=script_1) script_2 = p2pkh_script(decode_base58(remote_peer.btc_addr.decode())) tx_out_2 = TxOut(amount=current_channel.remote_amt, script_pubkey=script_2) #script_3 HTLC script_3 = Script([ 99, 168, secret_hash, 136, 118, 169, hash160(remote_peer.public_key.sec()), 103, encode_varint(1000), 177, 117, 118, 169, hash160(node.public_key.sec()), 104, 136, 172 ]) tx_out_3 = TxOut(amount=cost, script_pubkey=script_3) # Construct the commitment tx object commitment_tx = Tx(1, [tx_in], [tx_out_1, tx_out_2, tx_out_3], 0, True) #sign it commitment_tx.tx_ins[0].script_sig = get_script_sig( commitment_tx, node.private_key) return commitment_tx
def sig_hash_bip143(prev_tx, tx, txi, redeem_script=None, witness_script=None, testnet=False): """ bip143 1:04LE version 2:32 hash prevouts 3:32 hash sequence 4:32+4LE outpoint 5:* script_code of the input 6:08LE value of output spent 7:04LE n_sequence of the input 8:32 hash outputs 9:4LE n_locktime 10:4LE sighash """ s = util.int_to_little_endian(tx["version"], 4) # 1 hash_all_prevouts, hash_all_sequence = hash_all_txis(tx) s += hash_all_prevouts + hash_all_sequence # 2,3 s += txi["txid"][::-1] + util.int_to_little_endian(txi["idx"], 4) # 4 # 5 if witness_script: script_code = script.serialize(witness_script) elif redeem_script: script_code = script.serialize(script.p2pkh_script(redeem_script[1])) else: script_code = script.serialize(script.p2pkh_script(prev_tx["txos"][txi["idx"]]["script"][1])) s += script_code s += util.int_to_little_endian(prev_tx["txos"][txi["idx"]]["amount"], 8) # 6 s += util.int_to_little_endian(txi["seq.no"], 4) # 7 s += hash_all_txos(tx) # 8 s += util.int_to_little_endian(tx["locktime"], 4) # 9 s += util.int_to_little_endian(util.SIGHASH_ALL, 4) # 10 return int.from_bytes(util.hash256(s), 'big')
def test_example_1(self): tx_ins = [] prev_tx = bytes.fromhex( '8be2f69037de71e3bc856a6627ed3e222a7a2d0ce81daeeb54a3aea8db274149') prev_index = 4 tx_ins.append(TxIn(prev_tx, prev_index)) tx_outs = [] h160 = decode_base58('mzx5YhAH9kNHtcN481u6WkjeHjYtVeKVh2') tx_outs.append( TxOut( amount=int(0.38 * 100000000), script_pubkey=p2pkh_script(h160), )) h160 = decode_base58('mnrVtF8DWjMu839VW3rBfgYaAfKk8983Xf') tx_outs.append( TxOut( amount=int(0.1 * 100000000), script_pubkey=p2pkh_script(h160), )) tx_obj = Tx(1, tx_ins, tx_outs, 0, testnet=True) z = tx_obj.sig_hash(0) pk = PrivateKey(secret=8675309) der = pk.sign(z).der() sig = der + SIGHASH_ALL.to_bytes(1, 'big') sec = pk.point.sec() tx_obj.tx_ins[0].script_sig = Script([sig, sec]) want = '0100000001494127dba8aea354ebae1de80c2d7a2a223eed27666a85bce371de3790f6e28b040000006b483045022100fa3032607b50e8cb05bedc9d43f986f19dedc22e61320b9765061c5cd9c66946022072d514ef637988515bfa59a660596206de68f0ed4090d0a398e70f4d81370dfb012103935581e52c354cd2f484fe8ed83af7a3097005b2f9c60bff71d35bd795f54b67ffffffff0280d54302000000001976a914d52ad7ca9b3d096a38e752c2018e6fbc40cdf26f88ac80969800000000001976a914507b27411ccf7f16f10297de6cef3f291623eddf88ac00000000' self.assertEqual(tx_obj.serialize().hex(), want)
def sig_hash_bip143(self, input_index, redeem_script=None, witness_script=None): '''Returns the integer representation of the hash that needs to get signed for index input_index''' tx_in = self.tx_ins[input_index] # per BIP143 spec s = int_to_little_endian(self.version, 4) s += self.hash_prevouts() + self.hash_sequence() s += tx_in.prev_tx[::-1] + int_to_little_endian(tx_in.prev_index, 4) if witness_script: script_code = witness_script.serialize() elif redeem_script: script_code = p2pkh_script(redeem_script.cmds[1]).serialize() else: script_code = p2pkh_script( tx_in.script_pubkey(self.testnet).cmds[1]).serialize() s += script_code s += int_to_little_endian(tx_in.value(), 8) s += int_to_little_endian(tx_in.sequence, 4) s += self.hash_outputs() s += int_to_little_endian(self.locktime, 4) s += int_to_little_endian(SIGHASH_ALL, 4) return int.from_bytes(hash256(s), 'big')
def get_output_info(num_outputs, amount_available): tx_outs = [] amount = amount_available for i in range(num_outputs): target_address = input("Enter address of recipient: ") target_h160 = decode_base58(target_address) valid_amount = False target_amount = int(float(input("How much would you like to pay them (in tBTC)? ")) * sat_in_bit) while(valid_amount == False): if(target_amount > amount): print("Insufficient Funds") target_amount = int(float(input("How much would you like to pay them (in tBTC)? ")) * sat_in_bit) else: print("Sufficient Funds") valid_amount = True amount = amount - target_amount print(str(amount/sat_in_bit)+" tBTC remaining") if(target_address[0]=='2'): print("This recipient is a P2SH") target_script = p2sh_script(target_h160) tx_outs.append(TxOut(amount = target_amount, script_pubkey = target_script)) else: print("This recipient is a P2PKH") target_script = p2pkh_script(target_h160) tx_outs.append(TxOut(amount = target_amount, script_pubkey = target_script)) if(amount > 0): print("There is a remainder of "+str(amount/sat_in_bit)+" tBTC. Please fill in recipient details:") target_address = input("Enter address of recipient: ") target_h160 = decode_base58(target_address) target_amount = amount if(target_address[0]=='2'): print("This recipient is a P2SH") target_script = p2sh_script(target_h160) tx_outs.append(TxOut(amount = target_amount, script_pubkey = target_script)) else: print("This recipient is a P2PKH") target_script = p2pkh_script(target_h160) tx_outs.append(TxOut(amount = target_amount, script_pubkey = target_script)) return tx_outs
def test_exercise_5(self): prev_tx_1 = bytes.fromhex( '11d05ce707c1120248370d1cbf5561d22c4f83aeba0436792c82e0bd57fe2a2f') prev_index_1 = 1 prev_tx_2 = bytes.fromhex( '51f61f77bd061b9a0da60d4bedaaf1b1fad0c11e65fdc744797ee22d20b03d15') prev_index_2 = 1 target_address = 'mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv' target_amount = 0.0429 secret = 8675309 priv = PrivateKey(secret=secret) tx_ins = [] tx_ins.append(TxIn(prev_tx_1, prev_index_1, Script([]), 0xffffffff)) tx_ins.append(TxIn(prev_tx_2, prev_index_2, Script([]), 0xffffffff)) tx_outs = [] h160 = decode_base58(target_address) script_pubkey = p2pkh_script(h160) target_satoshis = int(target_amount * 100000000) tx_outs.append(TxOut(target_satoshis, script_pubkey)) tx_obj = Tx(1, tx_ins, tx_outs, 0, testnet=True) self.assertTrue(tx_obj.sign_input(0, priv)) self.assertTrue(tx_obj.sign_input(1, priv)) self.assertTrue(tx_obj.verify()) want = '01000000022f2afe57bde0822c793604baae834f2cd26155bf1c0d37480212c107e75cd011010000006a47304402204cc5fe11b2b025f8fc9f6073b5e3942883bbba266b71751068badeb8f11f0364022070178363f5dea4149581a4b9b9dbad91ec1fd990e3fa14f9de3ccb421fa5b269012103935581e52c354cd2f484fe8ed83af7a3097005b2f9c60bff71d35bd795f54b67ffffffff153db0202de27e7944c7fd651ec1d0fab1f1aaed4b0da60d9a1b06bd771ff651010000006b483045022100b7a938d4679aa7271f0d32d83b61a85eb0180cf1261d44feaad23dfd9799dafb02205ff2f366ddd9555f7146861a8298b7636be8b292090a224c5dc84268480d8be1012103935581e52c354cd2f484fe8ed83af7a3097005b2f9c60bff71d35bd795f54b67ffffffff01d0754100000000001976a914ad346f8eb57dee9a37981716e498120ae80e44f788ac00000000' self.assertEqual(tx_obj.serialize().hex(), want)
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_example_5(self): tx_ins = [] prev_tx = bytes.fromhex('0d6fe5213c0b3291f208cba8bfb59b7476dffacc4e5cb66f6eb20a080843a299') prev_index = 13 tx_ins.append(TxIn(prev_tx, prev_index, Script([]), 0xffffffff)) tx_outs = [] change_amount = int(0.33 * 100000000) change_h160 = decode_base58('mzx5YhAH9kNHtcN481u6WkjeHjYtVeKVh2') change_script = p2pkh_script(change_h160) tx_outs.append(TxOut(change_amount, change_script)) target_amount = int(0.1 * 100000000) target_h160 = decode_base58('mnrVtF8DWjMu839VW3rBfgYaAfKk8983Xf') target_script = p2pkh_script(target_h160) tx_outs.append(TxOut(target_amount, target_script)) transaction = Tx(1, tx_ins, tx_outs, 0, testnet=True) want = '010000000199a24308080ab26e6fb65c4eccfadf76749bb5bfa8cb08f291320b3c21e56f0d0d00000000ffffffff02408af701000000001976a914d52ad7ca9b3d096a38e752c2018e6fbc40cdf26f88ac80969800000000001976a914507b27411ccf7f16f10297de6cef3f291623eddf88ac00000000' self.assertEqual(transaction.serialize().hex(), want)
def sig_hash_bip143(self, input_index, redeem_script=None, witness_script=None): '''Returns the integer representation of the hash that needs to get signed for index input_index''' tx_in = self.tx_ins[input_index] print("****** in sig_hash_bip143") # per BIP143 spec s = int_to_little_endian(self.version, 4) # applicable to all tx_ins in this tx s += self.hash_prevouts() + self.hash_sequence( ) # applicable to all tx_ins in this tx s += tx_in.prev_tx[::-1] + int_to_little_endian( tx_in.prev_index, 4) # specific to this tx_in # # Setting the script_code: # # If there is a witness_script, then the situation is either a p2wsh # or a p2sh-p2wsh. Use the witnesss script to make the script_code: if witness_script: script_code = witness_script.serialize() # If there is a redeem_script, then the situation is a p2sh-p2wpkh. # Make the script_code from the hash in the redeem_script-which is the # 20-byte public key hash. elif redeem_script: script_code = p2pkh_script(redeem_script.cmds[1]).serialize() # If no witness_script or redeem_script, the situation is a straight # p2wpkh. Use the 20 byte hash from the utxo script_pubkey. else: script_code = p2pkh_script( tx_in.script_pubkey(self.testnet).cmds[1]).serialize() s += script_code # specific to this tx_ins s += int_to_little_endian(tx_in.value(), 8) # specific to this tx_ins s += int_to_little_endian(tx_in.sequence, 4) # specific to this tx_ins s += self.hash_outputs() # applicable to all tx_ins in this tx s += int_to_little_endian(self.locktime, 4) # applicable to all tx_ins in this tx s += int_to_little_endian(SIGHASH_ALL, 4) # applicable to all tx_ins in this tx print("****** out sig_hash_bip143") return int.from_bytes(hash256(s), 'big')
def send(self, adddress, amount, fee=500): # collect inputs unspent = self.unspent() tx_ins = [] input_sum = 0 for utxo in unspent: if input_sum >= amount + fee: break input_sum += utxo.amount tx_in = TxIn(utxo.tx_id, utxo.index) tx_ins.append(tx_in) # make sure we have enough assert input_sum > amount + fee, 'not enough satoshis' # send output send_h160 = decode_base58(address) send_script = p2pkh_script(send_h160) send_output = TxOut(amount=amount, script_pubkey=send_script) # change output change_amount = input_sum - amount - fee change_h160 = decode_base58(self.address()) change_script = p2pkh_script(change_h160) change_output = TxOut(amount=amount, script_pubkey=change_script) # construct tx = Tx(1, tx_ins, [send_output, change_output], 0, True) # sign for i in range(len(tx_ins)): utxo = unspent[i] assert tx.sign_input(i, self.private_key, utxo.script_pubkey) print(f'signed {i}') print(tx) # broadcast import bit tx_hex = tx.serialize().hex() print(tx_hex) # raises a ConnectionError if it fails print(bit.network.NetworkAPI.broadcast_tx_testnet(tx_hex))
def test_exercise_3_1(self): prev_tx = bytes.fromhex( 'eb581753a4dbd6befeaaaa28a6f4576698ba13a07c03da693a65bce11cf9887a') prev_index = 1 target_address = 'mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv' target_amount = 0.04 change_address = 'mzx5YhAH9kNHtcN481u6WkjeHjYtVeKVh2' fee = 50000 secret = 8675309 private_key = PrivateKey(secret=secret) tx_ins = [] tx_ins.append(TxIn(prev_tx, prev_index)) tx_outs = [] h160 = decode_base58(target_address) script_pubkey = p2pkh_script(h160) target_satoshis = int(target_amount * 100000000) tx_outs.append(TxOut(target_satoshis, script_pubkey)) h160 = decode_base58(change_address) script_pubkey = p2pkh_script(h160) prev_amount = tx_ins[0].value(testnet=True) change_satoshis = prev_amount - target_satoshis - fee tx_outs.append(TxOut(change_satoshis, script_pubkey)) tx_obj = Tx(1, tx_ins, tx_outs, 0, testnet=True) tx_obj.sign_input(0, private_key) if private_key.point.address(testnet=True) != change_address: raise RuntimeError( 'Private Key does not correspond to Change Address, check priv_key and change_address' ) if tx_ins[0].script_pubkey( testnet=True).instructions[2] != decode_base58(change_address): raise RuntimeError( 'Output is not something you can spend with this private key. Check that the prev_tx and prev_index are correct' ) if tx_obj.fee() > 0.05 * 100000000 or tx_obj.fee() <= 0: raise RuntimeError( 'Check that the change amount is reasonable. Fee is {}'.format( tx_obj.fee())) self.assertEqual( tx_obj.serialize().hex(), '01000000017a88f91ce1bc653a69da037ca013ba986657f4a628aaaafebed6dba4531758eb010000006a47304402204ce6e3877ed2e18d2165276cbdba241507ce72b44d8df640eb6cb4d415eaaea002207dffd162da35593d86188ce87a1cbc9d3a5b26391870f19bf1764ca05b315ad9012103935581e52c354cd2f484fe8ed83af7a3097005b2f9c60bff71d35bd795f54b67ffffffff0200093d00000000001976a914ad346f8eb57dee9a37981716e498120ae80e44f788ac7077e401000000001976a914d52ad7ca9b3d096a38e752c2018e6fbc40cdf26f88ac00000000' )
def test_address(self): address_1 = '1BenRpVUFK65JFWcQSuHnJKzc4M8ZP8Eqa' h160 = decode_base58(address_1) p2pkh_script_pubkey = p2pkh_script(h160) self.assertEqual(p2pkh_script_pubkey.address(), address_1) address_2 = 'mrAjisaT4LXL5MzE81sfcDYKU3wqWSvf9q' self.assertEqual(p2pkh_script_pubkey.address(testnet=True), address_2) address_3 = '3CLoMMyuoDQTPRD3XYZtCvgvkadrAdvdXh' h160 = decode_base58(address_3) p2sh_script_pubkey = p2sh_script(h160) self.assertEqual(p2sh_script_pubkey.address(), address_3) address_4 = '2N3u1R6uwQfuobCqbCgBkpsgBxvr1tZpe7B' self.assertEqual(p2sh_script_pubkey.address(testnet=True), address_4)
def test_exercise_3_2(self): prev_tx_1 = bytes.fromhex( '89cbfe2eddaddf1eb11f5c4adf6adaa9bca4adc01b2a3d03f8dd36125c068af4') prev_index_1 = 0 prev_tx_2 = bytes.fromhex( '19069e1304d95f70e03311d9d58ee821e0978e83ecfc47a30af7cd10fca55cf4') prev_index_2 = 0 target_address = 'mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv' fee = 50000 secret = 61740721216174072121 private_key = PrivateKey(secret=secret) tx_ins = [] tx_ins.append(TxIn(prev_tx_1, prev_index_1)) tx_ins.append(TxIn(prev_tx_2, prev_index_2)) tx_outs = [] h160 = decode_base58(target_address) script_pubkey = p2pkh_script(h160) target_satoshis = tx_ins[0].value(True) + tx_ins[1].value(True) - fee tx_outs.append(TxOut(target_satoshis, script_pubkey)) tx_obj = Tx(1, tx_ins, tx_outs, 0, testnet=True) tx_obj.sign_input(0, private_key) tx_obj.sign_input(1, private_key) if tx_ins[0].script_pubkey( testnet=True).instructions[2] != decode_base58( private_key.point.address(testnet=True)): raise RuntimeError( 'Output is not something you can spend with this private key. Check that the prev_tx and prev_index are correct' ) if tx_obj.fee() > 0.05 * 100000000 or tx_obj.fee() <= 0: raise RuntimeError( 'Check that the change amount is reasonable. Fee is {}'.format( tx_obj.fee())) self.assertEqual( tx_obj.serialize().hex(), '0100000002f48a065c1236ddf8033d2a1bc0ada4bca9da6adf4a5c1fb11edfaddd2efecb89000000006a47304402204b9ee431a2f5deaefb5282a34d7dcfdb47d55b1e3ce00cac4c6b6e6f0f0e8d58022062710e84786d2c6c89ddda5a149b45088b15230c6b825f0f21490f99bd74c81d012103f96f3a1efd31e1a8d7078118ee56bff7355d58907ce0f865f5f0b3dbe34e55befffffffff45ca5fc10cdf70aa347fcec838e97e021e88ed5d91133e0705fd904139e0619000000006a473044022073d7217b2d582e55978284c2628015a14e3490e835c76488eb29b63de15d17920220384e4b5282c911273efd4d98170e7092e10a729d142db17f4725c15364fa4ecc012103f96f3a1efd31e1a8d7078118ee56bff7355d58907ce0f865f5f0b3dbe34e55beffffffff01021f320a000000001976a914ad346f8eb57dee9a37981716e498120ae80e44f788ac00000000' )
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_create_legacy_tx(): # to_alice = total_amount - to_bob - fee txo_amount = 0.01750649 tx_fee = 0.0005 to_bob = 0.005 sat_amount = int(txo_amount * 10 ** 8) sat_tx_fee = int(tx_fee * 10 ** 8) sat_to_bob = int(to_bob * 10 ** 8) sat_to_alice = sat_amount - sat_to_bob - sat_tx_fee # add txo: to alice alice = 'mxFMySFd6tkjnomB1LgGC85i5hvwGtaFiW' h160 = util.decode_base58(alice) print(h160.hex()) lock_script = script.p2pkh_script(h160) txo_0 = { "amount": sat_to_alice, "script": lock_script } # add txo: to bob bob = "mtTt5dA1vbELiycUagedatkPQRm1QseoCa" h160 = util.decode_base58(bob) print(h160.hex()) lock_script = script.p2pkh_script(h160) txo_1 = { "amount": sat_to_bob, "script": lock_script } # add_txi txid = "dd21423466a93ccca9ea5b548e0c19efcfc3aee41036a90102bca600cd9260fb" # "asm": "OP_DUP OP_HASH160 e4c8b088f49dbc6a2248400e5002d2a29aed6953 OP_EQUALVERIFY OP_CHECKSIG", # generate unlock script prev_tx = tx.fetch(bytes.fromhex(txid), True) print(prev_tx) for i, txo in enumerate(prev_tx['txos']): if script.is_p2pkh(txo['script']): print(i, "p2pkh") elif script.is_p2sh(txo['script']): print(i, "p2sh") elif script.is_p2wpkh(txo['script']): print(i, "p2wpkh") elif script.is_p2wsh(txo['script']): print(i, "pswsh") # lock_script: p2pkh txi_0 = { "txid": bytes.fromhex(txid), "idx": 1, "script": [], "seq.no": 0 } tx_obj = { "version": 1, # "mark": None, # "flag": None, "txi.count": 1, "txis": [txi_0], "txo.count": 2, "txos": [txo_0, txo_1], # "wits": None, "locktime": 0 } # alice's 'sec_key': 947605268396919657983759089664, sec_key = 947605268396919657983759089664 z = tx.sig_hash(tx_obj, 0, prev_tx["txos"][1]["script"]) print(z) sig = ecc.sig(sec_key, z) der = ecc.sig_der(sig) pub_key = ecc.ecc_mul(sec_key) sec = ecc.sec(pub_key[0], pub_key[1], False) print(sec) sig_with_type = der + util.SIGHASH_ALL.to_bytes(1, 'big') txi_0["script"] = [sig_with_type, sec] print(tx_obj) new_tx_bytes = tx.serialize(tx_obj) print(new_tx_bytes.hex()) # tx verification stream = BytesIO(new_tx_bytes) tx_obj = tx.parse(stream) print(tx_obj) tx.verify(tx_obj, testnet=True) return new_tx_bytes
# UTXO that we gonna receive prev_tx = bytes.fromhex( '1ed5583812bda08b71a71c2fa1e6788dac956efa9d2c26b6c9fd10f6e885658f') prev_index = 1 # create the txin with the output of the UTXO we have been given tx_in = TxIn(prev_tx, prev_index) tx_outs = [] change_amount = int(0.00003 * 100000000) # output address that will receive the sat we have not spend change_h160 = decode_base58('mvEg6eZ3sUApodedYQrkpEPMMALsr1K1k1') change_script = p2pkh_script(change_h160) change_output = TxOut(amount=change_amount, script_pubkey=change_script) # output address that will receive our sat target_amount = int(0.00006 * 100000000) target_h160 = decode_base58('mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv') target_script = p2pkh_script(target_h160) target_output = TxOut(amount=target_amount, script_pubkey=target_script) tx_obj = Tx(1, [tx_in], [change_output, target_output], 0, True) #print(tx_obj).hex() # now we sign the transaction z = tx_obj.sig_hash(0)
tx_previa = bytes.fromhex( 'b685879f3939fa9531899b729394ed85edab8b6850b72a9e378ea31af96a304a') index_tx_previa = 1 tx_inputs = [] tx_inputs.append(TxIn(tx_previa, index_tx_previa)) #OUPUTS tx_outputs = [] destinatario = 'mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB' monto = .00008 change_adress = ADDRESS cambio = .00001 #SEND OUTPUT h160 = decode_base58(destinatario) script_pubkey = p2pkh_script(h160) monto_satoshis = int(monto * 100_000_000) tx_outputs.append(TxOut(monto_satoshis, script_pubkey)) #CHANGE OUPUT h160 = decode_base58(change_adress) script_pubkey = p2pkh_script(h160) cambio_satoshis = int(cambio * 100_000_000) tx_outputs.append(TxOut(cambio_satoshis, script_pubkey)) #TX BUILD TX_BUILD = Tx(1, tx_inputs, tx_outputs, 0, testnet=True) #SIGN print(TX_BUILD.sign_input(0, PrivKey)) print(TX_BUILD.serialize().hex())
def pubkey_to_p2pkh_script(cls, pubkey): h160 = pubkey.hash160() return p2pkh_script(h160)
pay_private_key = PrivateKey(pay_secret) output_address = pay_private_key.point.address(testnet=True) # out1_address resulting from the above pay_secret # out1_address = 'mgbxvp8L3o5zbw8P81VWVv42gUj9eZNjAN' change_secret = 9883161471906162552674337436001522581212416354973578695250248738884382136882 #secret = random.getrandbits(256) change_private_key = PrivateKey(change_secret) change_address = change_private_key.point.address(testnet=True) paying_amount = prev_tx_obj.tx_outs[0].amount paid_amount = math.floor(paying_amount * .1) fee = math.floor(paid_amount * .1) change_amount = paying_amount - paid_amount - fee paid_script = p2pkh_script(decode_base58(output_address)) change_script = p2pkh_script(decode_base58(change_address)) tx_out_paid = TxOut(paid_amount, paid_script) tx_out_change = TxOut(change_amount, change_script) tx = Tx(1, [txi], [tx_out_paid, tx_out_change], 0, True) print(tx) print(tx.sign_input(input_index=0, private_key=input_private_key)) print(tx) print("tx_in script...") print(tx.tx_ins[0].script_sig) print(tx.serialize().hex())
def construct_tx_out(address, amount): h160 = decode_base58(address) script = p2pkh_script(h160) return TxOut(amount=amount, script_pubkey=script)
'df29440e796ff7e843d643380d00b79f0d6dab55c84a983849b04f9a8025f072') prev_index1 = 0 prev_tx2 = bytes.fromhex( 'df29440e796ff7e843d643380d00b79f0d6dab55c84a983849b04f9a8025f072') prev_index2 = 0 # create the txin with the output of the UTXO we have been given tx_in1 = TxIn(prev_tx1, prev_index1) tx_in2 = TxIn(prev_tx1, prev_index1) target_amount = int(9000) # output address that will receive the sat we have not spend target_h160 = decode_base58('mvEg6eZ3sUApodedYQrkpEPMMALsr1K1k1') target_script = p2pkh_script(target_h160) target_output = TxOut(amount=target_amount, script_pubkey=target_script) # output address that will receive our sat target_script = p2pkh_script(target_h160) target_output = TxOut(amount=target_amount, script_pubkey=target_script) tx_obj = Tx(1, [tx_in], [target_output], 0, True) #print(tx_obj).hex() # now we sign the transaction z = tx_obj.sig_hash(0) private_key = PrivateKey(little_endian_to_int( hash256(b'dat_test_private_key'))) der = private_key.sign(z).der()
def test_broadcast(self): from bloomfilter import BloomFilter last_block_hex = '00000000000000a03f9432ac63813c6710bfe41712ac5ef6faab093fe2917636' secret = little_endian_to_int(hash256(b'Jimmy Song')) private_key = PrivateKey(secret=secret) h160 = private_key.point.hash160() addr = private_key.point.address(testnet=True) target_address = 'mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv' target_h160 = decode_base58(target_address) target_script = p2pkh_script(target_h160) fee = 5000 # fee in satoshis # connect to programmingblockchain.com in testnet mode node = SimpleNode('programmingblockchain.com', testnet=True) # create a bloom filter of size 30 and 5 functions. Add a tweak. bf = BloomFilter(30, 5, 90210) # add the h160 to the bloom filter bf.add(h160) # load the bloom filter with the filterload command node.send(bf.filterload()) # set start block to last_block from above start_block = bytes.fromhex(last_block_hex) # send a getheaders message with the starting block getheaders = GetHeadersMessage(start_block=start_block) node.send(getheaders) # wait for the headers message headers = node.wait_for(HeadersMessage) block_hashes = [b.hash() for b in headers.blocks] # initialize prev_tx, prev_index and prev_amount to None prev_tx, prev_index, prev_amount = None, None, None for h, tx_obj in node.get_filtered_block_txs(block_hashes): self.assertEqual(h, tx_obj.hash()) tx_obj.testnet = True # loop through the tx outs for i, tx_out in enumerate(tx_obj.tx_outs): # if our output has the same address as our address we found it if tx_out.script_pubkey.address(testnet=True) == addr: # we found our utxo. set prev_tx, prev_index, and tx prev_tx = h prev_index = i prev_amount = tx_out.amount self.assertEqual( h.hex(), 'b2cddd41d18d00910f88c31aa58c6816a190b8fc30fe7c665e1cd2ec60efdf3f' ) self.assertEqual(i, 7) break if prev_tx: break # create the TxIn tx_in = TxIn(prev_tx, prev_index) # calculate the output amount (previous amount minus the fee) output_amount = prev_amount - fee # create a new TxOut to the target script with the output amount tx_out = TxOut(output_amount, target_script) # create a new transaction with the one input and one output tx_obj = Tx(1, [tx_in], [tx_out], 0, testnet=True) # sign the only input of the transaction self.assertTrue(tx_obj.sign_input_p2pkh(0, private_key)) # serialize and hex to see what it looks like want = '01000000013fdfef60ecd21c5e667cfe30fcb890a116688ca51ac3880f91008dd141ddcdb2070000006b483045022100ff77d2559261df5490ed00d231099c4b8ea867e6ccfe8e3e6d077313ed4f1428022033a1db8d69eb0dc376f89684d1ed1be75719888090388a16f1e8eedeb8067768012103dc585d46cfca73f3a75ba1ef0c5756a21c1924587480700c6eb64e3f75d22083ffffffff019334e500000000001976a914ad346f8eb57dee9a37981716e498120ae80e44f788ac00000000' self.assertEqual(tx_obj.serialize().hex(), want) # send this signed transaction on the network node.send_tx(tx_obj)
def output_from_address(cls, address, amount): # creates an output from the Base 58 Checksum string # the Base 58 Checksum string is what a payor would receive from the payee hash160_bytes = decode_base58(address) script_pub_key = p2pkh_script(hash160_bytes) return cls(amount, script_pub_key)