From fab9a08e145dc5a1d9576bf062473f1095b56a16 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 10 Mar 2023 10:45:28 +0100 Subject: [PATCH 1/2] refactor: Replace block_hash with block_out --- src/rpc/mining.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 8753f845a5f..0df43d1b419 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -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& block_out) { - block_hash.SetNull(); + block_out.reset(); block.hashMerkleRoot = BlockMerkleRoot(block); while (max_tries > 0 && block.nNonce < std::numeric_limits::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainman.GetConsensus()) && !ShutdownRequested()) { @@ -131,12 +131,11 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& return true; } - std::shared_ptr shared_pblock = std::make_shared(block); - if (!chainman.ProcessNewBlock(shared_pblock, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) { + block_out = std::make_shared(block); + if (!chainman.ProcessNewBlock(block_out, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) { throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); } - block_hash = block.GetHash(); return true; } @@ -147,16 +146,15 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me std::unique_ptr pblocktemplate(BlockAssembler{chainman.ActiveChainstate(), &mempool}.CreateNewBlock(coinbase_script)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); - CBlock *pblock = &pblocktemplate->block; - uint256 block_hash; - if (!GenerateBlock(chainman, *pblock, nMaxTries, block_hash)) { + std::shared_ptr block_out; + if (!GenerateBlock(chainman, pblocktemplate->block, nMaxTries, block_out)) { break; } - if (!block_hash.IsNull()) { + if (block_out) { --nGenerate; - blockHashes.push_back(block_hash.GetHex()); + blockHashes.push_back(block_out->GetHash().GetHex()); } } return blockHashes; @@ -376,15 +374,15 @@ static RPCHelpMan generateblock() } } - uint256 block_hash; + std::shared_ptr block_out; 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) || !block_out) { throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block."); } UniValue obj(UniValue::VOBJ); - obj.pushKV("hash", block_hash.GetHex()); + obj.pushKV("hash", block_out->GetHash().GetHex()); return obj; }, }; From fa18504d5767a40dc9827fb081633219bf251001 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 10 Mar 2023 10:40:26 +0100 Subject: [PATCH 2/2] rpc: Add submit option to generateblock --- src/rpc/client.cpp | 1 + src/rpc/mining.cpp | 17 ++++++++++++++--- test/functional/rpc_generate.py | 7 ++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 9449b9d197e..4459dd71aa6 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -37,6 +37,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "generatetodescriptor", 0, "num_blocks" }, { "generatetodescriptor", 2, "maxtries" }, { "generateblock", 1, "transactions" }, + { "generateblock", 2, "submit" }, { "getnetworkhashps", 0, "nblocks" }, { "getnetworkhashps", 1, "height" }, { "sendtoaddress", 1, "amount" }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 0df43d1b419..d55e20ba5e3 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -115,7 +115,7 @@ static RPCHelpMan getnetworkhashps() }; } -static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, std::shared_ptr& block_out) +static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, std::shared_ptr& block_out, bool process_new_block) { block_out.reset(); block.hashMerkleRoot = BlockMerkleRoot(block); @@ -132,6 +132,9 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& } block_out = std::make_shared(block); + + 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"); } @@ -148,7 +151,7 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); std::shared_ptr block_out; - if (!GenerateBlock(chainman, pblocktemplate->block, nMaxTries, block_out)) { + if (!GenerateBlock(chainman, pblocktemplate->block, nMaxTries, block_out, /*process_new_block=*/true)) { break; } @@ -293,11 +296,13 @@ static RPCHelpMan generateblock() {"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::Type::OBJ, "", "", { {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{ @@ -346,6 +351,7 @@ static RPCHelpMan generateblock() } } + const bool process_new_block{request.params[2].isNull() ? true : request.params[2].get_bool()}; CBlock block; ChainstateManager& chainman = EnsureChainman(node); @@ -377,12 +383,17 @@ static RPCHelpMan generateblock() std::shared_ptr block_out; uint64_t max_tries{DEFAULT_MAX_TRIES}; - if (!GenerateBlock(chainman, block, max_tries, block_out) || !block_out) { + if (!GenerateBlock(chainman, block, max_tries, block_out, process_new_block) || !block_out) { throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block."); } UniValue obj(UniValue::VOBJ); 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; }, }; diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py index 8948ccb48d9..20f62079fd6 100755 --- a/test/functional/rpc_generate.py +++ b/test/functional/rpc_generate.py @@ -29,8 +29,13 @@ class RPCGenerateTest(BitcoinTestFramework): node = self.nodes[0] 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() + 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'] block = node.getblock(blockhash=hash, verbose=2) assert_equal(len(block['tx']), 1)