| 357 | } |
| 358 | |
| 359 | static RPCMethod waitforblock() |
| 360 | { |
| 361 | return RPCMethod{ |
| 362 | "waitforblock", |
| 363 | "Waits for a specific new block and returns useful info about it.\n" |
| 364 | "\nReturns the current block on timeout or exit.\n" |
| 365 | "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)", |
| 366 | { |
| 367 | {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."}, |
| 368 | {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."}, |
| 369 | }, |
| 370 | RPCResult{ |
| 371 | RPCResult::Type::OBJ, "", "", |
| 372 | { |
| 373 | {RPCResult::Type::STR_HEX, "hash", "The blockhash"}, |
| 374 | {RPCResult::Type::NUM, "height", "Block height"}, |
| 375 | }}, |
| 376 | RPCExamples{ |
| 377 | HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000") |
| 378 | + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") |
| 379 | }, |
| 380 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
| 381 | { |
| 382 | int timeout = 0; |
| 383 | |
| 384 | uint256 hash(ParseHashV(request.params[0], "blockhash")); |
| 385 | |
| 386 | if (!request.params[1].isNull()) |
| 387 | timeout = request.params[1].getInt<int>(); |
| 388 | if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout"); |
| 389 | |
| 390 | NodeContext& node = EnsureAnyNodeContext(request.context); |
| 391 | Mining& miner = EnsureMining(node); |
| 392 | |
| 393 | // Abort if RPC came out of warmup too early |
| 394 | BlockRef current_block{CHECK_NONFATAL(miner.getTip()).value()}; |
| 395 | |
| 396 | const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout}; |
| 397 | while (current_block.hash != hash) { |
| 398 | std::optional<BlockRef> block; |
| 399 | if (timeout) { |
| 400 | auto now{std::chrono::steady_clock::now()}; |
| 401 | if (now >= deadline) break; |
| 402 | const MillisecondsDouble remaining{deadline - now}; |
| 403 | block = miner.waitTipChanged(current_block.hash, remaining); |
| 404 | } else { |
| 405 | block = miner.waitTipChanged(current_block.hash); |
| 406 | } |
| 407 | // Return current block upon shutdown |
| 408 | if (!block) break; |
| 409 | current_block = *block; |
| 410 | } |
| 411 | |
| 412 | UniValue ret(UniValue::VOBJ); |
| 413 | ret.pushKV("hash", current_block.hash.GetHex()); |
| 414 | ret.pushKV("height", current_block.height); |
| 415 | return ret; |
| 416 | }, |
nothing calls this directly
no test coverage detected