| 59 | |
| 60 | namespace wallet { |
| 61 | RPCHelpMan signblock() |
| 62 | { |
| 63 | return RPCHelpMan{"signblock", |
| 64 | "\nSigns a block proposal, checking that it would be accepted first. Errors if it cannot sign the block. Note that this call adds the witnessScript to your wallet for signing purposes! This function is intended for QA and testing.\n", |
| 65 | { |
| 66 | {"blockhex", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded block from getnewblockhex"}, |
| 67 | {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "The hex-encoded witness script. Required for dynamic federation blocks. Argument is \"\" when the block is P2WPKH."}, |
| 68 | }, |
| 69 | RPCResult{ |
| 70 | RPCResult::Type::ARR, "", "", |
| 71 | { |
| 72 | {RPCResult::Type::OBJ, "", "", |
| 73 | { |
| 74 | {RPCResult::Type::STR_HEX, "pubkey", "signature's pubkey"}, |
| 75 | {RPCResult::Type::STR_HEX, "sig", "the signature itself"}, |
| 76 | }}, |
| 77 | }, |
| 78 | }, |
| 79 | RPCExamples{ |
| 80 | HelpExampleCli("signblock", "0000002018c6f2f913f9902aeab...5ca501f77be96de63f609010000000000000000015100000000") |
| 81 | }, |
| 82 | [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue |
| 83 | { |
| 84 | if (!g_signed_blocks) { |
| 85 | throw JSONRPCError(RPC_MISC_ERROR, "Signed blocks are not active for this network."); |
| 86 | } |
| 87 | |
| 88 | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); |
| 89 | if (!wallet) return NullUniValue; |
| 90 | CWallet* const pwallet = wallet.get(); |
| 91 | |
| 92 | CBlock block; |
| 93 | if (!DecodeHexBlk(block, request.params[0].get_str())) |
| 94 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); |
| 95 | |
| 96 | LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan(); |
| 97 | if (!spk_man) { |
| 98 | throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command"); |
| 99 | } |
| 100 | |
| 101 | { |
| 102 | LOCK(cs_main); |
| 103 | uint256 hash = block.GetHash(); |
| 104 | if (pwallet->chain().hasBlocks(hash, 0, std::nullopt)) |
| 105 | throw JSONRPCError(RPC_VERIFY_ERROR, "already have block"); |
| 106 | |
| 107 | CBlockIndex* const pindexPrev = wallet->chain().getTip(); |
| 108 | // TestBlockValidity only supports blocks built on the current Tip |
| 109 | if (block.hashPrevBlock != pindexPrev->GetBlockHash()) |
| 110 | throw JSONRPCError(RPC_VERIFY_ERROR, "proposal was not based on our best chain"); |
| 111 | |
| 112 | BlockValidationState state; |
| 113 | if (!wallet->chain().testBlockValidity(state, Params(), block, pindexPrev, false, true) || !state.IsValid()) { |
| 114 | std::string strRejectReason = state.GetRejectReason(); |
| 115 | if (strRejectReason.empty()) |
| 116 | throw JSONRPCError(RPC_VERIFY_ERROR, state.IsInvalid() ? "Block proposal was invalid" : "Error checking block proposal"); |
| 117 | throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason); |
| 118 | } |
nothing calls this directly
no test coverage detected