Compare commits

..

2 Commits

Author SHA1 Message Date
tequ
04b704e8e1 Reject hook wasm without memory section
Add fixHookMemoryMissing Amendment and extend guard validation to detect wasm modules that do not declare a memory section. When the amendment is enabled, such hooks are rejected as malformed at install time.

Also handle unavailable WasmEdge memory during hook execution as a WASM error under the new amendment, and add SetHook coverage for hooks created before and after the amendment is enabled.
2026-07-04 00:14:11 +09:00
Richard Holland
bb244ef772 put release builds into a candidate folder to prevent auto-update scripts running before smoke tests (#761) 2026-06-21 12:12:43 +10:00
15 changed files with 370 additions and 1835 deletions

View File

@@ -77,11 +77,6 @@ test.ledger > xrpld.app
test.ledger > xrpld.core
test.ledger > xrpld.ledger
test.ledger > xrpl.protocol
test.net > test.toplevel
test.net > xrpl.basics
test.net > xrpld.core
test.net > xrpld.net
test.net > xrpl.json
test.nodestore > test.jtx
test.nodestore > test.toplevel
test.nodestore > test.unit_test

View File

@@ -95,8 +95,16 @@ if [[ "$4" == "" ]]; then
echo "Non GH, local building, no Action runner magic"
else
# GH Action, runner
cp /io/release-build/xahaud /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
cp /io/release-build/release.info /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
if [[ "$(git rev-parse --abbrev-ref HEAD)" == "release" ]]; then
echo "building on the release branch... placing it in builds/candidate"
mkdir /data/builds/candidate
cp /io/release-build/xahaud /data/builds/candidate/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
cp /io/release-build/release.info /data/builds/candidate/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
else
echo "building non-release branch, placing it in builds root"
cp /io/release-build/xahaud /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
cp /io/release-build/release.info /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
fi
echo "Published build to: http://build.xahau.tech/"
echo $(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
fi

View File

@@ -17,6 +17,7 @@
#define featureHooksUpdate2 "1"
#define fix20250131 "1"
#define fixGuardDepth32 "1"
#define fixHookMemoryMissing "1"
namespace hook_api {
struct Rules
{
@@ -267,6 +268,7 @@ enum hook_log_code : uint16_t {
CUSTOM_SECTION_DISALLOWED =
86, // the wasm contained a custom section (id=0)
INTERNAL_ERROR = 87, // an internal error described by the log text
MEMORY_MISSING = 88, // hook wasm did not contain a memory section
// RH NOTE: only HookSet msgs got log codes, possibly all Hook log lines
// should get a code?
};
@@ -445,6 +447,7 @@ getImportWhitelist(Rules const& rules)
enum GuardRulesVersion : uint64_t {
GuardRuleFix20250131 = 0x00000001,
GuardRuleDepth32 = 0x00000002,
GuardRuleMemoryMissing = 0x00000004,
};
inline uint64_t
@@ -455,6 +458,8 @@ getGuardRulesVersion(Rules const& rules)
version |= GuardRuleFix20250131;
if (rules.enabled(fixGuardDepth32))
version |= GuardRuleDepth32;
if (rules.enabled(fixHookMemoryMissing))
version |= GuardRuleMemoryMissing;
return version;
}

View File

@@ -893,6 +893,7 @@ validateGuards(
int last_import_number = -1;
int import_count = 0;
int last_section_type = 0;
bool has_memory_section = false;
for (int i = 8, j = 0; i < wasm.size();)
{
if (j == i)
@@ -1181,11 +1182,24 @@ validateGuards(
func_type_map[j] = type_idx;
}
}
else if (section_type == 5) // memory section
{
has_memory_section = true;
}
i = next_section;
continue;
}
if ((rulesVersion & hook_api::GuardRuleMemoryMissing) &&
!has_memory_section)
{
GUARDLOG(hook::log::MEMORY_MISSING)
<< "Malformed transaction. Hook did not contain a memory section."
<< "\n";
return {};
}
// we must subtract import_count from the hook and cbak function in order to
// be able to look them up in the functions section. this is a rule of the
// webassembly spec note that at this point in execution we are guarenteed

View File

@@ -150,23 +150,32 @@
WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \
COMMA __VA_ARGS__))
#define HOOK_SETUP() \
using enum hook_api::hook_return_code; \
try \
{ \
[[maybe_unused]] ApplyContext& applyCtx = hookCtx.applyCtx; \
[[maybe_unused]] auto& view = applyCtx.view(); \
[[maybe_unused]] auto j = applyCtx.app.journal("View"); \
[[maybe_unused]] WasmEdge_MemoryInstanceContext* memoryCtx = \
WasmEdge_CallingFrameGetMemoryInstance(&frameCtx, 0); \
[[maybe_unused]] unsigned char* memory = \
WasmEdge_MemoryInstanceGetPointer(memoryCtx, 0, 0); \
[[maybe_unused]] const uint64_t memory_length = \
WasmEdge_MemoryInstanceGetPageSize(memoryCtx) * \
WasmEdge_kPageSize; \
[[maybe_unused]] auto& api = hookCtx.api(); \
if (!memoryCtx || !memory || !memory_length) \
return INTERNAL_ERROR;
#define HOOK_SETUP() \
using enum hook_api::hook_return_code; \
try \
{ \
[[maybe_unused]] ApplyContext& applyCtx = hookCtx.applyCtx; \
[[maybe_unused]] auto& view = applyCtx.view(); \
[[maybe_unused]] auto j = applyCtx.app.journal("View"); \
[[maybe_unused]] WasmEdge_MemoryInstanceContext* memoryCtx = \
WasmEdge_CallingFrameGetMemoryInstance(&frameCtx, 0); \
if (!memoryCtx) \
{ \
JLOG(j.warn()) << "HookError[" << HC_ACC() \
<< "]: wasm memory is unavailable"; \
if (view.rules().enabled(fixHookMemoryMissing)) \
{ \
hookCtx.result.exitType = hook_api::ExitType::WASM_ERROR; \
hookCtx.result.exitReason = ""; \
return INTERNAL_ERROR; \
} \
} \
[[maybe_unused]] unsigned char* memory = \
WasmEdge_MemoryInstanceGetPointer(memoryCtx, 0, 0); \
[[maybe_unused]] const uint64_t memory_length = \
WasmEdge_MemoryInstanceGetPageSize(memoryCtx) * \
WasmEdge_kPageSize; \
[[maybe_unused]] auto& api = hookCtx.api();
#define HOOK_TEARDOWN() \
} \

View File

@@ -34,6 +34,7 @@
// If you add an amendment here, then do not forget to increment `numFeatures`
// in include/xrpl/protocol/Feature.h.
XRPL_FIX (HookMemoryMissing, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (HookMap, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (GuardDepth32, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(NamedHooks, Supported::yes, VoteBehavior::DefaultNo)

View File

@@ -3081,6 +3081,100 @@ public:
ter(temMALFORMED));
}
void
testWasmMissingMemory(FeatureBitset features)
{
testcase("missing memory");
using namespace jtx;
auto const alice = Account{"alice"};
auto const bob = Account{"bob"};
auto const carol = Account{"carol"};
TestHook missing_memory_wasm = wasm[R"[test.hook](
(module
(type $rollback_type
(func (param i32 i32 i64) (result i64)))
(type $guard_type (func (param i32 i32) (result i32)))
(type $hook_type (func (param i32) (result i64)))
(import "env" "rollback"
(func $rollback (type $rollback_type)))
(import "env" "_g" (func $_g (type $guard_type)))
(func $hook (type $hook_type) (param i32) (result i64)
i32.const 1
i32.const 1
i64.const 0
call $rollback
drop
i32.const 1
i32.const 1
call $_g
drop
i64.const 0)
(export "hook" (func $hook)))
)[test.hook]"];
for (auto const& withFix : {false, true})
{
// test if the Hook is created before the Amendment is enabled
Env env{*this, features - fixHookMemoryMissing};
env.fund(XRP(10000), alice, bob, carol);
env(ripple::test::jtx::hook(alice, {{hso(missing_memory_wasm)}}, 0),
M("Install missing memory hook"),
HSFEE);
env.close();
if (withFix)
{
env.enableFeature(fixHookMemoryMissing);
env.close();
}
env(pay(bob, alice, XRP(1)),
M("Test missing memory hook"),
fee(XRP(1)),
ter(tecHOOK_REJECTED));
auto meta = env.meta();
BEAST_REQUIRE(meta);
BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions));
auto const& hookExecutions = meta->getFieldArray(sfHookExecutions);
BEAST_REQUIRE(hookExecutions.size() == 1);
auto const& e = hookExecutions[0];
auto const expectedExitType = withFix
? hook_api::ExitType::WASM_ERROR
: hook_api::ExitType::UNSET;
BEAST_EXPECT(
e.getFieldU8(sfHookResult) ==
static_cast<uint8_t>(expectedExitType));
BEAST_EXPECT(e.getFieldVL(sfHookReturnString).size() == 0);
BEAST_EXPECT(
e.getFieldU64(sfHookReturnCode) ==
0x8000000000000001 /* INTERNAL_ERROR */);
}
for (auto const& withFix : {false, true})
{
// test if the Hook is created after the Amendment is enabled
auto f = features - fixHookMemoryMissing;
if (withFix)
f = f | fixHookMemoryMissing;
Env env{*this, f};
env.fund(XRP(10000), alice, bob, carol);
auto const expectedTer =
withFix ? TER{temMALFORMED} : TER{tesSUCCESS};
env(ripple::test::jtx::hook(alice, {{hso(missing_memory_wasm)}}, 0),
M("Install missing memory hook"),
HSFEE,
ter(expectedTer));
env.close();
}
}
void
test_accept(FeatureBitset features)
{
@@ -15077,6 +15171,8 @@ public:
void
testWithFeatures(FeatureBitset features)
{
testWasmMissingMemory(features);
return;
testHooksOwnerDir(features);
testHooksDisabled(features);
testTxStructure(features);
@@ -15103,6 +15199,7 @@ public:
testFillCopy(features);
testWasm(features);
testWasmMissingMemory(features);
test_accept(features);
test_rollback(features);

View File

@@ -191,6 +191,42 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
}},
/* ==== WASM: 1 ==== */
{R"[test.hook](
(module
(type $rollback_type
(func (param i32 i32 i64) (result i64)))
(type $guard_type (func (param i32 i32) (result i32)))
(type $hook_type (func (param i32) (result i64)))
(import "env" "rollback"
(func $rollback (type $rollback_type)))
(import "env" "_g" (func $_g (type $guard_type)))
(func $hook (type $hook_type) (param i32) (result i64)
i32.const 1
i32.const 1
i64.const 0
call $rollback
drop
i32.const 1
i32.const 1
call $_g
drop
i64.const 0)
(export "hook" (func $hook)))
)[test.hook]",
{
0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x13U,
0x03U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x02U,
0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U,
0x19U, 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x08U, 0x72U, 0x6FU, 0x6CU,
0x6CU, 0x62U, 0x61U, 0x63U, 0x6BU, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU,
0x76U, 0x02U, 0x5FU, 0x67U, 0x00U, 0x01U, 0x03U, 0x02U, 0x01U, 0x02U,
0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x02U,
0x0AU, 0x16U, 0x01U, 0x14U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U, 0x42U,
0x00U, 0x10U, 0x00U, 0x1AU, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U, 0x01U,
0x1AU, 0x42U, 0x00U, 0x0BU,
}},
/* ==== WASM: 2 ==== */
{R"[test.hook](
(module
(type (;0;) (func (param i32 i32) (result i64)))
@@ -240,7 +276,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x0BU,
}},
/* ==== WASM: 2 ==== */
/* ==== WASM: 3 ==== */
{R"[test.hook](
(module
(type (;0;) (func (param i32 i32) (result i64)))
@@ -294,7 +330,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x14U, 0x10U, 0x00U, 0x1AU, 0x0CU, 0x00U, 0x0BU, 0x0BU,
}},
/* ==== WASM: 3 ==== */
/* ==== WASM: 4 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -361,7 +397,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x80U, 0x80U, 0x00U, 0x20U, 0x02U, 0x0BU,
}},
/* ==== WASM: 4 ==== */
/* ==== WASM: 5 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -467,7 +503,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x6AU, 0x24U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x20U, 0x03U, 0x0BU,
}},
/* ==== WASM: 5 ==== */
/* ==== WASM: 6 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -542,7 +578,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x6AU, 0x24U, 0x80U, 0x80U, 0x80U, 0x80U, 0x00U, 0x20U, 0x05U, 0x0BU,
}},
/* ==== WASM: 6 ==== */
/* ==== WASM: 7 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g(uint32_t, uint32_t);
@@ -1159,7 +1195,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x78U, 0x29U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x33U, 0x32U, 0x00U,
}},
/* ==== WASM: 7 ==== */
/* ==== WASM: 8 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g(uint32_t, uint32_t);
@@ -1588,7 +1624,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U,
}},
/* ==== WASM: 8 ==== */
/* ==== WASM: 9 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -1794,7 +1830,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x3DU, 0x20U, 0x30U, 0x78U, 0x45U, 0x31U, 0x00U,
}},
/* ==== WASM: 9 ==== */
/* ==== WASM: 10 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -1916,7 +1952,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x58U, 0x4EU, 0x00U,
}},
/* ==== WASM: 10 ==== */
/* ==== WASM: 11 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -2049,7 +2085,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x4FU, 0x4EU, 0x43U, 0x45U, 0x53U, 0x00U,
}},
/* ==== WASM: 11 ==== */
/* ==== WASM: 12 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -2129,7 +2165,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x54U, 0x00U,
}},
/* ==== WASM: 12 ==== */
/* ==== WASM: 13 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -2174,7 +2210,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x30U, 0x00U,
}},
/* ==== WASM: 13 ==== */
/* ==== WASM: 14 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -2493,7 +2529,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x80U, 0x80U, 0x80U, 0x00U, 0x0BU,
}},
/* ==== WASM: 14 ==== */
/* ==== WASM: 15 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -3279,7 +3315,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x37U, 0x36U, 0x33U, 0x4CU, 0x4CU, 0x20U, 0x29U, 0x00U,
}},
/* ==== WASM: 15 ==== */
/* ==== WASM: 16 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -3669,7 +3705,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x80U, 0x80U, 0x80U, 0x00U, 0x0BU,
}},
/* ==== WASM: 16 ==== */
/* ==== WASM: 17 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -3850,7 +3886,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x38U, 0x4CU, 0x4CU, 0x29U, 0x00U,
}},
/* ==== WASM: 17 ==== */
/* ==== WASM: 18 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -4039,7 +4075,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x29U, 0x00U,
}},
/* ==== WASM: 18 ==== */
/* ==== WASM: 19 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -4278,7 +4314,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U, 0x42U, 0x00U, 0x10U, 0x85U, 0x80U, 0x80U, 0x80U, 0x00U, 0x0BU,
}},
/* ==== WASM: 19 ==== */
/* ==== WASM: 20 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -4980,7 +5016,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x38U, 0x35U, 0x35U, 0x32U, 0x55U, 0x29U, 0x00U,
}},
/* ==== WASM: 20 ==== */
/* ==== WASM: 21 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -6325,7 +6361,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x20U, 0x29U, 0x00U,
}},
/* ==== WASM: 21 ==== */
/* ==== WASM: 22 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -6427,7 +6463,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x84U, 0x80U, 0x80U, 0x80U, 0x00U, 0x0BU,
}},
/* ==== WASM: 22 ==== */
/* ==== WASM: 23 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -6470,7 +6506,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U, 0x0BU,
}},
/* ==== WASM: 23 ==== */
/* ==== WASM: 24 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -6618,7 +6654,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x34U, 0x34U, 0x4CU, 0x4CU, 0x2CU, 0x20U, 0x33U, 0x29U, 0x00U,
}},
/* ==== WASM: 24 ==== */
/* ==== WASM: 25 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -6946,7 +6982,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x38U, 0x34U, 0x39U, 0x30U, 0x4CU, 0x4CU, 0x00U,
}},
/* ==== WASM: 25 ==== */
/* ==== WASM: 26 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -7151,7 +7187,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x10U, 0x85U, 0x80U, 0x80U, 0x80U, 0x00U, 0x0BU,
}},
/* ==== WASM: 26 ==== */
/* ==== WASM: 27 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -7835,7 +7871,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x20U, 0x3DU, 0x3DU, 0x20U, 0x30U, 0x00U,
}},
/* ==== WASM: 27 ==== */
/* ==== WASM: 28 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -8130,7 +8166,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x32U, 0x34U, 0x31U, 0x36U, 0x55U, 0x4CU, 0x4CU, 0x00U,
}},
/* ==== WASM: 28 ==== */
/* ==== WASM: 29 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -8843,7 +8879,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x31U, 0x33U, 0x33U, 0x38U, 0x20U, 0x29U, 0x00U,
}},
/* ==== WASM: 29 ==== */
/* ==== WASM: 30 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -8928,7 +8964,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x30U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x32U, 0x30U, 0x00U,
}},
/* ==== WASM: 30 ==== */
/* ==== WASM: 31 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -8990,7 +9026,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x80U, 0x80U, 0x00U, 0x0BU,
}},
/* ==== WASM: 31 ==== */
/* ==== WASM: 32 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -9067,7 +9103,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x31U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x33U, 0x32U, 0x00U,
}},
/* ==== WASM: 32 ==== */
/* ==== WASM: 33 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -9144,7 +9180,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x31U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x33U, 0x32U, 0x00U,
}},
/* ==== WASM: 33 ==== */
/* ==== WASM: 34 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -9401,7 +9437,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U, 0x00U,
}},
/* ==== WASM: 34 ==== */
/* ==== WASM: 35 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -9559,7 +9595,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x04U, 0x00U, 0x00U,
}},
/* ==== WASM: 35 ==== */
/* ==== WASM: 36 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -9912,7 +9948,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U, 0x2AU, 0x04U, 0x00U, 0x00U, 0x31U, 0x04U, 0x00U, 0x00U,
}},
/* ==== WASM: 36 ==== */
/* ==== WASM: 37 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -9945,7 +9981,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x82U, 0x80U, 0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x0BU,
}},
/* ==== WASM: 37 ==== */
/* ==== WASM: 38 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -10172,7 +10208,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U,
}},
/* ==== WASM: 38 ==== */
/* ==== WASM: 39 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -10203,7 +10239,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x0BU,
}},
/* ==== WASM: 39 ==== */
/* ==== WASM: 40 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -10514,7 +10550,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U,
}},
/* ==== WASM: 40 ==== */
/* ==== WASM: 41 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -10591,7 +10627,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x33U, 0x32U, 0x00U,
}},
/* ==== WASM: 41 ==== */
/* ==== WASM: 42 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -10625,7 +10661,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x80U, 0x80U, 0x00U, 0x1AU, 0x20U, 0x01U, 0x0BU,
}},
/* ==== WASM: 42 ==== */
/* ==== WASM: 43 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -10712,7 +10748,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x32U, 0x00U,
}},
/* ==== WASM: 43 ==== */
/* ==== WASM: 44 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -10746,7 +10782,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x0BU,
}},
/* ==== WASM: 44 ==== */
/* ==== WASM: 45 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -10886,7 +10922,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x54U, 0x5FU, 0x4DU, 0x45U, 0x54U, 0x00U,
}},
/* ==== WASM: 45 ==== */
/* ==== WASM: 46 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -11076,7 +11112,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x31U, 0x34U, 0x00U,
}},
/* ==== WASM: 46 ==== */
/* ==== WASM: 47 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -11230,7 +11266,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U,
}},
/* ==== WASM: 47 ==== */
/* ==== WASM: 48 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -11391,7 +11427,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U,
}},
/* ==== WASM: 48 ==== */
/* ==== WASM: 49 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -11548,7 +11584,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x53U, 0x4CU, 0x4FU, 0x54U, 0x53U, 0x00U,
}},
/* ==== WASM: 49 ==== */
/* ==== WASM: 50 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -11633,7 +11669,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x74U, 0x79U, 0x70U, 0x65U, 0x28U, 0x29U, 0x00U,
}},
/* ==== WASM: 50 ==== */
/* ==== WASM: 51 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -11890,7 +11926,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U, 0x00U,
}},
/* ==== WASM: 51 ==== */
/* ==== WASM: 52 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -12128,7 +12164,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x3EU, 0x20U, 0x30U, 0x00U,
}},
/* ==== WASM: 52 ==== */
/* ==== WASM: 53 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -12224,7 +12260,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x53U, 0x54U, 0x00U,
}},
/* ==== WASM: 53 ==== */
/* ==== WASM: 54 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -12334,7 +12370,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x20U, 0x31U, 0x00U,
}},
/* ==== WASM: 54 ==== */
/* ==== WASM: 55 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -12464,7 +12500,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x30U, 0x30U, 0x30U, 0x4CU, 0x4CU, 0x00U,
}},
/* ==== WASM: 55 ==== */
/* ==== WASM: 56 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -12738,7 +12774,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x30U, 0x00U,
}},
/* ==== WASM: 56 ==== */
/* ==== WASM: 57 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -12875,7 +12911,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x2CU, 0x20U, 0x73U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x31U, 0x00U,
}},
/* ==== WASM: 57 ==== */
/* ==== WASM: 58 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -13169,7 +13205,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x5FU, 0x53U, 0x4CU, 0x4FU, 0x54U, 0x53U, 0x00U,
}},
/* ==== WASM: 58 ==== */
/* ==== WASM: 59 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -13403,7 +13439,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x5FU, 0x53U, 0x4CU, 0x4FU, 0x54U, 0x53U, 0x00U,
}},
/* ==== WASM: 59 ==== */
/* ==== WASM: 60 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -13699,7 +13735,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x2CU, 0x20U, 0x31U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x30U, 0x00U,
}},
/* ==== WASM: 60 ==== */
/* ==== WASM: 61 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -13903,7 +13939,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x6EU, 0x74U, 0x32U, 0x22U, 0x20U, 0x2BU, 0x20U, 0x69U, 0x29U, 0x00U,
}},
/* ==== WASM: 61 ==== */
/* ==== WASM: 62 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -14020,7 +14056,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x69U, 0x29U, 0x00U,
}},
/* ==== WASM: 62 ==== */
/* ==== WASM: 63 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -14129,7 +14165,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x6EU, 0x74U, 0x65U, 0x6EU, 0x74U, 0x32U, 0x22U, 0x29U, 0x00U,
}},
/* ==== WASM: 63 ==== */
/* ==== WASM: 64 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -14402,7 +14438,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U,
}},
/* ==== WASM: 64 ==== */
/* ==== WASM: 65 ==== */
{R"[test.hook](
#include <stdint.h>
#define sfInvoiceID ((5U << 16U) + 17U)
@@ -14621,7 +14657,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x30U, 0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x33U, 0x32U, 0x00U,
}},
/* ==== WASM: 65 ==== */
/* ==== WASM: 66 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -14733,7 +14769,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x58U, 0x49U, 0x53U, 0x54U, 0x00U,
}},
/* ==== WASM: 66 ==== */
/* ==== WASM: 67 ==== */
{R"[test.hook](
#include <stdint.h>
#define sfInvoiceID ((5U << 16U) + 17U)
@@ -14869,7 +14905,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x3DU, 0x20U, 0x33U, 0x32U, 0x00U,
}},
/* ==== WASM: 67 ==== */
/* ==== WASM: 68 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -15005,7 +15041,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x49U, 0x47U, 0x00U,
}},
/* ==== WASM: 68 ==== */
/* ==== WASM: 69 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -15144,7 +15180,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x66U, 0x28U, 0x64U, 0x61U, 0x74U, 0x61U, 0x32U, 0x29U, 0x00U,
}},
/* ==== WASM: 69 ==== */
/* ==== WASM: 70 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -15256,7 +15292,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x30U, 0x00U,
}},
/* ==== WASM: 70 ==== */
/* ==== WASM: 71 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -15350,7 +15386,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x61U, 0x64U, 0x5BU, 0x69U, 0x5DU, 0x00U,
}},
/* ==== WASM: 71 ==== */
/* ==== WASM: 72 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -15483,7 +15519,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x64U, 0x5BU, 0x69U, 0x5DU, 0x00U,
}},
/* ==== WASM: 72 ==== */
/* ==== WASM: 73 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -15571,7 +15607,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x61U, 0x74U, 0x61U, 0x29U, 0x00U,
}},
/* ==== WASM: 73 ==== */
/* ==== WASM: 74 ==== */
{R"[test.hook](
#include <stdint.h>
#define sfInvoiceID ((5U << 16U) + 17U)
@@ -15682,7 +15718,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x20U, 0x33U, 0x32U, 0x00U,
}},
/* ==== WASM: 74 ==== */
/* ==== WASM: 75 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -15893,7 +15929,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U,
}},
/* ==== WASM: 75 ==== */
/* ==== WASM: 76 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -16001,7 +16037,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x20U, 0x22U, 0x32U, 0x22U, 0x2CU, 0x20U, 0x31U, 0x29U, 0x00U,
}},
/* ==== WASM: 76 ==== */
/* ==== WASM: 77 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -16613,7 +16649,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U,
}},
/* ==== WASM: 77 ==== */
/* ==== WASM: 78 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -16800,7 +16836,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x63U, 0x65U, 0x29U, 0x20U, 0x3EU, 0x20U, 0x30U, 0x00U,
}},
/* ==== WASM: 78 ==== */
/* ==== WASM: 79 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -17150,7 +17186,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x20U, 0x30U, 0x00U,
}},
/* ==== WASM: 79 ==== */
/* ==== WASM: 80 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -17286,7 +17322,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U,
}},
/* ==== WASM: 80 ==== */
/* ==== WASM: 81 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -17345,7 +17381,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x64U, 0xE1U, 0xF1U,
}},
/* ==== WASM: 81 ==== */
/* ==== WASM: 82 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -17518,7 +17554,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x54U, 0x5FU, 0x45U, 0x58U, 0x49U, 0x53U, 0x54U, 0x00U,
}},
/* ==== WASM: 82 ==== */
/* ==== WASM: 83 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -17666,7 +17702,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x30U, 0x00U, 0x22U, 0x00U, 0x00U, 0x00U, 0x00U,
}},
/* ==== WASM: 83 ==== */
/* ==== WASM: 84 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -17820,7 +17856,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x0FU, 0x0BU, 0x02U, 0x56U, 0x00U,
}},
/* ==== WASM: 84 ==== */
/* ==== WASM: 85 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -17917,7 +17953,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x3DU, 0x20U, 0x30U, 0x00U,
}},
/* ==== WASM: 85 ==== */
/* ==== WASM: 86 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -17976,7 +18012,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x4FU, 0x46U, 0x5FU, 0x42U, 0x4FU, 0x55U, 0x4EU, 0x44U, 0x53U, 0x00U,
}},
/* ==== WASM: 86 ==== */
/* ==== WASM: 87 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -18035,7 +18071,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x4EU, 0x44U, 0x53U, 0x00U,
}},
/* ==== WASM: 87 ==== */
/* ==== WASM: 88 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -19864,7 +19900,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x53U, 0x4DU, 0x41U, 0x4CU, 0x4CU, 0x00U,
}},
/* ==== WASM: 88 ==== */
/* ==== WASM: 89 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -21483,7 +21519,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x29U, 0x29U, 0x00U,
}},
/* ==== WASM: 89 ==== */
/* ==== WASM: 90 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -24416,7 +24452,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x4FU, 0x4FU, 0x5FU, 0x53U, 0x4DU, 0x41U, 0x4CU, 0x4CU, 0x00U,
}},
/* ==== WASM: 90 ==== */
/* ==== WASM: 91 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -26381,7 +26417,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x54U, 0x4FU, 0x4FU, 0x5FU, 0x53U, 0x4DU, 0x41U, 0x4CU, 0x4CU, 0x00U,
}},
/* ==== WASM: 91 ==== */
/* ==== WASM: 92 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -26666,7 +26702,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x29U, 0x20U, 0x3DU, 0x3DU, 0x20U, 0x30U, 0x00U,
}},
/* ==== WASM: 92 ==== */
/* ==== WASM: 93 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g(uint32_t, uint32_t);
@@ -27253,7 +27289,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x4EU, 0x5FU, 0x46U, 0x41U, 0x49U, 0x4CU, 0x55U, 0x52U, 0x45U, 0x00U,
}},
/* ==== WASM: 93 ==== */
/* ==== WASM: 94 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -27282,7 +27318,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x0BU,
}},
/* ==== WASM: 94 ==== */
/* ==== WASM: 95 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -27314,7 +27350,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x20U, 0x52U, 0x65U, 0x6AU, 0x65U, 0x63U, 0x74U, 0x65U, 0x64U, 0x00U,
}},
/* ==== WASM: 95 ==== */
/* ==== WASM: 96 ==== */
{R"[test.hook](
(module
(type (;0;) (func (param i32 i32 i64) (result i64)))
@@ -27341,7 +27377,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x00U, 0x0BU,
}},
/* ==== WASM: 96 ==== */
/* ==== WASM: 97 ==== */
{R"[test.hook](
(module
(type (;0;) (func (param i32 i32) (result i32)))
@@ -27394,7 +27430,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x00U, 0x1AU, 0x0BU,
}},
/* ==== WASM: 97 ==== */
/* ==== WASM: 98 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -34037,7 +34073,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x39U, 0x30U, 0x31U, 0x32U, 0x33U, 0x00U,
}},
/* ==== WASM: 98 ==== */
/* ==== WASM: 99 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -34083,7 +34119,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x0BU, 0x06U, 0x76U, 0x61U, 0x6CU, 0x75U, 0x65U, 0x00U,
}},
/* ==== WASM: 99 ==== */
/* ==== WASM: 100 ==== */
{R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
@@ -34112,7 +34148,7 @@ std::map<std::string, std::vector<uint8_t>> wasm = {
0x0BU,
}},
/* ==== WASM: 100 ==== */
/* ==== WASM: 101 ==== */
{R"[test.hook](
#include <stdint.h>
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);

File diff suppressed because it is too large Load Diff

View File

@@ -1,351 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2024 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <test/jtx.h>
#include <xrpld/core/Job.h>
#include <xrpld/core/JobQueue.h>
#include <xrpld/net/RPCSub.h>
#include <xrpl/json/json_value.h>
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <atomic>
#include <chrono>
#include <memory>
#include <string>
#include <thread>
namespace ripple {
namespace test {
// Minimal HTTP endpoint that counts received webhook POSTs and replies
// with a configurable status. Responses are EOF-delimited (no
// Content-Length) and the socket is closed right after writing — the
// exact shape that triggered the original handleData EOF-completion
// leak. So these tests exercise RPCSub flow control AND the HTTPClient
// EOF fix end to end: if either regressed, delivery would stall and the
// expected count would never be reached within the timeout.
class MockWebhookEndpoint
{
boost::asio::io_service ios_;
std::unique_ptr<boost::asio::io_service::work> work_;
boost::asio::ip::tcp::acceptor acceptor_;
std::thread thread_;
unsigned short port_;
std::atomic<int> received_{0};
std::atomic<int> status_{200};
std::atomic<int> delayMs_{0};
public:
MockWebhookEndpoint()
: work_(std::make_unique<boost::asio::io_service::work>(ios_))
, acceptor_(
ios_,
boost::asio::ip::tcp::endpoint(
boost::asio::ip::address::from_string("127.0.0.1"),
0))
{
port_ = acceptor_.local_endpoint().port();
accept();
thread_ = std::thread([this] { ios_.run(); });
}
~MockWebhookEndpoint()
{
work_.reset();
boost::system::error_code ec;
acceptor_.close(ec);
ios_.stop();
if (thread_.joinable())
thread_.join();
}
unsigned short
port() const
{
return port_;
}
int
received() const
{
return received_;
}
void
setStatus(int s)
{
status_ = s;
}
// Delay each reply so delivery is deterministically slower than the
// microsecond-fast enqueue loop — keeps the deque full for the
// queue-cap drop test regardless of scheduling.
void
setResponseDelay(int ms)
{
delayMs_ = ms;
}
private:
void
accept()
{
auto sock = std::make_shared<boost::asio::ip::tcp::socket>(ios_);
acceptor_.async_accept(*sock, [this, sock](auto ec) {
if (ec)
return;
handle(sock);
accept();
});
}
void
handle(std::shared_ptr<boost::asio::ip::tcp::socket> sock)
{
auto buf = std::make_shared<boost::asio::streambuf>();
boost::asio::async_read_until(
*sock, *buf, "\r\n\r\n", [this, sock, buf](auto ec, std::size_t) {
if (ec)
return;
++received_;
auto const delay = delayMs_.load();
if (delay > 0)
{
auto timer =
std::make_shared<boost::asio::steady_timer>(ios_);
timer->expires_from_now(std::chrono::milliseconds(delay));
timer->async_wait(
[this, sock, timer](auto) { reply(sock); });
}
else
{
reply(sock);
}
});
}
void
reply(std::shared_ptr<boost::asio::ip::tcp::socket> sock)
{
// EOF-delimited reply: no Content-Length, close after writing.
// This is the realistic failing-webhook shape.
auto resp = std::make_shared<std::string>(
"HTTP/1.0 " + std::to_string(status_.load()) +
" Reply\r\n\r\n{\"result\":{}}");
boost::asio::async_write(
*sock, boost::asio::buffer(*resp), [sock, resp](auto, std::size_t) {
boost::system::error_code ig;
sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ig);
sock->close(ig);
});
}
};
//------------------------------------------------------------------------------
class RPCSub_test : public beast::unit_test::suite
{
// Generous ceiling: the instrumented Debug (coverage) build is much
// slower than Release, so timeouts are sized for that, not Release.
template <class Cond>
bool
waitFor(Cond cond, std::chrono::seconds timeout = std::chrono::seconds{30})
{
auto const deadline = std::chrono::steady_clock::now() + timeout;
while (!cond() && std::chrono::steady_clock::now() < deadline)
std::this_thread::sleep_for(std::chrono::milliseconds(10));
return cond();
}
std::shared_ptr<RPCSub>
makeSub(
jtx::Env& env,
MockWebhookEndpoint& ep,
std::size_t maxQueueSize = 16384)
{
return make_RPCSub(
env.app().getOPs(),
env.app().getJobQueue(),
"http://127.0.0.1:" + std::to_string(ep.port()) + "/",
"",
"",
env.app().logs(),
maxQueueSize);
}
// True once no RPCSub sending job is queued or running. sendThread
// captures a raw `this`, so the RPCSub must not be destroyed while a
// job is still in flight — wait on this before letting the sub die.
bool
sendingIdle(jtx::Env& env)
{
return env.app().getJobQueue().getJobCountTotal(jtCLIENT_SUBSCRIBE) ==
0;
}
// Wait for all events to reach the endpoint AND the sending job to
// finish, so the sub can be torn down without racing sendThread.
void
drainAndSettle(jtx::Env& env, MockWebhookEndpoint& ep, int expected)
{
bool const delivered =
waitFor([&] { return ep.received() >= expected; });
bool const idle = waitFor([&] { return sendingIdle(env); });
log << " drainAndSettle: received=" << ep.received() << "/" << expected
<< " idle=" << idle << std::endl;
BEAST_EXPECT(delivered);
BEAST_EXPECT(idle);
}
void
send(std::shared_ptr<RPCSub> const& sub, int n)
{
Json::Value ev(Json::objectValue);
ev["n"] = n;
sub->send(ev, false);
}
void
testDelivery()
{
testcase("Webhook events are delivered");
using namespace jtx;
Env env{*this};
MockWebhookEndpoint ep;
static constexpr int N = 10;
{
auto sub = makeSub(env, ep);
for (int i = 0; i < N; ++i)
send(sub, i);
drainAndSettle(env, ep, N);
}
BEAST_EXPECT(ep.received() == N);
}
void
testErrorsDoNotStall()
{
testcase("Delivery continues when endpoint returns HTTP 500");
// The original bug (xrpld #6341): an endpoint returning errors
// without Content-Length never completed, stalling delivery to
// ALL subscribers. Here every response is a 500 with no
// Content-Length (EOF-delimited) — all N must still arrive.
using namespace jtx;
Env env{*this};
MockWebhookEndpoint ep;
ep.setStatus(500);
static constexpr int N = 10;
{
auto sub = makeSub(env, ep);
for (int i = 0; i < N; ++i)
send(sub, i);
drainAndSettle(env, ep, N);
}
BEAST_EXPECT(ep.received() == N);
}
void
testRestartAfterDrain()
{
testcase("Sending restarts after the queue drains");
// After a batch drains, sendThread clears mSending and returns.
// A later send() must start a fresh sending job; if mSending were
// left set (the #6341 failure mode) the second burst would never
// be delivered.
using namespace jtx;
Env env{*this};
MockWebhookEndpoint ep;
{
auto sub = makeSub(env, ep);
// First burst, then wait for the sending job to fully drain
// and exit (mSending cleared) — deterministically, not via a
// sleep.
for (int i = 0; i < 5; ++i)
send(sub, i);
drainAndSettle(env, ep, 5);
// Second burst must start a fresh sending job.
for (int i = 5; i < 10; ++i)
send(sub, i);
drainAndSettle(env, ep, 10);
}
BEAST_EXPECT(ep.received() == 10);
}
void
testQueueCapDrops()
{
testcase("Events past the queue cap are dropped");
// With a tiny cap, pushing far more events than delivery can keep
// up with forces send() down the drop path: enqueue is microsecond
// -fast while each (delayed) HTTP delivery is a full round-trip, so
// the deque sits at the cap and excess events are dropped. The
// delay makes "delivery slower than enqueue" hold regardless of
// scheduling, so this isn't timing-dependent. We just need some
// delivered (cap works) and some dropped (drop path exercised).
using namespace jtx;
Env env{*this};
MockWebhookEndpoint ep;
ep.setResponseDelay(50);
static constexpr int pushed = 50;
{
auto sub = makeSub(env, ep, /*maxQueueSize*/ 2);
for (int i = 0; i < pushed; ++i)
send(sub, i);
BEAST_EXPECT(waitFor([&] { return sendingIdle(env); }));
}
log << " queue cap: received " << ep.received() << "/" << pushed
<< std::endl;
BEAST_EXPECT(ep.received() > 0);
BEAST_EXPECT(ep.received() < pushed);
}
public:
void
run() override
{
testDelivery();
testErrorsDoNotStall();
testRestartAfterDrain();
testQueueCapDrops();
}
};
BEAST_DEFINE_TESTSUITE(RPCSub, net, ripple);
} // namespace test
} // namespace ripple

View File

@@ -22,6 +22,7 @@
#include <xrpld/core/JobQueue.h>
#include <xrpld/net/InfoSub.h>
#include <boost/asio/io_service.hpp>
namespace ripple {
@@ -38,17 +39,16 @@ protected:
explicit RPCSub(InfoSub::Source& source);
};
// VFALCO Why is the io_service needed?
std::shared_ptr<RPCSub>
make_RPCSub(
InfoSub::Source& source,
boost::asio::io_service& io_service,
JobQueue& jobQueue,
std::string const& strUrl,
std::string const& strUsername,
std::string const& strPassword,
Logs& logs,
// Max events buffered before new ones are dropped. Configurable so
// tests can exercise the drop path without queueing the full default.
std::size_t maxQueueSize = 16384);
Logs& logs);
} // namespace ripple

View File

@@ -122,20 +122,12 @@ public:
mComplete = complete;
mTimeout = timeout;
// Bind a non-owning `this` (not shared_from_this()) into mBuild.
// mBuild is a member, so capturing a shared_ptr to self here would
// form a reference cycle (this -> mBuild -> shared_ptr<this>) that
// never breaks, leaking the object and its socket FD after the
// request completes. mBuild is only ever invoked from
// handleRequest(), which always runs inside an async handler that
// already holds a shared_from_this(), so the object is guaranteed
// alive whenever mBuild fires — a raw `this` is safe.
request(
bSSL,
deqSites,
std::bind(
&HTTPClientImp::makeGet,
this,
shared_from_this(),
strPath,
std::placeholders::_1,
std::placeholders::_2),
@@ -401,12 +393,8 @@ public:
if (boost::regex_match(strHeader, smMatch, reBody)) // we got some body
mBody = smMatch[1];
bool const hasContentLength =
boost::regex_match(strHeader, smMatch, reSize);
mReceivedContentLength = hasContentLength;
std::size_t const responseSize = [&] {
if (hasContentLength)
if (boost::regex_match(strHeader, smMatch, reSize))
return beast::lexicalCast<std::size_t>(
std::string(smMatch[1]), maxResponseSize_);
return maxResponseSize_;
@@ -457,24 +445,22 @@ public:
JLOG(j_.trace()) << "Read error: " << mShutdown.message();
invokeComplete(mShutdown);
return;
}
// Either the read completed normally or it ended at EOF. EOF is a
// successful completion for EOF-delimited responses, but it is an
// error when the server promised a Content-Length and closed early.
JLOG(j_.trace()) << "Complete.";
mResponse.commit(bytes_transferred);
std::string strBody{
{std::istreambuf_iterator<char>(&mResponse)},
std::istreambuf_iterator<char>()};
auto completeEc = ecResult;
if (completeEc == boost::asio::error::eof && !mReceivedContentLength)
completeEc.clear();
invokeComplete(completeEc, mStatus, mBody + strBody);
else
{
if (mShutdown)
{
JLOG(j_.trace()) << "Complete.";
}
else
{
mResponse.commit(bytes_transferred);
std::string strBody{
{std::istreambuf_iterator<char>(&mResponse)},
std::istreambuf_iterator<char>()};
invokeComplete(ecResult, mStatus, mBody + strBody);
}
}
}
// Call cancel the deadline timer and invoke the completion routine.
@@ -530,7 +516,6 @@ private:
boost::asio::streambuf mHeader;
boost::asio::streambuf mResponse;
std::string mBody;
bool mReceivedContentLength = false;
const unsigned short mPort;
std::size_t const maxResponseSize_;
int mStatus;

View File

@@ -1585,10 +1585,6 @@ struct RPCCallImp
// callbackFuncP.
// Receive reply
if (ecResult)
Throw<std::runtime_error>(
"RPC transport error: " + ecResult.message());
if (strData.empty())
Throw<std::runtime_error>(
"no response from server. Please "
@@ -1752,7 +1748,6 @@ rpcClient(
}
{
//@@start blocking-request
boost::asio::io_service isService;
RPCCall::fromNetwork(
isService,
@@ -1776,7 +1771,6 @@ rpcClient(
headers);
isService.run(); // This blocks until there are no more
// outstanding async calls.
//@@end blocking-request
}
if (jvOutput.isMember("result"))
{
@@ -1887,21 +1881,15 @@ fromNetwork(
// Send request
// Number of bytes to try to receive if no Content-Length header is
// received. Webhook event deliveries ("event") ignore the response
// body, so a missing Content-Length must not pre-allocate the full
// 256MB RPC reply budget per in-flight delivery (maxInFlight can be
// 32 -> 8GB). Cap those small; genuine RPC replies (CLI) keep the
// large budget.
auto const RPC_REPLY_MAX_BYTES =
(strMethod == "event") ? megabytes(1) : megabytes(256);
// Number of bytes to try to receive if no
// Content-Length header received
constexpr auto RPC_REPLY_MAX_BYTES = megabytes(256);
using namespace std::chrono_literals;
// auto constexpr RPC_NOTIFY = 10min; // Wietse: lolwut 10 minutes for one
// HTTP call?
auto constexpr RPC_NOTIFY = 30s;
//@@start async-request
HTTPClient::request(
bSSL,
io_service,
@@ -1926,7 +1914,6 @@ fromNetwork(
std::placeholders::_3,
j),
j);
//@@end async-request
}
} // namespace RPCCall

View File

@@ -24,30 +24,29 @@
#include <xrpl/basics/contract.h>
#include <xrpl/json/to_string.h>
#include <deque>
#include <memory>
namespace ripple {
// Subscription object for JSON-RPC
class RPCSubImp : public RPCSub, public std::enable_shared_from_this<RPCSubImp>
class RPCSubImp : public RPCSub
{
public:
RPCSubImp(
InfoSub::Source& source,
boost::asio::io_service& io_service,
JobQueue& jobQueue,
std::string const& strUrl,
std::string const& strUsername,
std::string const& strPassword,
Logs& logs,
std::size_t maxQueueSize)
Logs& logs)
: RPCSub(source)
, m_io_service(io_service)
, m_jobQueue(jobQueue)
, mUrl(strUrl)
, mSSL(false)
, mUsername(strUsername)
, mPassword(strPassword)
, mSending(false)
, maxQueueSize_(maxQueueSize)
, j_(logs.journal("RPCSub"))
, logs_(logs)
{
@@ -79,26 +78,14 @@ public:
{
std::lock_guard sl(mLock);
if (mDeque.size() >= maxQueueSize_)
{
// Always advance mSeq so consumers can detect the gap, but
// rate-limit the log: a hopelessly behind endpoint drops on
// every send() and would otherwise flood the log. Warn on
// the first drop of a run and then once per dropLogInterval.
if (mDropped++ % dropLogInterval == 0)
{
JLOG(j_.warn())
<< "RPCCall::fromNetwork drop: queue full ("
<< mDeque.size() << "), seq=" << mSeq
<< ", endpoint=" << mIp << ", dropped=" << mDropped;
}
++mSeq;
return;
}
// Endpoint caught up enough to accept again; reset so the next
// overflow burst logs its first drop immediately.
mDropped = 0;
// Wietse: we're not going to limit this, this is admin-port only, scale
// accordingly Dropping events just like this results in inconsistent
// data on the receiving end if (mDeque.size() >= eventQueueMax)
// {
// // Drop the previous event.
// JLOG(j_.warn()) << "RPCCall::fromNetwork drop";
// mDeque.pop_back();
// }
auto jm = broadcast ? j_.debug() : j_.info();
JLOG(jm) << "RPCCall::fromNetwork push: " << jvObj;
@@ -110,7 +97,10 @@ public:
// Start a sending thread.
JLOG(j_.info()) << "RPCCall::fromNetwork start";
startSendingJob();
mSending = m_jobQueue.addJob(
jtCLIENT_SUBSCRIBE, "RPCSub::sendThread", [this]() {
sendThread();
});
}
}
@@ -131,66 +121,48 @@ public:
}
private:
// Maximum concurrent HTTP deliveries per batch. Bounds file
// descriptor usage while still allowing parallel delivery to
// capable endpoints. With a 1024 FD process limit shared across
// peers, clients, and the node store, 32 per subscriber is a
// meaningful but survivable chunk even with multiple subscribers.
static constexpr int maxInFlight = 32;
// Log one drop warning per this many drops while the queue stays
// full, to avoid flooding the log on a persistently behind endpoint.
static constexpr std::size_t dropLogInterval = 1000;
// Schedule a sending job. Must be called under mLock. The job holds a
// weak_ptr and re-locks it on entry, so the RPCSub is kept alive for
// the duration of the batch even if it is unsubscribed (and would
// otherwise be destroyed) concurrently — sendThread dereferences this
// only via that strong ref. mDeque events are delivered until the sub
// is gone, after which weak.lock() fails and the job is a no-op.
void
startSendingJob()
{
std::weak_ptr<RPCSubImp> weak = weak_from_this();
mSending = m_jobQueue.addJob(
jtCLIENT_SUBSCRIBE, "RPCSub::sendThread", [weak]() {
if (auto self = weak.lock())
self->sendThread();
});
}
// XXX Could probably create a bunch of send jobs in a single get of the
// lock.
void
sendThread()
{
// Process exactly ONE batch per job, then re-queue if more events
// remain, rather than draining the whole backlog in a single job.
// A local io_service's .run() blocks this worker thread for the
// batch (up to the per-request timeout), so re-queueing between
// batches keeps one slow/hung subscriber from monopolising a
// job-queue worker and starving consensus/ledger/RPC work.
//
// mSending must be cleared under the lock on every non-requeue
// exit path; if it ever stays set without a job in flight, send()
// sees mSending == true and never restarts us, stalling the queue
// forever — the original bug (xrpld issue #6341).
boost::asio::io_service io_service;
int dispatched = 0;
Json::Value jvEvent;
bool bSend;
try
do
{
{
// Obtain the lock to manipulate the queue and change sending.
std::lock_guard sl(mLock);
while (!mDeque.empty() && dispatched < maxInFlight)
if (mDeque.empty())
{
mSending = false;
bSend = false;
}
else
{
auto const [seq, env] = mDeque.front();
mDeque.pop_front();
Json::Value jvEvent = env;
jvEvent = env;
jvEvent["seq"] = seq;
bSend = true;
}
}
// Send outside of the lock.
if (bSend)
{
// XXX Might not need this in a try.
try
{
JLOG(j_.info()) << "RPCCall::fromNetwork: " << mIp;
RPCCall::fromNetwork(
io_service,
m_io_service,
mIp,
mPort,
mUsername,
@@ -201,51 +173,21 @@ private:
mSSL,
true,
logs_);
++dispatched;
}
catch (const std::exception& e)
{
JLOG(j_.info())
<< "RPCCall::fromNetwork exception: " << e.what();
}
}
// dispatched is always > 0 here (send() only starts a job
// after enqueuing, and the re-queue below only fires with a
// non-empty deque), but guard anyway so an empty batch can't
// log/spin — it falls straight through to clear mSending.
if (dispatched > 0)
{
JLOG(j_.info()) << "RPCCall::fromNetwork: " << mIp
<< " dispatching " << dispatched << " events";
io_service.run();
}
}
catch (std::exception const& e)
{
// Bail rather than re-queue: a persistently failing endpoint
// would otherwise spin the job queue. mSending is reset so the
// next send() restarts delivery.
JLOG(j_.warn()) << "RPCSub::sendThread exception: " << e.what();
std::lock_guard sl(mLock);
mSending = false;
return;
}
catch (...)
{
JLOG(j_.warn()) << "RPCSub::sendThread unknown exception";
std::lock_guard sl(mLock);
mSending = false;
return;
}
// Batch complete: re-queue for the next one (mSending stays set)
// or clear mSending if the queue drained — both under the lock to
// avoid a lost-wakeup race with send().
std::lock_guard sl(mLock);
if (mDeque.empty())
mSending = false;
else
startSendingJob();
} while (bSend);
}
private:
// Wietse: we're not going to limit this, this is admin-port only, scale
// accordingly enum { eventQueueMax = 32 };
boost::asio::io_service& m_io_service;
JobQueue& m_jobQueue;
std::string mUrl;
@@ -258,15 +200,8 @@ private:
int mSeq; // Next id to allocate.
std::size_t mDropped = 0; // Consecutive drops while queue is full.
bool mSending; // Sending threead is active.
// Maximum queued events before dropping. The default (16384) is a
// ~10-minute buffer at 100+ events/ledger; a hopelessly behind
// endpoint trips it and consumers detect the gap via the seq field.
std::size_t const maxQueueSize_;
std::deque<std::pair<int, Json::Value>> mDeque;
beast::Journal const j_;
@@ -282,21 +217,21 @@ RPCSub::RPCSub(InfoSub::Source& source) : InfoSub(source, Consumer())
std::shared_ptr<RPCSub>
make_RPCSub(
InfoSub::Source& source,
boost::asio::io_service& io_service,
JobQueue& jobQueue,
std::string const& strUrl,
std::string const& strUsername,
std::string const& strPassword,
Logs& logs,
std::size_t maxQueueSize)
Logs& logs)
{
return std::make_shared<RPCSubImp>(
std::ref(source),
std::ref(io_service),
std::ref(jobQueue),
strUrl,
strUsername,
strPassword,
logs,
maxQueueSize);
logs);
}
} // namespace ripple

View File

@@ -76,6 +76,7 @@ doSubscribe(RPC::JsonContext& context)
{
auto rspSub = make_RPCSub(
context.app.getOPs(),
context.app.getIOService(),
context.app.getJobQueue(),
strUrl,
strUsername,