mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 15:00:30 +01:00
Check for multiple opReturns before processing txOutputs
This commit is contained in:
parent
f31bf0d5cf
commit
5dffe7159e
2 changed files with 26 additions and 19 deletions
|
@ -24,6 +24,7 @@ import bisq.core.dao.state.blockchain.TempTx;
|
||||||
import bisq.core.dao.state.blockchain.TempTxOutput;
|
import bisq.core.dao.state.blockchain.TempTxOutput;
|
||||||
import bisq.core.dao.state.blockchain.TxOutput;
|
import bisq.core.dao.state.blockchain.TxOutput;
|
||||||
import bisq.core.dao.state.blockchain.TxOutputType;
|
import bisq.core.dao.state.blockchain.TxOutputType;
|
||||||
|
import bisq.core.dao.state.blockchain.TxType;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
@ -105,7 +106,10 @@ public class TxOutputParser {
|
||||||
byte[] opReturnData = tempTxOutput.getOpReturnData();
|
byte[] opReturnData = tempTxOutput.getOpReturnData();
|
||||||
if (opReturnData == null) {
|
if (opReturnData == null) {
|
||||||
long txOutputValue = tempTxOutput.getValue();
|
long txOutputValue = tempTxOutput.getValue();
|
||||||
if (isUnlockBondTx(tempTxOutput.getValue(), index)) {
|
if (tempTx.getTxType() == TxType.INVALID) {
|
||||||
|
// Set all non opReturn outputs to BTC_OUTPUT if the tx is invalid
|
||||||
|
tempTxOutput.setTxOutputType(TxOutputType.BTC_OUTPUT);
|
||||||
|
} else if (isUnlockBondTx(tempTxOutput.getValue(), index)) {
|
||||||
// We need to handle UNLOCK transactions separately as they don't follow the pattern on spending BSQ
|
// We need to handle UNLOCK transactions separately as they don't follow the pattern on spending BSQ
|
||||||
// The LOCKUP BSQ is burnt unless the output exactly matches the input, that would cause the
|
// The LOCKUP BSQ is burnt unless the output exactly matches the input, that would cause the
|
||||||
// output to not be BSQ output at all
|
// output to not be BSQ output at all
|
||||||
|
|
|
@ -101,6 +101,15 @@ public class TxParser {
|
||||||
|
|
||||||
long accumulatedInputValue = txInputParser.getAccumulatedInputValue();
|
long accumulatedInputValue = txInputParser.getAccumulatedInputValue();
|
||||||
txOutputParser.setAvailableInputValue(accumulatedInputValue);
|
txOutputParser.setAvailableInputValue(accumulatedInputValue);
|
||||||
|
|
||||||
|
// We don't allow multiple opReturn outputs (they are non-standard but to be safe lets check it)
|
||||||
|
long numOpReturnOutputs = tempTx.getTempTxOutputs().stream().filter(txOutputParser::isOpReturnOutput).count();
|
||||||
|
if (numOpReturnOutputs > 1) {
|
||||||
|
tempTx.setTxType(TxType.INVALID);
|
||||||
|
String msg = "Invalid tx. We have multiple opReturn outputs. tx=" + tempTx;
|
||||||
|
log.warn(msg);
|
||||||
|
}
|
||||||
|
|
||||||
txOutputParser.setUnlockBlockHeight(txInputParser.getUnlockBlockHeight());
|
txOutputParser.setUnlockBlockHeight(txInputParser.getUnlockBlockHeight());
|
||||||
txOutputParser.setOptionalSpentLockupTxOutput(txInputParser.getOptionalSpentLockupTxOutput());
|
txOutputParser.setOptionalSpentLockupTxOutput(txInputParser.getOptionalSpentLockupTxOutput());
|
||||||
txOutputParser.setTempTx(tempTx); //TODO remove
|
txOutputParser.setTempTx(tempTx); //TODO remove
|
||||||
|
@ -134,11 +143,15 @@ public class TxParser {
|
||||||
|
|
||||||
remainingInputValue = txOutputParser.getAvailableInputValue();
|
remainingInputValue = txOutputParser.getAvailableInputValue();
|
||||||
|
|
||||||
|
// TODO(SQ): If the tx is set to INVALID in this check the txOutputs stay valid
|
||||||
processOpReturnType(blockHeight, tempTx);
|
processOpReturnType(blockHeight, tempTx);
|
||||||
|
|
||||||
// We don't allow multiple opReturn outputs (they are non-standard but to be safe lets check it)
|
// TODO(SQ): Should the destroyed BSQ from an INVALID tx be considered as burnt fee?
|
||||||
long numOpReturnOutputs = tempTx.getTempTxOutputs().stream().filter(txOutputParser::isOpReturnOutput).count();
|
if (remainingInputValue > 0)
|
||||||
if (numOpReturnOutputs <= 1) {
|
tempTx.setBurntFee(remainingInputValue);
|
||||||
|
|
||||||
|
// Process the type of transaction if not already determined to be INVALID
|
||||||
|
if (tempTx.getTxType() != TxType.INVALID) {
|
||||||
boolean isAnyTxOutputTypeUndefined = tempTx.getTempTxOutputs().stream()
|
boolean isAnyTxOutputTypeUndefined = tempTx.getTempTxOutputs().stream()
|
||||||
.anyMatch(txOutput -> TxOutputType.UNDEFINED == txOutput.getTxOutputType());
|
.anyMatch(txOutput -> TxOutputType.UNDEFINED == txOutput.getTxOutputType());
|
||||||
if (!isAnyTxOutputTypeUndefined) {
|
if (!isAnyTxOutputTypeUndefined) {
|
||||||
|
@ -151,21 +164,11 @@ public class TxParser {
|
||||||
getOptionalOpReturnType()
|
getOptionalOpReturnType()
|
||||||
);
|
);
|
||||||
tempTx.setTxType(txType);
|
tempTx.setTxType(txType);
|
||||||
if (remainingInputValue > 0)
|
|
||||||
tempTx.setBurntFee(remainingInputValue);
|
|
||||||
} else {
|
} else {
|
||||||
tempTx.setTxType(TxType.INVALID);
|
tempTx.setTxType(TxType.INVALID);
|
||||||
String msg = "We have undefined txOutput types which must not happen. tx=" + tempTx;
|
String msg = "We have undefined txOutput types which must not happen. tx=" + tempTx;
|
||||||
DevEnv.logErrorAndThrowIfDevMode(msg);
|
DevEnv.logErrorAndThrowIfDevMode(msg);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// TODO(SQ): The transaction has already been parsed here and the individual txouputs are considered
|
|
||||||
// spendable or otherwise correct. Perhaps this check should be done earlier.
|
|
||||||
|
|
||||||
// We don't consider a tx with multiple OpReturn outputs valid.
|
|
||||||
tempTx.setTxType(TxType.INVALID);
|
|
||||||
String msg = "Invalid tx. We have multiple opReturn outputs. tx=" + tempTx;
|
|
||||||
log.warn(msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,8 +263,8 @@ public class TxParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processCompensationRequest(int blockHeight, TempTx tempTx, long bsqFee) {
|
private void processCompensationRequest(int blockHeight, TempTx tempTx, long bsqFee) {
|
||||||
boolean isFeeAndPhaseValid;
|
boolean isFeeAndPhaseValid =
|
||||||
isFeeAndPhaseValid = isFeeAndPhaseValid(blockHeight, bsqFee, DaoPhase.Phase.PROPOSAL, Param.PROPOSAL_FEE);
|
isFeeAndPhaseValid(blockHeight, bsqFee, DaoPhase.Phase.PROPOSAL, Param.PROPOSAL_FEE);
|
||||||
Optional<TempTxOutput> optionalIssuanceCandidate = txOutputParser.getOptionalIssuanceCandidate();
|
Optional<TempTxOutput> optionalIssuanceCandidate = txOutputParser.getOptionalIssuanceCandidate();
|
||||||
if (isFeeAndPhaseValid) {
|
if (isFeeAndPhaseValid) {
|
||||||
if (optionalIssuanceCandidate.isPresent()) {
|
if (optionalIssuanceCandidate.isPresent()) {
|
||||||
|
@ -281,8 +284,8 @@ public class TxParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processProposal(int blockHeight, TempTx tempTx, long bsqFee) {
|
private void processProposal(int blockHeight, TempTx tempTx, long bsqFee) {
|
||||||
boolean isFeeAndPhaseValid;
|
boolean isFeeAndPhaseValid =
|
||||||
isFeeAndPhaseValid = isFeeAndPhaseValid(blockHeight, bsqFee, DaoPhase.Phase.PROPOSAL, Param.PROPOSAL_FEE);
|
isFeeAndPhaseValid(blockHeight, bsqFee, DaoPhase.Phase.PROPOSAL, Param.PROPOSAL_FEE);
|
||||||
if (!isFeeAndPhaseValid) {
|
if (!isFeeAndPhaseValid) {
|
||||||
tempTx.setTxType(TxType.INVALID);
|
tempTx.setTxType(TxType.INVALID);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue