Thanks for your recommendation. I implemented it now and it seems it works
like expected (still testing). Please note that I have a bit different use
case as usual replace by fee style txs. I need to "unlock" inputs which
were use for a trade MultiSig tx where the other users inputs come from a
never confirming tx (too low fees). So I just grab my inputs and transfer
it to a new address I control with a fee higher as the double spent tx.
public void doubleSpendTransaction(Transaction txToDoubleSpend, Address
newOutputAddress, Runnable resultHandler, ErrorMessageHandler
errorMessageHandler) throws InsufficientMoneyException {
final TransactionConfidence.ConfidenceType confidenceType =
txToDoubleSpend.getConfidence().getConfidenceType();
if (confidenceType == TransactionConfidence.ConfidenceType.PENDING) {
Transaction newTransaction = new Transaction(params);
txToDoubleSpend.getInputs().stream().forEach(input -> {
if (input.getConnectedOutput() != null &&
input.getConnectedOutput().isMine(wallet) &&
input.getConnectedOutput().getParentTransaction()
!= null && input.getValue() != null) {
newTransaction.addInput(new TransactionInput(params,
newTransaction,
new byte[]{},
new TransactionOutPoint(params,
input.getOutpoint().getIndex(),
new Transaction(params,
input.getConnectedOutput().getParentTransaction().bitcoinSerialize())),
Coin.valueOf(input.getValue().value)));
} else {
log.error("Input had null values: " + input.toString());
}
}
);
if (!newTransaction.getInputs().isEmpty() && txToDoubleSpend.getFee()
!= null) {
// We use a higher fee to be sure we get that tx confirmed
final Coin newFee =
txToDoubleSpend.getFee().add(FeePolicy.getFixedTxFeeForTrades());
newTransaction.addOutput(txToDoubleSpend.getValueSentFromMe(wallet).subtract(newFee),
newOutputAddress);
Wallet.SendRequest sendRequest =
Wallet.SendRequest.forTx(newTransaction);
sendRequest.aesKey = aesKey;
sendRequest.coinSelector = new TradeWalletCoinSelector(params,
newOutputAddress);
// We don't expect change but set it just in case
sendRequest.changeAddress = newOutputAddress;
sendRequest.feePerKb = newFee;
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
Futures.addCallback(sendResult.broadcastComplete, new
FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction result) {
log.error(result.toString());
resultHandler.run();
}
@Override
public void onFailure(@NotNull Throwable t) {
errorMessageHandler.handleErrorMessage(t.getMessage());
}
});
} else {
errorMessageHandler.handleErrorMessage("We could not find inputs we
control in the transaction we want to double spend.");
}
} else if (confidenceType == TransactionConfidence.ConfidenceType.BUILDING)
{
errorMessageHandler.handleErrorMessage("That transaction is already in
the blockchain so we cannot double spend it.");
} else if (confidenceType == TransactionConfidence.ConfidenceType.DEAD) {
errorMessageHandler.handleErrorMessage("One of the inputs of that
transaction has been already double spent.");
}
}
--
You received this message because you are subscribed to the Google Groups
"bitcoinj" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.