From e3e82a102099bc2891aca3543758b1a7dc1a11c1 Mon Sep 17 00:00:00 2001 From: TuxedoFish <“harryliversedge@gmail.com”> Date: Thu, 10 Sep 2026 10:53:16 +0100 Subject: [PATCH] Add ApiConfig::validateJson to skip WebsocketMessageParser's DOM validation pass crack() runs a full simdjson DOM parse ahead of its on-demand parse purely to guarantee malformed input is rejected as a catchable error rather than hitting an internal simdjson ondemand assertion (issue #109). That's a real cost on every non-fast-pathed message. Set validateJson=false once the feed is trusted to skip it. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_018Le73N2EZjGLsCqmCScAse --- include/hyperliquid/config/Config.h | 2 ++ include/hyperliquid/websocket/WebsocketMessageParser.h | 4 +++- src/websocket/WebsocketMessageParser.cpp | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/hyperliquid/config/Config.h b/include/hyperliquid/config/Config.h index c384ee9..34af637 100644 --- a/include/hyperliquid/config/Config.h +++ b/include/hyperliquid/config/Config.h @@ -36,5 +36,7 @@ namespace hyperliquid // Default vault/subaccount address used when a per-call vaultAddress isn't given - see // Signing::prepareBodyForType for which action types this fallback does and doesn't apply to. std::optional vaultAddress; + // Set false to skip WebsocketMessageParser's extra DOM validation pass (see crack()). + bool validateJson = true; }; } diff --git a/include/hyperliquid/websocket/WebsocketMessageParser.h b/include/hyperliquid/websocket/WebsocketMessageParser.h index f872771..1d4fd57 100644 --- a/include/hyperliquid/websocket/WebsocketMessageParser.h +++ b/include/hyperliquid/websocket/WebsocketMessageParser.h @@ -4,6 +4,7 @@ #include #include #include "WebsocketMessageHandler.h" +#include "../config/Config.h" namespace hyperliquid { @@ -14,7 +15,8 @@ namespace hyperliquid class WebsocketMessageParser { public: - WebsocketMessageParser(); + // See ApiConfig::validateJson. + explicit WebsocketMessageParser(const ApiConfig& config = ApiConfig{}); ~WebsocketMessageParser(); WebsocketMessageParser(WebsocketMessageParser&&) noexcept; diff --git a/src/websocket/WebsocketMessageParser.cpp b/src/websocket/WebsocketMessageParser.cpp index 903812c..f23cb0b 100644 --- a/src/websocket/WebsocketMessageParser.cpp +++ b/src/websocket/WebsocketMessageParser.cpp @@ -103,6 +103,9 @@ namespace hyperliquid simdjson::ondemand::parser parser; simdjson::padded_string padded; simdjson::dom::parser domParser; + bool validateJson_; + + explicit Impl(bool validateJson) : validateJson_(validateJson) {} // simdjson's ondemand API can hit an internal assertion (abort) rather than a catchable // simdjson_error when a value is looked up by name more than once on the same malformed @@ -111,6 +114,7 @@ namespace hyperliquid // a structurally invalid document. void validateStructure(std::string_view message) { + if (!validateJson_) return; domParser.parse(message.data(), message.size()).value(); } @@ -1493,7 +1497,7 @@ namespace hyperliquid } }; - WebsocketMessageParser::WebsocketMessageParser() : impl_(std::make_unique()) {} + WebsocketMessageParser::WebsocketMessageParser(const ApiConfig& config) : impl_(std::make_unique(config.validateJson)) {} WebsocketMessageParser::~WebsocketMessageParser() = default; WebsocketMessageParser::WebsocketMessageParser(WebsocketMessageParser&&) noexcept = default;