diff --git a/doc/release-notes.md b/doc/release-notes.md
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -3,3 +3,5 @@
This release includes the following features and fixes:
+ - New `minerfund` subfield of `coinbasetxn` in `getblocktemplate` to enable
+ easy fetching of valid addresses for infrastructure funding.
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -5,15 +5,18 @@
#include
#include
+#include
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
@@ -424,9 +427,17 @@
" \"coinbasevalue\" : n, (numeric) maximum allowable "
"input to coinbase transaction, including the generation award and "
"transaction fees (in satoshis)\n"
- " \"coinbasetxn\" : { ... }, (json object) information "
+ " \"coinbasetxn\" : { (json object) information "
"for coinbase transaction\n"
- " \"target\" : \"xxxx\", (string) The hash target\n"
+ " \"minerfund\" : { (json object) information "
+ "related to the coinbase miner fund\n"
+ " \"addresses\" : [ ... ], (array) List of valid "
+ "addresses for the miner fund output\n"
+ " \"minimumvalue\" : n, (numeric) The minimum "
+ "value the miner fund output must pay\n"
+ " },\n"
+ " },\n"
+ " \"target\" : \"xxxx\", (string) The hash target\n"
" \"mintime\" : xxx, (numeric) The minimum "
"timestamp appropriate for next block time in seconds since epoch "
"(Jan 1 1970 GMT)\n"
@@ -456,6 +467,7 @@
.Check(request);
LOCK(cs_main);
+ const CChainParams &chainparams = config.GetChainParams();
std::string strMode = "template";
UniValue lpval = NullUniValue;
@@ -503,7 +515,7 @@
return "inconclusive-not-best-prevblk";
}
BlockValidationState state;
- TestBlockValidity(state, config.GetChainParams(), block, pindexPrev,
+ TestBlockValidity(state, chainparams, block, pindexPrev,
BlockValidationOptions(config)
.withCheckPoW(false)
.withCheckMerkleRoot(true));
@@ -614,7 +626,7 @@
CBlock *pblock = &pblocktemplate->block;
// Update nTime
- UpdateTime(pblock, config.GetChainParams(), pindexPrev);
+ UpdateTime(pblock, chainparams, pindexPrev);
pblock->nNonce = 0;
UniValue aCaps(UniValue::VARR);
@@ -657,6 +669,26 @@
UniValue aux(UniValue::VOBJ);
aux.pushKV("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()));
+ UniValue minerFundList(UniValue::VARR);
+ const Consensus::Params &consensusParams = chainparams.GetConsensus();
+ for (auto fundDestination :
+ GetMinerFundWhitelist(consensusParams, pindexPrev)) {
+ minerFundList.push_back(EncodeCashAddr(fundDestination, chainparams));
+ }
+
+ 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);
@@ -672,6 +704,7 @@
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() +
i64tostr(nTransactionsUpdatedLast));
diff --git a/test/functional/abc-magnetic-anomaly-mining.py b/test/functional/abc-magnetic-anomaly-mining.py
--- a/test/functional/abc-magnetic-anomaly-mining.py
+++ b/test/functional/abc-magnetic-anomaly-mining.py
@@ -98,7 +98,6 @@
tmpl = mining_node.getblocktemplate()
assert 'proposal' in tmpl['capabilities']
- assert 'coinbasetxn' not in tmpl
# Check the template transaction metadata and ordering
last_txid = 0
diff --git a/test/functional/abc_mining_basic.py b/test/functional/abc_mining_basic.py
--- a/test/functional/abc_mining_basic.py
+++ b/test/functional/abc_mining_basic.py
@@ -22,6 +22,7 @@
from decimal import Decimal
AXION_ACTIVATION_TIME = 2000000600
+MINER_FUND_ADDR = 'bchreg:pqnqv9lt7e5vjyp0w88zf2af0l92l8rxdgd35g0pkl'
class AbcMiningRPCTest(BitcoinTestFramework):
@@ -36,13 +37,6 @@
node = self.nodes[0]
address = node.get_deterministic_priv_key().address
- # Move MTP forward to axion activation
- node.setmocktime(AXION_ACTIVATION_TIME)
- node.generatetoaddress(6, address)
- assert_equal(
- node.getblockchaininfo()['mediantime'],
- AXION_ACTIVATION_TIME)
-
# Assert the results of getblocktemplate have expected values. Keys not
# in 'expected' are not checked.
def assert_getblocktemplate(expected):
@@ -55,6 +49,26 @@
for key, value in expected.items():
assert_equal(blockTemplate[key], value)
+ # Move block time to just before axion activation
+ node.setmocktime(AXION_ACTIVATION_TIME)
+ node.generatetoaddress(5, address)
+
+ # Before axion activation, the miner fund list is empty
+ assert_getblocktemplate({
+ 'coinbasetxn': {
+ 'minerfund': {
+ 'addresses': [],
+ 'minimumvalue': 0,
+ },
+ },
+ })
+
+ # Move MTP forward to axion activation
+ node.generatetoaddress(1, address)
+ assert_equal(
+ node.getblockchaininfo()['mediantime'],
+ AXION_ACTIVATION_TIME)
+
def get_best_coinbase():
return node.getblock(node.getbestblockhash(), 2)['tx'][0]
@@ -66,6 +80,14 @@
# them are covered in mining_basic.py
assert_equal(node.getmempoolinfo()['size'], 0)
assert_getblocktemplate({
+ 'coinbasetxn': {
+ # We expect to start seeing the miner fund addresses since the
+ # next block will start enforcing them.
+ 'minerfund': {
+ 'addresses': [MINER_FUND_ADDR],
+ 'minimumvalue': block_reward * 8 // 100 * COIN,
+ },
+ },
# Although the coinbase value need not necessarily be the same as
# the last block due to halvings and fees, we know this to be true
# since we are not crossing a halving boundary and there are no
@@ -86,6 +108,12 @@
assert_equal(total, block_reward)
assert_getblocktemplate({
+ 'coinbasetxn': {
+ 'minerfund': {
+ 'addresses': [MINER_FUND_ADDR],
+ 'minimumvalue': block_reward * 8 // 100 * COIN,
+ },
+ },
# Again, we assume the coinbase value is the same as prior blocks.
'coinbasevalue': block_reward * COIN,
'mintime': AXION_ACTIVATION_TIME + 1,
@@ -95,6 +123,12 @@
node.setmocktime(AXION_ACTIVATION_TIME + 1)
node.generatetoaddress(6, address)
assert_getblocktemplate({
+ 'coinbasetxn': {
+ 'minerfund': {
+ 'addresses': [MINER_FUND_ADDR],
+ 'minimumvalue': block_reward * 8 // 100 * COIN,
+ },
+ },
'coinbasevalue': block_reward * COIN,
'mintime': AXION_ACTIVATION_TIME + 2,
})
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py
--- a/test/functional/mining_basic.py
+++ b/test/functional/mining_basic.py
@@ -90,7 +90,6 @@
tmpl = node.getblocktemplate()
self.log.info("getblocktemplate: Test capability advertised")
assert 'proposal' in tmpl['capabilities']
- assert 'coinbasetxn' not in tmpl
next_height = int(tmpl["height"])
coinbase_tx = create_coinbase(height=next_height)