Line data Source code
1 : // Copyright (c) 2016-2020 The ZCash developers
2 : // Copyright (c) 2020-2021 The PIVX Core developers
3 : // Distributed under the MIT software license, see the accompanying
4 : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
5 :
6 : #include "sapling/sapling_validation.h"
7 :
8 : #include "consensus/consensus.h" // for MAX_BLOCK_SIZE_CURRENT
9 : #include "script/interpreter.h" // for SigHash
10 : #include "consensus/validation.h" // for CValidationState
11 : #include "util/system.h" // for error()
12 : #include "consensus/upgrades.h" // for CurrentEpochBranchId()
13 :
14 : #include <librustzcash.h>
15 :
16 : namespace SaplingValidation {
17 :
18 : // Verifies that Shielded txs are properly formed and performs content-independent checks
19 891269 : bool CheckTransaction(const CTransaction& tx, CValidationState& state, CAmount& nValueOut)
20 : {
21 891269 : bool hasSaplingData = tx.hasSaplingData();
22 :
23 : // v1 must not have shielded data.
24 891269 : if (!tx.isSaplingVersion() && hasSaplingData) {
25 0 : return state.DoS(100, error("%s: Not Sapling version with Sapling data", __func__ ),
26 : REJECT_INVALID, "bad-txns-form-not-sapling");
27 : }
28 :
29 : // if the tx has no shielded data, return true. No check needed.
30 891269 : if (!hasSaplingData) {
31 : return true;
32 : }
33 :
34 : // From here, all of the checks are done in v3+ transactions.
35 :
36 : // if the tx has shielded data, cannot be a coinstake, coinbase, zcspend and zcmint
37 5072 : if (tx.IsCoinStake() || tx.IsCoinBase() || tx.HasZerocoinSpendInputs() || tx.HasZerocoinMintOutputs())
38 6 : return state.DoS(100, error("%s: Sapling version with invalid data", __func__),
39 : REJECT_INVALID, "bad-txns-invalid-sapling");
40 :
41 : // Upgrade enforced, basic version rules passing, let's check it
42 5070 : return CheckTransactionWithoutProofVerification(tx, state, nValueOut);
43 : }
44 :
45 5072 : bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState& state, CAmount& nValueOut)
46 : {
47 : // Basic checks that don't depend on any context
48 5072 : const Consensus::Params& consensus = Params().GetConsensus();
49 : // If the tx got to this point, must be v3+.
50 5072 : assert(tx.isSaplingVersion());
51 :
52 : // Check for non-zero valueBalance when there are no Sapling inputs or outputs
53 5072 : if (tx.sapData->vShieldedSpend.empty() && tx.sapData->vShieldedOutput.empty() && tx.sapData->valueBalance != 0) {
54 0 : return state.DoS(100, error("%s: tx.sapData->valueBalance has no sources or sinks", __func__ ),
55 : REJECT_INVALID, "bad-txns-valuebalance-nonzero");
56 : }
57 :
58 : // Check for overflow valueBalance
59 5072 : if (tx.sapData->valueBalance > consensus.nMaxMoneyOut || tx.sapData->valueBalance < -consensus.nMaxMoneyOut) {
60 0 : return state.DoS(100, error("%s: abs(tx.sapData->valueBalance) too large", __func__),
61 : REJECT_INVALID, "bad-txns-valuebalance-toolarge");
62 : }
63 :
64 5072 : if (tx.sapData->valueBalance < 0) {
65 : // NB: negative valueBalance "takes" money from the transparent value pool just as outputs do
66 4791 : nValueOut += -tx.sapData->valueBalance;
67 :
68 4791 : if (!consensus.MoneyRange(nValueOut)) {
69 0 : return state.DoS(100, error("%s: txout total out of range", __func__ ),
70 : REJECT_INVALID, "bad-txns-txouttotal-toolarge");
71 : }
72 : }
73 :
74 : // Ensure input values do not exceed consensus.nMaxMoneyOut
75 : // We have not resolved the txin values at this stage,
76 : // but we do know what the shielded tx claim to add
77 : // to the value pool.
78 :
79 : // NB: positive valueBalance "adds" money to the transparent value pool, just as inputs do
80 5072 : if (tx.sapData->valueBalance > 0 && !consensus.MoneyRange(tx.sapData->valueBalance)) {
81 0 : return state.DoS(100, error("%s: txin total out of range", __func__ ),
82 : REJECT_INVALID, "bad-txns-txintotal-toolarge");
83 : }
84 :
85 : // Check for duplicate sapling nullifiers in this transaction
86 5072 : {
87 5072 : std::set<uint256> vSaplingNullifiers;
88 5463 : for (const SpendDescription& spend_desc : tx.sapData->vShieldedSpend) {
89 392 : if (vSaplingNullifiers.count(spend_desc.nullifier))
90 3 : return state.DoS(100, error("%s: duplicate nullifiers", __func__ ),
91 : REJECT_INVALID, "bad-spend-description-nullifiers-duplicate");
92 :
93 391 : vSaplingNullifiers.insert(spend_desc.nullifier);
94 : }
95 : }
96 :
97 5071 : return true;
98 : }
99 :
100 : /**
101 : * Check a transaction contextually against a set of consensus rules valid at a given block height.
102 : *
103 : * Notes:
104 : * 1. AcceptToMemoryPool calls CheckTransaction and this function.
105 : * 2. ProcessNewBlock calls AcceptBlock, which calls CheckBlock (which calls CheckTransaction)
106 : * and ContextualCheckBlock (which calls this function).
107 : * 3. For consensus rules that relax restrictions (where a transaction that is invalid at
108 : * nHeight can become valid at a later height), we make the bans conditional on not
109 : * being in Initial Block Download mode.
110 : * 4. The isInitBlockDownload argument is a function parameter to assist with testing.
111 : *
112 : */
113 663443 : bool ContextualCheckTransaction(
114 : const CTransaction& tx,
115 : CValidationState &state,
116 : const CChainParams& chainparams,
117 : const int nHeight,
118 : const bool isMined,
119 : bool isInitBlockDownload)
120 : {
121 663443 : const int DOS_LEVEL_BLOCK = 100;
122 : // DoS level set to 10 to be more forgiving.
123 663443 : const int DOS_LEVEL_MEMPOOL = 10;
124 :
125 : // For constricting rules, we don't need to account for IBD mode.
126 663443 : auto dosLevelConstricting = isMined ? DOS_LEVEL_BLOCK : DOS_LEVEL_MEMPOOL;
127 : // For rules that are relaxing (or might become relaxing when a future
128 : // network upgrade is implemented), we need to account for IBD mode.
129 663443 : auto dosLevelPotentiallyRelaxing = isMined ? DOS_LEVEL_BLOCK : (
130 178059 : isInitBlockDownload ? 0 : DOS_LEVEL_MEMPOOL);
131 :
132 : // If Sapling is not active return quickly and don't perform any check here.
133 : // basic data checks are performed in CheckTransaction which is ALWAYS called before ContextualCheckTransaction.
134 663443 : if (!chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_V5_0)) {
135 : // If the v5 upgrade was not enforced, then let's not perform any check
136 622366 : if (tx.IsShieldedTx()) {
137 0 : return state.DoS(dosLevelConstricting, error("%s: Sapling not activated", __func__),
138 : REJECT_INVALID, "bad-txns-invalid-sapling-act");
139 : }
140 622366 : return true;
141 : }
142 :
143 : // Reject transactions with invalid version
144 41077 : if (!tx.isSaplingVersion() && tx.hasSaplingData()) {
145 0 : return state.DoS(
146 : dosLevelConstricting,
147 0 : error("%s: Sapling version too low", __func__ ),
148 : REJECT_INVALID, "bad-tx-sapling-version-too-low");
149 : }
150 :
151 41077 : bool hasShieldedData = tx.hasSaplingData();
152 : // A coinbase/coinstake transaction cannot have output descriptions nor shielded spends
153 41077 : if (tx.IsCoinBase() || tx.IsCoinStake()) {
154 31937 : if (hasShieldedData)
155 0 : return state.DoS(
156 : dosLevelPotentiallyRelaxing,
157 0 : error("%s: coinbase/coinstake has output/spend descriptions", __func__ ),
158 : REJECT_INVALID, "bad-cs-has-shielded-data");
159 : }
160 :
161 41077 : if (hasShieldedData) {
162 4338 : uint256 dataToBeSigned;
163 :
164 4338 : if (tx.HasExchangeAddr() && Params().GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_V5_6)) {
165 3 : return state.DoS(100, error("%s: Sapling version with invalid data", __func__),
166 : REJECT_INVALID, "bad-txns-exchange-addr-has-sapling");
167 : }
168 :
169 : // Empty output script.
170 8674 : CScript scriptCode;
171 4337 : try {
172 4337 : dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_SAPLING);
173 0 : } catch (const std::logic_error& ex) {
174 : // A logic error should never occur because we pass NOT_AN_INPUT and
175 : // SIGHASH_ALL to SignatureHash().
176 0 : return state.DoS(100, error("%s: error computing signature hash", __func__ ),
177 : REJECT_INVALID, "error-computing-signature-hash");
178 : }
179 :
180 : // Sapling verification process
181 4337 : auto ctx = librustzcash_sapling_verification_ctx_init();
182 :
183 4674 : for (const SpendDescription &spend : tx.sapData->vShieldedSpend) {
184 337 : if (!librustzcash_sapling_check_spend(
185 : ctx,
186 : spend.cv.begin(),
187 : spend.anchor.begin(),
188 : spend.nullifier.begin(),
189 : spend.rk.begin(),
190 : spend.zkproof.begin(),
191 : spend.spendAuthSig.begin(),
192 337 : dataToBeSigned.begin())) {
193 0 : librustzcash_sapling_verification_ctx_free(ctx);
194 0 : return state.DoS(
195 : dosLevelPotentiallyRelaxing,
196 0 : error("%s: Sapling spend description invalid", __func__ ),
197 : REJECT_INVALID, "bad-txns-sapling-spend-description-invalid");
198 : }
199 : }
200 :
201 9115 : for (const OutputDescription &output : tx.sapData->vShieldedOutput) {
202 4778 : if (!librustzcash_sapling_check_output(
203 : ctx,
204 : output.cv.begin(),
205 : output.cmu.begin(),
206 : output.ephemeralKey.begin(),
207 : output.zkproof.begin())) {
208 0 : librustzcash_sapling_verification_ctx_free(ctx);
209 : // This should be a non-contextual check, but we check it here
210 : // as we need to pass over the outputs anyway in order to then
211 : // call librustzcash_sapling_final_check().
212 0 : return state.DoS(100, error("%s: Sapling output description invalid", __func__ ),
213 : REJECT_INVALID, "bad-txns-sapling-output-description-invalid");
214 : }
215 : }
216 :
217 8674 : if (!librustzcash_sapling_final_check(
218 : ctx,
219 4337 : tx.sapData->valueBalance,
220 4337 : tx.sapData->bindingSig.begin(),
221 4337 : dataToBeSigned.begin())) {
222 0 : librustzcash_sapling_verification_ctx_free(ctx);
223 0 : return state.DoS(
224 : dosLevelPotentiallyRelaxing,
225 0 : error("%s: Sapling binding signature invalid", __func__ ),
226 : REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid");
227 : }
228 :
229 4337 : librustzcash_sapling_verification_ctx_free(ctx);
230 : }
231 : return true;
232 : }
233 :
234 :
235 : } // End SaplingValidation namespace
|