Line data Source code
1 : // Copyright (c) 2017 The Dash Core developers
2 : // Copyright (c) 2020-2022 The PIVX Core developers
3 : // Distributed under the MIT software license, see the accompanying
4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 :
6 : #include "evo/specialtx_validation.h"
7 :
8 : #include "chain.h"
9 : #include "coins.h"
10 : #include "chainparams.h"
11 : #include "clientversion.h"
12 : #include "consensus/validation.h"
13 : #include "evo/deterministicmns.h"
14 : #include "evo/providertx.h"
15 : #include "llmq/quorums_blockprocessor.h"
16 : #include "messagesigner.h"
17 : #include "primitives/transaction.h"
18 : #include "primitives/block.h"
19 : #include "script/standard.h"
20 : #include "spork.h"
21 :
22 : /* -- Helper static functions -- */
23 :
24 1573 : static bool CheckService(const CService& addr, CValidationState& state)
25 : {
26 1573 : if (!addr.IsValid()) {
27 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-ipaddr");
28 : }
29 1573 : if (!Params().IsRegTestNet() && !addr.IsRoutable()) {
30 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-ipaddr");
31 : }
32 :
33 : // IP port must be the default one on main-net, which cannot be used on other nets.
34 1646 : static int mainnetDefaultPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
35 1573 : if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
36 2 : if (addr.GetPort() != mainnetDefaultPort) {
37 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-ipaddr-port");
38 : }
39 1571 : } else if (addr.GetPort() == mainnetDefaultPort) {
40 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-ipaddr-port");
41 : }
42 :
43 : // !TODO: add support for IPv6 and Tor
44 1573 : if (!addr.IsIPv4()) {
45 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-ipaddr");
46 : }
47 :
48 : return true;
49 : }
50 :
51 : template <typename Payload>
52 87 : static bool CheckHashSig(const Payload& pl, const CKeyID& keyID, CValidationState& state)
53 : {
54 87 : std::string strError;
55 87 : if (!CHashSigner::VerifyHash(::SerializeHash(pl), keyID, pl.vchSig, strError)) {
56 4 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig", false, strError);
57 : }
58 : return true;
59 : }
60 :
61 : template <typename Payload>
62 93 : static bool CheckHashSig(const Payload& pl, const CBLSPublicKey& pubKey, CValidationState& state)
63 : {
64 93 : if (!pl.sig.VerifyInsecure(pubKey, ::SerializeHash(pl))) {
65 6 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig", false);
66 : }
67 : return true;
68 : }
69 :
70 : template <typename Payload>
71 462 : static bool CheckStringSig(const Payload& pl, const CKeyID& keyID, CValidationState& state)
72 : {
73 462 : std::string strError;
74 924 : if (!CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError)) {
75 0 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig", false, strError);
76 : }
77 : return true;
78 : }
79 :
80 : template <typename Payload>
81 1778 : static bool CheckInputsHash(const CTransaction& tx, const Payload& pl, CValidationState& state)
82 : {
83 1778 : if (CalcTxInputsHash(tx) != pl.inputsHash) {
84 3 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-inputs-hash");
85 : }
86 :
87 : return true;
88 : }
89 :
90 1201 : static bool CheckCollateralOut(const CTxOut& out, const ProRegPL& pl, CValidationState& state, CTxDestination& collateralDestRet)
91 : {
92 1201 : if (!ExtractDestination(out.scriptPubKey, collateralDestRet)) {
93 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-dest");
94 : }
95 : // don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
96 : // this check applies to internal and external collateral, but internal collaterals are not necessarely a P2PKH
97 3602 : if (collateralDestRet == CTxDestination(pl.keyIDOwner) ||
98 2401 : collateralDestRet == CTxDestination(pl.keyIDVoting)) {
99 3 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-reuse");
100 : }
101 : // check collateral amount
102 1200 : if (out.nValue != Params().GetConsensus().nMNCollateralAmt) {
103 6 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-collateral-amount");
104 : }
105 : return true;
106 : }
107 :
108 : // Provider Register Payload
109 1476 : static bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache* view, CValidationState& state)
110 : {
111 :
112 2952 : ProRegPL pl;
113 1476 : if (!GetValidatedTxPayload(tx, pl, state)) {
114 : // pass the state returned by the function above
115 : return false;
116 : }
117 :
118 : // It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later
119 : // If any of both is set, it must be valid however
120 2950 : if (pl.addr != CService() && !CheckService(pl.addr, state)) {
121 : // pass the state returned by the function above
122 : return false;
123 : }
124 :
125 25797 : if (pl.collateralOutpoint.hash.IsNull()) {
126 : // collateral included in the proReg tx
127 737 : if (pl.collateralOutpoint.n >= tx.vout.size()) {
128 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-index");
129 : }
130 1473 : CTxDestination collateralTxDest;
131 737 : if (!CheckCollateralOut(tx.vout[pl.collateralOutpoint.n], pl, state, collateralTxDest)) {
132 : // pass the state returned by the function above
133 1 : return false;
134 : }
135 : // collateral is part of this ProRegTx, so we know the collateral is owned by the issuer
136 736 : if (!pl.vchSig.empty()) {
137 0 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig");
138 : }
139 738 : } else if (pindexPrev != nullptr) {
140 466 : assert(view != nullptr);
141 :
142 : // Referenced external collateral.
143 : // This is checked only when pindexPrev is not null (thus during ConnectBlock-->CheckSpecialTx),
144 : // because this is a contextual check: we need the updated utxo set, to verify that
145 : // the coin exists and it is unspent.
146 928 : Coin coin;
147 466 : if (!view->GetUTXOCoin(pl.collateralOutpoint, coin)) {
148 6 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral");
149 : }
150 926 : CTxDestination collateralTxDest;
151 464 : if (!CheckCollateralOut(coin.out, pl, state, collateralTxDest)) {
152 : // pass the state returned by the function above
153 4 : return false;
154 : }
155 : // Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH.
156 : // Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx
157 462 : const CKeyID* keyForPayloadSig = boost::get<CKeyID>(&collateralTxDest);
158 462 : if (!keyForPayloadSig) {
159 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-pkh");
160 : }
161 : // collateral is not part of this ProRegTx, so we must verify ownership of the collateral
162 462 : if (!CheckStringSig(pl, *keyForPayloadSig, state)) {
163 : // pass the state returned by the function above
164 : return false;
165 : }
166 : }
167 :
168 1470 : if (!CheckInputsHash(tx, pl, state)) {
169 : return false;
170 : }
171 :
172 1469 : if (pindexPrev) {
173 1811 : auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
174 : // only allow reusing of addresses when it's for the same collateral (which replaces the old MN)
175 912 : if (mnList.HasUniqueProperty(pl.addr) && mnList.GetUniquePropertyMN(pl.addr)->collateralOutpoint != pl.collateralOutpoint) {
176 9 : return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-IP-address");
177 : }
178 : // never allow duplicate keys, even if this ProTx would replace an existing MN
179 906 : if (mnList.HasUniqueProperty(pl.keyIDOwner)) {
180 6 : return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-owner-key");
181 : }
182 904 : if (mnList.HasUniqueProperty(pl.pubKeyOperator)) {
183 6 : return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-operator-key");
184 : }
185 : }
186 :
187 : return true;
188 : }
189 :
190 : // Provider Update Service Payload
191 98 : static bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
192 : {
193 :
194 196 : ProUpServPL pl;
195 98 : if (!GetValidatedTxPayload(tx, pl, state)) {
196 : // pass the state returned by the function above
197 : return false;
198 : }
199 :
200 98 : if (!CheckService(pl.addr, state)) {
201 : // pass the state returned by the function above
202 : return false;
203 : }
204 :
205 98 : if (!CheckInputsHash(tx, pl, state)) {
206 : // pass the state returned by the function above
207 : return false;
208 : }
209 :
210 98 : if (pindexPrev) {
211 60 : auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
212 115 : auto mn = mnList.GetMN(pl.proTxHash);
213 60 : if (!mn) {
214 2 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
215 : }
216 :
217 : // don't allow updating to addresses already used by other MNs
218 74 : if (mnList.HasUniqueProperty(pl.addr) && mnList.GetUniquePropertyMN(pl.addr)->proTxHash != pl.proTxHash) {
219 6 : return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
220 : }
221 :
222 57 : if (!pl.scriptOperatorPayout.empty()) {
223 13 : if (mn->nOperatorReward == 0) {
224 : // don't allow to set operator reward payee in case no operatorReward was set
225 3 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-operator-payee");
226 : }
227 : // we may support other kinds of scripts later, but restrict it for now
228 12 : if (!pl.scriptOperatorPayout.IsPayToPublicKeyHash()) {
229 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-operator-payee");
230 : }
231 : }
232 :
233 : // we can only check the signature if pindexPrev != nullptr and the MN is known
234 56 : if (!CheckHashSig(pl, mn->pdmnState->pubKeyOperator.Get(), state)) {
235 : // pass the state returned by the function above
236 : return false;
237 : }
238 : }
239 :
240 : return true;
241 : }
242 :
243 : // Provider Update Registrar Payload
244 148 : static bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache* view, CValidationState& state)
245 : {
246 :
247 148 : ProUpRegPL pl;
248 148 : if (!GetValidatedTxPayload(tx, pl, state)) {
249 : // pass the state returned by the function above
250 : return false;
251 : }
252 :
253 296 : CTxDestination payoutDest;
254 148 : if (!ExtractDestination(pl.scriptPayout, payoutDest)) {
255 : // should not happen as we checked script types before
256 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-dest");
257 : }
258 :
259 : // don't allow reuse of payee key for other keys
260 148 : if (payoutDest == CTxDestination(pl.keyIDVoting)) {
261 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-reuse");
262 : }
263 :
264 148 : if (!CheckInputsHash(tx, pl, state)) {
265 : return false;
266 : }
267 :
268 148 : if (pindexPrev) {
269 90 : assert(view != nullptr);
270 :
271 : // ProUpReg txes are disabled when the legacy system is still active
272 : // !TODO: remove after complete transition to DMN
273 90 : if (!deterministicMNManager->LegacyMNObsolete(pindexPrev->nHeight + 1)) {
274 0 : return state.DoS(10, false, REJECT_INVALID, "spork-21-inactive");
275 : }
276 :
277 90 : auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
278 175 : auto dmn = mnList.GetMN(pl.proTxHash);
279 90 : if (!dmn) {
280 2 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
281 : }
282 :
283 : // don't allow reuse of payee key for owner key
284 89 : if (payoutDest == CTxDestination(dmn->pdmnState->keyIDOwner)) {
285 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-reuse");
286 : }
287 :
288 174 : Coin coin;
289 89 : if (!view->GetUTXOCoin(dmn->collateralOutpoint, coin)) {
290 : // this should never happen (there would be no dmn otherwise)
291 0 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-collateral");
292 : }
293 :
294 : // don't allow reuse of collateral key for other keys (don't allow people to put the payee key onto an online server)
295 174 : CTxDestination collateralTxDest;
296 89 : if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
297 0 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-collateral-dest");
298 : }
299 267 : if (collateralTxDest == CTxDestination(dmn->pdmnState->keyIDOwner) ||
300 178 : collateralTxDest == CTxDestination(pl.keyIDVoting)) {
301 0 : return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-reuse");
302 : }
303 :
304 89 : if (mnList.HasUniqueProperty(pl.pubKeyOperator)) {
305 72 : auto otherDmn = mnList.GetUniquePropertyMN(pl.pubKeyOperator);
306 37 : if (pl.proTxHash != otherDmn->proTxHash) {
307 6 : return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-key");
308 : }
309 : }
310 :
311 87 : if (!CheckHashSig(pl, dmn->pdmnState->keyIDOwner, state)) {
312 : // pass the state returned by the function above
313 : return false;
314 : }
315 :
316 : }
317 :
318 : return true;
319 : }
320 :
321 : // Provider Update Revoke Payload
322 62 : static bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
323 : {
324 :
325 62 : ProUpRevPL pl;
326 62 : if (!GetValidatedTxPayload(tx, pl, state)) {
327 : // pass the state returned by the function above
328 : return false;
329 : }
330 :
331 62 : if (!CheckInputsHash(tx, pl, state)) {
332 : // pass the state returned by the function above
333 : return false;
334 : }
335 :
336 62 : if (pindexPrev) {
337 37 : auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
338 72 : auto dmn = mnList.GetMN(pl.proTxHash);
339 37 : if (!dmn)
340 0 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
341 :
342 37 : if (!CheckHashSig(pl, dmn->pdmnState->pubKeyOperator.Get(), state)) {
343 : // pass the state returned by the function above
344 : return false;
345 : }
346 : }
347 :
348 : return true;
349 : }
350 :
351 : // LLMQ final commitment Payload
352 5538 : bool VerifyLLMQCommitment(const llmq::CFinalCommitment& qfc, const CBlockIndex* pindexPrev, CValidationState& state)
353 : {
354 5538 : AssertLockHeld(cs_main);
355 :
356 : // Check DKG maintenance mode
357 5538 : if (sporkManager.IsSporkActive(SPORK_22_LLMQ_DKG_MAINTENANCE) && !IsInitialBlockDownload()) {
358 : // only null commitments are accepted
359 182 : if (!qfc.IsNull()) {
360 9 : return state.DoS(50, false, REJECT_INVALID, "bad-qc-not-null-spork22");
361 : }
362 : }
363 :
364 : // Check version
365 5535 : if (qfc.nVersion == 0 || qfc.nVersion > llmq::CFinalCommitment::CURRENT_VERSION) {
366 0 : return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-version");
367 : }
368 :
369 : // Check type
370 11073 : Optional<Consensus::LLMQParams> params = Params().GetConsensus().GetLLMQParams(qfc.llmqType);
371 5535 : if (params == nullopt) {
372 0 : return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-type");
373 : }
374 :
375 : // Check sizes
376 5535 : if (!qfc.VerifySizes(*params)) {
377 0 : return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-sizes");
378 : }
379 :
380 5535 : if (pindexPrev) {
381 : // Get quorum index
382 2640 : CBlockIndex* pindexQuorum = LookupBlockIndex(qfc.quorumHash);
383 2640 : if (!pindexQuorum) {
384 3 : return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-hash-not-found");
385 : }
386 :
387 : // Check height
388 2639 : if (pindexQuorum->nHeight % params->dkgInterval != 0) {
389 : // not first block of DKG interval
390 3 : return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-height");
391 : }
392 :
393 : // Check height limit
394 2638 : if (pindexPrev->nHeight - pindexQuorum->nHeight > params->cacheDkgInterval) {
395 6 : return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-height-old");
396 : }
397 :
398 2636 : if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) {
399 : // not part of active chain
400 3 : return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-hash-not-active-chain");
401 : }
402 :
403 : // Get members and check signatures (for not-null commitments)
404 2635 : if (!qfc.IsNull()) {
405 546 : std::vector<CBLSPublicKey> allkeys;
406 1092 : for (const auto& m : deterministicMNManager->GetAllQuorumMembers((Consensus::LLMQType)qfc.llmqType, pindexQuorum)) {
407 819 : allkeys.emplace_back(m->pdmnState->pubKeyOperator.Get());
408 : }
409 273 : if (!qfc.Verify(allkeys, *params)) {
410 0 : return state.DoS(100, false, REJECT_INVALID, "bad-qc-invalid");
411 : }
412 : }
413 : }
414 :
415 : return true;
416 : }
417 :
418 5434 : static bool CheckLLMQCommitmentTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
419 : {
420 5434 : AssertLockHeld(cs_main);
421 :
422 10868 : llmq::LLMQCommPL pl;
423 5434 : if (!GetTxPayload(tx, pl)) {
424 0 : return state.DoS(100, false, REJECT_INVALID, "bad-qc-payload");
425 : }
426 :
427 5434 : if (pl.nVersion == 0 || pl.nVersion > llmq::LLMQCommPL::CURRENT_VERSION) {
428 0 : return state.DoS(100, false, REJECT_INVALID, "bad-qc-version");
429 : }
430 :
431 5434 : if (pindexPrev && pl.nHeight != (uint32_t)pindexPrev->nHeight + 1) {
432 2 : return state.DoS(100, false, REJECT_INVALID, "bad-qc-height");
433 : }
434 :
435 5433 : return VerifyLLMQCommitment(pl.commitment, pindexPrev, state);
436 : }
437 :
438 : // Basic non-contextual checks for all tx types
439 1386505 : static bool CheckSpecialTxBasic(const CTransaction& tx, CValidationState& state)
440 : {
441 1386505 : bool hasExtraPayload = tx.hasExtraPayload();
442 :
443 1386505 : if (tx.IsNormalType()) {
444 : // Type-0 txes don't have extra payload
445 1379289 : if (hasExtraPayload) {
446 3 : return state.DoS(100, error("%s: Type 0 doesn't support extra payload", __func__),
447 : REJECT_INVALID, "bad-txns-type-payload");
448 : }
449 : // Normal transaction. Nothing to check
450 : return true;
451 : }
452 :
453 : // Special txes need at least version 2
454 7221 : if (!tx.isSaplingVersion()) {
455 3 : return state.DoS(100, error("%s: Type %d not supported with version %d", __func__, tx.nType, tx.nVersion),
456 : REJECT_INVALID, "bad-txns-type-version");
457 : }
458 :
459 : // Cannot be coinbase/coinstake tx
460 7220 : if (tx.IsCoinBase() || tx.IsCoinStake()) {
461 0 : return state.DoS(10, error("%s: Special tx is coinbase or coinstake", __func__),
462 : REJECT_INVALID, "bad-txns-special-coinbase");
463 : }
464 :
465 : // Special txes must have a non-empty payload
466 7220 : if (!hasExtraPayload) {
467 3 : return state.DoS(100, error("%s: Special tx (type=%d) without extra payload", __func__, tx.nType),
468 : REJECT_INVALID, "bad-txns-payload-empty");
469 : }
470 :
471 : // Size limits
472 7219 : if (tx.extraPayload->size() > MAX_SPECIALTX_EXTRAPAYLOAD) {
473 3 : return state.DoS(100, error("%s: Special tx payload oversize (%d)", __func__, tx.extraPayload->size()),
474 : REJECT_INVALID, "bad-txns-payload-oversize");
475 : }
476 :
477 : return true;
478 : }
479 :
480 : // contextual and non-contextual per-type checks
481 : // - pindexPrev=null: CheckBlock-->CheckSpecialTxNoContext
482 : // - pindexPrev=chainActive.Tip: AcceptToMemoryPoolWorker-->CheckSpecialTx
483 : // - pindexPrev=pindex->pprev: ConnectBlock-->ProcessSpecialTxsInBlock-->CheckSpecialTx
484 1386505 : bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache* view, CValidationState& state)
485 : {
486 1386505 : AssertLockHeld(cs_main);
487 :
488 1386505 : if (!CheckSpecialTxBasic(tx, state)) {
489 : // pass the state returned by the function above
490 : return false;
491 : }
492 1386501 : if (pindexPrev) {
493 : // reject special transactions before enforcement
494 673886 : if (!tx.IsNormalType() && !Params().GetConsensus().NetworkUpgradeActive(pindexPrev->nHeight + 1, Consensus::UPGRADE_V6_0)) {
495 0 : return state.DoS(100, error("%s: Special tx when v6 upgrade not enforced yet", __func__),
496 : REJECT_INVALID, "bad-txns-v6-not-active");
497 : }
498 : }
499 : // per-type checks
500 1386501 : switch (tx.nType) {
501 : case CTransaction::TxType::NORMAL: {
502 : // nothing to check
503 : return true;
504 : }
505 1476 : case CTransaction::TxType::PROREG: {
506 : // provider-register
507 1476 : return CheckProRegTx(tx, pindexPrev, view, state);
508 : }
509 98 : case CTransaction::TxType::PROUPSERV: {
510 : // provider-update-service
511 98 : return CheckProUpServTx(tx, pindexPrev, state);
512 : }
513 148 : case CTransaction::TxType::PROUPREG: {
514 : // provider-update-registrar
515 148 : return CheckProUpRegTx(tx, pindexPrev, view, state);
516 : }
517 62 : case CTransaction::TxType::PROUPREV: {
518 : // provider-update-revoke
519 62 : return CheckProUpRevTx(tx, pindexPrev, state);
520 : }
521 5434 : case CTransaction::TxType::LLMQCOMM: {
522 : // quorum commitment
523 5434 : return CheckLLMQCommitmentTx(tx, pindexPrev, state);
524 : }
525 : }
526 :
527 0 : return state.DoS(10, error("%s: special tx %s with invalid type %d", __func__, tx.GetHash().ToString(), tx.nType),
528 : REJECT_INVALID, "bad-tx-type");
529 : }
530 :
531 712621 : bool CheckSpecialTxNoContext(const CTransaction& tx, CValidationState& state)
532 : {
533 712621 : return CheckSpecialTx(tx, nullptr, nullptr, state);
534 : }
535 :
536 :
537 56431 : bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, const CCoinsViewCache* view, CValidationState& state, bool fJustCheck)
538 : {
539 56431 : AssertLockHeld(cs_main);
540 :
541 : // check special txes
542 559019 : for (const CTransactionRef& tx: block.vtx) {
543 502593 : if (!CheckSpecialTx(*tx, pindex->pprev, view, state)) {
544 : // pass the state returned by the function above
545 5 : return false;
546 : }
547 : }
548 :
549 56426 : if (!llmq::quorumBlockProcessor->ProcessBlock(block, pindex, state, fJustCheck)) {
550 : // pass the state returned by the function above
551 : return false;
552 : }
553 :
554 56422 : if (!deterministicMNManager->ProcessBlock(block, pindex, state, fJustCheck)) {
555 : // pass the state returned by the function above
556 12 : return false;
557 : }
558 :
559 : return true;
560 : }
561 :
562 1457 : bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex)
563 : {
564 1457 : if (!deterministicMNManager->UndoBlock(block, pindex)) {
565 : return false;
566 : }
567 1457 : if (!llmq::quorumBlockProcessor->UndoBlock(block, pindex)) {
568 0 : return false;
569 : }
570 : return true;
571 : }
572 :
573 1927 : uint256 CalcTxInputsHash(const CTransaction& tx)
574 : {
575 1927 : CHashWriter hw(CLIENT_VERSION, SER_GETHASH);
576 : // transparent inputs
577 3955 : for (const CTxIn& in: tx.vin) {
578 2028 : hw << in.prevout;
579 : }
580 : // shield inputs
581 1927 : if (tx.hasSaplingData()) {
582 0 : for (const SpendDescription& sd: tx.sapData->vShieldedSpend) {
583 0 : hw << sd.nullifier;
584 : }
585 : }
586 1927 : return hw.GetHash();
587 : }
588 :
589 : template <typename T>
590 1784 : bool GetValidatedTxPayload(const CTransaction& tx, T& obj, CValidationState& state)
591 : {
592 1784 : if (tx.nType != T::SPECIALTX_TYPE) {
593 0 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-type");
594 : }
595 1784 : if (!GetTxPayload(tx, obj)) {
596 3 : return state.DoS(100, false, REJECT_INVALID, "bad-protx-payload");
597 : }
598 1783 : return obj.IsTriviallyValid(state);
599 : }
|