• R/O
  • HTTP
  • SSH
  • HTTPS

pybtm: 提交

Python3 implementation of the Bytom protocol. https://pypi.org/project/pybtm/


Commit MetaInfo

修订版819ce1a6da2b315a378fdf3fa55327447dc93186 (tree)
时间2019-03-29 16:25:51
作者Chengcheng Zhang <943420582@qq.c...>
CommiterChengcheng Zhang

Log Message

add transaction.py

更改概述

差异

--- a/pybtm/__init__.py
+++ b/pybtm/__init__.py
@@ -1,2 +1,2 @@
11 name = "pybtm"
2-version = "0.0.19"
\ No newline at end of file
2+version = "0.0.20"
\ No newline at end of file
--- /dev/null
+++ b/pybtm/transaction.py
@@ -0,0 +1,364 @@
1+import requests
2+import json
3+from _pysha3 import sha3_256
4+from .receiver import *
5+
6+# submit_transaction broadcast raw transaction
7+# raw_transaction_str is signed transaction,
8+# network_str is mainnet or testnet
9+# test data 1:
10+# raw_transaction_str: 070100010160015e0873eddd68c4ba07c9410984799928288ae771bdccc6d974e72c95727813461fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8094ebdc030101160014052620b86a6d5e07311d5019dffa3864ccc8a6bd630240312a052f36efb9826aa1021ec91bc6f125dd07f9c4bff87014612069527e15246518806b654d57fff8b6fe91866a19d5a2fb63a5894335fce92a7b4a7fcd340720e87ca3acdebdcad9a1d0f2caecf8ce0dbfc73d060807a210c6f225488347961402013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8082eee0020116001418028ef4f8b8c278907864a1977a5ee6707b2a6b00013cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80b8b872011600142935e4869d0317d9701c80a02ecf888143cb9dd200
11+# network_str: testnet
12+def submit_transaction(raw_transaction_str, network_str):
13+ raw_transaction_dict = {
14+ "transaction": raw_transaction_str
15+ }
16+ raw_transaction_json = json.dumps(raw_transaction_dict)
17+ headers = {
18+ "content-type": "application/json",
19+ "accept": "application/json"
20+ }
21+ if network_str == "mainnet":
22+ url = "https://blockmeta.com/api/v2/broadcast-transaction"
23+ else:
24+ url = "https://blockmeta.com/api/wisdom/broadcast-transaction"
25+ response = requests.post(url, headers=headers, data=raw_transaction_json)
26+ return response.text[:-1]
27+
28+
29+# def decode_raw_transaction(raw_transaction_str):
30+# raw_transaction_dict = {
31+# "raw_transaction": raw_transaction_str
32+# }
33+# raw_transaction_json = json.dumps(raw_transaction_dict)
34+# headers = {
35+# "content-type": "application/json",
36+# "accept": "application/json"
37+# }
38+# url = 'http://127.0.0.1:9888/decode-raw-transaction'
39+# response = requests.post(url, headers=headers, data=raw_transaction_json)
40+# return {
41+# "response": response.text[:-1]
42+# }
43+
44+
45+def get_uvarint(uvarint_str):
46+ uvarint_bytes = bytes.fromhex(uvarint_str)
47+ x, s, i = 0, 0, 0
48+ while True:
49+ b = uvarint_bytes[i]
50+ if b < 0x80:
51+ if i > 9 or i == 9 and b > 1:
52+ return "overflow"
53+ return x | int(b) << s, i + 1
54+ x |= int(b & 0x7f) << s
55+ s += 7
56+ i += 1
57+
58+
59+'''
60+get_spend_output_id create tx_input spend output id
61+test data 1:
62+ source_id_hexstr: 28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21
63+ asset_id_hexstr: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
64+ amount_int: 41250000000
65+ source_position_int: 0
66+ vmversion_int: 1
67+ control_program_hexstr: 00149335b1cbd4a77b78e33315a0ed10a95b12e7ca48
68+ spend_output_id_hexstr: f229ec6f403d586dc87aa2546bbe64c5f7b5f46eb13c6ee4823d03bc88a7cf17
69+'''
70+def get_spend_output_id(source_id_hexstr, asset_id_hexstr, amount_int, source_position_int, vmversion_int, control_program_hexstr):
71+ amount_hexstr = amount_int.to_bytes(8, byteorder='little').hex()
72+ source_position_hexstr = source_position_int.to_bytes(8, byteorder='little').hex()
73+ vmversion_hexstr = vmversion_int.to_bytes(8, byteorder='little').hex()
74+ cp_length_int = len(control_program_hexstr) // 2
75+ cp_length_hexstr = cp_length_int.to_bytes((cp_length_int.bit_length() + 7) // 8, byteorder='little').hex()
76+ sc_hexstr = source_id_hexstr + asset_id_hexstr + amount_hexstr + source_position_hexstr + vmversion_hexstr + cp_length_hexstr + control_program_hexstr
77+ innerhash_bytes = sha3_256(bytes.fromhex(sc_hexstr)).digest()
78+ spend_bytes = b'entryid:output1:' + innerhash_bytes
79+ spend_output_id_hexstr = sha3_256(spend_bytes).hexdigest()
80+ return spend_output_id_hexstr
81+
82+'''
83+get_input_id create tx input_id
84+test data 1:
85+ spend_output_id_hexstr: f229ec6f403d586dc87aa2546bbe64c5f7b5f46eb13c6ee4823d03bc88a7cf17
86+ input_id_hexstr: 6e3f378ed844b143a335e306f4ba26746157589c87e8fc8cba6463c566c56768
87+'''
88+def get_input_id(spend_output_id_hexstr):
89+ innerhash_bytes = sha3_256(bytes.fromhex(spend_output_id_hexstr)).digest()
90+ input_id_hexstr = sha3_256(b'entryid:spend1:' + innerhash_bytes).hexdigest()
91+ return input_id_hexstr
92+
93+
94+def get_mux_id(prepare_mux_hexstr):
95+ innerhash_bytes = sha3_256(bytes.fromhex(prepare_mux_hexstr)).digest()
96+ mux_id_hexstr = sha3_256(b'entryid:mux1:' + innerhash_bytes).hexdigest()
97+ return mux_id_hexstr
98+
99+
100+def get_output_id(prepare_output_id_hexstr):
101+ innerhash_bytes = sha3_256(bytes.fromhex(prepare_output_id_hexstr)).digest()
102+ output_id_hexstr = sha3_256(b'entryid:output1:' + innerhash_bytes).hexdigest()
103+ return output_id_hexstr
104+
105+
106+def get_tx_id(prepare_tx_id_hexstr):
107+ innerhash_bytes = sha3_256(bytes.fromhex(prepare_tx_id_hexstr)).digest()
108+ tx_id_hexstr = sha3_256(b'entryid:txheader:' + innerhash_bytes).hexdigest()
109+ return tx_id_hexstr
110+
111+
112+def get_issue_input_id(prepare_issue_hexstr):
113+ innerhash_bytes = sha3_256(bytes.fromhex(prepare_issue_hexstr)).digest()
114+ tx_id_hexstr = sha3_256(b'entryid:issuance1:' + innerhash_bytes).hexdigest()
115+ return tx_id_hexstr
116+
117+
118+def get_coinbase_input_id(prepare_coinbase_input_id_hexstr):
119+ innerhash_bytes = sha3_256(bytes.fromhex(prepare_coinbase_input_id_hexstr)).digest()
120+ coinbase_input_id_hexstr = sha3_256(b'entryid:coinbase1:' + innerhash_bytes).hexdigest()
121+ return coinbase_input_id_hexstr
122+
123+
124+'''
125+decode_raw_tx decode raw transaction
126+testdata 1:
127+ raw_tx_str: 070100010161015f28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d5990100011600149335b1cbd4a77b78e33315a0ed10a95b12e7ca48630240897e2d9d24a3b5faaed0579dee7597b401491595675f897504f8945b29d836235bd2fca72a3ad0cae814628973ebcd142d9d6cc92d0b2571b69e5370a98a340c208cb7fb3086f58db9a31401b99e8c658be66134fb9034de1d5c462679270b090702013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80f9f8bc98010116001406ce4b689ba026ffd3a7ca65d1d059546d4b78a000013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c6868f01011600147929ef91997c827bebf60fa608f876ea27523c4700
128+ network_str: solonet
129+ transaction:
130+{
131+ "fee": 20000000,
132+ "inputs": [
133+ {
134+ "address": "sm1qjv6mrj755aah3cenzksw6y9ftvfw0jjgk0l2mw",
135+ "amount": 41250000000,
136+ "asset_definition": {},
137+ "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
138+ "control_program": "00149335b1cbd4a77b78e33315a0ed10a95b12e7ca48",
139+ "input_id": "6e3f378ed844b143a335e306f4ba26746157589c87e8fc8cba6463c566c56768",
140+ "spent_output_id": "f229ec6f403d586dc87aa2546bbe64c5f7b5f46eb13c6ee4823d03bc88a7cf17",
141+ "type": "spend",
142+ "witness_arguments": [
143+ "897e2d9d24a3b5faaed0579dee7597b401491595675f897504f8945b29d836235bd2fca72a3ad0cae814628973ebcd142d9d6cc92d0b2571b69e5370a98a340c",
144+ "8cb7fb3086f58db9a31401b99e8c658be66134fb9034de1d5c462679270b0907"
145+ ]
146+ }
147+ ],
148+ "outputs": [
149+ {
150+ "address": "sm1qqm8yk6ym5qn0l5a8efjar5ze23k5k79qnvtslj",
151+ "amount": 40930000000,
152+ "asset_definition": {},
153+ "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
154+ "control_program": "001406ce4b689ba026ffd3a7ca65d1d059546d4b78a0",
155+ "id": "74c73266730d3c6ea32e8667ef9b867068736b84be240fe9fef205fa68bb7b95",
156+ "position": 0,
157+ "type": "control"
158+ },
159+ {
160+ "address": "sm1q0y57lyve0jp8h6lkp7nq37rkagn4y0z8hvh6kq",
161+ "amount": 300000000,
162+ "asset_definition": {},
163+ "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
164+ "control_program": "00147929ef91997c827bebf60fa608f876ea27523c47",
165+ "id": "f115a833d0c302a5006032858a7ed3987f0feb2daf2a9f849384950e4766af51",
166+ "position": 1,
167+ "type": "control"
168+ }
169+ ],
170+ "size": 333,
171+ "time_range": 0,
172+ "tx_id": "814a73dd57bae67c604f9cbc696cbc42035577423408cb9267136ed971e2bf63",
173+ "version": 1
174+}
175+'''
176+def decode_raw_tx(raw_tx_str, network_str):
177+ tx = {
178+ "fee": 0,
179+ "inputs": [],
180+ "outputs": [],
181+ "size": 0,
182+ "time_range": 0,
183+ "tx_id": "",
184+ "version": 0
185+ }
186+ tx['fee'] = 0
187+ tx['size'] = len(raw_tx_str) // 2
188+ length = 0
189+ offset = 2
190+ tx['version'], length = get_uvarint(raw_tx_str[offset:offset+18])
191+ offset = offset + 2 * length
192+ tx['time_range'], length = get_uvarint(raw_tx_str[offset:offset+18])
193+ offset = offset + 2 * length
194+ tx_input_amount, length = get_uvarint(raw_tx_str[offset:offset+8])
195+ offset = offset + 2 * length
196+ prepare_mux_hexstr = (tx_input_amount).to_bytes((tx_input_amount.bit_length() + 7) // 8, 'little').hex()
197+ prepare_tx_id_hexstr = (tx['version']).to_bytes(8, 'little').hex() + (tx['time_range']).to_bytes(8, 'little').hex()
198+ for _ in range(tx_input_amount):
199+ _, length = get_uvarint(raw_tx_str[offset:offset+18])
200+ offset = offset + 2 * length
201+ _, length = get_uvarint(raw_tx_str[offset:offset+18])
202+ offset = offset + 2 * length
203+ input_type = int(raw_tx_str[offset:offset+2], 16)
204+ offset += 2
205+ if input_type == 0: # issue
206+ tx_input = {
207+ "amount": 0,
208+ "asset_definition": "", # TODO:fix it!!
209+ "asset_id": "",
210+ "input_id": "",
211+ "issuance_program": "",
212+ "type": "",
213+ "witness_arguments": []
214+ }
215+ tx_input['type'] = "issue"
216+ _, length = get_uvarint(raw_tx_str[offset:offset+18])
217+ offset = offset + 2 * length
218+ nonce = raw_tx_str[offset:offset+16]
219+ offset += 16
220+ nonce_hash_hexstr = sha3_256(bytes.fromhex(nonce)).hexdigest()
221+ tx_input['asset_id'] = raw_tx_str[offset:offset+64]
222+ offset += 64
223+ tx_input['amount'], length = get_uvarint(raw_tx_str[offset:offset+18])
224+ offset = offset + 2 * length
225+ _, length = get_uvarint(raw_tx_str[offset:offset+18])
226+ offset = offset + 2 * length
227+ asset_definition_size, length = get_uvarint(raw_tx_str[offset:offset+18])
228+ offset = offset + 2 * length
229+ tx_input['asset_definition'] = bytes.fromhex(raw_tx_str[offset:offset+2*asset_definition_size]).decode()
230+ offset = offset + 2 * asset_definition_size
231+ _, length = get_uvarint(raw_tx_str[offset:offset+18])
232+ offset = offset + 2 * length
233+ issuance_program_length, length = get_uvarint(raw_tx_str[offset:offset+18])
234+ offset = offset + 2 * length
235+ tx_input['issuance_program'] = raw_tx_str[offset:offset+2*issuance_program_length]
236+ offset = offset + 2 * issuance_program_length
237+ witness_arguments_amount, length = get_uvarint(raw_tx_str[offset:offset+18])
238+ offset = offset + 2 * length
239+ for _ in range(witness_arguments_amount):
240+ argument_length, length = get_uvarint(raw_tx_str[offset:offset+18])
241+ offset = offset + 2 * length
242+ argument = raw_tx_str[offset:offset+2*argument_length]
243+ offset = offset + 2 * argument_length
244+ tx_input['witness_arguments'].append(argument)
245+ prepare_issue_hexstr = nonce_hash_hexstr + tx_input['asset_id'] + (tx_input['amount']).to_bytes(8, byteorder='little').hex()
246+ tx_input['input_id'] = get_issue_input_id(prepare_issue_hexstr)
247+ tx['inputs'].append(tx_input)
248+ prepare_mux_hexstr += tx_input['input_id'] + tx_input['asset_id'] + (tx_input['amount']).to_bytes(8, byteorder='little').hex() + '0000000000000000'
249+ prepare_mux_hexstr += '0100000000000000' + '0151'
250+ mux_id_hexstr = get_mux_id(prepare_mux_hexstr)
251+ elif input_type == 1: # spend
252+ tx_input = {
253+ "address": "",
254+ "amount": 0,
255+ "asset_definition": {},
256+ "asset_id": "",
257+ "control_program": "",
258+ "input_id": "",
259+ "spent_output_id": "",
260+ "type": "",
261+ "witness_arguments": []
262+ }
263+ tx_input['type'] = "spend"
264+ _, length = get_uvarint(raw_tx_str[offset:offset+18])
265+ offset = offset + 2 * length
266+ source_id = raw_tx_str[offset:offset+64]
267+ offset += 64
268+ tx_input['asset_id'] = raw_tx_str[offset:offset+64]
269+ offset += 64
270+ tx_input['amount'], length = get_uvarint(raw_tx_str[offset:offset+18])
271+ offset = offset + 2 * length
272+ tx['fee'] += tx_input['amount']
273+ source_positon, length = get_uvarint(raw_tx_str[offset:offset+18])
274+ offset = offset + 2 * length
275+ vmversion, length = get_uvarint(raw_tx_str[offset:offset+18])
276+ offset = offset + 2 * length
277+ control_program_length, length = get_uvarint(raw_tx_str[offset:offset+18])
278+ offset = offset + 2 * length
279+ tx_input['control_program'] = raw_tx_str[offset:offset+2*control_program_length]
280+ offset = offset + 2 * control_program_length
281+ tx_input['address'] = get_address(tx_input['control_program'], network_str)
282+ _, length = get_uvarint(raw_tx_str[offset:offset+18])
283+ offset = offset + 2 * length
284+ witness_arguments_amount, length = get_uvarint(raw_tx_str[offset:offset+18])
285+ offset = offset + 2 * length
286+ 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'])
287+ tx_input['input_id'] = get_input_id(tx_input['spent_output_id'])
288+ for _ in range(witness_arguments_amount):
289+ argument_length, length = get_uvarint(raw_tx_str[offset:offset+18])
290+ offset = offset + 2 * length
291+ argument = raw_tx_str[offset:offset+2*argument_length]
292+ offset = offset + 2 * argument_length
293+ tx_input['witness_arguments'].append(argument)
294+ tx['inputs'].append(tx_input)
295+ prepare_mux_hexstr += tx_input['input_id'] + tx_input['asset_id'] + (tx_input['amount']).to_bytes(8, byteorder='little').hex() + '0000000000000000'
296+ prepare_mux_hexstr += '0100000000000000' + '0151'
297+ mux_id_hexstr = get_mux_id(prepare_mux_hexstr)
298+ elif input_type == 2: # coinbase
299+ tx_input = {
300+ "amount": 0,
301+ "arbitrary": "",
302+ "asset_definition": {},
303+ "asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
304+ "input_id": "",
305+ "type": "",
306+ "witness_arguments": []
307+ }
308+ tx_input['type'] = "coinbase"
309+ arbitrary_length, length = get_uvarint(raw_tx_str[offset:offset+18])
310+ prepare_coinbase_input_id_hexstr = raw_tx_str[offset:offset+2*length]
311+ offset = offset + 2 * length
312+ tx_input['arbitrary'] = raw_tx_str[offset:offset+2*arbitrary_length]
313+ prepare_coinbase_input_id_hexstr += tx_input['arbitrary']
314+ offset = offset + 2 * arbitrary_length
315+ tx_input['input_id'] = get_coinbase_input_id(prepare_coinbase_input_id_hexstr)
316+ offset = offset + 2
317+ tx['inputs'].append(tx_input)
318+ prepare_mux_hexstr += tx_input['input_id'] + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
319+ tx_output_amount, length = get_uvarint(raw_tx_str[offset:offset+18])
320+ offset = offset + 2 * length
321+ prepare_tx_id_hexstr += (tx_output_amount).to_bytes((tx_output_amount.bit_length() + 7) // 8, 'little').hex()
322+ for i in range(tx_output_amount):
323+ tx_output = {
324+ "address": "",
325+ "amount": 0,
326+ "asset_definition": {},
327+ "asset_id": "",
328+ "control_program": "",
329+ "id": "",
330+ "position": 0,
331+ "type": ""
332+ }
333+ tx_output['position'] = i
334+ _, length = get_uvarint(raw_tx_str[offset:offset+18])
335+ offset = offset + 2 * length
336+ _, length = get_uvarint(raw_tx_str[offset:offset+18])
337+ offset = offset + 2 * length
338+ tx_output['asset_id'] = raw_tx_str[offset:offset+64]
339+ offset = offset + 64
340+ tx_output['amount'], length = get_uvarint(raw_tx_str[offset:offset+18])
341+ if tx_input['type'] == "coinbase":
342+ prepare_mux_hexstr = prepare_mux_hexstr + (tx_output['amount']).to_bytes(8, byteorder='little').hex() + '0000000000000000' + '0100000000000000' + '0151'
343+ mux_id_hexstr = get_mux_id(prepare_mux_hexstr)
344+ offset = offset + 2 * length
345+ if tx_output['asset_id'] == 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff':
346+ tx['fee'] -= tx_output['amount']
347+ _, length = get_uvarint(raw_tx_str[offset:offset+18])
348+ offset = offset + 2 * length
349+ control_program_length, length = get_uvarint(raw_tx_str[offset:offset+18])
350+ offset = offset + 2 * length
351+ tx_output['control_program'] = raw_tx_str[offset:offset+2*control_program_length]
352+ offset = offset + 2 * control_program_length
353+ tx_output['address'] = get_address(tx_output['control_program'], network_str)
354+ _, length = get_uvarint(raw_tx_str[offset:offset+18])
355+ offset = offset + 2 * length
356+ 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']
357+ tx_output['id'] = get_output_id(prepare_output_id_hexstr)
358+ prepare_tx_id_hexstr += tx_output['id']
359+ tx_output['type'] = 'control'
360+ tx['outputs'].append(tx_output)
361+ if tx_input['type'] == "coinbase":
362+ tx['fee'] = 0
363+ tx['tx_id'] = get_tx_id(prepare_tx_id_hexstr)
364+ return tx
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
55
66 setuptools.setup(
77 name="pybtm",
8- version="0.0.19",
8+ version="0.0.20",
99 author="zcc0721",
1010 author_email="zcc0721@foxmail.com",
1111 description="Python3 implementation of the Bytom protocol.",
Show on old repository browser