Skip to content

Commit feda41e

Browse files
author
MarcoFalke
committed
Merge #14811: Mining: Enforce that segwit option must be set in GBT
d2ce315 [docs] add release note for change to GBT (John Newbery) 0025c9e [mining] segwit option must be set in GBT (John Newbery) Pull request description: Calling getblocktemplate without the segwit rule specified is most likely a client error, since it results in lower fees for the miner. Prevent this client error by failing getblocktemplate if called without the segwit rule specified. Of the previous 1000 blocks (measured at block [551591 (hash 0x...173c811)](https://blockstream.info/block/000000000000000000173c811e79858808abc3216af607035973f002bef60a7a)), 991 included segwit transactions. Tree-SHA512: 7933b073d72683c9ab9318db46a085ec19a56a14937945c73f783ac7656887619a86b74db0bdfcb8121df44f63a1d6a6fb19e98505b2a26a6a8a6e768e442fee
2 parents 45fe390 + d2ce315 commit feda41e

11 files changed

+39
-62
lines changed

doc/release-notes.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ platform.
6565
Notable changes
6666
===============
6767

68+
Mining
69+
------
70+
71+
- Calls to `getblocktemplate` will fail if the segwit rule is not specified.
72+
Calling `getblocktemplate` without segwit specified is almost certainly
73+
a misconfiguration since doing so results in lower rewards for the miner.
74+
6875
Command line option changes
6976
---------------------------
7077

@@ -182,6 +189,8 @@ in the Low-level Changes section below.
182189
P2SH-P2WPKH, and P2SH-P2WSH. Requests for P2WSH and P2SH-P2WSH accept
183190
an additional `witnessscript` parameter.
184191

192+
- See the [Mining](#mining) section for changes to `getblocktemplate`.
193+
185194
Low-level changes
186195
=================
187196

src/bench/block_assemble.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ static std::shared_ptr<CBlock> PrepareBlock(const CScript& coinbase_scriptPubKey
2727
{
2828
auto block = std::make_shared<CBlock>(
2929
BlockAssembler{Params()}
30-
.CreateNewBlock(coinbase_scriptPubKey, /* fMineWitnessTx */ true)
30+
.CreateNewBlock(coinbase_scriptPubKey)
3131
->block);
3232

3333
block->nTime = ::chainActive.Tip()->GetMedianTimePast() + 1;

src/miner.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ void BlockAssembler::resetBlock()
9595
nFees = 0;
9696
}
9797

98-
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx)
98+
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
9999
{
100100
int64_t nTimeStart = GetTimeMicros();
101101

@@ -139,7 +139,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
139139
// not activated.
140140
// TODO: replace this with a call to main to assess validity of a mempool
141141
// transaction (which in most cases can be a no-op).
142-
fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()) && fMineWitnessTx;
142+
fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus());
143143

144144
int nPackagesSelected = 0;
145145
int nDescendantsUpdated = 0;

src/miner.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ class BlockAssembler
157157
BlockAssembler(const CChainParams& params, const Options& options);
158158

159159
/** Construct a new block template with coinbase to scriptPubKeyIn */
160-
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx=true);
160+
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);
161161

162162
private:
163163
// utility functions

src/rpc/mining.cpp

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -311,15 +311,15 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
311311
" https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
312312
" https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n",
313313
{
314-
{"template_request", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "A json object in the following spec",
314+
{"template_request", RPCArg::Type::OBJ, /* opt */ false, /* default_val */ "", "A json object in the following spec",
315315
{
316316
{"mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
317317
{"capabilities", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A list of strings",
318318
{
319319
{"support", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"},
320320
},
321321
},
322-
{"rules", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A list of strings",
322+
{"rules", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A list of strings",
323323
{
324324
{"support", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "client side supported softfork deployment"},
325325
},
@@ -503,21 +503,17 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
503503
}
504504

505505
const struct VBDeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT];
506-
// If the caller is indicating segwit support, then allow CreateNewBlock()
507-
// to select witness transactions, after segwit activates (otherwise
508-
// don't).
509-
bool fSupportsSegwit = setClientRules.find(segwit_info.name) != setClientRules.end();
506+
// GBT must be called with 'segwit' set in the rules
507+
if (setClientRules.count(segwit_info.name) != 1) {
508+
throw JSONRPCError(RPC_INVALID_PARAMETER, "getblocktemplate must be called with the segwit rule set (call with {\"rules\": [\"segwit\"]})");
509+
}
510510

511511
// Update block
512512
static CBlockIndex* pindexPrev;
513513
static int64_t nStart;
514514
static std::unique_ptr<CBlockTemplate> pblocktemplate;
515-
// Cache whether the last invocation was with segwit support, to avoid returning
516-
// a segwit-block to a non-segwit caller.
517-
static bool fLastTemplateSupportsSegwit = true;
518515
if (pindexPrev != chainActive.Tip() ||
519-
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5) ||
520-
fLastTemplateSupportsSegwit != fSupportsSegwit)
516+
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
521517
{
522518
// Clear pindexPrev so future calls make a new block, despite any failures from here on
523519
pindexPrev = nullptr;
@@ -526,11 +522,10 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
526522
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
527523
CBlockIndex* pindexPrevNew = chainActive.Tip();
528524
nStart = GetTime();
529-
fLastTemplateSupportsSegwit = fSupportsSegwit;
530525

531526
// Create new block
532527
CScript scriptDummy = CScript() << OP_TRUE;
533-
pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy, fSupportsSegwit);
528+
pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy);
534529
if (!pblocktemplate)
535530
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
536531

@@ -682,7 +677,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
682677
result.pushKV("bits", strprintf("%08x", pblock->nBits));
683678
result.pushKV("height", (int64_t)(pindexPrev->nHeight+1));
684679

685-
if (!pblocktemplate->vchCoinbaseCommitment.empty() && fSupportsSegwit) {
680+
if (!pblocktemplate->vchCoinbaseCommitment.empty()) {
686681
result.pushKV("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end()));
687682
}
688683

src/test/validation_block_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ std::shared_ptr<CBlock> Block(const uint256& prev_hash)
5454
CScript pubKey;
5555
pubKey << i++ << OP_TRUE;
5656

57-
auto ptemplate = BlockAssembler(Params()).CreateNewBlock(pubKey, false);
57+
auto ptemplate = BlockAssembler(Params()).CreateNewBlock(pubKey);
5858
auto pblock = std::make_shared<CBlock>(ptemplate->block);
5959
pblock->hashPrevBlock = prev_hash;
6060
pblock->nTime = ++time;

test/functional/feature_segwit.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def run_test(self):
9090

9191
self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
9292
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
93-
tmpl = self.nodes[0].getblocktemplate({})
93+
tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
9494
assert(tmpl['sizelimit'] == 1000000)
9595
assert('weightlimit' not in tmpl)
9696
assert(tmpl['sigoplimit'] == 20000)
@@ -232,15 +232,7 @@ def run_test(self):
232232
assert(tx.wit.is_null())
233233
assert(txid3 in self.nodes[0].getrawmempool())
234234

235-
# Now try calling getblocktemplate() without segwit support.
236-
template = self.nodes[0].getblocktemplate()
237-
238-
# Check that tx1 is the only transaction of the 3 in the template.
239-
template_txids = [t['txid'] for t in template['transactions']]
240-
assert(txid2 not in template_txids and txid3 not in template_txids)
241-
assert(txid1 in template_txids)
242-
243-
# Check that running with segwit support results in all 3 being included.
235+
# Check that getblocktemplate includes all transactions.
244236
template = self.nodes[0].getblocktemplate({"rules": ["segwit"]})
245237
template_txids = [t['txid'] for t in template['transactions']]
246238
assert(txid1 in template_txids)

test/functional/mining_basic.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
def assert_template(node, block, expect, rehash=True):
3131
if rehash:
3232
block.hashMerkleRoot = block.calc_merkle_root()
33-
rsp = node.getblocktemplate(template_request={'data': b2x(block.serialize()), 'mode': 'proposal'})
33+
rsp = node.getblocktemplate(template_request={'data': b2x(block.serialize()), 'mode': 'proposal', 'rules': ['segwit']})
3434
assert_equal(rsp, expect)
3535

3636

@@ -60,7 +60,7 @@ def assert_submitblock(block, result_str_1, result_str_2=None):
6060

6161
# Mine a block to leave initial block download
6262
node.generatetoaddress(1, node.get_deterministic_priv_key().address)
63-
tmpl = node.getblocktemplate()
63+
tmpl = node.getblocktemplate({'rules': ['segwit']})
6464
self.log.info("getblocktemplate: Test capability advertised")
6565
assert 'proposal' in tmpl['capabilities']
6666
assert 'coinbasetxn' not in tmpl
@@ -86,6 +86,9 @@ def assert_submitblock(block, result_str_1, result_str_2=None):
8686
block.nNonce = 0
8787
block.vtx = [coinbase_tx]
8888

89+
self.log.info("getblocktemplate: segwit rule must be set")
90+
assert_raises_rpc_error(-8, "getblocktemplate must be called with the segwit rule set", node.getblocktemplate)
91+
8992
self.log.info("getblocktemplate: Test valid block")
9093
assert_template(node, block, None)
9194

@@ -102,7 +105,7 @@ def assert_submitblock(block, result_str_1, result_str_2=None):
102105
assert_raises_rpc_error(-22, "Block does not start with a coinbase", node.submitblock, b2x(bad_block.serialize()))
103106

104107
self.log.info("getblocktemplate: Test truncated final transaction")
105-
assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(block.serialize()[:-1]), 'mode': 'proposal'})
108+
assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(block.serialize()[:-1]), 'mode': 'proposal', 'rules': ['segwit']})
106109

107110
self.log.info("getblocktemplate: Test duplicate transaction")
108111
bad_block = copy.deepcopy(block)
@@ -132,7 +135,7 @@ def assert_submitblock(block, result_str_1, result_str_2=None):
132135
bad_block_sn = bytearray(block.serialize())
133136
assert_equal(bad_block_sn[TX_COUNT_OFFSET], 1)
134137
bad_block_sn[TX_COUNT_OFFSET] += 1
135-
assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(bad_block_sn), 'mode': 'proposal'})
138+
assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(bad_block_sn), 'mode': 'proposal', 'rules': ['segwit']})
136139

137140
self.log.info("getblocktemplate: Test bad bits")
138141
bad_block = copy.deepcopy(block)

test/functional/mining_getblocktemplate_longpoll.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ class LongpollThread(threading.Thread):
1515
def __init__(self, node):
1616
threading.Thread.__init__(self)
1717
# query current longpollid
18-
template = node.getblocktemplate()
18+
template = node.getblocktemplate({'rules': ['segwit']})
1919
self.longpollid = template['longpollid']
2020
# create a new connection to the node, we can't use the same
2121
# connection from two threads
2222
self.node = get_rpc_proxy(node.url, 1, timeout=600, coveragedir=node.coverage_dir)
2323

2424
def run(self):
25-
self.node.getblocktemplate({'longpollid':self.longpollid})
25+
self.node.getblocktemplate({'longpollid': self.longpollid, 'rules': ['segwit']})
2626

2727
class GetBlockTemplateLPTest(BitcoinTestFramework):
2828
def set_test_params(self):
@@ -34,10 +34,10 @@ def skip_test_if_missing_module(self):
3434
def run_test(self):
3535
self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.")
3636
self.nodes[0].generate(10)
37-
template = self.nodes[0].getblocktemplate()
37+
template = self.nodes[0].getblocktemplate({'rules': ['segwit']})
3838
longpollid = template['longpollid']
3939
# longpollid should not change between successive invocations if nothing else happens
40-
template2 = self.nodes[0].getblocktemplate()
40+
template2 = self.nodes[0].getblocktemplate({'rules': ['segwit']})
4141
assert(template2['longpollid'] == longpollid)
4242

4343
# Test 1: test that the longpolling wait if we do nothing

test/functional/mining_prioritisetransaction.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,10 @@ def run_test(self):
142142
# getblocktemplate to (eventually) return a new block.
143143
mock_time = int(time.time())
144144
self.nodes[0].setmocktime(mock_time)
145-
template = self.nodes[0].getblocktemplate()
145+
template = self.nodes[0].getblocktemplate({'rules': ['segwit']})
146146
self.nodes[0].prioritisetransaction(txid=tx_id, fee_delta=-int(self.relayfee*COIN))
147147
self.nodes[0].setmocktime(mock_time+10)
148-
new_template = self.nodes[0].getblocktemplate()
148+
new_template = self.nodes[0].getblocktemplate({'rules': ['segwit']})
149149

150150
assert(template != new_template)
151151

0 commit comments

Comments
 (0)