Implement Orchard signature validation consensus rules

This commit is contained in:
Jack Grigg 2021-06-14 11:45:54 +01:00
parent af1b9c15bb
commit 3fe8285c7e
6 changed files with 93 additions and 32 deletions

View File

@ -7,6 +7,8 @@
#include "utiltest.h" #include "utiltest.h"
#include "zcash/Proof.hpp" #include "zcash/Proof.hpp"
#include <rust/orchard.h>
class MockCValidationState : public CValidationState { class MockCValidationState : public CValidationState {
public: public:
MOCK_METHOD5(DoS, bool(int level, bool ret, MOCK_METHOD5(DoS, bool(int level, bool ret,
@ -26,13 +28,14 @@ public:
TEST(CheckBlock, VersionTooLow) { TEST(CheckBlock, VersionTooLow) {
auto verifier = ProofVerifier::Strict(); auto verifier = ProofVerifier::Strict();
auto orchardAuth = orchard::AuthValidator::Batch();
CBlock block; CBlock block;
block.nVersion = 1; block.nVersion = 1;
MockCValidationState state; MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "version-too-low", false)).Times(1); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "version-too-low", false)).Times(1);
EXPECT_FALSE(CheckBlock(block, state, Params(), verifier, false, false, true)); EXPECT_FALSE(CheckBlock(block, state, Params(), verifier, orchardAuth, false, false, true));
} }
@ -72,9 +75,10 @@ TEST(CheckBlock, BlockSproutRejectsBadVersion) {
CBlockIndex indexPrev {Params().GenesisBlock()}; CBlockIndex indexPrev {Params().GenesisBlock()};
auto verifier = ProofVerifier::Strict(); auto verifier = ProofVerifier::Strict();
auto orchardAuth = orchard::AuthValidator::Batch();
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-version-too-low", false)).Times(1); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-version-too-low", false)).Times(1);
EXPECT_FALSE(CheckBlock(block, state, Params(), verifier, false, false, true)); EXPECT_FALSE(CheckBlock(block, state, Params(), verifier, orchardAuth, false, false, true));
} }

View File

@ -1188,7 +1188,7 @@ bool ContextualCheckTransaction(
bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool CheckTransaction(const CTransaction& tx, CValidationState &state,
ProofVerifier& verifier) ProofVerifier& verifier, orchard::AuthValidator& orchardAuth)
{ {
// Don't count coinbase transactions because mining skews the count // Don't count coinbase transactions because mining skews the count
if (!tx.IsCoinBase()) { if (!tx.IsCoinBase()) {
@ -1209,6 +1209,9 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state,
// Sapling zk-SNARK proofs are checked in librustzcash_sapling_check_{spend,output}, // Sapling zk-SNARK proofs are checked in librustzcash_sapling_check_{spend,output},
// called from ContextualCheckTransaction. // called from ContextualCheckTransaction.
// Queue Orchard signatures to be batch-validated.
tx.GetOrchardBundle().QueueSignatureValidation(orchardAuth, tx.GetHash());
return true; return true;
} }
} }
@ -1504,8 +1507,12 @@ bool AcceptToMemoryPool(
return false; return false;
} }
// This will be a single-transaction batch, which is still more efficient as every
// Orchard bundle contains at least two signatures.
auto orchardAuth = orchard::AuthValidator::Batch();
auto verifier = ProofVerifier::Strict(); auto verifier = ProofVerifier::Strict();
if (!CheckTransaction(tx, state, verifier)) if (!CheckTransaction(tx, state, verifier, orchardAuth))
return error("AcceptToMemoryPool: CheckTransaction failed"); return error("AcceptToMemoryPool: CheckTransaction failed");
// Check transaction contextually against the set of consensus rules which apply in the next block to be mined. // Check transaction contextually against the set of consensus rules which apply in the next block to be mined.
@ -1646,9 +1653,9 @@ bool AcceptToMemoryPool(
} }
} }
// We don't yet know if the transaction commits to consensusBranchId, // For v1-v4 transactions, we don't yet know if the transaction commits
// but if the entry gets added to the mempool, then it has passed // to consensusBranchId, but if the entry gets added to the mempool, then
// ContextualCheckInputs and therefore this is correct. // it has passed ContextualCheckInputs and therefore this is correct.
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx), fSpendsCoinbase, consensusBranchId); CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx), fSpendsCoinbase, consensusBranchId);
unsigned int nSize = entry.GetTxSize(); unsigned int nSize = entry.GetTxSize();
@ -1701,6 +1708,13 @@ bool AcceptToMemoryPool(
return state.Error("AcceptToMemoryPool: " + errmsg); return state.Error("AcceptToMemoryPool: " + errmsg);
} }
// Check Orchard bundle authorizations.
// This is done near the end to help prevent CPU exhaustion
// denial-of-service attacks.
if (!orchardAuth.Validate()) {
return state.DoS(100, false, REJECT_INVALID, "bad-orchard-bundle-authorization");
}
// Check against previous transactions // Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks. // This is done last to help prevent CPU exhaustion denial-of-service attacks.
PrecomputedTransactionData txdata(tx); PrecomputedTransactionData txdata(tx);
@ -2732,13 +2746,20 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// proof verification is expensive, disable if possible // proof verification is expensive, disable if possible
auto verifier = fExpensiveChecks ? ProofVerifier::Strict() : ProofVerifier::Disabled(); auto verifier = fExpensiveChecks ? ProofVerifier::Strict() : ProofVerifier::Disabled();
// Disable Orchard batch signature validation if possible.
auto orchardAuth = fExpensiveChecks ?
orchard::AuthValidator::Batch() : orchard::AuthValidator::Disabled();
// If in initial block download, and this block is an ancestor of a checkpoint, // If in initial block download, and this block is an ancestor of a checkpoint,
// and -ibdskiptxverification is set, disable all transaction checks. // and -ibdskiptxverification is set, disable all transaction checks.
bool fCheckTransactions = ShouldCheckTransactions(chainparams, pindex); bool fCheckTransactions = ShouldCheckTransactions(chainparams, pindex);
// Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in // Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in
if (!CheckBlock(block, state, chainparams, verifier, !fJustCheck, !fJustCheck, fCheckTransactions)) if (!CheckBlock(block, state, chainparams, verifier, orchardAuth,
!fJustCheck, !fJustCheck, fCheckTransactions))
{
return false; return false;
}
// verify that the view's current state corresponds to the previous block // verify that the view's current state corresponds to the previous block
uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash();
@ -3051,6 +3072,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
block.vtx[0].GetValueOut(), blockReward), block.vtx[0].GetValueOut(), blockReward),
REJECT_INVALID, "bad-cb-amount"); REJECT_INVALID, "bad-cb-amount");
// Ensure Orchard signatures are valid (if we are checking them)
if (!orchardAuth.Validate()) {
return state.DoS(100,
error("ConnectBlock(): an Orchard bundle within the block is invalid"),
REJECT_INVALID, "bad-orchard-bundle-authorization");
}
if (!control.Wait()) if (!control.Wait())
return state.DoS(100, false); return state.DoS(100, false);
int64_t nTime2 = GetTimeMicros(); nTimeVerify += nTime2 - nTimeStart; int64_t nTime2 = GetTimeMicros(); nTimeVerify += nTime2 - nTimeStart;
@ -4142,6 +4170,7 @@ bool CheckBlock(const CBlock& block,
CValidationState& state, CValidationState& state,
const CChainParams& chainparams, const CChainParams& chainparams,
ProofVerifier& verifier, ProofVerifier& verifier,
orchard::AuthValidator& orchardAuth,
bool fCheckPOW, bool fCheckPOW,
bool fCheckMerkleRoot, bool fCheckMerkleRoot,
bool fCheckTransactions) bool fCheckTransactions)
@ -4192,7 +4221,7 @@ bool CheckBlock(const CBlock& block,
// Check transactions // Check transactions
for (const CTransaction& tx : block.vtx) for (const CTransaction& tx : block.vtx)
if (!CheckTransaction(tx, state, verifier)) if (!CheckTransaction(tx, state, verifier, orchardAuth))
return error("CheckBlock(): CheckTransaction failed"); return error("CheckBlock(): CheckTransaction failed");
unsigned int nSigOps = 0; unsigned int nSigOps = 0;
@ -4394,9 +4423,9 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
* Store block on disk. * Store block on disk.
* If dbp is non-NULL, the file is known to already reside on disk. * If dbp is non-NULL, the file is known to already reside on disk.
* *
* JoinSplit proofs are not verified here; the only caller of AcceptBlock * JoinSplit proofs and Orchard authorizations are not verified here; the only
* (ProcessNewBlock) later invokes ActivateBestChain, which ultimately calls * caller of AcceptBlock (ProcessNewBlock) later invokes ActivateBestChain,
* ConnectBlock in a manner that can verify the proofs * which ultimately calls ConnectBlock in a manner that can verify the proofs.
*/ */
static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp)
{ {
@ -4428,10 +4457,12 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
if (fTooFarAhead) return true; // Block height is too high if (fTooFarAhead) return true; // Block height is too high
} }
// See method docstring for why this is always disabled. // See method docstring for why these are always disabled.
auto verifier = ProofVerifier::Disabled(); auto verifier = ProofVerifier::Disabled();
auto orchardAuth = orchard::AuthValidator::Disabled();
bool fCheckTransactions = ShouldCheckTransactions(chainparams, pindex); bool fCheckTransactions = ShouldCheckTransactions(chainparams, pindex);
if ((!CheckBlock(block, state, chainparams, verifier, true, true, fCheckTransactions)) || if ((!CheckBlock(block, state, chainparams, verifier, orchardAuth, true, true, fCheckTransactions)) ||
!ContextualCheckBlock(block, state, chainparams, pindex->pprev, fCheckTransactions)) { !ContextualCheckBlock(block, state, chainparams, pindex->pprev, fCheckTransactions)) {
if (state.IsInvalid() && !state.CorruptionPossible()) { if (state.IsInvalid() && !state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID; pindex->nStatus |= BLOCK_FAILED_VALID;
@ -4517,14 +4548,16 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
CBlockIndex indexDummy(block); CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev; indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1; indexDummy.nHeight = pindexPrev->nHeight + 1;
// JoinSplit proofs are verified in ConnectBlock
// JoinSplit proofs and Orchard authorizations are verified in ConnectBlock
auto verifier = ProofVerifier::Disabled(); auto verifier = ProofVerifier::Disabled();
auto orchardAuth = orchard::AuthValidator::Disabled();
// NOTE: CheckBlockHeader is called by CheckBlock // NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev)) if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev))
return false; return false;
// The following may be duplicative of the `CheckBlock` call within `ConnectBlock` // The following may be duplicative of the `CheckBlock` call within `ConnectBlock`
if (!CheckBlock(block, state, chainparams, verifier, false, fCheckMerkleRoot, true)) if (!CheckBlock(block, state, chainparams, verifier, orchardAuth, false, fCheckMerkleRoot, true))
return false; return false;
if (!ContextualCheckBlock(block, state, chainparams, pindexPrev, true)) if (!ContextualCheckBlock(block, state, chainparams, pindexPrev, true))
return false; return false;
@ -4919,6 +4952,9 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
// Flags used to permit skipping checks for efficiency // Flags used to permit skipping checks for efficiency
auto verifier = ProofVerifier::Disabled(); // No need to verify JoinSplits twice auto verifier = ProofVerifier::Disabled(); // No need to verify JoinSplits twice
bool fCheckTransactions = true; bool fCheckTransactions = true;
// We may as well check Orchard authorizations if we are checking
// transactions, since we can batch-validate them.
auto orchardAuth = orchard::AuthValidator::Batch();
for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
{ {
@ -4934,7 +4970,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
// check level 1: verify block validity // check level 1: verify block validity
fCheckTransactions = ShouldCheckTransactions(chainparams, pindex); fCheckTransactions = ShouldCheckTransactions(chainparams, pindex);
if (nCheckLevel >= 1 && !CheckBlock(block, state, chainparams, verifier, true, true, fCheckTransactions)) if (nCheckLevel >= 1 && !CheckBlock(block, state, chainparams, verifier, orchardAuth, true, true, fCheckTransactions))
return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 2: verify undo validity // check level 2: verify undo validity

View File

@ -42,6 +42,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <rust/orchard.h>
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
class CBlockIndex; class CBlockIndex;
@ -358,7 +360,8 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
/** Transaction validation functions */ /** Transaction validation functions */
/** Context-independent validity checks */ /** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state, ProofVerifier& verifier); bool CheckTransaction(const CTransaction& tx, CValidationState& state,
ProofVerifier& verifier, orchard::AuthValidator& orchardAuth);
bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state); bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state);
namespace Consensus { namespace Consensus {
@ -464,6 +467,7 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state,
bool CheckBlock(const CBlock& block, CValidationState& state, bool CheckBlock(const CBlock& block, CValidationState& state,
const CChainParams& chainparams, const CChainParams& chainparams,
ProofVerifier& verifier, ProofVerifier& verifier,
orchard::AuthValidator& orchardAuth,
bool fCheckPOW, bool fCheckPOW,
bool fCheckMerkleRoot, bool fCheckMerkleRoot,
bool fCheckTransactions); bool fCheckTransactions);

View File

@ -11,6 +11,8 @@
#include "utiltime.h" #include "utiltime.h"
#include "zcash/Proof.hpp" #include "zcash/Proof.hpp"
#include <rust/orchard.h>
#include <cstdio> #include <cstdio>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
@ -57,7 +59,8 @@ BOOST_AUTO_TEST_CASE(May15)
// After May 15'th, big blocks are OK: // After May 15'th, big blocks are OK:
forkingBlock.nTime = tMay15; // Invalidates PoW forkingBlock.nTime = tMay15; // Invalidates PoW
auto verifier = ProofVerifier::Strict(); auto verifier = ProofVerifier::Strict();
BOOST_CHECK(CheckBlock(forkingBlock, state, Params(), verifier, false, false, true)); auto orchardAuth = orchard::AuthValidator::Disabled(); // Block is before NU5
BOOST_CHECK(CheckBlock(forkingBlock, state, Params(), verifier, orchardAuth, false, false, true));
} }
SetMockTime(0); SetMockTime(0);

View File

@ -34,6 +34,7 @@
#include <boost/test/data/test_case.hpp> #include <boost/test/data/test_case.hpp>
#include <rust/ed25519.h> #include <rust/ed25519.h>
#include <rust/orchard.h>
#include <univalue.h> #include <univalue.h>
@ -68,6 +69,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
std::string comment(""); std::string comment("");
auto verifier = ProofVerifier::Strict(); auto verifier = ProofVerifier::Strict();
auto orchardAuth = orchard::AuthValidator::Batch();
ScriptError err; ScriptError err;
for (size_t idx = 0; idx < tests.size(); idx++) { for (size_t idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx]; UniValue test = tests[idx];
@ -111,7 +113,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
stream >> tx; stream >> tx;
CValidationState state; CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier), strTest + comment); BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier, orchardAuth), strTest + comment);
BOOST_CHECK_MESSAGE(state.IsValid(), comment); BOOST_CHECK_MESSAGE(state.IsValid(), comment);
PrecomputedTransactionData txdata(tx); PrecomputedTransactionData txdata(tx);
@ -156,6 +158,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
std::string comment(""); std::string comment("");
auto verifier = ProofVerifier::Strict(); auto verifier = ProofVerifier::Strict();
auto orchardAuth = orchard::AuthValidator::Batch();
ScriptError err; ScriptError err;
for (size_t idx = 0; idx < tests.size(); idx++) { for (size_t idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx]; UniValue test = tests[idx];
@ -204,7 +207,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
} }
CValidationState state; CValidationState state;
fValid = CheckTransaction(tx, state, verifier) && state.IsValid(); fValid = CheckTransaction(tx, state, verifier, orchardAuth) && state.IsValid();
PrecomputedTransactionData txdata(tx); PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++) for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
@ -243,11 +246,12 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
stream >> tx; stream >> tx;
CValidationState state; CValidationState state;
auto verifier = ProofVerifier::Strict(); auto verifier = ProofVerifier::Strict();
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier) && state.IsValid(), "Simple deserialized transaction should be valid."); auto orchardAuth = orchard::AuthValidator::Disabled(); // No Orchard component
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier, orchardAuth) && state.IsValid(), "Simple deserialized transaction should be valid.");
// Check that duplicate txins fail // Check that duplicate txins fail
tx.vin.push_back(tx.vin[0]); tx.vin.push_back(tx.vin[0]);
BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state, verifier) || !state.IsValid(), "Transaction with duplicate txins should be invalid."); BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state, verifier, orchardAuth) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
} }
// //
@ -424,6 +428,7 @@ void test_simple_sapling_invalidity(uint32_t consensusBranchId, CMutableTransact
void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransaction tx) void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransaction tx)
{ {
auto orchardAuth = orchard::AuthValidator::Disabled(); // No Orchard components
auto verifier = ProofVerifier::Strict(); auto verifier = ProofVerifier::Strict();
{ {
// Ensure that empty vin/vout remain invalid without // Ensure that empty vin/vout remain invalid without
@ -477,26 +482,26 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa
jsdesc->vpub_old = -1; jsdesc->vpub_old = -1;
BOOST_CHECK_THROW((CTransaction(newTx)), std::ios_base::failure); BOOST_CHECK_THROW((CTransaction(newTx)), std::ios_base::failure);
BOOST_CHECK(!CheckTransaction(UNSAFE_CTransaction(newTx), state, verifier)); BOOST_CHECK(!CheckTransaction(UNSAFE_CTransaction(newTx), state, verifier, orchardAuth));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-negative"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-negative");
jsdesc->vpub_old = MAX_MONEY + 1; jsdesc->vpub_old = MAX_MONEY + 1;
BOOST_CHECK_THROW((CTransaction(newTx)), std::ios_base::failure); BOOST_CHECK_THROW((CTransaction(newTx)), std::ios_base::failure);
BOOST_CHECK(!CheckTransaction(UNSAFE_CTransaction(newTx), state, verifier)); BOOST_CHECK(!CheckTransaction(UNSAFE_CTransaction(newTx), state, verifier, orchardAuth));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-toolarge"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-toolarge");
jsdesc->vpub_old = 0; jsdesc->vpub_old = 0;
jsdesc->vpub_new = -1; jsdesc->vpub_new = -1;
BOOST_CHECK_THROW((CTransaction(newTx)), std::ios_base::failure); BOOST_CHECK_THROW((CTransaction(newTx)), std::ios_base::failure);
BOOST_CHECK(!CheckTransaction(UNSAFE_CTransaction(newTx), state, verifier)); BOOST_CHECK(!CheckTransaction(UNSAFE_CTransaction(newTx), state, verifier, orchardAuth));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-negative"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-negative");
jsdesc->vpub_new = MAX_MONEY + 1; jsdesc->vpub_new = MAX_MONEY + 1;
BOOST_CHECK_THROW((CTransaction(newTx)), std::ios_base::failure); BOOST_CHECK_THROW((CTransaction(newTx)), std::ios_base::failure);
BOOST_CHECK(!CheckTransaction(UNSAFE_CTransaction(newTx), state, verifier)); BOOST_CHECK(!CheckTransaction(UNSAFE_CTransaction(newTx), state, verifier, orchardAuth));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-toolarge"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-toolarge");
jsdesc->vpub_new = (MAX_MONEY / 2) + 10; jsdesc->vpub_new = (MAX_MONEY / 2) + 10;
@ -506,7 +511,7 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa
JSDescription *jsdesc2 = &newTx.vJoinSplit[1]; JSDescription *jsdesc2 = &newTx.vJoinSplit[1];
jsdesc2->vpub_new = (MAX_MONEY / 2) + 10; jsdesc2->vpub_new = (MAX_MONEY / 2) + 10;
BOOST_CHECK(!CheckTransaction(newTx, state, verifier)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier, orchardAuth));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-txintotal-toolarge"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-txintotal-toolarge");
} }
{ {
@ -520,7 +525,7 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa
jsdesc->nullifiers[0] = GetRandHash(); jsdesc->nullifiers[0] = GetRandHash();
jsdesc->nullifiers[1] = jsdesc->nullifiers[0]; jsdesc->nullifiers[1] = jsdesc->nullifiers[0];
BOOST_CHECK(!CheckTransaction(newTx, state, verifier)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier, orchardAuth));
BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate"); BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
jsdesc->nullifiers[1] = GetRandHash(); jsdesc->nullifiers[1] = GetRandHash();
@ -532,7 +537,7 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa
jsdesc2->nullifiers[0] = GetRandHash(); jsdesc2->nullifiers[0] = GetRandHash();
jsdesc2->nullifiers[1] = jsdesc->nullifiers[0]; jsdesc2->nullifiers[1] = jsdesc->nullifiers[0];
BOOST_CHECK(!CheckTransaction(newTx, state, verifier)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier, orchardAuth));
BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate"); BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
} }
{ {
@ -551,7 +556,7 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa
CTransaction finalNewTx(newTx); CTransaction finalNewTx(newTx);
BOOST_CHECK(finalNewTx.IsCoinBase()); BOOST_CHECK(finalNewTx.IsCoinBase());
} }
BOOST_CHECK(!CheckTransaction(newTx, state, verifier)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier, orchardAuth));
BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-joinsplits"); BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-joinsplits");
} }
} }

View File

@ -18,6 +18,8 @@
#include "wallet/wallet.h" #include "wallet/wallet.h"
#include "zcash/Proof.hpp" #include "zcash/Proof.hpp"
#include <rust/orchard.h>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <atomic> #include <atomic>
@ -487,8 +489,15 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssValue >> wtx; ssValue >> wtx;
CValidationState state; CValidationState state;
auto verifier = ProofVerifier::Strict(); auto verifier = ProofVerifier::Strict();
if (!(CheckTransaction(wtx, state, verifier) && (wtx.GetHash() == hash) && state.IsValid())) auto orchardAuth = orchard::AuthValidator::Batch();
if (!(
CheckTransaction(wtx, state, verifier, orchardAuth) &&
(wtx.GetHash() == hash) &&
orchardAuth.Validate() &&
state.IsValid())
) {
return false; return false;
}
// Undo serialize changes in 31600 // Undo serialize changes in 31600
if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703) if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)