From a97f4923b487ccbf9ec337f1408d50919f886c52 Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Fri, 11 Mar 2016 14:05:28 +0100 Subject: [PATCH] Get rid of SendRequest.DEFAULT_FEE_PER_KB "constant". If you have been reading that field, you probably want to use Transaction.REFERENCE_DEFAULT_MIN_TX_FEE. If you have been writing to that field to change the SendRequest.feePerKb default, use a Context.feePerKb instead. There is also a new Context.ensureMinRequiredFee. --- .../main/java/org/bitcoinj/core/Context.java | 26 +++++- .../main/java/org/bitcoinj/core/Wallet.java | 10 +-- .../AbstractFullPrunedBlockChainTest.java | 6 +- .../org/bitcoinj/core/BlockChainTest.java | 14 +--- .../org/bitcoinj/core/ChainSplitTest.java | 5 +- .../core/TransactionBroadcastTest.java | 1 - .../java/org/bitcoinj/core/WalletTest.java | 81 ++++++++++++------- .../channels/ChannelConnectionTest.java | 10 +-- .../channels/PaymentChannelStateTest.java | 3 +- .../testing/TestWithNetworkConnections.java | 5 +- .../org/bitcoinj/testing/TestWithWallet.java | 4 +- .../examples/ExamplePaymentChannelClient.java | 2 +- 12 files changed, 94 insertions(+), 73 deletions(-) diff --git a/core/src/main/java/org/bitcoinj/core/Context.java b/core/src/main/java/org/bitcoinj/core/Context.java index 3a35d48c..37b6ba48 100644 --- a/core/src/main/java/org/bitcoinj/core/Context.java +++ b/core/src/main/java/org/bitcoinj/core/Context.java @@ -1,5 +1,6 @@ package org.bitcoinj.core; +import org.bitcoinj.core.Wallet.SendRequest; import org.slf4j.*; import static com.google.common.base.Preconditions.*; @@ -30,6 +31,8 @@ public class Context { private TxConfidenceTable confidenceTable; private NetworkParameters params; private int eventHorizon = 100; + private boolean ensureMinRequiredFee = true; + private Coin feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; /** * Creates a new context object. For now, this will be done for you by the framework. Eventually you will be @@ -46,15 +49,18 @@ public class Context { } /** - * Creates a new context object. For now, this will be done for you by the framework. Eventually you will be - * expected to do this yourself in the same manner as fetching a NetworkParameters object (at the start of your app). + * Creates a new custom context object. This is mainly meant for unit tests for now. * * @param params The network parameters that will be associated with this context. * @param eventHorizon Number of blocks after which the library will delete data and be unable to always process reorgs (see {@link #getEventHorizon()}. + * @param feePerKb The default fee per 1000 bytes of transaction data to pay when completing transactions. For details, see {@link SendRequest#feePerKb}. + * @param ensureMinRequiredFee Whether to ensure the minimum required fee by default when completing transactions. For details, see {@link SendRequest#ensureMinRequiredFee}. */ - public Context(NetworkParameters params, int eventHorizon) { + public Context(NetworkParameters params, int eventHorizon, Coin feePerKb, boolean ensureMinRequiredFee) { this(params); this.eventHorizon = eventHorizon; + this.feePerKb = feePerKb; + this.ensureMinRequiredFee = ensureMinRequiredFee; } private static volatile Context lastConstructed; @@ -155,4 +161,18 @@ public class Context { public int getEventHorizon() { return eventHorizon; } + + /** + * The default fee per 1000 bytes of transaction data to pay when completing transactions. For details, see {@link SendRequest#feePerKb}. + */ + public Coin getFeePerKb() { + return feePerKb; + } + + /** + * Whether to ensure the minimum required fee by default when completing transactions. For details, see {@link SendRequest#ensureMinRequiredFee}. + */ + public boolean isEnsureMinRequiredFee() { + return ensureMinRequiredFee; + } } diff --git a/core/src/main/java/org/bitcoinj/core/Wallet.java b/core/src/main/java/org/bitcoinj/core/Wallet.java index b60466b3..6c77bc96 100644 --- a/core/src/main/java/org/bitcoinj/core/Wallet.java +++ b/core/src/main/java/org/bitcoinj/core/Wallet.java @@ -3721,13 +3721,7 @@ public class Wallet extends BaseTaggableObject * when choosing which transactions to add to a block. Note that, to keep this equivalent to Bitcoin Core * definition, a kilobyte is defined as 1000 bytes, not 1024.

*/ - public Coin feePerKb = DEFAULT_FEE_PER_KB; - - /** - * If you want to modify the default fee for your entire app without having to change each SendRequest you make, - * you can do it here. This is primarily useful for unit tests. - */ - public static Coin DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; + public Coin feePerKb = Context.get().getFeePerKb(); /** *

Requires that there be enough fee for a default Bitcoin Core to at least relay the transaction. @@ -3738,7 +3732,7 @@ public class Wallet extends BaseTaggableObject * 26,000 bytes. If you get a transaction which is that large, you should set a feePerKb of at least * {@link Transaction#REFERENCE_DEFAULT_MIN_TX_FEE}.

*/ - public boolean ensureMinRequiredFee = true; + public boolean ensureMinRequiredFee = Context.get().isEnsureMinRequiredFee(); /** * If true (the default), the inputs will be signed. diff --git a/core/src/test/java/org/bitcoinj/core/AbstractFullPrunedBlockChainTest.java b/core/src/test/java/org/bitcoinj/core/AbstractFullPrunedBlockChainTest.java index c504ee01..6f4d6ebf 100644 --- a/core/src/test/java/org/bitcoinj/core/AbstractFullPrunedBlockChainTest.java +++ b/core/src/test/java/org/bitcoinj/core/AbstractFullPrunedBlockChainTest.java @@ -37,9 +37,6 @@ import java.util.Arrays; import java.util.List; import static org.bitcoinj.core.Coin.FIFTY_COINS; -import org.bitcoinj.store.BlockStore; -import org.bitcoinj.store.MemoryBlockStore; -import org.bitcoinj.testing.FakeTxBuilder; import static org.junit.Assert.*; import org.junit.rules.ExpectedException; @@ -60,12 +57,11 @@ public abstract class AbstractFullPrunedBlockChainTest { }; protected FullPrunedBlockChain chain; protected FullPrunedBlockStore store; - protected Context context; @Before public void setUp() throws Exception { BriefLogFormatter.init(); - context = new Context(PARAMS); + Context.propagate(new Context(PARAMS, 100, Coin.ZERO, false)); } public abstract FullPrunedBlockStore createStore(NetworkParameters params, int blockCount) diff --git a/core/src/test/java/org/bitcoinj/core/BlockChainTest.java b/core/src/test/java/org/bitcoinj/core/BlockChainTest.java index 3326a004..51b1373f 100644 --- a/core/src/test/java/org/bitcoinj/core/BlockChainTest.java +++ b/core/src/test/java/org/bitcoinj/core/BlockChainTest.java @@ -73,11 +73,10 @@ public class BlockChainTest { @Before public void setUp() throws Exception { BriefLogFormatter.initVerbose(); - Context testNetContext = new Context(testNet); - testNetChain = new BlockChain(testNet, new Wallet(testNetContext), new MemoryBlockStore(testNet)); - Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO; - Context context = new Context(PARAMS); - wallet = new Wallet(context) { + Context.propagate(new Context(testNet, 100, Coin.ZERO, false)); + testNetChain = new BlockChain(testNet, new Wallet(testNet), new MemoryBlockStore(testNet)); + Context.propagate(new Context(PARAMS, 100, Coin.ZERO, false)); + wallet = new Wallet(PARAMS) { @Override public void receiveFromBlock(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType, int relativityOffset) throws VerificationException { @@ -96,11 +95,6 @@ public class BlockChainTest { coinbaseTo = wallet.currentReceiveKey().toAddress(PARAMS); } - @After - public void tearDown() { - Wallet.SendRequest.DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; - } - @Test public void testBasicChaining() throws Exception { // Check that we can plug a few blocks together and the futures work. diff --git a/core/src/test/java/org/bitcoinj/core/ChainSplitTest.java b/core/src/test/java/org/bitcoinj/core/ChainSplitTest.java index 6216d126..e853b0b0 100644 --- a/core/src/test/java/org/bitcoinj/core/ChainSplitTest.java +++ b/core/src/test/java/org/bitcoinj/core/ChainSplitTest.java @@ -59,10 +59,9 @@ public class ChainSplitTest { public void setUp() throws Exception { BriefLogFormatter.init(); Utils.setMockClock(); // Use mock clock - Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO; - Context context = new Context(PARAMS); + Context.propagate(new Context(PARAMS, 100, Coin.ZERO, false)); MemoryBlockStore blockStore = new MemoryBlockStore(PARAMS); - wallet = new Wallet(context); + wallet = new Wallet(PARAMS); ECKey key1 = wallet.freshReceiveKey(); ECKey key2 = wallet.freshReceiveKey(); chain = new BlockChain(PARAMS, wallet, blockStore); diff --git a/core/src/test/java/org/bitcoinj/core/TransactionBroadcastTest.java b/core/src/test/java/org/bitcoinj/core/TransactionBroadcastTest.java index e1273ecd..bac2bd4e 100644 --- a/core/src/test/java/org/bitcoinj/core/TransactionBroadcastTest.java +++ b/core/src/test/java/org/bitcoinj/core/TransactionBroadcastTest.java @@ -244,7 +244,6 @@ public class TransactionBroadcastTest extends TestWithPeerGroup { // Do the same thing with an offline transaction. peerGroup.removeWallet(wallet); Wallet.SendRequest req = Wallet.SendRequest.to(dest, valueOf(2, 0)); - req.ensureMinRequiredFee = false; Transaction t3 = checkNotNull(wallet.sendCoinsOffline(req)); assertNull(outbound(p1)); // Nothing sent. // Add the wallet to the peer group (simulate initialization). Transactions should be announced. diff --git a/core/src/test/java/org/bitcoinj/core/WalletTest.java b/core/src/test/java/org/bitcoinj/core/WalletTest.java index 6283b156..3af8c534 100644 --- a/core/src/test/java/org/bitcoinj/core/WalletTest.java +++ b/core/src/test/java/org/bitcoinj/core/WalletTest.java @@ -313,7 +313,6 @@ public class WalletTest extends TestWithWallet { // Try to create a send with a fee but no password (this should fail). try { - req.ensureMinRequiredFee = false; wallet.completeTx(req); fail(); } catch (ECKey.MissingPrivateKeyException kce) { @@ -324,7 +323,6 @@ public class WalletTest extends TestWithWallet { // Try to create a send with a fee but the wrong password (this should fail). req = Wallet.SendRequest.to(destination, v2); req.aesKey = wrongAesKey; - req.ensureMinRequiredFee = false; try { wallet.completeTx(req); @@ -339,7 +337,6 @@ public class WalletTest extends TestWithWallet { // Create a send with a fee with the correct password (this should succeed). req = Wallet.SendRequest.to(destination, v2); req.aesKey = aesKey; - req.ensureMinRequiredFee = false; } // Complete the transaction successfully. @@ -438,7 +435,6 @@ public class WalletTest extends TestWithWallet { assertEquals(v3, wallet.getBalance()); Wallet.SendRequest req = Wallet.SendRequest.to(new ECKey().toAddress(PARAMS), valueOf(0, 48)); req.aesKey = aesKey; - req.ensureMinRequiredFee = false; req.shuffleOutputs = false; wallet.completeTx(req); Transaction t3 = req.tx; @@ -478,7 +474,6 @@ public class WalletTest extends TestWithWallet { t2.addOutput(v3, a2); t2.addOutput(v4, a2); SendRequest req = SendRequest.forTx(t2); - req.ensureMinRequiredFee = false; wallet.completeTx(req); // Do some basic sanity checks. @@ -1901,7 +1896,6 @@ public class WalletTest extends TestWithWallet { TransactionOutput o2 = new TransactionOutput(PARAMS, t2, v2, k2.toAddress(PARAMS)); t2.addOutput(o2); SendRequest req = SendRequest.forTx(t2); - req.ensureMinRequiredFee = false; wallet.completeTx(req); // Commit t2, so it is placed in the pending pool @@ -2195,6 +2189,7 @@ public class WalletTest extends TestWithWallet { Script script = ScriptBuilder.createOpReturnScript("hello world!".getBytes()); tx.addOutput(messagePrice, script); SendRequest request = Wallet.SendRequest.forTx(tx); + request.ensureMinRequiredFee = true; wallet.completeTx(request); } @@ -2235,6 +2230,7 @@ public class WalletTest extends TestWithWallet { tx.addOutput(messagePrice, script1); tx.addOutput(messagePrice, script2); SendRequest request = Wallet.SendRequest.forTx(tx); + request.ensureMinRequiredFee = true; wallet.completeTx(request); } @@ -2245,6 +2241,7 @@ public class WalletTest extends TestWithWallet { Address notMyAddr = new ECKey().toAddress(PARAMS); tx.addOutput(Transaction.MIN_NONDUST_OUTPUT.subtract(SATOSHI), notMyAddr); SendRequest request = Wallet.SendRequest.forTx(tx); + request.ensureMinRequiredFee = true; wallet.completeTx(request); } @@ -2271,6 +2268,7 @@ public class WalletTest extends TestWithWallet { tx.addOutput(Coin.ZERO, ScriptBuilder.createOpReturnScript("hello world!".getBytes())); tx.addOutput(Coin.SATOSHI, notMyAddr); SendRequest request = Wallet.SendRequest.forTx(tx); + request.ensureMinRequiredFee = true; wallet.completeTx(request); } @@ -2283,6 +2281,7 @@ public class WalletTest extends TestWithWallet { tx.addOutput(Coin.CENT, ScriptBuilder.createOpReturnScript("hello world!".getBytes())); tx.addOutput(Transaction.MIN_NONDUST_OUTPUT.subtract(SATOSHI), notMyAddr); SendRequest request = Wallet.SendRequest.forTx(tx); + request.ensureMinRequiredFee = true; wallet.completeTx(request); } @@ -2323,14 +2322,15 @@ public class WalletTest extends TestWithWallet { // Not allowed to send dust. try { - wallet.createSend(notMyAddr, SATOSHI); + SendRequest request = SendRequest.to(notMyAddr, SATOSHI); + request.ensureMinRequiredFee = true; + wallet.completeTx(request); fail(); } catch (Wallet.DustySendRequested e) { // Expected. } // Spend it all without fee enforcement SendRequest req = SendRequest.to(notMyAddr, SATOSHI.multiply(12)); - req.ensureMinRequiredFee = false; assertNotNull(wallet.sendCoinsOffline(req)); assertEquals(ZERO, wallet.getBalance()); @@ -2340,7 +2340,10 @@ public class WalletTest extends TestWithWallet { wallet.receiveFromBlock(tx4, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); // Simple test to make sure if we have an ouput < 0.01 we get a fee - Transaction spend1 = wallet.createSend(notMyAddr, CENT.subtract(SATOSHI)); + SendRequest request1 = SendRequest.to(notMyAddr, CENT.subtract(SATOSHI)); + request1.ensureMinRequiredFee = true; + wallet.completeTx(request1); + Transaction spend1 = request1.tx; assertEquals(2, spend1.getOutputs().size()); // We optimize for priority, so the output selected should be the largest one. // We should have paid the default minfee. @@ -2348,7 +2351,10 @@ public class WalletTest extends TestWithWallet { Coin.COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); // But not at exactly 0.01 - Transaction spend2 = wallet.createSend(notMyAddr, CENT); + SendRequest request2 = SendRequest.to(notMyAddr, CENT); + request2.ensureMinRequiredFee = true; + wallet.completeTx(request2); + Transaction spend2 = request2.tx; assertEquals(2, spend2.getOutputs().size()); // We optimize for priority, so the output selected should be the largest one assertEquals(Coin.COIN, spend2.getOutput(0).getValue().add(spend2.getOutput(1).getValue())); @@ -2356,6 +2362,7 @@ public class WalletTest extends TestWithWallet { // ...but not more fee than what we request SendRequest request3 = SendRequest.to(notMyAddr, CENT.subtract(SATOSHI)); request3.feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI); + request3.ensureMinRequiredFee = true; wallet.completeTx(request3); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI), request3.tx.getFee()); Transaction spend3 = request3.tx; @@ -2367,6 +2374,7 @@ public class WalletTest extends TestWithWallet { // ...unless we need it SendRequest request4 = SendRequest.to(notMyAddr, CENT.subtract(SATOSHI)); request4.feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.subtract(SATOSHI); + request4.ensureMinRequiredFee = true; wallet.completeTx(request4); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request4.tx.getFee()); Transaction spend4 = request4.tx; @@ -2376,6 +2384,7 @@ public class WalletTest extends TestWithWallet { Coin.COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); SendRequest request5 = SendRequest.to(notMyAddr, Coin.COIN.subtract(CENT.subtract(SATOSHI))); + request5.ensureMinRequiredFee = true; wallet.completeTx(request5); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request5.tx.getFee()); Transaction spend5 = request5.tx; @@ -2386,6 +2395,7 @@ public class WalletTest extends TestWithWallet { Coin.COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); SendRequest request6 = SendRequest.to(notMyAddr, Coin.COIN.subtract(CENT)); + request6.ensureMinRequiredFee = true; wallet.completeTx(request6); assertEquals(ZERO, request6.tx.getFee()); Transaction spend6 = request6.tx; @@ -2395,6 +2405,7 @@ public class WalletTest extends TestWithWallet { assertEquals(Coin.COIN, spend6.getOutput(0).getValue().add(spend6.getOutput(1).getValue())); SendRequest request7 = SendRequest.to(notMyAddr, Coin.COIN.subtract(CENT.subtract(SATOSHI.multiply(2)).multiply(2))); + request7.ensureMinRequiredFee = true; request7.tx.addOutput(CENT.subtract(SATOSHI), notMyAddr); wallet.completeTx(request7); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request7.tx.getFee()); @@ -2406,6 +2417,7 @@ public class WalletTest extends TestWithWallet { Coin.COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); SendRequest request8 = SendRequest.to(notMyAddr, COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); + request8.ensureMinRequiredFee = true; wallet.completeTx(request8); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request8.tx.getFee()); Transaction spend8 = request8.tx; @@ -2416,6 +2428,7 @@ public class WalletTest extends TestWithWallet { SendRequest request9 = SendRequest.to(notMyAddr, COIN.subtract( Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT).subtract(SATOSHI))); + request9.ensureMinRequiredFee = true; wallet.completeTx(request9); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT).subtract(SATOSHI), request9.tx.getFee()); Transaction spend9 = request9.tx; @@ -2427,6 +2440,7 @@ public class WalletTest extends TestWithWallet { SendRequest request10 = SendRequest.to(notMyAddr, COIN.subtract( Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT))); + request10.ensureMinRequiredFee = true; wallet.completeTx(request10); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request10.tx.getFee()); Transaction spend10 = request10.tx; @@ -2439,6 +2453,7 @@ public class WalletTest extends TestWithWallet { SendRequest request11 = SendRequest.to(notMyAddr, COIN.subtract( Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT).add(SATOSHI.multiply(2)))); request11.feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI); + request11.ensureMinRequiredFee = true; wallet.completeTx(request11); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI), request11.tx.getFee()); Transaction spend11 = request11.tx; @@ -2491,6 +2506,7 @@ public class WalletTest extends TestWithWallet { request15.tx.addOutput(CENT, notMyAddr); assertTrue(request15.tx.unsafeBitcoinSerialize().length > 1000); request15.feePerKb = SATOSHI; + request15.ensureMinRequiredFee = true; wallet.completeTx(request15); assertEquals(SATOSHI.multiply(2), request15.tx.getFee()); Transaction spend15 = request15.tx; @@ -2504,6 +2520,7 @@ public class WalletTest extends TestWithWallet { SendRequest request16 = SendRequest.to(notMyAddr, CENT); request16.feePerKb = ZERO; + request16.ensureMinRequiredFee = true; for (int i = 0; i < 29; i++) request16.tx.addOutput(CENT, notMyAddr); assertTrue(request16.tx.unsafeBitcoinSerialize().length > 1000); @@ -2524,6 +2541,7 @@ public class WalletTest extends TestWithWallet { request17.tx.addOutput(CENT, notMyAddr); request17.tx.addOutput(new TransactionOutput(PARAMS, request17.tx, CENT, new byte[15])); request17.feePerKb = SATOSHI; + request17.ensureMinRequiredFee = true; wallet.completeTx(request17); assertEquals(SATOSHI, request17.tx.getFee()); assertEquals(1, request17.tx.getInputs().size()); @@ -2552,6 +2570,7 @@ public class WalletTest extends TestWithWallet { request18.tx.addOutput(CENT, notMyAddr); request18.tx.addOutput(new TransactionOutput(PARAMS, request18.tx, CENT, new byte[17])); request18.feePerKb = SATOSHI; + request18.ensureMinRequiredFee = true; wallet.completeTx(request18); assertEquals(SATOSHI.multiply(2), request18.tx.getFee()); assertEquals(1, request18.tx.getInputs().size()); @@ -2576,6 +2595,7 @@ public class WalletTest extends TestWithWallet { assertEquals(wallet.getBalance(), CENT.add(COIN)); SendRequest request19 = SendRequest.to(notMyAddr, CENT); request19.feePerKb = ZERO; + request19.ensureMinRequiredFee = true; for (int i = 0; i < 99; i++) request19.tx.addOutput(CENT, notMyAddr); // If we send now, we shouldn't need a fee and should only have to spend our COIN @@ -2586,6 +2606,7 @@ public class WalletTest extends TestWithWallet { // Now reset request19 and give it a fee per kb request19.tx.clearInputs(); request19 = SendRequest.forTx(request19.tx); + request19.ensureMinRequiredFee = true; request19.feePerKb = SATOSHI; request19.shuffleOutputs = false; wallet.completeTx(request19); @@ -2601,6 +2622,7 @@ public class WalletTest extends TestWithWallet { // Create another transaction that will spend COIN + fee, which makes it require both inputs SendRequest request20 = SendRequest.to(notMyAddr, CENT); request20.feePerKb = ZERO; + request20.ensureMinRequiredFee = true; for (int i = 0; i < 99; i++) request20.tx.addOutput(CENT, notMyAddr); // If we send now, we shouldn't have a fee and should only have to spend our COIN @@ -2626,6 +2648,7 @@ public class WalletTest extends TestWithWallet { // result of an output < CENT. SendRequest request21 = SendRequest.to(notMyAddr, CENT); request21.feePerKb = ZERO; + request21.ensureMinRequiredFee = true; for (int i = 0; i < 99; i++) request21.tx.addOutput(CENT, notMyAddr); request21.tx.addOutput(CENT.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), notMyAddr); @@ -2642,6 +2665,7 @@ public class WalletTest extends TestWithWallet { // Same as request 19 SendRequest request25 = SendRequest.to(notMyAddr, CENT); request25.feePerKb = ZERO; + request25.ensureMinRequiredFee = true; for (int i = 0; i < 70; i++) request25.tx.addOutput(CENT, notMyAddr); // If we send now, we shouldn't need a fee and should only have to spend our COIN @@ -2653,7 +2677,6 @@ public class WalletTest extends TestWithWallet { request25.tx.clearInputs(); request25 = SendRequest.forTx(request25.tx); request25.feePerKb = CENT.divide(3); - request25.ensureMinRequiredFee = false; request25.shuffleOutputs = false; wallet.completeTx(request25); assertEquals(CENT.subtract(SATOSHI), request25.tx.getFee()); @@ -2684,6 +2707,7 @@ public class WalletTest extends TestWithWallet { notMyAddr); assertTrue(request26.tx.unsafeBitcoinSerialize().length > 1000); request26.feePerKb = SATOSHI; + request26.ensureMinRequiredFee = true; wallet.completeTx(request26); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT).subtract(SATOSHI), request26.tx.getFee()); @@ -2701,7 +2725,6 @@ public class WalletTest extends TestWithWallet { @Test public void basicCategoryStepTest() throws Exception { // Creates spends that step through the possible fee solver categories - SendRequest.DEFAULT_FEE_PER_KB = ZERO; // Make sure TestWithWallet isnt doing anything crazy. assertEquals(0, wallet.getTransactions(true).size()); @@ -2720,6 +2743,7 @@ public class WalletTest extends TestWithWallet { // Create a spend that will throw away change (category 3 type 2 in which the change causes fee which is worth more than change) SendRequest request1 = SendRequest.to(notMyAddr, balance.subtract(SATOSHI)); + request1.ensureMinRequiredFee = true; wallet.completeTx(request1); assertEquals(SATOSHI, request1.tx.getFee()); assertEquals(request1.tx.getInputs().size(), i); // We should have spent all inputs @@ -2731,6 +2755,7 @@ public class WalletTest extends TestWithWallet { // ... and create a spend that will throw away change (category 3 type 1 in which the change causes dust output) SendRequest request2 = SendRequest.to(notMyAddr, balance.subtract(SATOSHI)); + request2.ensureMinRequiredFee = true; wallet.completeTx(request2); assertEquals(SATOSHI, request2.tx.getFee()); assertEquals(request2.tx.getInputs().size(), i - 1); // We should have spent all inputs - 1 @@ -2743,6 +2768,7 @@ public class WalletTest extends TestWithWallet { // ... and create a spend that will throw away change (category 3 type 1 in which the change causes dust output) // but that also could have been category 2 if it wanted SendRequest request3 = SendRequest.to(notMyAddr, CENT.add(tenThousand).subtract(SATOSHI)); + request3.ensureMinRequiredFee = true; wallet.completeTx(request3); assertEquals(SATOSHI, request3.tx.getFee()); assertEquals(request3.tx.getInputs().size(), i - 2); // We should have spent all inputs - 2 @@ -2750,6 +2776,7 @@ public class WalletTest extends TestWithWallet { // SendRequest request4 = SendRequest.to(notMyAddr, balance.subtract(SATOSHI)); request4.feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.divide(request3.tx.unsafeBitcoinSerialize().length); + request4.ensureMinRequiredFee = true; wallet.completeTx(request4); assertEquals(SATOSHI, request4.tx.getFee()); assertEquals(request4.tx.getInputs().size(), i - 2); // We should have spent all inputs - 2 @@ -2763,6 +2790,7 @@ public class WalletTest extends TestWithWallet { // ...that is just slightly less than is needed for category 1 SendRequest request5 = SendRequest.to(notMyAddr, CENT.add(tenThousand).subtract(SATOSHI)); + request5.ensureMinRequiredFee = true; wallet.completeTx(request5); assertEquals(SATOSHI, request5.tx.getFee()); assertEquals(1, request5.tx.getOutputs().size()); // We should have no change output @@ -2774,11 +2802,10 @@ public class WalletTest extends TestWithWallet { // ... that puts us in category 1 (no fee!) SendRequest request6 = SendRequest.to(notMyAddr, CENT.add(tenThousand).subtract(SATOSHI)); + request6.ensureMinRequiredFee = true; wallet.completeTx(request6); assertEquals(ZERO, request6.tx.getFee()); assertEquals(2, request6.tx.getOutputs().size()); // We should have a change output - - SendRequest.DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; } @Test @@ -2801,6 +2828,7 @@ public class WalletTest extends TestWithWallet { // The selector will choose 2 with MIN_TX_FEE fee SendRequest request1 = SendRequest.to(notMyAddr, CENT.add(SATOSHI)); + request1.ensureMinRequiredFee = true; wallet.completeTx(request1); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request1.tx.getFee()); assertEquals(request1.tx.getInputs().size(), i); // We should have spent all inputs @@ -2834,6 +2862,7 @@ public class WalletTest extends TestWithWallet { wallet.commitTx(req.tx); SendRequest emptyReq = SendRequest.emptyWallet(myAddress); emptyReq.feePerKb = fee; + emptyReq.ensureMinRequiredFee = true; emptyReq.emptyWallet = true; emptyReq.coinSelector = AllowUnconfirmedCoinSelector.get(); wallet.completeTx(emptyReq); @@ -2883,6 +2912,7 @@ public class WalletTest extends TestWithWallet { request1.tx.addOutput(CENT, notMyAddr); request1.tx.addOutput(new TransactionOutput(PARAMS, request1.tx, CENT, new byte[16])); request1.feePerKb = SATOSHI; + request1.ensureMinRequiredFee = true; // We get a category 2 using COIN+CENT // It spends COIN + 1(fee) and because its output is thus < CENT, we have to pay MIN_TX_FEE // When it tries category 1, its too large and requires COIN + 2 (fee) @@ -2901,6 +2931,7 @@ public class WalletTest extends TestWithWallet { request2.tx.addOutput(CENT, notMyAddr); request2.tx.addOutput(new TransactionOutput(PARAMS, request2.tx, CENT, new byte[16])); request2.feePerKb = SATOSHI; + request2.ensureMinRequiredFee = true; // The process is the same as above, but now we can complete category 1 with one more input, and pay a fee of 2 wallet.completeTx(request2); assertEquals(SATOSHI.multiply(2), request2.tx.getFee()); @@ -3022,45 +3053,37 @@ public class WalletTest extends TestWithWallet { Transaction tx = createFakeTx(PARAMS, CENT, myAddress); wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); SendRequest request = SendRequest.emptyWallet(outputKey); - request.ensureMinRequiredFee = false; wallet.completeTx(request); - assertEquals(Wallet.SendRequest.DEFAULT_FEE_PER_KB, request.tx.getFee()); + assertEquals(ZERO, request.tx.getFee()); wallet.commitTx(request.tx); assertEquals(ZERO, wallet.getBalance()); assertEquals(CENT, request.tx.getOutput(0).getValue()); // Add 1 confirmed cent and 1 unconfirmed cent. Verify only one cent is emptied because of the coin selection // policies that are in use by default. - block = new StoredBlock(makeSolvedTestBlock(blockStore, outputKey), BigInteger.ONE, 1); + block = new StoredBlock(makeSolvedTestBlock(blockStore, outputKey), BigInteger.ONE, 2); tx = createFakeTx(PARAMS, CENT, myAddress); wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); tx = createFakeTx(PARAMS, CENT, myAddress); wallet.receivePending(tx, null); request = SendRequest.emptyWallet(outputKey); - request.ensureMinRequiredFee = false; wallet.completeTx(request); - assertEquals(Wallet.SendRequest.DEFAULT_FEE_PER_KB, request.tx.getFee()); + assertEquals(ZERO, request.tx.getFee()); wallet.commitTx(request.tx); assertEquals(ZERO, wallet.getBalance()); assertEquals(CENT, request.tx.getOutput(0).getValue()); // Add an unsendable value - StoredBlock block2 = new StoredBlock(block.getHeader().createNextBlock(outputKey), BigInteger.ONE, 3); - Coin outputValue = Transaction.MIN_NONDUST_OUTPUT.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE).subtract(SATOSHI); + block = new StoredBlock(block.getHeader().createNextBlock(outputKey), BigInteger.ONE, 3); + Coin outputValue = Transaction.MIN_NONDUST_OUTPUT.subtract(SATOSHI); tx = createFakeTx(PARAMS, outputValue, myAddress); - wallet.receiveFromBlock(tx, block2, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); + wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); try { request = SendRequest.emptyWallet(outputKey); + assertEquals(ZERO, request.tx.getFee()); wallet.completeTx(request); fail(); } catch (Wallet.CouldNotAdjustDownwards e) {} - request = SendRequest.emptyWallet(outputKey); - request.ensureMinRequiredFee = false; - wallet.completeTx(request); - assertEquals(ZERO, request.tx.getFee()); - wallet.commitTx(request.tx); - assertEquals(ZERO, wallet.getBalance()); - assertEquals(outputValue, request.tx.getOutput(0).getValue()); } @Test diff --git a/core/src/test/java/org/bitcoinj/protocols/channels/ChannelConnectionTest.java b/core/src/test/java/org/bitcoinj/protocols/channels/ChannelConnectionTest.java index 908c1a9c..f92a2f04 100644 --- a/core/src/test/java/org/bitcoinj/protocols/channels/ChannelConnectionTest.java +++ b/core/src/test/java/org/bitcoinj/protocols/channels/ChannelConnectionTest.java @@ -102,11 +102,11 @@ public class ChannelConnectionTest extends TestWithWallet { public void setUp() throws Exception { super.setUp(); Utils.setMockClock(); // Use mock clock + Context.propagate(new Context(PARAMS, 3, Coin.ZERO, false)); // Shorter event horizon for unit tests. sendMoneyToWallet(COIN, AbstractBlockChain.NewBlockType.BEST_CHAIN); sendMoneyToWallet(COIN, AbstractBlockChain.NewBlockType.BEST_CHAIN); wallet.addExtension(new StoredPaymentChannelClientStates(wallet, failBroadcaster)); - Context context = new Context(PARAMS, 3); // Shorter event horizon for unit tests. - serverWallet = new Wallet(context); + serverWallet = new Wallet(PARAMS); serverWallet.addExtension(new StoredPaymentChannelServerStates(serverWallet, failBroadcaster)); serverWallet.freshReceiveKey(); // Use an atomic boolean to indicate failure because fail()/assert*() dont work in network threads @@ -163,7 +163,7 @@ public class ChannelConnectionTest extends TestWithWallet { exectuteSimpleChannelTest(userKeySetup); } - public void exectuteSimpleChannelTest(KeyParameter userKeySetup) throws Exception { + private void exectuteSimpleChannelTest(KeyParameter userKeySetup) throws Exception { // Test with network code and without any issues. We'll broadcast two txns: multisig contract and settle transaction. final SettableFuture> serverCloseFuture = SettableFuture.create(); final SettableFuture channelOpenFuture = SettableFuture.create(); @@ -251,8 +251,8 @@ public class ChannelConnectionTest extends TestWithWallet { // Wait for the server thread to catch up with closing serverState.close().get(); assertEquals(PaymentChannelServerState.State.CLOSED, serverState.getState()); - if (!serverState.getBestValueToMe().equals(amount) || !serverState.getFeePaid().equals(Coin.ZERO)) - fail(); + assertEquals(amount, serverState.getBestValueToMe()); + assertEquals(ZERO, serverState.getFeePaid()); assertTrue(channels.mapChannels.isEmpty()); // Send the settle TX to the client wallet. diff --git a/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelStateTest.java b/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelStateTest.java index 945ac6e4..1ccf2e21 100644 --- a/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelStateTest.java +++ b/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelStateTest.java @@ -88,6 +88,7 @@ public class PaymentChannelStateTest extends TestWithWallet { public void setUp() throws Exception { Utils.setMockClock(); // Use mock clock super.setUp(); + Context.propagate(new Context(PARAMS, 100, Coin.ZERO, true)); wallet.addExtension(new StoredPaymentChannelClientStates(wallet, new TransactionBroadcaster() { @Override public TransactionBroadcast broadcastTransaction(Transaction tx) { @@ -710,7 +711,7 @@ public class PaymentChannelStateTest extends TestWithWallet { } catch (ValueOutOfRangeException e) {} clientState = makeClientState(wallet, myKey, ECKey.fromPublicOnly(serverKey.getPubKey()), - Transaction.MIN_NONDUST_OUTPUT.subtract(Coin.SATOSHI).add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), + Transaction.MIN_NONDUST_OUTPUT.subtract(Coin.SATOSHI).add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), EXPIRE_TIME); assertEquals(PaymentChannelClientState.State.NEW, clientState.getState()); try { diff --git a/core/src/test/java/org/bitcoinj/testing/TestWithNetworkConnections.java b/core/src/test/java/org/bitcoinj/testing/TestWithNetworkConnections.java index 98115259..278156d7 100644 --- a/core/src/test/java/org/bitcoinj/testing/TestWithNetworkConnections.java +++ b/core/src/test/java/org/bitcoinj/testing/TestWithNetworkConnections.java @@ -82,9 +82,7 @@ public class TestWithNetworkConnections { public void setUp(BlockStore blockStore) throws Exception { BriefLogFormatter.init(); - - context = new Context(PARAMS); - Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO; + Context.propagate(new Context(PARAMS, 100, Coin.ZERO, false)); this.blockStore = blockStore; // Allow subclasses to override the wallet object with their own. if (wallet == null) { @@ -131,7 +129,6 @@ public class TestWithNetworkConnections { } public void tearDown() throws Exception { - Wallet.SendRequest.DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; stopPeerServers(); } diff --git a/core/src/test/java/org/bitcoinj/testing/TestWithWallet.java b/core/src/test/java/org/bitcoinj/testing/TestWithWallet.java index acdd36f9..3072f4f4 100644 --- a/core/src/test/java/org/bitcoinj/testing/TestWithWallet.java +++ b/core/src/test/java/org/bitcoinj/testing/TestWithWallet.java @@ -47,8 +47,7 @@ public class TestWithWallet { public void setUp() throws Exception { BriefLogFormatter.init(); - Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO; - Context ctx = new Context(PARAMS); + Context.propagate(new Context(PARAMS, 100, Coin.ZERO, false)); wallet = new Wallet(PARAMS); myKey = wallet.currentReceiveKey(); myAddress = myKey.toAddress(PARAMS); @@ -57,7 +56,6 @@ public class TestWithWallet { } public void tearDown() throws Exception { - Wallet.SendRequest.DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; } @Nullable diff --git a/examples/src/main/java/org/bitcoinj/examples/ExamplePaymentChannelClient.java b/examples/src/main/java/org/bitcoinj/examples/ExamplePaymentChannelClient.java index 2c5fb7d0..193708a9 100644 --- a/examples/src/main/java/org/bitcoinj/examples/ExamplePaymentChannelClient.java +++ b/examples/src/main/java/org/bitcoinj/examples/ExamplePaymentChannelClient.java @@ -198,7 +198,7 @@ public class ExamplePaymentChannelClient { private void waitForSufficientBalance(Coin amount) { // Not enough money in the wallet. - Coin amountPlusFee = amount.add(Wallet.SendRequest.DEFAULT_FEE_PER_KB); + Coin amountPlusFee = amount.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE); // ESTIMATED because we don't really need to wait for confirmation. ListenableFuture balanceFuture = appKit.wallet().getBalanceFuture(amountPlusFee, Wallet.BalanceType.ESTIMATED); if (!balanceFuture.isDone()) {