Skip to content

Commit

Permalink
Add fee to SendRequest again
Browse files Browse the repository at this point in the history
  • Loading branch information
ManfredKarrer authored and oscarguindzberg committed Dec 20, 2018
1 parent bcafe50 commit 7dd1bfd
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 5 deletions.
17 changes: 17 additions & 0 deletions core/src/main/java/org/bitcoinj/wallet/SendRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,22 @@ public class SendRequest {
*/
public Address changeAddress = null;

/**
* <p>A transaction can have a fee attached, which is defined as the difference between the input values
* and output values. Any value taken in that is not provided to an output can be claimed by a miner. This
* is how mining is incentivized in later years of the Bitcoin system when inflation drops. It also provides
* a way for people to prioritize their transactions over others and is used as a way to make denial of service
* attacks expensive.</p>
*
* <p>This is a constant fee (in satoshis) which will be added to the transaction. It is recommended that it be
* at least {@link Transaction#REFERENCE_DEFAULT_MIN_TX_FEE} if it is set, as default Bitcoin Core will
* otherwise simply treat the transaction as if there were no fee at all.</p>
*
* <p>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.</p>
*/
public Coin fee = null;

/**
* <p>A transaction can have a fee attached, which is defined as the difference between the input values
* and output values. Any value taken in that is not provided to an output can be claimed by a miner. This
Expand Down Expand Up @@ -256,6 +272,7 @@ public String toString() {
MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(this).omitNullValues();
helper.add("emptyWallet", emptyWallet);
helper.add("changeAddress", changeAddress);
helper.add("fee", fee);
helper.add("feePerKb", feePerKb);
helper.add("ensureMinRequiredFee", ensureMinRequiredFee);
helper.add("signInputs", signInputs);
Expand Down
25 changes: 20 additions & 5 deletions core/src/main/java/org/bitcoinj/wallet/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -3990,8 +3990,9 @@ public void completeTx(SendRequest req) throws InsufficientMoneyException {
req.tx.addInput(output);

if (req.emptyWallet) {
final Coin baseFee = req.fee == null ? Coin.ZERO : req.fee;
final Coin feePerKb = req.feePerKb == null ? Coin.ZERO : req.feePerKb;
if (!adjustOutputDownwardsForFee(req.tx, bestCoinSelection, feePerKb, req.ensureMinRequiredFee))
if (!adjustOutputDownwardsForFee(req.tx, bestCoinSelection, baseFee, feePerKb, req.ensureMinRequiredFee))
throw new CouldNotAdjustDownwards();
}

Expand All @@ -4013,6 +4014,12 @@ public void completeTx(SendRequest req) throws InsufficientMoneyException {
if (size > Transaction.MAX_STANDARD_TX_SIZE)
throw new ExceededMaxTransactionSize();

final Coin calculatedFee = req.tx.getFee();
if (calculatedFee != null)
log.info(" with a fee of {}/kB, {} for {} bytes",
calculatedFee.multiply(1000).divide(size).toFriendlyString(), calculatedFee.toFriendlyString(),
size);

// 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
// point - the user isn't interested in a confidence transition they made themselves.
Expand All @@ -4025,6 +4032,7 @@ public void completeTx(SendRequest req) throws InsufficientMoneyException {
req.tx.setExchangeRate(req.exchangeRate);
req.tx.setMemo(req.memo);
req.completed = true;
req.fee = calculatedFee;
log.info(" completed: {}", req.tx);
} finally {
lock.unlock();
Expand Down Expand Up @@ -4088,10 +4096,10 @@ public void signTransaction(SendRequest req) {
}

/** Reduce the value of the first output of a transaction to pay the given feePerKb as appropriate for its size. */
private boolean adjustOutputDownwardsForFee(Transaction tx, CoinSelection coinSelection, Coin feePerKb,
private boolean adjustOutputDownwardsForFee(Transaction tx, CoinSelection coinSelection, Coin baseFee, Coin feePerKb,
boolean ensureMinRequiredFee) {
final int size = tx.unsafeBitcoinSerialize().length + estimateBytesForSigning(coinSelection);
Coin fee = feePerKb.multiply(size).divide(1000);
Coin fee = baseFee.add(feePerKb.multiply(size).divide(1000));
if (ensureMinRequiredFee && fee.compareTo(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE) < 0)
fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
TransactionOutput output = tx.getOutput(0);
Expand Down Expand Up @@ -4837,7 +4845,14 @@ public FeeCalculation calculateFee(SendRequest req, Coin value, List<Transaction
while (true) {
resetTxInputs(req, originalInputs);

Coin fees = req.feePerKb.multiply(lastCalculatedSize).divide(1000);
Coin fees = req.fee == null ? Coin.ZERO : req.fee;
if (lastCalculatedSize > 0) {
// If the size is exactly 1000 bytes then we'll over-pay, but this should be rare.
fees = fees.add(req.feePerKb.multiply(lastCalculatedSize).divide(1000));
} 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;

Expand Down Expand Up @@ -5252,7 +5267,7 @@ private Transaction rekeyOneBatch(long timeSecs, @Nullable KeyParameter aesKey,
}
// When not signing, don't waste addresses.
rekeyTx.addOutput(toMove.valueGathered, sign ? freshReceiveAddress() : currentReceiveAddress());
if (!adjustOutputDownwardsForFee(rekeyTx, toMove, Transaction.DEFAULT_TX_FEE, true)) {
if (!adjustOutputDownwardsForFee(rekeyTx, toMove, Coin.ZERO, Transaction.DEFAULT_TX_FEE, true)) {
log.error("Failed to adjust rekey tx for fees.");
return null;
}
Expand Down

0 comments on commit 7dd1bfd

Please sign in to comment.