From 5dc214ab48487447d41b4b97c9b18f971d08cb42 Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Fri, 26 Jun 2026 20:20:09 +0700 Subject: [PATCH] fix(hooks): report exports separately from emits --- src/test/app/Export_test.cpp | 12 +++++++----- src/xrpld/app/hook/detail/applyHook.cpp | 8 ++++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/test/app/Export_test.cpp b/src/test/app/Export_test.cpp index 7bc7b2c72..313150414 100644 --- a/src/test/app/Export_test.cpp +++ b/src/test/app/Export_test.cpp @@ -485,7 +485,7 @@ struct Export_test : public beast::unit_test::suite json(jss::HookParameters, params), ter(tesSUCCESS)); - // Verify hook fired successfully with exactly 1 emission. + // Verify hook fired successfully with exactly 1 export. { auto const m = env.meta(); BEAST_EXPECT(m); @@ -496,12 +496,14 @@ struct Export_test : public beast::unit_test::suite // result=3 is ExitType::ACCEPT BEAST_EXPECT(execs[0].getFieldU8(sfHookResult) == 3); - BEAST_EXPECT(execs[0].getFieldU16(sfHookEmitCount) == 1); + BEAST_EXPECT(execs[0].getFieldU16(sfHookEmitCount) == 0); + BEAST_EXPECT(execs[0].getFieldU16(sfHookExportCount) == 1); BEAST_EXPECT(execs[0].getFieldU64(sfHookReturnCode) == 0); - // Emissions metadata should be present. - BEAST_EXPECT(m->isFieldPresent(sfHookEmissions)); - BEAST_EXPECT(m->getFieldArray(sfHookEmissions).size() == 1); + // HookEmissions tracks normal emitted transactions. Export wrappers + // use the emitted directory for scheduling but are counted + // separately as HookExportCount. + BEAST_EXPECT(!m->isFieldPresent(sfHookEmissions)); // The emitted dir should NOT be empty (ttEXPORT is in it). BEAST_EXPECT(!dirIsEmpty(*env.current(), keylet::emittedDir())); diff --git a/src/xrpld/app/hook/detail/applyHook.cpp b/src/xrpld/app/hook/detail/applyHook.cpp index 5ac36398f..da582d376 100644 --- a/src/xrpld/app/hook/detail/applyHook.cpp +++ b/src/xrpld/app/hook/detail/applyHook.cpp @@ -1533,8 +1533,12 @@ hook::finalizeHookResult( .getField(sfEmitDetails) .downcast(); - emission_txnid.emplace_back( - id, emitDetails.getFieldH256(sfEmitNonce)); + if (ptr->getTxnType() == ttEXPORT) + exported_txnid.emplace_back(id); + else + emission_txnid.emplace_back( + id, emitDetails.getFieldH256(sfEmitNonce)); + sleEmitted = std::make_shared(emittedId); // RH TODO: add a new constructor to STObject to avoid this