PIVX Core  5.6.99
P2P Digital Currency
sapling_validation.cpp
Go to the documentation of this file.
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 
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 bool CheckTransaction(const CTransaction& tx, CValidationState& state, CAmount& nValueOut)
20 {
21  bool hasSaplingData = tx.hasSaplingData();
22 
23  // v1 must not have shielded data.
24  if (!tx.isSaplingVersion() && hasSaplingData) {
25  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  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
38  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  return CheckTransactionWithoutProofVerification(tx, state, nValueOut);
43 }
44 
46 {
47  // Basic checks that don't depend on any context
48  const Consensus::Params& consensus = Params().GetConsensus();
49  // If the tx got to this point, must be v3+.
50  assert(tx.isSaplingVersion());
51 
52  // Check for non-zero valueBalance when there are no Sapling inputs or outputs
53  if (tx.sapData->vShieldedSpend.empty() && tx.sapData->vShieldedOutput.empty() && tx.sapData->valueBalance != 0) {
54  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  if (tx.sapData->valueBalance > consensus.nMaxMoneyOut || tx.sapData->valueBalance < -consensus.nMaxMoneyOut) {
60  return state.DoS(100, error("%s: abs(tx.sapData->valueBalance) too large", __func__),
61  REJECT_INVALID, "bad-txns-valuebalance-toolarge");
62  }
63 
64  if (tx.sapData->valueBalance < 0) {
65  // NB: negative valueBalance "takes" money from the transparent value pool just as outputs do
66  nValueOut += -tx.sapData->valueBalance;
67 
68  if (!consensus.MoneyRange(nValueOut)) {
69  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  if (tx.sapData->valueBalance > 0 && !consensus.MoneyRange(tx.sapData->valueBalance)) {
81  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  {
87  std::set<uint256> vSaplingNullifiers;
88  for (const SpendDescription& spend_desc : tx.sapData->vShieldedSpend) {
89  if (vSaplingNullifiers.count(spend_desc.nullifier))
90  return state.DoS(100, error("%s: duplicate nullifiers", __func__ ),
91  REJECT_INVALID, "bad-spend-description-nullifiers-duplicate");
92 
93  vSaplingNullifiers.insert(spend_desc.nullifier);
94  }
95  }
96 
97  return true;
98 }
99 
114  const CTransaction& tx,
115  CValidationState &state,
116  const CChainParams& chainparams,
117  const int nHeight,
118  const bool isMined,
119  bool isInitBlockDownload)
120 {
121  const int DOS_LEVEL_BLOCK = 100;
122  // DoS level set to 10 to be more forgiving.
123  const int DOS_LEVEL_MEMPOOL = 10;
124 
125  // For constricting rules, we don't need to account for IBD mode.
126  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  auto dosLevelPotentiallyRelaxing = isMined ? DOS_LEVEL_BLOCK : (
130  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  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  if (tx.IsShieldedTx()) {
137  return state.DoS(dosLevelConstricting, error("%s: Sapling not activated", __func__),
138  REJECT_INVALID, "bad-txns-invalid-sapling-act");
139  }
140  return true;
141  }
142 
143  // Reject transactions with invalid version
144  if (!tx.isSaplingVersion() && tx.hasSaplingData()) {
145  return state.DoS(
146  dosLevelConstricting,
147  error("%s: Sapling version too low", __func__ ),
148  REJECT_INVALID, "bad-tx-sapling-version-too-low");
149  }
150 
151  bool hasShieldedData = tx.hasSaplingData();
152  // A coinbase/coinstake transaction cannot have output descriptions nor shielded spends
153  if (tx.IsCoinBase() || tx.IsCoinStake()) {
154  if (hasShieldedData)
155  return state.DoS(
156  dosLevelPotentiallyRelaxing,
157  error("%s: coinbase/coinstake has output/spend descriptions", __func__ ),
158  REJECT_INVALID, "bad-cs-has-shielded-data");
159  }
160 
161  if (hasShieldedData) {
162  uint256 dataToBeSigned;
163 
165  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  CScript scriptCode;
171  try {
172  dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_SAPLING);
173  } 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  return state.DoS(100, error("%s: error computing signature hash", __func__ ),
177  REJECT_INVALID, "error-computing-signature-hash");
178  }
179 
180  // Sapling verification process
182 
183  for (const SpendDescription &spend : tx.sapData->vShieldedSpend) {
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  dataToBeSigned.begin())) {
194  return state.DoS(
195  dosLevelPotentiallyRelaxing,
196  error("%s: Sapling spend description invalid", __func__ ),
197  REJECT_INVALID, "bad-txns-sapling-spend-description-invalid");
198  }
199  }
200 
201  for (const OutputDescription &output : tx.sapData->vShieldedOutput) {
203  ctx,
204  output.cv.begin(),
205  output.cmu.begin(),
206  output.ephemeralKey.begin(),
207  output.zkproof.begin())) {
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  return state.DoS(100, error("%s: Sapling output description invalid", __func__ ),
213  REJECT_INVALID, "bad-txns-sapling-output-description-invalid");
214  }
215  }
216 
218  ctx,
219  tx.sapData->valueBalance,
220  tx.sapData->bindingSig.begin(),
221  dataToBeSigned.begin())) {
223  return state.DoS(
224  dosLevelPotentiallyRelaxing,
225  error("%s: Sapling binding signature invalid", __func__ ),
226  REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid");
227  }
228 
230  }
231  return true;
232 }
233 
234 
235 } // End SaplingValidation namespace
int64_t CAmount
Amount in PIV (Can be negative)
Definition: amount.h:13
const CChainParams & Params()
Return the currently selected parameters.
CChainParams defines various tweakable parameters of a given instance of the PIVX system.
Definition: chainparams.h:43
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:72
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:244
bool HasZerocoinSpendInputs() const
bool HasExchangeAddr() const
bool IsShieldedTx() const
Definition: transaction.h:319
bool HasZerocoinMintOutputs() const
bool IsCoinBase() const
Definition: transaction.h:376
Optional< SaplingTxData > sapData
Definition: transaction.h:275
bool isSaplingVersion() const
Definition: transaction.h:314
bool IsCoinStake() const
bool hasSaplingData() const
Definition: transaction.h:305
Capture information about block/transaction validation.
Definition: validation.h:24
bool DoS(int level, bool ret=false, unsigned int chRejectCodeIn=0, std::string strRejectReasonIn="", bool corruptionIn=false, const std::string &strDebugMessageIn="")
Definition: validation.h:39
A shielded output to a transaction.
uint256 cmu
The u-coordinate of the note commitment for the output note.
libzcash::GrothProof zkproof
A zero-knowledge proof using the output circuit.
uint256 cv
A value commitment to the value of the output note.
uint256 ephemeralKey
A Jubjub public key.
A shielded input to a transaction.
spend_auth_sig_t spendAuthSig
A signature authorizing this spend.
uint256 cv
A value commitment to the value of the input note.
libzcash::GrothProof zkproof
A zero-knowledge proof using the spend circuit.
uint256 anchor
A Merkle root of the Sapling note commitment tree at some block height in the past.
uint256 rk
The randomized public key for spendAuthSig.
uint256 nullifier
The nullifier of the input note.
unsigned char * begin()
Definition: uint256.h:63
256-bit opaque blob.
Definition: uint256.h:138
uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, unsigned int nIn, int nHashType, const CAmount &amount, SigVersion sigversion, const PrecomputedTransactionData *cache)
const unsigned int NOT_AN_INPUT
Special case nIn for signing Sapling txs.
Definition: interpreter.h:19
@ SIGHASH_ALL
Definition: interpreter.h:24
void librustzcash_sapling_verification_ctx_free(void *)
Frees a Sapling verification context returned from librustzcash_sapling_verification_ctx_init.
bool librustzcash_sapling_check_output(void *ctx, const unsigned char *cv, const unsigned char *cm, const unsigned char *ephemeralKey, const unsigned char *zkproof)
Check the validity of a Sapling Output description, accumulating the value commitment into the contex...
void * librustzcash_sapling_verification_ctx_init()
Creates a Sapling verification context.
bool librustzcash_sapling_final_check(void *ctx, int64_t valueBalance, const unsigned char *bindingSig, const unsigned char *sighashValue)
Finally checks the validity of the entire Sapling transaction given valueBalance and the binding sign...
bool librustzcash_sapling_check_spend(void *ctx, const unsigned char *cv, const unsigned char *anchor, const unsigned char *nullifier, const unsigned char *rk, const unsigned char *zkproof, const unsigned char *spendAuthSig, const unsigned char *sighashValue)
Check the validity of a Sapling Spend description, accumulating the value commitment into the context...
@ UPGRADE_V5_0
Definition: params.h:36
@ UPGRADE_V5_6
Definition: params.h:40
bool CheckTransactionWithoutProofVerification(const CTransaction &tx, CValidationState &state, CAmount &nValueOut)
bool CheckTransaction(const CTransaction &tx, CValidationState &state, CAmount &nValueOut)
Context-independent validity checks.
bool ContextualCheckTransaction(const CTransaction &tx, CValidationState &state, const CChainParams &chainparams, const int nHeight, const bool isMined, bool isInitBlockDownload)
Check a transaction contextually against a set of consensus rules valid at a given block height.
Parameters that influence chain consensus.
Definition: params.h:171
CAmount nMaxMoneyOut
Definition: params.h:183
bool MoneyRange(const CAmount &nValue) const
Definition: params.h:217
bool NetworkUpgradeActive(int nHeight, Consensus::UpgradeIndex idx) const
Returns true if the given network upgrade is active as of the given block height.
Definition: params.cpp:12
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
@ SIGVERSION_SAPLING
Definition: transaction.h:28