mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-02-24 06:47:54 +01:00
Wallet: throw more appropriate exception types during completion.
Resolves issue 560.
This commit is contained in:
parent
028a1cca69
commit
b47995ed97
3 changed files with 19 additions and 14 deletions
|
@ -1884,6 +1884,11 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class CompletionException extends RuntimeException {}
|
||||||
|
public static class DustySendRequested extends CompletionException {}
|
||||||
|
public static class CouldNotAdjustDownwards extends CompletionException {}
|
||||||
|
public static class ExceededMaxTransactionSize extends CompletionException {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a spend request containing an incomplete transaction, makes it valid by adding outputs and signed inputs
|
* Given a spend request containing an incomplete transaction, makes it valid by adding outputs and signed inputs
|
||||||
* according to the instructions in the request. The transaction in the request is modified by this method, as is
|
* according to the instructions in the request. The transaction in the request is modified by this method, as is
|
||||||
|
@ -1891,8 +1896,10 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
|
||||||
*
|
*
|
||||||
* @param req a SendRequest that contains the incomplete transaction and details for how to make it valid.
|
* @param req a SendRequest that contains the incomplete transaction and details for how to make it valid.
|
||||||
* @throws InsufficientMoneyException if the request could not be completed due to not enough balance.
|
* @throws InsufficientMoneyException if the request could not be completed due to not enough balance.
|
||||||
* @throws IllegalArgumentException if you try and complete the same SendRequest twice, or if the given send request
|
* @throws IllegalArgumentException if you try and complete the same SendRequest twice
|
||||||
* cannot be completed without violating the protocol rules.
|
* @throws DustySendRequested if the resultant transaction would violate the dust rules (an output that's too small to be worthwhile)
|
||||||
|
* @throws CouldNotAdjustDownwards if emptying the wallet was requested and the output can't be shrunk for fees without violating a protocol rule.
|
||||||
|
* @throws ExceededMaxTransactionSize if the resultant transaction is too big for Bitcoin to process (try breaking up the amounts of value)
|
||||||
*/
|
*/
|
||||||
public void completeTx(SendRequest req) throws InsufficientMoneyException {
|
public void completeTx(SendRequest req) throws InsufficientMoneyException {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
@ -1925,7 +1932,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
|
||||||
for (TransactionOutput output : req.tx.getOutputs())
|
for (TransactionOutput output : req.tx.getOutputs())
|
||||||
if (output.getValue().compareTo(Utils.CENT) < 0) {
|
if (output.getValue().compareTo(Utils.CENT) < 0) {
|
||||||
if (output.getValue().compareTo(output.getMinNonDustValue()) < 0)
|
if (output.getValue().compareTo(output.getMinNonDustValue()) < 0)
|
||||||
throw new IllegalArgumentException("Tried to send dust with ensureMinRequiredFee set - no way to complete this");
|
throw new DustySendRequested();
|
||||||
needAtLeastReferenceFee = true;
|
needAtLeastReferenceFee = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1967,7 +1974,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
|
||||||
final BigInteger feePerKb = req.feePerKb == null ? BigInteger.ZERO : req.feePerKb;
|
final BigInteger feePerKb = req.feePerKb == null ? BigInteger.ZERO : req.feePerKb;
|
||||||
Transaction tx = req.tx;
|
Transaction tx = req.tx;
|
||||||
if (!adjustOutputDownwardsForFee(tx, bestCoinSelection, baseFee, feePerKb))
|
if (!adjustOutputDownwardsForFee(tx, bestCoinSelection, baseFee, feePerKb))
|
||||||
throw new InsufficientMoneyException.CouldNotAdjustDownwards();
|
throw new CouldNotAdjustDownwards();
|
||||||
}
|
}
|
||||||
|
|
||||||
totalInput = totalInput.add(bestCoinSelection.valueGathered);
|
totalInput = totalInput.add(bestCoinSelection.valueGathered);
|
||||||
|
@ -1991,11 +1998,8 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
|
||||||
|
|
||||||
// Check size.
|
// Check size.
|
||||||
int size = req.tx.bitcoinSerialize().length;
|
int size = req.tx.bitcoinSerialize().length;
|
||||||
if (size > Transaction.MAX_STANDARD_TX_SIZE) {
|
if (size > Transaction.MAX_STANDARD_TX_SIZE)
|
||||||
throw new IllegalArgumentException(
|
throw new ExceededMaxTransactionSize();
|
||||||
String.format("Transaction could not be created without exceeding max size: %d vs %d", size,
|
|
||||||
Transaction.MAX_STANDARD_TX_SIZE));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Label the transaction as being self created. We can use this later to spend its change output even before
|
// Label the transaction as being self created. We can use this later to spend its change output even before
|
||||||
// the transaction is confirmed. We deliberately won't bother notifying listeners here as there's not much
|
// the transaction is confirmed. We deliberately won't bother notifying listeners here as there's not much
|
||||||
|
|
|
@ -1463,7 +1463,7 @@ public class WalletTest extends TestWithWallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = Wallet.ExceededMaxTransactionSize.class)
|
||||||
public void respectMaxStandardSize() throws Exception {
|
public void respectMaxStandardSize() throws Exception {
|
||||||
// Check that we won't create txns > 100kb. Average tx size is ~220 bytes so this would have to be enormous.
|
// Check that we won't create txns > 100kb. Average tx size is ~220 bytes so this would have to be enormous.
|
||||||
sendMoneyToWallet(Utils.toNanoCoins(100, 0), AbstractBlockChain.NewBlockType.BEST_CHAIN);
|
sendMoneyToWallet(Utils.toNanoCoins(100, 0), AbstractBlockChain.NewBlockType.BEST_CHAIN);
|
||||||
|
@ -1498,11 +1498,12 @@ public class WalletTest extends TestWithWallet {
|
||||||
Transaction tx3 = createFakeTx(params, BigInteger.TEN, myAddress);
|
Transaction tx3 = createFakeTx(params, BigInteger.TEN, myAddress);
|
||||||
wallet.receiveFromBlock(tx3, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 2);
|
wallet.receiveFromBlock(tx3, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 2);
|
||||||
|
|
||||||
// No way we can add nearly enough fee
|
// Not allowed to send dust.
|
||||||
try {
|
try {
|
||||||
wallet.createSend(notMyAddr, BigInteger.ONE);
|
wallet.createSend(notMyAddr, BigInteger.ONE);
|
||||||
fail();
|
fail();
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (Wallet.DustySendRequested e) {
|
||||||
|
// Expected.
|
||||||
}
|
}
|
||||||
// Spend it all without fee enforcement
|
// Spend it all without fee enforcement
|
||||||
SendRequest req = SendRequest.to(notMyAddr, BigInteger.TEN.add(BigInteger.ONE.add(BigInteger.ONE)));
|
SendRequest req = SendRequest.to(notMyAddr, BigInteger.TEN.add(BigInteger.ONE.add(BigInteger.ONE)));
|
||||||
|
@ -2179,7 +2180,7 @@ public class WalletTest extends TestWithWallet {
|
||||||
try {
|
try {
|
||||||
wallet.completeTx(request);
|
wallet.completeTx(request);
|
||||||
fail();
|
fail();
|
||||||
} catch (InsufficientMoneyException.CouldNotAdjustDownwards e) {}
|
} catch (Wallet.CouldNotAdjustDownwards e) {}
|
||||||
request.ensureMinRequiredFee = false;
|
request.ensureMinRequiredFee = false;
|
||||||
wallet.completeTx(request);
|
wallet.completeTx(request);
|
||||||
wallet.commitTx(request.tx);
|
wallet.commitTx(request.tx);
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class Main extends Application {
|
||||||
// last months worth or more (takes a few seconds).
|
// last months worth or more (takes a few seconds).
|
||||||
bitcoin.setCheckpoints(getClass().getResourceAsStream("checkpoints"));
|
bitcoin.setCheckpoints(getClass().getResourceAsStream("checkpoints"));
|
||||||
// As an example!
|
// As an example!
|
||||||
bitcoin.useTor();
|
// bitcoin.useTor();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now configure and start the appkit. This will take a second or two - we could show a temporary splash screen
|
// Now configure and start the appkit. This will take a second or two - we could show a temporary splash screen
|
||||||
|
|
Loading…
Add table
Reference in a new issue