| 193 | } |
| 194 | |
| 195 | bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set<std::pair<uint256, COutPoint>>& setPeginsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore, bool fScriptChecks, const std::vector<std::pair<CScript, CScript>>& fedpegscripts) |
| 196 | { |
| 197 | // are the actual inputs available? |
| 198 | if (!inputs.HaveInputs(tx)) { |
| 199 | return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, "bad-txns-inputs-missingorspent", |
| 200 | strprintf("%s: inputs missing/spent", __func__)); |
| 201 | } |
| 202 | |
| 203 | std::vector<CTxOut> spent_inputs; |
| 204 | CAmount nValueIn = 0; |
| 205 | for (unsigned int i = 0; i < tx.vin.size(); ++i) { |
| 206 | const COutPoint &prevout = tx.vin[i].prevout; |
| 207 | if (tx.vin[i].m_is_pegin) { |
| 208 | // Check existence and validity of pegin witness |
| 209 | std::string err; |
| 210 | if (tx.witness.vtxinwit.size() <= i || !IsValidPeginWitness(tx.witness.vtxinwit[i].m_pegin_witness, fedpegscripts, prevout, err, true)) { |
| 211 | return state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, "bad-pegin-witness", err); |
| 212 | } |
| 213 | std::pair<uint256, COutPoint> pegin = std::make_pair(uint256(tx.witness.vtxinwit[i].m_pegin_witness.stack[2]), prevout); |
| 214 | if (inputs.IsPeginSpent(pegin)) { |
| 215 | return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-double-pegin", strprintf("Double-pegin of %s:%d", prevout.hash.ToString(), prevout.n)); |
| 216 | } |
| 217 | if (setPeginsSpent.count(pegin)) { |
| 218 | return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-double-pegin-in-obj", |
| 219 | strprintf("Double-pegin of %s:%d in single tx/block", prevout.hash.ToString(), prevout.n)); |
| 220 | } |
| 221 | setPeginsSpent.insert(pegin); |
| 222 | |
| 223 | // Tally the input amount. |
| 224 | spent_inputs.push_back(GetPeginOutputFromWitness(tx.witness.vtxinwit[i].m_pegin_witness)); |
| 225 | const CTxOut& out = spent_inputs.back(); |
| 226 | nValueIn += out.nValue.GetAmount(); // Non-explicit already filtered by IsValidPeginWitness |
| 227 | if (!MoneyRange(out.nValue.GetAmount())) { |
| 228 | return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputvalues-outofrange"); |
| 229 | } |
| 230 | } else { |
| 231 | const Coin& coin = inputs.AccessCoin(prevout); |
| 232 | assert(!coin.IsSpent()); |
| 233 | |
| 234 | // If prev is coinbase, check that it's matured |
| 235 | if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) { |
| 236 | return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase", |
| 237 | strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight)); |
| 238 | } |
| 239 | spent_inputs.push_back(coin.out); |
| 240 | if (coin.out.nValue.IsExplicit()) { |
| 241 | nValueIn += coin.out.nValue.GetAmount(); |
| 242 | } |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | if (g_con_elementsmode) { |
| 247 | // Tally transaction fees |
| 248 | if (!HasValidFee(tx)) { |
| 249 | return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange"); |
| 250 | } |
| 251 | |
| 252 | // Verify that amounts add up. |
nothing calls this directly
no test coverage detected