use of org.bitcoinj.core.Address in project catena-java by alinush.
the class CatenaClient method beforeBlockChainDownload.
/**
* Sets up the wallet for the Catena client and reads back previous statements if the wallet was restarted.
*/
private void beforeBlockChainDownload() {
wallet = getCatenaWallet();
ext = wallet.getCatenaExtension();
CatenaWalletListener listener = new CatenaWalletListener(wallet);
List<Address> watchedAddrs = wallet().getWatchedAddresses();
// should've been given a txid in the constructor.
if (watchedAddrs.isEmpty()) {
wallet.setRebootingHint(false);
checkState(rootOfTrustTxid != null);
log.info("Starting new wallet with: " + "\n\ttxid=" + rootOfTrustTxid + ", \n\tchainAddr=" + expectedChainAddr);
// Here we Bloom filter for the root-of-trust TXID but because bitcoinj is limited and cannot redownload
// the chain after it matched this TXN, we have to also specify the chain address here to make sure we don't
// miss relevant blocks and TXs.
peerGroup().addPeerFilterProvider(new TxidBloomFilterProvider(rootOfTrustTxid));
wallet.addWatchedAddress(expectedChainAddr);
ext.setRootOfTrustTxid(rootOfTrustTxid);
// NOTE: Cannot set name of chain here because don't have the root-of-trust TX with the name yet
// Otherwise, we have the chain's address in our watched addresses list which means we can read back the
// root-of-trust txid saved in our CatenaWalletExtension.
} else {
wallet.setRebootingHint(true);
checkState(watchedAddrs.size() == 1);
Address chainAddr = watchedAddrs.get(0);
String chainName = null;
if (ext.hasName())
chainName = ext.getName();
rootOfTrustTxid = ext.getRootOfTrustTxid();
log.info("Restarting old wallet with: " + "\n\taddr=" + chainAddr + ", \n\ttxid=" + rootOfTrustTxid + ", \n\t" + (chainName != null ? "name=" + chainName : "no chain name yet") + ", \n\tnumtxns=" + wallet.getTransactions(false).size());
// Call onWalletChanged() here to process Catena TXs and initialize the chain
listener.onWalletChanged(wallet);
}
// We just want to hear about certain events when debugging!
wallet().addScriptChangeEventListener(Threading.SAME_THREAD, listener);
wallet().addCoinsReceivedEventListener(Threading.SAME_THREAD, listener);
wallet().addCoinsSentEventListener(Threading.SAME_THREAD, listener);
// We run these listeners in the same thread as the Wallet listeners because we are concerned with race
// conditions: as we handle an old fork, a new one can occur and we would be processing the old one with TX
// confidence data from the new fork, possibly putting landing us in an incorrect state.
wallet().addChangeEventListener(Threading.SAME_THREAD, listener);
wallet().addReorganizeEventListener(Threading.SAME_THREAD, listener);
// TODO: can get extra info about reorgs by using chain().addReorganizeListener()
// Wallet is succesfully reloaded with TX from previous invocation of
// CatenaClient (i.e., wallet survives restarts).
}
use of org.bitcoinj.core.Address in project catena-java by alinush.
the class ClientWallet method isTransactionRelevant.
/**
* The client will never process the root-of-trust TX because it does not
* have its PK added to the wallet, so the TX will seem irrelevant to the
* wallet. To prevent that, we override this method.
*
* This method also adds the PK in the root-of-trust TX to the list of
* watched addresses.
*/
@Override
public boolean isTransactionRelevant(Transaction tx) throws ScriptException {
lock.lock();
try {
CatenaWalletExtension ext = getCatenaExtension();
boolean isRelevant = super.isTransactionRelevant(tx);
boolean isRootOfTrustTx = false;
if (ext.hasRootOfTrustTxid()) {
isRootOfTrustTx = ext.getRootOfTrustTxid().equals(tx.getHash());
if (isRootOfTrustTx) {
// NOTE: We save this in the wallet extension later, for now we just display them.
Address chainAddr = tx.getOutput(0).getAddressFromP2PKHScript(params);
log.debug("Identified chain address from root-of-trust TX " + tx.getHashAsString() + ": " + chainAddr);
if (ext.hasName() == false) {
log.debug("Also, identified chain name from root-of-trust TX " + tx.getHashAsString() + ": " + new String(CatenaUtils.getCatenaTxData(tx)));
}
checkState(chainAddr != null, "No P2PKH address in the root-of-trust TX's first output");
// NOTE: By the time we add the Catena chain's PK to the wallet it could be too late because bitcoinj
// might've downloaded future blocks (i.e., blocks past the root-of-trust block) and ignored Catena
// TXs in those blocks since it didn't have this PK in its Bloom filter yet. For now, this code
// doesn't have any effect until bitcoinj will handle blockchain redownloads. That's why we also pass
// the chain address to the CatenaClient constructor.
// addWatchedAddresses(ImmutableList.<Address>of(chainAddr), 1);
}
} else {
// log.trace("Too early to match root-of-trust TXN because TXID is not yet set in wallet extension.");
}
return isRelevant || isRootOfTrustTx;
} finally {
lock.unlock();
}
}
use of org.bitcoinj.core.Address in project bisq-core by bisq-network.
the class SellerAsMakerCreatesAndSignsDepositTx method run.
@Override
protected void run() {
try {
runInterceptHook();
checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not be null");
BtcWalletService walletService = processModel.getBtcWalletService();
String id = processModel.getOffer().getId();
TradingPeer tradingPeer = processModel.getTradingPeer();
final Offer offer = trade.getOffer();
// params
final boolean makerIsBuyer = false;
final byte[] contractHash = Hash.getSha256Hash(trade.getContractAsJson());
trade.setContractHash(contractHash);
log.debug("\n\n------------------------------------------------------------\n" + "Contract as json\n" + trade.getContractAsJson() + "\n------------------------------------------------------------\n");
final Coin makerInputAmount = offer.getSellerSecurityDeposit().add(trade.getTradeAmount());
Optional<AddressEntry> addressEntryOptional = walletService.getAddressEntry(id, AddressEntry.Context.MULTI_SIG);
checkArgument(addressEntryOptional.isPresent(), "addressEntryOptional must be present");
AddressEntry makerMultiSigAddressEntry = addressEntryOptional.get();
makerMultiSigAddressEntry.setCoinLockedInMultiSig(makerInputAmount);
walletService.saveAddressEntryList();
final Coin msOutputAmount = makerInputAmount.add(trade.getTxFee()).add(offer.getBuyerSecurityDeposit());
final List<RawTransactionInput> takerRawTransactionInputs = tradingPeer.getRawTransactionInputs();
final long takerChangeOutputValue = tradingPeer.getChangeOutputValue();
final String takerChangeAddressString = tradingPeer.getChangeOutputAddress();
final Address makerAddress = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.RESERVED_FOR_TRADE).getAddress();
final Address makerChangeAddress = walletService.getOrCreateAddressEntry(AddressEntry.Context.AVAILABLE).getAddress();
final byte[] buyerPubKey = tradingPeer.getMultiSigPubKey();
final byte[] sellerPubKey = processModel.getMyMultiSigPubKey();
checkArgument(Arrays.equals(sellerPubKey, makerMultiSigAddressEntry.getPubKey()), "sellerPubKey from AddressEntry must match the one from the trade data. trade id =" + id);
final byte[] arbitratorBtcPubKey = trade.getArbitratorBtcPubKey();
PreparedDepositTxAndMakerInputs result = processModel.getTradeWalletService().makerCreatesAndSignsDepositTx(makerIsBuyer, contractHash, makerInputAmount, msOutputAmount, takerRawTransactionInputs, takerChangeOutputValue, takerChangeAddressString, makerAddress, makerChangeAddress, buyerPubKey, sellerPubKey, arbitratorBtcPubKey);
processModel.setPreparedDepositTx(result.depositTransaction);
processModel.setRawTransactionInputs(result.rawMakerInputs);
complete();
} catch (Throwable t) {
failed(t);
}
}
use of org.bitcoinj.core.Address in project bisq-core by bisq-network.
the class CreateTakerFeeTx method run.
@Override
protected void run() {
try {
runInterceptHook();
User user = processModel.getUser();
NodeAddress selectedArbitratorNodeAddress = ArbitratorSelectionRule.select(user.getAcceptedArbitratorAddresses(), processModel.getOffer());
log.debug("selectedArbitratorAddress " + selectedArbitratorNodeAddress);
Arbitrator selectedArbitrator = user.getAcceptedArbitratorByAddress(selectedArbitratorNodeAddress);
checkNotNull(selectedArbitrator, "selectedArbitrator must not be null at CreateTakeOfferFeeTx");
BtcWalletService walletService = processModel.getBtcWalletService();
String id = processModel.getOffer().getId();
AddressEntry addressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.OFFER_FUNDING);
AddressEntry reservedForTradeAddressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.RESERVED_FOR_TRADE);
AddressEntry changeAddressEntry = walletService.getOrCreateAddressEntry(AddressEntry.Context.AVAILABLE);
Address fundingAddress = addressEntry.getAddress();
Address reservedForTradeAddress = reservedForTradeAddressEntry.getAddress();
Address changeAddress = changeAddressEntry.getAddress();
final TradeWalletService tradeWalletService = processModel.getTradeWalletService();
if (trade.isCurrencyForTakerFeeBtc()) {
tradeFeeTx = tradeWalletService.createBtcTradingFeeTx(fundingAddress, reservedForTradeAddress, changeAddress, processModel.getFundsNeededForTradeAsLong(), processModel.isUseSavingsWallet(), trade.getTakerFee(), trade.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) {
processModel.setTakeOfferFeeTx(tradeFeeTx);
trade.setTakerFeeTxId(tradeFeeTx.getHashAsString());
walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
trade.setState(Trade.State.TAKER_PUBLISHED_TAKER_FEE_TX);
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 = processModel.getBsqWalletService();
Transaction preparedBurnFeeTx = processModel.getBsqWalletService().getPreparedBurnFeeTx(trade.getTakerFee());
Transaction txWithBsqFee = tradeWalletService.completeBsqTradingFeeTx(preparedBurnFeeTx, fundingAddress, reservedForTradeAddress, changeAddress, processModel.getFundsNeededForTradeAsLong(), processModel.isUseSavingsWallet(), trade.getTxFee());
Transaction signedTx = processModel.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 (!completed) {
if (transaction != null) {
log.debug("Successfully sent tx with id " + transaction.getHashAsString());
trade.setTakerFeeTxId(transaction.getHashAsString());
processModel.setTakeOfferFeeTx(transaction);
walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);
trade.setState(Trade.State.TAKER_PUBLISHED_TAKER_FEE_TX);
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) {
log.error(t.toString());
t.printStackTrace();
trade.setErrorMessage("An error occurred.\n" + "Error message:\n" + t.getMessage());
failed(t);
} else {
log.warn("We got the onFailure callback called after the timeout has been triggered a complete().");
}
}
});
}
} catch (Throwable t) {
failed(t);
}
}
use of org.bitcoinj.core.Address in project bisq-core by bisq-network.
the class BuyerSetupPayoutTxListener method run.
@Override
protected void run() {
try {
runInterceptHook();
if (!trade.isPayoutPublished()) {
BtcWalletService walletService = processModel.getBtcWalletService();
final String id = processModel.getOffer().getId();
Address address = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.TRADE_PAYOUT).getAddress();
final TransactionConfidence confidence = walletService.getConfidenceForAddress(address);
if (isInNetwork(confidence)) {
applyConfidence(confidence);
} else {
confidenceListener = new AddressConfidenceListener(address) {
@Override
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
if (isInNetwork(confidence))
applyConfidence(confidence);
}
};
walletService.addAddressConfidenceListener(confidenceListener);
tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), newValue -> {
if (trade.isPayoutPublished()) {
swapMultiSigEntry();
// hack to remove tradeStateSubscription at callback
UserThread.execute(this::unSubscribe);
}
});
}
}
// we complete immediately, our object stays alive because the balanceListener is stored in the WalletService
complete();
} catch (Throwable t) {
failed(t);
}
}
Aggregations