use of com.google.common.util.concurrent.FutureCallback in project bisq-desktop by bisq-network.
the class WithdrawalView method onWithdraw.
// /////////////////////////////////////////////////////////////////////////////////////////
// UI handlers
// /////////////////////////////////////////////////////////////////////////////////////////
@FXML
public void onWithdraw() {
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
try {
// We do not know sendersAmount if senderPaysFee is true. We repeat fee calculation after first attempt if senderPaysFee is true.
Transaction feeEstimationTransaction = walletService.getFeeEstimationTransactionForMultipleAddresses(fromAddresses, amountAsCoin);
if (feeExcluded && feeEstimationTransaction != null) {
sendersAmount = amountAsCoin.add(feeEstimationTransaction.getFee());
feeEstimationTransaction = walletService.getFeeEstimationTransactionForMultipleAddresses(fromAddresses, sendersAmount);
}
checkNotNull(feeEstimationTransaction, "feeEstimationTransaction must not be null");
Coin fee = feeEstimationTransaction.getFee();
sendersAmount = feeExcluded ? amountAsCoin.add(fee) : amountAsCoin;
Coin receiverAmount = feeExcluded ? amountAsCoin : amountAsCoin.subtract(fee);
if (areInputsValid()) {
int txSize = feeEstimationTransaction.bitcoinSerialize().length;
log.info("Fee for tx with size {}: {} " + Res.getBaseCurrencyCode() + "", txSize, fee.toPlainString());
if (receiverAmount.isPositive()) {
double feePerByte = CoinUtil.getFeePerByte(fee, txSize);
double kb = txSize / 1000d;
new Popup<>().headLine(Res.get("funds.withdrawal.confirmWithdrawalRequest")).confirmation(Res.get("shared.sendFundsDetailsWithFee", formatter.formatCoinWithCode(sendersAmount), withdrawFromTextField.getText(), withdrawToTextField.getText(), formatter.formatCoinWithCode(fee), feePerByte, kb, formatter.formatCoinWithCode(receiverAmount))).actionButtonText(Res.get("shared.yes")).onAction(() -> doWithdraw(sendersAmount, fee, new FutureCallback<Transaction>() {
@Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
if (transaction != null) {
log.debug("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
} else {
log.error("onWithdraw transaction is null");
}
List<Trade> trades = new ArrayList<>(tradeManager.getTradableList());
trades.stream().filter(Trade::isPayoutPublished).forEach(trade -> {
walletService.getAddressEntry(trade.getId(), AddressEntry.Context.TRADE_PAYOUT).ifPresent(addressEntry -> {
if (walletService.getBalanceForAddress(addressEntry.getAddress()).isZero())
tradeManager.addTradeToClosedTrades(trade);
});
});
}
@Override
public void onFailure(@NotNull Throwable t) {
log.error("onWithdraw onFailure");
}
})).closeButtonText(Res.get("shared.cancel")).show();
} else {
new Popup<>().warning(Res.get("portfolio.pending.step5_buyer.amountTooLow")).show();
}
}
} catch (InsufficientFundsException e) {
new Popup<>().warning(Res.get("funds.withdrawal.warn.amountExceeds") + "\n\nError message:\n" + e.getMessage()).show();
} catch (Throwable e) {
e.printStackTrace();
log.error(e.toString());
new Popup<>().warning(e.toString()).show();
}
} else {
GUIUtil.showNotReadyForTxBroadcastPopups(p2PService, walletsSetup);
}
}
use of com.google.common.util.concurrent.FutureCallback in project bisq-core by bisq-network.
the class BtcWalletService method doubleSpendTransaction.
// /////////////////////////////////////////////////////////////////////////////////////////
// Double spend unconfirmed transaction (unlock in case we got into a tx with a too low mining fee)
// /////////////////////////////////////////////////////////////////////////////////////////
public void doubleSpendTransaction(String txId, Runnable resultHandler, ErrorMessageHandler errorMessageHandler) throws InsufficientFundsException {
AddressEntry addressEntry = getOrCreateUnusedAddressEntry(AddressEntry.Context.AVAILABLE);
checkNotNull(addressEntry.getAddress(), "addressEntry.getAddress() must not be null");
Optional<Transaction> transactionOptional = wallet.getTransactions(true).stream().filter(t -> t.getHashAsString().equals(txId)).findAny();
if (transactionOptional.isPresent()) {
Transaction txToDoubleSpend = transactionOptional.get();
Address toAddress = addressEntry.getAddress();
final TransactionConfidence.ConfidenceType confidenceType = txToDoubleSpend.getConfidence().getConfidenceType();
if (confidenceType == TransactionConfidence.ConfidenceType.PENDING) {
log.debug("txToDoubleSpend no. of inputs " + txToDoubleSpend.getInputs().size());
Transaction newTransaction = new Transaction(params);
txToDoubleSpend.getInputs().stream().forEach(input -> {
final TransactionOutput connectedOutput = input.getConnectedOutput();
if (connectedOutput != null && connectedOutput.isMine(wallet) && connectedOutput.getParentTransaction() != null && connectedOutput.getParentTransaction().getConfidence() != null && input.getValue() != null) {
// if (connectedOutput.getParentTransaction().getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) {
newTransaction.addInput(new TransactionInput(params, newTransaction, new byte[] {}, new TransactionOutPoint(params, input.getOutpoint().getIndex(), new Transaction(params, connectedOutput.getParentTransaction().bitcoinSerialize())), Coin.valueOf(input.getValue().value)));
/* } else {
log.warn("Confidence of parent tx is not of type BUILDING: ConfidenceType=" +
connectedOutput.getParentTransaction().getConfidence().getConfidenceType());
}*/
}
});
log.info("newTransaction no. of inputs " + newTransaction.getInputs().size());
log.info("newTransaction size in kB " + newTransaction.bitcoinSerialize().length / 1024);
if (!newTransaction.getInputs().isEmpty()) {
Coin amount = Coin.valueOf(newTransaction.getInputs().stream().mapToLong(input -> input.getValue() != null ? input.getValue().value : 0).sum());
newTransaction.addOutput(amount, toAddress);
try {
Coin fee;
int counter = 0;
int txSize = 0;
Transaction tx;
SendRequest sendRequest;
Coin txFeeForWithdrawalPerByte = getTxFeeForWithdrawalPerByte();
do {
counter++;
fee = txFeeForWithdrawalPerByte.multiply(txSize);
newTransaction.clearOutputs();
newTransaction.addOutput(amount.subtract(fee), toAddress);
sendRequest = SendRequest.forTx(newTransaction);
sendRequest.fee = fee;
sendRequest.feePerKb = Coin.ZERO;
sendRequest.ensureMinRequiredFee = false;
sendRequest.aesKey = aesKey;
sendRequest.coinSelector = new BtcCoinSelector(toAddress);
sendRequest.changeAddress = toAddress;
wallet.completeTx(sendRequest);
tx = sendRequest.tx;
txSize = tx.bitcoinSerialize().length;
printTx("FeeEstimationTransaction", tx);
sendRequest.tx.getOutputs().forEach(o -> log.debug("Output value " + o.getValue().toFriendlyString()));
} while (feeEstimationNotSatisfied(counter, tx));
if (counter == 10)
log.error("Could not calculate the fee. Tx=" + tx);
Wallet.SendResult sendResult = null;
try {
sendRequest = SendRequest.forTx(newTransaction);
sendRequest.fee = fee;
sendRequest.feePerKb = Coin.ZERO;
sendRequest.ensureMinRequiredFee = false;
sendRequest.aesKey = aesKey;
sendRequest.coinSelector = new BtcCoinSelector(toAddress);
sendRequest.changeAddress = toAddress;
sendResult = wallet.sendCoins(sendRequest);
} catch (InsufficientMoneyException e) {
// in some cases getFee did not calculate correctly and we still get an InsufficientMoneyException
log.warn("We still have a missing fee " + (e.missing != null ? e.missing.toFriendlyString() : ""));
amount = amount.subtract(e.missing);
newTransaction.clearOutputs();
newTransaction.addOutput(amount, toAddress);
sendRequest = SendRequest.forTx(newTransaction);
sendRequest.fee = fee;
sendRequest.feePerKb = Coin.ZERO;
sendRequest.ensureMinRequiredFee = false;
sendRequest.aesKey = aesKey;
sendRequest.coinSelector = new BtcCoinSelector(toAddress, false);
sendRequest.changeAddress = toAddress;
try {
sendResult = wallet.sendCoins(sendRequest);
printTx("FeeEstimationTransaction", newTransaction);
} catch (InsufficientMoneyException e2) {
errorMessageHandler.handleErrorMessage("We did not get the correct fee calculated. " + (e2.missing != null ? e2.missing.toFriendlyString() : ""));
}
}
if (sendResult != null) {
log.info("Broadcasting double spending transaction. " + sendResult.tx);
Futures.addCallback(sendResult.broadcastComplete, new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction result) {
log.info("Double spending transaction published. " + result);
resultHandler.run();
}
@Override
public void onFailure(@NotNull Throwable t) {
log.error("Broadcasting double spending transaction failed. " + t.getMessage());
errorMessageHandler.handleErrorMessage(t.getMessage());
}
});
}
} catch (InsufficientMoneyException e) {
throw new InsufficientFundsException("The fees for that transaction exceed the available funds " + "or the resulting output value is below the min. dust value:\n" + "Missing " + (e.missing != null ? e.missing.toFriendlyString() : "null"));
}
} else {
String errorMessage = "We could not find inputs we control in the transaction we want to double spend.";
log.warn(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
}
} 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.");
}
}
}
use of com.google.common.util.concurrent.FutureCallback in project bisq-core by bisq-network.
the class WalletConfig method startUp.
@Override
protected void startUp() throws Exception {
// Runs in a separate thread.
Context.propagate(context);
if (!directory.exists()) {
if (!directory.mkdirs()) {
throw new IOException("Could not create directory " + directory.getAbsolutePath());
}
}
log.info("Wallet directory: {}", directory);
try {
File chainFile = new File(directory, spvChainFileName);
boolean chainFileExists = chainFile.exists();
// BTC wallet
vBtcWalletFile = new File(directory, btcWalletFileName);
boolean shouldReplayWallet = (vBtcWalletFile.exists() && !chainFileExists) || seed != null;
BisqKeyChainGroup keyChainGroup;
if (seed != null)
keyChainGroup = new BisqKeyChainGroup(params, new BtcDeterministicKeyChain(seed), true);
else
keyChainGroup = new BisqKeyChainGroup(params, true);
vBtcWallet = createOrLoadWallet(vBtcWalletFile, shouldReplayWallet, keyChainGroup, false, seed);
vBtcWallet.allowSpendingUnconfirmedTransactions();
if (seed != null)
keyChainGroup = new BisqKeyChainGroup(params, new BisqDeterministicKeyChain(seed), false);
else
keyChainGroup = new BisqKeyChainGroup(params, new BisqDeterministicKeyChain(vBtcWallet.getKeyChainSeed()), false);
// BSQ wallet
if (BisqEnvironment.isBaseCurrencySupportingBsq()) {
vBsqWalletFile = new File(directory, bsqWalletFileName);
vBsqWallet = createOrLoadWallet(vBsqWalletFile, shouldReplayWallet, keyChainGroup, true, seed);
}
// Initiate Bitcoin network objects (block store, blockchain and peer group)
vStore = provideBlockStore(chainFile);
if (!chainFileExists || seed != null) {
if (checkpoints != null) {
// Initialize the chain file with a checkpoint to speed up first-run sync.
long time;
if (seed != null) {
// we created both wallets at the same time
time = seed.getCreationTimeSeconds();
if (chainFileExists) {
log.info("Deleting the chain file in preparation from restore.");
vStore.close();
if (!chainFile.delete())
throw new IOException("Failed to delete chain file in preparation for restore.");
vStore = new SPVBlockStore(params, chainFile);
}
} else {
time = vBtcWallet.getEarliestKeyCreationTime();
}
if (time > 0)
CheckpointManager.checkpoint(params, checkpoints, vStore, time);
else
log.warn("Creating a new uncheckpointed block store due to a wallet with a creation time of zero: this will result in a very slow chain sync");
} else if (chainFileExists) {
log.info("Deleting the chain file in preparation from restore.");
vStore.close();
if (!chainFile.delete())
throw new IOException("Failed to delete chain file in preparation for restore.");
vStore = new SPVBlockStore(params, chainFile);
}
}
vChain = new BlockChain(params, vStore);
vPeerGroup = createPeerGroup();
vPeerGroup.setBroadcastToAllPeers(true);
if (minBroadcastConnections > 0)
vPeerGroup.setMinBroadcastConnections(minBroadcastConnections);
vPeerGroup.setUserAgent(userAgent, Version.VERSION);
// before we're actually connected the broadcast waits for an appropriate number of connections.
if (peerAddresses != null) {
for (PeerAddress addr : peerAddresses) vPeerGroup.addAddress(addr);
log.info("We try to connect to {} btc nodes", numConnectionForBtc);
vPeerGroup.setMaxConnections(Math.min(numConnectionForBtc, peerAddresses.length));
peerAddresses = null;
} else if (!params.equals(RegTestParams.get())) {
vPeerGroup.addPeerDiscovery(discovery != null ? discovery : new DnsDiscovery(params));
}
vChain.addWallet(vBtcWallet);
vPeerGroup.addWallet(vBtcWallet);
if (vBsqWallet != null) {
// noinspection ConstantConditions
vChain.addWallet(vBsqWallet);
// noinspection ConstantConditions
vPeerGroup.addWallet(vBsqWallet);
}
onSetupCompleted();
if (blockingStartup) {
vPeerGroup.start();
// Make sure we shut down cleanly.
installShutdownHook();
final DownloadProgressTracker listener = new DownloadProgressTracker();
vPeerGroup.startBlockChainDownload(listener);
listener.await();
} else {
Futures.addCallback(vPeerGroup.startAsync(), new FutureCallback() {
@Override
public void onSuccess(@Nullable Object result) {
final PeerDataEventListener listener = downloadListener == null ? new DownloadProgressTracker() : downloadListener;
vPeerGroup.startBlockChainDownload(listener);
}
@Override
public void onFailure(@NotNull Throwable t) {
throw new RuntimeException(t);
}
});
}
} catch (BlockStoreException e) {
throw new IOException(e);
}
}
use of com.google.common.util.concurrent.FutureCallback in project bisq-core by bisq-network.
the class CreateMakerFeeTx method run.
@Override
protected void run() {
Offer offer = model.getOffer();
try {
runInterceptHook();
String id = offer.getId();
BtcWalletService walletService = model.getWalletService();
NodeAddress selectedArbitratorNodeAddress = ArbitratorSelectionRule.select(model.getUser().getAcceptedArbitratorAddresses(), model.getOffer());
log.debug("selectedArbitratorAddress " + selectedArbitratorNodeAddress);
Arbitrator selectedArbitrator = model.getUser().getAcceptedArbitratorByAddress(selectedArbitratorNodeAddress);
checkNotNull(selectedArbitrator, "selectedArbitrator must not be null at CreateOfferFeeTx");
Address fundingAddress = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.OFFER_FUNDING).getAddress();
Address reservedForTradeAddress = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.RESERVED_FOR_TRADE).getAddress();
Address changeAddress = walletService.getOrCreateAddressEntry(AddressEntry.Context.AVAILABLE).getAddress();
final TradeWalletService tradeWalletService = model.getTradeWalletService();
if (offer.isCurrencyForMakerFeeBtc()) {
tradeFeeTx = tradeWalletService.createBtcTradingFeeTx(fundingAddress, reservedForTradeAddress, changeAddress, model.getReservedFundsForOffer(), model.isUseSavingsWallet(), offer.getMakerFee(), offer.getTxFee(), selectedArbitrator.getBtcAddress(), new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
// we delay one render frame to be sure we don't get called before the method call has
// returned (tradeFeeTx would be null in that case)
UserThread.execute(() -> {
if (!completed) {
offer.setOfferFeePaymentTxId(transaction.getHashAsString());
model.setTransaction(transaction);
walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
model.getOffer().setState(Offer.State.OFFER_FEE_PAID);
complete();
} else {
log.warn("We got the onSuccess callback called after the timeout has been triggered a complete().");
}
});
}
@Override
public void onFailure(@NotNull Throwable t) {
if (!completed) {
failed(t);
} else {
log.warn("We got the onFailure callback called after the timeout has been triggered a complete().");
}
}
});
} else {
final BsqWalletService bsqWalletService = model.getBsqWalletService();
Transaction preparedBurnFeeTx = model.getBsqWalletService().getPreparedBurnFeeTx(offer.getMakerFee());
Transaction txWithBsqFee = tradeWalletService.completeBsqTradingFeeTx(preparedBurnFeeTx, fundingAddress, reservedForTradeAddress, changeAddress, model.getReservedFundsForOffer(), model.isUseSavingsWallet(), offer.getTxFee());
Transaction signedTx = model.getBsqWalletService().signTx(txWithBsqFee);
WalletService.checkAllScriptSignaturesForTx(signedTx);
bsqWalletService.commitTx(signedTx);
// We need to create another instance, otherwise the tx would trigger an invalid state exception
// if it gets committed 2 times
tradeWalletService.commitTx(tradeWalletService.getClonedTransaction(signedTx));
bsqWalletService.broadcastTx(signedTx, new FutureCallback<Transaction>() {
@Override
public void onSuccess(@Nullable Transaction transaction) {
if (transaction != null) {
offer.setOfferFeePaymentTxId(transaction.getHashAsString());
model.setTransaction(transaction);
log.debug("onSuccess, offerId={}, OFFER_FUNDING", id);
walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
log.debug("Successfully sent tx with id " + transaction.getHashAsString());
model.getOffer().setState(Offer.State.OFFER_FEE_PAID);
complete();
}
}
@Override
public void onFailure(@NotNull Throwable t) {
log.error(t.toString());
t.printStackTrace();
offer.setErrorMessage("An error occurred.\n" + "Error message:\n" + t.getMessage());
failed(t);
}
});
}
} catch (Throwable t) {
offer.setErrorMessage("An error occurred.\n" + "Error message:\n" + t.getMessage());
failed(t);
}
}
use of com.google.common.util.concurrent.FutureCallback in project openflowplugin by opendaylight.
the class HandshakeListenerImpl method addBarrierCallback.
private FutureCallback<RpcResult<BarrierOutput>> addBarrierCallback() {
return new FutureCallback<RpcResult<BarrierOutput>>() {
@Override
@SuppressWarnings("checkstyle:IllegalCatch")
public void onSuccess(@Nullable final RpcResult<BarrierOutput> result) {
if (LOG.isDebugEnabled()) {
LOG.debug("succeeded by getting sweep barrier after post-handshake for device {}", connectionContext.getDeviceInfo());
}
try {
ConnectionStatus connectionStatusResult = deviceConnectedHandler.deviceConnected(connectionContext);
if (connectionStatusResult != ConnectionStatus.MAY_CONTINUE) {
connectionContext.closeConnection(false);
}
SessionStatistics.countEvent(connectionContext.getDeviceInfo().toString(), SessionStatistics.ConnectionStatus.CONNECTION_CREATED);
} catch (final Exception e) {
LOG.warn("initial processing failed for device {}", connectionContext.getDeviceInfo(), e);
SessionStatistics.countEvent(connectionContext.getDeviceInfo().toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP);
connectionContext.closeConnection(true);
}
}
@Override
public void onFailure(final Throwable throwable) {
LOG.warn("failed to get sweep barrier after post-handshake for device {}", connectionContext.getDeviceInfo(), throwable);
connectionContext.closeConnection(false);
}
};
}
Aggregations