def submit_txn_(self, msg, submit): headers = {'Content-Type': 'application/octet-stream'} r = requests.post(self.WEB_SERVER_ADDR + '/txn/sheets/sheet', data=msg.binary(self._coin.magic), headers=headers, timeout=30) print('>>> 发送数据1\n:', hexlify(msg.binary(self._coin.magic)), len(hexlify(msg.binary(self._coin.magic)))) if r.status_code == 200: msg2 = protocol.Message.parse(r.content, self._coin.magic) print(">>> 接收数据1\n:", hexlify(r.content), len(hexlify(r.content))) print(">>> 接收数据\n:", msg2) # print('>>> r.content:',r.content,len(r.content)) # print('>>> r.content:',hexlify(r.content),len(hexlify(r.content))) if msg2.command == protocol.OrgSheet.command: # assert(msg2.sequence == self._sequence) # step 1: check message is not imitation # wait to do: verify msg.signature ... # check pay_to balance coin_hash = self._wallet.publicHash() + self._wallet.coin_type d = {} for p in msg.pay_to: if p.value != 0 or p.address[ 0:1] != b'\x6a': # not OP_RETURN d[util.base58.decode_check(p.address)[1:]] = p.value print('>>> p.address:', util.base58.decode_check(p.address)[1:], len(util.base58.decode_check(p.address)[1:])) print('>>> d:', d, len(d)) # 打印msg2字段信息 pks_out = msg2.pks_out # print('>>> pks_out:',pks_out,len(pks_out)) # print('pks_out items:',str(pks_out[0])) for idx in range(len(msg2.tx_out)): item = msg2.tx_out[idx] # print('>>> item:',item) # OP_RETURN if item.value == 0 and item.pk_script[0:1] == b'\x6a': continue # ignore # addr = script.get_script_address(item.pk_script,None) # if not addr: # print('Error: invalid output address (idx=%i)' % (idx,)) # return 0 # else: # value_ = d.pop(addr,None) # if item.value != value_: # if (value_ is None) and addr[2:] == coin_hash: # pass # else: # print('Error: invalid output value (idx=%i)' % (idx,)) # return 0 # for addr in d.keys(): # if coin_hash != addr[2:]: # the left address should be pay-to-self # print('Error: unknown output address (%s)' % (hexlify(addr),)) # return 0 # be ensure not pay to unexpected person # step 2: sign first pks_out (numbers of tx_in) pks_out0 = msg2.pks_out[0].items pks_num = len(pks_out0) print('>>> pks_out0:', pks_out0, len(pks_out0)) print('>>> pks_num:', pks_num) tx_ins2 = [] pub_key = self._wallet.publicKey() print('>>> pub_key', hexlify(pub_key), len(hexlify(pub_key))) for (idx, tx_in) in enumerate(msg2.tx_in): # sign every inputs if idx < pks_num: hash_type = 1 payload = script.make_payload(pks_out0[idx], msg2.version, msg2.tx_in, msg2.tx_out, 0, idx, hash_type) # lock_time=0 # 76b8230000db83cf42e02199d4fa29d14a197a167ade519298f0c2f98ec5478092497bcd5c00b7ac print('>>> pks_out0[idx]:', pks_out0[idx]) print('>>> msg2.version:', msg2.version) # 1 print('>>> msg2.tx_in:', msg2.tx_in) print('>>> msg2.tx_out:', msg2.tx_out) print('>>> idx:', idx) # 0 print('>>> hash_type:', hash_type) # 1 # print('......payload:',payload) payload1 = hexlify(payload) print('>>> ready sign payload:', payload, len(payload)) print('>>> ready sign hexpayload:', payload1, len(payload1)) sig_test = self._wallet.sign(payload) sig_test_s = hexlify(sig_test) print('>>> sig_test_s:', sig_test_s) sig = self._wallet.sign(payload) + CHR(hash_type) print('>>> sig:', sig, len(sig)) print('>>> CHR(hash_type):', CHR(hash_type), len(CHR(hash_type))) sig_script = CHR(len(sig)) + sig + \ CHR(len(pub_key)) + pub_key print('>>> sig_script:', sig_script, len(sig_script)) tx_ins2.append( protocol.TxnIn(tx_in.prev_output, sig_script, tx_in.sequence)) print('>>> sig_script:', sig_script, len(sig_script)) else: tx_ins2.append(tx_in) print('tx_ins2:', tx_ins2, len(tx_ins2)) # step 3: make payload and submit txn = protocol.Transaction(msg2.version, tx_ins2, msg2.tx_out, msg2.lock_time, b'') # sig_raw = b'' print('>> txn:', txn) payload = txn.binary(self._coin.magic) print('>>txn payload:', payload, len(payload), hexlify(payload)) print('>> payload_hex:', hexlify(payload), len(hexlify(payload))) hash_ = util.sha256d(payload[24:-1]) # exclude sig_raw print('>> hash_:', hash_, len(hash_)) state_info = [ msg2.sequence, txn, 'requested', hash_, msg2.last_uocks ] self._wait_submit.append(state_info) while len(self._wait_submit) > self.SHEET_CACHE_SIZE: del self._wait_submit[0] if submit: unsign_num = len(msg2.tx_in) - pks_num print('>>> len(msg2.tx_in):', len(msg2.tx_in)) print('>>> pks_num:', pks_num) if unsign_num != 0: # leaving to sign print('Warning: some input not signed: %i' % (unsign_num, )) # return 0 else: print('>>> txn.binary(self._coin.magic):', txn.binary(self._coin.magic), len(txn.binary(self._coin.magic))) r2 = requests.post(self.WEB_SERVER_ADDR + '/txn/sheets/txn', data=txn.binary(self._coin.magic), headers=headers, timeout=30) if r2.status_code == 200: print('r2.content:', r2.content, len(r2.content)) msg3 = protocol.Message.parse( r2.content, self._coin.magic) print('>>> msg3:', msg3) print('>>> hash_:', hash_, len(hash_)) print('>>> msg3.hash:', msg3.hash) if msg3.command == protocol.UdpConfirm.command and msg3.hash == hash_: state_info[2] = 'submited' print('>>> msg2:', msg2) print('>>> msg2.sequence:', msg2.sequence) return msg2.sequence # else: return 0 # meet unexpected error else: print('Error: ' + self.get_reject_msg_(r2)) # return 0 else: return msg2.sequence else: print('Error: ' + self.get_reject_msg_(r)) return 0
def submit_txn_(self, msg, submit): headers = {'Content-Type': 'application/octet-stream'} r = requests.post(self.WEB_SERVER_ADDR + '/txn/sheets/sheet', data=msg.binary(self._coin.magic), headers=headers, timeout=30) if r.status_code == 200: msg2 = protocol.Message.parse(r.content, self._coin.magic) if msg2.command == protocol.OrgSheet.command: # assert(msg2.sequence == self._sequence) # step 1: check message is not imitation # wait to do: verify msg.signature ... # check pay_to balance coin_hash = self._wallet.publicHash() + self._wallet.coin_type d = {} for p in msg.pay_to: if p.value != 0 or p.address[ 0:1] != b'\x6a': # not OP_RETURN d[util.base58.decode_check(p.address)[1:]] = p.value for idx in range(len(msg2.tx_out)): item = msg2.tx_out[idx] if item.value == 0 and item.pk_script[ 0:1] == b'\x6a': # OP_RETURN continue # ignore addr = script.get_script_address(item.pk_script, None) if not addr: print('Error: invalid output address (idx=%i)' % (idx, )) return 0 else: value_ = d.pop(addr, None) if item.value != value_: if (value_ is None) and addr[2:] == coin_hash: pass else: print('Error: invalid output value (idx=%i)' % (idx, )) return 0 for addr in d.keys(): if coin_hash != addr[ 2:]: # the left address should be pay-to-self print('Error: unknown output address (%s)' % (hexlify(addr), )) return 0 # be ensure not pay to unexpected person # step 2: sign first pks_out (numbers of tx_in) pks_out0 = msg2.pks_out[0].items pks_num = len(pks_out0) tx_ins2 = [] pub_key = self._wallet.publicKey() for (idx, tx_in) in enumerate(msg2.tx_in): # sign every inputs if idx < pks_num: hash_type = 1 payload = script.make_payload(pks_out0[idx], msg2.version, msg2.tx_in, msg2.tx_out, 0, idx, hash_type) # lock_time=0 sig = self._wallet.sign(payload) + CHR(hash_type) sig_script = CHR(len(sig)) + sig + CHR( len(pub_key)) + pub_key tx_ins2.append( protocol.TxnIn(tx_in.prev_output, sig_script, tx_in.sequence)) else: tx_ins2.append(tx_in) # step 3: make payload and submit txn = protocol.Transaction(msg2.version, tx_ins2, msg2.tx_out, msg2.lock_time, b'') # sig_raw = b'' payload = txn.binary(self._coin.magic) hash_ = util.sha256d(payload[24:-1]) # exclude sig_raw state_info = [ msg2.sequence, txn, 'requested', hash_, msg2.last_uocks ] self._wait_submit.append(state_info) while len(self._wait_submit) > self.SHEET_CACHE_SIZE: del self._wait_submit[0] if submit: unsign_num = len(msg2.tx_in) - pks_num if unsign_num != 0: # leaving to sign print('Warning: some input not signed: %i' % (unsign_num, )) # return 0 else: r2 = requests.post(self.WEB_SERVER_ADDR + '/txn/sheets/txn', data=txn.binary(self._coin.magic), headers=headers, timeout=30) if r2.status_code == 200: msg3 = protocol.Message.parse( r2.content, self._coin.magic) if msg3.command == protocol.UdpConfirm.command and msg3.hash == hash_: state_info[2] = 'submited' return msg2.sequence # else: return 0 # meet unexpected error else: print('Error: ' + self.get_reject_msg_(r2)) # return 0 else: return msg2.sequence else: print('Error: ' + self.get_reject_msg_(r)) return 0
def txn_sheets_(environ, method, response, action): if action == 'sheet': if method == 'POST': sErr = ''; sequence = 0 try: data, msg = binary_input(environ) # from post data with bitcoin-msg-format if msg.command == 'makesheet': if (msg.vcn & node._link_mask) != node._chain_no: sErr = 'chain no mismatch' elif DbLocker.wait_enter(15): # max wait 10 seconds ret = None try: if node.in_catching(): sErr = 'node not ready' else: sequence = msg.sequence pay_from = [(item.value,item.address) for item in msg.pay_from] pay_to = [(item.value,item.address) for item in msg.pay_to] (tx,pks_list,last_uocks) = node.make_txn_sheet(pay_from,pay_to,msg.scan_count,msg.min_utxo,msg.max_utxo,msg.sort_flag,msg.last_uocks) if tx: b = [protocol.format.VarStrList(item) for item in pks_list] sig = server_sign(msg.sequence,b,last_uocks,tx.version,tx.tx_in,tx.tx_out,tx.lock_time) msg2 = protocol.OrgSheet(msg.sequence,b,last_uocks,tx.version,tx.tx_in,tx.tx_out,tx.lock_time,sig) ret = binary_result(200,msg2.binary(node.coin.magic),response) except Exception as e: sErr = str(e) traceback.print_exc() DbLocker.leave() if ret: return ret else: sErr = 'require DB locker failed' else: sErr = 'node in busy' except Exception as e: sErr = str(e) traceback.print_exc() if not sErr: sErr = 'unknown error' bin_msg = protocol.UdpReject(sequence,sErr,'makesheet').binary(node.coin.magic) return binary_result(200,bin_msg,response) elif action == 'txn': if method == 'POST': sErr = '' try: data, msg = binary_input(environ) # wait to do: set msg.sig_raw and adjust data # ... if msg.command != 'tx': sErr = 'invalid txn format' elif DbLocker.wait_enter(15): ret = None try: if node.in_catching(): sErr = 'node not ready' else: node._apiserver_cmd.insert(0,('relay_sheet',msg,data)) hash_ = util.sha256d(data[24:-1]) # prefix message is 24 bytes, last byte is sig_raw, the left is payload msg2 = protocol.UdpConfirm(hash_,0xffffffff) ret = binary_result(200,msg2.binary(node.coin.magic),response) except Exception as e: sErr = str(e) traceback.print_exc() DbLocker.leave() if ret: return ret else: sErr = 'require DB locker failed' except Exception as e: sErr = str(e) traceback.print_exc() if not sErr: sErr = 'unknown error' bin_msg = protocol.UdpReject(0,sErr,'transaction').binary(node.coin.magic) return binary_result(200,bin_msg,response) elif action == 'state': if method == 'GET': sErr = '' try: param = http_input(environ) txn_hash = param.get('hash','') # txn_hash should be utf-8 string txn_detail = int(param.get('detail',0)) if txn_hash: txn_hash = unhexlify(txn_hash) # txn_hash has changed to bytes if DbLocker.wait_enter(15): ret = None try: if node.in_catching(): sErr = 'node not ready' else: txn2 = node.txns_get(txn_hash,only_main=True) # get mainchain transcation if txn2: block = node.block_get_(txn2) if block and block.mainchain: if txn_detail: bin_msg = protocol.UtxoState(node._link_no,[block.height],[txn2.index << 16],[txn2]) ret = binary_result(200,bin_msg.binary(node.coin.magic),response) else: confirm_num = node.chain_height - block.height txn_idx = txn2.index msg2 = protocol.UdpConfirm(txn_hash,((txn_idx&0xffff)<<48) | ((confirm_num&0xffff)<<32) | (block.height&0xffffffff)) ret = binary_result(200,msg2.binary(node.coin.magic),response) else: sErr = 'invalid block' else: txn2 = node._search_mempool(txn_hash) if txn2: if txn_detail: bin_msg = protocol.UtxoState(node._link_no,[0],[0],[txn2]) ret = binary_result(200,bin_msg.binary(node.coin.magic),response) else: sErr = 'in pending state' else: sErr = 'no transaction' except Exception as e: sErr = str(e) traceback.print_exc() DbLocker.leave() if ret: return ret else: sErr = 'require DB locker failed' else: sErr = 'invalid argument' except Exception as e: sErr = str(e) traceback.print_exc() if not sErr: sErr = 'unknown error' bin_msg = protocol.UdpReject(0,sErr,'state').binary(node.coin.magic) return binary_result(200,bin_msg,response) elif action == 'txns': # receive many txn, it is useful for testing if method == 'POST': succNum = 0; errNum = 0 try: dataBuf = environ['wsgi.input'].read(int(environ.get('CONTENT_LENGTH',0))) while True: msgLen = protocol.Message.first_msg_len(dataBuf) if msgLen is None or msgLen > len(dataBuf): break # ignore if not enough bytes # parse the message and handle it data = dataBuf[:msgLen] dataBuf = dataBuf[msgLen:] msg = protocol.Message.parse(data,curr_coin.magic) # wait to do: set msg.sig_raw and adjust data # ... if msg.command == 'tx' and DbLocker.wait_enter(15): try: if node.in_catching(): print('tx command received, but node not ready') else: node._apiserver_cmd.insert(0,('relay_sheet',msg,data)) succNum += 1 # not reply: protocol.UdpConfirm(util.sha256d(data[24:-1]),0xffffffff) except Exception as e: errNum += 1 traceback.print_exc() DbLocker.leave() except Exception as e: traceback.print_exc() sErr = '%i:%i' % (succNum,errNum) bin_msg = protocol.UdpReject(0,sErr,'txns').binary(node.coin.magic) return binary_result(200,bin_msg,response)