From 97e0161cfdf450a7b81ac466d075f8a017e75056 Mon Sep 17 00:00:00 2001 From: Lee *!* Clagett Date: Thu, 22 Jan 2026 15:05:53 -0500 Subject: [PATCH] Add constraints/limits to async rest responses (#229) --- src/config.h | 10 ++++++++++ src/error.cpp | 3 +++ src/error.h | 1 + src/rest_server.cpp | 19 ++++++++++++++++++- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/config.h b/src/config.h index b0429a5..f294df6 100644 --- a/src/config.h +++ b/src/config.h @@ -1,5 +1,6 @@ #pragma once +#include #include "cryptonote_config.h" namespace lws @@ -7,5 +8,14 @@ namespace lws namespace config { extern cryptonote::network_type network; + + //! Max queued clients when waiting for cacheable daemon response + constexpr const std::size_t daemon_wait_queue_max = 25000; + + //! Max queued clients for `get_random_outs` + constexpr const std::size_t get_random_outs_max = 10000; + + //! Max memory allowed for `submit_raw_tx` buffering + constexpr const std::size_t submit_tx_max = 100 * 1024 * 1024; } } diff --git a/src/error.cpp b/src/error.cpp index a4db6c9..3d7b0d6 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -91,6 +91,8 @@ namespace lws return "Invalid subaddress range provided"; case error::json_rpc: return "Error returned by JSON-RPC server"; + case error::load: + return "Server load limits have been reached"; case error::exchange_rates_old: return "Exchange rates are older than cache interval"; case error::max_subaddresses: @@ -125,6 +127,7 @@ namespace lws case error::bad_view_key: return std::errc::bad_address; case error::daemon_timeout: + case error::load: return std::errc::timed_out; case error::exceeded_blockchain_buffer: return std::errc::no_buffer_space; diff --git a/src/error.h b/src/error.h index ca67de3..2980e87 100644 --- a/src/error.h +++ b/src/error.h @@ -60,6 +60,7 @@ namespace lws http_server, //!< HTTP server failure (init or run) invalid_range, //!< Invalid subaddress range provided json_rpc, //!< Error returned by JSON-RPC server + load, //!< Server load limits reached max_subaddresses, //!< Max subaddresses exceeded not_enough_mixin, //!< Not enough outputs to meet mixin count not_enough_amount, //!< Not enough outputs to meet amount diff --git a/src/rest_server.cpp b/src/rest_server.cpp index 3719281..8578e91 100644 --- a/src/rest_server.cpp +++ b/src/rest_server.cpp @@ -364,6 +364,9 @@ namespace lws auto active = cache.status.lock(); if (active) { + if (config::daemon_wait_queue_max < active->resumers.size()) + return {error::load}; + active->resumers.push_back(std::move(resume)); return async_ready(); } @@ -757,6 +760,9 @@ namespace lws auto active = cache.status.lock(); if (active) { + if (config::get_random_outs_max < active->resumers.size()) + return {error::load}; + active->resumers.emplace_back(std::move(req), std::move(resume)); return success(); } @@ -1193,6 +1199,9 @@ namespace lws auto active = cache.status.lock(); if (active) { + if (config::daemon_wait_queue_max < active->resumers.size()) + return {error::load}; + active->resumers.emplace_back(std::move(req), std::move(resume)); return async_ready(); } @@ -1587,6 +1596,7 @@ namespace lws boost::asio::steady_timer timer; boost::asio::io_context::strand strand; std::deque>> resumers; + std::size_t outstanding; frame(rest_server_data& parent, net::zmq::async_client client) : parent(std::addressof(parent)), @@ -1594,7 +1604,8 @@ namespace lws client(std::move(client)), timer(parent.io), strand(parent.io), - resumers() + resumers(), + outstanding(0) {} }; @@ -1620,6 +1631,10 @@ namespace lws auto active = cache.status.lock(); if (active) { + if (std::numeric_limits::max() - msg.size() < active->outstanding || config::submit_tx_max < msg.size() + active->outstanding) + return {error::load}; + + active->outstanding += msg.size(); active->resumers.emplace_back(std::move(msg), std::move(resume)); return success(); } @@ -1709,6 +1724,7 @@ namespace lws return; } next = std::move(self_->resumers.front().first); + self_->outstanding -= std::min(self_->outstanding, next.size()); } set_timeout(std::chrono::seconds{10}, false); @@ -1751,6 +1767,7 @@ namespace lws active = std::make_shared(*data.global, std::move(*client)); cache.status = active; + active->outstanding += msg.size(); active->resumers.emplace_back(std::move(msg), std::move(resume)); lock.unlock();