diff --git a/core/src/main/java/com/google/bitcoin/core/Wallet.java b/core/src/main/java/com/google/bitcoin/core/Wallet.java index c89db878..8dddd186 100644 --- a/core/src/main/java/com/google/bitcoin/core/Wallet.java +++ b/core/src/main/java/com/google/bitcoin/core/Wallet.java @@ -1689,7 +1689,7 @@ public class Wallet implements Serializable, BlockChainListener { *

You might also consider adding a {@link SendRequest#feePerKb} to set the fee per kb of transaction size * (rounded down to the nearest kb) as that is how transactions are sorted when added to a block by miners.

*/ - public BigInteger fee = BigInteger.ZERO; + public BigInteger fee = null; /** *

A transaction can have a fee attached, which is defined as the difference between the input values @@ -1705,7 +1705,13 @@ public class Wallet implements Serializable, BlockChainListener { * *

You might also consider using a {@link SendRequest#fee} to set the fee added for the first kb of size.

*/ - public BigInteger feePerKb = BigInteger.ZERO; + public BigInteger 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 BigInteger DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; /** *

Requires that there be enough fee for a default reference client to at least relay the transaction. @@ -1954,13 +1960,10 @@ public class Wallet implements Serializable, BlockChainListener { // Note that output.isMine(this) needs to test the keychain which is currently an array, so it's // O(candidate outputs ^ keychain.size())! There's lots of low hanging fruit here. LinkedList candidates = calculateSpendCandidates(true); - Address changeAddress = req.changeAddress; - int minSize = 0; // This can throw InsufficientMoneyException. - FeeCalculation feeCalculation = null; + FeeCalculation feeCalculation; try { - feeCalculation = new FeeCalculation(req, value, originalInputs, needAtLeastReferenceFee, - candidates, changeAddress, minSize); + feeCalculation = new FeeCalculation(req, value, originalInputs, needAtLeastReferenceFee, candidates); } catch (InsufficientMoneyException e) { // TODO: Propagate this after 0.9 is released and stop returning a boolean. return false; @@ -1979,6 +1982,9 @@ public class Wallet implements Serializable, BlockChainListener { log.info(" with {} coins change", bitcoinValueToFriendlyString(bestChangeOutput.getValue())); } final BigInteger calculatedFee = totalInput.subtract(totalOutput); + if (calculatedFee.compareTo(BigInteger.ZERO) > 0) { + log.info(" with a fee of {}", bitcoinValueToFriendlyString(calculatedFee)); + } // Now sign the inputs, thus proving that we are entitled to redeem the connected outputs. try { @@ -3084,8 +3090,7 @@ public class Wallet implements Serializable, BlockChainListener { private TransactionOutput bestChangeOutput; public FeeCalculation(SendRequest req, BigInteger value, List originalInputs, - boolean needAtLeastReferenceFee, LinkedList candidates, - Address changeAddress, int minSize) throws InsufficientMoneyException { + boolean needAtLeastReferenceFee, LinkedList candidates) throws InsufficientMoneyException { // There are 3 possibilities for what adding change might do: // 1) No effect // 2) Causes increase in fee (change < 0.01 COINS) @@ -3099,14 +3104,22 @@ public class Wallet implements Serializable, BlockChainListener { TransactionOutput selection2Change = null; CoinSelection selection1 = null; TransactionOutput selection1Change = null; + // We keep track of the last size of the transaction we calculated but only if the act of adding inputs and + // change resulted in the size crossing a 1000 byte boundary. Otherwise it stays at zero. + int lastCalculatedSize = 0; + BigInteger valueNeeded; while (true) { resetTxInputs(req, originalInputs); - BigInteger fees = req.fee.add(BigInteger.valueOf(minSize/1000).multiply(req.feePerKb)); + BigInteger fees = req.fee == null ? BigInteger.ZERO : req.fee; + if (lastCalculatedSize > 0) + fees = fees.add(BigInteger.valueOf((lastCalculatedSize / 1000) + 1).multiply(req.feePerKb)); + else + fees = fees.add(req.feePerKb); // First time around the loop. if (needAtLeastReferenceFee && fees.compareTo(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE) < 0) fees = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; - BigInteger valueNeeded = value.add(fees); + valueNeeded = value.add(fees); if (additionalValueForNextCategory != null) valueNeeded = valueNeeded.add(additionalValueForNextCategory); BigInteger additionalValueSelected = additionalValueForNextCategory; @@ -3146,7 +3159,8 @@ public class Wallet implements Serializable, BlockChainListener { if (change.compareTo(BigInteger.ZERO) > 0) { // The value of the inputs is greater than what we want to send. Just like in real life then, // we need to take back some coins ... this is called "change". Add another output that sends the change - // back to us. The address comes either from the request or getChangeAddress() as a default.. + // back to us. The address comes either from the request or getChangeAddress() as a default. + Address changeAddress = req.changeAddress; if (changeAddress == null) changeAddress = getChangeAddress(); changeOutput = new TransactionOutput(params, req.tx, change, changeAddress); @@ -3177,11 +3191,12 @@ public class Wallet implements Serializable, BlockChainListener { checkState(input.getScriptBytes().length == 0); } - // Estimate transaction size and loop again if we need more fee per kb - size += estimateBytesForSpending(selection); + // Estimate transaction size and loop again if we need more fee per kb. The serialized tx doesn't + // include things we haven't added yet like input signatures/scripts or the change output. size += req.tx.bitcoinSerialize().length; - if (size/1000 > minSize/1000 && req.feePerKb.compareTo(BigInteger.ZERO) > 0) { - minSize = size; + size += estimateBytesForSigning(selection); + if (size/1000 > lastCalculatedSize/1000 && req.feePerKb.compareTo(BigInteger.ZERO) > 0) { + lastCalculatedSize = size; // We need more fees anyway, just try again with the same additional value additionalValueForNextCategory = additionalValueSelected; continue; @@ -3216,7 +3231,7 @@ public class Wallet implements Serializable, BlockChainListener { resetTxInputs(req, originalInputs); if (selection3 == null && selection2 == null && selection1 == null) { - log.warn("Insufficient value in wallet for send"); + log.warn("Insufficient value in wallet for send: needed {}", bitcoinValueToFriendlyString(valueNeeded)); throw new InsufficientMoneyException(); } @@ -3249,7 +3264,7 @@ public class Wallet implements Serializable, BlockChainListener { } } - private int estimateBytesForSpending(CoinSelection selection) { + private int estimateBytesForSigning(CoinSelection selection) { int size = 0; for (TransactionOutput output : selection.gathered) { try { diff --git a/core/src/test/java/com/google/bitcoin/core/BlockChainTest.java b/core/src/test/java/com/google/bitcoin/core/BlockChainTest.java index 9bf9cc29..f530ea5b 100644 --- a/core/src/test/java/com/google/bitcoin/core/BlockChainTest.java +++ b/core/src/test/java/com/google/bitcoin/core/BlockChainTest.java @@ -24,6 +24,7 @@ import com.google.bitcoin.store.BlockStore; import com.google.bitcoin.store.MemoryBlockStore; import com.google.bitcoin.utils.BriefLogFormatter; import com.google.common.util.concurrent.ListenableFuture; +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -63,6 +64,7 @@ public class BlockChainTest { public void setUp() throws Exception { BriefLogFormatter.initVerbose(); testNetChain = new BlockChain(testNet, new Wallet(testNet), new MemoryBlockStore(testNet)); + Wallet.SendRequest.DEFAULT_FEE_PER_KB = BigInteger.ZERO; unitTestParams = UnitTestParams.get(); wallet = new Wallet(unitTestParams) { @@ -83,6 +85,11 @@ public class BlockChainTest { coinbaseTo = wallet.getKeys().get(0).toAddress(unitTestParams); } + @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. @@ -323,11 +330,8 @@ public class BlockChainTest { assertNull(coinbaseSpend); } - // Give it one more block - should now be able to spend coinbase transaction. - // Non relevant tx. - Transaction tx3 = createFakeTx(unitTestParams, Utils.toNanoCoins(1, 0), - new ECKey().toAddress(unitTestParams)); - + // Give it one more block - should now be able to spend coinbase transaction. Non relevant tx. + Transaction tx3 = createFakeTx(unitTestParams, Utils.toNanoCoins(1, 0), new ECKey().toAddress(unitTestParams)); Block b3 = createFakeBlock(blockStore, tx3).block; chain.add(b3); diff --git a/core/src/test/java/com/google/bitcoin/core/ChainSplitTest.java b/core/src/test/java/com/google/bitcoin/core/ChainSplitTest.java index 652ef171..4e5934a7 100644 --- a/core/src/test/java/com/google/bitcoin/core/ChainSplitTest.java +++ b/core/src/test/java/com/google/bitcoin/core/ChainSplitTest.java @@ -44,6 +44,7 @@ public class ChainSplitTest { @Before public void setUp() throws Exception { BriefLogFormatter.init(); + Wallet.SendRequest.DEFAULT_FEE_PER_KB = BigInteger.ZERO; unitTestParams = UnitTestParams.get(); wallet = new Wallet(unitTestParams); wallet.addKey(new ECKey()); diff --git a/core/src/test/java/com/google/bitcoin/core/PeerGroupTest.java b/core/src/test/java/com/google/bitcoin/core/PeerGroupTest.java index 0ae7e96b..e6bda429 100644 --- a/core/src/test/java/com/google/bitcoin/core/PeerGroupTest.java +++ b/core/src/test/java/com/google/bitcoin/core/PeerGroupTest.java @@ -46,7 +46,8 @@ public class PeerGroupTest extends TestWithPeerGroup { } @After - public void shutDown() throws Exception { + public void tearDown() throws Exception { + super.tearDown(); peerGroup.stopAndWait(); } diff --git a/core/src/test/java/com/google/bitcoin/core/TestWithNetworkConnections.java b/core/src/test/java/com/google/bitcoin/core/TestWithNetworkConnections.java index 9ada4f9e..01c90c97 100644 --- a/core/src/test/java/com/google/bitcoin/core/TestWithNetworkConnections.java +++ b/core/src/test/java/com/google/bitcoin/core/TestWithNetworkConnections.java @@ -24,6 +24,7 @@ import org.easymock.EasyMock; import org.easymock.IMocksControl; import org.jboss.netty.channel.*; +import java.math.BigInteger; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -60,6 +61,7 @@ public class TestWithNetworkConnections { control.checkOrder(false); unitTestParams = UnitTestParams.get(); + Wallet.SendRequest.DEFAULT_FEE_PER_KB = BigInteger.ZERO; this.blockStore = blockStore; wallet = new Wallet(unitTestParams); key = new ECKey(); @@ -74,6 +76,10 @@ public class TestWithNetworkConnections { pipeline = createPipeline(channel); } + public void tearDown() throws Exception { + Wallet.SendRequest.DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; + } + protected ChannelPipeline createPipeline(Channel channel) { ChannelPipeline pipeline = control.createMock(ChannelPipeline.class); expect(channel.getPipeline()).andStubReturn(pipeline); diff --git a/core/src/test/java/com/google/bitcoin/core/TestWithWallet.java b/core/src/test/java/com/google/bitcoin/core/TestWithWallet.java index d9e552ba..8bed75eb 100644 --- a/core/src/test/java/com/google/bitcoin/core/TestWithWallet.java +++ b/core/src/test/java/com/google/bitcoin/core/TestWithWallet.java @@ -20,6 +20,7 @@ import com.google.bitcoin.params.UnitTestParams; import com.google.bitcoin.store.BlockStore; import com.google.bitcoin.store.MemoryBlockStore; import com.google.bitcoin.utils.BriefLogFormatter; +import org.junit.After; import org.junit.Before; import java.io.IOException; @@ -40,6 +41,7 @@ public class TestWithWallet { @Before public void setUp() throws Exception { BriefLogFormatter.init(); + Wallet.SendRequest.DEFAULT_FEE_PER_KB = BigInteger.ZERO; myKey = new ECKey(); myAddress = myKey.toAddress(params); wallet = new Wallet(params); @@ -48,6 +50,11 @@ public class TestWithWallet { chain = new BlockChain(params, wallet, blockStore); } + @After + public void tearDown() throws Exception { + Wallet.SendRequest.DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; + } + protected Transaction sendMoneyToWallet(Wallet wallet, Transaction tx, AbstractBlockChain.NewBlockType type) throws IOException, ProtocolException, VerificationException { if (type == null) { diff --git a/core/src/test/java/com/google/bitcoin/core/WalletTest.java b/core/src/test/java/com/google/bitcoin/core/WalletTest.java index 46e35b03..3832f348 100644 --- a/core/src/test/java/com/google/bitcoin/core/WalletTest.java +++ b/core/src/test/java/com/google/bitcoin/core/WalletTest.java @@ -1193,7 +1193,8 @@ public class WalletTest extends TestWithWallet { StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, notMyAddr), BigInteger.ONE, 1); Transaction tx1 = createFakeTx(params, BigInteger.ONE, myAddress); wallet.receiveFromBlock(tx1, block, AbstractBlockChain.NewBlockType.BEST_CHAIN); - Transaction tx2 = createFakeTx(params, BigInteger.ONE, myAddress); assertTrue(!tx1.getHash().equals(tx2.getHash())); + Transaction tx2 = createFakeTx(params, BigInteger.ONE, myAddress); + assertTrue(!tx1.getHash().equals(tx2.getHash())); wallet.receiveFromBlock(tx2, block, AbstractBlockChain.NewBlockType.BEST_CHAIN); Transaction tx3 = createFakeTx(params, BigInteger.TEN, myAddress); wallet.receiveFromBlock(tx3, block, AbstractBlockChain.NewBlockType.BEST_CHAIN); @@ -1364,24 +1365,25 @@ public class WalletTest extends TestWithWallet { assertTrue(request15.tx.bitcoinSerialize().length > 1000); request15.feePerKb = BigInteger.ONE; assertTrue(wallet.completeTx(request15)); - assertEquals(BigInteger.ONE, request15.fee); + assertEquals(BigInteger.valueOf(2), request15.fee); Transaction spend15 = request15.tx; - // If a transaction is over 1kb, the set fee should be added + // If a transaction is over 1kb, 2 satoshis should be added. assertEquals(31, spend15.getOutputs().size()); // We optimize for priority, so the output selected should be the largest one BigInteger outValue15 = BigInteger.ZERO; for (TransactionOutput out : spend15.getOutputs()) outValue15 = outValue15.add(out.getValue()); - assertEquals(outValue15, Utils.COIN.subtract(BigInteger.ONE)); + assertEquals(Utils.COIN.subtract(BigInteger.valueOf(2)), outValue15); SendRequest request16 = SendRequest.to(notMyAddr, Utils.CENT); + request16.feePerKb = BigInteger.ZERO; for (int i = 0; i < 29; i++) request16.tx.addOutput(Utils.CENT, notMyAddr); assertTrue(request16.tx.bitcoinSerialize().length > 1000); assertTrue(wallet.completeTx(request16)); + // Of course the fee shouldn't be added if feePerKb == 0 assertEquals(BigInteger.ZERO, request16.fee); Transaction spend16 = request16.tx; - // Of course the fee shouldn't be added if feePerKb == 0 assertEquals(31, spend16.getOutputs().size()); // We optimize for priority, so the output selected should be the largest one BigInteger outValue16 = BigInteger.ZERO; @@ -1389,14 +1391,14 @@ public class WalletTest extends TestWithWallet { outValue16 = outValue16.add(out.getValue()); assertEquals(Utils.COIN, outValue16); - // Create a transaction who's max size could be up to 999 (if signatures were maximum size) + // Create a transaction whose max size could be up to 999 (if signatures were maximum size) SendRequest request17 = SendRequest.to(notMyAddr, Utils.CENT); for (int i = 0; i < 22; i++) request17.tx.addOutput(Utils.CENT, notMyAddr); request17.tx.addOutput(new TransactionOutput(params, request17.tx, Utils.CENT, new byte[15])); request17.feePerKb = BigInteger.ONE; assertTrue(wallet.completeTx(request17)); - assertEquals(BigInteger.ZERO, request17.fee); + assertEquals(BigInteger.ONE, request17.fee); assertEquals(1, request17.tx.getInputs().size()); // Calculate its max length to make sure it is indeed 999 int theoreticalMaxLength17 = request17.tx.bitcoinSerialize().length + myKey.getPubKey().length + 75; @@ -1404,54 +1406,59 @@ public class WalletTest extends TestWithWallet { theoreticalMaxLength17 -= in.getScriptBytes().length; assertEquals(999, theoreticalMaxLength17); Transaction spend17 = request17.tx; - // Its actual size must be between 997 and 999 (inclusive) as signatures have a 3-byte size range (almost always) - assertTrue(spend17.bitcoinSerialize().length >= 997 && spend17.bitcoinSerialize().length <= 999); - // Now check that it didn't get a fee since its max size is 999 + { + // Its actual size must be between 997 and 999 (inclusive) as signatures have a 3-byte size range (almost always) + final int length = spend17.bitcoinSerialize().length; + assertTrue(Integer.toString(length), length >= 997 && length <= 999); + } + // Now check that it got a fee of 1 since its max size is 999 (1kb). assertEquals(25, spend17.getOutputs().size()); // We optimize for priority, so the output selected should be the largest one BigInteger outValue17 = BigInteger.ZERO; for (TransactionOutput out : spend17.getOutputs()) outValue17 = outValue17.add(out.getValue()); - assertEquals(Utils.COIN, outValue17); + assertEquals(Utils.COIN.subtract(BigInteger.ONE), outValue17); - // Create a transaction who's max size could be up to 1000 (if signatures were maximum size) + // Create a transaction who's max size could be up to 1001 (if signatures were maximum size) SendRequest request18 = SendRequest.to(notMyAddr, Utils.CENT); for (int i = 0; i < 22; i++) request18.tx.addOutput(Utils.CENT, notMyAddr); - request18.tx.addOutput(new TransactionOutput(params, request18.tx, Utils.CENT, new byte[16])); + request18.tx.addOutput(new TransactionOutput(params, request18.tx, Utils.CENT, new byte[17])); request18.feePerKb = BigInteger.ONE; assertTrue(wallet.completeTx(request18)); - assertEquals(BigInteger.ONE, request18.fee); + assertEquals(BigInteger.valueOf(2), request18.fee); assertEquals(1, request18.tx.getInputs().size()); - // Calculate its max length to make sure it is indeed 1000 + // Calculate its max length to make sure it is indeed 1001 Transaction spend18 = request18.tx; int theoreticalMaxLength18 = spend18.bitcoinSerialize().length + myKey.getPubKey().length + 75; for (TransactionInput in : spend18.getInputs()) theoreticalMaxLength18 -= in.getScriptBytes().length; - assertEquals(1000, theoreticalMaxLength18); + assertEquals(1001, theoreticalMaxLength18); // Its actual size must be between 998 and 1000 (inclusive) as signatures have a 3-byte size range (almost always) assertTrue(spend18.bitcoinSerialize().length >= 998); - assertTrue(spend18.bitcoinSerialize().length <= 1000); + assertTrue(spend18.bitcoinSerialize().length <= 1001); // Now check that it did get a fee since its max size is 1000 assertEquals(25, spend18.getOutputs().size()); // We optimize for priority, so the output selected should be the largest one BigInteger outValue18 = BigInteger.ZERO; for (TransactionOutput out : spend18.getOutputs()) outValue18 = outValue18.add(out.getValue()); - assertEquals(outValue18, Utils.COIN.subtract(BigInteger.ONE)); + assertEquals(outValue18, Utils.COIN.subtract(BigInteger.valueOf(2))); // Now create a transaction that will spend COIN + fee, which makes it require both inputs assertEquals(wallet.getBalance(), Utils.CENT.add(Utils.COIN)); SendRequest request19 = SendRequest.to(notMyAddr, Utils.CENT); + request19.feePerKb = BigInteger.ZERO; for (int i = 0; i < 99; i++) request19.tx.addOutput(Utils.CENT, notMyAddr); - // If we send now, we shouldnt need a fee and should only have to spend our COIN + // If we send now, we shouldn't need a fee and should only have to spend our COIN assertTrue(wallet.completeTx(request19)); assertEquals(BigInteger.ZERO, request19.fee); assertEquals(1, request19.tx.getInputs().size()); assertEquals(100, request19.tx.getOutputs().size()); // Now reset request19 and give it a fee per kb - request19.completed = false; request19.tx.clearInputs(); + request19.completed = false; + request19.tx.clearInputs(); request19.feePerKb = BigInteger.ONE; assertTrue(wallet.completeTx(request19)); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request19.fee); @@ -1466,9 +1473,10 @@ public class WalletTest extends TestWithWallet { // Create another transaction that will spend COIN + fee, which makes it require both inputs SendRequest request20 = SendRequest.to(notMyAddr, Utils.CENT); + request20.feePerKb = BigInteger.ZERO; for (int i = 0; i < 99; i++) request20.tx.addOutput(Utils.CENT, notMyAddr); - // If we send now, we shouldnt need a fee and should only have to spend our COIN + // If we send now, we shouldn't have a fee and should only have to spend our COIN assertTrue(wallet.completeTx(request20)); assertEquals(BigInteger.ZERO, request20.fee); assertEquals(1, request20.tx.getInputs().size()); @@ -1477,16 +1485,19 @@ public class WalletTest extends TestWithWallet { request20.completed = false; request20.tx.clearInputs(); request20.feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; assertTrue(wallet.completeTx(request20)); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(BigInteger.valueOf(3)), request20.fee); + // 4kb tx. + assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(BigInteger.valueOf(4)), request20.fee); assertEquals(2, request20.tx.getInputs().size()); BigInteger outValue20 = BigInteger.ZERO; for (TransactionOutput out : request20.tx.getOutputs()) outValue20 = outValue20.add(out.getValue()); // This time the fee we wanted to pay was more, so that should be what we paid - assertEquals(outValue20, Utils.COIN.add(Utils.CENT).subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(BigInteger.valueOf(3)))); + assertEquals(outValue20, Utils.COIN.add(Utils.CENT).subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(BigInteger.valueOf(4)))); - // Same as request 19, but make the change 0 (so it doesnt force fee) and make us require min fee as a result of an output < CENT + // Same as request 19, but make the change 0 (so it doesnt force fee) and make us require min fee as a + // result of an output < CENT. SendRequest request21 = SendRequest.to(notMyAddr, Utils.CENT); + request21.feePerKb = BigInteger.ZERO; for (int i = 0; i < 99; i++) request21.tx.addOutput(Utils.CENT, notMyAddr); request21.tx.addOutput(Utils.CENT.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), notMyAddr); @@ -1502,15 +1513,18 @@ public class WalletTest extends TestWithWallet { // Test feePerKb when we aren't using ensureMinRequiredFee // Same as request 19 SendRequest request25 = SendRequest.to(notMyAddr, Utils.CENT); - for (int i = 0; i < 99; i++) + request25.feePerKb = BigInteger.ZERO; + for (int i = 0; i < 70; i++) request25.tx.addOutput(Utils.CENT, notMyAddr); - // If we send now, we shouldnt need a fee and should only have to spend our COIN + // If we send now, we shouldn't need a fee and should only have to spend our COIN assertTrue(wallet.completeTx(request25)); assertEquals(BigInteger.ZERO, request25.fee); assertEquals(1, request25.tx.getInputs().size()); - assertEquals(100, request25.tx.getOutputs().size()); + assertEquals(72, request25.tx.getOutputs().size()); + System.out.println(request25.tx.bitcoinSerialize().length); // Now reset request19 and give it a fee per kb - request25.completed = false; request25.tx.clearInputs(); + request25.tx.clearInputs(); + request25 = SendRequest.forTx(request25.tx); request25.feePerKb = Utils.CENT.divide(BigInteger.valueOf(3)); request25.ensureMinRequiredFee = false; assertTrue(wallet.completeTx(request25)); @@ -1519,13 +1533,13 @@ public class WalletTest extends TestWithWallet { BigInteger outValue25 = BigInteger.ZERO; for (TransactionOutput out : request25.tx.getOutputs()) outValue25 = outValue25.add(out.getValue()); - // Our change output should be one nanocoin + // Our change output should be one satoshi // Change this assert when we eventually randomize output order assertEquals(BigInteger.ONE, request25.tx.getOutput(request25.tx.getOutputs().size() - 1).getValue()); - // and our fee should be CENT-1 nanocoin + // and our fee should be CENT-1 satoshi assertEquals(outValue25, Utils.COIN.add(BigInteger.ONE)); - //Spend our CENT output + // Spend our CENT output. Transaction spendTx5 = new Transaction(params); spendTx5.addOutput(Utils.CENT, notMyAddr); spendTx5.addInput(tx5.getOutput(0)); @@ -1557,7 +1571,7 @@ 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 = BigInteger.ZERO; // Make sure TestWithWallet isnt doing anything crazy. assertEquals(0, wallet.getTransactions(true).size()); @@ -1631,6 +1645,8 @@ public class WalletTest extends TestWithWallet { assertTrue(wallet.completeTx(request6)); assertEquals(BigInteger.ZERO, request6.fee); assertEquals(2, request6.tx.getOutputs().size()); // We should have a change output + + SendRequest.DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; } @Test @@ -1701,11 +1717,10 @@ public class WalletTest extends TestWithWallet { for (int i = 0; i < 16; i++) request2.tx.addOutput(Utils.CENT, notMyAddr); request2.tx.addOutput(new TransactionOutput(params, request2.tx, Utils.CENT, new byte[16])); - request2.fee = BigInteger.ONE; request2.feePerKb = BigInteger.ONE; // The process is the same as above, but now we can complete category 1 with one more input, and pay a fee of 2 assertTrue(wallet.completeTx(request2)); - assertEquals(BigInteger.ONE.shiftLeft(1), request2.fee); + assertEquals(BigInteger.valueOf(2), request2.fee); assertEquals(4, request2.tx.getInputs().size()); }