|
60 | 60 | ... little_endian_to_int,
|
61 | 61 | ... read_varint,
|
62 | 62 | ... SIGHASH_ALL,
|
63 |
| ->>> ) |
| 63 | +... ) |
64 | 64 | >>> from merkleblock import MerkleBlock
|
65 | 65 | >>> from network import (
|
66 | 66 | ... GetDataMessage,
|
|
70 | 70 | ... SimpleNode,
|
71 | 71 | ... TX_DATA_TYPE,
|
72 | 72 | ... FILTERED_BLOCK_DATA_TYPE,
|
73 |
| ->>> ) |
| 73 | +... ) |
74 | 74 | >>> from script import p2pkh_script, Script
|
75 | 75 | >>> from tx import Tx, TxIn, TxOut, TxFetcher
|
76 |
| ->>> last_block_hex = '00000000000538d5c2246336644f9a4956551afb44ba47278759ec55\ |
77 |
| -ea912e19' |
78 |
| ->>> secret = little_endian_to_int(hash256(b'')) |
| 76 | +>>> last_block_hex = '00000000000000a03f9432ac63813c6710bfe41712ac5ef6faab093f\ |
| 77 | +e2917636' |
| 78 | +>>> secret = little_endian_to_int(hash256(b'Jimmy Song')) |
79 | 79 | >>> private_key = PrivateKey(secret=secret)
|
80 | 80 | >>> addr = private_key.point.address(testnet=True)
|
81 | 81 | >>> h160 = decode_base58(addr)
|
82 | 82 | >>> target_address = 'mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv'
|
83 | 83 | >>> target_h160 = decode_base58(target_address)
|
84 | 84 | >>> target_script = p2pkh_script(target_h160)
|
85 | 85 | >>> fee = 5000 # fee in satoshis
|
| 86 | +>>> # connect to tbtc.programmingblockchain.com in testnet mode |
86 | 87 | >>> node = SimpleNode('tbtc.programmingblockchain.com', testnet=True, logging=\
|
87 |
| -True) |
| 88 | +False) |
| 89 | +>>> # create a bloom filter of size 30 and 5 functions. Add a tweak. |
88 | 90 | >>> bf = BloomFilter(30, 5, 90210)
|
| 91 | +>>> # add the h160 to the bloom filter |
89 | 92 | >>> bf.add(h160)
|
| 93 | +>>> # complete the handshake |
90 | 94 | >>> node.handshake()
|
| 95 | +>>> # load the bloom filter with the filterload command |
91 | 96 | >>> node.send(bf.filterload())
|
| 97 | +>>> # set start block to last_block from above |
92 | 98 | >>> start_block = bytes.fromhex(last_block_hex)
|
| 99 | +>>> # send a getheaders message with the starting block |
93 | 100 | >>> getheaders = GetHeadersMessage(start_block=start_block)
|
94 | 101 | >>> node.send(getheaders)
|
| 102 | +>>> # wait for the headers message |
95 | 103 | >>> headers = node.wait_for(HeadersMessage)
|
| 104 | +>>> # store the last block as None |
96 | 105 | >>> last_block = None
|
| 106 | +>>> # initialize the GetDataMessage |
97 | 107 | >>> getdata = GetDataMessage()
|
| 108 | +>>> # loop through the blocks in the headers |
98 | 109 | >>> for b in headers.blocks:
|
| 110 | +... # check that the proof of work on the block is valid |
99 | 111 | ... if not b.check_pow():
|
100 | 112 | ... raise RuntimeError('proof of work is invalid')
|
| 113 | +... # check that this block's prev_block is the last block |
101 | 114 | ... if last_block is not None and b.prev_block != last_block:
|
102 | 115 | ... raise RuntimeError('chain broken')
|
| 116 | +... # add a new item to the getdata message |
| 117 | +... # should be FILTERED_BLOCK_DATA_TYPE and block hash |
103 | 118 | ... getdata.add_data(FILTERED_BLOCK_DATA_TYPE, b.hash())
|
| 119 | +... # set the last block to the current hash |
104 | 120 | ... last_block = b.hash()
|
| 121 | +>>> # send the getdata message |
105 | 122 | >>> node.send(getdata)
|
106 |
| ->>> prev_tx, prev_index = None, None |
| 123 | +>>> # initialize prev_tx, prev_index and prev_amount to None |
| 124 | +>>> prev_tx, prev_index, prev_amount = None, None, None |
| 125 | +>>> # loop while prev_tx is None |
107 | 126 | >>> while prev_tx is None:
|
| 127 | +... # wait for the merkleblock or tx commands |
108 | 128 | ... message = node.wait_for(MerkleBlock, Tx)
|
| 129 | +... # if we have the merkleblock command |
109 | 130 | ... if message.command == b'merkleblock':
|
| 131 | +... # check that the MerkleBlock is valid |
110 | 132 | ... if not message.is_valid():
|
111 | 133 | ... raise RuntimeError('invalid merkle proof')
|
| 134 | +... # else we have the tx command |
112 | 135 | ... else:
|
| 136 | +... # set the tx's testnet to be True |
113 | 137 | ... message.testnet = True
|
| 138 | +... # loop through the tx outs |
114 | 139 | ... for i, tx_out in enumerate(message.tx_outs):
|
| 140 | +... # if our output has the same address as our address we found it |
115 | 141 | ... if tx_out.script_pubkey.address(testnet=True) == addr:
|
| 142 | +... # we found our utxo. set prev_tx, prev_index, and tx |
116 | 143 | ... prev_tx = message.hash()
|
117 | 144 | ... prev_index = i
|
| 145 | +... prev_amount = tx_out.amount |
118 | 146 | ... print('found: {}:{}'.format(prev_tx.hex(), prev_index))
|
| 147 | +found: b2cddd41d18d00910f88c31aa58c6816a190b8fc30fe7c665e1cd2ec60efdf3f:7 |
| 148 | +>>> # create the TxIn |
119 | 149 | >>> tx_in = TxIn(prev_tx, prev_index)
|
| 150 | +>>> # calculate the output amount (previous amount minus the fee) |
120 | 151 | >>> output_amount = prev_amount - fee
|
121 |
| ->>> tx_outs = TxOut(output_amount, target_script) |
| 152 | +>>> # create a new TxOut to the target script with the output amount |
| 153 | +>>> tx_out = TxOut(output_amount, target_script) |
| 154 | +>>> # create a new transaction with the one input and one output |
122 | 155 | >>> tx_obj = Tx(1, [tx_in], [tx_out], 0, testnet=True)
|
123 |
| ->>> tx_obj.sign_input(0, private_key) |
| 156 | +>>> # sign the only input of the transaction |
| 157 | +>>> print(tx_obj.sign_input(0, private_key)) |
| 158 | +True |
| 159 | +>>> # serialize and hex to see what it looks like |
124 | 160 | >>> print(tx_obj.serialize().hex())
|
125 |
| -010000000194e631abb9e1079ec72a1616a3aa0111c614e65b96a6a4420e2cc6af9e6cc96e0000\ |
126 |
| -00006a47304402203cc8c56abe1c0dd043afa9eb125dafbebdde2dd4cd7abf0fb1aae0667a2200\ |
127 |
| -6e02203c95b74d0f0735bbf1b261d36e077515b6939fc088b9d7c1b7030a5e494596330121021c\ |
128 |
| -dd761c7eb1c90c0af0a5963e94bf0203176b4662778d32bd6d7ab5d8628b32ffffffff01f88298\ |
129 |
| -00000000001976a914ad346f8eb57dee9a37981716e498120ae80e44f788ac00000000 |
| 161 | +01000000013fdfef60ecd21c5e667cfe30fcb890a116688ca51ac3880f91008dd141ddcdb20700\ |
| 162 | +00006b483045022100ff77d2559261df5490ed00d231099c4b8ea867e6ccfe8e3e6d077313ed4f\ |
| 163 | +1428022033a1db8d69eb0dc376f89684d1ed1be75719888090388a16f1e8eedeb8067768012103\ |
| 164 | +dc585d46cfca73f3a75ba1ef0c5756a21c1924587480700c6eb64e3f75d22083ffffffff019334\ |
| 165 | +e500000000001976a914ad346f8eb57dee9a37981716e498120ae80e44f788ac00000000 |
| 166 | +>>> # send this signed transaction on the network |
130 | 167 | >>> node.send(tx_obj)
|
| 168 | +>>> # wait a sec so this message goes through with time.sleep(1) |
131 | 169 | >>> time.sleep(1)
|
| 170 | +>>> # now ask for this transaction from the other node |
| 171 | +>>> # create a GetDataMessage |
132 | 172 | >>> getdata = GetDataMessage()
|
| 173 | +>>> # ask for our transaction by adding it to the message |
133 | 174 | >>> getdata.add_data(TX_DATA_TYPE, tx_obj.hash())
|
| 175 | +>>> # send the message |
134 | 176 | >>> node.send(getdata)
|
| 177 | +>>> # now wait for a Tx response |
135 | 178 | >>> received_tx = node.wait_for(Tx)
|
| 179 | +>>> # if the received tx has the same id as our tx, we are done! |
136 | 180 | >>> if received_tx.id() == tx_obj.id():
|
137 | 181 | ... print('success!')
|
138 | 182 | success!
|
|
0 commit comments