diff --git a/core/src/main/java/org/bitcoinj/core/TransactionOutput.java b/core/src/main/java/org/bitcoinj/core/TransactionOutput.java index 20335cf6..3c21d315 100644 --- a/core/src/main/java/org/bitcoinj/core/TransactionOutput.java +++ b/core/src/main/java/org/bitcoinj/core/TransactionOutput.java @@ -205,6 +205,16 @@ public class TransactionOutput extends ChildMessage { throw new IllegalStateException("Output linked to wrong parent transaction?"); } + /** + * Will this transaction be relayable and mined by default miners? + */ + public boolean isDust() { + // Transactions that are OP_RETURN can't be dust regardless of their value. + if (getScriptPubKey().isOpReturn()) + return false; + return getValue().isLessThan(getMinNonDustValue()); + } + /** *
Gets the minimum value for a txout of this size to be considered non-dust by Bitcoin Core * (and thus relayed). See: CTxOut::IsDust() in Bitcoin Core. The assumption is that any output that would diff --git a/core/src/main/java/org/bitcoinj/core/Wallet.java b/core/src/main/java/org/bitcoinj/core/Wallet.java index 646cddae..74f9a3af 100644 --- a/core/src/main/java/org/bitcoinj/core/Wallet.java +++ b/core/src/main/java/org/bitcoinj/core/Wallet.java @@ -4119,15 +4119,12 @@ public class Wallet extends BaseTaggableObject for (TransactionOutput output : req.tx.getOutputs()) { if (output.getValue().compareTo(Coin.CENT) < 0) { needAtLeastReferenceFee = true; - if (output.getValue().compareTo(output.getMinNonDustValue()) < 0) { // Is transaction a "dust". - if (output.getScriptPubKey().isOpReturn()) { // Transactions that are OP_RETURN can't be dust regardless of their value. - ++opReturnCount; - continue; - } else { - throw new DustySendRequested(); - } - } - break; + if (output.isDust()) + throw new DustySendRequested(); + if (output.getScriptPubKey().isOpReturn()) + ++opReturnCount; + else + break; } } } @@ -4277,7 +4274,7 @@ public class Wallet extends BaseTaggableObject fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; TransactionOutput output = tx.getOutput(0); output.setValue(output.getValue().subtract(fee)); - return output.getMinNonDustValue().compareTo(output.getValue()) <= 0; + return !output.isDust(); } /** @@ -5084,11 +5081,11 @@ public class Wallet extends BaseTaggableObject changeAddress = currentChangeAddress(); changeOutput = new TransactionOutput(params, req.tx, change, changeAddress); // If the change output would result in this transaction being rejected as dust, just drop the change and make it a fee - if (req.ensureMinRequiredFee && change.isLessThan(Transaction.MIN_NONDUST_OUTPUT)) { + if (req.ensureMinRequiredFee && changeOutput.isDust()) { // This solution definitely fits in category 3 isCategory3 = true; additionalValueForNextCategory = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add( - Transaction.MIN_NONDUST_OUTPUT.add(Coin.SATOSHI)); + changeOutput.getMinNonDustValue().add(Coin.SATOSHI)); } else { size += changeOutput.unsafeBitcoinSerialize().length + VarInt.sizeOf(req.tx.getOutputs().size()) - VarInt.sizeOf(req.tx.getOutputs().size() - 1); // This solution is either category 1 or 2 diff --git a/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelServerState.java b/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelServerState.java index 94237f24..f07717f6 100644 --- a/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelServerState.java +++ b/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelServerState.java @@ -250,7 +250,7 @@ public abstract class PaymentChannelServerState { Wallet.SendRequest req = makeUnsignedChannelContract(newValueToMe); - if (!fullyUsedUp && refundSize.compareTo(req.tx.getOutput(0).getMinNonDustValue()) < 0) + if (!fullyUsedUp && refundSize.isLessThan(req.tx.getOutput(0).getMinNonDustValue())) throw new ValueOutOfRangeException("Attempt to refund negative value or value too small to be accepted by the network"); // Get the wallet's copy of the contract (ie with confidence information), if this is null, the wallet diff --git a/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelV1ClientState.java b/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelV1ClientState.java index 7ec56a77..483a6fa1 100644 --- a/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelV1ClientState.java +++ b/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelV1ClientState.java @@ -134,7 +134,7 @@ public class PaymentChannelV1ClientState extends PaymentChannelClientState { // format which one is the change. If we start obfuscating the change output better in future this may // be worth revisiting. TransactionOutput multisigOutput = template.addOutput(totalValue, ScriptBuilder.createMultiSigOutputScript(2, keys)); - if (multisigOutput.getMinNonDustValue().compareTo(totalValue) > 0) + if (multisigOutput.isDust()) throw new ValueOutOfRangeException("totalValue too small to use"); Wallet.SendRequest req = Wallet.SendRequest.forTx(template); req.coinSelector = AllowUnconfirmedCoinSelector.get(); diff --git a/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelV2ClientState.java b/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelV2ClientState.java index 63752b88..685cc19a 100644 --- a/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelV2ClientState.java +++ b/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelV2ClientState.java @@ -110,7 +110,7 @@ public class PaymentChannelV2ClientState extends PaymentChannelClientState { ScriptBuilder.createCLTVPaymentChannelOutput(BigInteger.valueOf(expiryTime), myKey, serverKey); TransactionOutput transactionOutput = template.addOutput(totalValue, ScriptBuilder.createP2SHOutputScript(redeemScript)); - if (transactionOutput.getMinNonDustValue().compareTo(totalValue) > 0) + if (transactionOutput.isDust()) throw new ValueOutOfRangeException("totalValue too small to use"); Wallet.SendRequest req = Wallet.SendRequest.forTx(template); req.coinSelector = AllowUnconfirmedCoinSelector.get();