3 from _pysha3 import sha3_256
4 from .receiver import *
6 # submit_transaction broadcast raw transaction
7 # raw_transaction_str is signed transaction,
9 # raw_transaction_hexstr: 070100010160015e5dfc352f9247985e92b2688a9a0a0e3e45a52f633c7d2c35cf6485fc1f03a89cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8094ebdc030101160014052620b86a6d5e07311d5019dffa3864ccc8a6bd630240988348a301c86563eb16105cc0c7e12e8cd1fbc7e9031933dac05a32d2a696bc77b83f25a99a4a9458d976c5327b8004918545a3fde567f28d805f741db54e0b20e87ca3acdebdcad9a1d0f2caecf8ce0dbfc73d060807a210c6f225488347961402013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80b6f7f302011600147950bb5fcfb1c3fe14198c14ebd4ad85bb69bbc500013cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8084af5f011600141d8e1c2d71843f41e2131d7fd6df8b47e2cf56b900
10 # submit_url: https://blockmeta.com/api/wisdom/broadcast-transaction
12 # raw_transaction_hexstr: 07010001015f015d2f4a8f10afbc0448779fadd916a3f1b8518ffe0b7d20fdf470d8e9b4993ef2b4ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0d8883200011600144a594e3e4cbbd87629476e7ee24c1637df66c0b76302406fd39079681118840fd6fd66cdff769f2d05d8520312e9dd559dc23c36a3cb3921e47cba233d5d2267eb0f128a908d1bab877e172e880d3f36dc6a5e5826540c202854e5c181f5a862edd190e413d75937549758ef4902e1475aac52623f0a239302013cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc09dd81001160014f63f68597df5c88a92e04229e0fd08a3584ade3b00013cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80e1eb1701160014664f28ec6ab8826a028658dc0d0d1f94c6e20fa300
13 # submit_url: https://blockmeta.com/api/v2/broadcast-transaction
14 def submit_transaction(raw_transaction_hexstr, submit_url):
15 raw_transaction_dict = {
16 "transaction": raw_transaction_hexstr
18 raw_transaction_json = json.dumps(raw_transaction_dict)
20 "content-type": "application/json",
21 "accept": "application/json"
23 response = requests.post(submit_url, headers=headers, data=raw_transaction_json)
24 return response.text[:-1]
27 # def decode_raw_transaction(raw_transaction_str):
28 # raw_transaction_dict = {
29 # "raw_transaction": raw_transaction_str
31 # raw_transaction_json = json.dumps(raw_transaction_dict)
33 # "content-type": "application/json",
34 # "accept": "application/json"
36 # url = 'http://127.0.0.1:9888/decode-raw-transaction'
37 # response = requests.post(url, headers=headers, data=raw_transaction_json)
39 # "response": response.text[:-1]
43 def get_uvarint(uvarint_str):
44 uvarint_bytes = bytes.fromhex(uvarint_str)
49 if i > 9 or i == 9 and b > 1:
51 return x | int(b) << s, i + 1
52 x |= int(b & 0x7f) << s
58 get_spend_output_id create tx_input spend output id
60 source_id_hexstr: 28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21
61 asset_id_hexstr: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
62 amount_int: 41250000000
63 source_position_int: 0
65 control_program_hexstr: 00149335b1cbd4a77b78e33315a0ed10a95b12e7ca48
66 spend_output_id_hexstr: f229ec6f403d586dc87aa2546bbe64c5f7b5f46eb13c6ee4823d03bc88a7cf17
68 def get_spend_output_id(source_id_hexstr, asset_id_hexstr, amount_int, source_position_int, vmversion_int, control_program_hexstr):
69 amount_hexstr = amount_int.to_bytes(8, byteorder='little').hex()
70 source_position_hexstr = source_position_int.to_bytes(8, byteorder='little').hex()
71 vmversion_hexstr = vmversion_int.to_bytes(8, byteorder='little').hex()
72 cp_length_int = len(control_program_hexstr) // 2
73 cp_length_hexstr = cp_length_int.to_bytes((cp_length_int.bit_length() + 7) // 8, byteorder='little').hex()
74 sc_hexstr = source_id_hexstr + asset_id_hexstr + amount_hexstr + source_position_hexstr + vmversion_hexstr + cp_length_hexstr + control_program_hexstr
75 innerhash_bytes = sha3_256(bytes.fromhex(sc_hexstr)).digest()
76 spend_bytes = b'entryid:output1:' + innerhash_bytes
77 spend_output_id_hexstr = sha3_256(spend_bytes).hexdigest()
78 return spend_output_id_hexstr
81 get_input_id create tx input_id
83 spend_output_id_hexstr: f229ec6f403d586dc87aa2546bbe64c5f7b5f46eb13c6ee4823d03bc88a7cf17
84 input_id_hexstr: 6e3f378ed844b143a335e306f4ba26746157589c87e8fc8cba6463c566c56768
86 def get_input_id(spend_output_id_hexstr):
87 innerhash_bytes = sha3_256(bytes.fromhex(spend_output_id_hexstr)).digest()
88 input_id_hexstr = sha3_256(b'entryid:spend1:' + innerhash_bytes).hexdigest()
89 return input_id_hexstr
92 def get_mux_id(prepare_mux_hexstr):
93 innerhash_bytes = sha3_256(bytes.fromhex(prepare_mux_hexstr)).digest()
94 mux_id_hexstr = sha3_256(b'entryid:mux1:' + innerhash_bytes).hexdigest()
98 def get_output_id(prepare_output_id_hexstr):
99 innerhash_bytes = sha3_256(bytes.fromhex(prepare_output_id_hexstr)).digest()
100 output_id_hexstr = sha3_256(b'entryid:output1:' + innerhash_bytes).hexdigest()
101 return output_id_hexstr
104 def get_tx_id(prepare_tx_id_hexstr):
105 innerhash_bytes = sha3_256(bytes.fromhex(prepare_tx_id_hexstr)).digest()
106 tx_id_hexstr = sha3_256(b'entryid:txheader:' + innerhash_bytes).hexdigest()
110 def get_issue_input_id(prepare_issue_hexstr):
111 innerhash_bytes = sha3_256(bytes.fromhex(prepare_issue_hexstr)).digest()
112 tx_id_hexstr = sha3_256(b'entryid:issuance1:' + innerhash_bytes).hexdigest()
116 def get_coinbase_input_id(prepare_coinbase_input_id_hexstr):
117 innerhash_bytes = sha3_256(bytes.fromhex(prepare_coinbase_input_id_hexstr)).digest()
118 coinbase_input_id_hexstr = sha3_256(b'entryid:coinbase1:' + innerhash_bytes).hexdigest()
119 return coinbase_input_id_hexstr
123 decode_raw_tx decode raw transaction
125 raw_transaction_str: 070100010161015f28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d5990100011600149335b1cbd4a77b78e33315a0ed10a95b12e7ca48630240897e2d9d24a3b5faaed0579dee7597b401491595675f897504f8945b29d836235bd2fca72a3ad0cae814628973ebcd142d9d6cc92d0b2571b69e5370a98a340c208cb7fb3086f58db9a31401b99e8c658be66134fb9034de1d5c462679270b090702013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80f9f8bc98010116001406ce4b689ba026ffd3a7ca65d1d059546d4b78a000013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c6868f01011600147929ef91997c827bebf60fa608f876ea27523c4700
132 "address": "sm1qjv6mrj755aah3cenzksw6y9ftvfw0jjgk0l2mw",
133 "amount": 41250000000,
134 "asset_definition": {},
135 "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
136 "control_program": "00149335b1cbd4a77b78e33315a0ed10a95b12e7ca48",
137 "input_id": "6e3f378ed844b143a335e306f4ba26746157589c87e8fc8cba6463c566c56768",
138 "spent_output_id": "f229ec6f403d586dc87aa2546bbe64c5f7b5f46eb13c6ee4823d03bc88a7cf17",
140 "witness_arguments": [
141 "897e2d9d24a3b5faaed0579dee7597b401491595675f897504f8945b29d836235bd2fca72a3ad0cae814628973ebcd142d9d6cc92d0b2571b69e5370a98a340c",
142 "8cb7fb3086f58db9a31401b99e8c658be66134fb9034de1d5c462679270b0907"
148 "address": "sm1qqm8yk6ym5qn0l5a8efjar5ze23k5k79qnvtslj",
149 "amount": 40930000000,
150 "asset_definition": {},
151 "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
152 "control_program": "001406ce4b689ba026ffd3a7ca65d1d059546d4b78a0",
153 "id": "74c73266730d3c6ea32e8667ef9b867068736b84be240fe9fef205fa68bb7b95",
158 "address": "sm1q0y57lyve0jp8h6lkp7nq37rkagn4y0z8hvh6kq",
160 "asset_definition": {},
161 "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
162 "control_program": "00147929ef91997c827bebf60fa608f876ea27523c47",
163 "id": "f115a833d0c302a5006032858a7ed3987f0feb2daf2a9f849384950e4766af51",
170 "tx_id": "814a73dd57bae67c604f9cbc696cbc42035577423408cb9267136ed971e2bf63",
174 def decode_raw_tx(raw_transaction_str, network_str):
185 tx['size'] = len(raw_transaction_str) // 2
188 tx['version'], length = get_uvarint(raw_transaction_str[offset:offset+18])
189 offset = offset + 2 * length
190 tx['time_range'], length = get_uvarint(raw_transaction_str[offset:offset+18])
191 offset = offset + 2 * length
192 tx_input_amount, length = get_uvarint(raw_transaction_str[offset:offset+8])
193 offset = offset + 2 * length
194 prepare_mux_hexstr = (tx_input_amount).to_bytes((tx_input_amount.bit_length() + 7) // 8, 'little').hex()
195 prepare_tx_id_hexstr = (tx['version']).to_bytes(8, 'little').hex() + (tx['time_range']).to_bytes(8, 'little').hex()
196 for _ in range(tx_input_amount):
197 _, length = get_uvarint(raw_transaction_str[offset:offset+18])
198 offset = offset + 2 * length
199 _, length = get_uvarint(raw_transaction_str[offset:offset+18])
200 offset = offset + 2 * length
201 input_type = int(raw_transaction_str[offset:offset+2], 16)
203 if input_type == 0: # issue
206 "asset_definition": "", # TODO:fix it!!
209 "issuance_program": "",
211 "witness_arguments": []
213 tx_input['type'] = "issue"
214 _, length = get_uvarint(raw_transaction_str[offset:offset+18])
215 offset = offset + 2 * length
216 nonce = raw_transaction_str[offset:offset+16]
218 nonce_hash_hexstr = sha3_256(bytes.fromhex(nonce)).hexdigest()
219 tx_input['asset_id'] = raw_transaction_str[offset:offset+64]
221 tx_input['amount'], length = get_uvarint(raw_transaction_str[offset:offset+18])
222 offset = offset + 2 * length
223 _, length = get_uvarint(raw_transaction_str[offset:offset+18])
224 offset = offset + 2 * length
225 asset_definition_size, length = get_uvarint(raw_transaction_str[offset:offset+18])
226 offset = offset + 2 * length
227 tx_input['asset_definition'] = bytes.fromhex(raw_transaction_str[offset:offset+2*asset_definition_size]).decode()
228 offset = offset + 2 * asset_definition_size
229 _, length = get_uvarint(raw_transaction_str[offset:offset+18])
230 offset = offset + 2 * length
231 issuance_program_length, length = get_uvarint(raw_transaction_str[offset:offset+18])
232 offset = offset + 2 * length
233 tx_input['issuance_program'] = raw_transaction_str[offset:offset+2*issuance_program_length]
234 offset = offset + 2 * issuance_program_length
235 witness_arguments_amount, length = get_uvarint(raw_transaction_str[offset:offset+18])
236 offset = offset + 2 * length
237 for _ in range(witness_arguments_amount):
238 argument_length, length = get_uvarint(raw_transaction_str[offset:offset+18])
239 offset = offset + 2 * length
240 argument = raw_transaction_str[offset:offset+2*argument_length]
241 offset = offset + 2 * argument_length
242 tx_input['witness_arguments'].append(argument)
243 prepare_issue_hexstr = nonce_hash_hexstr + tx_input['asset_id'] + (tx_input['amount']).to_bytes(8, byteorder='little').hex()
244 tx_input['input_id'] = get_issue_input_id(prepare_issue_hexstr)
245 tx['inputs'].append(tx_input)
246 prepare_mux_hexstr += tx_input['input_id'] + tx_input['asset_id'] + (tx_input['amount']).to_bytes(8, byteorder='little').hex() + '0000000000000000'
247 prepare_mux_hexstr += '0100000000000000' + '0151'
248 mux_id_hexstr = get_mux_id(prepare_mux_hexstr)
249 elif input_type == 1: # spend
253 "asset_definition": {},
255 "control_program": "",
257 "spent_output_id": "",
259 "witness_arguments": []
261 tx_input['type'] = "spend"
262 _, length = get_uvarint(raw_transaction_str[offset:offset+18])
263 offset = offset + 2 * length
264 source_id = raw_transaction_str[offset:offset+64]
266 tx_input['asset_id'] = raw_transaction_str[offset:offset+64]
268 tx_input['amount'], length = get_uvarint(raw_transaction_str[offset:offset+18])
269 offset = offset + 2 * length
270 tx['fee'] += tx_input['amount']
271 source_positon, length = get_uvarint(raw_transaction_str[offset:offset+18])
272 offset = offset + 2 * length
273 vmversion, length = get_uvarint(raw_transaction_str[offset:offset+18])
274 offset = offset + 2 * length
275 control_program_length, length = get_uvarint(raw_transaction_str[offset:offset+18])
276 offset = offset + 2 * length
277 tx_input['control_program'] = raw_transaction_str[offset:offset+2*control_program_length]
278 offset = offset + 2 * control_program_length
279 tx_input['address'] = get_address(tx_input['control_program'], network_str)['address']
280 _, length = get_uvarint(raw_transaction_str[offset:offset+18])
281 offset = offset + 2 * length
282 witness_arguments_amount, length = get_uvarint(raw_transaction_str[offset:offset+18])
283 offset = offset + 2 * length
284 if witness_arguments_amount == 1:
286 tx_input['witness_arguments'] = None
288 for _ in range(witness_arguments_amount):
289 argument_length, length = get_uvarint(raw_transaction_str[offset:offset+18])
290 offset = offset + 2 * length
291 argument = raw_transaction_str[offset:offset+2*argument_length]
292 offset = offset + 2 * argument_length
293 tx_input['witness_arguments'].append(argument)
294 tx_input['spent_output_id'] = get_spend_output_id(source_id, tx_input['asset_id'], tx_input['amount'], source_positon, vmversion, tx_input['control_program'])
295 tx_input['input_id'] = get_input_id(tx_input['spent_output_id'])
296 tx['inputs'].append(tx_input)
297 prepare_mux_hexstr += tx_input['input_id'] + tx_input['asset_id'] + (tx_input['amount']).to_bytes(8, byteorder='little').hex() + '0000000000000000'
298 prepare_mux_hexstr += '0100000000000000' + '0151'
299 mux_id_hexstr = get_mux_id(prepare_mux_hexstr)
300 elif input_type == 2: # coinbase
304 "asset_definition": {},
305 "asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
308 "witness_arguments": []
310 tx_input['type'] = "coinbase"
311 arbitrary_length, length = get_uvarint(raw_transaction_str[offset:offset+18])
312 prepare_coinbase_input_id_hexstr = raw_transaction_str[offset:offset+2*length]
313 offset = offset + 2 * length
314 tx_input['arbitrary'] = raw_transaction_str[offset:offset+2*arbitrary_length]
315 prepare_coinbase_input_id_hexstr += tx_input['arbitrary']
316 offset = offset + 2 * arbitrary_length
317 tx_input['input_id'] = get_coinbase_input_id(prepare_coinbase_input_id_hexstr)
319 tx['inputs'].append(tx_input)
320 prepare_mux_hexstr += tx_input['input_id'] + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
321 tx_output_amount, length = get_uvarint(raw_transaction_str[offset:offset+18])
322 offset = offset + 2 * length
323 prepare_tx_id_hexstr += (tx_output_amount).to_bytes((tx_output_amount.bit_length() + 7) // 8, 'little').hex()
324 for i in range(tx_output_amount):
328 "asset_definition": {},
330 "control_program": "",
335 tx_output['position'] = i
336 _, length = get_uvarint(raw_transaction_str[offset:offset+18])
337 offset = offset + 2 * length
338 _, length = get_uvarint(raw_transaction_str[offset:offset+18])
339 offset = offset + 2 * length
340 tx_output['asset_id'] = raw_transaction_str[offset:offset+64]
342 tx_output['amount'], length = get_uvarint(raw_transaction_str[offset:offset+18])
343 if tx_input['type'] == "coinbase":
344 prepare_mux_hexstr = prepare_mux_hexstr + (tx_output['amount']).to_bytes(8, byteorder='little').hex() + '0000000000000000' + '0100000000000000' + '0151'
345 mux_id_hexstr = get_mux_id(prepare_mux_hexstr)
346 offset = offset + 2 * length
347 if tx_output['asset_id'] == 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff':
348 tx['fee'] -= tx_output['amount']
349 _, length = get_uvarint(raw_transaction_str[offset:offset+18])
350 offset = offset + 2 * length
351 control_program_length, length = get_uvarint(raw_transaction_str[offset:offset+18])
352 offset = offset + 2 * length
353 tx_output['control_program'] = raw_transaction_str[offset:offset+2*control_program_length]
354 offset = offset + 2 * control_program_length
355 tx_output['address'] = get_address(tx_output['control_program'], network_str)['address']
356 _, length = get_uvarint(raw_transaction_str[offset:offset+18])
357 offset = offset + 2 * length
358 prepare_output_id_hexstr = mux_id_hexstr + tx_output['asset_id'] + (tx_output['amount']).to_bytes(8, byteorder='little').hex() + (i).to_bytes(8, byteorder='little').hex() + '0100000000000000' + (control_program_length).to_bytes((control_program_length.bit_length() + 7) // 8, 'little').hex() + tx_output['control_program']
359 tx_output['id'] = get_output_id(prepare_output_id_hexstr)
360 prepare_tx_id_hexstr += tx_output['id']
361 tx_output['type'] = 'control'
362 tx['outputs'].append(tx_output)
363 if tx_input['type'] == "coinbase":
365 tx['tx_id'] = get_tx_id(prepare_tx_id_hexstr)