Search in sources :

Example 6 with TempTxOutput

use of bisq.core.dao.state.blockchain.TempTxOutput in project bisq-core by bisq-network.

the class TxParser method findTx.

// Apply state changes to tx, inputs and outputs
// return true if any input contained BSQ
// Any tx with BSQ input is a BSQ tx (except genesis tx but that is not handled in
// that class).
// There might be txs without any valid BSQ txOutput but we still keep track of it,
// for instance to calculate the total burned BSQ.
public Optional<Tx> findTx(RawTx rawTx, String genesisTxId, int genesisBlockHeight, Coin genesisTotalSupply) {
    txInputParser = new TxInputParser(bsqStateService);
    txOutputParser = new TxOutputParser(bsqStateService);
    // Let's see if we have a genesis tx
    Optional<TempTx> optionalGenesisTx = TxParser.findGenesisTx(genesisTxId, genesisBlockHeight, genesisTotalSupply, rawTx);
    if (optionalGenesisTx.isPresent()) {
        TempTx genesisTx = optionalGenesisTx.get();
        txOutputParser.processGenesisTxOutput(genesisTx);
        return Optional.of(Tx.fromTempTx(genesisTx));
    }
    // If it is not a genesis tx we continue to parse to see if it is a valid BSQ tx.
    int blockHeight = rawTx.getBlockHeight();
    // We could pass tx also to the sub validators but as long we have not refactored the validators to pure
    // functions lets use the parsingModel.
    TempTx tempTx = TempTx.fromRawTx(rawTx);
    for (int inputIndex = 0; inputIndex < tempTx.getTxInputs().size(); inputIndex++) {
        TxInput input = tempTx.getTxInputs().get(inputIndex);
        TxOutputKey outputKey = input.getConnectedTxOutputKey();
        txInputParser.process(outputKey, blockHeight, rawTx.getId(), inputIndex);
    }
    long accumulatedInputValue = txInputParser.getAccumulatedInputValue();
    txOutputParser.setAvailableInputValue(accumulatedInputValue);
    txOutputParser.setUnlockBlockHeight(txInputParser.getUnlockBlockHeight());
    txOutputParser.setOptionalSpentLockupTxOutput(txInputParser.getOptionalSpentLockupTxOutput());
    // TODO remove
    txOutputParser.setTempTx(tempTx);
    boolean hasBsqInputs = accumulatedInputValue > 0;
    if (hasBsqInputs) {
        final List<TempTxOutput> outputs = tempTx.getTempTxOutputs();
        // We start with last output as that might be an OP_RETURN output and gives us the specific tx type, so it is
        // easier and cleaner at parsing the other outputs to detect which kind of tx we deal with.
        // Setting the opReturn type here does not mean it will be a valid BSQ tx as the checks are only partial and
        // BSQ inputs are not verified yet.
        // We keep the temporary opReturn type in the parsingModel object.
        checkArgument(!outputs.isEmpty(), "outputs must not be empty");
        int lastIndex = outputs.size() - 1;
        txOutputParser.processOpReturnCandidate(outputs.get(lastIndex));
        // We iterate all outputs including the opReturn to do a full validation including the BSQ fee
        for (int index = 0; index < outputs.size(); index++) {
            boolean isLastOutput = index == lastIndex;
            txOutputParser.processTxOutput(isLastOutput, outputs.get(index), index);
        }
        remainingInputValue = txOutputParser.getAvailableInputValue();
        processOpReturnType(blockHeight, tempTx);
        // 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) {
            boolean isAnyTxOutputTypeUndefined = tempTx.getTempTxOutputs().stream().anyMatch(txOutput -> TxOutputType.UNDEFINED == txOutput.getTxOutputType());
            if (!isAnyTxOutputTypeUndefined) {
                // TODO(chirhonul): we don't modify the tempTx within the call below, so maybe we should
                // use RawTx?
                TxType txType = TxParser.getBisqTxType(tempTx, txOutputParser.getOptionalOpReturnTypeCandidate().isPresent(), remainingInputValue, getOptionalOpReturnType());
                tempTx.setTxType(txType);
                if (remainingInputValue > 0)
                    tempTx.setBurntFee(remainingInputValue);
            } else {
                tempTx.setTxType(TxType.INVALID);
                String msg = "We have undefined txOutput types which must not happen. tx=" + tempTx;
                DevEnv.logErrorAndThrowIfDevMode(msg);
            }
        } else {
            // 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);
        }
    }
    if (hasBsqInputs || txInputParser.getBurntBondValue() > 0)
        return Optional.of(Tx.fromTempTx(tempTx));
    else
        return Optional.empty();
}
Also used : TempTx(bisq.core.dao.state.blockchain.TempTx) TxType(bisq.core.dao.state.blockchain.TxType) TempTxOutput(bisq.core.dao.state.blockchain.TempTxOutput) TxOutputKey(bisq.core.dao.state.blockchain.TxOutputKey) TxInput(bisq.core.dao.state.blockchain.TxInput)

Aggregations

TempTxOutput (bisq.core.dao.state.blockchain.TempTxOutput)6 TempTx (bisq.core.dao.state.blockchain.TempTx)3 OpReturnType (bisq.core.dao.state.blockchain.OpReturnType)2 BondingConsensus (bisq.core.dao.bonding.BondingConsensus)1 InvalidGenesisTxException (bisq.core.dao.node.parser.exceptions.InvalidGenesisTxException)1 BsqStateService (bisq.core.dao.state.BsqStateService)1 TxInput (bisq.core.dao.state.blockchain.TxInput)1 TxOutput (bisq.core.dao.state.blockchain.TxOutput)1 TxOutputKey (bisq.core.dao.state.blockchain.TxOutputKey)1 TxOutputType (bisq.core.dao.state.blockchain.TxOutputType)1 TxType (bisq.core.dao.state.blockchain.TxType)1 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 Preconditions.checkArgument (com.google.common.base.Preconditions.checkArgument)1 Preconditions.checkNotNull (com.google.common.base.Preconditions.checkNotNull)1 Optional (java.util.Optional)1 Getter (lombok.Getter)1 Setter (lombok.Setter)1 Slf4j (lombok.extern.slf4j.Slf4j)1