Last active
December 8, 2016 12:28
-
-
Save kumrzz/4a2de9588731e54475e41efd276d17ee to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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