mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-23 07:15:29 +01:00
Merge bitcoin/bitcoin#18933: rpc: Add submit option to generateblock
fa18504d57
rpc: Add submit option to generateblock (MarcoFalke)fab9a08e14
refactor: Replace block_hash with block_out (MarcoFalke) Pull request description: When submit is turned off, a block can be generated and returned as hex, to be used for further tests. For example, it can be submitted on a different node, on a different interface (like p2p), or just never submitted and be used for other testing purposes. ACKs for top commit: instagibbs: ACKfa18504d57
TheCharlatan: tACKfa18504d57
Tree-SHA512: 1b2ab6b71bb7e155c6482d75f5373f4e77de6446cb16bc2dfd19e7a4075b3a6ad87d7ad7a049a9eed934cb71574acfd27202f54c8bb3b03fac869f2e95db7ee5
This commit is contained in:
commit
8acfb1f8e0
3 changed files with 29 additions and 14 deletions
|
@ -37,6 +37,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||||
{ "generatetodescriptor", 0, "num_blocks" },
|
{ "generatetodescriptor", 0, "num_blocks" },
|
||||||
{ "generatetodescriptor", 2, "maxtries" },
|
{ "generatetodescriptor", 2, "maxtries" },
|
||||||
{ "generateblock", 1, "transactions" },
|
{ "generateblock", 1, "transactions" },
|
||||||
|
{ "generateblock", 2, "submit" },
|
||||||
{ "getnetworkhashps", 0, "nblocks" },
|
{ "getnetworkhashps", 0, "nblocks" },
|
||||||
{ "getnetworkhashps", 1, "height" },
|
{ "getnetworkhashps", 1, "height" },
|
||||||
{ "sendtoaddress", 1, "amount" },
|
{ "sendtoaddress", 1, "amount" },
|
||||||
|
|
|
@ -115,9 +115,9 @@ static RPCHelpMan getnetworkhashps()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, uint256& block_hash)
|
static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)
|
||||||
{
|
{
|
||||||
block_hash.SetNull();
|
block_out.reset();
|
||||||
block.hashMerkleRoot = BlockMerkleRoot(block);
|
block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||||
|
|
||||||
while (max_tries > 0 && block.nNonce < std::numeric_limits<uint32_t>::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainman.GetConsensus()) && !ShutdownRequested()) {
|
while (max_tries > 0 && block.nNonce < std::numeric_limits<uint32_t>::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainman.GetConsensus()) && !ShutdownRequested()) {
|
||||||
|
@ -131,12 +131,14 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t&
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
|
block_out = std::make_shared<const CBlock>(block);
|
||||||
if (!chainman.ProcessNewBlock(shared_pblock, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) {
|
|
||||||
|
if (!process_new_block) return true;
|
||||||
|
|
||||||
|
if (!chainman.ProcessNewBlock(block_out, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) {
|
||||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
|
||||||
}
|
}
|
||||||
|
|
||||||
block_hash = block.GetHash();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,16 +149,15 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me
|
||||||
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler{chainman.ActiveChainstate(), &mempool}.CreateNewBlock(coinbase_script));
|
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler{chainman.ActiveChainstate(), &mempool}.CreateNewBlock(coinbase_script));
|
||||||
if (!pblocktemplate.get())
|
if (!pblocktemplate.get())
|
||||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
|
||||||
CBlock *pblock = &pblocktemplate->block;
|
|
||||||
|
|
||||||
uint256 block_hash;
|
std::shared_ptr<const CBlock> block_out;
|
||||||
if (!GenerateBlock(chainman, *pblock, nMaxTries, block_hash)) {
|
if (!GenerateBlock(chainman, pblocktemplate->block, nMaxTries, block_out, /*process_new_block=*/true)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!block_hash.IsNull()) {
|
if (block_out) {
|
||||||
--nGenerate;
|
--nGenerate;
|
||||||
blockHashes.push_back(block_hash.GetHex());
|
blockHashes.push_back(block_out->GetHash().GetHex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return blockHashes;
|
return blockHashes;
|
||||||
|
@ -295,11 +296,13 @@ static RPCHelpMan generateblock()
|
||||||
{"rawtx/txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
|
{"rawtx/txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{"submit", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to submit the block before the RPC call returns or to return it as hex."},
|
||||||
},
|
},
|
||||||
RPCResult{
|
RPCResult{
|
||||||
RPCResult::Type::OBJ, "", "",
|
RPCResult::Type::OBJ, "", "",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::STR_HEX, "hash", "hash of generated block"},
|
{RPCResult::Type::STR_HEX, "hash", "hash of generated block"},
|
||||||
|
{RPCResult::Type::STR_HEX, "hex", /*optional=*/true, "hex of generated block, only present when submit=false"},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
RPCExamples{
|
RPCExamples{
|
||||||
|
@ -348,6 +351,7 @@ static RPCHelpMan generateblock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool process_new_block{request.params[2].isNull() ? true : request.params[2].get_bool()};
|
||||||
CBlock block;
|
CBlock block;
|
||||||
|
|
||||||
ChainstateManager& chainman = EnsureChainman(node);
|
ChainstateManager& chainman = EnsureChainman(node);
|
||||||
|
@ -376,15 +380,20 @@ static RPCHelpMan generateblock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 block_hash;
|
std::shared_ptr<const CBlock> block_out;
|
||||||
uint64_t max_tries{DEFAULT_MAX_TRIES};
|
uint64_t max_tries{DEFAULT_MAX_TRIES};
|
||||||
|
|
||||||
if (!GenerateBlock(chainman, block, max_tries, block_hash) || block_hash.IsNull()) {
|
if (!GenerateBlock(chainman, block, max_tries, block_out, process_new_block) || !block_out) {
|
||||||
throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
|
throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue obj(UniValue::VOBJ);
|
UniValue obj(UniValue::VOBJ);
|
||||||
obj.pushKV("hash", block_hash.GetHex());
|
obj.pushKV("hash", block_out->GetHash().GetHex());
|
||||||
|
if (!process_new_block) {
|
||||||
|
CDataStream block_ser{SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()};
|
||||||
|
block_ser << *block_out;
|
||||||
|
obj.pushKV("hex", HexStr(block_ser));
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,8 +29,13 @@ class RPCGenerateTest(BitcoinTestFramework):
|
||||||
node = self.nodes[0]
|
node = self.nodes[0]
|
||||||
miniwallet = MiniWallet(node)
|
miniwallet = MiniWallet(node)
|
||||||
|
|
||||||
self.log.info('Generate an empty block to address')
|
self.log.info('Mine an empty block to address and return the hex')
|
||||||
address = miniwallet.get_address()
|
address = miniwallet.get_address()
|
||||||
|
generated_block = self.generateblock(node, output=address, transactions=[], submit=False)
|
||||||
|
node.submitblock(hexdata=generated_block['hex'])
|
||||||
|
assert_equal(generated_block['hash'], node.getbestblockhash())
|
||||||
|
|
||||||
|
self.log.info('Generate an empty block to address')
|
||||||
hash = self.generateblock(node, output=address, transactions=[])['hash']
|
hash = self.generateblock(node, output=address, transactions=[])['hash']
|
||||||
block = node.getblock(blockhash=hash, verbose=2)
|
block = node.getblock(blockhash=hash, verbose=2)
|
||||||
assert_equal(len(block['tx']), 1)
|
assert_equal(len(block['tx']), 1)
|
||||||
|
|
Loading…
Add table
Reference in a new issue