static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams) { int maxHalvings = 64; CAmount nInitialSubsidy = 50 * COIN; CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 0 BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2); for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) { int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval; CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); BOOST_CHECK(nSubsidy <= nInitialSubsidy); BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2); nPreviousSubsidy = nSubsidy; } BOOST_CHECK_EQUAL(GetBlockSubsidy(maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), 0); }
// Test that a Sprout tx with negative version is still rejected // by CheckBlock under Sprout consensus rules. TEST(CheckBlock, BlockSproutRejectsBadVersion) { SelectParams(CBaseChainParams::MAIN); CMutableTransaction mtx; mtx.vin.resize(1); mtx.vin[0].prevout.SetNull(); mtx.vin[0].scriptSig = CScript() << 1 << OP_0; mtx.vout.resize(1); mtx.vout[0].scriptPubKey = CScript() << OP_TRUE; mtx.vout[0].nValue = 0; mtx.vout.push_back(CTxOut( GetBlockSubsidy(1, Params().GetConsensus())/5, Params().GetFoundersRewardScriptAtHeight(1))); mtx.fOverwintered = false; mtx.nVersion = -1; mtx.nVersionGroupId = 0; CTransaction tx {mtx}; CBlock block; block.vtx.push_back(tx); MockCValidationState state; CBlockIndex indexPrev {Params().GenesisBlock()}; auto verifier = libzcash::ProofVerifier::Strict(); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-version-too-low", false)).Times(1); EXPECT_FALSE(CheckBlock(block, state, verifier, false, false)); }
static void DuplicateInputs(benchmark::State& state) { const CScript SCRIPT_PUB{CScript(OP_TRUE)}; const CChainParams& chainparams = Params(); CBlock block{}; CMutableTransaction coinbaseTx{}; CMutableTransaction naughtyTx{}; CBlockIndex* pindexPrev = ::ChainActive().Tip(); assert(pindexPrev != nullptr); block.nBits = GetNextWorkRequired(pindexPrev, &block, chainparams.GetConsensus()); block.nNonce = 0; auto nHeight = pindexPrev->nHeight + 1; // Make a coinbase TX coinbaseTx.vin.resize(1); coinbaseTx.vin[0].prevout.SetNull(); coinbaseTx.vout.resize(1); coinbaseTx.vout[0].scriptPubKey = SCRIPT_PUB; coinbaseTx.vout[0].nValue = GetBlockSubsidy(nHeight, chainparams.GetConsensus()); coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0; naughtyTx.vout.resize(1); naughtyTx.vout[0].nValue = 0; naughtyTx.vout[0].scriptPubKey = SCRIPT_PUB; uint64_t n_inputs = (((MAX_BLOCK_SERIALIZED_SIZE / WITNESS_SCALE_FACTOR) - (CTransaction(coinbaseTx).GetTotalSize() + CTransaction(naughtyTx).GetTotalSize())) / 41) - 100; for (uint64_t x = 0; x < (n_inputs - 1); ++x) { naughtyTx.vin.emplace_back(GetRandHash(), 0, CScript(), 0); } naughtyTx.vin.emplace_back(naughtyTx.vin.back()); block.vtx.push_back(MakeTransactionRef(std::move(coinbaseTx))); block.vtx.push_back(MakeTransactionRef(std::move(naughtyTx))); block.hashMerkleRoot = BlockMerkleRoot(block); while (state.KeepRunning()) { CValidationState cvstate{}; assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false)); assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate"); } }
CAmount CSuperblock::GetPaymentsLimit(int nBlockHeight) { const Consensus::Params& consensusParams = Params().GetConsensus(); if (!IsValidBlockHeight(nBlockHeight)) { return 0; } // min subsidy for high diff networks and vice versa int nBits = consensusParams.fPowAllowMinDifficultyBlocks ? UintToArith256(consensusParams.powLimit).GetCompact() : 1; // some part of all blocks issued during the cycle goes to superblock, see GetBlockSubsidy CAmount nSuperblockPartOfSubsidy = GetBlockSubsidy(nBits, nBlockHeight - 1, consensusParams, true); CAmount nPaymentsLimit = nSuperblockPartOfSubsidy * consensusParams.nSuperblockCycle; LogPrint("gobject", "CSuperblock::GetPaymentsLimit -- Valid superblock height %d, payments max %lld\n", nBlockHeight, nPaymentsLimit); return nPaymentsLimit; }
TEST_F(ContextualCheckBlockTest, BadCoinbaseHeight) { // Put a transaction in a block with no height in scriptSig CMutableTransaction mtx = GetFirstBlockCoinbaseTx(); mtx.vin[0].scriptSig = CScript() << OP_0; mtx.vout.pop_back(); // remove the FR output CBlock block; block.vtx.push_back(mtx); // Treating block as genesis should pass MockCValidationState state; EXPECT_TRUE(ContextualCheckBlock(block, state, NULL)); // Give the transaction a Founder's Reward vout mtx.vout.push_back(CTxOut( GetBlockSubsidy(1, Params().GetConsensus())/5, Params().GetFoundersRewardScriptAtHeight(1))); // Treating block as non-genesis should fail CTransaction tx2 {mtx}; block.vtx[0] = tx2; CBlock prev; CBlockIndex indexPrev {prev}; indexPrev.nHeight = 0; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-height", false)).Times(1); EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev)); // Setting to an incorrect height should fail mtx.vin[0].scriptSig = CScript() << 2 << OP_0; CTransaction tx3 {mtx}; block.vtx[0] = tx3; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-height", false)).Times(1); EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev)); // After correcting the scriptSig, should pass mtx.vin[0].scriptSig = CScript() << 1 << OP_0; CTransaction tx4 {mtx}; block.vtx[0] = tx4; EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev)); }
// Returns a valid but empty mutable transaction at block height 1. CMutableTransaction GetFirstBlockCoinbaseTx() { CMutableTransaction mtx; // No inputs. mtx.vin.resize(1); mtx.vin[0].prevout.SetNull(); // Set height to 1. mtx.vin[0].scriptSig = CScript() << 1 << OP_0; // Give it a single zero-valued, always-valid output. mtx.vout.resize(1); mtx.vout[0].scriptPubKey = CScript() << OP_TRUE; mtx.vout[0].nValue = 0; // Give it a Founder's Reward vout for height 1. mtx.vout.push_back(CTxOut( GetBlockSubsidy(1, Params().GetConsensus())/5, Params().GetFoundersRewardScriptAtHeight(1))); return mtx; }
CBlockTemplate* CreateNewBlock(CAccountViewCache &view, CTransactionDBCache &txCache, CScriptDBViewCache &scriptCache){ // // Create new block auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate()); if (!pblocktemplate.get()) return NULL; CBlock *pblock = &pblocktemplate->block; // pointer for convenience // Create coinbase tx CRewardTransaction rtx; // Add our coinbase tx as first transaction pblock->vptx.push_back(make_shared<CRewardTransaction>(rtx)); pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOps.push_back(-1); // updated at end // Largest block you're willing to create: unsigned int nBlockMaxSize = SysCfg().GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: nBlockMaxSize = max((unsigned int) 1000, min((unsigned int) (MAX_BLOCK_SIZE - 1000), nBlockMaxSize)); // How much of the block should be dedicated to high-priority transactions, // included regardless of the fees they pay unsigned int nBlockPrioritySize = SysCfg().GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE); nBlockPrioritySize = min(nBlockMaxSize, nBlockPrioritySize); // Minimum block size you want to create; block will be filled with free transactions // until there are no more or the block reaches this size: unsigned int nBlockMinSize = SysCfg().GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE); nBlockMinSize = min(nBlockMaxSize, nBlockMinSize); // Collect memory pool transactions into the block int64_t nFees = 0; { LOCK2(cs_main, mempool.cs); CBlockIndex* pIndexPrev = chainActive.Tip(); pblock->SetFuelRate(GetElementForBurn(pIndexPrev)); // This vector will be sorted into a priority queue: vector<TxPriority> vecPriority; GetPriorityTx(vecPriority, pblock->GetFuelRate()); // Collect transactions into block uint64_t nBlockSize = ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION); uint64_t nBlockTx(0); bool fSortedByFee(true); uint64_t nTotalRunStep(0); int64_t nTotalFuel(0); TxPriorityCompare comparer(fSortedByFee); make_heap(vecPriority.begin(), vecPriority.end(), comparer); while (!vecPriority.empty()) { // Take highest priority transaction off the priority queue: double dPriority = vecPriority.front().get<0>(); double dFeePerKb = vecPriority.front().get<1>(); shared_ptr<CBaseTransaction> stx = vecPriority.front().get<2>(); CBaseTransaction *pBaseTx = stx.get(); //const CTransaction& tx = *(vecPriority.front().get<2>()); pop_heap(vecPriority.begin(), vecPriority.end(), comparer); vecPriority.pop_back(); // Size limits unsigned int nTxSize = ::GetSerializeSize(*pBaseTx, SER_NETWORK, PROTOCOL_VERSION); if (nBlockSize + nTxSize >= nBlockMaxSize) continue; // Skip free transactions if we're past the minimum block size: if (fSortedByFee && (dFeePerKb < CTransaction::nMinRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; // Prioritize by fee once past the priority size or we run out of high-priority // transactions: if (!fSortedByFee && ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority))) { fSortedByFee = true; comparer = TxPriorityCompare(fSortedByFee); make_heap(vecPriority.begin(), vecPriority.end(), comparer); } if(uint256() != std::move(txCache.IsContainTx(std::move(pBaseTx->GetHash())))) { LogPrint("INFO","CreatePosTx duplicate tx\n"); continue; } CTxUndo txundo; CValidationState state; if(pBaseTx->IsCoinBase()){ ERRORMSG("TX type is coin base tx error......"); // assert(0); //never come here } if (CONTRACT_TX == pBaseTx->nTxType) { LogPrint("vm", "tx hash=%s CreateNewBlock run contract\n", pBaseTx->GetHash().GetHex()); } CAccountViewCache viewTemp(view, true); CScriptDBViewCache scriptCacheTemp(scriptCache, true); pBaseTx->nFuelRate = pblock->GetFuelRate(); if (!pBaseTx->ExecuteTx(nBlockTx + 1, viewTemp, state, txundo, pIndexPrev->nHeight + 1, txCache, scriptCacheTemp)) { continue; } // Run step limits if(nTotalRunStep + pBaseTx->nRunStep >= MAX_BLOCK_RUN_STEP) continue; assert(viewTemp.Flush()); assert(scriptCacheTemp.Flush()); nFees += pBaseTx->GetFee(); nBlockSize += stx->GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION); nTotalRunStep += pBaseTx->nRunStep; nTotalFuel += pBaseTx->GetFuel(pblock->GetFuelRate()); nBlockTx++; pblock->vptx.push_back(stx); LogPrint("fuel", "miner total fuel:%d, tx fuel:%d runStep:%d fuelRate:%d txhash:%s\n",nTotalFuel, pBaseTx->GetFuel(pblock->GetFuelRate()), pBaseTx->nRunStep, pblock->GetFuelRate(), pBaseTx->GetHash().GetHex()); } nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; LogPrint("INFO","CreateNewBlock(): total size %u\n", nBlockSize); assert(nFees-nTotalFuel >= 0); ((CRewardTransaction*) pblock->vptx[0].get())->rewardValue = nFees - nTotalFuel + GetBlockSubsidy(pIndexPrev->nHeight + 1); // Fill in header pblock->SetHashPrevBlock(pIndexPrev->GetBlockHash()); UpdateTime(*pblock, pIndexPrev); pblock->SetBits(GetNextWorkRequired(pIndexPrev, pblock)); pblock->SetNonce(0); pblock->SetHeight(pIndexPrev->nHeight + 1); pblock->SetFuel(nTotalFuel); } return pblocktemplate.release(); }
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx) { int64_t nTimeStart = GetTimeMicros(); resetBlock(); pblocktemplate.reset(new CBlockTemplate()); if(!pblocktemplate.get()) return nullptr; pblock = &pblocktemplate->block; // pointer for convenience // Add dummy coinbase tx as first transaction pblock->vtx.emplace_back(); pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end LOCK2(cs_main, mempool.cs); CBlockIndex* pindexPrev = chainActive.Tip(); assert(pindexPrev != nullptr); nHeight = pindexPrev->nHeight + 1; pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios if (chainparams.MineBlocksOnDemand()) pblock->nVersion = gArgs.GetArg("-blockversion", pblock->nVersion); pblock->nTime = GetAdjustedTime(); const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) ? nMedianTimePast : pblock->GetBlockTime(); // Decide whether to include witness transactions // This is only needed in case the witness softfork activation is reverted // (which would require a very deep reorganization) or when // -promiscuousmempoolflags is used. // TODO: replace this with a call to main to assess validity of a mempool // transaction (which in most cases can be a no-op). fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()) && fMineWitnessTx; int nPackagesSelected = 0; int nDescendantsUpdated = 0; addPackageTxs(nPackagesSelected, nDescendantsUpdated); int64_t nTime1 = GetTimeMicros(); nLastBlockTx = nBlockTx; nLastBlockWeight = nBlockWeight; // Create coinbase transaction. CMutableTransaction coinbaseTx; coinbaseTx.vin.resize(1); coinbaseTx.vin[0].prevout.SetNull(); coinbaseTx.vout.resize(1); coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn; coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus()); coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0; pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx)); pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus()); pblocktemplate->vTxFees[0] = -nFees; LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost); // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]); CValidationState state; if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); } int64_t nTime2 = GetTimeMicros(); LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart)); return std::move(pblocktemplate); }