diff --git a/src/Makefile.am b/src/Makefile.am index 8b08c1f7c..65f17b8d3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -473,6 +473,7 @@ libavian_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(AVIAN_INCLUDES) libavian_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libavian_consensus_a_SOURCES = \ amount.h \ + founder_payment.h \ arith_uint256.cpp \ arith_uint256.h \ consensus/merkle.cpp \ @@ -513,6 +514,7 @@ libavian_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(AVIAN_INCLUDES) libavian_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libavian_common_a_SOURCES = \ base58.cpp \ + founder_payment.cpp \ chainparams.cpp \ coins.cpp \ compressor.cpp \ diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp index 602a545d2..a014bb9e3 100644 --- a/src/bench/checkblock.cpp +++ b/src/bench/checkblock.cpp @@ -50,7 +50,7 @@ static void DeserializeAndCheckBlockTest(benchmark::State& state) assert(stream.Rewind(sizeof(block_bench::block566553))); CValidationState validationState; - assert(CheckBlock(block, validationState, chainParams->GetConsensus())); + assert(CheckBlock(block, validationState, chainParams->GetConsensus(), 0)); } } diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index e3c1ee1bc..a2ae3268a 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -199,7 +199,8 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector< return READ_STATUS_INVALID; CValidationState state; - if (!CheckBlock(block, state, Params().GetConsensus())) { + + if (!CheckBlock(block, state, Params().GetConsensus(), 0)) { // TODO: We really want to just check merkle tree manually here, // but that is expensive, and CheckBlock caches a block's // "checked-status" (in the CBlock?). CBlock should be able to diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 9438b4cfa..85c89de2c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -208,6 +208,12 @@ class CMainParams : public CChainParams { vFixedSeeds = std::vector(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); + // Founder reward + vector rewardStructures = { + {INT_MAX, 5} // 5% founder/dev fee forever + }; + consensus.nFounderPayment = FounderPayment(rewardStructures, 1121000); // Block 1121000 + fDefaultConsistencyChecks = false; fRequireStandard = true; fMineBlocksOnDemand = false; @@ -359,6 +365,12 @@ class CTestNetParams : public CChainParams { vFixedSeeds = std::vector(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); + // Founder reward + vector rewardStructures = { + {INT_MAX, 5} // 5% founder/dev fee forever + }; + consensus.nFounderPayment = FounderPayment(rewardStructures, 150, "n1BurnXXXXXXXXXXXXXXXXXXXXXXU1qejP"); // Block 150 (burn coins) + fDefaultConsistencyChecks = false; fRequireStandard = false; fMineBlocksOnDemand = false; @@ -371,14 +383,11 @@ class CTestNetParams : public CChainParams { }; chainTxData = ChainTxData{ - // Update as we know more about the contents of the Avian chain - // Stats as of 0000cd2943664b4bda8be6e80351f9ff022475ae6a341a868babc4efd846000d block 42000 - 1654349227, // * UNIX timestamp of last known number of transactions - 66085, // * total number of transactions between genesis and that timestamp - // (the tx=... number in the SetBestChain debug.log lines) - 0.001 // * estimated number of transactions per second after that timestamp + 0, + 0, + 0 }; - + /** AVN Start **/ // Burn Amounts nIssueAssetBurnAmount = 500 * COIN; @@ -547,6 +556,12 @@ class CRegTestParams : public CChainParams { assert(consensus.hashGenesisBlock == uint256S("0x653634d03d27ed84e8aba5dd47903906ad7be4876a1d3677be0db2891dcf787f")); assert(genesis.hashMerkleRoot == uint256S("63d9b6b6b549a2d96eb5ac4eb2ab80761e6d7bffa9ae1a647191e08d6416184d")); + // Founder reward + vector rewardStructures = { + {INT_MAX, 5} // 5% founder/dev fee forever + }; + consensus.nFounderPayment = FounderPayment(rewardStructures, 1, "n1BurnXXXXXXXXXXXXXXXXXXXXXXU1qejP"); // Block 1 (burn coins) + vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds. vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds. diff --git a/src/consensus/params.h b/src/consensus/params.h index d3546d209..30141641a 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -1,6 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017 The Raven Core developers +// Copyright (c) 2022 The Avian Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,6 +9,8 @@ #define AVIAN_CONSENSUS_PARAMS_H #include "uint256.h" +#include "founder_payment.h" + #include #include #include @@ -90,6 +93,9 @@ struct ConsensusParams { // AVN Flight Plans uint32_t nFlightPlansActivationTime; + // AVN Founder Payment + FounderPayment nFounderPayment; + // Avian Name System (ANS) uint32_t nAvianNameSystemTime; diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index e0a6d4feb..027a73d19 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2017-2017 The Bitcoin Core developers // Copyright (c) 2017-2020 The Raven Core developers +// Copyright (c) 2022 The Avian Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -166,7 +167,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i return nSigOps; } -bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs, bool fMempoolCheck, bool fBlockCheck) +bool CheckTransaction(const CTransaction& tx, CValidationState &state, int nHeight, CAmount blockReward, bool fCheckDuplicateInputs, bool fMempoolCheck, bool fBlockCheck) { // Basic checks that don't depend on any context if (tx.vin.empty()) @@ -383,10 +384,19 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe for (auto vout : tx.vout) { if (vout.scriptPubKey.IsAssetScript() || vout.scriptPubKey.IsNullAsset()) { return state.DoS(0, error("%s: coinbase contains asset transaction", __func__), - REJECT_INVALID, "bad-txns-coinbase-contains-asset-txes"); + REJECT_INVALID, "bad-txns-coinbase-contains-asset-txes"); } } } + + FounderPayment founderPayment = Params().GetConsensus().nFounderPayment; + CAmount founderReward = founderPayment.getFounderPaymentAmount(nHeight, blockReward); + int founderStartHeight = founderPayment.getStartBlock(); + + // std::cout << "height=" << nHeight << ", reward=" << founderReward << endl; + + if(nHeight > founderStartHeight && founderReward && !founderPayment.IsBlockPayeeValid(tx, nHeight, blockReward)) + return state.DoS(100, false, REJECT_INVALID, "bad-cb-founder-payment-not-found"); } else { diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h index c8d1d1988..3ad1bc4e8 100644 --- a/src/consensus/tx_verify.h +++ b/src/consensus/tx_verify.h @@ -26,7 +26,7 @@ class CNullAssetTxData; /** Transaction validation functions */ /** Context-independent validity checks */ -bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCheckDuplicateInputs=true, bool fMempoolCheck = false, bool fBlockCheck = false); +bool CheckTransaction(const CTransaction& tx, CValidationState& state, int nHeight, CAmount blockReward, bool fCheckDuplicateInputs=true, bool fMempoolCheck = false, bool fBlockCheck = false); namespace Consensus { /** diff --git a/src/founder_payment.cpp b/src/founder_payment.cpp new file mode 100644 index 000000000..bf94fdbf7 --- /dev/null +++ b/src/founder_payment.cpp @@ -0,0 +1,59 @@ +#include "founder_payment.h" + +#include "base58.h" +#include "chainparams.h" +#include "util.h" +#include + +CAmount FounderPayment::getFounderPaymentAmount(int blockHeight, CAmount blockReward) +{ + if (blockHeight <= startBlock) { + return 0; + } + + for (int i = 0; i < rewardStructures.size(); i++) { + FounderRewardStructure rewardStructure = rewardStructures[i]; + if (rewardStructure.blockHeight == INT_MAX || blockHeight <= rewardStructure.blockHeight) { + return blockReward * rewardStructure.rewardPercentage / 100; + } + } + return 0; +} + +void FounderPayment::FillFounderPayment(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutFounderRet) +{ + // Make sure it's not filled yet + CAmount founderPayment = getFounderPaymentAmount(nBlockHeight, blockReward); + // if(founderPayment == 0) { + // LogPrintf("FounderPayment::FillFounderPayment -- Founder payment has not started\n"); + // return; + // } + txoutFounderRet = CTxOut(); + CScript payee; + // Fill payee with the foundFounderRewardStrcutureFounderRewardStrcutureer address + CAvianAddress cbAddress(founderAddress); + payee = GetScriptForDestination(cbAddress.Get()); + // GET FOUNDER PAYMENT VARIABLES SETUP + + // split reward between miner ... + txNew.vout[0].nValue -= founderPayment; + txoutFounderRet = CTxOut(founderPayment, payee); + txNew.vout.push_back(txoutFounderRet); + LogPrintf("FounderPayment::FillFounderPayment -- Founder payment %lld to %s\n", founderPayment, founderAddress.c_str()); +} + +bool FounderPayment::IsBlockPayeeValid(const CTransaction& txNew, const int height, const CAmount blockReward) +{ + CScript payee; + // fill payee with the founder address + payee = GetScriptForDestination(CAvianAddress(founderAddress).Get()); + const CAmount founderReward = getFounderPaymentAmount(height, blockReward); + // std::cout << "founderReward = " << founderReward << endl; + BOOST_FOREACH (const CTxOut& out, txNew.vout) { + if (out.scriptPubKey == payee && out.nValue >= founderReward) { + return true; + } + } + + return false; +} diff --git a/src/founder_payment.h b/src/founder_payment.h new file mode 100644 index 000000000..e6f88750d --- /dev/null +++ b/src/founder_payment.h @@ -0,0 +1,41 @@ +#ifndef AVN_FOUNDER_PAYMENT_H_ +#define AVN_FOUNDER_PAYMENT_H_ + +#include "amount.h" +#include "primitives/transaction.h" +#include "script/standard.h" +#include +#include + +using namespace std; + +static const string DEFAULT_FOUNDER_ADDRESS = "RDs4A4sDHp4otDHQQuFSaPDYEg2xx3hbdN"; + +struct FounderRewardStructure { + int blockHeight; + int rewardPercentage; +}; + +class FounderPayment +{ +public: + FounderPayment(vector rewardStructures = {}, int startBlock = 0, const string& address = DEFAULT_FOUNDER_ADDRESS) + { + this->founderAddress = address; + this->startBlock = startBlock; + this->rewardStructures = rewardStructures; + } + ~FounderPayment(){}; + CAmount getFounderPaymentAmount(int blockHeight, CAmount blockReward); + void FillFounderPayment(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutFounderRet); + bool IsBlockPayeeValid(const CTransaction& txNew, const int height, const CAmount blockReward); + int getStartBlock() { return this->startBlock; } + +private: + string founderAddress; + int startBlock; + vector rewardStructures; +}; + + +#endif /* AVN_FOUNDER_PAYMENT_H_ */ diff --git a/src/miner.cpp b/src/miner.cpp index 25b3c3e55..a2cf29f22 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -197,6 +197,14 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn; coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus()); coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0; + + // NOTE: unlike in bitcoin, we need to pass PREVIOUS block height here + CAmount blockReward = nFees + GetBlockSubsidy(pindexPrev->nHeight, Params().GetConsensus()); + + // Fill founder payment + FounderPayment founderPayment = chainparams.GetConsensus().nFounderPayment; + founderPayment.FillFounderPayment(coinbaseTx, nHeight, blockReward, pblock->txoutFounder); + pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx)); pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus()); pblocktemplate->vTxFees[0] = -nFees; diff --git a/src/primitives/block.h b/src/primitives/block.h index d3a8b343d..fa2254655 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -134,6 +134,9 @@ class CBlock : public CBlockHeader // network and disk std::vector vtx; + // founder payment + mutable CTxOut txoutFounder; + // memory only mutable bool fChecked; @@ -161,6 +164,7 @@ class CBlock : public CBlockHeader CBlockHeader::SetNull(); vtx.clear(); fChecked = false; + txoutFounder = CTxOut(); } CBlockHeader GetBlockHeader() const diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 9782d786f..8f06e7127 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -697,6 +697,19 @@ UniValue getblocktemplate(const JSONRPCRequest& request) UniValue result(UniValue::VOBJ); result.push_back(Pair("capabilities", aCaps)); + UniValue founderObj(UniValue::VOBJ); + FounderPayment founderPayment = Params().GetConsensus().nFounderPayment; + if(pblock->txoutFounder!= CTxOut()) { + CTxDestination address; + ExtractDestination(pblock->txoutFounder.scriptPubKey, address); + CAvianAddress address2(address); + founderObj.push_back(Pair("payee", address2.ToString().c_str())); + founderObj.push_back(Pair("script", HexStr(pblock->txoutFounder.scriptPubKey.begin(), pblock->txoutFounder.scriptPubKey.end()))); + founderObj.push_back(Pair("amount", pblock->txoutFounder.nValue)); + } + result.push_back(Pair("founder", founderObj)); + result.push_back(Pair("founder_payments_started", pindexPrev->nHeight + 1 > founderPayment.getStartBlock())); + UniValue aRules(UniValue::VARR); UniValue vbavailable(UniValue::VOBJ); for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) { diff --git a/src/test/assets/asset_tx_tests.cpp b/src/test/assets/asset_tx_tests.cpp index f87277668..86b92271e 100644 --- a/src/test/assets/asset_tx_tests.cpp +++ b/src/test/assets/asset_tx_tests.cpp @@ -528,7 +528,7 @@ BOOST_FIXTURE_TEST_SUITE(asset_tx_tests, BasicTestingSetup) bool fCheckBlock = false; // Check that the CheckTransaction will fail when trying to add it to the mempool - bool fCheck = !CheckTransaction(tx, state, true, fCheckMempool, fCheckBlock); + bool fCheck = !CheckTransaction(tx, state, 0, 0, true, fCheckMempool, fCheckBlock); BOOST_CHECK(fCheck); BOOST_CHECK(state.GetRejectReason() == "bad-mempool-txns-asset-reissued-amount-isn't-zero"); @@ -539,7 +539,7 @@ BOOST_FIXTURE_TEST_SUITE(asset_tx_tests, BasicTestingSetup) // Turn on the BIP that enforces the block check SetEnforcedValues(true); - fCheck = !CheckTransaction(tx, state, true, fCheckMempool, fCheckBlock); + fCheck = !CheckTransaction(tx, state, 0, 0, true, fCheckMempool, fCheckBlock); BOOST_CHECK(fCheck); BOOST_CHECK(state.GetRejectReason() == "bad-txns-asset-reissued-amount-isn't-zero"); } @@ -591,14 +591,14 @@ BOOST_FIXTURE_TEST_SUITE(asset_tx_tests, BasicTestingSetup) // Setting the coinbase check to true // This check should now fail on the CheckTransaction call SetEnforcedCoinbase(true); - bool fCheck = CheckTransaction(tx, state, true); + bool fCheck = CheckTransaction(tx, state, 0, 0, true); BOOST_CHECK(!fCheck); BOOST_CHECK(state.GetRejectReason() == "bad-txns-coinbase-contains-asset-txes"); // Setting the coinbase check to false // This check should now pass the CheckTransaction call SetEnforcedCoinbase(false); - fCheck = CheckTransaction(tx, state, true); + fCheck = CheckTransaction(tx, state, 0, 0, true); BOOST_CHECK(fCheck); // Remove wallet used for testing diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 211e6f42e..4363b8431 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -205,7 +205,7 @@ BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup) stream >> tx; CValidationState state; - BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest); + BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state, 0, 0), strTest); BOOST_CHECK(state.IsValid()); std::vector raw = ParseHex(raw_script); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 7609e4de0..4c5f0d5db 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -160,7 +160,7 @@ BOOST_FIXTURE_TEST_SUITE(transaction_tests, BasicTestingSetup) CTransaction tx(deserialize, stream); CValidationState state; - BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); + BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, 0, 0), strTest); BOOST_CHECK(state.IsValid()); PrecomputedTransactionData txdata(tx); @@ -252,7 +252,7 @@ BOOST_FIXTURE_TEST_SUITE(transaction_tests, BasicTestingSetup) CTransaction tx(deserialize, stream); CValidationState state; - fValid = CheckTransaction(tx, state) && state.IsValid(); + fValid = CheckTransaction(tx, state, 0, 0) && state.IsValid(); PrecomputedTransactionData txdata(tx); for (unsigned int i = 0; i < tx.vin.size() && fValid; i++) @@ -290,11 +290,11 @@ BOOST_FIXTURE_TEST_SUITE(transaction_tests, BasicTestingSetup) CMutableTransaction tx; stream >> tx; CValidationState state; - BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid."); + BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, 0, 0) && state.IsValid(), "Simple deserialized transaction should be valid."); // Check that duplicate txins fail tx.vin.push_back(tx.vin[0]); - BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state) || !state.IsValid(), "Transaction with duplicate txins should be invalid."); + BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state, 0, 0) || !state.IsValid(), "Transaction with duplicate txins should be invalid."); } // diff --git a/src/txmempool.cpp b/src/txmempool.cpp index db8e8af34..4b13d1c0f 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -889,7 +889,7 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigne indexed_transaction_set::iterator i = mapTx.find(hash); if (i != mapTx.end()) { CValidationState state; - if (!setAlreadyRemoving.count(hash) && !CheckTransaction(i->GetTx(), state, passets)) { + if (!setAlreadyRemoving.count(hash) && !CheckTransaction(i->GetTx(), state, 0, 0, passets)) { entries.push_back(&*i); trans.emplace_back(i->GetTx()); setAlreadyRemoving.insert(hash); @@ -905,7 +905,7 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigne indexed_transaction_set::iterator i = mapTx.find(hash); if (i != mapTx.end()) { CValidationState state; - if (!setAlreadyRemoving.count(hash) && !CheckTransaction(i->GetTx(), state, passets)) { + if (!setAlreadyRemoving.count(hash) && !CheckTransaction(i->GetTx(), state, 0, 0, passets)) { entries.push_back(&*i); trans.emplace_back(i->GetTx()); setAlreadyRemoving.insert(hash); @@ -922,7 +922,7 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigne indexed_transaction_set::iterator i = mapTx.find(hash); if (i != mapTx.end()) { CValidationState state; - if (!setAlreadyRemoving.count(hash) && !CheckTransaction(i->GetTx(), state, passets)) { + if (!setAlreadyRemoving.count(hash) && !CheckTransaction(i->GetTx(), state, 0, 0, passets)) { entries.push_back(&*i); trans.emplace_back(i->GetTx()); setAlreadyRemoving.insert(hash); diff --git a/src/validation.cpp b/src/validation.cpp index 6ca0a9fcb..f6f53fbdf 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -549,7 +549,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool bool fCheckDuplicates = true; bool fCheckMempool = true; - if (!CheckTransaction(tx, state, fCheckDuplicates, fCheckMempool)) + if (!CheckTransaction(tx, state, 0, 0, fCheckDuplicates, fCheckMempool)) return false; // state filled in by CheckTransaction // Coinbase is only valid in a block, not as a loose transaction @@ -2445,7 +2445,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd int64_t nTimeStart = GetTimeMicros(); // Check it again in case a previous version let a bad block in - if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck)) // Force the check of asset duplicates when connecting the block + if (!CheckBlock(block, state, chainparams.GetConsensus(), 0, !fJustCheck, !fJustCheck)) // Force the check of asset duplicates when connecting the block return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); // verify that the view's current state corresponds to the previous block @@ -2798,6 +2798,11 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd block.vtx[0]->GetValueOut(AreEnforcedValuesDeployed()), blockReward), REJECT_INVALID, "bad-cb-amount"); + FounderPayment founderPayment = Params().GetConsensus().nFounderPayment; + if (!founderPayment.IsBlockPayeeValid(*block.vtx[0], pindex->nHeight, blockReward)) + return state.DoS(0, error("ConnectBlock(): couldn't find founders fee payments"), + REJECT_INVALID, "bad-cb-payee"); + if (!control.Wait()) return state.DoS(100, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed"); int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; @@ -4001,7 +4006,7 @@ static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, return true; } -bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::ConsensusParams& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckAssetDuplicate, bool fForceDuplicateCheck) +bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::ConsensusParams& consensusParams, int nHeight, bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckAssetDuplicate, bool fForceDuplicateCheck) { // These are checks that are independent of context. @@ -4043,17 +4048,17 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::C for (unsigned int i = 1; i < block.vtx.size(); i++) if (block.vtx[i]->IsCoinBase()) return state.DoS(100, false, REJECT_INVALID, "bad-cb-multiple", false, "more than one coinbase"); - // Check transactions bool fCheckBlock = CHECK_BLOCK_TRANSACTION_TRUE; bool fCheckDuplicates = CHECK_DUPLICATE_TRANSACTION_TRUE; bool fCheckMempool = CHECK_MEMPOOL_TRANSACTION_FALSE; + CAmount blockReward = GetBlockSubsidy(nHeight - 1, Params().GetConsensus()); for (const auto& tx : block.vtx) { // We only want to check the blocks when they are added to our chain // We want to make sure when nodes shutdown and restart that they still // verify the blocks in the database correctly even if Enforce Value BIP is active fCheckBlock = CHECK_BLOCK_TRANSACTION_TRUE; - if (!CheckTransaction(*tx, state, fCheckDuplicates, fCheckMempool, fCheckBlock)) + if (!CheckTransaction(*tx, state, nHeight - 1, blockReward, fCheckDuplicates, fCheckMempool, fCheckBlock)) return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), strprintf("Transaction check failed (tx hash %s) %s %s", tx->GetHash().ToString(), state.GetDebugMessage(), state.GetRejectReason())); @@ -4514,7 +4519,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr> wtx; CValidationState state; - if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid())) { + if (!(CheckTransaction(wtx, state, 0, 0) && (wtx.GetHash() == hash) && state.IsValid())) { // If a client has a wallet.dat that contains asset transactions, but we are syncing the chain. // we want to make sure that we don't fail to load this wallet transaction just because it is an asset transaction // before asset are active