| 1229 | } |
| 1230 | |
| 1231 | static RPCHelpMan pruneblockchain() |
| 1232 | { |
| 1233 | return RPCHelpMan{"pruneblockchain", "", |
| 1234 | { |
| 1235 | {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block height to prune up to. May be set to a discrete height, or to a " + UNIX_EPOCH_TIME + "\n" |
| 1236 | " to prune blocks whose block time is at least 2 hours older than the provided timestamp."}, |
| 1237 | }, |
| 1238 | RPCResult{ |
| 1239 | RPCResult::Type::NUM, "", "Height of the last block pruned"}, |
| 1240 | RPCExamples{ |
| 1241 | HelpExampleCli("pruneblockchain", "1000") |
| 1242 | + HelpExampleRpc("pruneblockchain", "1000") |
| 1243 | }, |
| 1244 | [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue |
| 1245 | { |
| 1246 | if (!node::fPruneMode) |
| 1247 | throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode."); |
| 1248 | |
| 1249 | ChainstateManager& chainman = EnsureAnyChainman(request.context); |
| 1250 | LOCK(cs_main); |
| 1251 | CChainState& active_chainstate = chainman.ActiveChainstate(); |
| 1252 | CChain& active_chain = active_chainstate.m_chain; |
| 1253 | |
| 1254 | int heightParam = request.params[0].get_int(); |
| 1255 | if (heightParam < 0) |
| 1256 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height."); |
| 1257 | |
| 1258 | // Height value more than a billion is too high to be a block height, and |
| 1259 | // too low to be a block time (corresponds to timestamp from Sep 2001). |
| 1260 | if (heightParam > 1000000000) { |
| 1261 | // Add a 2 hour buffer to include blocks which might have had old timestamps |
| 1262 | CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0); |
| 1263 | if (!pindex) { |
| 1264 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp."); |
| 1265 | } |
| 1266 | heightParam = pindex->nHeight; |
| 1267 | } |
| 1268 | |
| 1269 | unsigned int height = (unsigned int) heightParam; |
| 1270 | unsigned int chainHeight = (unsigned int) active_chain.Height(); |
| 1271 | if (chainHeight < Params().PruneAfterHeight()) |
| 1272 | throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning."); |
| 1273 | else if (height > chainHeight) |
| 1274 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height."); |
| 1275 | else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) { |
| 1276 | LogPrint(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.\n"); |
| 1277 | height = chainHeight - MIN_BLOCKS_TO_KEEP; |
| 1278 | } |
| 1279 | |
| 1280 | PruneBlockFilesManual(active_chainstate, height); |
| 1281 | const CBlockIndex* block = active_chain.Tip(); |
| 1282 | CHECK_NONFATAL(block); |
| 1283 | while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) { |
| 1284 | block = block->pprev; |
| 1285 | } |
| 1286 | return uint64_t(block->nHeight); |
| 1287 | }, |
| 1288 | }; |
nothing calls this directly
no test coverage detected