Skip to content

Instantly share code, notes, and snippets.

@kumrzz
Last active December 8, 2016 12:28
Show Gist options
  • Save kumrzz/4a2de9588731e54475e41efd276d17ee to your computer and use it in GitHub Desktop.
Save kumrzz/4a2de9588731e54475e41efd276d17ee to your computer and use it in GitHub Desktop.
"""
assumes you've entered (sendamount+fee) greater than Wallet balance
ignores special treatment of vout for coinbase tx
ignores fee considerations, assumes this is already part of nTargetValue
https://github.com/bitcoin/bitcoin/blob/v0.5.3/src/wallet.cpp#L760
http://bitcoin.stackexchange.com/questions/1077/what-is-the-coin-selection-algorithm
"""
import random
def SelectCoins():
nTargetValue = 1.71#spend amount including fee
print 'nTargetValue: ', str(nTargetValue)
setCoinsRet = nValueRet = None
try:
print '1st pass:'
return SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet)
except:
try:
print '2nd pass:'
return SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet)
except:
print '3rd pass:'
return SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet)
def SelectCoinsMinConf(nTargetValue, nConfMine, nConfTheirs, setCoinsRet=None, nValueRet=None):
CWalletTx = [{'id':'utxoA','confs':1,'value':0.1, 'fromMe':True},
{'id':'utxoB','confs':0,'value':0.3, 'fromMe':True},
{'id':'utxoC','confs':1,'value':0.5, 'fromMe':False},
{'id':'utxoD','confs':1,'value':1.0, 'fromMe':False},]
for pcoin in CWalletTx:
if pcoin['fromMe']:
if pcoin['confs'] < nConfMine:
CWalletTx[:] = [d for d in CWalletTx if d != pcoin]
else:#not mine, conf acceptance further restricted:
if pcoin['confs'] < nConfTheirs:
CWalletTx[:] = [d for d in CWalletTx if d != pcoin]
print 'currentwalletchoice:' + ','.join([coin['id'] for coin in CWalletTx])
vCoins = []#list of utxos smaller than sendamount
for coin in CWalletTx:
n = coin['value']
if n == nTargetValue:
nBest = [coin]#converted nBest to list for future procs
print '1. exact single utxo match found'
break
else:
if n < nTargetValue:#adding utxo to vCoins if < sendamount
vCoins.append(coin)
try:
nBest#exit to end as nBest already located in prior section
except:
nTotalLower = sum(coin['value'] for coin in vCoins)
print 'nTotalLower: ', str(nTotalLower)
if nTotalLower == nTargetValue:
print '2. (sum(utxo<sendamt) == sendamount, usu. for a wallet sweep'
nBest = vCoins
else:
print '3. (sum(utxo<sendamt) <> sendamount'
if nTotalLower < nTargetValue:
tmplist = [x['value'] for x in CWalletTx if x not in vCoins]#utxos@ >sendamount
if len(tmplist) > 0:#coz else it fails @ nil utxo>sendamount
coinLowestLarger = CWalletTx[[x['value'] for x in CWalletTx].index(min(tmplist))]
#coinLowestLarger = min(x for x in CWalletTx if x not in vCoins)
print '3.+ coinLowestLarger: ', coinLowestLarger['id']
nBest = [coinLowestLarger]#converted nBest to list for future procs
else:#nTotalLower > nTargetValue
vfIncluded = []
for nRep in range(1,1000):
rndcount = random.randint(2,len(vCoins))#choosing no. of selections
rndnumsample = random.sample(range(len(vCoins)), rndcount)#randchoice
vsmpl = [vCoins[rndnum] for rndnum in rndnumsample]
nTotal = sum(k['value'] for k in vsmpl)
if nTotal == nTargetValue:
nBest = vsmpl
print 'exact utxo combo match found'
break
else:#otherwise only considering sets@ sum > sendamount
if sum(coin['value'] for coin in vsmpl) > nTargetValue:
vfIncluded.append(vsmpl)
try:
nBest#exit to end as nBest already located in prior section
except:
sumlst = [sum(m[o]['value'] for o in range(len(m))) for m in vfIncluded]
idx1 = sumlst.index(min(sumlst))
print '4. min of rndsmpl:', str(min(sumlst))
nBest = vfIncluded[idx1]
tmplist = [x['value'] for x in CWalletTx if x not in vCoins]#utxos@ >sendamount
if len(tmplist) > 0:#coz else it fails @ nil utxo>sendamount
coinLowestLarger = CWalletTx[[x['value'] for x in CWalletTx].index(min(tmplist))]
if coinLowestLarger['value'] < min(sumlst):
nBest = [coinLowestLarger]
return nBest
#now actually running the above function:
nBest = SelectCoins()
vfBest = [coin['id'] for coin in nBest]
vValue = sum(coin['value'] for coin in nBest)
print ''
print 'nBest: '+ ','.join(vfBest) + ' = ' + str(vValue)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment