diff --git a/src/avalanche/peermanager.cpp b/src/avalanche/peermanager.cpp --- a/src/avalanche/peermanager.cpp +++ b/src/avalanche/peermanager.cpp @@ -234,9 +234,7 @@ // Check the proof's validity. ProofValidationState validationState; - if (!WITH_LOCK(cs_main, return proof->verify( - validationState, - chainman.ActiveChainstate().CoinsTip()))) { + if (!proof->verify(validationState, chainman)) { if (isOrphanState(validationState)) { // Only accept orphan proofs if there's room in the orphan pool. auto status = orphanProofPool.addProofIfNoConflict(proof); @@ -450,18 +448,13 @@ std::vector invalidProofIds; std::vector newOrphans; - { - LOCK(cs_main); - - const CCoinsViewCache &coins = chainman.ActiveChainstate().CoinsTip(); - for (const auto &p : peers) { - ProofValidationState state; - if (!p.proof->verify(state, coins)) { - if (isOrphanState(state)) { - newOrphans.push_back(p.proof); - } - invalidProofIds.push_back(p.getProofId()); + for (const auto &p : peers) { + ProofValidationState state; + if (!p.proof->verify(state, chainman)) { + if (isOrphanState(state)) { + newOrphans.push_back(p.proof); } + invalidProofIds.push_back(p.getProofId()); } } diff --git a/src/avalanche/proof.h b/src/avalanche/proof.h --- a/src/avalanche/proof.h +++ b/src/avalanche/proof.h @@ -19,7 +19,7 @@ #include class ArgsManager; -class CCoinsView; +class ChainstateManager; struct bilingual_str; /** @@ -189,7 +189,8 @@ Amount getStakedAmount() const; bool verify(ProofValidationState &state) const; - bool verify(ProofValidationState &state, const CCoinsView &view) const; + bool verify(ProofValidationState &state, + const ChainstateManager &chainman) const; }; using ProofRef = RCUPtr; diff --git a/src/avalanche/proof.cpp b/src/avalanche/proof.cpp --- a/src/avalanche/proof.cpp +++ b/src/avalanche/proof.cpp @@ -13,7 +13,7 @@ #include #include #include -#include // For g_chainman +#include // For ChainstateManager #include @@ -180,14 +180,13 @@ return true; } -bool Proof::verify(ProofValidationState &state, const CCoinsView &view) const { +bool Proof::verify(ProofValidationState &state, + const ChainstateManager &chainman) const { if (!verify(state)) { // state is set by verify. return false; } - const int64_t activeHeight = - WITH_LOCK(cs_main, return g_chainman.ActiveHeight()); const int64_t stakeUtxoMinConfirmations = gArgs.GetArg("-avaproofstakeutxoconfirmations", AVALANCHE_DEFAULT_STAKE_UTXO_CONFIRMATIONS); @@ -197,10 +196,16 @@ const COutPoint &utxo = s.getUTXO(); Coin coin; - if (!view.GetCoin(utxo, coin)) { - // The coins are not in the UTXO set. - return state.Invalid(ProofValidationResult::MISSING_UTXO, - "utxo-missing-or-spent"); + int64_t activeHeight; + { + LOCK(cs_main); + if (!chainman.ActiveChainstate().CoinsTip().GetCoin(utxo, coin)) { + // The coins are not in the UTXO set. + return state.Invalid(ProofValidationResult::MISSING_UTXO, + "utxo-missing-or-spent"); + } + + activeHeight = chainman.ActiveHeight(); } if ((s.getHeight() + stakeUtxoMinConfirmations - 1) > activeHeight) { diff --git a/src/avalanche/test/proof_tests.cpp b/src/avalanche/test/proof_tests.cpp --- a/src/avalanche/test/proof_tests.cpp +++ b/src/avalanche/test/proof_tests.cpp @@ -889,8 +889,6 @@ BOOST_AUTO_TEST_CASE(verify) { gArgs.ForceSetArg("-avaproofstakeutxoconfirmations", "1"); - CCoinsView coinsDummy; - CCoinsViewCache coins(&coinsDummy); auto key = CKey::MakeCompressedKey(); const CPubKey pubkey = key.GetPubKey(); @@ -898,18 +896,25 @@ const Amount value = 12345 * COIN; const uint32_t height = 10; + ChainstateManager &chainman = *Assert(m_node.chainman); + + auto addCoin = [&](const COutPoint &outpoint, const Coin &coin) { + LOCK(cs_main); + chainman.ActiveChainstate().CoinsTip().AddCoin(outpoint, coin, false); + }; + COutPoint pkh_outpoint(TxId(InsecureRand256()), InsecureRand32()); CTxOut pkh_output(value, GetScriptForRawPubKey(pubkey)); - coins.AddCoin(pkh_outpoint, Coin(pkh_output, height, false), false); + addCoin(pkh_outpoint, Coin(pkh_output, height, false)); COutPoint nonstd_outpoint(TxId(InsecureRand256()), InsecureRand32()); CTxOut nonstd_output(value, CScript() << OP_TRUE); - coins.AddCoin(nonstd_outpoint, Coin(nonstd_output, height, false), false); + addCoin(nonstd_outpoint, Coin(nonstd_output, height, false)); COutPoint p2sh_outpoint(TxId(InsecureRand256()), InsecureRand32()); CTxOut p2sh_output(value, GetScriptForDestination(ScriptHash(InsecureRand160()))); - coins.AddCoin(p2sh_outpoint, Coin(p2sh_output, height, false), false); + addCoin(p2sh_outpoint, Coin(p2sh_output, height, false)); const auto runCheck = [&](const ProofValidationResult result, const COutPoint &o, const Amount v, @@ -922,7 +927,7 @@ ProofValidationState state; BOOST_CHECK(p->verify(state)); - BOOST_CHECK(p->verify(state, coins) == + BOOST_CHECK(p->verify(state, chainman) == (result == ProofValidationResult::NONE)); BOOST_CHECK(state.GetResult() == result); }; @@ -970,7 +975,7 @@ ProofRef p = ProofBuilder(0, 0, key).build(); ProofValidationState state; - BOOST_CHECK(!p->verify(state, coins)); + BOOST_CHECK(!p->verify(state, chainman)); BOOST_CHECK(state.GetResult() == ProofValidationResult::NO_STAKE); } @@ -982,7 +987,7 @@ ProofRef p = pb.build(); ProofValidationState state; - BOOST_CHECK(!p->verify(state, coins)); + BOOST_CHECK(!p->verify(state, chainman)); BOOST_CHECK(state.GetResult() == ProofValidationResult::DUST_THRESOLD); } @@ -993,7 +998,7 @@ ProofRef p = pb.build(); ProofValidationState state; - BOOST_CHECK(!p->verify(state, coins)); + BOOST_CHECK(!p->verify(state, chainman)); BOOST_CHECK(state.GetResult() == ProofValidationResult::DUST_THRESOLD); } @@ -1004,7 +1009,7 @@ ProofRef p = TestProofBuilder::buildDuplicatedStakes(pb); ProofValidationState state; - BOOST_CHECK(!p->verify(state, coins)); + BOOST_CHECK(!p->verify(state, chainman)); BOOST_CHECK(state.GetResult() == ProofValidationResult::DUPLICATE_STAKE); } @@ -1013,8 +1018,7 @@ { COutPoint other_pkh_outpoint(TxId(InsecureRand256()), InsecureRand32()); CTxOut other_pkh_output(value, GetScriptForRawPubKey(pubkey)); - coins.AddCoin(other_pkh_outpoint, Coin(other_pkh_output, height, false), - false); + addCoin(other_pkh_outpoint, Coin(other_pkh_output, height, false)); ProofBuilder pb(0, 0, key); BOOST_CHECK(pb.addUTXO(pkh_outpoint, value, height, false, key)); @@ -1022,7 +1026,7 @@ ProofRef p = TestProofBuilder::buildWithReversedOrderStakes(pb); ProofValidationState state; - BOOST_CHECK(!p->verify(state, coins)); + BOOST_CHECK(!p->verify(state, chainman)); BOOST_CHECK(state.GetResult() == ProofValidationResult::WRONG_STAKE_ORDERING); } @@ -1042,7 +1046,7 @@ h, false, key); // Add the coin to the UTXO set to verify it's immature - coins.AddCoin(outpoint, Coin(output, h, false), false); + addCoin(outpoint, Coin(output, h, false)); runCheck(ProofValidationResult::IMMATURE_UTXO, outpoint, value, h, false, key); } @@ -1067,7 +1071,7 @@ const uint32_t stakeConfs = std::get<0>(*it); COutPoint outpoint(TxId(InsecureRand256()), InsecureRand32()); CTxOut output(value, GetScriptForRawPubKey(pubkey)); - coins.AddCoin(outpoint, Coin(output, stakeConfs, false), false); + addCoin(outpoint, Coin(output, stakeConfs, false)); gArgs.ForceSetArg("-avaproofstakeutxoconfirmations", std::get<1>(*it)); @@ -1078,9 +1082,6 @@ } BOOST_AUTO_TEST_CASE(deterministic_proofid) { - CCoinsView coinsDummy; - CCoinsViewCache coins(&coinsDummy); - auto key = CKey::MakeCompressedKey(); const Amount value = 12345 * COIN; diff --git a/src/rpc/avalanche.cpp b/src/rpc/avalanche.cpp --- a/src/rpc/avalanche.cpp +++ b/src/rpc/avalanche.cpp @@ -84,9 +84,7 @@ avalanche::ProofValidationState state; { - LOCK(cs_main); - if (!proof.verify(state, - node.chainman->ActiveChainstate().CoinsTip())) { + if (!proof.verify(state, *Assert(node.chainman))) { throw JSONRPCError(RPC_INVALID_PARAMETER, "The proof is invalid: " + state.ToString()); }