OSDN Git Service

b16668f1de7f5764c4e13745dac30dd0035caa8f
[bytom/bytom-kit.git] / app / model / transaction.py
1 import requests
2 import json
3 from _pysha3 import sha3_256
4 from app.model import receiver
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 {
27         "response": response.text[:-1]
28     }
29
30
31 def decode_raw_transaction(raw_transaction_str):
32     raw_transaction_dict = {
33         "raw_transaction": raw_transaction_str
34     }
35     raw_transaction_json = json.dumps(raw_transaction_dict)
36     headers = {
37         "content-type": "application/json",
38         "accept": "application/json"
39     }
40     url = 'http://127.0.0.1:9888/decode-raw-transaction'
41     response = requests.post(url, headers=headers, data=raw_transaction_json)
42     return {
43         "response": response.text[:-1]
44     }
45
46
47 def get_uvarint(uvarint_str):
48     uvarint_bytes = bytes.fromhex(uvarint_str)
49     x, s, i = 0, 0, 0
50     while True:
51         b = uvarint_bytes[i]
52         if b < 0x80:
53             if i > 9 or i == 9 and b > 1:
54                 return "overflow"
55             return x | int(b) << s, i + 1
56         x |= int(b & 0x7f) << s
57         s += 7
58         i += 1
59
60
61 '''
62 get_spend_output_id create tx_input spend output id
63 test data 1:
64   source_id_hexstr: 28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21
65   asset_id_hexstr: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
66   amount_int: 41250000000
67   source_position_int: 0
68   vmversion_int: 1
69   control_program_hexstr: 00149335b1cbd4a77b78e33315a0ed10a95b12e7ca48
70   spend_output_id_hexstr: f229ec6f403d586dc87aa2546bbe64c5f7b5f46eb13c6ee4823d03bc88a7cf17
71 '''
72 def get_spend_output_id(source_id_hexstr, asset_id_hexstr, amount_int, source_position_int, vmversion_int, control_program_hexstr):
73     amount_hexstr = amount_int.to_bytes(8, byteorder='little').hex()
74     source_position_hexstr = source_position_int.to_bytes(8, byteorder='little').hex()
75     vmversion_hexstr = vmversion_int.to_bytes(8, byteorder='little').hex()
76     cp_length_int = len(control_program_hexstr) // 2
77     cp_length_hexstr = cp_length_int.to_bytes((cp_length_int.bit_length() + 7) // 8, byteorder='little').hex()
78     sc_hexstr = source_id_hexstr + asset_id_hexstr + amount_hexstr + source_position_hexstr + vmversion_hexstr + cp_length_hexstr +  control_program_hexstr
79     innerhash_bytes = sha3_256(bytes.fromhex(sc_hexstr)).digest()
80     spend_bytes = b'entryid:output1:' + innerhash_bytes
81     spend_output_id_hexstr = sha3_256(spend_bytes).hexdigest()
82     return spend_output_id_hexstr
83
84 '''
85 get_input_id create tx input_id
86 test data 1:
87     spend_output_id_hexstr: f229ec6f403d586dc87aa2546bbe64c5f7b5f46eb13c6ee4823d03bc88a7cf17
88     input_id_hexstr: 6e3f378ed844b143a335e306f4ba26746157589c87e8fc8cba6463c566c56768
89 '''
90 def get_input_id(spend_output_id_hexstr):
91     innerhash_bytes = sha3_256(bytes.fromhex(spend_output_id_hexstr)).digest()
92     input_id_hexstr = sha3_256(b'entryid:spend1:' + innerhash_bytes).hexdigest()
93     return input_id_hexstr
94
95
96 '''
97 decode_raw_tx decode raw transaction
98 testdata 1:
99     raw_tx_str: 070100010161015f28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d5990100011600149335b1cbd4a77b78e33315a0ed10a95b12e7ca48630240897e2d9d24a3b5faaed0579dee7597b401491595675f897504f8945b29d836235bd2fca72a3ad0cae814628973ebcd142d9d6cc92d0b2571b69e5370a98a340c208cb7fb3086f58db9a31401b99e8c658be66134fb9034de1d5c462679270b090702013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80f9f8bc98010116001406ce4b689ba026ffd3a7ca65d1d059546d4b78a000013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c6868f01011600147929ef91997c827bebf60fa608f876ea27523c4700
100     network_str: solotnet
101     transaction: 
102         {
103             "fee": 20000000,
104             "inputs": [
105                 {
106                 "address": "sm1qjv6mrj755aah3cenzksw6y9ftvfw0jjgk0l2mw",
107                 "amount": 41250000000,
108                 "asset_definition": {},
109                 "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
110                 "control_program": "00149335b1cbd4a77b78e33315a0ed10a95b12e7ca48",
111                 "input_id": "6e3f378ed844b143a335e306f4ba26746157589c87e8fc8cba6463c566c56768",
112                 "spent_output_id": "f229ec6f403d586dc87aa2546bbe64c5f7b5f46eb13c6ee4823d03bc88a7cf17",
113                 "type": "spend",
114                 "witness_arguments": [
115                     "897e2d9d24a3b5faaed0579dee7597b401491595675f897504f8945b29d836235bd2fca72a3ad0cae814628973ebcd142d9d6cc92d0b2571b69e5370a98a340c",
116                     "8cb7fb3086f58db9a31401b99e8c658be66134fb9034de1d5c462679270b0907"
117                 ]
118                 }
119             ],
120             "outputs": [
121                 {
122                 "address": "sm1qqm8yk6ym5qn0l5a8efjar5ze23k5k79qnvtslj",
123                 "amount": 40930000000,
124                 "asset_definition": {},
125                 "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
126                 "control_program": "001406ce4b689ba026ffd3a7ca65d1d059546d4b78a0",
127                 "id": "74c73266730d3c6ea32e8667ef9b867068736b84be240fe9fef205fa68bb7b95",
128                 "position": 0,
129                 "type": "control"
130                 },
131                 {
132                 "address": "sm1q0y57lyve0jp8h6lkp7nq37rkagn4y0z8hvh6kq",
133                 "amount": 300000000,
134                 "asset_definition": {},
135                 "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
136                 "control_program": "00147929ef91997c827bebf60fa608f876ea27523c47",
137                 "id": "f115a833d0c302a5006032858a7ed3987f0feb2daf2a9f849384950e4766af51",
138                 "position": 1,
139                 "type": "control"
140                 }
141             ],
142             "size": 333,
143             "time_range": 0,
144             "tx_id": "814a73dd57bae67c604f9cbc696cbc42035577423408cb9267136ed971e2bf63",
145             "version": 1
146         }
147 '''
148 def decode_raw_tx(raw_tx_str, network_str):
149     tx = {
150         "fee": 0,
151         "inputs": [],
152         "outputs": [],
153         "size": 0,
154         "time_range": 0,
155         "tx_id": "",
156         "version": 0
157     }
158     tx['fee'] = 0
159     tx['size'] = len(raw_tx_str) // 2
160     length = 0
161     offset = 2
162     tx['version'], length = get_uvarint(raw_tx_str[offset:offset+16])
163     offset = offset + 2 * length
164     tx['time_range'], length = get_uvarint(raw_tx_str[offset:offset+16])
165     offset = offset + 2 * length
166     tx_input_amount, length = get_uvarint(raw_tx_str[offset:offset+8])
167     offset = offset + 2 * length
168     for _ in range(tx_input_amount):
169         tx_input = {
170             "address": "",
171             "amount": 0,
172             "asset_definition": {},
173             "asset_id": "",
174             "control_program": "",
175             "input_id": "",
176             "spend_output_id": "",
177             "type": "",
178             "witness_arguments": []
179         }
180         _, length = get_uvarint(raw_tx_str[offset:offset+16])
181         offset = offset + 2 * length
182         _, length = get_uvarint(raw_tx_str[offset:offset+16])
183         offset = offset + 2 * length
184         input_type = int(raw_tx_str[offset:offset+2], 16)
185         offset += 2
186         if input_type == 0:
187             pass
188         elif input_type == 1:
189             tx_input['type'] = "spend"
190             _, length = get_uvarint(raw_tx_str[offset:offset+16])
191             offset = offset + 2 * length
192             source_id = raw_tx_str[offset:offset+64]
193             offset += 64
194             tx_input['asset_id'] = raw_tx_str[offset:offset+64]
195             offset += 64
196             tx_input['amount'], length = get_uvarint(raw_tx_str[offset:offset+16])
197             offset = offset + 2 * length
198             tx['fee'] += tx_input['amount']
199             source_positon, length = get_uvarint(raw_tx_str[offset:offset+16])
200             offset = offset + 2 * length
201             vmversion, length = get_uvarint(raw_tx_str[offset:offset+16])
202             offset = offset + 2 * length
203             control_program_length, length = get_uvarint(raw_tx_str[offset:offset+16])
204             offset = offset + 2 * length
205             tx_input['control_program'] = raw_tx_str[offset:offset+2*control_program_length]
206             offset = offset + 2 * control_program_length
207             tx_input['address'] = receiver.create_address(tx_input['control_program'], network_str)['address']
208             _, length = get_uvarint(raw_tx_str[offset:offset+16])
209             offset = offset + 2 * length
210             witness_arguments_amount, length = get_uvarint(raw_tx_str[offset:offset+16])
211             offset = offset + 2 * length
212             tx_input['spend_output_id'] = get_spend_output_id(source_id, tx_input['asset_id'], tx_input['amount'], source_positon, vmversion, tx_input['control_program'])
213             tx_input['input_id'] = get_input_id(tx_input['spend_output_id'])
214             for _ in range(witness_arguments_amount):
215                 argument_length, length = get_uvarint(raw_tx_str[offset:offset+16])
216                 offset = offset + 2 * length
217                 argument = raw_tx_str[offset:offset+2*argument_length]
218                 offset = offset + 2 * argument_length
219                 tx_input['witness_arguments'].append(argument)
220             tx['inputs'].append(tx_input)
221         elif input_type == 2:
222             pass
223     tx_output_amount, length = get_uvarint(raw_tx_str[offset:offset+16])
224     offset = offset + 2 * length
225     for i in range(tx_output_amount):
226         tx_output = {
227             "address": "",
228             "amount": 0,
229             "asset_definition": {},
230             "asset_id": "",
231             "control_program": "",
232             "id": "",
233             "position": 0,
234             "type": ""
235         }
236         tx_output['position'] = i
237         _, length = get_uvarint(raw_tx_str[offset:offset+16])
238         offset = offset + 2 * length
239         _, length = get_uvarint(raw_tx_str[offset:offset+16])
240         offset = offset + 2 * length
241         tx_output['asset_id'] = raw_tx_str[offset:offset+64]
242         offset = offset + 64
243         tx_output['amount'], length = get_uvarint(raw_tx_str[offset:offset+16])
244         offset = offset + 2 * length
245         tx['fee'] -= tx_output['amount']
246         _, length = get_uvarint(raw_tx_str[offset:offset+16])
247         offset = offset + 2 * length
248         control_program_length, length = get_uvarint(raw_tx_str[offset:offset+16])
249         offset = offset + 2 * length
250         tx_output['control_program'] = raw_tx_str[offset:offset+2*control_program_length]
251         offset = offset + 2 * control_program_length
252         tx_output['address'] = receiver.create_address(tx_output['control_program'], network_str)['address']
253         _, length = get_uvarint(raw_tx_str[offset:offset+16])
254         offset = offset + 2 * length
255         tx['outputs'].append(tx_output)
256     return tx