Skip to content

Commit

Permalink
rpcdaemon: load JSON RPC validation spec once at startup (#1761)
Browse files Browse the repository at this point in the history
* rpcdaemon: load JSON RPC validation spec once at startup

* rpcdaemon: restore JSON RPC validator
  • Loading branch information
canepat authored Jan 17, 2024
1 parent 94baa51 commit 70dc351
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 25 deletions.
4 changes: 4 additions & 0 deletions silkworm/rpc/daemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <silkworm/rpc/ethbackend/remote_backend.hpp>
#include <silkworm/rpc/ethdb/file/local_database.hpp>
#include <silkworm/rpc/ethdb/kv/remote_database.hpp>
#include <silkworm/rpc/http/json_rpc_validator.hpp>
#include <silkworm/rpc/http/jwt.hpp>

namespace silkworm::rpc {
Expand Down Expand Up @@ -223,6 +224,9 @@ Daemon::Daemon(DaemonSettings settings, std::optional<mdbx::env> chaindata_env)

// Set compatibility with Erigon RpcDaemon at JSON RPC level
compatibility::set_erigon_json_api_compatibility_required(settings_.erigon_json_rpc_compatibility);

// Load JSON RPC specification for Ethereum API
rpc::http::JsonRpcValidator::load_specification();
}

void Daemon::add_private_services() {
Expand Down
2 changes: 1 addition & 1 deletion silkworm/rpc/http/json_rpc_validator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ static const std::string kRequestFieldParameters{"params"};
static const std::string kRequestRequiredFields{
kRequestFieldJsonRpc + "," + kRequestFieldId + "," + kRequestFieldMethod + "," + kRequestFieldParameters};

JsonRpcValidator::JsonRpcValidator() : accept_unknown_methods_{true} {
void JsonRpcValidator::load_specification() {
const auto spec = nlohmann::json::parse(json_rpc_specification, nullptr, /*allow_exceptions=*/false);
if (spec.contains("methods")) {
for (const auto& method : spec["methods"]) {
Expand Down
13 changes: 6 additions & 7 deletions silkworm/rpc/http/json_rpc_validator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@ struct JsonRpcValidationResult {

class JsonRpcValidator {
public:
JsonRpcValidator();
~JsonRpcValidator() = default;
static void load_specification();
static const std::string& openrpc_version() { return openrpc_version_; }

JsonRpcValidationResult validate(const nlohmann::json& request);
const std::string& openrpc_version() const { return openrpc_version_; }

private:
void check_request_fields(const nlohmann::json& request, JsonRpcValidationResult& result);
Expand All @@ -49,10 +48,10 @@ class JsonRpcValidator {
void validate_number(const nlohmann::json& number, JsonRpcValidationResult& result);
void validate_null(const nlohmann::json& value, JsonRpcValidationResult& result);

std::string openrpc_version_;
std::map<std::string, nlohmann::json> method_specs_;
std::map<std::string, boost::regex> patterns_;
bool accept_unknown_methods_;
inline static std::string openrpc_version_;
inline static std::map<std::string, nlohmann::json> method_specs_;
inline static std::map<std::string, boost::regex> patterns_;
bool accept_unknown_methods_{true};
};

} // namespace silkworm::rpc::http
36 changes: 21 additions & 15 deletions silkworm/rpc/http/json_rpc_validator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,19 @@

namespace silkworm::rpc::http {

//! Ensure JSON RPC spec has been loaded before creating JsonRpcValidator instance
static JsonRpcValidator create_validator_for_test() {
JsonRpcValidator::load_specification();
return {};
}

TEST_CASE("rpc::http::JsonRpcValidator loads spec in constructor", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
CHECK(validator.openrpc_version() == "1.2.4");
REQUIRE_NOTHROW(JsonRpcValidator::load_specification());
CHECK(JsonRpcValidator::openrpc_version() == "1.2.4");
}

TEST_CASE("rpc::http::JsonRpcValidator validates request fields", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"jsonrpc", "2.0"},
Expand All @@ -43,7 +49,7 @@ TEST_CASE("rpc::http::JsonRpcValidator validates request fields", "[rpc][http][j
}

TEST_CASE("rpc::http::JsonRpcValidator detects missing request field", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"method", "eth_getBlockByNumber"},
Expand Down Expand Up @@ -74,7 +80,7 @@ TEST_CASE("rpc::http::JsonRpcValidator detects missing request field", "[rpc][ht
}

TEST_CASE("rpc::http::JsonRpcValidator validates invalid request fields", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"jsonrpc", 2},
Expand Down Expand Up @@ -119,7 +125,7 @@ TEST_CASE("rpc::http::JsonRpcValidator validates invalid request fields", "[rpc]
}

TEST_CASE("rpc::http::JsonRpcValidator accepts missing params field", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"jsonrpc", "2.0"},
Expand All @@ -132,7 +138,7 @@ TEST_CASE("rpc::http::JsonRpcValidator accepts missing params field", "[rpc][htt
}

TEST_CASE("rpc::http::JsonRpcValidator detects unknown fields", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"unknown", "2.0"},
Expand All @@ -146,7 +152,7 @@ TEST_CASE("rpc::http::JsonRpcValidator detects unknown fields", "[rpc][http][jso
}

TEST_CASE("rpc::http::JsonRpcValidator accepts missing optional parameter", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"jsonrpc", "2.0"},
Expand All @@ -160,7 +166,7 @@ TEST_CASE("rpc::http::JsonRpcValidator accepts missing optional parameter", "[rp
}

TEST_CASE("rpc::http::JsonRpcValidator validates string parameter", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"jsonrpc", "2.0"},
Expand Down Expand Up @@ -218,7 +224,7 @@ TEST_CASE("rpc::http::JsonRpcValidator validates string parameter", "[rpc][http]
}

TEST_CASE("rpc::http::JsonRpcValidator validates optional parameter if provided", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"jsonrpc", "2.0"},
Expand All @@ -231,7 +237,7 @@ TEST_CASE("rpc::http::JsonRpcValidator validates optional parameter if provided"
}

TEST_CASE("rpc::http::JsonRpcValidator validates enum", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"jsonrpc", "2.0"},
Expand Down Expand Up @@ -262,7 +268,7 @@ TEST_CASE("rpc::http::JsonRpcValidator validates enum", "[rpc][http][json_rpc_va
}

TEST_CASE("rpc::http::JsonRpcValidator validates hash", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"jsonrpc", "2.0"},
Expand All @@ -283,7 +289,7 @@ TEST_CASE("rpc::http::JsonRpcValidator validates hash", "[rpc][http][json_rpc_va
}

TEST_CASE("rpc::http::JsonRpcValidator validates array", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"jsonrpc", "2.0"},
Expand All @@ -303,7 +309,7 @@ TEST_CASE("rpc::http::JsonRpcValidator validates array", "[rpc][http][json_rpc_v
}

TEST_CASE("rpc::http::JsonRpcValidator validates object", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator{};
JsonRpcValidator validator{create_validator_for_test()};

nlohmann::json request = {
{"jsonrpc", "2.0"},
Expand Down Expand Up @@ -378,7 +384,7 @@ TEST_CASE("rpc::http::JsonRpcValidator validates object", "[rpc][http][json_rpc_
}

TEST_CASE("rpc::http::JsonRpcValidator validates spec test request", "[rpc][http][json_rpc_validator]") {
JsonRpcValidator validator;
JsonRpcValidator validator{create_validator_for_test()};

const auto tests_dir = test::get_tests_dir();
for (const auto& test_file : std::filesystem::recursive_directory_iterator(tests_dir)) {
Expand Down
3 changes: 1 addition & 2 deletions silkworm/rpc/http/request_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ class RequestHandler {

const commands::RpcApiTable& rpc_api_table_;

// commented for performance reason
// JsonRpcValidator json_rpc_validator_;
JsonRpcValidator json_rpc_validator_;
};

} // namespace silkworm::rpc::http

0 comments on commit 70dc351

Please sign in to comment.