diff --git a/src/miner.cpp b/src/miner.cpp
index 655d0c704..11cb03287 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -1,577 +1,580 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <miner.h>
 
 #include <amount.h>
 #include <chain.h>
 #include <chainparams.h>
 #include <coins.h>
 #include <config.h>
 #include <consensus/activation.h>
 #include <consensus/consensus.h>
 #include <consensus/merkle.h>
 #include <consensus/tx_verify.h>
 #include <consensus/validation.h>
 #include <minerfund.h>
 #include <net.h>
 #include <policy/policy.h>
 #include <policy/settings.h>
 #include <pow/pow.h>
 #include <primitives/transaction.h>
 #include <timedata.h>
 #include <util/moneystr.h>
 #include <util/system.h>
 #include <validation.h>
 
 #include <algorithm>
 #include <utility>
 
 int64_t UpdateTime(CBlockHeader *pblock, const CChainParams &chainParams,
                    const CBlockIndex *pindexPrev) {
     int64_t nOldTime = pblock->nTime;
     int64_t nNewTime =
         std::max(pindexPrev->GetMedianTimePast() + 1, GetAdjustedTime());
 
     if (nOldTime < nNewTime) {
         pblock->nTime = nNewTime;
     }
 
     // Updating time can change work required on testnet:
     if (chainParams.GetConsensus().fPowAllowMinDifficultyBlocks) {
         pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainParams);
     }
 
     return nNewTime - nOldTime;
 }
 
 uint64_t CTxMemPoolModifiedEntry::GetVirtualSizeWithAncestors() const {
     return GetVirtualTransactionSize(nSizeWithAncestors,
                                      nSigOpCountWithAncestors);
 }
 
 BlockAssembler::Options::Options()
     : nExcessiveBlockSize(DEFAULT_MAX_BLOCK_SIZE),
       nMaxGeneratedBlockSize(DEFAULT_MAX_GENERATED_BLOCK_SIZE),
       blockMinFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB) {}
 
 BlockAssembler::BlockAssembler(const CChainParams &params,
                                const CTxMemPool &mempool,
                                const Options &options)
     : chainParams(params), m_mempool(mempool) {
     blockMinFeeRate = options.blockMinFeeRate;
     // Limit size to between 1K and options.nExcessiveBlockSize -1K for sanity:
     nMaxGeneratedBlockSize = std::max<uint64_t>(
         1000, std::min<uint64_t>(options.nExcessiveBlockSize - 1000,
                                  options.nMaxGeneratedBlockSize));
     // Calculate the max consensus sigchecks for this block.
     auto nMaxBlockSigChecks = GetMaxBlockSigChecksCount(nMaxGeneratedBlockSize);
     // Allow the full amount of signature check operations in lieu of a separate
     // config option. (We are mining relayed transactions with validity cached
     // by everyone else, and so the block will propagate quickly, regardless of
     // how many sigchecks it contains.)
     nMaxGeneratedBlockSigChecks = nMaxBlockSigChecks;
 }
 
 static BlockAssembler::Options DefaultOptions(const Config &config) {
     // Block resource limits
     // If -blockmaxsize is not given, limit to DEFAULT_MAX_GENERATED_BLOCK_SIZE
     // If only one is given, only restrict the specified resource.
     // If both are given, restrict both.
     BlockAssembler::Options options;
 
     options.nExcessiveBlockSize = config.GetMaxBlockSize();
 
     if (gArgs.IsArgSet("-blockmaxsize")) {
         options.nMaxGeneratedBlockSize =
             gArgs.GetArg("-blockmaxsize", DEFAULT_MAX_GENERATED_BLOCK_SIZE);
     }
 
     Amount n = Amount::zero();
     if (gArgs.IsArgSet("-blockmintxfee") &&
         ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) {
         options.blockMinFeeRate = CFeeRate(n);
     }
 
     return options;
 }
 
 BlockAssembler::BlockAssembler(const Config &config, const CTxMemPool &mempool)
     : BlockAssembler(config.GetChainParams(), mempool, DefaultOptions(config)) {
 }
 
 void BlockAssembler::resetBlock() {
     inBlock.clear();
 
     // Reserve space for coinbase tx.
     nBlockSize = 1000;
     nBlockSigOps = 100;
 
     // These counters do not include coinbase tx.
     nBlockTx = 0;
     nFees = Amount::zero();
 }
 
 std::optional<int64_t> BlockAssembler::m_last_block_num_txs{std::nullopt};
 std::optional<int64_t> BlockAssembler::m_last_block_size{std::nullopt};
 
 std::unique_ptr<CBlockTemplate>
-BlockAssembler::CreateNewBlock(const CScript &scriptPubKeyIn) {
+BlockAssembler::CreateNewBlock(CChainState &chainstate,
+                               const CScript &scriptPubKeyIn) {
     int64_t nTimeStart = GetTimeMicros();
 
     resetBlock();
 
     pblocktemplate.reset(new CBlockTemplate());
     if (!pblocktemplate.get()) {
         return nullptr;
     }
 
     // Pointer for convenience.
     CBlock *const pblock = &pblocktemplate->block;
 
     // Add dummy coinbase tx as first transaction.  It is updated at the end.
     pblocktemplate->entries.emplace_back(CTransactionRef(), -SATOSHI, -1);
 
     LOCK2(cs_main, m_mempool.cs);
-    CBlockIndex *pindexPrev = ::ChainActive().Tip();
+    assert(std::addressof(*::ChainActive().Tip()) ==
+           std::addressof(*chainstate.m_chain.Tip()));
+    CBlockIndex *pindexPrev = chainstate.m_chain.Tip();
     assert(pindexPrev != nullptr);
     nHeight = pindexPrev->nHeight + 1;
 
     const Consensus::Params &consensusParams = chainParams.GetConsensus();
 
     pblock->nVersion = ComputeBlockVersion(pindexPrev, consensusParams);
     // -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();
     nMedianTimePast = pindexPrev->GetMedianTimePast();
     nLockTimeCutoff =
         (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
             ? nMedianTimePast
             : pblock->GetBlockTime();
 
     int nPackagesSelected = 0;
     int nDescendantsUpdated = 0;
     addPackageTxs(nPackagesSelected, nDescendantsUpdated);
 
     if (IsMagneticAnomalyEnabled(consensusParams, pindexPrev)) {
         // If magnetic anomaly is enabled, we make sure transaction are
         // canonically ordered.
         std::sort(std::begin(pblocktemplate->entries) + 1,
                   std::end(pblocktemplate->entries),
                   [](const CBlockTemplateEntry &a, const CBlockTemplateEntry &b)
                       -> bool { return a.tx->GetId() < b.tx->GetId(); });
     }
 
     // Copy all the transactions refs into the block
     pblock->vtx.reserve(pblocktemplate->entries.size());
     for (const CBlockTemplateEntry &entry : pblocktemplate->entries) {
         pblock->vtx.push_back(entry.tx);
     }
 
     int64_t nTime1 = GetTimeMicros();
 
     m_last_block_num_txs = nBlockTx;
     m_last_block_size = nBlockSize;
 
     // Create coinbase transaction.
     CMutableTransaction coinbaseTx;
     coinbaseTx.vin.resize(1);
     coinbaseTx.vin[0].prevout = COutPoint();
     coinbaseTx.vout.resize(1);
     coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
     coinbaseTx.vout[0].nValue =
         nFees + GetBlockSubsidy(nHeight, consensusParams);
     coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
 
     const std::vector<CTxDestination> whitelisted =
         GetMinerFundWhitelist(consensusParams, pindexPrev);
     if (!whitelisted.empty()) {
         const Amount fund = GetMinerFundAmount(coinbaseTx.vout[0].nValue);
         coinbaseTx.vout[0].nValue -= fund;
         coinbaseTx.vout.emplace_back(fund,
                                      GetScriptForDestination(whitelisted[0]));
     }
 
     // Make sure the coinbase is big enough.
     uint64_t coinbaseSize = ::GetSerializeSize(coinbaseTx, PROTOCOL_VERSION);
     if (coinbaseSize < MIN_TX_SIZE) {
         coinbaseTx.vin[0].scriptSig
             << std::vector<uint8_t>(MIN_TX_SIZE - coinbaseSize - 1);
     }
 
     pblocktemplate->entries[0].tx = MakeTransactionRef(coinbaseTx);
     pblocktemplate->entries[0].fees = -1 * nFees;
     pblock->vtx[0] = pblocktemplate->entries[0].tx;
 
     uint64_t nSerializeSize = GetSerializeSize(*pblock, PROTOCOL_VERSION);
 
     LogPrintf("CreateNewBlock(): total size: %u txs: %u fees: %ld sigops %d\n",
               nSerializeSize, nBlockTx, nFees, nBlockSigOps);
 
     // Fill in header.
     pblock->hashPrevBlock = pindexPrev->GetBlockHash();
     UpdateTime(pblock, chainParams, pindexPrev);
     pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainParams);
     pblock->nNonce = 0;
     pblocktemplate->entries[0].sigOpCount = 0;
 
     BlockValidationState state;
-    if (!TestBlockValidity(state, chainParams, ::ChainstateActive(), *pblock,
-                           pindexPrev,
+    assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate));
+    if (!TestBlockValidity(state, chainParams, chainstate, *pblock, pindexPrev,
                            BlockValidationOptions(nMaxGeneratedBlockSize)
                                .withCheckPoW(false)
                                .withCheckMerkleRoot(false))) {
         throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s",
                                            __func__, state.ToString()));
     }
     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);
 }
 
 void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries &testSet) {
     for (CTxMemPool::setEntries::iterator iit = testSet.begin();
          iit != testSet.end();) {
         // Only test txs not already in the block.
         if (inBlock.count(*iit)) {
             testSet.erase(iit++);
         } else {
             iit++;
         }
     }
 }
 
 bool BlockAssembler::TestPackage(uint64_t packageSize,
                                  int64_t packageSigOps) const {
     auto blockSizeWithPackage = nBlockSize + packageSize;
     if (blockSizeWithPackage >= nMaxGeneratedBlockSize) {
         return false;
     }
 
     if (nBlockSigOps + packageSigOps >= nMaxGeneratedBlockSigChecks) {
         return false;
     }
 
     return true;
 }
 
 /**
  * Perform transaction-level checks before adding to block:
  * - Transaction finality (locktime)
  * - Serialized size (in case -blockmaxsize is in use)
  */
 bool BlockAssembler::TestPackageTransactions(
     const CTxMemPool::setEntries &package) const {
     uint64_t nPotentialBlockSize = nBlockSize;
     for (CTxMemPool::txiter it : package) {
         TxValidationState state;
         if (!ContextualCheckTransaction(chainParams.GetConsensus(), it->GetTx(),
                                         state, nHeight, nLockTimeCutoff,
                                         nMedianTimePast)) {
             return false;
         }
 
         uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), PROTOCOL_VERSION);
         if (nPotentialBlockSize + nTxSize >= nMaxGeneratedBlockSize) {
             return false;
         }
 
         nPotentialBlockSize += nTxSize;
     }
 
     return true;
 }
 
 void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) {
     pblocktemplate->entries.emplace_back(iter->GetSharedTx(), iter->GetFee(),
                                          iter->GetSigOpCount());
     nBlockSize += iter->GetTxSize();
     ++nBlockTx;
     nBlockSigOps += iter->GetSigOpCount();
     nFees += iter->GetFee();
     inBlock.insert(iter);
 
     bool fPrintPriority =
         gArgs.GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
     if (fPrintPriority) {
         LogPrintf(
             "fee %s txid %s\n",
             CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
             iter->GetTx().GetId().ToString());
     }
 }
 
 int BlockAssembler::UpdatePackagesForAdded(
     const CTxMemPool::setEntries &alreadyAdded,
     indexed_modified_transaction_set &mapModifiedTx) {
     int nDescendantsUpdated = 0;
     for (CTxMemPool::txiter it : alreadyAdded) {
         CTxMemPool::setEntries descendants;
         m_mempool.CalculateDescendants(it, descendants);
         // Insert all descendants (not yet in block) into the modified set.
         for (CTxMemPool::txiter desc : descendants) {
             if (alreadyAdded.count(desc)) {
                 continue;
             }
 
             ++nDescendantsUpdated;
             modtxiter mit = mapModifiedTx.find(desc);
             if (mit == mapModifiedTx.end()) {
                 CTxMemPoolModifiedEntry modEntry(desc);
                 modEntry.nSizeWithAncestors -= it->GetTxSize();
                 modEntry.nModFeesWithAncestors -= it->GetModifiedFee();
                 modEntry.nSigOpCountWithAncestors -= it->GetSigOpCount();
                 mapModifiedTx.insert(modEntry);
             } else {
                 mapModifiedTx.modify(mit, update_for_parent_inclusion(it));
             }
         }
     }
 
     return nDescendantsUpdated;
 }
 
 // Skip entries in mapTx that are already in a block or are present in
 // mapModifiedTx (which implies that the mapTx ancestor state is stale due to
 // ancestor inclusion in the block). Also skip transactions that we've already
 // failed to add. This can happen if we consider a transaction in mapModifiedTx
 // and it fails: we can then potentially consider it again while walking mapTx.
 // It's currently guaranteed to fail again, but as a belt-and-suspenders check
 // we put it in failedTx and avoid re-evaluation, since the re-evaluation would
 // be using cached size/sigops/fee values that are not actually correct.
 bool BlockAssembler::SkipMapTxEntry(
     CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx,
     CTxMemPool::setEntries &failedTx) {
     assert(it != m_mempool.mapTx.end());
     return mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it);
 }
 
 void BlockAssembler::SortForBlock(
     const CTxMemPool::setEntries &package,
     std::vector<CTxMemPool::txiter> &sortedEntries) {
     // Sort package by ancestor count. If a transaction A depends on transaction
     // B, then A's ancestor count must be greater than B's. So this is
     // sufficient to validly order the transactions for block inclusion.
     sortedEntries.clear();
     sortedEntries.insert(sortedEntries.begin(), package.begin(), package.end());
     std::sort(sortedEntries.begin(), sortedEntries.end(),
               CompareTxIterByAncestorCount());
 }
 
 /**
  * addPackageTx includes transactions paying a fee by ensuring that
  * the partial ordering of transactions is maintained.  That is to say
  * children come after parents, despite having a potentially larger fee.
  * @param[out] nPackagesSelected    How many packages were selected
  * @param[out] nDescendantsUpdated  Number of descendant transactions updated
  */
 void BlockAssembler::addPackageTxs(int &nPackagesSelected,
                                    int &nDescendantsUpdated) {
     // selection algorithm orders the mempool based on feerate of a
     // transaction including all unconfirmed ancestors. Since we don't remove
     // transactions from the mempool as we select them for block inclusion, we
     // need an alternate method of updating the feerate of a transaction with
     // its not-yet-selected ancestors as we go. This is accomplished by
     // walking the in-mempool descendants of selected transactions and storing
     // a temporary modified state in mapModifiedTxs. Each time through the
     // loop, we compare the best transaction in mapModifiedTxs with the next
     // transaction in the mempool to decide what transaction package to work
     // on next.
 
     // mapModifiedTx will store sorted packages after they are modified because
     // some of their txs are already in the block.
     indexed_modified_transaction_set mapModifiedTx;
     // Keep track of entries that failed inclusion, to avoid duplicate work.
     CTxMemPool::setEntries failedTx;
 
     // Start by adding all descendants of previously added txs to mapModifiedTx
     // and modifying them for their already included ancestors.
     UpdatePackagesForAdded(inBlock, mapModifiedTx);
 
     CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator
         mi = m_mempool.mapTx.get<ancestor_score>().begin();
     CTxMemPool::txiter iter;
 
     // Limit the number of attempts to add transactions to the block when it is
     // close to full; this is just a simple heuristic to finish quickly if the
     // mempool has a lot of entries.
     const int64_t MAX_CONSECUTIVE_FAILURES = 1000;
     int64_t nConsecutiveFailed = 0;
 
     while (mi != m_mempool.mapTx.get<ancestor_score>().end() ||
            !mapModifiedTx.empty()) {
         // First try to find a new transaction in mapTx to evaluate.
         if (mi != m_mempool.mapTx.get<ancestor_score>().end() &&
             SkipMapTxEntry(m_mempool.mapTx.project<0>(mi), mapModifiedTx,
                            failedTx)) {
             ++mi;
             continue;
         }
 
         // Now that mi is not stale, determine which transaction to evaluate:
         // the next entry from mapTx, or the best from mapModifiedTx?
         bool fUsingModified = false;
 
         modtxscoreiter modit = mapModifiedTx.get<ancestor_score>().begin();
         if (mi == m_mempool.mapTx.get<ancestor_score>().end()) {
             // We're out of entries in mapTx; use the entry from mapModifiedTx
             iter = modit->iter;
             fUsingModified = true;
         } else {
             // Try to compare the mapTx entry to the mapModifiedTx entry.
             iter = m_mempool.mapTx.project<0>(mi);
             if (modit != mapModifiedTx.get<ancestor_score>().end() &&
                 CompareTxMemPoolEntryByAncestorFee()(
                     *modit, CTxMemPoolModifiedEntry(iter))) {
                 // The best entry in mapModifiedTx has higher score than the one
                 // from mapTx. Switch which transaction (package) to consider
                 iter = modit->iter;
                 fUsingModified = true;
             } else {
                 // Either no entry in mapModifiedTx, or it's worse than mapTx.
                 // Increment mi for the next loop iteration.
                 ++mi;
             }
         }
 
         // We skip mapTx entries that are inBlock, and mapModifiedTx shouldn't
         // contain anything that is inBlock.
         assert(!inBlock.count(iter));
 
         uint64_t packageSize = iter->GetSizeWithAncestors();
         Amount packageFees = iter->GetModFeesWithAncestors();
         int64_t packageSigOps = iter->GetSigOpCountWithAncestors();
         if (fUsingModified) {
             packageSize = modit->nSizeWithAncestors;
             packageFees = modit->nModFeesWithAncestors;
             packageSigOps = modit->nSigOpCountWithAncestors;
         }
 
         if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
             // Don't include this package, but don't stop yet because something
             // else we might consider may have a sufficient fee rate (since txes
             // are ordered by virtualsize feerate, not actual feerate).
             if (fUsingModified) {
                 // Since we always look at the best entry in mapModifiedTx, we
                 // must erase failed entries so that we can consider the next
                 // best entry on the next loop iteration
                 mapModifiedTx.get<ancestor_score>().erase(modit);
                 failedTx.insert(iter);
             }
             continue;
         }
 
         // The following must not use virtual size since TestPackage relies on
         // having an accurate call to
         // GetMaxBlockSigOpsCount(blockSizeWithPackage).
         if (!TestPackage(packageSize, packageSigOps)) {
             if (fUsingModified) {
                 // Since we always look at the best entry in mapModifiedTx, we
                 // must erase failed entries so that we can consider the next
                 // best entry on the next loop iteration
                 mapModifiedTx.get<ancestor_score>().erase(modit);
                 failedTx.insert(iter);
             }
 
             ++nConsecutiveFailed;
 
             if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES &&
                 nBlockSize > nMaxGeneratedBlockSize - 1000) {
                 // Give up if we're close to full and haven't succeeded in a
                 // while.
                 break;
             }
 
             continue;
         }
 
         CTxMemPool::setEntries ancestors;
         uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
         std::string dummy;
         m_mempool.CalculateMemPoolAncestors(*iter, ancestors, nNoLimit,
                                             nNoLimit, nNoLimit, nNoLimit, dummy,
                                             false);
 
         onlyUnconfirmed(ancestors);
         ancestors.insert(iter);
 
         // Test if all tx's are Final.
         if (!TestPackageTransactions(ancestors)) {
             if (fUsingModified) {
                 mapModifiedTx.get<ancestor_score>().erase(modit);
                 failedTx.insert(iter);
             }
             continue;
         }
 
         // This transaction will make it in; reset the failed counter.
         nConsecutiveFailed = 0;
 
         // Package can be added. Sort the entries in a valid order.
         std::vector<CTxMemPool::txiter> sortedEntries;
         SortForBlock(ancestors, sortedEntries);
 
         for (auto &entry : sortedEntries) {
             AddToBlock(entry);
             // Erase from the modified set, if present
             mapModifiedTx.erase(entry);
         }
 
         ++nPackagesSelected;
 
         // Update transactions that depend on each of these
         nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx);
     }
 }
 
 static const std::vector<uint8_t>
 getExcessiveBlockSizeSig(uint64_t nExcessiveBlockSize) {
     std::string cbmsg = "/EB" + getSubVersionEB(nExcessiveBlockSize) + "/";
     std::vector<uint8_t> vec(cbmsg.begin(), cbmsg.end());
     return vec;
 }
 
 void IncrementExtraNonce(CBlock *pblock, const CBlockIndex *pindexPrev,
                          uint64_t nExcessiveBlockSize,
                          unsigned int &nExtraNonce) {
     // Update nExtraNonce
     static uint256 hashPrevBlock;
     if (hashPrevBlock != pblock->hashPrevBlock) {
         nExtraNonce = 0;
         hashPrevBlock = pblock->hashPrevBlock;
     }
 
     ++nExtraNonce;
     // Height first in coinbase required for block.version=2
     unsigned int nHeight = pindexPrev->nHeight + 1;
     CMutableTransaction txCoinbase(*pblock->vtx[0]);
     txCoinbase.vin[0].scriptSig =
         (CScript() << nHeight << CScriptNum(nExtraNonce)
                    << getExcessiveBlockSizeSig(nExcessiveBlockSize));
 
     // Make sure the coinbase is big enough.
     uint64_t coinbaseSize = ::GetSerializeSize(txCoinbase, PROTOCOL_VERSION);
     if (coinbaseSize < MIN_TX_SIZE) {
         txCoinbase.vin[0].scriptSig
             << std::vector<uint8_t>(MIN_TX_SIZE - coinbaseSize - 1);
     }
 
     assert(txCoinbase.vin[0].scriptSig.size() <= MAX_COINBASE_SCRIPTSIG_SIZE);
     assert(::GetSerializeSize(txCoinbase, PROTOCOL_VERSION) >= MIN_TX_SIZE);
 
     pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
     pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
 }
diff --git a/src/miner.h b/src/miner.h
index 01b23ba83..df20677f3 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -1,234 +1,234 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_MINER_H
 #define BITCOIN_MINER_H
 
 #include <primitives/block.h>
 #include <txmempool.h>
 
 #include <boost/multi_index/ordered_index.hpp>
 #include <boost/multi_index_container.hpp>
 
 #include <cstdint>
 #include <memory>
 #include <optional>
 
 class CBlockIndex;
 class CChainParams;
 class Config;
 class CScript;
 
 namespace Consensus {
 struct Params;
 }
 
 static const bool DEFAULT_PRINTPRIORITY = false;
 
 struct CBlockTemplateEntry {
     CTransactionRef tx;
     Amount fees;
     int64_t sigOpCount;
 
     CBlockTemplateEntry(CTransactionRef _tx, Amount _fees, int64_t _sigOpCount)
         : tx(_tx), fees(_fees), sigOpCount(_sigOpCount){};
 };
 
 struct CBlockTemplate {
     CBlock block;
 
     std::vector<CBlockTemplateEntry> entries;
 };
 
 // Container for tracking updates to ancestor feerate as we include (parent)
 // transactions in a block
 struct CTxMemPoolModifiedEntry {
     explicit CTxMemPoolModifiedEntry(CTxMemPool::txiter entry) {
         iter = entry;
         nSizeWithAncestors = entry->GetSizeWithAncestors();
         nModFeesWithAncestors = entry->GetModFeesWithAncestors();
         nSigOpCountWithAncestors = entry->GetSigOpCountWithAncestors();
     }
 
     Amount GetModifiedFee() const { return iter->GetModifiedFee(); }
     uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
     uint64_t GetVirtualSizeWithAncestors() const;
     Amount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
     size_t GetTxSize() const { return iter->GetTxSize(); }
     size_t GetTxVirtualSize() const { return iter->GetTxVirtualSize(); }
     const CTransaction &GetTx() const { return iter->GetTx(); }
 
     CTxMemPool::txiter iter;
     uint64_t nSizeWithAncestors;
     Amount nModFeesWithAncestors;
     int64_t nSigOpCountWithAncestors;
 };
 
 /**
  * Comparator for CTxMemPool::txiter objects.
  * It simply compares the internal memory address of the CTxMemPoolEntry object
  * pointed to. This means it has no meaning, and is only useful for using them
  * as key in other indexes.
  */
 struct CompareCTxMemPoolIter {
     bool operator()(const CTxMemPool::txiter &a,
                     const CTxMemPool::txiter &b) const {
         return &(*a) < &(*b);
     }
 };
 
 struct modifiedentry_iter {
     typedef CTxMemPool::txiter result_type;
     result_type operator()(const CTxMemPoolModifiedEntry &entry) const {
         return entry.iter;
     }
 };
 
 // A comparator that sorts transactions based on number of ancestors.
 // This is sufficient to sort an ancestor package in an order that is valid
 // to appear in a block.
 struct CompareTxIterByAncestorCount {
     bool operator()(const CTxMemPool::txiter &a,
                     const CTxMemPool::txiter &b) const {
         if (a->GetCountWithAncestors() != b->GetCountWithAncestors()) {
             return a->GetCountWithAncestors() < b->GetCountWithAncestors();
         }
         return CompareIteratorById()(a, b);
     }
 };
 
 typedef boost::multi_index_container<
     CTxMemPoolModifiedEntry,
     boost::multi_index::indexed_by<
         boost::multi_index::ordered_unique<modifiedentry_iter,
                                            CompareCTxMemPoolIter>,
         // sorted by modified ancestor fee rate
         boost::multi_index::ordered_non_unique<
             // Reuse same tag from CTxMemPool's similar index
             boost::multi_index::tag<ancestor_score>,
             boost::multi_index::identity<CTxMemPoolModifiedEntry>,
             CompareTxMemPoolEntryByAncestorFee>>>
     indexed_modified_transaction_set;
 
 typedef indexed_modified_transaction_set::nth_index<0>::type::iterator
     modtxiter;
 typedef indexed_modified_transaction_set::index<ancestor_score>::type::iterator
     modtxscoreiter;
 
 struct update_for_parent_inclusion {
     explicit update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {}
 
     void operator()(CTxMemPoolModifiedEntry &e) {
         e.nModFeesWithAncestors -= iter->GetFee();
         e.nSizeWithAncestors -= iter->GetTxSize();
         e.nSigOpCountWithAncestors -= iter->GetSigOpCount();
     }
 
     CTxMemPool::txiter iter;
 };
 
 /** Generate a new block, without valid proof-of-work */
 class BlockAssembler {
 private:
     // The constructed block template
     std::unique_ptr<CBlockTemplate> pblocktemplate;
 
     // Configuration parameters for the block size
     uint64_t nMaxGeneratedBlockSize;
     uint64_t nMaxGeneratedBlockSigChecks;
     CFeeRate blockMinFeeRate;
 
     // Information on the current status of the block
     uint64_t nBlockSize;
     uint64_t nBlockTx;
     uint64_t nBlockSigOps;
     Amount nFees;
     CTxMemPool::setEntries inBlock;
 
     // Chain context for the block
     int nHeight;
     int64_t nLockTimeCutoff;
     int64_t nMedianTimePast;
     const CChainParams &chainParams;
 
     const CTxMemPool &m_mempool;
 
 public:
     struct Options {
         Options();
         uint64_t nExcessiveBlockSize;
         uint64_t nMaxGeneratedBlockSize;
         CFeeRate blockMinFeeRate;
     };
 
     BlockAssembler(const Config &config, const CTxMemPool &mempool);
     BlockAssembler(const CChainParams &params, const CTxMemPool &mempool,
                    const Options &options);
 
     /** Construct a new block template with coinbase to scriptPubKeyIn */
     std::unique_ptr<CBlockTemplate>
-    CreateNewBlock(const CScript &scriptPubKeyIn);
+    CreateNewBlock(CChainState &chainstate, const CScript &scriptPubKeyIn);
 
     uint64_t GetMaxGeneratedBlockSize() const { return nMaxGeneratedBlockSize; }
 
     static std::optional<int64_t> m_last_block_num_txs;
     static std::optional<int64_t> m_last_block_size;
 
 private:
     // utility functions
     /** Clear the block's state and prepare for assembling a new block */
     void resetBlock();
     /** Add a tx to the block */
     void AddToBlock(CTxMemPool::txiter iter);
 
     // Methods for how to add transactions to a block.
     /**
      * Add transactions based on feerate including unconfirmed ancestors.
      * Increments nPackagesSelected / nDescendantsUpdated with corresponding
      * statistics from the package selection (for logging statistics).
      */
     void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated)
         EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs);
 
     // helper functions for addPackageTxs()
     /** Remove confirmed (inBlock) entries from given set */
     void onlyUnconfirmed(CTxMemPool::setEntries &testSet);
     /** Test if a new package would "fit" in the block */
     bool TestPackage(uint64_t packageSize, int64_t packageSigOpCount) const;
     /**
      * Perform checks on each transaction in a package:
      * locktime, serialized size (if necessary). These checks should always
      * succeed, and they're here only as an extra check in case of suboptimal
      * node configuration.
      */
     bool TestPackageTransactions(const CTxMemPool::setEntries &package) const;
     /**
      * Return true if given transaction from mapTx has already been evaluated,
      * or if the transaction's cached data in mapTx is incorrect.
      */
     bool SkipMapTxEntry(CTxMemPool::txiter it,
                         indexed_modified_transaction_set &mapModifiedTx,
                         CTxMemPool::setEntries &failedTx)
         EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs);
     /** Sort the package in an order that is valid to appear in a block */
     void SortForBlock(const CTxMemPool::setEntries &package,
                       std::vector<CTxMemPool::txiter> &sortedEntries);
     /**
      * Add descendants of given transactions to mapModifiedTx with ancestor
      * state updated assuming given transactions are inBlock. Returns number of
      * updated descendants.
      */
     int UpdatePackagesForAdded(const CTxMemPool::setEntries &alreadyAdded,
                                indexed_modified_transaction_set &mapModifiedTx)
         EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs);
 };
 
 /** Modify the extranonce in a block */
 void IncrementExtraNonce(CBlock *pblock, const CBlockIndex *pindexPrev,
                          uint64_t nExcessiveBlockSize,
                          unsigned int &nExtraNonce);
 int64_t UpdateTime(CBlockHeader *pblock, const CChainParams &chainParams,
                    const CBlockIndex *pindexPrev);
 #endif // BITCOIN_MINER_H
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 9c0d3189c..79e145ea3 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -1,1218 +1,1220 @@
 // Copyright (c) 2010 Satoshi Nakamoto
 // Copyright (c) 2009-2018 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <amount.h>
 #include <blockvalidity.h>
 #include <cashaddrenc.h>
 #include <chain.h>
 #include <chainparams.h>
 #include <config.h>
 #include <consensus/activation.h>
 #include <consensus/consensus.h>
 #include <consensus/params.h>
 #include <consensus/validation.h>
 #include <core_io.h>
 #include <key_io.h>
 #include <miner.h>
 #include <minerfund.h>
 #include <net.h>
 #include <node/context.h>
 #include <policy/policy.h>
 #include <pow/pow.h>
 #include <rpc/blockchain.h>
 #include <rpc/mining.h>
 #include <rpc/server.h>
 #include <rpc/util.h>
 #include <script/descriptor.h>
 #include <script/script.h>
 #include <shutdown.h>
 #include <txmempool.h>
 #include <univalue.h>
 #include <util/strencodings.h>
 #include <util/string.h>
 #include <util/system.h>
 #include <util/translation.h>
 #include <validation.h>
 #include <validationinterface.h>
 #include <warnings.h>
 
 #include <cstdint>
 
 /**
  * Return average network hashes per second based on the last 'lookup' blocks,
  * or from the last difficulty change if 'lookup' is nonpositive. If 'height' is
  * nonnegative, compute the estimate at the time when a given block was found.
  */
 static UniValue GetNetworkHashPS(int lookup, int height) {
     CBlockIndex *pb = ::ChainActive().Tip();
 
     if (height >= 0 && height < ::ChainActive().Height()) {
         pb = ::ChainActive()[height];
     }
 
     if (pb == nullptr || !pb->nHeight) {
         return 0;
     }
 
     // If lookup is -1, then use blocks since last difficulty change.
     if (lookup <= 0) {
         lookup = pb->nHeight %
                      Params().GetConsensus().DifficultyAdjustmentInterval() +
                  1;
     }
 
     // If lookup is larger than chain, then set it to chain length.
     if (lookup > pb->nHeight) {
         lookup = pb->nHeight;
     }
 
     CBlockIndex *pb0 = pb;
     int64_t minTime = pb0->GetBlockTime();
     int64_t maxTime = minTime;
     for (int i = 0; i < lookup; i++) {
         pb0 = pb0->pprev;
         int64_t time = pb0->GetBlockTime();
         minTime = std::min(time, minTime);
         maxTime = std::max(time, maxTime);
     }
 
     // In case there's a situation where minTime == maxTime, we don't want a
     // divide by zero exception.
     if (minTime == maxTime) {
         return 0;
     }
 
     arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork;
     int64_t timeDiff = maxTime - minTime;
 
     return workDiff.getdouble() / timeDiff;
 }
 
 static RPCHelpMan getnetworkhashps() {
     return RPCHelpMan{
         "getnetworkhashps",
         "Returns the estimated network hashes per second based on the last n "
         "blocks.\n"
         "Pass in [blocks] to override # of blocks, -1 specifies since last "
         "difficulty change.\n"
         "Pass in [height] to estimate the network speed at the time when a "
         "certain block was found.\n",
         {
             {"nblocks", RPCArg::Type::NUM, /* default */ "120",
              "The number of blocks, or -1 for blocks since last difficulty "
              "change."},
             {"height", RPCArg::Type::NUM, /* default */ "-1",
              "To estimate at the time of the given height."},
         },
         RPCResult{RPCResult::Type::NUM, "", "Hashes per second estimated"},
         RPCExamples{HelpExampleCli("getnetworkhashps", "") +
                     HelpExampleRpc("getnetworkhashps", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
             return GetNetworkHashPS(
                 !request.params[0].isNull() ? request.params[0].get_int() : 120,
                 !request.params[1].isNull() ? request.params[1].get_int() : -1);
         },
     };
 }
 
 static bool GenerateBlock(const Config &config, ChainstateManager &chainman,
                           CBlock &block, uint64_t &max_tries,
                           unsigned int &extra_nonce, BlockHash &block_hash) {
     block_hash.SetNull();
     const uint64_t nExcessiveBlockSize = config.GetMaxBlockSize();
 
     {
         LOCK(cs_main);
         IncrementExtraNonce(&block, ::ChainActive().Tip(), nExcessiveBlockSize,
                             extra_nonce);
     }
 
     const Consensus::Params &params = config.GetChainParams().GetConsensus();
 
     while (max_tries > 0 &&
            block.nNonce < std::numeric_limits<uint32_t>::max() &&
            !CheckProofOfWork(block.GetHash(), block.nBits, params) &&
            !ShutdownRequested()) {
         ++block.nNonce;
         --max_tries;
     }
     if (max_tries == 0 || ShutdownRequested()) {
         return false;
     }
     if (block.nNonce == std::numeric_limits<uint32_t>::max()) {
         return true;
     }
 
     std::shared_ptr<const CBlock> shared_pblock =
         std::make_shared<const CBlock>(block);
     if (!chainman.ProcessNewBlock(config, shared_pblock, true, nullptr)) {
         throw JSONRPCError(RPC_INTERNAL_ERROR,
                            "ProcessNewBlock, block not accepted");
     }
 
     block_hash = block.GetHash();
     return true;
 }
 
 static UniValue generateBlocks(const Config &config,
                                ChainstateManager &chainman,
                                const CTxMemPool &mempool,
                                const CScript &coinbase_script, int nGenerate,
                                uint64_t nMaxTries) {
     int nHeightEnd = 0;
     int nHeight = 0;
 
     {
         // Don't keep cs_main locked.
         LOCK(cs_main);
         nHeight = ::ChainActive().Height();
         nHeightEnd = nHeight + nGenerate;
     }
 
     unsigned int nExtraNonce = 0;
     UniValue blockHashes(UniValue::VARR);
     while (nHeight < nHeightEnd && !ShutdownRequested()) {
         std::unique_ptr<CBlockTemplate> pblocktemplate(
-            BlockAssembler(config, mempool).CreateNewBlock(coinbase_script));
+            BlockAssembler(config, mempool)
+                .CreateNewBlock(::ChainstateActive(), coinbase_script));
 
         if (!pblocktemplate.get()) {
             throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
         }
 
         CBlock *pblock = &pblocktemplate->block;
 
         BlockHash block_hash;
         if (!GenerateBlock(config, chainman, *pblock, nMaxTries, nExtraNonce,
                            block_hash)) {
             break;
         }
 
         if (!block_hash.IsNull()) {
             ++nHeight;
             blockHashes.push_back(block_hash.GetHex());
         }
     }
     return blockHashes;
 }
 
 static bool getScriptFromDescriptor(const std::string &descriptor,
                                     CScript &script, std::string &error) {
     FlatSigningProvider key_provider;
     const auto desc =
         Parse(descriptor, key_provider, error, /* require_checksum = */ false);
     if (desc) {
         if (desc->IsRange()) {
             throw JSONRPCError(RPC_INVALID_PARAMETER,
                                "Ranged descriptor not accepted. Maybe pass "
                                "through deriveaddresses first?");
         }
 
         FlatSigningProvider provider;
         std::vector<CScript> scripts;
         if (!desc->Expand(0, key_provider, scripts, provider)) {
             throw JSONRPCError(
                 RPC_INVALID_ADDRESS_OR_KEY,
                 strprintf("Cannot derive script without private keys"));
         }
 
         // Combo descriptors can have 2 scripts, so we can't just check
         // scripts.size() == 1
         CHECK_NONFATAL(scripts.size() > 0 && scripts.size() <= 2);
 
         if (scripts.size() == 1) {
             script = scripts.at(0);
         } else {
             // Else take the 2nd script, since it is p2pkh
             script = scripts.at(1);
         }
 
         return true;
     }
 
     return false;
 }
 
 static RPCHelpMan generatetodescriptor() {
     return RPCHelpMan{
         "generatetodescriptor",
         "Mine blocks immediately to a specified descriptor (before the RPC "
         "call returns)\n",
         {
             {"num_blocks", RPCArg::Type::NUM, RPCArg::Optional::NO,
              "How many blocks are generated immediately."},
             {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO,
              "The descriptor to send the newly generated bitcoin to."},
             {"maxtries", RPCArg::Type::NUM,
              /* default */ ToString(DEFAULT_MAX_TRIES),
              "How many iterations to try."},
         },
         RPCResult{RPCResult::Type::ARR,
                   "",
                   "hashes of blocks generated",
                   {
                       {RPCResult::Type::STR_HEX, "", "blockhash"},
                   }},
         RPCExamples{"\nGenerate 11 blocks to mydesc\n" +
                     HelpExampleCli("generatetodescriptor", "11 \"mydesc\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const int num_blocks{request.params[0].get_int()};
             const uint64_t max_tries{request.params[2].isNull()
                                          ? DEFAULT_MAX_TRIES
                                          : request.params[2].get_int()};
 
             CScript coinbase_script;
             std::string error;
             if (!getScriptFromDescriptor(request.params[1].get_str(),
                                          coinbase_script, error)) {
                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
             }
 
             const CTxMemPool &mempool = EnsureMemPool(request.context);
             ChainstateManager &chainman = EnsureChainman(request.context);
 
             return generateBlocks(config, chainman, mempool, coinbase_script,
                                   num_blocks, max_tries);
         },
     };
 }
 
 static RPCHelpMan generate() {
     return RPCHelpMan{"generate",
                       "has been replaced by the -generate cli option. Refer to "
                       "-help for more information.",
                       {},
                       {},
                       RPCExamples{""},
                       [&](const RPCHelpMan &self, const Config &config,
                           const JSONRPCRequest &request) -> UniValue {
                           throw JSONRPCError(RPC_METHOD_NOT_FOUND,
                                              self.ToString());
                       }};
 }
 
 static RPCHelpMan generatetoaddress() {
     return RPCHelpMan{
         "generatetoaddress",
         "Mine blocks immediately to a specified address before the "
         "RPC call returns)\n",
         {
             {"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO,
              "How many blocks are generated immediately."},
             {"address", RPCArg::Type::STR, RPCArg::Optional::NO,
              "The address to send the newly generated bitcoin to."},
             {"maxtries", RPCArg::Type::NUM,
              /* default */ ToString(DEFAULT_MAX_TRIES),
              "How many iterations to try."},
         },
         RPCResult{RPCResult::Type::ARR,
                   "",
                   "hashes of blocks generated",
                   {
                       {RPCResult::Type::STR_HEX, "", "blockhash"},
                   }},
         RPCExamples{
             "\nGenerate 11 blocks to myaddress\n" +
             HelpExampleCli("generatetoaddress", "11 \"myaddress\"") +
             "If you are using the " PACKAGE_NAME " wallet, you can "
             "get a new address to send the newly generated bitcoin to with:\n" +
             HelpExampleCli("getnewaddress", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const int num_blocks{request.params[0].get_int()};
             const uint64_t max_tries{request.params[2].isNull()
                                          ? DEFAULT_MAX_TRIES
                                          : request.params[2].get_int64()};
 
             CTxDestination destination = DecodeDestination(
                 request.params[1].get_str(), config.GetChainParams());
             if (!IsValidDestination(destination)) {
                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                    "Error: Invalid address");
             }
 
             const CTxMemPool &mempool = EnsureMemPool(request.context);
             ChainstateManager &chainman = EnsureChainman(request.context);
 
             CScript coinbase_script = GetScriptForDestination(destination);
 
             return generateBlocks(config, chainman, mempool, coinbase_script,
                                   num_blocks, max_tries);
         },
     };
 }
 
 static RPCHelpMan generateblock() {
     return RPCHelpMan{
         "generateblock",
         "Mine a block with a set of ordered transactions immediately to a "
         "specified address or descriptor (before the RPC call returns)\n",
         {
             {"output", RPCArg::Type::STR, RPCArg::Optional::NO,
              "The address or descriptor to send the newly generated bitcoin "
              "to."},
             {
                 "transactions",
                 RPCArg::Type::ARR,
                 RPCArg::Optional::NO,
                 "An array of hex strings which are either txids or raw "
                 "transactions.\n"
                 "Txids must reference transactions currently in the mempool.\n"
                 "All transactions must be valid and in valid order, otherwise "
                 "the block will be rejected.",
                 {
                     {"rawtx/txid", RPCArg::Type::STR_HEX,
                      RPCArg::Optional::OMITTED, ""},
                 },
             },
         },
         RPCResult{
             RPCResult::Type::OBJ,
             "",
             "",
             {
                 {RPCResult::Type::STR_HEX, "hash", "hash of generated block"},
             }},
         RPCExamples{
             "\nGenerate a block to myaddress, with txs rawtx and "
             "mempool_txid\n" +
             HelpExampleCli("generateblock",
                            R"("myaddress" '["rawtx", "mempool_txid"]')")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const auto address_or_descriptor = request.params[0].get_str();
             CScript coinbase_script;
             std::string error;
 
             const CChainParams &chainparams = config.GetChainParams();
 
             if (!getScriptFromDescriptor(address_or_descriptor, coinbase_script,
                                          error)) {
                 const auto destination =
                     DecodeDestination(address_or_descriptor, chainparams);
                 if (!IsValidDestination(destination)) {
                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                        "Error: Invalid address or descriptor");
                 }
 
                 coinbase_script = GetScriptForDestination(destination);
             }
 
             const CTxMemPool &mempool = EnsureMemPool(request.context);
 
             std::vector<CTransactionRef> txs;
             const auto raw_txs_or_txids = request.params[1].get_array();
             for (size_t i = 0; i < raw_txs_or_txids.size(); i++) {
                 const auto str(raw_txs_or_txids[i].get_str());
 
                 uint256 hash;
                 CMutableTransaction mtx;
                 if (ParseHashStr(str, hash)) {
                     const auto tx = mempool.get(TxId(hash));
                     if (!tx) {
                         throw JSONRPCError(
                             RPC_INVALID_ADDRESS_OR_KEY,
                             strprintf("Transaction %s not in mempool.", str));
                     }
 
                     txs.emplace_back(tx);
 
                 } else if (DecodeHexTx(mtx, str)) {
                     txs.push_back(MakeTransactionRef(std::move(mtx)));
 
                 } else {
                     throw JSONRPCError(
                         RPC_DESERIALIZATION_ERROR,
                         strprintf("Transaction decode failed for %s", str));
                 }
             }
 
             CBlock block;
 
             {
                 LOCK(cs_main);
 
                 CTxMemPool empty_mempool;
                 std::unique_ptr<CBlockTemplate> blocktemplate(
                     BlockAssembler(config, empty_mempool)
-                        .CreateNewBlock(coinbase_script));
+                        .CreateNewBlock(::ChainstateActive(), coinbase_script));
                 if (!blocktemplate) {
                     throw JSONRPCError(RPC_INTERNAL_ERROR,
                                        "Couldn't create new block");
                 }
                 block = blocktemplate->block;
             }
 
             CHECK_NONFATAL(block.vtx.size() == 1);
 
             // Add transactions
             block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
 
             {
                 LOCK(cs_main);
 
                 BlockValidationState state;
                 if (!TestBlockValidity(state, chainparams, ::ChainstateActive(),
                                        block,
                                        g_chainman.m_blockman.LookupBlockIndex(
                                            block.hashPrevBlock),
                                        BlockValidationOptions(config)
                                            .withCheckPoW(false)
                                            .withCheckMerkleRoot(false))) {
                     throw JSONRPCError(RPC_VERIFY_ERROR,
                                        strprintf("TestBlockValidity failed: %s",
                                                  state.ToString()));
                 }
             }
 
             BlockHash block_hash;
             uint64_t max_tries{DEFAULT_MAX_TRIES};
             unsigned int extra_nonce{0};
 
             if (!GenerateBlock(config, EnsureChainman(request.context), block,
                                max_tries, extra_nonce, block_hash) ||
                 block_hash.IsNull()) {
                 throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
             }
 
             UniValue obj(UniValue::VOBJ);
             obj.pushKV("hash", block_hash.GetHex());
             return obj;
         },
     };
 }
 
 static RPCHelpMan getmininginfo() {
     return RPCHelpMan{
         "getmininginfo",
         "Returns a json object containing mining-related "
         "information.",
         {},
         RPCResult{
             RPCResult::Type::OBJ,
             "",
             "",
             {
                 {RPCResult::Type::NUM, "blocks", "The current block"},
                 {RPCResult::Type::NUM, "currentblocksize", /* optional */ true,
                  "The block size of the last assembled block (only present if "
                  "a block was ever assembled)"},
                 {RPCResult::Type::NUM, "currentblocktx", /* optional */ true,
                  "The number of block transactions of the last assembled block "
                  "(only present if a block was ever assembled)"},
                 {RPCResult::Type::NUM, "difficulty", "The current difficulty"},
                 {RPCResult::Type::NUM, "networkhashps",
                  "The network hashes per second"},
                 {RPCResult::Type::NUM, "pooledtx", "The size of the mempool"},
                 {RPCResult::Type::STR, "chain",
                  "current network name (main, test, regtest)"},
                 {RPCResult::Type::STR, "warnings",
                  "any network and blockchain warnings"},
             }},
         RPCExamples{HelpExampleCli("getmininginfo", "") +
                     HelpExampleRpc("getmininginfo", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
             const CTxMemPool &mempool = EnsureMemPool(request.context);
 
             UniValue obj(UniValue::VOBJ);
             obj.pushKV("blocks", int(::ChainActive().Height()));
             if (BlockAssembler::m_last_block_size) {
                 obj.pushKV("currentblocksize",
                            *BlockAssembler::m_last_block_size);
             }
             if (BlockAssembler::m_last_block_num_txs) {
                 obj.pushKV("currentblocktx",
                            *BlockAssembler::m_last_block_num_txs);
             }
             obj.pushKV("difficulty",
                        double(GetDifficulty(::ChainActive().Tip())));
             obj.pushKV("networkhashps",
                        getnetworkhashps().HandleRequest(config, request));
             obj.pushKV("pooledtx", uint64_t(mempool.size()));
             obj.pushKV("chain", config.GetChainParams().NetworkIDString());
             obj.pushKV("warnings", GetWarnings(false).original);
             return obj;
         },
     };
 }
 
 // NOTE: Unlike wallet RPC (which use XEC values), mining RPCs follow GBT (BIP
 // 22) in using satoshi amounts
 static RPCHelpMan prioritisetransaction() {
     return RPCHelpMan{
         "prioritisetransaction",
         "Accepts the transaction into mined blocks at a higher "
         "(or lower) priority\n",
         {
             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "The transaction id."},
             {"dummy", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG,
              "API-Compatibility for previous API. Must be zero or null.\n"
              "                  DEPRECATED. For forward compatibility "
              "use named arguments and omit this parameter."},
             {"fee_delta", RPCArg::Type::NUM, RPCArg::Optional::NO,
              "The fee value (in satoshis) to add (or subtract, if negative).\n"
              "                        The fee is not actually paid, only the "
              "algorithm for selecting transactions into a block\n"
              "                  considers the transaction as it would "
              "have paid a higher (or lower) fee."},
         },
         RPCResult{RPCResult::Type::BOOL, "", "Returns true"},
         RPCExamples{
             HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") +
             HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
 
             TxId txid(ParseHashV(request.params[0], "txid"));
             Amount nAmount = request.params[2].get_int64() * SATOSHI;
 
             if (!(request.params[1].isNull() ||
                   request.params[1].get_real() == 0)) {
                 throw JSONRPCError(
                     RPC_INVALID_PARAMETER,
                     "Priority is no longer supported, dummy argument to "
                     "prioritisetransaction must be 0.");
             }
 
             EnsureMemPool(request.context).PrioritiseTransaction(txid, nAmount);
             return true;
         },
     };
 }
 
 // NOTE: Assumes a conclusive result; if result is inconclusive, it must be
 // handled by caller
 static UniValue BIP22ValidationResult(const Config &config,
                                       const BlockValidationState &state) {
     if (state.IsValid()) {
         return NullUniValue;
     }
 
     if (state.IsError()) {
         throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
     }
 
     if (state.IsInvalid()) {
         std::string strRejectReason = state.GetRejectReason();
         if (strRejectReason.empty()) {
             return "rejected";
         }
         return strRejectReason;
     }
 
     // Should be impossible.
     return "valid?";
 }
 
 static RPCHelpMan getblocktemplate() {
     return RPCHelpMan{
         "getblocktemplate",
         "If the request parameters include a 'mode' key, that is used to "
         "explicitly select between the default 'template' request or a "
         "'proposal'.\n"
         "It returns data needed to construct a block to work on.\n"
         "For full specification, see BIPs 22, 23, 9, and 145:\n"
         "    "
         "https://github.com/bitcoin/bips/blob/master/"
         "bip-0022.mediawiki\n"
         "    "
         "https://github.com/bitcoin/bips/blob/master/"
         "bip-0023.mediawiki\n"
         "    "
         "https://github.com/bitcoin/bips/blob/master/"
         "bip-0009.mediawiki#getblocktemplate_changes\n"
         "    ",
         {
             {"template_request",
              RPCArg::Type::OBJ,
              "{}",
              "Format of the template",
              {
                  {"mode", RPCArg::Type::STR, /* treat as named arg */
                   RPCArg::Optional::OMITTED_NAMED_ARG,
                   "This must be set to \"template\", \"proposal\" (see BIP "
                   "23), or omitted"},
                  {
                      "capabilities",
                      RPCArg::Type::ARR,
                      /* treat as named arg */
                      RPCArg::Optional::OMITTED_NAMED_ARG,
                      "A list of strings",
                      {
                          {"support", RPCArg::Type::STR,
                           RPCArg::Optional::OMITTED,
                           "client side supported feature, 'longpoll', "
                           "'coinbasetxn', 'coinbasevalue', 'proposal', "
                           "'serverlist', 'workid'"},
                      },
                  },
              },
              "\"template_request\""},
         },
         RPCResult{
             RPCResult::Type::OBJ,
             "",
             "",
             {
                 {RPCResult::Type::NUM, "version",
                  "The preferred block version"},
                 {RPCResult::Type::STR, "previousblockhash",
                  "The hash of current highest block"},
                 {RPCResult::Type::ARR,
                  "transactions",
                  "contents of non-coinbase transactions that should be "
                  "included in the next block",
                  {
                      {RPCResult::Type::OBJ,
                       "",
                       "",
                       {
                           {RPCResult::Type::STR_HEX, "data",
                            "transaction data encoded in hexadecimal "
                            "(byte-for-byte)"},
                           {RPCResult::Type::STR_HEX, "txid",
                            "transaction id encoded in little-endian "
                            "hexadecimal"},
                           {RPCResult::Type::STR_HEX, "hash",
                            "hash encoded in little-endian hexadecimal"},
                           {RPCResult::Type::ARR,
                            "depends",
                            "array of numbers",
                            {
                                {RPCResult::Type::NUM, "",
                                 "transactions before this one (by 1-based "
                                 "index in 'transactions' list) that must be "
                                 "present in the final block if this one is"},
                            }},
                           {RPCResult::Type::NUM, "fee",
                            "difference in value between transaction inputs and "
                            "outputs (in satoshis); for coinbase transactions, "
                            "this is a negative Number of the total collected "
                            "block fees (ie, not including the block subsidy); "
                            "if key is not present, fee is unknown and clients "
                            "MUST NOT assume there isn't one"},
                           {RPCResult::Type::NUM, "sigops",
                            "total SigOps cost, as counted for purposes of "
                            "block limits; if key is not present, sigop cost is "
                            "unknown and clients MUST NOT assume it is zero"},
                       }},
                  }},
                 {RPCResult::Type::OBJ,
                  "coinbaseaux",
                  "data that should be included in the coinbase's scriptSig "
                  "content",
                  {
                      {RPCResult::Type::ELISION, "", ""},
                  }},
                 {RPCResult::Type::NUM, "coinbasevalue",
                  "maximum allowable input to coinbase transaction, including "
                  "the generation award and transaction fees (in satoshis)"},
                 {RPCResult::Type::OBJ,
                  "coinbasetxn",
                  "information for coinbase transaction",
                  {
                      {RPCResult::Type::OBJ,
                       "minerfund",
                       "information related to the coinbase miner fund",
                       {
 
                           {RPCResult::Type::ARR,
                            "addresses",
                            "List of valid addresses for the miner fund output",
                            {
                                {RPCResult::Type::ELISION, "", ""},
                            }},
 
                           {RPCResult::Type::STR_AMOUNT, "minimumvalue",
                            "The minimum value the miner fund output must pay"},
 
                       }},
                      {RPCResult::Type::ELISION, "", ""},
                  }},
                 {RPCResult::Type::STR, "target", "The hash target"},
                 {RPCResult::Type::NUM_TIME, "mintime",
                  "The minimum timestamp appropriate for the next block time, "
                  "expressed in " +
                      UNIX_EPOCH_TIME},
                 {RPCResult::Type::ARR,
                  "mutable",
                  "list of ways the block template may be changed",
                  {
                      {RPCResult::Type::STR, "value",
                       "A way the block template may be changed, e.g. 'time', "
                       "'transactions', 'prevblock'"},
                  }},
                 {RPCResult::Type::STR_HEX, "noncerange",
                  "A range of valid nonces"},
                 {RPCResult::Type::NUM, "sigoplimit",
                  "limit of sigops in blocks"},
                 {RPCResult::Type::NUM, "sizelimit", "limit of block size"},
                 {RPCResult::Type::NUM_TIME, "curtime",
                  "current timestamp in " + UNIX_EPOCH_TIME},
                 {RPCResult::Type::STR, "bits",
                  "compressed target of next block"},
                 {RPCResult::Type::NUM, "height",
                  "The height of the next block"},
             }},
         RPCExamples{HelpExampleCli("getblocktemplate", "") +
                     HelpExampleRpc("getblocktemplate", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
             const CChainParams &chainparams = config.GetChainParams();
 
             std::string strMode = "template";
             UniValue lpval = NullUniValue;
             std::set<std::string> setClientRules;
             if (!request.params[0].isNull()) {
                 const UniValue &oparam = request.params[0].get_obj();
                 const UniValue &modeval = find_value(oparam, "mode");
                 if (modeval.isStr()) {
                     strMode = modeval.get_str();
                 } else if (modeval.isNull()) {
                     /* Do nothing */
                 } else {
                     throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
                 }
                 lpval = find_value(oparam, "longpollid");
 
                 if (strMode == "proposal") {
                     const UniValue &dataval = find_value(oparam, "data");
                     if (!dataval.isStr()) {
                         throw JSONRPCError(
                             RPC_TYPE_ERROR,
                             "Missing data String key for proposal");
                     }
 
                     CBlock block;
                     if (!DecodeHexBlk(block, dataval.get_str())) {
                         throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
                                            "Block decode failed");
                     }
 
                     const BlockHash hash = block.GetHash();
                     const CBlockIndex *pindex =
                         g_chainman.m_blockman.LookupBlockIndex(hash);
                     if (pindex) {
                         if (pindex->IsValid(BlockValidity::SCRIPTS)) {
                             return "duplicate";
                         }
                         if (pindex->nStatus.isInvalid()) {
                             return "duplicate-invalid";
                         }
                         return "duplicate-inconclusive";
                     }
 
                     CBlockIndex *const pindexPrev = ::ChainActive().Tip();
                     // TestBlockValidity only supports blocks built on the
                     // current Tip
                     if (block.hashPrevBlock != pindexPrev->GetBlockHash()) {
                         return "inconclusive-not-best-prevblk";
                     }
                     BlockValidationState state;
                     TestBlockValidity(state, chainparams, ::ChainstateActive(),
                                       block, pindexPrev,
                                       BlockValidationOptions(config)
                                           .withCheckPoW(false)
                                           .withCheckMerkleRoot(true));
                     return BIP22ValidationResult(config, state);
                 }
             }
 
             if (strMode != "template") {
                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
             }
 
             NodeContext &node = EnsureNodeContext(request.context);
             if (!node.connman) {
                 throw JSONRPCError(
                     RPC_CLIENT_P2P_DISABLED,
                     "Error: Peer-to-peer functionality missing or disabled");
             }
 
             if (node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) {
                 throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED,
                                    "Bitcoin is not connected!");
             }
 
             if (::ChainstateActive().IsInitialBlockDownload()) {
                 throw JSONRPCError(
                     RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME
                     " is in initial sync and waiting for blocks...");
             }
 
             static unsigned int nTransactionsUpdatedLast;
             const CTxMemPool &mempool = EnsureMemPool(request.context);
 
             if (!lpval.isNull()) {
                 // Wait to respond until either the best block changes, OR a
                 // minute has passed and there are more transactions
                 uint256 hashWatchedChain;
                 std::chrono::steady_clock::time_point checktxtime;
                 unsigned int nTransactionsUpdatedLastLP;
 
                 if (lpval.isStr()) {
                     // Format: <hashBestChain><nTransactionsUpdatedLast>
                     std::string lpstr = lpval.get_str();
 
                     hashWatchedChain =
                         ParseHashV(lpstr.substr(0, 64), "longpollid");
                     nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64));
                 } else {
                     // NOTE: Spec does not specify behaviour for non-string
                     // longpollid, but this makes testing easier
                     hashWatchedChain = ::ChainActive().Tip()->GetBlockHash();
                     nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
                 }
 
                 // Release lock while waiting
                 LEAVE_CRITICAL_SECTION(cs_main);
                 {
                     checktxtime = std::chrono::steady_clock::now() +
                                   std::chrono::minutes(1);
 
                     WAIT_LOCK(g_best_block_mutex, lock);
                     while (g_best_block == hashWatchedChain && IsRPCRunning()) {
                         if (g_best_block_cv.wait_until(lock, checktxtime) ==
                             std::cv_status::timeout) {
                             // Timeout: Check transactions for update
                             // without holding the mempool look to avoid
                             // deadlocks
                             if (mempool.GetTransactionsUpdated() !=
                                 nTransactionsUpdatedLastLP) {
                                 break;
                             }
                             checktxtime += std::chrono::seconds(10);
                         }
                     }
                 }
                 ENTER_CRITICAL_SECTION(cs_main);
 
                 if (!IsRPCRunning()) {
                     throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED,
                                        "Shutting down");
                 }
                 // TODO: Maybe recheck connections/IBD and (if something wrong)
                 // send an expires-immediately template to stop miners?
             }
 
             // Update block
             static CBlockIndex *pindexPrev;
             static int64_t nStart;
             static std::unique_ptr<CBlockTemplate> pblocktemplate;
             if (pindexPrev != ::ChainActive().Tip() ||
                 (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast &&
                  GetTime() - nStart > 5)) {
                 // Clear pindexPrev so future calls make a new block, despite
                 // any failures from here on
                 pindexPrev = nullptr;
 
                 // Store the pindexBest used before CreateNewBlock, to avoid
                 // races
                 nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
                 CBlockIndex *pindexPrevNew = ::ChainActive().Tip();
                 nStart = GetTime();
 
                 // Create new block
                 CScript scriptDummy = CScript() << OP_TRUE;
                 pblocktemplate =
-                    BlockAssembler(config, mempool).CreateNewBlock(scriptDummy);
+                    BlockAssembler(config, mempool)
+                        .CreateNewBlock(::ChainstateActive(), scriptDummy);
                 if (!pblocktemplate) {
                     throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
                 }
 
                 // Need to update only after we know CreateNewBlock succeeded
                 pindexPrev = pindexPrevNew;
             }
 
             CHECK_NONFATAL(pindexPrev);
             // pointer for convenience
             CBlock *pblock = &pblocktemplate->block;
 
             // Update nTime
             UpdateTime(pblock, chainparams, pindexPrev);
             pblock->nNonce = 0;
 
             UniValue aCaps(UniValue::VARR);
             aCaps.push_back("proposal");
 
             Amount coinbasevalue = Amount::zero();
 
             UniValue transactions(UniValue::VARR);
             transactions.reserve(pblock->vtx.size());
             int index_in_template = 0;
             for (const auto &it : pblock->vtx) {
                 const CTransaction &tx = *it;
                 const TxId txId = tx.GetId();
 
                 if (tx.IsCoinBase()) {
                     index_in_template++;
 
                     for (const auto &o : pblock->vtx[0]->vout) {
                         coinbasevalue += o.nValue;
                     }
 
                     continue;
                 }
 
                 UniValue entry(UniValue::VOBJ);
                 entry.reserve(5);
                 entry.__pushKV("data", EncodeHexTx(tx));
                 entry.__pushKV("txid", txId.GetHex());
                 entry.__pushKV("hash", tx.GetHash().GetHex());
                 entry.__pushKV("fee",
                                pblocktemplate->entries[index_in_template].fees /
                                    SATOSHI);
                 int64_t nTxSigOps =
                     pblocktemplate->entries[index_in_template].sigOpCount;
                 entry.__pushKV("sigops", nTxSigOps);
 
                 transactions.push_back(entry);
                 index_in_template++;
             }
 
             UniValue aux(UniValue::VOBJ);
 
             UniValue minerFundList(UniValue::VARR);
             const Consensus::Params &consensusParams =
                 chainparams.GetConsensus();
             for (auto fundDestination :
                  GetMinerFundWhitelist(consensusParams, pindexPrev)) {
                 minerFundList.push_back(
                     EncodeDestination(fundDestination, config));
             }
 
             int64_t minerFundMinValue = 0;
             if (IsAxionEnabled(consensusParams, pindexPrev)) {
                 minerFundMinValue =
                     int64_t(GetMinerFundAmount(coinbasevalue) / SATOSHI);
             }
 
             UniValue minerFund(UniValue::VOBJ);
             minerFund.pushKV("addresses", minerFundList);
             minerFund.pushKV("minimumvalue", minerFundMinValue);
 
             UniValue coinbasetxn(UniValue::VOBJ);
             coinbasetxn.pushKV("minerfund", minerFund);
 
             arith_uint256 hashTarget =
                 arith_uint256().SetCompact(pblock->nBits);
 
             UniValue aMutable(UniValue::VARR);
             aMutable.push_back("time");
             aMutable.push_back("transactions");
             aMutable.push_back("prevblock");
 
             UniValue result(UniValue::VOBJ);
             result.pushKV("capabilities", aCaps);
 
             result.pushKV("version", pblock->nVersion);
 
             result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex());
             result.pushKV("transactions", transactions);
             result.pushKV("coinbaseaux", aux);
             result.pushKV("coinbasetxn", coinbasetxn);
             result.pushKV("coinbasevalue", int64_t(coinbasevalue / SATOSHI));
             result.pushKV("longpollid",
                           ::ChainActive().Tip()->GetBlockHash().GetHex() +
                               ToString(nTransactionsUpdatedLast));
             result.pushKV("target", hashTarget.GetHex());
             result.pushKV("mintime",
                           int64_t(pindexPrev->GetMedianTimePast()) + 1);
             result.pushKV("mutable", aMutable);
             result.pushKV("noncerange", "00000000ffffffff");
             result.pushKV("sigoplimit",
                           GetMaxBlockSigChecksCount(DEFAULT_MAX_BLOCK_SIZE));
             result.pushKV("sizelimit", DEFAULT_MAX_BLOCK_SIZE);
             result.pushKV("curtime", pblock->GetBlockTime());
             result.pushKV("bits", strprintf("%08x", pblock->nBits));
             result.pushKV("height", int64_t(pindexPrev->nHeight) + 1);
 
             return result;
         },
     };
 }
 
 class submitblock_StateCatcher final : public CValidationInterface {
 public:
     uint256 hash;
     bool found;
     BlockValidationState state;
 
     explicit submitblock_StateCatcher(const uint256 &hashIn)
         : hash(hashIn), found(false), state() {}
 
 protected:
     void BlockChecked(const CBlock &block,
                       const BlockValidationState &stateIn) override {
         if (block.GetHash() != hash) {
             return;
         }
 
         found = true;
         state = stateIn;
     }
 };
 
 static RPCHelpMan submitblock() {
     // We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
     return RPCHelpMan{
         "submitblock",
         "Attempts to submit new block to network.\n"
         "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n",
         {
             {"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "the hex-encoded block data to submit"},
             {"dummy", RPCArg::Type::STR, /* default */ "ignored",
              "dummy value, for compatibility with BIP22. This value is "
              "ignored."},
         },
         RPCResult{RPCResult::Type::NONE, "",
                   "Returns JSON Null when valid, a string according to BIP22 "
                   "otherwise"},
         RPCExamples{HelpExampleCli("submitblock", "\"mydata\"") +
                     HelpExampleRpc("submitblock", "\"mydata\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
             CBlock &block = *blockptr;
             if (!DecodeHexBlk(block, request.params[0].get_str())) {
                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
                                    "Block decode failed");
             }
 
             if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) {
                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
                                    "Block does not start with a coinbase");
             }
 
             const BlockHash hash = block.GetHash();
             {
                 LOCK(cs_main);
                 const CBlockIndex *pindex =
                     g_chainman.m_blockman.LookupBlockIndex(hash);
                 if (pindex) {
                     if (pindex->IsValid(BlockValidity::SCRIPTS)) {
                         return "duplicate";
                     }
                     if (pindex->nStatus.isInvalid()) {
                         return "duplicate-invalid";
                     }
                 }
             }
 
             bool new_block;
             auto sc =
                 std::make_shared<submitblock_StateCatcher>(block.GetHash());
             RegisterSharedValidationInterface(sc);
             bool accepted = EnsureChainman(request.context)
                                 .ProcessNewBlock(config, blockptr,
                                                  /* fForceProcessing */ true,
                                                  /* fNewBlock */ &new_block);
             UnregisterSharedValidationInterface(sc);
             if (!new_block && accepted) {
                 return "duplicate";
             }
 
             if (!sc->found) {
                 return "inconclusive";
             }
 
             return BIP22ValidationResult(config, sc->state);
         },
     };
 }
 
 static RPCHelpMan submitheader() {
     return RPCHelpMan{
         "submitheader",
         "Decode the given hexdata as a header and submit it as a candidate "
         "chain tip if valid."
         "\nThrows when the header is invalid.\n",
         {
             {"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "the hex-encoded block header data"},
         },
         RPCResult{RPCResult::Type::NONE, "", "None"},
         RPCExamples{HelpExampleCli("submitheader", "\"aabbcc\"") +
                     HelpExampleRpc("submitheader", "\"aabbcc\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             CBlockHeader h;
             if (!DecodeHexBlockHeader(h, request.params[0].get_str())) {
                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
                                    "Block header decode failed");
             }
             {
                 LOCK(cs_main);
                 if (!g_chainman.m_blockman.LookupBlockIndex(h.hashPrevBlock)) {
                     throw JSONRPCError(RPC_VERIFY_ERROR,
                                        "Must submit previous header (" +
                                            h.hashPrevBlock.GetHex() +
                                            ") first");
                 }
             }
 
             BlockValidationState state;
             EnsureChainman(request.context)
                 .ProcessNewBlockHeaders(config, {h}, state);
             if (state.IsValid()) {
                 return NullUniValue;
             }
             if (state.IsError()) {
                 throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
             }
             throw JSONRPCError(RPC_VERIFY_ERROR, state.GetRejectReason());
         },
     };
 }
 
 static RPCHelpMan estimatefee() {
     return RPCHelpMan{
         "estimatefee",
         "Estimates the approximate fee per kilobyte needed for a "
         "transaction\n",
         {},
         RPCResult{RPCResult::Type::NUM, "", "estimated fee-per-kilobyte"},
         RPCExamples{HelpExampleCli("estimatefee", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const CTxMemPool &mempool = EnsureMemPool(request.context);
             return mempool.estimateFee().GetFeePerK();
         },
     };
 }
 
 void RegisterMiningRPCCommands(CRPCTable &t) {
     // clang-format off
     static const CRPCCommand commands[] = {
         //  category    actor (function)
         //  ----------  ----------------------
         {"mining",      getnetworkhashps,      },
         {"mining",      getmininginfo,         },
         {"mining",      prioritisetransaction, },
         {"mining",      getblocktemplate,      },
         {"mining",      submitblock,           },
         {"mining",      submitheader,          },
 
         {"generating",  generatetoaddress,     },
         {"generating",  generatetodescriptor,  },
         {"generating",  generateblock,         },
 
         {"util",        estimatefee,           },
 
         {"hidden",      generate,              },
     };
     // clang-format on
     for (const auto &c : commands) {
         t.appendCommand(c.name, &c);
     }
 }
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index cb1442bd2..1f644c894 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -1,337 +1,338 @@
 // Copyright (c) 2017-2018 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <blockfilter.h>
 #include <chainparams.h>
 #include <config.h>
 #include <consensus/validation.h>
 #include <index/blockfilterindex.h>
 #include <miner.h>
 #include <pow/pow.h>
 #include <script/standard.h>
 #include <test/util/blockfilter.h>
 #include <test/util/setup_common.h>
 #include <validation.h>
 
 #include <boost/test/unit_test.hpp>
 
 BOOST_AUTO_TEST_SUITE(blockfilter_index_tests)
 
 struct BuildChainTestingSetup : public TestChain100Setup {
     CBlock CreateBlock(const CBlockIndex *prev,
                        const std::vector<CMutableTransaction> &txns,
                        const CScript &scriptPubKey);
     bool BuildChain(const CBlockIndex *pindex,
                     const CScript &coinbase_script_pub_key, size_t length,
                     std::vector<std::shared_ptr<CBlock>> &chain);
 };
 
 static bool CheckFilterLookups(BlockFilterIndex &filter_index,
                                const CBlockIndex *block_index,
                                uint256 &last_header) {
     BlockFilter expected_filter;
     if (!ComputeFilter(filter_index.GetFilterType(), block_index,
                        expected_filter)) {
         BOOST_ERROR("ComputeFilter failed on block " << block_index->nHeight);
         return false;
     }
 
     BlockFilter filter;
     uint256 filter_header;
     std::vector<BlockFilter> filters;
     std::vector<uint256> filter_hashes;
 
     BOOST_CHECK(filter_index.LookupFilter(block_index, filter));
     BOOST_CHECK(filter_index.LookupFilterHeader(block_index, filter_header));
     BOOST_CHECK(filter_index.LookupFilterRange(block_index->nHeight,
                                                block_index, filters));
     BOOST_CHECK(filter_index.LookupFilterHashRange(block_index->nHeight,
                                                    block_index, filter_hashes));
 
     BOOST_CHECK_EQUAL(filters.size(), 1U);
     BOOST_CHECK_EQUAL(filter_hashes.size(), 1U);
 
     BOOST_CHECK_EQUAL(filter.GetHash(), expected_filter.GetHash());
     BOOST_CHECK_EQUAL(filter_header,
                       expected_filter.ComputeHeader(last_header));
     BOOST_CHECK_EQUAL(filters[0].GetHash(), expected_filter.GetHash());
     BOOST_CHECK_EQUAL(filter_hashes[0], expected_filter.GetHash());
 
     filters.clear();
     filter_hashes.clear();
     last_header = filter_header;
     return true;
 }
 
 CBlock BuildChainTestingSetup::CreateBlock(
     const CBlockIndex *prev, const std::vector<CMutableTransaction> &txns,
     const CScript &scriptPubKey) {
     const Config &config = GetConfig();
     std::unique_ptr<CBlockTemplate> pblocktemplate =
-        BlockAssembler(config, *m_node.mempool).CreateNewBlock(scriptPubKey);
+        BlockAssembler(config, *m_node.mempool)
+            .CreateNewBlock(::ChainstateActive(), scriptPubKey);
     CBlock &block = pblocktemplate->block;
     block.hashPrevBlock = prev->GetBlockHash();
     block.nTime = prev->nTime + 1;
 
     // Replace mempool-selected txns with just coinbase plus passed-in txns:
     block.vtx.resize(1);
     for (const CMutableTransaction &tx : txns) {
         block.vtx.push_back(MakeTransactionRef(tx));
     }
     // IncrementExtraNonce creates a valid coinbase and merkleRoot
     unsigned int extraNonce = 0;
     IncrementExtraNonce(&block, prev, config.GetMaxBlockSize(), extraNonce);
 
     while (!CheckProofOfWork(block.GetHash(), block.nBits,
                              config.GetChainParams().GetConsensus())) {
         ++block.nNonce;
     }
 
     return block;
 }
 
 bool BuildChainTestingSetup::BuildChain(
     const CBlockIndex *pindex, const CScript &coinbase_script_pub_key,
     size_t length, std::vector<std::shared_ptr<CBlock>> &chain) {
     std::vector<CMutableTransaction> no_txns;
 
     chain.resize(length);
     for (auto &block : chain) {
         block = std::make_shared<CBlock>(
             CreateBlock(pindex, no_txns, coinbase_script_pub_key));
         CBlockHeader header = block->GetBlockHeader();
 
         BlockValidationState state;
         if (!Assert(m_node.chainman)
                  ->ProcessNewBlockHeaders(GetConfig(), {header}, state,
                                           &pindex)) {
             return false;
         }
     }
 
     return true;
 }
 
 BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync,
                         BuildChainTestingSetup) {
     BlockFilterIndex filter_index(BlockFilterType::BASIC, 1 << 20, true);
 
     uint256 last_header;
 
     // Filter should not be found in the index before it is started.
     {
         LOCK(cs_main);
 
         BlockFilter filter;
         uint256 filter_header;
         std::vector<BlockFilter> filters;
         std::vector<uint256> filter_hashes;
 
         for (const CBlockIndex *block_index = ::ChainActive().Genesis();
              block_index != nullptr;
              block_index = ::ChainActive().Next(block_index)) {
             BOOST_CHECK(!filter_index.LookupFilter(block_index, filter));
             BOOST_CHECK(
                 !filter_index.LookupFilterHeader(block_index, filter_header));
             BOOST_CHECK(!filter_index.LookupFilterRange(block_index->nHeight,
                                                         block_index, filters));
             BOOST_CHECK(!filter_index.LookupFilterHashRange(
                 block_index->nHeight, block_index, filter_hashes));
         }
     }
 
     // BlockUntilSyncedToCurrentChain should return false before index is
     // started.
     BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());
 
     filter_index.Start();
 
     // Allow filter index to catch up with the block index.
     constexpr int64_t timeout_ms = 10 * 1000;
     int64_t time_start = GetTimeMillis();
     while (!filter_index.BlockUntilSyncedToCurrentChain()) {
         BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis());
         UninterruptibleSleep(std::chrono::milliseconds{100});
     }
 
     // Check that filter index has all blocks that were in the chain before it
     // started.
     {
         LOCK(cs_main);
         const CBlockIndex *block_index;
         for (block_index = ::ChainActive().Genesis(); block_index != nullptr;
              block_index = ::ChainActive().Next(block_index)) {
             CheckFilterLookups(filter_index, block_index, last_header);
         }
     }
 
     // Create two forks.
     const CBlockIndex *tip;
     {
         LOCK(cs_main);
         tip = ::ChainActive().Tip();
     }
 
     // Make sure we disable reorg protection.
     gArgs.ForceSetArg("-parkdeepreorg", "false");
 
     CKey coinbase_key_A, coinbase_key_B;
     coinbase_key_A.MakeNewKey(true);
     coinbase_key_B.MakeNewKey(true);
     CScript coinbase_script_pub_key_A =
         GetScriptForDestination(PKHash(coinbase_key_A.GetPubKey()));
     CScript coinbase_script_pub_key_B =
         GetScriptForDestination(PKHash(coinbase_key_B.GetPubKey()));
     std::vector<std::shared_ptr<CBlock>> chainA, chainB;
     BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key_A, 10, chainA));
     BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key_B, 10, chainB));
 
     // Check that new blocks on chain A get indexed.
     uint256 chainA_last_header = last_header;
     for (size_t i = 0; i < 2; i++) {
         const auto &block = chainA[i];
         BOOST_REQUIRE(Assert(m_node.chainman)
                           ->ProcessNewBlock(GetConfig(), block, true, nullptr));
     }
     for (size_t i = 0; i < 2; i++) {
         const auto &block = chainA[i];
         const CBlockIndex *block_index;
         {
             LOCK(cs_main);
             block_index =
                 g_chainman.m_blockman.LookupBlockIndex(block->GetHash());
         }
 
         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
         CheckFilterLookups(filter_index, block_index, chainA_last_header);
     }
 
     // Reorg to chain B.
     uint256 chainB_last_header = last_header;
     for (size_t i = 0; i < 3; i++) {
         const auto &block = chainB[i];
         BOOST_REQUIRE(Assert(m_node.chainman)
                           ->ProcessNewBlock(GetConfig(), block, true, nullptr));
     }
     for (size_t i = 0; i < 3; i++) {
         const auto &block = chainB[i];
         const CBlockIndex *block_index;
         {
             LOCK(cs_main);
             block_index =
                 g_chainman.m_blockman.LookupBlockIndex(block->GetHash());
         }
 
         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
         CheckFilterLookups(filter_index, block_index, chainB_last_header);
     }
 
     // Check that filters for stale blocks on A can be retrieved.
     chainA_last_header = last_header;
     for (size_t i = 0; i < 2; i++) {
         const auto &block = chainA[i];
         const CBlockIndex *block_index;
         {
             LOCK(cs_main);
             block_index =
                 g_chainman.m_blockman.LookupBlockIndex(block->GetHash());
         }
 
         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
         CheckFilterLookups(filter_index, block_index, chainA_last_header);
     }
 
     // Reorg back to chain A.
     for (size_t i = 2; i < 4; i++) {
         const auto &block = chainA[i];
         BOOST_REQUIRE(Assert(m_node.chainman)
                           ->ProcessNewBlock(GetConfig(), block, true, nullptr));
     }
 
     // Check that chain A and B blocks can be retrieved.
     chainA_last_header = last_header;
     chainB_last_header = last_header;
     for (size_t i = 0; i < 3; i++) {
         const CBlockIndex *block_index;
 
         {
             LOCK(cs_main);
             block_index =
                 g_chainman.m_blockman.LookupBlockIndex(chainA[i]->GetHash());
         }
         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
         CheckFilterLookups(filter_index, block_index, chainA_last_header);
 
         {
             LOCK(cs_main);
             block_index =
                 g_chainman.m_blockman.LookupBlockIndex(chainB[i]->GetHash());
         }
         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
         CheckFilterLookups(filter_index, block_index, chainB_last_header);
     }
 
     // Test lookups for a range of filters/hashes.
     std::vector<BlockFilter> filters;
     std::vector<uint256> filter_hashes;
 
     {
         LOCK(cs_main);
         tip = ::ChainActive().Tip();
     }
     BOOST_CHECK(filter_index.LookupFilterRange(0, tip, filters));
     BOOST_CHECK(filter_index.LookupFilterHashRange(0, tip, filter_hashes));
 
     BOOST_CHECK(tip->nHeight >= 0);
     BOOST_CHECK_EQUAL(filters.size(), tip->nHeight + 1U);
     BOOST_CHECK_EQUAL(filter_hashes.size(), tip->nHeight + 1U);
 
     filters.clear();
     filter_hashes.clear();
 
     filter_index.Interrupt();
     filter_index.Stop();
 }
 
 BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup) {
     BlockFilterIndex *filter_index;
 
     filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
     BOOST_CHECK(filter_index == nullptr);
 
     BOOST_CHECK(
         InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
 
     filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
     BOOST_CHECK(filter_index != nullptr);
     BOOST_CHECK(filter_index->GetFilterType() == BlockFilterType::BASIC);
 
     // Initialize returns false if index already exists.
     BOOST_CHECK(
         !InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
 
     int iter_count = 0;
     ForEachBlockFilterIndex(
         [&iter_count](BlockFilterIndex &_index) { iter_count++; });
     BOOST_CHECK_EQUAL(iter_count, 1);
 
     BOOST_CHECK(DestroyBlockFilterIndex(BlockFilterType::BASIC));
 
     // Destroy returns false because index was already destroyed.
     BOOST_CHECK(!DestroyBlockFilterIndex(BlockFilterType::BASIC));
 
     filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
     BOOST_CHECK(filter_index == nullptr);
 
     // Reinitialize index.
     BOOST_CHECK(
         InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
 
     DestroyAllBlockFilterIndexes();
 
     filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
     BOOST_CHECK(filter_index == nullptr);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index e3c56ba7b..55c5021e9 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -1,740 +1,758 @@
 // Copyright (c) 2011-2019 The Bitcoin Core developers
 // Copyright (c) 2017-2020 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <miner.h>
 
 #include <chain.h>
 #include <chainparams.h>
 #include <coins.h>
 #include <config.h>
 #include <consensus/consensus.h>
 #include <consensus/merkle.h>
 #include <consensus/tx_verify.h>
 #include <consensus/validation.h>
 #include <policy/policy.h>
 #include <script/standard.h>
 #include <txmempool.h>
 #include <uint256.h>
 #include <util/strencodings.h>
 #include <util/string.h>
 #include <util/system.h>
 #include <util/time.h>
 #include <validation.h>
 
 #include <test/util/setup_common.h>
 
 #include <boost/test/unit_test.hpp>
 
 #include <memory>
 
 namespace miner_tests {
 struct MinerTestingSetup : public TestingSetup {
     void TestPackageSelection(const CChainParams &chainparams,
                               const CScript &scriptPubKey,
                               const std::vector<CTransactionRef> &txFirst)
         EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
     bool TestSequenceLocks(const CTransaction &tx, int flags)
         EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs) {
         return CheckSequenceLocks(::ChainstateActive(), *m_node.mempool, tx,
                                   flags);
     }
     BlockAssembler AssemblerForTest(const CChainParams &params);
 };
 } // namespace miner_tests
 
 BOOST_FIXTURE_TEST_SUITE(miner_tests, MinerTestingSetup)
 
 static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB);
 
 BlockAssembler MinerTestingSetup::AssemblerForTest(const CChainParams &params) {
     BlockAssembler::Options options;
     options.blockMinFeeRate = blockMinFeeRate;
     return BlockAssembler(params, *m_node.mempool, options);
 }
 
 constexpr static struct {
     uint8_t extranonce;
     uint32_t nonce;
 } blockinfo[] = {
     {4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5},
     {2, 0xce440296}, {2, 0x52cfe198}, {1, 0x77a72cd0}, {2, 0xbb5d6f84},
     {2, 0x83f30c2c}, {1, 0x48a73d5b}, {1, 0xef7dcd01}, {2, 0x6809c6c4},
     {2, 0x0883ab3c}, {1, 0x087bbbe2}, {2, 0x2104a814}, {2, 0xdffb6daa},
     {1, 0xee8a0a08}, {2, 0xba4237c1}, {1, 0xa70349dc}, {1, 0x344722bb},
     {3, 0xd6294733}, {2, 0xec9f5c94}, {2, 0xca2fbc28}, {1, 0x6ba4f406},
     {2, 0x015d4532}, {1, 0x6e119b7c}, {2, 0x43e8f314}, {2, 0x27962f38},
     {2, 0xb571b51b}, {2, 0xb36bee23}, {2, 0xd17924a8}, {2, 0x6bc212d9},
     {1, 0x630d4948}, {2, 0x9a4c4ebb}, {2, 0x554be537}, {1, 0xd63ddfc7},
     {2, 0xa10acc11}, {1, 0x759a8363}, {2, 0xfb73090d}, {1, 0xe82c6a34},
     {1, 0xe33e92d7}, {3, 0x658ef5cb}, {2, 0xba32ff22}, {5, 0x0227a10c},
     {1, 0xa9a70155}, {5, 0xd096d809}, {1, 0x37176174}, {1, 0x830b8d0f},
     {1, 0xc6e3910e}, {2, 0x823f3ca8}, {1, 0x99850849}, {1, 0x7521fb81},
     {1, 0xaacaabab}, {1, 0xd645a2eb}, {5, 0x7aea1781}, {5, 0x9d6e4b78},
     {1, 0x4ce90fd8}, {1, 0xabdc832d}, {6, 0x4a34f32a}, {2, 0xf2524c1c},
     {2, 0x1bbeb08a}, {1, 0xad47f480}, {1, 0x9f026aeb}, {1, 0x15a95049},
     {2, 0xd1cb95b2}, {2, 0xf84bbda5}, {1, 0x0fa62cd1}, {1, 0xe05f9169},
     {1, 0x78d194a9}, {5, 0x3e38147b}, {5, 0x737ba0d4}, {1, 0x63378e10},
     {1, 0x6d5f91cf}, {2, 0x88612eb8}, {2, 0xe9639484}, {1, 0xb7fabc9d},
     {2, 0x19b01592}, {1, 0x5a90dd31}, {2, 0x5bd7e028}, {2, 0x94d00323},
     {1, 0xa9b9c01a}, {1, 0x3a40de61}, {1, 0x56e7eec7}, {5, 0x859f7ef6},
     {1, 0xfd8e5630}, {1, 0x2b0c9f7f}, {1, 0xba700e26}, {1, 0x7170a408},
     {1, 0x70de86a8}, {1, 0x74d64cd5}, {1, 0x49e738a1}, {2, 0x6910b602},
     {0, 0x643c565f}, {1, 0x54264b3f}, {2, 0x97ea6396}, {2, 0x55174459},
     {2, 0x03e8779a}, {1, 0x98f34d8f}, {1, 0xc07b2b07}, {1, 0xdfe29668},
     {1, 0x3141c7c1}, {1, 0xb3b595f4}, {1, 0x735abf08}, {5, 0x623bfbce},
     {2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e},
     {2, 0xbbbeb305}, {2, 0xfe1c810a},
 };
 
 static CBlockIndex CreateBlockIndex(int nHeight)
     EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
     CBlockIndex index;
     index.nHeight = nHeight;
     index.pprev = ::ChainActive().Tip();
     return index;
 }
 
 // Test suite for ancestor feerate transaction selection.
 // Implemented as an additional function, rather than a separate test case,
 // to allow reusing the blockchain created in CreateNewBlock_validity.
 void MinerTestingSetup::TestPackageSelection(
     const CChainParams &chainparams, const CScript &scriptPubKey,
     const std::vector<CTransactionRef> &txFirst) {
     // Test the ancestor feerate transaction selection.
     TestMemPoolEntryHelper entry;
 
     // Test that a medium fee transaction will be selected after a higher fee
     // rate package with a low fee rate parent.
     CMutableTransaction tx;
     tx.vin.resize(1);
     tx.vin[0].scriptSig = CScript() << OP_1;
     tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
     tx.vout.resize(1);
     tx.vout[0].nValue = int64_t(5000000000LL - 1000) * SATOSHI;
     // This tx has a low fee: 1000 satoshis.
     // Save this txid for later use.
     TxId parentTxId = tx.GetId();
     m_node.mempool->addUnchecked(entry.Fee(1000 * SATOSHI)
                                      .Time(GetTime())
                                      .SpendsCoinbase(true)
                                      .FromTx(tx));
 
     // This tx has a medium fee: 10000 satoshis.
     tx.vin[0].prevout = COutPoint(txFirst[1]->GetId(), 0);
     tx.vout[0].nValue = int64_t(5000000000LL - 10000) * SATOSHI;
     TxId mediumFeeTxId = tx.GetId();
     m_node.mempool->addUnchecked(entry.Fee(10000 * SATOSHI)
                                      .Time(GetTime())
                                      .SpendsCoinbase(true)
                                      .FromTx(tx));
 
     // This tx has a high fee, but depends on the first transaction.
     tx.vin[0].prevout = COutPoint(parentTxId, 0);
     // 50k satoshi fee.
     tx.vout[0].nValue = int64_t(5000000000LL - 1000 - 50000) * SATOSHI;
     TxId highFeeTxId = tx.GetId();
     m_node.mempool->addUnchecked(entry.Fee(50000 * SATOSHI)
                                      .Time(GetTime())
                                      .SpendsCoinbase(false)
                                      .FromTx(tx));
 
     std::unique_ptr<CBlockTemplate> pblocktemplate =
-        AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+        AssemblerForTest(chainparams)
+            .CreateNewBlock(::ChainstateActive(), scriptPubKey);
     BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == parentTxId);
     BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == highFeeTxId);
     BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == mediumFeeTxId);
 
     // Test that a package below the block min tx fee doesn't get included
     tx.vin[0].prevout = COutPoint(highFeeTxId, 0);
     // 0 fee.
     tx.vout[0].nValue = int64_t(5000000000LL - 1000 - 50000) * SATOSHI;
     TxId freeTxId = tx.GetId();
     m_node.mempool->addUnchecked(entry.Fee(Amount::zero()).FromTx(tx));
     size_t freeTxSize = GetSerializeSize(tx, PROTOCOL_VERSION);
 
     // Calculate a fee on child transaction that will put the package just
     // below the block min tx fee (assuming 1 child tx of the same size).
     Amount feeToUse = blockMinFeeRate.GetFee(2 * freeTxSize) - SATOSHI;
 
     tx.vin[0].prevout = COutPoint(freeTxId, 0);
     tx.vout[0].nValue =
         int64_t(5000000000LL - 1000 - 50000) * SATOSHI - feeToUse;
     TxId lowFeeTxId = tx.GetId();
     m_node.mempool->addUnchecked(entry.Fee(feeToUse).FromTx(tx));
-    pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+    pblocktemplate = AssemblerForTest(chainparams)
+                         .CreateNewBlock(::ChainstateActive(), scriptPubKey);
     // Verify that the free tx and the low fee tx didn't get selected.
     for (const auto &txn : pblocktemplate->block.vtx) {
         BOOST_CHECK(txn->GetId() != freeTxId);
         BOOST_CHECK(txn->GetId() != lowFeeTxId);
     }
 
     // Test that packages above the min relay fee do get included, even if one
     // of the transactions is below the min relay fee. Remove the low fee
     // transaction and replace with a higher fee transaction
     m_node.mempool->removeRecursive(CTransaction(tx),
                                     MemPoolRemovalReason::REPLACED);
     // Now we should be just over the min relay fee.
     tx.vout[0].nValue -= 2 * SATOSHI;
     lowFeeTxId = tx.GetId();
     m_node.mempool->addUnchecked(entry.Fee(feeToUse + 2 * SATOSHI).FromTx(tx));
-    pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+    pblocktemplate = AssemblerForTest(chainparams)
+                         .CreateNewBlock(::ChainstateActive(), scriptPubKey);
     BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == freeTxId);
     BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == lowFeeTxId);
 
     // Test that transaction selection properly updates ancestor fee
     // calculations as ancestor transactions get included in a block. Add a
     // 0-fee transaction that has 2 outputs.
     tx.vin[0].prevout = COutPoint(txFirst[2]->GetId(), 0);
     tx.vout.resize(2);
     tx.vout[0].nValue = int64_t(5000000000LL - 100000000) * SATOSHI;
     // 1BCC output.
     tx.vout[1].nValue = 100000000 * SATOSHI;
     TxId freeTxId2 = tx.GetId();
     m_node.mempool->addUnchecked(
         entry.Fee(Amount::zero()).SpendsCoinbase(true).FromTx(tx));
 
     // This tx can't be mined by itself.
     tx.vin[0].prevout = COutPoint(freeTxId2, 0);
     tx.vout.resize(1);
     feeToUse = blockMinFeeRate.GetFee(freeTxSize);
     tx.vout[0].nValue = int64_t(5000000000LL - 100000000) * SATOSHI - feeToUse;
     TxId lowFeeTxId2 = tx.GetId();
     m_node.mempool->addUnchecked(
         entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
-    pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+    pblocktemplate = AssemblerForTest(chainparams)
+                         .CreateNewBlock(::ChainstateActive(), scriptPubKey);
 
     // Verify that this tx isn't selected.
     for (const auto &txn : pblocktemplate->block.vtx) {
         BOOST_CHECK(txn->GetId() != freeTxId2);
         BOOST_CHECK(txn->GetId() != lowFeeTxId2);
     }
 
     // This tx will be mineable, and should cause lowFeeTxId2 to be selected as
     // well.
     tx.vin[0].prevout = COutPoint(freeTxId2, 1);
     // 10k satoshi fee.
     tx.vout[0].nValue = (100000000 - 10000) * SATOSHI;
     m_node.mempool->addUnchecked(entry.Fee(10000 * SATOSHI).FromTx(tx));
-    pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+    pblocktemplate = AssemblerForTest(chainparams)
+                         .CreateNewBlock(::ChainstateActive(), scriptPubKey);
     BOOST_CHECK(pblocktemplate->block.vtx[8]->GetId() == lowFeeTxId2);
 }
 
 void TestCoinbaseMessageEB(uint64_t eb, std::string cbmsg,
                            const CTxMemPool &mempool) {
     GlobalConfig config;
     config.SetMaxBlockSize(eb);
 
     CScript scriptPubKey =
         CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909"
                               "a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112"
                               "de5c384df7ba0b8d578a4c702b6bf11d5f")
                   << OP_CHECKSIG;
 
     std::unique_ptr<CBlockTemplate> pblocktemplate =
-        BlockAssembler(config, mempool).CreateNewBlock(scriptPubKey);
+        BlockAssembler(config, mempool)
+            .CreateNewBlock(::ChainstateActive(), scriptPubKey);
 
     CBlock *pblock = &pblocktemplate->block;
 
     // IncrementExtraNonce creates a valid coinbase and merkleRoot
     unsigned int extraNonce = 0;
     IncrementExtraNonce(pblock, ::ChainActive().Tip(), config.GetMaxBlockSize(),
                         extraNonce);
     unsigned int nHeight = ::ChainActive().Tip()->nHeight + 1;
     std::vector<uint8_t> vec(cbmsg.begin(), cbmsg.end());
     BOOST_CHECK(pblock->vtx[0]->vin[0].scriptSig ==
                 (CScript() << nHeight << CScriptNum(extraNonce) << vec));
 }
 
 // Coinbase scriptSig has to contains the correct EB value
 // converted to MB, rounded down to the first decimal
 BOOST_AUTO_TEST_CASE(CheckCoinbase_EB) {
     TestCoinbaseMessageEB(1000001, "/EB1.0/", *m_node.mempool);
     TestCoinbaseMessageEB(2000000, "/EB2.0/", *m_node.mempool);
     TestCoinbaseMessageEB(8000000, "/EB8.0/", *m_node.mempool);
     TestCoinbaseMessageEB(8320000, "/EB8.3/", *m_node.mempool);
 }
 
 // NOTE: These tests rely on CreateNewBlock doing its own self-validation!
 BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) {
     // Note that by default, these tests run with size accounting enabled.
     GlobalConfig config;
     const CChainParams &chainparams = config.GetChainParams();
     CScript scriptPubKey =
         CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909"
                               "a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112"
                               "de5c384df7ba0b8d578a4c702b6bf11d5f")
                   << OP_CHECKSIG;
     std::unique_ptr<CBlockTemplate> pblocktemplate;
     CMutableTransaction tx;
     CScript script;
     TestMemPoolEntryHelper entry;
     entry.nFee = 11 * SATOSHI;
     entry.nHeight = 11;
 
     fCheckpointsEnabled = false;
 
     // Simple block creation, nothing special yet:
     BOOST_CHECK(pblocktemplate =
-                    AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+                    AssemblerForTest(chainparams)
+                        .CreateNewBlock(::ChainstateActive(), scriptPubKey));
 
     // We can't make transactions until we have inputs.
     // Therefore, load 110 blocks :)
     static_assert(std::size(blockinfo) == 110,
                   "Should have 110 blocks to import");
     int baseheight = 0;
     std::vector<CTransactionRef> txFirst;
     for (const auto &bi : blockinfo) {
         // pointer for convenience
         CBlock *pblock = &pblocktemplate->block;
         {
             LOCK(cs_main);
             pblock->nVersion = 1;
             pblock->nTime = ::ChainActive().Tip()->GetMedianTimePast() + 1;
             CMutableTransaction txCoinbase(*pblock->vtx[0]);
             txCoinbase.nVersion = 1;
             txCoinbase.vin[0].scriptSig = CScript();
             txCoinbase.vin[0].scriptSig.push_back(bi.extranonce);
             txCoinbase.vin[0].scriptSig.push_back(::ChainActive().Height());
             txCoinbase.vout.resize(1);
             txCoinbase.vout[0].scriptPubKey = CScript();
             pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
             if (txFirst.size() == 0) {
                 baseheight = ::ChainActive().Height();
             }
             if (txFirst.size() < 4) {
                 txFirst.push_back(pblock->vtx[0]);
             }
             pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
             pblock->nNonce = bi.nonce;
         }
         std::shared_ptr<const CBlock> shared_pblock =
             std::make_shared<const CBlock>(*pblock);
         BOOST_CHECK(
             Assert(m_node.chainman)
                 ->ProcessNewBlock(config, shared_pblock, true, nullptr));
         pblock->hashPrevBlock = pblock->GetHash();
     }
 
     LOCK(cs_main);
     LOCK(m_node.mempool->cs);
 
     // Just to make sure we can still make simple blocks.
     BOOST_CHECK(pblocktemplate =
-                    AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+                    AssemblerForTest(chainparams)
+                        .CreateNewBlock(::ChainstateActive(), scriptPubKey));
 
     const Amount BLOCKSUBSIDY = 50 * COIN;
     const Amount LOWFEE = CENT;
     const Amount HIGHFEE = COIN;
     const Amount HIGHERFEE = 4 * COIN;
 
     // block size > limit
     tx.vin.resize(1);
     tx.vin[0].scriptSig = CScript();
     // 18 * (520char + DROP) + OP_1 = 9433 bytes
     std::vector<uint8_t> vchData(520);
     for (unsigned int i = 0; i < 18; ++i) {
         tx.vin[0].scriptSig << vchData << OP_DROP;
     }
 
     tx.vin[0].scriptSig << OP_1;
     tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
     tx.vout.resize(1);
     tx.vout[0].nValue = BLOCKSUBSIDY;
     for (unsigned int i = 0; i < 128; ++i) {
         tx.vout[0].nValue -= LOWFEE;
         const TxId txid = tx.GetId();
         // Only first tx spends coinbase.
         bool spendsCoinbase = i == 0;
         m_node.mempool->addUnchecked(entry.Fee(LOWFEE)
                                          .Time(GetTime())
                                          .SpendsCoinbase(spendsCoinbase)
                                          .FromTx(tx));
         tx.vin[0].prevout = COutPoint(txid, 0);
     }
 
     BOOST_CHECK(pblocktemplate =
-                    AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+                    AssemblerForTest(chainparams)
+                        .CreateNewBlock(::ChainstateActive(), scriptPubKey));
     m_node.mempool->clear();
 
     // Orphan in mempool, template creation fails.
     m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
     BOOST_CHECK_EXCEPTION(
-        AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey),
+        AssemblerForTest(chainparams)
+            .CreateNewBlock(::ChainstateActive(), scriptPubKey),
         std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
     m_node.mempool->clear();
 
     // Child with higher priority than parent.
     tx.vin[0].scriptSig = CScript() << OP_1;
     tx.vin[0].prevout = COutPoint(txFirst[1]->GetId(), 0);
     tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
     TxId txid = tx.GetId();
     m_node.mempool->addUnchecked(
         entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
     tx.vin[0].prevout = COutPoint(txid, 0);
     tx.vin.resize(2);
     tx.vin[1].scriptSig = CScript() << OP_1;
     tx.vin[1].prevout = COutPoint(txFirst[0]->GetId(), 0);
     // First txn output + fresh coinbase - new txn fee.
     tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE;
     txid = tx.GetId();
     m_node.mempool->addUnchecked(
         entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
     BOOST_CHECK(pblocktemplate =
-                    AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+                    AssemblerForTest(chainparams)
+                        .CreateNewBlock(::ChainstateActive(), scriptPubKey));
     m_node.mempool->clear();
 
     // Coinbase in mempool, template creation fails.
     tx.vin.resize(1);
     tx.vin[0].prevout = COutPoint();
     tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
     tx.vout[0].nValue = Amount::zero();
     txid = tx.GetId();
     // Give it a fee so it'll get mined.
     m_node.mempool->addUnchecked(
         entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
     // Should throw bad-tx-coinbase
     BOOST_CHECK_EXCEPTION(
-        AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey),
+        AssemblerForTest(chainparams)
+            .CreateNewBlock(::ChainstateActive(), scriptPubKey),
         std::runtime_error, HasReason("bad-tx-coinbase"));
     m_node.mempool->clear();
 
     // Double spend txn pair in mempool, template creation fails.
     tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
     tx.vin[0].scriptSig = CScript() << OP_1;
     tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
     tx.vout[0].scriptPubKey = CScript() << OP_1;
     txid = tx.GetId();
     m_node.mempool->addUnchecked(
         entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
     tx.vout[0].scriptPubKey = CScript() << OP_2;
     txid = tx.GetId();
     m_node.mempool->addUnchecked(
         entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
     BOOST_CHECK_EXCEPTION(
-        AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey),
+        AssemblerForTest(chainparams)
+            .CreateNewBlock(::ChainstateActive(), scriptPubKey),
         std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
     m_node.mempool->clear();
 
     // Subsidy changing.
     int nHeight = ::ChainActive().Height();
     // Create an actual 209999-long block chain (without valid blocks).
     while (::ChainActive().Tip()->nHeight < 209999) {
         CBlockIndex *prev = ::ChainActive().Tip();
         CBlockIndex *next = new CBlockIndex();
         next->phashBlock = new BlockHash(InsecureRand256());
         ::ChainstateActive().CoinsTip().SetBestBlock(next->GetBlockHash());
         next->pprev = prev;
         next->nHeight = prev->nHeight + 1;
         next->BuildSkip();
         ::ChainActive().SetTip(next);
     }
     BOOST_CHECK(pblocktemplate =
-                    AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+                    AssemblerForTest(chainparams)
+                        .CreateNewBlock(::ChainstateActive(), scriptPubKey));
     // Extend to a 210000-long block chain.
     while (::ChainActive().Tip()->nHeight < 210000) {
         CBlockIndex *prev = ::ChainActive().Tip();
         CBlockIndex *next = new CBlockIndex();
         next->phashBlock = new BlockHash(InsecureRand256());
         ::ChainstateActive().CoinsTip().SetBestBlock(next->GetBlockHash());
         next->pprev = prev;
         next->nHeight = prev->nHeight + 1;
         next->BuildSkip();
         ::ChainActive().SetTip(next);
     }
 
     BOOST_CHECK(pblocktemplate =
-                    AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+                    AssemblerForTest(chainparams)
+                        .CreateNewBlock(::ChainstateActive(), scriptPubKey));
 
     // Invalid p2sh txn in mempool, template creation fails
     tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
     tx.vin[0].scriptSig = CScript() << OP_1;
     tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE;
     script = CScript() << OP_0;
     tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
     txid = tx.GetId();
     m_node.mempool->addUnchecked(
         entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
     tx.vin[0].prevout = COutPoint(txid, 0);
     tx.vin[0].scriptSig = CScript()
                           << std::vector<uint8_t>(script.begin(), script.end());
     tx.vout[0].nValue -= LOWFEE;
     txid = tx.GetId();
     m_node.mempool->addUnchecked(
         entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
     // Should throw blk-bad-inputs
     BOOST_CHECK_EXCEPTION(
-        AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey),
+        AssemblerForTest(chainparams)
+            .CreateNewBlock(::ChainstateActive(), scriptPubKey),
         std::runtime_error, HasReason("blk-bad-inputs"));
     m_node.mempool->clear();
 
     // Delete the dummy blocks again.
     while (::ChainActive().Tip()->nHeight > nHeight) {
         CBlockIndex *del = ::ChainActive().Tip();
         ::ChainActive().SetTip(del->pprev);
         ::ChainstateActive().CoinsTip().SetBestBlock(
             del->pprev->GetBlockHash());
         delete del->phashBlock;
         delete del;
     }
 
     // non-final txs in mempool
     SetMockTime(::ChainActive().Tip()->GetMedianTimePast() + 1);
     uint32_t flags = LOCKTIME_VERIFY_SEQUENCE | LOCKTIME_MEDIAN_TIME_PAST;
     // height map
     std::vector<int> prevheights;
 
     // Relative height locked.
     tx.nVersion = 2;
     tx.vin.resize(1);
     prevheights.resize(1);
     // Only 1 transaction.
     tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
     tx.vin[0].scriptSig = CScript() << OP_1;
     // txFirst[0] is the 2nd block
     tx.vin[0].nSequence = ::ChainActive().Tip()->nHeight + 1;
     prevheights[0] = baseheight + 1;
     tx.vout.resize(1);
     tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
     tx.vout[0].scriptPubKey = CScript() << OP_1;
     tx.nLockTime = 0;
     txid = tx.GetId();
     m_node.mempool->addUnchecked(
         entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
 
     const Consensus::Params &params = chainparams.GetConsensus();
 
     {
         // Locktime passes.
         TxValidationState state;
         BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(
             ::ChainActive().Tip(), params, CTransaction(tx), state, flags));
     }
 
     // Sequence locks fail.
     BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
     // Sequence locks pass on 2nd block.
     BOOST_CHECK(
         SequenceLocks(CTransaction(tx), flags, prevheights,
                       CreateBlockIndex(::ChainActive().Tip()->nHeight + 2)));
 
     // Relative time locked.
     tx.vin[0].prevout = COutPoint(txFirst[1]->GetId(), 0);
     // txFirst[1] is the 3rd block.
     tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG |
                           (((::ChainActive().Tip()->GetMedianTimePast() + 1 -
                              ::ChainActive()[1]->GetMedianTimePast()) >>
                             CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) +
                            1);
     prevheights[0] = baseheight + 2;
     txid = tx.GetId();
     m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
 
     {
         // Locktime passes.
         TxValidationState state;
         BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(
             ::ChainActive().Tip(), params, CTransaction(tx), state, flags));
     }
 
     // Sequence locks fail.
     BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
 
     for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
         // Trick the MedianTimePast.
         ::ChainActive()
             .Tip()
             ->GetAncestor(::ChainActive().Tip()->nHeight - i)
             ->nTime += 512;
     }
     // Sequence locks pass 512 seconds later.
     BOOST_CHECK(
         SequenceLocks(CTransaction(tx), flags, prevheights,
                       CreateBlockIndex(::ChainActive().Tip()->nHeight + 1)));
     for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
         // Undo tricked MTP.
         ::ChainActive()
             .Tip()
             ->GetAncestor(::ChainActive().Tip()->nHeight - i)
             ->nTime -= 512;
     }
 
     // Absolute height locked.
     tx.vin[0].prevout = COutPoint(txFirst[2]->GetId(), 0);
     tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1;
     prevheights[0] = baseheight + 3;
     tx.nLockTime = ::ChainActive().Tip()->nHeight + 1;
     txid = tx.GetId();
     m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
 
     {
         // Locktime fails.
         TxValidationState state;
         BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock(
             ::ChainActive().Tip(), params, CTransaction(tx), state, flags));
         BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-nonfinal");
     }
 
     // Sequence locks pass.
     BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
 
     {
         // Locktime passes on 2nd block.
         TxValidationState state;
         int64_t nMedianTimePast = ::ChainActive().Tip()->GetMedianTimePast();
         BOOST_CHECK(ContextualCheckTransaction(
             params, CTransaction(tx), state, ::ChainActive().Tip()->nHeight + 2,
             nMedianTimePast, nMedianTimePast));
     }
 
     // Absolute time locked.
     tx.vin[0].prevout = COutPoint(txFirst[3]->GetId(), 0);
     tx.nLockTime = ::ChainActive().Tip()->GetMedianTimePast();
     prevheights.resize(1);
     prevheights[0] = baseheight + 4;
     txid = tx.GetId();
     m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
 
     {
         // Locktime fails.
         TxValidationState state;
         BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock(
             ::ChainActive().Tip(), params, CTransaction(tx), state, flags));
         BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-nonfinal");
     }
 
     // Sequence locks pass.
     BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
 
     {
         // Locktime passes 1 second later.
         TxValidationState state;
         int64_t nMedianTimePast =
             ::ChainActive().Tip()->GetMedianTimePast() + 1;
         BOOST_CHECK(ContextualCheckTransaction(
             params, CTransaction(tx), state, ::ChainActive().Tip()->nHeight + 1,
             nMedianTimePast, nMedianTimePast));
     }
 
     // mempool-dependent transactions (not added)
     tx.vin[0].prevout = COutPoint(txid, 0);
     prevheights[0] = ::ChainActive().Tip()->nHeight + 1;
     tx.nLockTime = 0;
     tx.vin[0].nSequence = 0;
 
     {
         // Locktime passes.
         TxValidationState state;
         BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(
             ::ChainActive().Tip(), params, CTransaction(tx), state, flags));
     }
 
     // Sequence locks pass.
     BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
     tx.vin[0].nSequence = 1;
     // Sequence locks fail.
     BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
     tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG;
     // Sequence locks pass.
     BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
     tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1;
     // Sequence locks fail.
     BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
 
-    pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+    pblocktemplate = AssemblerForTest(chainparams)
+                         .CreateNewBlock(::ChainstateActive(), scriptPubKey);
     BOOST_CHECK(pblocktemplate);
 
     // None of the of the absolute height/time locked tx should have made it
     // into the template because we still check IsFinalTx in CreateNewBlock, but
     // relative locked txs will if inconsistently added to g_mempool. For now
     // these will still generate a valid template until BIP68 soft fork.
     BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3UL);
     // However if we advance height by 1 and time by 512, all of them should be
     // mined.
     for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
         // Trick the MedianTimePast.
         ::ChainActive()
             .Tip()
             ->GetAncestor(::ChainActive().Tip()->nHeight - i)
             ->nTime += 512;
     }
     ::ChainActive().Tip()->nHeight++;
     SetMockTime(::ChainActive().Tip()->GetMedianTimePast() + 1);
 
     BOOST_CHECK(pblocktemplate =
-                    AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+                    AssemblerForTest(chainparams)
+                        .CreateNewBlock(::ChainstateActive(), scriptPubKey));
     BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5UL);
 
     ::ChainActive().Tip()->nHeight--;
     SetMockTime(0);
     m_node.mempool->clear();
 
     TestPackageSelection(chainparams, scriptPubKey, txFirst);
 
     fCheckpointsEnabled = true;
 }
 
 void CheckBlockMaxSize(const Config &config, const CTxMemPool &mempool,
                        uint64_t size, uint64_t expected) {
     gArgs.ForceSetArg("-blockmaxsize", ToString(size));
 
     BlockAssembler ba(config, mempool);
     BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), expected);
 }
 
 BOOST_AUTO_TEST_CASE(BlockAssembler_construction) {
     GlobalConfig config;
 
     // We are working on a fake chain and need to protect ourselves.
     LOCK(cs_main);
 
     // Test around historical 1MB (plus one byte because that's mandatory)
     config.SetMaxBlockSize(ONE_MEGABYTE + 1);
     CheckBlockMaxSize(config, *m_node.mempool, 0, 1000);
     CheckBlockMaxSize(config, *m_node.mempool, 1000, 1000);
     CheckBlockMaxSize(config, *m_node.mempool, 1001, 1001);
     CheckBlockMaxSize(config, *m_node.mempool, 12345, 12345);
 
     CheckBlockMaxSize(config, *m_node.mempool, ONE_MEGABYTE - 1001,
                       ONE_MEGABYTE - 1001);
     CheckBlockMaxSize(config, *m_node.mempool, ONE_MEGABYTE - 1000,
                       ONE_MEGABYTE - 1000);
     CheckBlockMaxSize(config, *m_node.mempool, ONE_MEGABYTE - 999,
                       ONE_MEGABYTE - 999);
     CheckBlockMaxSize(config, *m_node.mempool, ONE_MEGABYTE,
                       ONE_MEGABYTE - 999);
 
     // Test around default cap
     config.SetMaxBlockSize(DEFAULT_MAX_BLOCK_SIZE);
 
     // Now we can use the default max block size.
     CheckBlockMaxSize(config, *m_node.mempool, DEFAULT_MAX_BLOCK_SIZE - 1001,
                       DEFAULT_MAX_BLOCK_SIZE - 1001);
     CheckBlockMaxSize(config, *m_node.mempool, DEFAULT_MAX_BLOCK_SIZE - 1000,
                       DEFAULT_MAX_BLOCK_SIZE - 1000);
     CheckBlockMaxSize(config, *m_node.mempool, DEFAULT_MAX_BLOCK_SIZE - 999,
                       DEFAULT_MAX_BLOCK_SIZE - 1000);
     CheckBlockMaxSize(config, *m_node.mempool, DEFAULT_MAX_BLOCK_SIZE,
                       DEFAULT_MAX_BLOCK_SIZE - 1000);
 
     // If the parameter is not specified, we use
     // DEFAULT_MAX_GENERATED_BLOCK_SIZE
     {
         gArgs.ClearForcedArg("-blockmaxsize");
         BlockAssembler ba(config, *m_node.mempool);
         BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(),
                           DEFAULT_MAX_GENERATED_BLOCK_SIZE);
     }
 }
 
 BOOST_AUTO_TEST_CASE(TestCBlockTemplateEntry) {
     const CTransaction tx;
     CTransactionRef txRef = MakeTransactionRef(tx);
     CBlockTemplateEntry txEntry(txRef, 1 * SATOSHI, 10);
     BOOST_CHECK_MESSAGE(txEntry.tx == txRef, "Transactions did not match");
     BOOST_CHECK_EQUAL(txEntry.fees, 1 * SATOSHI);
     BOOST_CHECK_EQUAL(txEntry.sigOpCount, 10);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp
index 6ce0d7251..9d8b5f8e7 100644
--- a/src/test/util/mining.cpp
+++ b/src/test/util/mining.cpp
@@ -1,57 +1,57 @@
 // Copyright (c) 2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <test/util/mining.h>
 
 #include <chainparams.h>
 #include <config.h>
 #include <consensus/merkle.h>
 #include <key_io.h>
 #include <miner.h>
 #include <node/context.h>
 #include <pow/pow.h>
 #include <script/standard.h>
 #include <util/check.h>
 #include <validation.h>
 
 CTxIn generatetoaddress(const Config &config, const NodeContext &node,
                         const std::string &address) {
     const auto dest = DecodeDestination(address, config.GetChainParams());
     assert(IsValidDestination(dest));
     const auto coinbase_script = GetScriptForDestination(dest);
 
     return MineBlock(config, node, coinbase_script);
 }
 
 CTxIn MineBlock(const Config &config, const NodeContext &node,
                 const CScript &coinbase_scriptPubKey) {
     auto block = PrepareBlock(config, node, coinbase_scriptPubKey);
 
     while (!CheckProofOfWork(block->GetHash(), block->nBits,
                              config.GetChainParams().GetConsensus())) {
         ++block->nNonce;
         assert(block->nNonce);
     }
 
     bool processed{
         Assert(node.chainman)->ProcessNewBlock(config, block, true, nullptr)};
     assert(processed);
 
     return CTxIn{block->vtx[0]->GetId(), 0};
 }
 
 std::shared_ptr<CBlock> PrepareBlock(const Config &config,
                                      const NodeContext &node,
                                      const CScript &coinbase_scriptPubKey) {
-    auto block =
-        std::make_shared<CBlock>(BlockAssembler{config, *Assert(node.mempool)}
-                                     .CreateNewBlock(coinbase_scriptPubKey)
-                                     ->block);
+    auto block = std::make_shared<CBlock>(
+        BlockAssembler{config, *Assert(node.mempool)}
+            .CreateNewBlock(::ChainstateActive(), coinbase_scriptPubKey)
+            ->block);
 
     LOCK(cs_main);
     block->nTime = ::ChainActive().Tip()->GetMedianTimePast() + 1;
     block->hashMerkleRoot = BlockMerkleRoot(*block);
 
     return block;
 }
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index be690a2bb..d96660ec3 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -1,416 +1,417 @@
 // Copyright (c) 2011-2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <test/util/setup_common.h>
 
 #include <banman.h>
 #include <chainparams.h>
 #include <config.h>
 #include <consensus/consensus.h>
 #include <consensus/validation.h>
 #include <crypto/sha256.h>
 #include <init.h>
 #include <interfaces/chain.h>
 #include <logging.h>
 #include <miner.h>
 #include <net.h>
 #include <net_processing.h>
 #include <noui.h>
 #include <pow/pow.h>
 #include <rpc/blockchain.h>
 #include <rpc/register.h>
 #include <rpc/server.h>
 #include <scheduler.h>
 #include <script/script_error.h>
 #include <script/scriptcache.h>
 #include <script/sigcache.h>
 #include <streams.h>
 #include <txdb.h>
 #include <txmempool.h>
 #include <util/strencodings.h>
 #include <util/time.h>
 #include <util/translation.h>
 #include <util/vector.h>
 #include <validation.h>
 #include <validationinterface.h>
 #include <walletinitinterface.h>
 
 #include <functional>
 #include <memory>
 
 const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr;
 
 FastRandomContext g_insecure_rand_ctx;
 /**
  * Random context to get unique temp data dirs. Separate from
  * g_insecure_rand_ctx, which can be seeded from a const env var
  */
 static FastRandomContext g_insecure_rand_ctx_temp_path;
 
 /**
  * Return the unsigned from the environment var if available,
  * otherwise 0
  */
 static uint256 GetUintFromEnv(const std::string &env_name) {
     const char *num = std::getenv(env_name.c_str());
     if (!num) {
         return {};
     }
     return uint256S(num);
 }
 
 void Seed(FastRandomContext &ctx) {
     // Should be enough to get the seed once for the process
     static uint256 seed{};
     static const std::string RANDOM_CTX_SEED{"RANDOM_CTX_SEED"};
     if (seed.IsNull()) {
         seed = GetUintFromEnv(RANDOM_CTX_SEED);
     }
     if (seed.IsNull()) {
         seed = GetRandHash();
     }
     LogPrintf("%s: Setting random seed for current tests to %s=%s\n", __func__,
               RANDOM_CTX_SEED, seed.GetHex());
     ctx = FastRandomContext(seed);
 }
 
 std::ostream &operator<<(std::ostream &os, const uint256 &num) {
     os << num.ToString();
     return os;
 }
 
 std::ostream &operator<<(std::ostream &os, const ScriptError &err) {
     os << ScriptErrorString(err);
     return os;
 }
 
 std::vector<const char *> fixture_extra_args{};
 
 BasicTestingSetup::BasicTestingSetup(
     const std::string &chainName, const std::vector<const char *> &extra_args)
     : m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME /
                   g_insecure_rand_ctx_temp_path.rand256().ToString()},
       m_args{} {
     // clang-format off
     std::vector<const char *> arguments = Cat(
         {
             "dummy",
             "-printtoconsole=0",
             "-logsourcelocations",
             "-logtimemicros",
             "-debug",
             "-debugexclude=libevent",
             "-debugexclude=leveldb",
         },
         extra_args);
     // clang-format on
     arguments = Cat(arguments, fixture_extra_args);
     auto &config = const_cast<Config &>(GetConfig());
     SetMockTime(0);
     fs::create_directories(m_path_root);
     m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
     gArgs.ForceSetArg("-datadir", fs::PathToString(m_path_root));
     gArgs.ClearPathCache();
     {
         SetupServerArgs(m_node);
         std::string error;
         const bool success{m_node.args->ParseParameters(
             arguments.size(), arguments.data(), error)};
         assert(success);
         assert(error.empty());
     }
     SelectParams(chainName);
     SeedInsecureRand();
     InitLogging(*m_node.args);
     AppInitParameterInteraction(config, *m_node.args);
     LogInstance().StartLogging();
     SHA256AutoDetect();
     ECC_Start();
     SetupEnvironment();
     SetupNetworking();
     InitSignatureCache();
     InitScriptExecutionCache();
 
     m_node.chain = interfaces::MakeChain(m_node, config.GetChainParams());
     g_wallet_init_interface.Construct(m_node);
 
     fCheckBlockIndex = true;
     static bool noui_connected = false;
     if (!noui_connected) {
         noui_connect();
         noui_connected = true;
     }
 }
 
 BasicTestingSetup::~BasicTestingSetup() {
     LogInstance().DisconnectTestLogger();
     fs::remove_all(m_path_root);
     gArgs.ClearArgs();
     ECC_Stop();
 }
 
 ChainTestingSetup::ChainTestingSetup(
     const std::string &chainName, const std::vector<const char *> &extra_args)
     : BasicTestingSetup(chainName, extra_args) {
     // We have to run a scheduler thread to prevent ActivateBestChain
     // from blocking due to queue overrun.
     m_node.scheduler = std::make_unique<CScheduler>();
     m_node.scheduler->m_service_thread = std::thread([&] {
         TraceThread("scheduler", [&] { m_node.scheduler->serviceQueue(); });
     });
     GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler);
 
     pblocktree.reset(new CBlockTreeDB(1 << 20, true));
 
     m_node.mempool = std::make_unique<CTxMemPool>(1);
 
     m_node.chainman = &::g_chainman;
 
     constexpr int script_check_threads = 2;
     StartScriptCheckWorkerThreads(script_check_threads);
 }
 
 ChainTestingSetup::~ChainTestingSetup() {
     if (m_node.scheduler) {
         m_node.scheduler->stop();
     }
     StopScriptCheckWorkerThreads();
     GetMainSignals().FlushBackgroundCallbacks();
     GetMainSignals().UnregisterBackgroundSignalScheduler();
     m_node.connman.reset();
     m_node.banman.reset();
     m_node.args = nullptr;
     UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman);
     m_node.mempool.reset();
     m_node.scheduler.reset();
     m_node.chainman->Reset();
     m_node.chainman = nullptr;
     pblocktree.reset();
 }
 
 TestingSetup::TestingSetup(const std::string &chainName,
                            const std::vector<const char *> &extra_args)
     : ChainTestingSetup(chainName, extra_args) {
     const Config &config = GetConfig();
     const CChainParams &chainparams = config.GetChainParams();
 
     // Ideally we'd move all the RPC tests to the functional testing framework
     // instead of unit tests, but for now we need these here.
     RPCServer rpcServer;
     RegisterAllRPCCommands(config, rpcServer, tableRPC);
 
     /**
      * RPC does not come out of the warmup state on its own. Normally, this is
      * handled in bitcoind's init path, but unit tests do not trigger this
      * codepath, so we call it explicitly as part of setup.
      */
     std::string rpcWarmupStatus;
     if (RPCIsInWarmup(&rpcWarmupStatus)) {
         SetRPCWarmupFinished();
     }
 
     m_node.chainman->InitializeChainstate(*m_node.mempool);
     ::ChainstateActive().InitCoinsDB(
         /* cache_size_bytes */ 1 << 23, /* in_memory */ true,
         /* should_wipe */ false);
     assert(!::ChainstateActive().CanFlushToDisk());
     ::ChainstateActive().InitCoinsCache(1 << 23);
     assert(::ChainstateActive().CanFlushToDisk());
     if (!::ChainstateActive().LoadGenesisBlock(chainparams)) {
         throw std::runtime_error("LoadGenesisBlock failed.");
     }
     {
         BlockValidationState state;
         if (!::ChainstateActive().ActivateBestChain(config, state)) {
             throw std::runtime_error(
                 strprintf("ActivateBestChain failed. (%s)", state.ToString()));
         }
     }
 
     m_node.banman = std::make_unique<BanMan>(
         m_args.GetDataDirPath() / "banlist.dat", chainparams, nullptr,
         DEFAULT_MISBEHAVING_BANTIME);
     // Deterministic randomness for tests.
     m_node.connman = std::make_unique<CConnman>(config, 0x1337, 0x1337);
     m_node.peerman = PeerManager::make(
         chainparams, *m_node.connman, m_node.banman.get(), *m_node.scheduler,
         *m_node.chainman, *m_node.mempool, false);
     {
         CConnman::Options options;
         options.m_msgproc = m_node.peerman.get();
         m_node.connman->Init(options);
     }
 }
 
 TestChain100Setup::TestChain100Setup() {
     // Generate a 100-block chain:
     coinbaseKey.MakeNewKey(true);
     CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey())
                                      << OP_CHECKSIG;
     for (int i = 0; i < COINBASE_MATURITY; i++) {
         std::vector<CMutableTransaction> noTxns;
         CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
         m_coinbase_txns.push_back(b.vtx[0]);
     }
 }
 
 CBlock TestChain100Setup::CreateAndProcessBlock(
     const std::vector<CMutableTransaction> &txns, const CScript &scriptPubKey) {
     const Config &config = GetConfig();
     CTxMemPool empty_pool;
-    CBlock block =
-        BlockAssembler(config, empty_pool).CreateNewBlock(scriptPubKey)->block;
+    CBlock block = BlockAssembler(config, empty_pool)
+                       .CreateNewBlock(::ChainstateActive(), scriptPubKey)
+                       ->block;
 
     Assert(block.vtx.size() == 1);
     for (const CMutableTransaction &tx : txns) {
         block.vtx.push_back(MakeTransactionRef(tx));
     }
 
     // Order transactions by canonical order
     std::sort(std::begin(block.vtx) + 1, std::end(block.vtx),
               [](const std::shared_ptr<const CTransaction> &txa,
                  const std::shared_ptr<const CTransaction> &txb) -> bool {
                   return txa->GetId() < txb->GetId();
               });
 
     // IncrementExtraNonce creates a valid coinbase and merkleRoot
     {
         LOCK(cs_main);
         unsigned int extraNonce = 0;
         IncrementExtraNonce(&block, ::ChainActive().Tip(),
                             config.GetMaxBlockSize(), extraNonce);
     }
 
     const Consensus::Params &params = config.GetChainParams().GetConsensus();
     while (!CheckProofOfWork(block.GetHash(), block.nBits, params)) {
         ++block.nNonce;
     }
 
     std::shared_ptr<const CBlock> shared_pblock =
         std::make_shared<const CBlock>(block);
     Assert(m_node.chainman)
         ->ProcessNewBlock(config, shared_pblock, true, nullptr);
 
     return block;
 }
 
 TestChain100Setup::~TestChain100Setup() {}
 
 CTxMemPoolEntry
 TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) const {
     return FromTx(MakeTransactionRef(tx));
 }
 
 CTxMemPoolEntry
 TestMemPoolEntryHelper::FromTx(const CTransactionRef &tx) const {
     return CTxMemPoolEntry(tx, nFee, nTime, nHeight, spendsCoinbase,
                            nSigOpCount, LockPoints());
 }
 
 /**
  * @returns a real block
  * (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af) with 9
  * txs.
  */
 CBlock getBlock13b8a() {
     CBlock block;
     CDataStream stream(
         ParseHex(
             "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb680000000"
             "0000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558"
             "da2fdb261b4d4c86041b1ab1bf9309010000000100000000000000000000000000"
             "00000000000000000000000000000000000000ffffffff07044c86041b0146ffff"
             "ffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf2"
             "54bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c"
             "4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada9027"
             "80da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100da"
             "b24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd0221"
             "00fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb4"
             "01ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369e"
             "d2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98e"
             "c706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad"
             "2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21ad"
             "c6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e86"
             "25a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d8982"
             "35e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff02"
             "80969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388"
             "ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd3"
             "88ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c522"
             "92d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3"
             "889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2f"
             "afd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d3"
             "1b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83aba"
             "f975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cb"
             "cba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044"
             "022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae7406056"
             "58022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e0100"
             "3614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c342"
             "3e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc"
             "2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13"
             "fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021"
             "e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91"
             "c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b4830"
             "4502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9"
             "236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddc"
             "ce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d78990"
             "4f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8"
             "ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942"
             "fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad5652937"
             "1864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd9"
             "0111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37"
             "f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b"
             "25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d0014104"
             "43bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf"
             "7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffff"
             "ffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a1232"
             "2d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70a"
             "e67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176"
             "f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf"
             "062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b956"
             "00db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd40"
             "67b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c6"
             "9b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e"
             "58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b217901000000"
             "8b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3c"
             "a2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b49"
             "1d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33"
             "d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312e"
             "f1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144a"
             "f553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd"
             "48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b"
             "659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0"
             "aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc3"
             "1895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9"
             "944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830"
             "450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1a"
             "f03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d9"
             "8a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d78990"
             "4f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8"
             "ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a03"
             "8fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261"
             "b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f6351285"
             "0811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa4207"
             "0082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0"
             "c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c0000000000"
             "1976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000"
             "000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed"
             "8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc"
             "87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded"
             "4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e"
             "3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29"
             "934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695"
             "a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93"
             "376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e9"
             "1349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49"
             "304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654"
             "d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66"
             "ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e88"
             "60c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8"
             "fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb604203"
             "4aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75e"
             "ef7942fc9288edd37c32f5c388ac00000000"),
         SER_NETWORK, PROTOCOL_VERSION);
     stream >> block;
     return block;
 }
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 05bfd6264..6ccb2e39b 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -1,389 +1,389 @@
 // Copyright (c) 2018-2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <boost/test/unit_test.hpp>
 
 #include <chain.h>
 #include <chainparams.h>
 #include <config.h>
 #include <consensus/merkle.h>
 #include <consensus/validation.h>
 #include <miner.h>
 #include <pow/pow.h>
 #include <random.h>
 #include <script/standard.h>
 #include <test/util/setup_common.h>
 #include <util/time.h>
 #include <validation.h>
 #include <validationinterface.h>
 
 #include <thread>
 
 namespace validation_block_tests {
 struct MinerTestingSetup : public RegTestingSetup {
     std::shared_ptr<CBlock> Block(const Config &config,
                                   const BlockHash &prev_hash);
     std::shared_ptr<const CBlock> GoodBlock(const Config &config,
                                             const BlockHash &prev_hash);
     std::shared_ptr<const CBlock> BadBlock(const Config &config,
                                            const BlockHash &prev_hash);
     std::shared_ptr<CBlock> FinalizeBlock(const Consensus::Params &params,
                                           std::shared_ptr<CBlock> pblock);
     void BuildChain(const Config &config, const BlockHash &root, int height,
                     const unsigned int invalid_rate,
                     const unsigned int branch_rate, const unsigned int max_size,
                     std::vector<std::shared_ptr<const CBlock>> &blocks);
 };
 } // namespace validation_block_tests
 
 BOOST_FIXTURE_TEST_SUITE(validation_block_tests, MinerTestingSetup)
 
 struct TestSubscriber final : public CValidationInterface {
     uint256 m_expected_tip;
 
     explicit TestSubscriber(uint256 tip) : m_expected_tip(tip) {}
 
     void UpdatedBlockTip(const CBlockIndex *pindexNew,
                          const CBlockIndex *pindexFork,
                          bool fInitialDownload) override {
         BOOST_CHECK_EQUAL(m_expected_tip, pindexNew->GetBlockHash());
     }
 
     void BlockConnected(const std::shared_ptr<const CBlock> &block,
                         const CBlockIndex *pindex) override {
         BOOST_CHECK_EQUAL(m_expected_tip, block->hashPrevBlock);
         BOOST_CHECK_EQUAL(m_expected_tip, pindex->pprev->GetBlockHash());
 
         m_expected_tip = block->GetHash();
     }
 
     void BlockDisconnected(const std::shared_ptr<const CBlock> &block,
                            const CBlockIndex *pindex) override {
         BOOST_CHECK_EQUAL(m_expected_tip, block->GetHash());
         BOOST_CHECK_EQUAL(m_expected_tip, pindex->GetBlockHash());
 
         m_expected_tip = block->hashPrevBlock;
     }
 };
 
 std::shared_ptr<CBlock> MinerTestingSetup::Block(const Config &config,
                                                  const BlockHash &prev_hash) {
     static int i = 0;
     static uint64_t time = config.GetChainParams().GenesisBlock().nTime;
 
     CScript pubKey;
     pubKey << i++ << OP_TRUE;
 
-    auto ptemplate =
-        BlockAssembler(config, *m_node.mempool).CreateNewBlock(pubKey);
+    auto ptemplate = BlockAssembler(config, *m_node.mempool)
+                         .CreateNewBlock(::ChainstateActive(), pubKey);
     auto pblock = std::make_shared<CBlock>(ptemplate->block);
     pblock->hashPrevBlock = prev_hash;
     pblock->nTime = ++time;
 
     pubKey.clear();
     {
         pubKey << OP_HASH160 << ToByteVector(CScriptID(CScript() << OP_TRUE))
                << OP_EQUAL;
     }
     // Make the coinbase transaction with two outputs:
     // One zero-value one that has a unique pubkey to make sure that blocks at
     // the same height can have a different hash. Another one that has the
     // coinbase reward in a P2SH with OP_TRUE as scriptPubKey to make it easy to
     // spend
     CMutableTransaction txCoinbase(*pblock->vtx[0]);
     txCoinbase.vout.resize(2);
     txCoinbase.vout[1].scriptPubKey = pubKey;
     txCoinbase.vout[1].nValue = txCoinbase.vout[0].nValue;
     txCoinbase.vout[0].nValue = Amount::zero();
     pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
 
     return pblock;
 }
 
 std::shared_ptr<CBlock>
 MinerTestingSetup::FinalizeBlock(const Consensus::Params &params,
                                  std::shared_ptr<CBlock> pblock) {
     pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
 
     while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, params)) {
         ++(pblock->nNonce);
     }
 
     return pblock;
 }
 
 // construct a valid block
 std::shared_ptr<const CBlock>
 MinerTestingSetup::GoodBlock(const Config &config, const BlockHash &prev_hash) {
     return FinalizeBlock(config.GetChainParams().GetConsensus(),
                          Block(config, prev_hash));
 }
 
 // construct an invalid block (but with a valid header)
 std::shared_ptr<const CBlock>
 MinerTestingSetup::BadBlock(const Config &config, const BlockHash &prev_hash) {
     auto pblock = Block(config, prev_hash);
 
     CMutableTransaction coinbase_spend;
     coinbase_spend.vin.push_back(
         CTxIn(COutPoint(pblock->vtx[0]->GetId(), 0), CScript(), 0));
     coinbase_spend.vout.push_back(pblock->vtx[0]->vout[0]);
 
     CTransactionRef tx = MakeTransactionRef(coinbase_spend);
     pblock->vtx.push_back(tx);
 
     auto ret = FinalizeBlock(config.GetChainParams().GetConsensus(), pblock);
     return ret;
 }
 
 void MinerTestingSetup::BuildChain(
     const Config &config, const BlockHash &root, int height,
     const unsigned int invalid_rate, const unsigned int branch_rate,
     const unsigned int max_size,
     std::vector<std::shared_ptr<const CBlock>> &blocks) {
     if (height <= 0 || blocks.size() >= max_size) {
         return;
     }
 
     bool gen_invalid = InsecureRandRange(100) < invalid_rate;
     bool gen_fork = InsecureRandRange(100) < branch_rate;
 
     const std::shared_ptr<const CBlock> pblock =
         gen_invalid ? BadBlock(config, root) : GoodBlock(config, root);
     blocks.push_back(pblock);
     if (!gen_invalid) {
         BuildChain(config, pblock->GetHash(), height - 1, invalid_rate,
                    branch_rate, max_size, blocks);
     }
 
     if (gen_fork) {
         blocks.push_back(GoodBlock(config, root));
         BuildChain(config, blocks.back()->GetHash(), height - 1, invalid_rate,
                    branch_rate, max_size, blocks);
     }
 }
 
 BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering) {
     GlobalConfig config;
     const CChainParams &chainParams = config.GetChainParams();
 
     // build a large-ish chain that's likely to have some forks
     std::vector<std::shared_ptr<const CBlock>> blocks;
     while (blocks.size() < 50) {
         blocks.clear();
         BuildChain(config, chainParams.GenesisBlock().GetHash(), 100, 15, 10,
                    500, blocks);
     }
 
     bool ignored;
     BlockValidationState state;
     std::vector<CBlockHeader> headers;
     std::transform(
         blocks.begin(), blocks.end(), std::back_inserter(headers),
         [](std::shared_ptr<const CBlock> b) { return b->GetBlockHeader(); });
 
     // Process all the headers so we understand the toplogy of the chain
     BOOST_CHECK(Assert(m_node.chainman)
                     ->ProcessNewBlockHeaders(config, headers, state));
 
     // Connect the genesis block and drain any outstanding events
     BOOST_CHECK(Assert(m_node.chainman)
                     ->ProcessNewBlock(
                         config,
                         std::make_shared<CBlock>(chainParams.GenesisBlock()),
                         true, &ignored));
     SyncWithValidationInterfaceQueue();
 
     // subscribe to events (this subscriber will validate event ordering)
     const CBlockIndex *initial_tip = nullptr;
     {
         LOCK(cs_main);
         initial_tip = ::ChainActive().Tip();
     }
     auto sub = std::make_shared<TestSubscriber>(initial_tip->GetBlockHash());
     RegisterSharedValidationInterface(sub);
 
     // create a bunch of threads that repeatedly process a block generated above
     // at random this will create parallelism and randomness inside validation -
     // the ValidationInterface will subscribe to events generated during block
     // validation and assert on ordering invariance
     std::vector<std::thread> threads;
     for (int i = 0; i < 10; i++) {
         threads.emplace_back([&]() {
             bool tlignored;
             FastRandomContext insecure;
             for (int j = 0; j < 1000; j++) {
                 auto block = blocks[insecure.randrange(blocks.size() - 1)];
                 Assert(m_node.chainman)
                     ->ProcessNewBlock(config, block, true, &tlignored);
             }
 
             // to make sure that eventually we process the full chain - do it
             // here
             for (auto block : blocks) {
                 if (block->vtx.size() == 1) {
                     bool processed =
                         Assert(m_node.chainman)
                             ->ProcessNewBlock(config, block, true, &tlignored);
                     assert(processed);
                 }
             }
         });
     }
 
     for (auto &t : threads) {
         t.join();
     }
     SyncWithValidationInterfaceQueue();
 
     UnregisterSharedValidationInterface(sub);
 
     LOCK(cs_main);
     BOOST_CHECK_EQUAL(sub->m_expected_tip,
                       ::ChainActive().Tip()->GetBlockHash());
 }
 
 /**
  * Test that mempool updates happen atomically with reorgs.
  *
  * This prevents RPC clients, among others, from retrieving
  * immediately-out-of-date mempool data during large reorgs.
  *
  * The test verifies this by creating a chain of `num_txs` blocks, matures their
  * coinbases, and then submits txns spending from their coinbase to the mempool.
  * A fork chain is then processed, invalidating the txns and evicting them from
  * the mempool.
  *
  * We verify that the mempool updates atomically by polling it continuously
  * from another thread during the reorg and checking that its size only changes
  * once. The size changing exactly once indicates that the polling thread's
  * view of the mempool is either consistent with the chain state before reorg,
  * or consistent with the chain state after the reorg, and not just consistent
  * with some intermediate state during the reorg.
  */
 BOOST_AUTO_TEST_CASE(mempool_locks_reorg) {
     GlobalConfig config;
     const CChainParams &chainParams = config.GetChainParams();
 
     bool ignored;
     auto ProcessBlock = [&](std::shared_ptr<const CBlock> block) -> bool {
         return Assert(m_node.chainman)
             ->ProcessNewBlock(config, block, /* fForceProcessing */ true,
                               /* fNewBlock */ &ignored);
     };
 
     // Process all mined blocks
     BOOST_REQUIRE(
         ProcessBlock(std::make_shared<CBlock>(chainParams.GenesisBlock())));
     auto last_mined = GoodBlock(config, chainParams.GenesisBlock().GetHash());
     BOOST_REQUIRE(ProcessBlock(last_mined));
 
     // Run the test multiple times
     for (int test_runs = 3; test_runs > 0; --test_runs) {
         BOOST_CHECK_EQUAL(last_mined->GetHash(),
                           ::ChainActive().Tip()->GetBlockHash());
 
         // Later on split from here
         const BlockHash split_hash{last_mined->hashPrevBlock};
 
         // Create a bunch of transactions to spend the miner rewards of the
         // most recent blocks
         std::vector<CTransactionRef> txs;
         for (int num_txs = 22; num_txs > 0; --num_txs) {
             CMutableTransaction mtx;
             mtx.vin.push_back(
                 CTxIn(COutPoint(last_mined->vtx[0]->GetId(), 1),
                       CScript() << ToByteVector(CScript() << OP_TRUE)));
             // Two outputs to make sure the transaction is larger than 100 bytes
             for (int i = 1; i < 3; ++i) {
                 mtx.vout.emplace_back(
                     CTxOut(50000 * SATOSHI,
                            CScript() << OP_DUP << OP_HASH160
                                      << ToByteVector(CScriptID(CScript() << i))
                                      << OP_EQUALVERIFY << OP_CHECKSIG));
             }
             txs.push_back(MakeTransactionRef(mtx));
             last_mined = GoodBlock(config, last_mined->GetHash());
             BOOST_REQUIRE(ProcessBlock(last_mined));
         }
 
         // Mature the inputs of the txs
         for (int j = COINBASE_MATURITY; j > 0; --j) {
             last_mined = GoodBlock(config, last_mined->GetHash());
             BOOST_REQUIRE(ProcessBlock(last_mined));
         }
 
         // Mine a reorg (and hold it back) before adding the txs to the mempool
         const BlockHash tip_init{last_mined->GetHash()};
 
         std::vector<std::shared_ptr<const CBlock>> reorg;
         last_mined = GoodBlock(config, split_hash);
         reorg.push_back(last_mined);
         for (size_t j = COINBASE_MATURITY + txs.size() + 1; j > 0; --j) {
             last_mined = GoodBlock(config, last_mined->GetHash());
             reorg.push_back(last_mined);
         }
 
         // Add the txs to the tx pool
         {
             LOCK(cs_main);
             TxValidationState state;
             for (const auto &tx : txs) {
                 BOOST_REQUIRE_MESSAGE(
                     AcceptToMemoryPool(::ChainstateActive(), config,
                                        *m_node.mempool, state, tx,
                                        /* bypass_limits */ false),
                     state.GetRejectReason());
             }
         }
 
         // Check that all txs are in the pool
         {
             LOCK(m_node.mempool->cs);
             BOOST_CHECK_EQUAL(m_node.mempool->mapTx.size(), txs.size());
         }
 
         // Run a thread that simulates an RPC caller that is polling while
         // validation is doing a reorg
         std::thread rpc_thread{[&]() {
             // This thread is checking that the mempool either contains all of
             // the transactions invalidated by the reorg, or none of them, and
             // not some intermediate amount.
             while (true) {
                 LOCK(m_node.mempool->cs);
                 if (m_node.mempool->mapTx.size() == 0) {
                     // We are done with the reorg
                     break;
                 }
                 // Internally, we might be in the middle of the reorg, but
                 // externally the reorg to the most-proof-of-work chain should
                 // be atomic. So the caller assumes that the returned mempool
                 // is consistent. That is, it has all txs that were there
                 // before the reorg.
                 assert(m_node.mempool->mapTx.size() == txs.size());
                 continue;
             }
             LOCK(cs_main);
             // We are done with the reorg, so the tip must have changed
             assert(tip_init != ::ChainActive().Tip()->GetBlockHash());
         }};
 
         // Make sure we disable reorg protection.
         gArgs.ForceSetArg("-parkdeepreorg", "false");
 
         // Submit the reorg in this thread to invalidate and remove the txs from
         // the tx pool
         for (const auto &b : reorg) {
             ProcessBlock(b);
         }
         // Check that the reorg was eventually successful
         BOOST_CHECK_EQUAL(last_mined->GetHash(),
                           ::ChainActive().Tip()->GetBlockHash());
 
         // We can join the other thread, which returns when the reorg was
         // successful
         rpc_thread.join();
     }
 }
 BOOST_AUTO_TEST_SUITE_END()