use of bisq.core.dao.state.blockchain.TempTxOutput in project bisq-core by bisq-network.
the class TxParser method getTxTypeForOpReturn.
private static TxType getTxTypeForOpReturn(TempTx tx, OpReturnType opReturnType) {
switch(opReturnType) {
case COMPENSATION_REQUEST:
boolean hasCorrectNumOutputs = tx.getTempTxOutputs().size() >= 3;
if (!hasCorrectNumOutputs) {
log.warn("Compensation request tx need to have at least 3 outputs");
return TxType.INVALID;
}
TempTxOutput issuanceTxOutput = tx.getTempTxOutputs().get(1);
boolean hasIssuanceOutput = issuanceTxOutput.getTxOutputType() == TxOutputType.ISSUANCE_CANDIDATE_OUTPUT;
if (!hasIssuanceOutput) {
log.warn("Compensation request txOutput type of output at index 1 need to be ISSUANCE_CANDIDATE_OUTPUT. " + "TxOutputType={}", issuanceTxOutput.getTxOutputType());
return TxType.INVALID;
}
return TxType.COMPENSATION_REQUEST;
case PROPOSAL:
return TxType.PROPOSAL;
case BLIND_VOTE:
return TxType.BLIND_VOTE;
case VOTE_REVEAL:
return TxType.VOTE_REVEAL;
case LOCKUP:
return TxType.LOCKUP;
default:
log.warn("We got a BSQ tx with fee and unknown OP_RETURN. tx={}", tx);
return TxType.INVALID;
}
}
use of bisq.core.dao.state.blockchain.TempTxOutput in project bisq-core by bisq-network.
the class TxParser method findGenesisTx.
/**
* Parse and return the genesis transaction for bisq, if applicable.
*
* @param genesisTxId The transaction id of the bisq genesis transaction.
* @param genesisBlockHeight The block height of the bisq genesis transaction.
* @param genesisTotalSupply The total supply of the genesis issuance for bisq.
* @param rawTx The candidate transaction.
* @return The genesis transaction if applicable, or Optional.empty() otherwise.
*/
public static Optional<TempTx> findGenesisTx(String genesisTxId, int genesisBlockHeight, Coin genesisTotalSupply, RawTx rawTx) {
boolean isGenesis = rawTx.getBlockHeight() == genesisBlockHeight && rawTx.getId().equals(genesisTxId);
if (!isGenesis)
return Optional.empty();
TempTx tempTx = TempTx.fromRawTx(rawTx);
tempTx.setTxType(TxType.GENESIS);
long remainingInputValue = genesisTotalSupply.getValue();
for (int i = 0; i < tempTx.getTempTxOutputs().size(); ++i) {
TempTxOutput txOutput = tempTx.getTempTxOutputs().get(i);
long value = txOutput.getValue();
boolean isValid = value <= remainingInputValue;
if (!isValid)
throw new InvalidGenesisTxException("Genesis tx is invalid; using more than available inputs. " + "Remaining input value is " + remainingInputValue + " sat; tx info: " + tempTx.toString());
remainingInputValue -= value;
txOutput.setTxOutputType(TxOutputType.GENESIS_OUTPUT);
}
if (remainingInputValue > 0) {
throw new InvalidGenesisTxException("Genesis tx is invalid; not using all available inputs. " + "Remaining input value is " + remainingInputValue + " sat, tx info: " + tempTx.toString());
}
return Optional.of(tempTx);
}
use of bisq.core.dao.state.blockchain.TempTxOutput in project bisq-core by bisq-network.
the class TxOutputParser method processGenesisTxOutput.
public void processGenesisTxOutput(TempTx genesisTx) {
for (int i = 0; i < genesisTx.getTempTxOutputs().size(); ++i) {
TempTxOutput tempTxOutput = genesisTx.getTempTxOutputs().get(i);
bsqStateService.addUnspentTxOutput(TxOutput.fromTempOutput(tempTxOutput));
}
}
use of bisq.core.dao.state.blockchain.TempTxOutput in project bisq-core by bisq-network.
the class TxOutputParser method handleOpReturnOutput.
private void handleOpReturnOutput(TempTxOutput tempTxOutput, boolean isLastOutput) {
TxOutputType txOutputType = OpReturnParser.getTxOutputType(tempTxOutput, isLastOutput);
tempTxOutput.setTxOutputType(txOutputType);
optionalVerifiedOpReturnType = getMappedOpReturnType(txOutputType);
optionalVerifiedOpReturnType.filter(verifiedOpReturnType -> verifiedOpReturnType == OpReturnType.LOCKUP).ifPresent(verifiedOpReturnType -> {
byte[] opReturnData = tempTxOutput.getOpReturnData();
checkNotNull(opReturnData, "opReturnData must not be null");
int lockTime = BondingConsensus.getLockTime(opReturnData);
tempTxOutput.setLockTime(lockTime);
});
}
use of bisq.core.dao.state.blockchain.TempTxOutput in project bisq-core by bisq-network.
the class TxParser method processOpReturnType.
private void processOpReturnType(int blockHeight, TempTx tempTx) {
// We might have a opReturn output
OpReturnType verifiedOpReturnType = null;
Optional<OpReturnType> optionalVerifiedOpReturnType = txOutputParser.getOptionalVerifiedOpReturnType();
if (optionalVerifiedOpReturnType.isPresent()) {
verifiedOpReturnType = optionalVerifiedOpReturnType.get();
long bsqFee = remainingInputValue;
boolean isFeeAndPhaseValid;
switch(verifiedOpReturnType) {
case PROPOSAL:
isFeeAndPhaseValid = isFeeAndPhaseValid(blockHeight, bsqFee, DaoPhase.Phase.PROPOSAL, Param.PROPOSAL_FEE);
if (!isFeeAndPhaseValid) {
tempTx.setTxType(TxType.INVALID);
}
break;
case COMPENSATION_REQUEST:
isFeeAndPhaseValid = isFeeAndPhaseValid(blockHeight, bsqFee, DaoPhase.Phase.PROPOSAL, Param.PROPOSAL_FEE);
Optional<TempTxOutput> optionalIssuanceCandidate = txOutputParser.getOptionalIssuanceCandidate();
if (isFeeAndPhaseValid) {
if (optionalIssuanceCandidate.isPresent()) {
// Now after we have validated the opReturn data we will apply the TxOutputType
optionalIssuanceCandidate.get().setTxOutputType(TxOutputType.ISSUANCE_CANDIDATE_OUTPUT);
} else {
log.warn("It can be that we have a opReturn which is correct from its structure but the whole tx " + "in not valid as the issuanceCandidate in not there. " + "As the BSQ fee is set it must be either a buggy tx or an manually crafted invalid tx.");
}
} else {
tempTx.setTxType(TxType.INVALID);
optionalIssuanceCandidate.ifPresent(tempTxOutput -> tempTxOutput.setTxOutputType(TxOutputType.BTC_OUTPUT));
// Empty Optional case is a possible valid case where a random tx matches our opReturn rules but it is not a
// valid BSQ tx.
}
break;
case BLIND_VOTE:
isFeeAndPhaseValid = isFeeAndPhaseValid(blockHeight, bsqFee, DaoPhase.Phase.BLIND_VOTE, Param.BLIND_VOTE_FEE);
if (!isFeeAndPhaseValid) {
tempTx.setTxType(TxType.INVALID);
Optional<TempTxOutput> optionalBlindVoteLockStakeOutput = txOutputParser.getOptionalBlindVoteLockStakeOutput();
optionalBlindVoteLockStakeOutput.ifPresent(tempTxOutput -> tempTxOutput.setTxOutputType(TxOutputType.BTC_OUTPUT));
// Empty Optional case is a possible valid case where a random tx matches our opReturn rules but it is not a
// valid BSQ tx.
}
break;
case VOTE_REVEAL:
boolean isPhaseValid = isPhaseValid(blockHeight, DaoPhase.Phase.VOTE_REVEAL);
boolean isVoteRevealInputInValid = txInputParser.getVoteRevealInputState() != TxInputParser.VoteRevealInputState.VALID;
if (!isPhaseValid) {
tempTx.setTxType(TxType.INVALID);
}
if (!isPhaseValid || isVoteRevealInputInValid) {
Optional<TempTxOutput> optionalVoteRevealUnlockStakeOutput = txOutputParser.getOptionalVoteRevealUnlockStakeOutput();
optionalVoteRevealUnlockStakeOutput.ifPresent(tempTxOutput -> tempTxOutput.setTxOutputType(TxOutputType.BTC_OUTPUT));
// Empty Optional case is a possible valid case where a random tx matches our opReturn rules but it is not a
// valid BSQ tx.
}
break;
case LOCKUP:
// do nothing
break;
}
}
// set the output to a BTC output. We must not use if else cases here!
if (verifiedOpReturnType != OpReturnType.COMPENSATION_REQUEST) {
txOutputParser.getOptionalIssuanceCandidate().ifPresent(tempTxOutput -> tempTxOutput.setTxOutputType(TxOutputType.BTC_OUTPUT));
}
if (verifiedOpReturnType != OpReturnType.BLIND_VOTE) {
txOutputParser.getOptionalBlindVoteLockStakeOutput().ifPresent(tempTxOutput -> tempTxOutput.setTxOutputType(TxOutputType.BTC_OUTPUT));
}
if (verifiedOpReturnType != OpReturnType.VOTE_REVEAL) {
txOutputParser.getOptionalVoteRevealUnlockStakeOutput().ifPresent(tempTxOutput -> tempTxOutput.setTxOutputType(TxOutputType.BTC_OUTPUT));
}
if (verifiedOpReturnType != OpReturnType.LOCKUP) {
txOutputParser.getOptionalLockupOutput().ifPresent(tempTxOutput -> tempTxOutput.setTxOutputType(TxOutputType.BTC_OUTPUT));
}
}
Aggregations