From 4b1e45fae2b330c8042ed86b2db1c49fb6d9c14b Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 17 May 2013 14:17:42 +0200 Subject: [PATCH] Make DefaultCoinSelector aware of priority, not just depth. --- .../java/com/google/bitcoin/core/Wallet.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/google/bitcoin/core/Wallet.java b/core/src/main/java/com/google/bitcoin/core/Wallet.java index ee55447d..0962c2d0 100644 --- a/core/src/main/java/com/google/bitcoin/core/Wallet.java +++ b/core/src/main/java/com/google/bitcoin/core/Wallet.java @@ -160,12 +160,18 @@ public class Wallet implements Serializable, BlockChainListener { public CoinSelection select(BigInteger target, LinkedList candidates); } + /** + * This class implements a {@link CoinSelector} which attempts to get the highest priority possible. This means that + * the transaction is the most likely to get confirmed + * Note that this means we may end up "spending" more priority than would be required to get the transaction we are + * creating confirmed. + */ public static class DefaultCoinSelector implements CoinSelector { public CoinSelection select(BigInteger biTarget, LinkedList candidates) { long target = biTarget.longValue(); long total = 0; LinkedList selected = Lists.newLinkedList(); - // Sort the inputs by age so we use oldest first. + // Sort the inputs by age*value so we get the highest "coindays" spent. // TODO: Consider changing the wallets internal format to track just outputs and keep them ordered. ArrayList sortedOutputs = new ArrayList(candidates); Collections.sort(sortedOutputs, new Comparator() { @@ -176,11 +182,19 @@ public class Wallet implements Serializable, BlockChainListener { TransactionConfidence conf2 = b.parentTransaction.getConfidence(); if (conf1.getConfidenceType() == ConfidenceType.BUILDING) depth1 = conf1.getDepthInBlocks(); if (conf2.getConfidenceType() == ConfidenceType.BUILDING) depth2 = conf2.getDepthInBlocks(); - if (depth1 < depth2) + BigInteger aCoinDepth = a.getValue().multiply(BigInteger.valueOf(depth1)); + BigInteger bCoinDepth = b.getValue().multiply(BigInteger.valueOf(depth2)); + if (aCoinDepth.compareTo(bCoinDepth) < 0) return 1; - else if (depth1 > depth2) + else if (bCoinDepth.compareTo(aCoinDepth) < 0) return -1; - // Their depths are equal (possibly pending) so sort by hash to ensure a total ordering. + // The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size + // (ie sort by reverse depth) + if (depth1 < depth2) + return -1; + else if (depth2 < depth1) + return 1; + // They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering. BigInteger aHash = a.parentTransaction.getHash().toBigInteger(); BigInteger bHash = b.parentTransaction.getHash().toBigInteger(); return aHash.compareTo(bHash);