mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-03-10 09:20:04 +01:00
DefaultCoinSelector: extract compareByDepth()
comparator
This commit is contained in:
parent
9eaff37897
commit
2be7ee33f8
2 changed files with 35 additions and 22 deletions
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.bitcoinj.wallet;
|
package org.bitcoinj.wallet;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import org.bitcoinj.base.BitcoinNetwork;
|
import org.bitcoinj.base.BitcoinNetwork;
|
||||||
import org.bitcoinj.base.Coin;
|
import org.bitcoinj.base.Coin;
|
||||||
import org.bitcoinj.base.Network;
|
import org.bitcoinj.base.Network;
|
||||||
|
@ -27,6 +26,7 @@ import org.bitcoinj.core.TransactionOutput;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,7 +54,7 @@ public class DefaultCoinSelector implements CoinSelector {
|
||||||
// When calculating the wallet balance, we may be asked to select all possible coins, if so, avoid sorting
|
// When calculating the wallet balance, we may be asked to select all possible coins, if so, avoid sorting
|
||||||
// them in order to improve performance.
|
// them in order to improve performance.
|
||||||
if (!target.equals(BitcoinNetwork.MAX_MONEY)) {
|
if (!target.equals(BitcoinNetwork.MAX_MONEY)) {
|
||||||
sortOutputs(sortedOutputs);
|
sortedOutputs.sort(DefaultCoinSelector::compareByDepth);
|
||||||
}
|
}
|
||||||
// Now iterate over the sorted outputs until we have got as close to the target as possible or a little
|
// Now iterate over the sorted outputs until we have got as close to the target as possible or a little
|
||||||
// bit over (excessive value will be change).
|
// bit over (excessive value will be change).
|
||||||
|
@ -71,24 +71,37 @@ public class DefaultCoinSelector implements CoinSelector {
|
||||||
return new CoinSelection(selected);
|
return new CoinSelection(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting static void sortOutputs(ArrayList<TransactionOutput> outputs) {
|
/**
|
||||||
Collections.sort(outputs, (a, b) -> {
|
* Comparator for sorting {@link TransactionOutput} by coin depth, value, and then hash.
|
||||||
int depth1 = a.getParentTransactionDepthInBlocks();
|
* @param a The first object to be compared
|
||||||
int depth2 = b.getParentTransactionDepthInBlocks();
|
* @param b The second object to be compared
|
||||||
Coin aValue = a.getValue();
|
* @return a negative integer, zero, or a positive integer as the first argument is
|
||||||
Coin bValue = b.getValue();
|
* less than, equal to, or greater than the second.
|
||||||
BigInteger aCoinDepth = BigInteger.valueOf(aValue.value).multiply(BigInteger.valueOf(depth1));
|
*/
|
||||||
BigInteger bCoinDepth = BigInteger.valueOf(bValue.value).multiply(BigInteger.valueOf(depth2));
|
public static int compareByDepth(TransactionOutput a, TransactionOutput b) {
|
||||||
int c1 = bCoinDepth.compareTo(aCoinDepth);
|
int depth1 = a.getParentTransactionDepthInBlocks();
|
||||||
if (c1 != 0) return c1;
|
int depth2 = b.getParentTransactionDepthInBlocks();
|
||||||
// The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size.
|
Coin aValue = a.getValue();
|
||||||
int c2 = bValue.compareTo(aValue);
|
Coin bValue = b.getValue();
|
||||||
if (c2 != 0) return c2;
|
BigInteger aCoinDepth = BigInteger.valueOf(aValue.value).multiply(BigInteger.valueOf(depth1));
|
||||||
// They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering.
|
BigInteger bCoinDepth = BigInteger.valueOf(bValue.value).multiply(BigInteger.valueOf(depth2));
|
||||||
BigInteger aHash = a.getParentTransactionHash().toBigInteger();
|
int c1 = bCoinDepth.compareTo(aCoinDepth);
|
||||||
BigInteger bHash = b.getParentTransactionHash().toBigInteger();
|
if (c1 != 0) return c1;
|
||||||
return aHash.compareTo(bHash);
|
// The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size.
|
||||||
});
|
int c2 = bValue.compareTo(aValue);
|
||||||
|
if (c2 != 0) return c2;
|
||||||
|
// They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering.
|
||||||
|
BigInteger aHash = a.getParentTransactionHash().toBigInteger();
|
||||||
|
BigInteger bHash = b.getParentTransactionHash().toBigInteger();
|
||||||
|
return aHash.compareTo(bHash);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #compareByDepth(TransactionOutput, TransactionOutput)} with {@link List#sort(Comparator)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
static void sortOutputs(ArrayList<TransactionOutput> outputs) {
|
||||||
|
Collections.sort(outputs, DefaultCoinSelector::compareByDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sub-classes can override this to just customize whether transactions are usable, but keep age sorting. */
|
/** Sub-classes can override this to just customize whether transactions are usable, but keep age sorting. */
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class DefaultCoinSelectorTest extends TestWithWallet {
|
||||||
ArrayList<TransactionOutput> candidates = new ArrayList<>();
|
ArrayList<TransactionOutput> candidates = new ArrayList<>();
|
||||||
candidates.add(t2.getOutput(0));
|
candidates.add(t2.getOutput(0));
|
||||||
candidates.add(t1.getOutput(0));
|
candidates.add(t1.getOutput(0));
|
||||||
DefaultCoinSelector.sortOutputs(candidates);
|
candidates.sort(DefaultCoinSelector::compareByDepth);
|
||||||
assertEquals(t1.getOutput(0), candidates.get(0));
|
assertEquals(t1.getOutput(0), candidates.get(0));
|
||||||
assertEquals(t2.getOutput(0), candidates.get(1));
|
assertEquals(t2.getOutput(0), candidates.get(1));
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ public class DefaultCoinSelectorTest extends TestWithWallet {
|
||||||
candidates.add(t3.getOutput(0));
|
candidates.add(t3.getOutput(0));
|
||||||
candidates.add(t2.getOutput(0));
|
candidates.add(t2.getOutput(0));
|
||||||
candidates.add(t1.getOutput(0));
|
candidates.add(t1.getOutput(0));
|
||||||
DefaultCoinSelector.sortOutputs(candidates);
|
candidates.sort(DefaultCoinSelector::compareByDepth);
|
||||||
assertEquals(t2.getOutput(0), candidates.get(0));
|
assertEquals(t2.getOutput(0), candidates.get(0));
|
||||||
assertEquals(t1.getOutput(0), candidates.get(1));
|
assertEquals(t1.getOutput(0), candidates.get(1));
|
||||||
assertEquals(t3.getOutput(0), candidates.get(2));
|
assertEquals(t3.getOutput(0), candidates.get(2));
|
||||||
|
|
Loading…
Add table
Reference in a new issue