Ejemplo n.º 1
0
   def __init__(self, lboxID, lboxName, script, M, N):
      self.uniqueIDB58 = lboxID
      self.shortName   = lboxName
      self.binScript   = script
      self.M           = M
      self.N           = N

      if getTxOutScriptType(script) == CPP_TXOUT_P2SH:
         self.p2shScrAddr = script_to_scrAddr(self.binScript)
      elif getTxOutScriptType(script) == CPP_TXOUT_MULTISIG:
         self.p2shScrAddr = script_to_scrAddr(script_to_p2sh_script(self.binScript))
      else:
         raise BadAddressError('Must initialize [mocked] lbox with MS or P2SH')
Ejemplo n.º 2
0
def distributeBtc(masterWallet, amount, sendingAddrList):
   pytx = None
   setupTheBDM()
   try:
      recipValuePairs = []
      utxoList = []
      for sendingAddr in sendingAddrList:
         addr160 = sendingAddr.getAddr160()
         # Make sure the sending addresses are in the masterWallet
         if not masterWallet.hasAddr(addr160):
            raise WalletAddressError, 'Address is not in wallet! [%s]' % sendingAddr.getAddrStr()
         utxoList.extend(masterWallet.getAddrTxOutList(addr160))
   

      for importedAddr in masterWallet.getLinearAddrList():
         if importedAddr.chainIndex<0:
            recipValuePairs.append((importedAddr.getAddr160(),amount))
      totalSpend = len(recipValuePairs)*amount
      fee = calcMinSuggestedFees(utxoList, totalSpend, MIN_RELAY_TX_FEE, len(recipValuePairs))[1]
      # Get the necessary utxo list
      selectedUtxoList = PySelectCoins(utxoList, totalSpend, fee)
      # get total value   
      totalAvailable = sum([u.getValue() for u in selectedUtxoList])
      totalChange = totalAvailable - (totalSpend + fee)

      # Make sure there are funds to cover the transaction.
      if totalChange < 0:
         print '***ERROR: you are trying to spend more than your balance!'
         raise NegativeValueError
      recipValuePairs.append((masterWallet.getNextUnusedAddress().getAddr160(), totalChange ))

      # ACR:  To support P2SH in general, had to change createFromTxOutSelection
      #       to take full scripts, not just hash160 values.  Convert the list
      #       before passing it in
      scrPairs = [[hash160_to_p2pkhash_script(r), v] for r,v in recipValuePairs]
            # we're providing a key map for the inputs.
      pubKeyMap = {}
      for utxo in selectedUtxoList:
         scrType = getTxOutScriptType(utxo.getScript())
         if scrType in CPP_TXOUT_STDSINGLESIG:
            scrAddr = utxo.getRecipientScrAddr()
            a160 = scrAddr_to_hash160(scrAddr)[1]
            addrObj = masterWallet.getAddrByHash160(a160)
            if addrObj:
               pubKeyMap[scrAddr] = addrObj.binPublicKey65.toBinStr()

      ustx = UnsignedTransaction().createFromTxOutSelection(selectedUtxoList, scrPairs, pubKeyMap)
      
      masterWallet.unlock(securePassphrase = SecureBinaryData(getpass('Enter your secret string:')))
      # Sign and prepare the final transaction for broadcast
      masterWallet.signUnsignedTx(ustx)
      pytx = ustx.getPyTxSignedIfPossible()
   
      print '\nSigned transaction to be broadcast using Armory "offline transactions"...'
      print ustx.serializeAscii()
   finally:
      TheBDM.beginCleanShutdown()
   return pytx
Ejemplo n.º 3
0
def distributeBtc(masterWallet, amount, sendingAddrList):
   pytx = None
   setupTheBDM()
   try:
      recipValuePairs = []
      utxoList = []
      for sendingAddr in sendingAddrList:
         addr160 = sendingAddr.getAddr160()
         # Make sure the sending addresses are in the masterWallet
         if not masterWallet.hasAddr(addr160):
            raise WalletAddressError, 'Address is not in wallet! [%s]' % sendingAddr.getAddrStr()
         utxoList.extend(masterWallet.getAddrTxOutList(addr160))
   

      for importedAddr in masterWallet.getLinearAddrList():
         if importedAddr.chainIndex<0:
            recipValuePairs.append((importedAddr.getAddr160(),amount))
      totalSpend = len(recipValuePairs)*amount
      fee = calcMinSuggestedFees(utxoList, totalSpend, MIN_RELAY_TX_FEE, len(recipValuePairs))
      # Get the necessary utxo list
      selectedUtxoList = PySelectCoins(utxoList, totalSpend, fee)
      # get total value   
      totalAvailable = sum([u.getValue() for u in selectedUtxoList])
      totalChange = totalAvailable - (totalSpend + fee)

      # Make sure there are funds to cover the transaction.
      if totalChange < 0:
         print '***ERROR: you are trying to spend more than your balance!'
         raise NegativeValueError
      recipValuePairs.append((masterWallet.getNextUnusedAddress().getAddr160(), totalChange ))

      # ACR:  To support P2SH in general, had to change createFromTxOutSelection
      #       to take full scripts, not just hash160 values.  Convert the list
      #       before passing it in
      scrPairs = [[hash160_to_p2pkhash_script(r), v] for r,v in recipValuePairs]
            # we're providing a key map for the inputs.
      pubKeyMap = {}
      for utxo in selectedUtxoList:
         scrType = getTxOutScriptType(utxo.getScript())
         if scrType in CPP_TXOUT_STDSINGLESIG:
            scrAddr = utxo.getRecipientScrAddr()
            a160 = scrAddr_to_hash160(scrAddr)[1]
            addrObj = masterWallet.getAddrByHash160(a160)
            if addrObj:
               pubKeyMap[scrAddr] = addrObj.binPublicKey65.toBinStr()

      ustx = UnsignedTransaction().createFromTxOutSelection(selectedUtxoList, scrPairs, pubKeyMap)
      
      masterWallet.unlock(securePassphrase = SecureBinaryData(getpass('Enter your secret string:')))
      # Sign and prepare the final transaction for broadcast
      masterWallet.signUnsignedTx(ustx)
      pytx = ustx.getPyTxSignedIfPossible()
   
      print '\nSigned transaction to be broadcast using Armory "offline transactions"...'
      print ustx.serializeAscii()
   finally:
      TheBDM.beginCleanShutdown()
   return pytx
Ejemplo n.º 4
0
def getDisplayStringForScript(binScript, wltMap, lboxList, maxChars=256, 
                              doBold=0, prefIDOverAddr=False, 
                              lblTrunc=12, lastTrunc=12):
   """
   NOTE: This was originally in ArmoryQt.py, but we really needed this to be
   more widely accessible.  And it's easier to test when this is in ArmoryUtils.  
   Yes, I realize that it's awkward that we have wltMap {WltID-->Wallet} but
   we have a lboxList [Lbox0, Lbox1, ...].  I will have to standardize the 
   member names and lookup structures.

   We have a script and want to show the user something useful about it.
   We have a couple different display modes, since some formats are space-
   constrained.  For instance, the DlgConfirmSend dialog only has space
   for 34 letters, as it was designed to be showing only an address string.

   This is similar to self.getContribStr, but that method is more focused
   on identifying participants of a multi-sig transaction.  It almost
   works here, but we need one that's more general.

   Consider a 3-of-5 lockbox with ID Abcd1234z and label 
   "My long-term savings super-secure" and p2sh address 2m83zQr9981pmKnrSwa32

                   10        20        30        40        50        60        70
         |         |         |         |         |         |         |         |
   256   Lockbox 3-of-5 "Long-term savings" (2m83zQr9981p...)
   256   Lockbox 3-of-5 "Long-term savings" (Abcd1234z)
    50   Lockbox 3-of-5 "Long-term sa..." (2m83zQr9981p...)
    35   Lockbox 3-of-5 "Long-term savings"
    32   Lockbox 3-of-5 "Long-term sa..."

   256   Wallet "LabelLabelLabelLabelLabelLabel" (1j93CnrAA3xn...)
   256   Wallet "LabelLabelLabelLabelLabelLabel" (Abcd1234z)
    50   Wallet "LabelLabelLa..." (1j93CnrAA3xn...)
    35   Wallet "LabelLabelLa..." 

   So we will always show the type and the label (possibly truncated).  If
   we can show the ID or Addr (whichever is preferred) we will do so, otherwise
   it gets left out.   If our truncation leaves the string too short, we 
   usually try to add back in a few chars.  It's not perfect, but it seems to 
   work reliably.

   The doBold arg indicates that we want to add html bold tags around the 
   first N parts of the return.  This is applied after the length calculations
   are performed, as bolding will have a very small impact on width
   """

   if maxChars<32:
      LOGERROR('getDisplayStringForScript() req at least 32 bytes output')
      return None

   scriptType = getTxOutScriptType(binScript) 
   scrAddr = script_to_scrAddr(binScript)

   if scriptType != CPP_TXOUT_OPRETURN:
      wlt = None
      for iterID,iterWlt in wltMap.iteritems():
         if iterWlt.hasScrAddr(scrAddr):
            wlt = iterWlt
            break
   
      lbox = None
      if wlt is None:
         searchScrAddr = scrAddr
         if scriptType==CPP_TXOUT_MULTISIG:
            searchScrAddr = script_to_scrAddr(script_to_p2sh_script(binScript))
            
         for iterLbox in lboxList:
            if iterLbox.hasScrAddr(searchScrAddr):
               lbox = iterLbox
               break
   else:
      wlt = None
      lbox = None

   # Return these with the display string
   wltID  = wlt.uniqueIDB58  if wlt  else None
   lboxID = lbox.uniqueIDB58 if lbox else None


   if wlt is not None:
      strType = 'Wallet:'
      strLabel = wlt.labelName
      addrStr = None
      if scriptType in CPP_TXOUT_HAS_ADDRSTR:
         addrStr = scrAddr_to_addrStr(scrAddr)

      strLast = wlt.uniqueIDB58 if addrStr is None else addrStr
      strLast = wlt.uniqueIDB58 if prefIDOverAddr else strLast
   elif lbox is not None:
      strType  = 'Lockbox %d-of-%d:' % (lbox.M, lbox.N)
      strLabel = lbox.shortName
      addrStr = scrAddr_to_addrStr(scrAddr)
      strLast = lbox.uniqueIDB58 if prefIDOverAddr else addrStr
   else:
      strType = ''
      strLabel = ''
      strLast = ''
      addrStr = None



   def truncateStr(theStr, maxLen):
      if len(theStr) <= maxLen:
         return theStr
      else:
         return theStr[:maxLen-3] + '...'

   if len(strType) > 0:
      # We have something to display... do it and return
      lenType  = len(strType)
      lenLabel = len(strLabel) + 3
      lenLast  = len(strLast) + 3
      lenLabelTrunc = min(lenLabel + 3, lblTrunc  + 6)
      lenLastTrunc  = min(lenLast  + 3, lastTrunc + 6)

      if lenType + lenLabel + lenLast <= maxChars:
         strLabel = ' "%s"' % strLabel
         strLast  = ' (%s)' % strLast  if lenLast>0  else ''
      elif lenType + lenLabel + lenLastTrunc <= maxChars:
         extraChars = maxChars - (lenType + lenLabel + lenLastTrunc)
         lastTrunc += extraChars
         strLabel = ' "%s"' % strLabel
         strLast  = ' (%s)' % truncateStr(strLast,lastTrunc) if lenLast>0 else ''
      elif lenType + lenLabelTrunc + lenLastTrunc <= maxChars:
         extraChars = maxChars - (lenType + lenLabelTrunc + lenLastTrunc)
         lblTrunc += extraChars/2 
         lastTrunc += extraChars/2 
         strLabel = ' "%s"' % truncateStr(strLabel, lblTrunc)
         strLast  = ' (%s)' % truncateStr(strLast, lastTrunc) if lenLast>0 else ''
      elif lenType + lenLabel <= maxChars:
         strLabel = ' "%s"' % strLabel
         strLast  = ''
      elif lenType + lenLabelTrunc <= maxChars:
         lblTrunc += maxChars - (lenType + lenLabelTrunc)
         strLabel = ' "%s"' % truncateStr(strLabel, lblTrunc)
         strLast  = ''
      else:
         # Total last resort, actually leave the label out...
         # If we still can't fit it... too bad, we have to show something
         lastTrunc = max(maxChars - (lenType + 4), 6)
         strLabel = ''
         strLast  = ' %s' % truncateStr(strLast, lastTrunc)

      if doBold>0:   strType  = '<b>%s</b>' % strType
      if doBold>1:   strLabel = '<b>%s</b>' % strLabel
      if doBold>2:   strLast  = '<b>%s</b>' % strLast
      displayStr = ''.join([strType, strLabel, strLast])
      return {'String':  displayStr,
              'WltID':   wltID,
              'LboxID':  lboxID,
              'AddrStr': addrStr}



   # If we're here, it didn't match any loaded wlt or lockbox
   dispStr = ''
   if scriptType in CPP_TXOUT_HAS_ADDRSTR:
      addrStr = script_to_addrStr(binScript)
      if len(addrStr) <= maxChars:
         dispStr = addrStr
      else:
         dispStr = addrStr[:maxChars-3] + '...'
   elif scriptType == CPP_TXOUT_MULTISIG:
      M,N,a160s,pubs = getMultisigScriptInfo(binScript)
      lbID = calcLockboxID(binScript)
      dispStr = 'Unknown %d-of-%d (%s)' % (M,N,lbID)
      addrStr = script_to_addrStr(script_to_p2sh_script(binScript))
      if len(dispStr) + len(addrStr) + 3 <= maxChars:
         dispStr += ' [%s]' % addrStr
      elif len(dispStr) + lastTrunc + 6 <= maxChars:
         dispStr += ' [%s...]' % addrStr[:lastTrunc]
   elif len(binScript) == 0:
      dispStr = 'Unknown Input' 
   elif scriptType == CPP_TXOUT_OPRETURN:
      msgPos = 2
      if len(binScript) > 77:
         msgPos = 3
      msgStr = binScript[msgPos:]
      dispStr = 'Msg (%d bytes): %s' % (len(binScript) - msgPos, msgStr)
   else:
      addrStr = script_to_addrStr(script_to_p2sh_script(binScript))
      dispStr = 'Non-Standard: %s' % addrStr
      if len(dispStr) > maxChars:
         dispStr = dispStr[:maxChars-3] + '...'

   return {'String':  dispStr,
           'WltID':   None,
           'LboxID':  None,
           'AddrStr': addrStr}
Ejemplo n.º 5
0
def getDisplayStringForScript(binScript,
                              wltMap,
                              lboxList,
                              maxChars=256,
                              doBold=0,
                              prefIDOverAddr=False,
                              lblTrunc=12,
                              lastTrunc=12):
    """
   NOTE: This was originally in ArmoryQt.py, but we really needed this to be
   more widely accessible.  And it's easier to test when this is in ArmoryUtils.  
   Yes, I realize that it's awkward that we have wltMap {WltID-->Wallet} but
   we have a lboxList [Lbox0, Lbox1, ...].  I will have to standardize the 
   member names and lookup structures.

   We have a script and want to show the user something useful about it.
   We have a couple different display modes, since some formats are space-
   constrained.  For instance, the DlgConfirmSend dialog only has space
   for 34 letters, as it was designed to be showing only an address string.

   This is similar to self.getContribStr, but that method is more focused
   on identifying participants of a multi-sig transaction.  It almost
   works here, but we need one that's more general.

   Consider a 3-of-5 lockbox with ID Abcd1234z and label 
   "My long-term savings super-secure" and p2sh address 2m83zQr9981pmKnrSwa32

                   10        20        30        40        50        60        70
         |         |         |         |         |         |         |         |
   256   Lockbox 3-of-5 "Long-term savings" (2m83zQr9981p...)
   256   Lockbox 3-of-5 "Long-term savings" (Abcd1234z)
    50   Lockbox 3-of-5 "Long-term sa..." (2m83zQr9981p...)
    35   Lockbox 3-of-5 "Long-term savings"
    32   Lockbox 3-of-5 "Long-term sa..."

   256   Wallet "LabelLabelLabelLabelLabelLabel" (1j93CnrAA3xn...)
   256   Wallet "LabelLabelLabelLabelLabelLabel" (Abcd1234z)
    50   Wallet "LabelLabelLa..." (1j93CnrAA3xn...)
    35   Wallet "LabelLabelLa..." 

   So we will always show the type and the label (possibly truncated).  If
   we can show the ID or Addr (whichever is preferred) we will do so, otherwise
   it gets left out.   If our truncation leaves the string too short, we 
   usually try to add back in a few chars.  It's not perfect, but it seems to 
   work reliably.

   The doBold arg indicates that we want to add html bold tags around the 
   first N parts of the return.  This is applied after the length calculations
   are performed, as bolding will have a very small impact on width
   """

    if maxChars < 32:
        LOGERROR('getDisplayStringForScript() req at least 32 bytes output')
        return None

    scriptType = getTxOutScriptType(binScript)
    scrAddr = script_to_scrAddr(binScript)

    wlt = None
    for iterID, iterWlt in wltMap.iteritems():
        if iterWlt.hasScrAddr(scrAddr):
            wlt = iterWlt
            break

    lbox = None
    if wlt is None:
        searchScrAddr = scrAddr
        if scriptType == CPP_TXOUT_MULTISIG:
            searchScrAddr = script_to_scrAddr(script_to_p2sh_script(binScript))

        for iterLbox in lboxList:
            if searchScrAddr == iterLbox.p2shScrAddr:
                lbox = iterLbox
                break

    # Return these with the display string
    wltID = wlt.uniqueIDB58 if wlt else None
    lboxID = lbox.uniqueIDB58 if lbox else None

    if wlt is not None:
        strType = 'Wallet:'
        strLabel = wlt.labelName
        addrStr = None
        if scriptType in CPP_TXOUT_HAS_ADDRSTR:
            addrStr = scrAddr_to_addrStr(scrAddr)

        strLast = wlt.uniqueIDB58 if addrStr is None else addrStr
        strLast = wlt.uniqueIDB58 if prefIDOverAddr else strLast
    elif lbox is not None:
        strType = 'Lockbox %d-of-%d:' % (lbox.M, lbox.N)
        strLabel = lbox.shortName
        addrStr = scrAddr_to_addrStr(lbox.p2shScrAddr)
        strLast = lbox.uniqueIDB58 if prefIDOverAddr else addrStr
    else:
        strType = ''
        strLabel = ''
        strLast = ''
        addrStr = None

    def truncateStr(theStr, maxLen):
        if len(theStr) <= maxLen:
            return theStr
        else:
            return theStr[:maxLen - 3] + '...'

    if len(strType) > 0:
        # We have something to display... do it and return
        lenType = len(strType)
        lenLabel = len(strLabel) + 3
        lenLast = len(strLast) + 3
        lenLabelTrunc = min(lenLabel + 3, lblTrunc + 6)
        lenLastTrunc = min(lenLast + 3, lastTrunc + 6)

        if lenType + lenLabel + lenLast <= maxChars:
            strLabel = ' "%s"' % strLabel
            strLast = ' (%s)' % strLast if lenLast > 0 else ''
        elif lenType + lenLabel + lenLastTrunc <= maxChars:
            extraChars = maxChars - (lenType + lenLabel + lenLastTrunc)
            lastTrunc += extraChars
            strLabel = ' "%s"' % strLabel
            strLast = ' (%s)' % truncateStr(strLast,
                                            lastTrunc) if lenLast > 0 else ''
        elif lenType + lenLabelTrunc + lenLastTrunc <= maxChars:
            extraChars = maxChars - (lenType + lenLabelTrunc + lenLastTrunc)
            lblTrunc += extraChars / 2
            lastTrunc += extraChars / 2
            strLabel = ' "%s"' % truncateStr(strLabel, lblTrunc)
            strLast = ' (%s)' % truncateStr(strLast,
                                            lastTrunc) if lenLast > 0 else ''
        elif lenType + lenLabel <= maxChars:
            strLabel = ' "%s"' % strLabel
            strLast = ''
        elif lenType + lenLabelTrunc <= maxChars:
            lblTrunc += maxChars - (lenType + lenLabelTrunc)
            strLabel = ' "%s"' % truncateStr(strLabel, lblTrunc)
            strLast = ''
        else:
            # Total last resort, actually leave the label out...
            # If we still can't fit it... too bad, we have to show something
            lastTrunc = max(maxChars - (lenType + 4), 6)
            strLabel = ''
            strLast = ' %s' % truncateStr(strLast, lastTrunc)

        if doBold > 0: strType = '<b>%s</b>' % strType
        if doBold > 1: strLabel = '<b>%s</b>' % strLabel
        if doBold > 2: strLast = '<b>%s</b>' % strLast
        displayStr = ''.join([strType, strLabel, strLast])
        return {
            'String': displayStr,
            'WltID': wltID,
            'LboxID': lboxID,
            'AddrStr': addrStr
        }

    # If we're here, it didn't match any loaded wlt or lockbox
    dispStr = ''
    if scriptType in CPP_TXOUT_HAS_ADDRSTR:
        addrStr = script_to_addrStr(binScript)
        if len(addrStr) <= maxChars:
            dispStr = addrStr
        else:
            dispStr = addrStr[:maxChars - 3] + '...'
    elif scriptType == CPP_TXOUT_MULTISIG:
        M, N, a160s, pubs = getMultisigScriptInfo(binScript)
        lbID = calcLockboxID(binScript)
        dispStr = 'Unknown %d-of-%d (%s)' % (M, N, lbID)
        addrStr = script_to_addrStr(script_to_p2sh_script(binScript))
        if len(dispStr) + len(addrStr) + 3 <= maxChars:
            dispStr += ' [%s]' % addrStr
        elif len(dispStr) + lastTrunc + 6 <= maxChars:
            dispStr += ' [%s...]' % addrStr[:lastTrunc]
    elif len(binScript) == 0:
        dispStr = 'Unknown Input'
    else:
        addrStr = script_to_addrStr(script_to_p2sh_script(binScript))
        dispStr = 'Non-Standard: %s' % addrStr
        if len(dispStr) > maxChars:
            dispStr = dispStr[:maxChars - 3] + '...'

    return {
        'String': dispStr,
        'WltID': None,
        'LboxID': None,
        'AddrStr': addrStr
    }