Beispiel #1
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)

        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
Beispiel #2
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)