use of bisq.core.dao.state.blockchain.TxOutput in project bisq-core by bisq-network.
the class BsqWalletService method getValueSentToMeForTransaction.
@Override
public Coin getValueSentToMeForTransaction(Transaction transaction) throws ScriptException {
Coin result = Coin.ZERO;
final String txId = transaction.getHashAsString();
// We check if we have a matching BSQ tx. We do that call here to avoid repeated calls in the loop.
Optional<Tx> txOptional = bsqStateService.getTx(txId);
// We check all the outputs of our tx
for (int i = 0; i < transaction.getOutputs().size(); i++) {
TransactionOutput output = transaction.getOutputs().get(i);
final boolean isConfirmed = output.getParentTransaction() != null && output.getParentTransaction().getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING;
if (output.isMineOrWatched(wallet)) {
if (isConfirmed) {
if (txOptional.isPresent()) {
// The index of the BSQ tx outputs are the same like the bitcoinj tx outputs
TxOutput txOutput = txOptional.get().getTxOutputs().get(i);
if (bsqStateService.isBsqTxOutputType(txOutput)) {
// TODO check why values are not the same
if (txOutput.getValue() != output.getValue().value) {
log.warn("getValueSentToMeForTransaction: Value of BSQ output do not match BitcoinJ tx output. " + "txOutput.getValue()={}, output.getValue().value={}, txId={}", txOutput.getValue(), output.getValue().value, txId);
}
// If it is a valid BSQ output we add it
result = result.add(Coin.valueOf(txOutput.getValue()));
}
}
}
/*else {
// TODO atm we don't display amounts of unconfirmed txs but that might change so we leave that code
// if it will be required
// If the tx is not confirmed yet we add the value and assume it is a valid BSQ output.
result = result.add(output.getValue());
}*/
}
}
return result;
}
use of bisq.core.dao.state.blockchain.TxOutput in project bisq-core by bisq-network.
the class JsonBlockChainExporter method maybeExport.
public void maybeExport() {
if (dumpBlockchainData) {
ListenableFuture<Void> future = executor.submit(() -> {
final BsqState bsqStateClone = bsqStateService.getClone();
Map<String, Tx> txMap = bsqStateService.getBlocksFromState(bsqStateClone).stream().filter(Objects::nonNull).flatMap(block -> block.getTxs().stream()).collect(Collectors.toMap(Tx::getId, tx -> tx));
for (Tx tx : txMap.values()) {
String txId = tx.getId();
final Optional<TxType> optionalTxType = bsqStateService.getOptionalTxType(txId);
optionalTxType.ifPresent(txType1 -> {
JsonTxType txType = txType1 != TxType.UNDEFINED_TX_TYPE ? JsonTxType.valueOf(txType1.name()) : null;
List<JsonTxOutput> outputs = new ArrayList<>();
tx.getTxOutputs().forEach(txOutput -> {
final Optional<SpentInfo> optionalSpentInfo = bsqStateService.getSpentInfo(txOutput);
final boolean isBsqOutput = bsqStateService.isBsqTxOutputType(txOutput);
final PubKeyScript pubKeyScript = txOutput.getPubKeyScript();
final JsonTxOutput outputForJson = new JsonTxOutput(txId, txOutput.getIndex(), isBsqOutput ? txOutput.getValue() : 0, !isBsqOutput ? txOutput.getValue() : 0, txOutput.getBlockHeight(), isBsqOutput, bsqStateService.getBurntFee(tx.getId()), txOutput.getAddress(), pubKeyScript != null ? new JsonScriptPubKey(pubKeyScript) : null, optionalSpentInfo.map(JsonSpentInfo::new).orElse(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.getTxInputs().stream().map(txInput -> {
Optional<TxOutput> optionalTxOutput = bsqStateService.getConnectedTxOutput(txInput);
if (optionalTxOutput.isPresent()) {
final TxOutput connectedTxOutput = optionalTxOutput.get();
final boolean isBsqOutput = bsqStateService.isBsqTxOutputType(connectedTxOutput);
return new JsonTxInput(txInput.getConnectedTxOutputIndex(), txInput.getConnectedTxOutputTxId(), connectedTxOutput.getValue(), isBsqOutput, connectedTxOutput.getAddress(), tx.getTime());
} else {
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toList());
final JsonTx jsonTx = new JsonTx(txId, tx.getBlockHeight(), tx.getBlockHash(), tx.getTime(), inputs, outputs, txType, txType != null ? txType.getDisplayString() : "", bsqStateService.getBurntFee(tx.getId()));
txFileManager.writeToDisc(Utilities.objectToJson(jsonTx), txId);
});
}
jsonFileManager.writeToDisc(Utilities.objectToJson(bsqStateClone), "BsqStateService");
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.state.blockchain.TxOutput in project bisq-core by bisq-network.
the class IssuanceService method issueBsq.
public void issueBsq(CompensationProposal compensationProposal, int chainHeight) {
bsqStateService.getIssuanceCandidateTxOutputs().stream().filter(txOutput -> isValid(txOutput, compensationProposal, periodService, chainHeight)).forEach(txOutput -> {
// We don't check atm if the output is unspent. We cannot use the bsqWallet as that would not
// reflect our current block state (could have been spent at later block which is valid and
// bsqWallet would show that spent state). We would need to support a spent status for the outputs
// which are interpreted as BTC (as a not yet accepted comp. request).
Optional<Tx> optionalTx = bsqStateService.getTx(compensationProposal.getTxId());
if (optionalTx.isPresent()) {
long amount = compensationProposal.getRequestedBsq().value;
Tx tx = optionalTx.get();
// We use key from first input
TxInput txInput = tx.getTxInputs().get(0);
String pubKey = txInput.getPubKey();
Issuance issuance = new Issuance(tx.getId(), chainHeight, amount, pubKey);
bsqStateService.addIssuance(issuance);
bsqStateService.addUnspentTxOutput(txOutput);
StringBuilder sb = new StringBuilder();
sb.append("\n################################################################################\n");
sb.append("We issued new BSQ to tx with ID ").append(txOutput.getTxId()).append("\nfor compensationProposal with UID ").append(compensationProposal.getTxId()).append("\n################################################################################\n");
log.info(sb.toString());
} else {
// TODO throw exception
log.error("Tx for compensation request not found. txId={}", compensationProposal.getTxId());
}
});
}
use of bisq.core.dao.state.blockchain.TxOutput in project bisq-core by bisq-network.
the class UnlockService method publishUnlockTx.
public void publishUnlockTx(String lockupTxId, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
try {
TxOutput lockupTxOutput = bsqStateService.getLockupTxOutput(lockupTxId).get();
final Transaction unlockTx = getUnlockTx(lockupTxOutput);
// noinspection Duplicates
walletsManager.publishAndCommitBsqTx(unlockTx, new TxBroadcaster.Callback() {
@Override
public void onSuccess(Transaction transaction) {
resultHandler.handleResult();
}
@Override
public void onTxMalleability(TxMalleabilityException exception) {
exceptionHandler.handleException(exception);
}
@Override
public void onFailure(TxBroadcastException exception) {
exceptionHandler.handleException(exception);
}
});
} catch (TransactionVerificationException | InsufficientMoneyException | WalletException exception) {
exceptionHandler.handleException(exception);
}
}
use of bisq.core.dao.state.blockchain.TxOutput in project bisq-core by bisq-network.
the class VoteRevealService method revealVote.
private void revealVote(MyVote myVote, int chainHeight) throws IOException, WalletException, InsufficientMoneyException, TransactionVerificationException, VoteRevealException {
// We collect all valid blind vote items we received via the p2p network.
// It might be that different nodes have a different collection of those items.
// To ensure we get a consensus of the data for later calculating the result we will put a hash of each
// voters blind vote collection into the opReturn data and check for a majority at issuance time.
// The voters "vote" with their stake at the reveal tx for their version of the blind vote collection.
// TODO make more clear by using param like here:
/* List<BlindVote> blindVotes = BlindVoteConsensus.getSortedBlindVoteListOfCycle(blindVoteListService);
VoteRevealConsensus.getHashOfBlindVoteList(blindVotes);*/
byte[] hashOfBlindVoteList = getHashOfBlindVoteList();
log.info("Sha256Ripemd160 hash of hashOfBlindVoteList " + Utilities.bytesAsHexString(hashOfBlindVoteList));
byte[] opReturnData = VoteRevealConsensus.getOpReturnData(hashOfBlindVoteList, myVote.getSecretKey());
// We search for my unspent stake output.
// myVote is already tested if it is in current cycle at maybeRevealVotes
// We expect that the blind vote tx and stake output is available. If not we throw an exception.
TxOutput stakeTxOutput = bsqStateService.getUnspentBlindVoteStakeTxOutputs().stream().filter(txOutput -> txOutput.getTxId().equals(myVote.getTxId())).findFirst().orElseThrow(() -> new VoteRevealException("stakeTxOutput is not found for myVote.", myVote));
// TODO is phase check needed and done in parser still?
if (periodService.isTxInCorrectCycle(stakeTxOutput.getTxId(), chainHeight)) {
Transaction voteRevealTx = getVoteRevealTx(stakeTxOutput, opReturnData);
log.info("voteRevealTx={}", voteRevealTx);
publishTx(voteRevealTx);
// TODO add comment...
// We don't want to wait for a successful broadcast to avoid issues if the broadcast succeeds delayed or at
// next startup but the tx was actually broadcasted.
myVoteListService.applyRevealTxId(myVote, voteRevealTx.getHashAsString());
// Just for additional resilience we republish our blind votes
final List<BlindVote> sortedBlindVoteListOfCycle = BlindVoteConsensus.getSortedBlindVoteListOfCycle(blindVoteListService);
rePublishBlindVotePayloadList(sortedBlindVoteListOfCycle);
} else {
final String msg = "Tx of stake out put is not in our cycle. That must not happen.";
log.error("{}. chainHeight={}, blindVoteTxId()={}", msg, chainHeight, myVote.getTxId());
voteRevealExceptions.add(new VoteRevealException(msg, stakeTxOutput.getTxId()));
}
}
Aggregations