mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-13 10:45:51 +00:00
SendRequest: New .childPaysForParent() method that constructs a CPFP transaction.
This commit is contained in:
parent
85f7c39aa5
commit
2ab367b4e4
@ -33,6 +33,7 @@ import org.bitcoinj.signers.*;
|
|||||||
import org.bitcoinj.store.*;
|
import org.bitcoinj.store.*;
|
||||||
import org.bitcoinj.utils.*;
|
import org.bitcoinj.utils.*;
|
||||||
import org.bitcoinj.wallet.*;
|
import org.bitcoinj.wallet.*;
|
||||||
|
import org.bitcoinj.wallet.KeyChain.KeyPurpose;
|
||||||
import org.bitcoinj.wallet.Protos.Wallet.*;
|
import org.bitcoinj.wallet.Protos.Wallet.*;
|
||||||
import org.bitcoinj.wallet.WalletTransaction.*;
|
import org.bitcoinj.wallet.WalletTransaction.*;
|
||||||
import org.slf4j.*;
|
import org.slf4j.*;
|
||||||
@ -3835,6 +3836,32 @@ public class Wallet extends BaseTaggableObject
|
|||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a SendRequest for a CPFP (child-pays-for-parent) transaction. The resulting transaction is already
|
||||||
|
* completed, so you should directly proceed to signing and broadcasting/committing the transaction. CPFP is
|
||||||
|
* currently only supported by a few miners, so use with care.
|
||||||
|
*/
|
||||||
|
public static SendRequest childPaysForParent(Wallet wallet, Transaction parentTransaction, Coin feeRaise) {
|
||||||
|
TransactionOutput outputToSpend = null;
|
||||||
|
for (final TransactionOutput output : parentTransaction.getOutputs()) {
|
||||||
|
if (output.isMine(wallet) && output.isAvailableForSpending()
|
||||||
|
&& output.getValue().isGreaterThan(feeRaise)) {
|
||||||
|
outputToSpend = output;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO spend another confirmed output of own wallet if needed
|
||||||
|
checkNotNull(outputToSpend, "Can't find adequately sized output that spends to us");
|
||||||
|
|
||||||
|
final Transaction tx = new Transaction(parentTransaction.getParams());
|
||||||
|
tx.addInput(outputToSpend);
|
||||||
|
tx.addOutput(outputToSpend.getValue().subtract(feeRaise), wallet.freshAddress(KeyPurpose.CHANGE));
|
||||||
|
tx.setPurpose(Transaction.Purpose.RAISE_FEE);
|
||||||
|
final SendRequest req = forTx(tx);
|
||||||
|
req.completed = true;
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
public static SendRequest toCLTVPaymentChannel(NetworkParameters params, Date releaseTime, ECKey from, ECKey to, Coin value) {
|
public static SendRequest toCLTVPaymentChannel(NetworkParameters params, Date releaseTime, ECKey from, ECKey to, Coin value) {
|
||||||
long time = releaseTime.getTime() / 1000L;
|
long time = releaseTime.getTime() / 1000L;
|
||||||
checkArgument(time >= Transaction.LOCKTIME_THRESHOLD, "Release time was too small");
|
checkArgument(time >= Transaction.LOCKTIME_THRESHOLD, "Release time was too small");
|
||||||
|
@ -22,6 +22,7 @@ import org.bitcoinj.core.listeners.WalletCoinsReceivedEventListener;
|
|||||||
import org.bitcoinj.core.listeners.WalletCoinsSentEventListener;
|
import org.bitcoinj.core.listeners.WalletCoinsSentEventListener;
|
||||||
import org.bitcoinj.core.listeners.TransactionConfidenceEventListener;
|
import org.bitcoinj.core.listeners.TransactionConfidenceEventListener;
|
||||||
import org.bitcoinj.core.TransactionConfidence.ConfidenceType;
|
import org.bitcoinj.core.TransactionConfidence.ConfidenceType;
|
||||||
|
import org.bitcoinj.core.Wallet.BalanceType;
|
||||||
import org.bitcoinj.core.Wallet.SendRequest;
|
import org.bitcoinj.core.Wallet.SendRequest;
|
||||||
import org.bitcoinj.crypto.*;
|
import org.bitcoinj.crypto.*;
|
||||||
import org.bitcoinj.script.Script;
|
import org.bitcoinj.script.Script;
|
||||||
@ -3062,6 +3063,29 @@ public class WalletTest extends TestWithWallet {
|
|||||||
assertEquals(outputValue, request.tx.getOutput(0).getValue());
|
assertEquals(outputValue, request.tx.getOutput(0).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void childPaysForParent() throws Exception {
|
||||||
|
// Receive confirmed balance to play with.
|
||||||
|
Transaction toMe = createFakeTxWithoutChangeAddress(PARAMS, COIN, myAddress);
|
||||||
|
wallet.receiveFromBlock(toMe, createFakeBlock(blockStore, toMe).storedBlock,
|
||||||
|
AbstractBlockChain.NewBlockType.BEST_CHAIN, 0);
|
||||||
|
assertEquals(Coin.COIN, wallet.getBalance(BalanceType.ESTIMATED_SPENDABLE));
|
||||||
|
assertEquals(Coin.COIN, wallet.getBalance(BalanceType.AVAILABLE_SPENDABLE));
|
||||||
|
// Receive unconfirmed coin without fee.
|
||||||
|
Transaction toMeWithoutFee = createFakeTxWithoutChangeAddress(PARAMS, COIN, myAddress);
|
||||||
|
wallet.receivePending(toMeWithoutFee, null);
|
||||||
|
assertEquals(Coin.COIN.multiply(2), wallet.getBalance(BalanceType.ESTIMATED_SPENDABLE));
|
||||||
|
assertEquals(Coin.COIN, wallet.getBalance(BalanceType.AVAILABLE_SPENDABLE));
|
||||||
|
// Craft a child-pays-for-parent transaction.
|
||||||
|
final Coin feeRaise = MILLICOIN;
|
||||||
|
final SendRequest sendRequest = SendRequest.childPaysForParent(wallet, toMeWithoutFee, feeRaise);
|
||||||
|
wallet.signTransaction(sendRequest);
|
||||||
|
wallet.commitTx(sendRequest.tx);
|
||||||
|
assertEquals(Transaction.Purpose.RAISE_FEE, sendRequest.tx.getPurpose());
|
||||||
|
assertEquals(Coin.COIN.multiply(2).subtract(feeRaise), wallet.getBalance(BalanceType.ESTIMATED_SPENDABLE));
|
||||||
|
assertEquals(Coin.COIN, wallet.getBalance(BalanceType.AVAILABLE_SPENDABLE));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void keyRotationRandom() throws Exception {
|
public void keyRotationRandom() throws Exception {
|
||||||
Utils.setMockClock();
|
Utils.setMockClock();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user