Wallet: always enforce OP_RETURN limit in completeTx()

Without this fix (and code cleanup) the `OP_RETURN` limit is not
enforced when `ensureMinRequiredFee` is false or `emptyWallet` is true.

Parameterize `twoOpReturnsPerTransactionTest()` to test all combinations
of `ensureMinRequiredFee` and `emptyWallet`.
This commit is contained in:
Sean Gilligan 2023-05-06 09:56:46 -07:00 committed by Andreas Schildbach
parent 3a28163d50
commit 27ff0823bb
2 changed files with 17 additions and 12 deletions

View File

@ -4550,17 +4550,16 @@ public class Wallet extends BaseTaggableObject
// Calculate the amount of value we need to import.
Coin valueNeeded = req.tx.getOutputSum().subtract(totalInput);
// Check for dusty sends and the OP_RETURN limit.
// Enforce the OP_RETURN limit
if (req.tx.getOutputs().stream()
.filter(o -> ScriptPattern.isOpReturn(o.getScriptPubKey()))
.count() > 1) // Only 1 OP_RETURN per transaction allowed.
throw new MultipleOpReturnRequested();
// Check for dusty sends
if (req.ensureMinRequiredFee && !req.emptyWallet) { // Min fee checking is handled later for emptyWallet.
int opReturnCount = 0;
for (TransactionOutput output : req.tx.getOutputs()) {
if (output.isDust())
throw new DustySendRequested();
if (ScriptPattern.isOpReturn(output.getScriptPubKey()))
++opReturnCount;
}
if (opReturnCount > 1) // Only 1 OP_RETURN per transaction allowed.
throw new MultipleOpReturnRequested();
if (req.tx.getOutputs().stream().anyMatch(TransactionOutput::isDust))
throw new DustySendRequested();
}
// Calculate a list of ALL potential candidates for spending and then ask a coin selector to provide us

View File

@ -18,6 +18,8 @@
package org.bitcoinj.wallet;
import com.google.common.collect.Lists;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.bitcoinj.base.BitcoinNetwork;
import org.bitcoinj.base.ScriptType;
import org.bitcoinj.base.internal.TimeUtils;
@ -75,6 +77,7 @@ import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -126,6 +129,7 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@RunWith(JUnitParamsRunner.class)
public class WalletTest extends TestWithWallet {
private static final Logger log = LoggerFactory.getLogger(WalletTest.class);
@ -2121,7 +2125,8 @@ public class WalletTest extends TestWithWallet {
}
@Test(expected = Wallet.MultipleOpReturnRequested.class)
public void twoOpReturnsPerTransactionTest() throws Exception {
@Parameters({"false, false", "false, true", "true, false", "true, true"})
public void twoOpReturnsPerTransactionTest(boolean ensureMinRequiredFee, boolean emptyWallet) throws Exception {
// Tests sending transaction where there are 2 attempts to write OP_RETURN scripts - this should fail and throw MultipleOpReturnRequested.
receiveATransaction(wallet, myAddress);
Transaction tx = new Transaction();
@ -2131,7 +2136,8 @@ public class WalletTest extends TestWithWallet {
tx.addOutput(messagePrice, script1);
tx.addOutput(messagePrice, script2);
SendRequest request = SendRequest.forTx(tx);
request.ensureMinRequiredFee = true;
request.ensureMinRequiredFee = ensureMinRequiredFee;
request.emptyWallet = emptyWallet;
wallet.completeTx(request);
}