def createFromCppUtxo(self, cppUtxo): self.scrAddr = cppUtxo.getRecipientScrAddr() self.val = cppUtxo.getValue() self.conf = cppUtxo.getNumConfirm() # For now, this will throw errors unless we always use hash160 scraddrs self.binScript = '\x76\xa9\x14' + CheckHash160(self.scrAddr) + '\x88\xac' self.txHash = cppUtxo.getTxHash() self.txOutIndex = cppUtxo.getTxOutIndex() return self
def pprintUnspentTxOutList(utxoList, headerLine='Coin Selection: '): totalSum = sum([u.getValue() for u in utxoList]) print headerLine, '(Total = %s BTC)' % coin2str(totalSum) print ' ','Owner Address'.ljust(34), print ' ','TxOutValue'.rjust(18), print ' ','NumConf'.rjust(8), print ' ','PriorityFactor'.rjust(16) for utxo in utxoList: a160 = CheckHash160(utxo.getRecipientScrAddr()) print ' ',hash160_to_addrStr(a160).ljust(34), print ' ',(coin2str(utxo.getValue()) + ' BTC').rjust(18), print ' ',str(utxo.getNumConfirm()).rjust(8), print ' ', ('%0.2f' % (utxo.getValue()*utxo.getNumConfirm()/(ONE_BTC*144.))).rjust(16)
def getRecipientHash160(self): return CheckHash160(self.scrAddr)
def sendDust(): try: utxiList = [] for utxo in self.dustTableModel.dustTxOutlist: # The PyCreateAndSignTx method require PyTx and PyBtcAddress objects rawTx = TheBDM.getTxByHash(utxo.getTxHash()).serialize() a160 = CheckHash160(utxo.getRecipientScrAddr()) for pyAddr in self.dustTableModel.wlt.addrMap.values(): if a160 == pyAddr.getAddr160(): pubKey = pyAddr.binPublicKey65.toBinStr() txoIdx = utxo.getTxOutIndex() utxiList.append( UnsignedTxInput(rawTx, txoIdx, None, pubKey)) break # Make copies, destroy them in the finally clause privKeyMap = {} for addrObj in self.dustTableModel.wlt.addrMap.values(): scrAddr = SCRADDR_P2PKH_BYTE + addrObj.getAddr160() if self.dustTableModel.wlt.useEncryption and self.dustTableModel.wlt.isLocked: # Target wallet is encrypted... unlockdlg = DlgUnlockWallet(self.dustTableModel.wlt, self.main, self.main, 'Unlock Wallet to Import') if not unlockdlg.exec_(): QMessageBox.critical(self, 'Wallet is Locked', \ 'Cannot send dust without unlocking the wallet!', \ QMessageBox.Ok) return privKeyMap[scrAddr] = addrObj.binPrivKey32_Plain.copy() signedTx = PyCreateAndSignTx( utxiList, [], privKeyMap, SIGHASH_NONE | SIGHASH_ANYONECANPAY) print "-------------" print binary_to_hex(signedTx.serialize()) # sock = socket.create_connection(('dust-b-gone.bitcoin.petertodd.org',80)) # sock.send(signedTx.serialize()) # sock.send(b'\n') # sock.close() except socket.error as err: QMessageBox.critical( self.main, tr('Negative Value'), tr(""" Failed to connect to dust-b-gone server: %s""" % err.strerror), QMessageBox.Ok) except NegativeValueError: QMessageBox.critical( self.main, tr('Negative Value'), tr(""" You must enter a positive value of at least 0.0000 0001 and less than %s for the dust limit.""" % MAX_DUST_LIMIT_STR), QMessageBox.Ok) except TooMuchPrecisionError: QMessageBox.critical( self.main.main, tr('Too much precision'), tr(""" Bitcoins can only be specified down to 8 decimal places. The smallest unit of a Bitcoin is 0.0000 0001 BTC. Please enter a dust limit of at least 0.0000 0001 and less than %s.""" % MAX_DUST_LIMIT_STR), QMessageBox.Ok) finally: for scraddr in privKeyMap: privKeyMap[scraddr].destroy()
def PySelectCoins(unspentTxOutInfo, targetOutVal, minFee=0, numRand=10, margin=CENT): """ Intense algorithm for coin selection: computes about 30 different ways to select coins based on the desired target output and the min tx fee. Then ranks the various solutions and picks the best one """ if sum([u.getValue() for u in unspentTxOutInfo]) < targetOutVal: return [] targExact = targetOutVal targMargin = targetOutVal+margin selectLists = [] # Start with the intelligent solutions with different sortings for sortMethod in range(8): diffSortList = PySortCoins(unspentTxOutInfo, sortMethod) selectLists.append(PySelectCoins_SingleInput_SingleValue( diffSortList, targExact, minFee )) selectLists.append(PySelectCoins_MultiInput_SingleValue( diffSortList, targExact, minFee )) selectLists.append(PySelectCoins_SingleInput_SingleValue( diffSortList, targMargin, minFee )) selectLists.append(PySelectCoins_MultiInput_SingleValue( diffSortList, targMargin, minFee )) selectLists.append(PySelectCoins_SingleInput_DoubleValue( diffSortList, targExact, minFee )) selectLists.append(PySelectCoins_MultiInput_DoubleValue( diffSortList, targExact, minFee )) selectLists.append(PySelectCoins_SingleInput_DoubleValue( diffSortList, targMargin, minFee )) selectLists.append(PySelectCoins_MultiInput_DoubleValue( diffSortList, targMargin, minFee )) # Throw in a couple random solutions, maybe we get lucky # But first, make a copy before in-place shuffling # NOTE: using list[:] like below, really causes a swig::vector<type> to freak out! #utxos = unspentTxOutInfo[:] #utxos = list(unspentTxOutInfo) for method in range(8,10): for i in range(numRand): utxos = PySortCoins(unspentTxOutInfo, method) selectLists.append(PySelectCoins_MultiInput_SingleValue(utxos, targExact, minFee)) selectLists.append(PySelectCoins_MultiInput_DoubleValue(utxos, targExact, minFee)) selectLists.append(PySelectCoins_MultiInput_SingleValue(utxos, targMargin, minFee)) selectLists.append(PySelectCoins_MultiInput_DoubleValue(utxos, targMargin, minFee)) # Now we define PyEvalCoinSelect as our sorting metric, and find the best solution scoreFunc = lambda ulist: PyEvalCoinSelect(ulist, targetOutVal, minFee) finalSelection = max(selectLists, key=scoreFunc) SCORES = getSelectCoinsScores(finalSelection, targetOutVal, minFee) if len(finalSelection)==0: return [] # If we selected a list that has only one or two inputs, and we have # other, tiny, unspent outputs from the same addresses, we should # throw one or two of them in to help clear them out. However, we # only do so if a plethora of conditions exist: # # First, we only consider doing this if the tx has <5 inputs already. # Also, we skip this process if the current tx doesn't have excessive # priority already -- we don't want to risk de-prioritizing a tx for # this purpose. # # Next we sort by LOWEST value, because we really benefit from this most # by clearing out tiny outputs. Along those lines, we don't even do # unless it has low priority -- don't want to take a high-priority utxo # and convert it to one that will be low-priority to start. # # Finally, we shouldn't do this if a high score was assigned to output # anonymity: this extra output may cause a tx with good output anonymity # to no longer possess this property IDEAL_NUM_INPUTS = 5 if len(finalSelection) < IDEAL_NUM_INPUTS and \ SCORES[IDX_OUTANONYM] == 0: utxoToHash160 = lambda a: CheckHash160(a.getRecipientScrAddr()) getPriority = lambda a: a.getValue() * a.getNumConfirm() getUtxoID = lambda a: a.getTxHash() + int_to_binary(a.getTxOutIndex()) alreadyUsedAddr = set( [utxoToHash160(utxo) for utxo in finalSelection] ) utxoSmallToLarge = sorted(unspentTxOutInfo, key=getPriority) utxoSmToLgIDs = [getUtxoID(utxo) for utxo in utxoSmallToLarge] finalSelectIDs = [getUtxoID(utxo) for utxo in finalSelection] for other in utxoSmallToLarge: # Skip it if it is already selected if getUtxoID(other) in finalSelectIDs: continue # We only consider UTXOs that won't link any new addresses together if not utxoToHash160(other) in alreadyUsedAddr: continue # Avoid zero-conf inputs altogether if other.getNumConfirm() == 0: continue # Don't consider any inputs that are high priority already if getPriority(other) > ONE_BTC*144: continue finalSelection.append(other) if len(finalSelection)>=IDEAL_NUM_INPUTS: break return finalSelection