From f6cb6c15d16c46df926e7d96b87de6e2c8719ff5 Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Tue, 19 Jul 2022 01:28:17 +0200 Subject: [PATCH] CoinSelection: add a new constructor that doesn't require valueGathered We'll add the output values up ourselves. This also deprecates the old constructor. --- .../org/bitcoinj/wallet/CoinSelection.java | 19 +++++++++++++++++-- .../bitcoinj/wallet/DefaultCoinSelector.java | 2 +- .../bitcoinj/wallet/KeyTimeCoinSelector.java | 4 +--- .../org/bitcoinj/wallettool/WalletTool.java | 14 ++++---------- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/bitcoinj/wallet/CoinSelection.java b/core/src/main/java/org/bitcoinj/wallet/CoinSelection.java index cf735a690..f1a667560 100644 --- a/core/src/main/java/org/bitcoinj/wallet/CoinSelection.java +++ b/core/src/main/java/org/bitcoinj/wallet/CoinSelection.java @@ -33,8 +33,23 @@ public class CoinSelection { public final Coin valueGathered; public final Collection gathered; - public CoinSelection(Coin valueGathered, Collection gathered) { - this.valueGathered = valueGathered; + public CoinSelection(Collection gathered) { + this.valueGathered = sumOutputValues(gathered); this.gathered = gathered; } + + /** + * @deprecated use {@link #CoinSelection(Collection)} + */ + @Deprecated + public CoinSelection(Coin valueGathered, Collection gathered) { + // ignore valueGathered + this(gathered); + } + + private static Coin sumOutputValues(Collection outputs) { + return outputs.stream() + .map(TransactionOutput::getValue) + .reduce(Coin.ZERO, Coin::add); + } } diff --git a/core/src/main/java/org/bitcoinj/wallet/DefaultCoinSelector.java b/core/src/main/java/org/bitcoinj/wallet/DefaultCoinSelector.java index 47ec36908..aee771d10 100644 --- a/core/src/main/java/org/bitcoinj/wallet/DefaultCoinSelector.java +++ b/core/src/main/java/org/bitcoinj/wallet/DefaultCoinSelector.java @@ -61,7 +61,7 @@ public class DefaultCoinSelector implements CoinSelector { } // Total may be lower than target here, if the given candidates were insufficient to create to requested // transaction. - return new CoinSelection(Coin.valueOf(total), selected); + return new CoinSelection(selected); } @VisibleForTesting static void sortOutputs(ArrayList outputs) { diff --git a/core/src/main/java/org/bitcoinj/wallet/KeyTimeCoinSelector.java b/core/src/main/java/org/bitcoinj/wallet/KeyTimeCoinSelector.java index 92058898c..63c69bdf8 100644 --- a/core/src/main/java/org/bitcoinj/wallet/KeyTimeCoinSelector.java +++ b/core/src/main/java/org/bitcoinj/wallet/KeyTimeCoinSelector.java @@ -58,7 +58,6 @@ public class KeyTimeCoinSelector implements CoinSelector { public CoinSelection select(Coin target, List candidates) { try { LinkedList gathered = new LinkedList<>(); - Coin valueGathered = Coin.ZERO; for (TransactionOutput output : candidates) { if (ignorePending && !isConfirmed(output)) continue; @@ -79,14 +78,13 @@ public class KeyTimeCoinSelector implements CoinSelector { checkNotNull(controllingKey, "Coin selector given output as candidate for which we lack the key"); if (controllingKey.getCreationTimeSeconds() >= unixTimeSeconds) continue; // It's older than the cutoff time so select. - valueGathered = valueGathered.add(output.getValue()); gathered.push(output); if (gathered.size() >= MAX_SIMULTANEOUS_INPUTS) { log.warn("Reached {} inputs, going further would yield a tx that is too large, stopping here.", gathered.size()); break; } } - return new CoinSelection(valueGathered, gathered); + return new CoinSelection(gathered); } catch (ScriptException e) { throw new RuntimeException(e); // We should never have problems understanding scripts in our wallet. } diff --git a/wallettool/src/main/java/org/bitcoinj/wallettool/WalletTool.java b/wallettool/src/main/java/org/bitcoinj/wallettool/WalletTool.java index 93fb71fe3..06c2d988b 100644 --- a/wallettool/src/main/java/org/bitcoinj/wallettool/WalletTool.java +++ b/wallettool/src/main/java/org/bitcoinj/wallettool/WalletTool.java @@ -453,20 +453,17 @@ public class WalletTool implements Callable { } final Address validSelectAddr = selectAddr; coinSelector = (target, candidates) -> { - Coin valueGathered = Coin.ZERO; List gathered = new LinkedList(); for (TransactionOutput candidate : candidates) { try { Address candidateAddr = candidate.getScriptPubKey().getToAddress(params); - if (validSelectAddr.equals(candidateAddr)) { + if (validSelectAddr.equals(candidateAddr)) gathered.add(candidate); - valueGathered = valueGathered.add(candidate.getValue()); - } } catch (ScriptException x) { // swallow } } - return new CoinSelection(valueGathered, gathered); + return new CoinSelection(gathered); }; } if (selectOutputStr != null) { @@ -474,17 +471,14 @@ public class WalletTool implements Callable { Sha256Hash selectTransactionHash = Sha256Hash.wrap(parts[0]); int selectIndex = Integer.parseInt(parts[1]); coinSelector = (target, candidates) -> { - Coin valueGathered = Coin.ZERO; List gathered = new LinkedList(); for (TransactionOutput candidate : candidates) { int candicateIndex = candidate.getIndex(); final Sha256Hash candidateTransactionHash = candidate.getParentTransactionHash(); - if (selectIndex == candicateIndex && selectTransactionHash.equals(candidateTransactionHash)) { + if (selectIndex == candicateIndex && selectTransactionHash.equals(candidateTransactionHash)) gathered.add(candidate); - valueGathered = valueGathered.add(candidate.getValue()); - } } - return new CoinSelection(valueGathered, gathered); + return new CoinSelection(gathered); }; } send(coinSelector, outputsStr, feePerVkb, lockTimeStr, allowUnconfirmed);