| 1733 | } |
| 1734 | |
| 1735 | static RPCHelpMan testproposedblock() |
| 1736 | { |
| 1737 | return RPCHelpMan{"testproposedblock", |
| 1738 | "\nChecks a block proposal for validity, and that it extends chaintip\n", |
| 1739 | { |
| 1740 | {"blockhex", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded block from getnewblockhex"}, |
| 1741 | {"acceptnonstd", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "If set false, returns error if block contains non-standard transaction. Default is set via `-acceptnonstdtxn`."}, |
| 1742 | }, |
| 1743 | RPCResult{RPCResult::Type::NONE, "", ""}, |
| 1744 | RPCExamples{ |
| 1745 | HelpExampleCli("testproposedblock", "<hex>") |
| 1746 | }, |
| 1747 | [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue |
| 1748 | { |
| 1749 | CBlock block; |
| 1750 | if (!DecodeHexBlk(block, request.params[0].get_str())) |
| 1751 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); |
| 1752 | |
| 1753 | ChainstateManager& chainman = EnsureAnyChainman(request.context); |
| 1754 | LOCK(cs_main); |
| 1755 | |
| 1756 | uint256 hash = block.GetHash(); |
| 1757 | node::BlockMap::iterator mi = chainman.BlockIndex().find(hash); |
| 1758 | if (mi != chainman.BlockIndex().end()) |
| 1759 | throw JSONRPCError(RPC_VERIFY_ALREADY_IN_CHAIN, "already have block"); |
| 1760 | |
| 1761 | CBlockIndex* const pindexPrev = chainman.ActiveChain().Tip(); |
| 1762 | // TestBlockValidity only supports blocks built on the current Tip |
| 1763 | if (block.hashPrevBlock != pindexPrev->GetBlockHash()) |
| 1764 | throw JSONRPCError(RPC_VERIFY_ERROR, "proposal was not based on our best chain"); |
| 1765 | |
| 1766 | BlockValidationState state; |
| 1767 | if (!TestBlockValidity(state, Params(), chainman.ActiveChainstate(), block, pindexPrev, false, true) || !state.IsValid()) { |
| 1768 | std::string strRejectReason = state.GetRejectReason(); |
| 1769 | if (strRejectReason.empty()) |
| 1770 | throw JSONRPCError(RPC_VERIFY_ERROR, state.IsInvalid() ? "Block proposal was invalid" : "Error checking block proposal"); |
| 1771 | throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason); |
| 1772 | } |
| 1773 | |
| 1774 | const CChainParams& chainparams = Params(); |
| 1775 | const bool acceptnonstd = !request.params[1].isNull() ? request.params[1].get_bool() : gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard()); |
| 1776 | if (!acceptnonstd) { |
| 1777 | for (auto& transaction : block.vtx) { |
| 1778 | if (transaction->IsCoinBase()) continue; |
| 1779 | std::string reason; |
| 1780 | if (!IsStandardTx(*transaction, reason)) { |
| 1781 | throw JSONRPCError(RPC_VERIFY_ERROR, "Block proposal included a non-standard transaction: " + reason); |
| 1782 | } |
| 1783 | } |
| 1784 | } |
| 1785 | |
| 1786 | return NullUniValue; |
| 1787 | }, |
| 1788 | }; |
| 1789 | } |
| 1790 | |
| 1791 | // END ELEMENTS |
| 1792 | // |
nothing calls this directly
no test coverage detected