use of bisq.core.dao.blockchain.vo.Tx in project bisq-core by bisq-network.
the class JsonBlockChainExporter method maybeExport.
public void maybeExport() {
if (dumpBlockchainData) {
ListenableFuture<Void> future = executor.submit(() -> {
final BsqBlockChain bsqBlockChainClone = readableBsqBlockChain.getClone();
for (Tx tx : bsqBlockChainClone.getTxMap().values()) {
String txId = tx.getId();
JsonTxType txType = tx.getTxType() != TxType.UNDEFINED_TX_TYPE ? JsonTxType.valueOf(tx.getTxType().name()) : null;
List<JsonTxOutput> outputs = new ArrayList<>();
tx.getOutputs().stream().forEach(txOutput -> {
final JsonTxOutput outputForJson = new JsonTxOutput(txId, txOutput.getIndex(), txOutput.isVerified() ? txOutput.getValue() : 0, !txOutput.isVerified() ? txOutput.getValue() : 0, txOutput.getBlockHeight(), txOutput.isVerified(), tx.getBurntFee(), txOutput.getAddress(), new JsonScriptPubKey(txOutput.getPubKeyScript()), txOutput.getSpentInfo() != null ? new JsonSpentInfo(txOutput.getSpentInfo()) : null, tx.getTime(), txType, txType != null ? txType.getDisplayString() : "", txOutput.getOpReturnData() != null ? Utils.HEX.encode(txOutput.getOpReturnData()) : null);
outputs.add(outputForJson);
txOutputFileManager.writeToDisc(Utilities.objectToJson(outputForJson), outputForJson.getId());
});
List<JsonTxInput> inputs = tx.getInputs().stream().map(txInput -> {
final TxOutput connectedTxOutput = txInput.getConnectedTxOutput();
return new JsonTxInput(txInput.getConnectedTxOutputIndex(), txInput.getConnectedTxOutputTxId(), connectedTxOutput != null ? connectedTxOutput.getValue() : 0, connectedTxOutput != null && connectedTxOutput.isVerified(), connectedTxOutput != null ? connectedTxOutput.getAddress() : null, tx.getTime());
}).collect(Collectors.toList());
final JsonTx jsonTx = new JsonTx(txId, tx.getBlockHeight(), tx.getBlockHash(), tx.getTime(), inputs, outputs, txType, txType != null ? txType.getDisplayString() : "", tx.getBurntFee());
txFileManager.writeToDisc(Utilities.objectToJson(jsonTx), txId);
}
bsqBlockChainFileManager.writeToDisc(Utilities.objectToJson(bsqBlockChainClone), "BsqBlockChain");
return null;
});
Futures.addCallback(future, new FutureCallback<Void>() {
public void onSuccess(Void ignore) {
log.trace("onSuccess");
}
public void onFailure(@NotNull Throwable throwable) {
log.error(throwable.toString());
throwable.printStackTrace();
}
});
}
}
use of bisq.core.dao.blockchain.vo.Tx in project bisq-core by bisq-network.
the class FullNodeParser method findBsqTxsInBlock.
// /////////////////////////////////////////////////////////////////////////////////////////
// Private
// /////////////////////////////////////////////////////////////////////////////////////////
private List<Tx> findBsqTxsInBlock(Block btcdBlock) throws BsqBlockchainException {
int blockHeight = btcdBlock.getHeight();
log.debug("Parse block at height={} ", blockHeight);
// Check if the new block is the same chain we have built on.
List<Tx> txList = new ArrayList<>();
// We use a list as we want to maintain sorting of tx intra-block dependency
List<Tx> bsqTxsInBlock = new ArrayList<>();
// We add all transactions to the block
long startTs = System.currentTimeMillis();
// We don't user foreach because scope for exception would not be in method body...
for (String txId : btcdBlock.getTx()) {
// TODO if we use requestFee move code to later point once we found our bsq txs, so we only request it for bsq txs
if (requestFee)
rpcService.requestFees(txId, blockHeight, feesByBlock);
final Tx tx = rpcService.requestTx(txId, blockHeight);
txList.add(tx);
checkForGenesisTx(blockHeight, bsqTxsInBlock, tx);
}
log.debug("Requesting {} transactions took {} ms", btcdBlock.getTx().size(), System.currentTimeMillis() - startTs);
// Worst case is that all txs in a block are depending on another, so only one get resolved at each iteration.
// Min tx size is 189 bytes (normally about 240 bytes), 1 MB can contain max. about 5300 txs (usually 2000).
// Realistically we don't expect more then a few recursive calls.
// There are some blocks with testing such dependency chains like block 130768 where at each iteration only
// one get resolved.
// Lately there is a patter with 24 iterations observed
recursiveFindBsqTxs(bsqTxsInBlock, txList, blockHeight, 0, 5300);
return bsqTxsInBlock;
}
use of bisq.core.dao.blockchain.vo.Tx in project bisq-core by bisq-network.
the class FullNodeParser method parseBlock.
BsqBlock parseBlock(Block btcdBlock) throws BsqBlockchainException, BlockNotConnectingException {
long startTs = System.currentTimeMillis();
List<Tx> bsqTxsInBlock = findBsqTxsInBlock(btcdBlock);
final BsqBlock bsqBlock = new BsqBlock(btcdBlock.getHeight(), btcdBlock.getTime(), btcdBlock.getHash(), btcdBlock.getPreviousBlockHash(), ImmutableList.copyOf(bsqTxsInBlock));
bsqBlockController.addBlockIfValid(bsqBlock);
log.debug("parseBlock took {} ms at blockHeight {}; bsqTxsInBlock.size={}", System.currentTimeMillis() - startTs, bsqBlock.getHeight(), bsqTxsInBlock.size());
return bsqBlock;
}
use of bisq.core.dao.blockchain.vo.Tx in project bisq-core by bisq-network.
the class RpcService method requestTx.
public Tx requestTx(String txId, int blockHeight) throws BsqBlockchainException {
try {
RawTransaction rawTransaction = requestRawTransaction(txId);
// rawTransaction.getTime() is in seconds but we keep it in ms internally
final long time = rawTransaction.getTime() * 1000;
final List<TxInput> txInputs = rawTransaction.getVIn().stream().filter(rawInput -> rawInput != null && rawInput.getVOut() != null && rawInput.getTxId() != null).map(rawInput -> new TxInput(rawInput.getTxId(), rawInput.getVOut())).collect(Collectors.toList());
final List<TxOutput> txOutputs = rawTransaction.getVOut().stream().filter(e -> e != null && e.getN() != null && e.getValue() != null && e.getScriptPubKey() != null).map(rawOutput -> {
byte[] opReturnData = null;
final com.neemre.btcdcli4j.core.domain.PubKeyScript scriptPubKey = rawOutput.getScriptPubKey();
if (scriptPubKey.getType().equals(ScriptTypes.NULL_DATA)) {
String[] chunks = scriptPubKey.getAsm().split(" ");
// We get on testnet a lot of "OP_RETURN 0" data, so we filter those away
if (chunks.length == 2 && chunks[0].equals("OP_RETURN") && !"0".equals(chunks[1])) {
try {
opReturnData = Utils.HEX.decode(chunks[1]);
} catch (Throwable t) {
// We get sometimes exceptions, seems BitcoinJ
// cannot handle all existing OP_RETURN data, but we ignore them
// anyway as our OP_RETURN data is valid in BitcoinJ
log.warn("Error at Utils.HEX.decode(chunks[1]): " + t.toString() + " / chunks[1]=" + chunks[1]);
}
}
}
// We don't support raw MS which are the only case where scriptPubKey.getAddresses()>1
String address = scriptPubKey.getAddresses() != null && scriptPubKey.getAddresses().size() == 1 ? scriptPubKey.getAddresses().get(0) : null;
final PubKeyScript pubKeyScript = dumpBlockchainData ? new PubKeyScript(scriptPubKey) : null;
return new TxOutput(rawOutput.getN(), rawOutput.getValue().movePointRight(8).longValue(), rawTransaction.getTxId(), pubKeyScript, address, opReturnData, blockHeight);
}).collect(Collectors.toList());
return new Tx(txId, blockHeight, rawTransaction.getBlockHash(), time, ImmutableList.copyOf(txInputs), ImmutableList.copyOf(txOutputs));
} catch (BitcoindException | CommunicationException e) {
log.error("error at requestTx with txId={}, blockHeight={}", txId, blockHeight);
throw new BsqBlockchainException(e.getMessage(), e);
}
}
use of bisq.core.dao.blockchain.vo.Tx in project bisq-desktop by bisq-network.
the class ProposalListItem method setupConfidence.
private void setupConfidence() {
final Tx tx = readableBsqBlockChain.getTxMap().get(proposal.getProposalPayload().getTxId());
if (tx != null) {
final String txId = tx.getId();
// We cache the walletTransaction once found
if (walletTransaction == null) {
final Optional<Transaction> transactionOptional = bsqWalletService.isWalletTransaction(txId);
transactionOptional.ifPresent(transaction -> walletTransaction = transaction);
}
if (walletTransaction != null) {
// It is our tx so we get confidence updates
if (txConfidenceListener == null) {
txConfidenceListener = new TxConfidenceListener(txId) {
@Override
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
updateConfidence(confidence.getConfidenceType(), confidence.getDepthInBlocks(), confidence.numBroadcastPeers());
}
};
bsqWalletService.addTxConfidenceListener(txConfidenceListener);
}
} else {
// tx from other users, we dont get confidence updates but as we have the bsq tx we can calculate it
// we get setupConfidence called at each new block from above listener so no need to register a new listener
int depth = bsqWalletService.getChainHeightProperty().get() - tx.getBlockHeight() + 1;
if (depth > 0)
updateConfidence(TransactionConfidence.ConfidenceType.BUILDING, depth, -1);
// log.error("name={}, id ={}, depth={}", compensationRequest.getPayload().getName(), compensationRequest.getPayload().getUid(), depth);
}
final TransactionConfidence confidence = bsqWalletService.getConfidenceForTxId(txId);
if (confidence != null)
updateConfidence(confidence, confidence.getDepthInBlocks());
}
}
Aggregations