diff --git a/src/miner.h b/src/miner.h
--- a/src/miner.h
+++ b/src/miner.h
@@ -24,10 +24,19 @@
 
 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<Amount> vTxFees;
-    std::vector<int64_t> vTxSigOpsCount;
+
+    std::vector<CBlockTemplateEntry> entries;
 };
 
 // Container for tracking updates to ancestor feerate as we include (parent)
diff --git a/src/miner.cpp b/src/miner.cpp
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -32,9 +32,6 @@
 #include <queue>
 #include <utility>
 
-#include <boost/thread.hpp>
-#include <boost/tuple/tuple.hpp>
-
 //////////////////////////////////////////////////////////////////////////////
 //
 // BitcoinMiner
@@ -142,12 +139,8 @@
     // Pointer for convenience.
     pblock = &pblocktemplate->block;
 
-    // Add dummy coinbase tx as first transaction.
-    pblock->vtx.emplace_back();
-    // updated at end
-    pblocktemplate->vTxFees.push_back(-SATOSHI);
-    // updated at end
-    pblocktemplate->vTxSigOpsCount.push_back(-1);
+    // Add dummy coinbase tx as first transaction.  It is updated at the end.
+    pblocktemplate->entries.emplace_back(CTransactionRef(), -SATOSHI, -1);
 
     LOCK2(cs_main, mpool->cs);
     CBlockIndex *pindexPrev = chainActive.Tip();
@@ -179,11 +172,10 @@
     if (IsMagneticAnomalyEnabled(*config, pindexPrev)) {
         // If magnetic anomaly is enabled, we make sure transaction are
         // canonically ordered.
-        std::sort(std::begin(pblock->vtx) + 1, std::end(pblock->vtx),
-                  [](const std::shared_ptr<const CTransaction> &a,
-                     const std::shared_ptr<const CTransaction> &b) -> bool {
-                      return a->GetId() < b->GetId();
-                  });
+        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(); });
     }
 
     int64_t nTime1 = GetTimeMicros();
@@ -209,8 +201,8 @@
             << std::vector<uint8_t>(MIN_TX_SIZE - coinbaseSize - 1);
     }
 
-    pblock->vtx[0] = MakeTransactionRef(coinbaseTx);
-    pblocktemplate->vTxFees[0] = -1 * nFees;
+    pblocktemplate->entries[0].tx = MakeTransactionRef(coinbaseTx);
+    pblocktemplate->entries[0].fees = -1 * nFees;
 
     uint64_t nSerializeSize =
         GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION);
@@ -223,8 +215,13 @@
     UpdateTime(pblock, *config, pindexPrev);
     pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, *config);
     pblock->nNonce = 0;
-    pblocktemplate->vTxSigOpsCount[0] = GetSigOpCountWithoutP2SH(
-        *pblock->vtx[0], STANDARD_CHECKDATASIG_VERIFY_FLAGS);
+    pblocktemplate->entries[0].sigOpCount = GetSigOpCountWithoutP2SH(
+        *pblocktemplate->entries[0].tx, STANDARD_CHECKDATASIG_VERIFY_FLAGS);
+
+    // Copy all the transactions into the block
+    for (const CBlockTemplateEntry &tx : pblocktemplate->entries) {
+        pblock->vtx.push_back(tx.tx);
+    }
 
     CValidationState state;
     BlockValidationOptions validationOptions(false, false);
@@ -351,9 +348,8 @@
 }
 
 void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) {
-    pblock->vtx.emplace_back(iter->GetSharedTx());
-    pblocktemplate->vTxFees.push_back(iter->GetFee());
-    pblocktemplate->vTxSigOpsCount.push_back(iter->GetSigOpCount());
+    pblocktemplate->entries.push_back(CBlockTemplateEntry(
+        iter->GetSharedTx(), iter->GetFee(), iter->GetSigOpCount()));
     nBlockSize += iter->GetTxSize();
     ++nBlockTx;
     nBlockSigOps += iter->GetSigOpCount();
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -633,9 +633,10 @@
         entry.pushKV("depends", deps);
 
         int index_in_template = i - 1;
-        entry.push_back(
-            Pair("fee", pblocktemplate->vTxFees[index_in_template] / SATOSHI));
-        int64_t nTxSigOps = pblocktemplate->vTxSigOpsCount[index_in_template];
+        entry.push_back(Pair(
+            "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);
diff --git a/test/functional/abc-magnetic-anomaly-mining.py b/test/functional/abc-magnetic-anomaly-mining.py
new file mode 100755
--- /dev/null
+++ b/test/functional/abc-magnetic-anomaly-mining.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test mining RPCs
+
+- getblocktemplate proposal mode
+- submitblock"""
+
+import time
+import random
+import decimal
+from binascii import b2a_hex
+import copy
+
+from test_framework.blocktools import create_coinbase
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.mininode import CBlock, CTransaction, FromHex, uint256_from_str
+from test_framework.util import *
+
+RPC_VERIFY_REJECTED = -26
+
+
+def b2x(b):
+    return b2a_hex(b).decode('ascii')
+
+
+def assert_template(node, block, expect, rehash=True):
+    if rehash:
+        block.hashMerkleRoot = block.calc_merkle_root()
+    rsp = node.getblocktemplate(
+        {'data': b2x(block.serialize()), 'mode': 'proposal'})
+    assert_equal(rsp, expect)
+
+
+class CTORMiningTest(BitcoinTestFramework):
+    def set_test_params(self):
+        # Setup two nodes so we can getblocktemplate
+        # it errors out if it is not connected to other nodes
+        self.num_nodes = 2
+        self.setup_clean_chain = True
+        self.block_heights = {}
+        self.tip = None
+        self.blocks = {}
+        self.mocktime = int(time.time()) - 600 * 100
+
+        extra_arg = ['-spendzeroconfchange=0', '-whitelist=127.0.0.1',
+                     "-magneticanomalyactivationtime=%d" % self.mocktime,
+                     "-replayprotectionactivationtime=%d" % (10 * self.mocktime)]
+        self.extra_args = [extra_arg, extra_arg]
+
+    def run_test(self):
+        mnode = self.nodes[0]
+
+        # Helper for updating the times
+        def update_time():
+            mnode.setmocktime(self.mocktime)
+            self.mocktime = self.mocktime + 600
+
+        mnode.getnewaddress()
+
+        # Generate some unspent utxos and also
+        # activate magnetic anomaly
+        for x in range(150):
+            update_time()
+            mnode.generate(1)
+
+        update_time()
+        unspent = mnode.listunspent()
+
+        transactions = {}
+        # Spend all our coinbases
+        while len(unspent):
+            inputs = []
+            # Grab a random number of inputs
+            for _ in range(random.randrange(1, 5)):
+                txin = unspent.pop()
+                inputs.append({
+                    'txid': txin['txid'],
+                    'vout': 0  # This is a coinbase
+                })
+                if len(unspent) == 0:
+                    break
+
+            outputs = {}
+            # Calculate a unique fee for this transaction
+            fee = decimal.Decimal(random.randint(
+                1000, 2000)) / decimal.Decimal(1e8)
+            # Spend to the same number of outputs as inputs, so we can leave
+            # the amounts unchanged and avoid rounding errors.
+            addr = ""
+            for _ in range(len(inputs)):
+                addr = mnode.getnewaddress()
+                output = {
+                    # 50 BCH per coinbase
+                    addr: decimal.Decimal(50)
+                }
+                outputs.update(output)
+
+            # Take the fee off the last output to avoid rounding errors we
+            # need the exact fee later for assertions
+            outputs[addr] -= fee
+
+            rawtx = mnode.createrawtransaction(inputs, outputs)
+            signedtx = mnode.signrawtransaction(rawtx)
+            txid = mnode.sendrawtransaction(signedtx['hex'])
+            # number of inputs is the same as the number of sigops in this
+            # case
+            transactions.update({txid: {'fee': fee, 'sigops': len(outputs)}})
+
+        tmpl = mnode.getblocktemplate()
+        assert 'proposal' in tmpl['capabilities']
+        assert 'coinbasetxn' not in tmpl
+
+        # Check the template transaction metadata and ordering
+        last_txid = 0
+        for txn in tmpl['transactions'][1:]:
+            txid = txn['txid']
+            txnMetadata = transactions[txid]
+            expectedFeeSats = int(txnMetadata['fee'] * 10**8)
+            expectedSigOps = txnMetadata['sigops']
+
+            txid_decoded = int(txid, 16)
+
+            # Assert we got the expected metadata
+            assert(expectedFeeSats == txn['fee'])
+            assert(expectedSigOps == txn['sigops'])
+            # Asser transaciton ids are in order
+            assert(last_txid == 0 or last_txid < txid_decoded)
+            last_txid = txid_decoded
+
+
+if __name__ == '__main__':
+    CTORMiningTest().main()