diff --git a/src/xrpld/app/hook/HookAPI.h b/src/xrpld/app/hook/HookAPI.h index 91c23e091..08d18fdfb 100644 --- a/src/xrpld/app/hook/HookAPI.h +++ b/src/xrpld/app/hook/HookAPI.h @@ -82,6 +82,13 @@ public: Expected etxn_nonce() const; + /// xport APIs + Expected + xport_reserve(uint64_t count) const; + + Expected, HookReturnCode> + xport(Slice const& txBlob) const; + /// float APIs Expected float_set(int32_t exponent, int64_t mantissa) const; diff --git a/src/xrpld/app/hook/detail/HookAPI.cpp b/src/xrpld/app/hook/detail/HookAPI.cpp index f8dcd7602..e1ce3c339 100644 --- a/src/xrpld/app/hook/detail/HookAPI.cpp +++ b/src/xrpld/app/hook/detail/HookAPI.cpp @@ -1223,6 +1223,70 @@ HookAPI::etxn_reserve(uint64_t count) const return count; } +Expected +HookAPI::xport_reserve(uint64_t count) const +{ + if (hookCtx.expected_export_count > -1) + return Unexpected(ALREADY_SET); + + if (count < 1) + return Unexpected(TOO_SMALL); + + if (count > hook_api::max_export) + return Unexpected(TOO_BIG); + + hookCtx.expected_export_count = count; + + return count; +} + +Expected, HookReturnCode> +HookAPI::xport(Slice const& txBlob) const +{ + auto& app = hookCtx.applyCtx.app; + auto j = app.journal("View"); + + if (hookCtx.expected_export_count < 0) + return Unexpected(PREREQUISITE_NOT_MET); + + if (hookCtx.result.exportedTxn.size() >= hookCtx.expected_export_count) + return Unexpected(TOO_MANY_EXPORTED_TXN); + + std::shared_ptr stpTrans; + try + { + SerialIter sit(txBlob); + stpTrans = std::make_shared(sit); + } + catch (std::exception const& e) + { + JLOG(j.trace()) << "HookExport[" << HC_ACC() << "]: Failed " + << e.what(); + return Unexpected(EXPORT_FAILURE); + } + + if (!stpTrans->isFieldPresent(sfAccount) || + stpTrans->getAccountID(sfAccount) != hookCtx.result.account) + { + JLOG(j.trace()) << "HookExport[" << HC_ACC() + << "]: Attempted to export a txn that's not for this " + "Hook's Account ID."; + return Unexpected(EXPORT_FAILURE); + } + + std::string reason; + auto tpTrans = std::make_shared(stpTrans, reason, app); + // RHTODO: is this needed or wise? VVV + if (tpTrans->getStatus() != NEW) + { + JLOG(j.trace()) << "HookExport[" << HC_ACC() + << "]: tpTrans->getStatus() != NEW"; + return Unexpected(EXPORT_FAILURE); + } + + return tpTrans; +} + uint32_t HookAPI::etxn_generation() const { diff --git a/src/xrpld/app/hook/detail/applyHook.cpp b/src/xrpld/app/hook/detail/applyHook.cpp index 0a630ab24..09ba76919 100644 --- a/src/xrpld/app/hook/detail/applyHook.cpp +++ b/src/xrpld/app/hook/detail/applyHook.cpp @@ -3096,18 +3096,10 @@ DEFINE_HOOK_FUNCTION(int64_t, xport_reserve, uint32_t count) HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx, // hookCtx on current stack - if (hookCtx.expected_export_count > -1) - return ALREADY_SET; - - if (count < 1) - return TOO_SMALL; - - if (count > hook_api::max_export) - return TOO_BIG; - - hookCtx.expected_export_count = count; - - return count; + auto const result = api.xport_reserve(count); + if (!result) + return result.error(); + return result.value(); HOOK_TEARDOWN(); } @@ -4196,47 +4188,16 @@ DEFINE_HOOK_FUNCTION( if (write_len < 32) return TOO_SMALL; - auto& app = hookCtx.applyCtx.app; + // Delegate to decoupled HookAPI for xport logic + ripple::Slice txBlob{ + reinterpret_cast(memory + read_ptr), read_len}; - if (hookCtx.expected_export_count < 0) - return PREREQUISITE_NOT_MET; + auto const res = api.xport(txBlob); - if (hookCtx.result.exportedTxn.size() >= hookCtx.expected_export_count) - return TOO_MANY_EXPORTED_TXN; + if (!res) + return res.error(); - ripple::Blob blob{memory + read_ptr, memory + read_ptr + read_len}; - - std::shared_ptr stpTrans; - try - { - stpTrans = std::make_shared( - SerialIter{memory + read_ptr, read_len}); - } - catch (std::exception& e) - { - JLOG(j.trace()) << "HookExport[" << HC_ACC() << "]: Failed " << e.what() - << "\n"; - return EXPORT_FAILURE; - } - - if (!stpTrans->isFieldPresent(sfAccount) || - stpTrans->getAccountID(sfAccount) != hookCtx.result.account) - { - JLOG(j.trace()) << "HookExport[" << HC_ACC() - << "]: Attempted to export a txn that's not for this " - "Hook's Account ID."; - return EXPORT_FAILURE; - } - - std::string reason; - auto tpTrans = std::make_shared(stpTrans, reason, app); - // RHTODO: is this needed or wise? VVV - if (tpTrans->getStatus() != NEW) - { - JLOG(j.trace()) << "HookExport[" << HC_ACC() - << "]: tpTrans->getStatus() != NEW"; - return EXPORT_FAILURE; - } + auto const& tpTrans = *res; auto const& txID = tpTrans->getID(); if (txID.size() > write_len)