diff --git a/src/ripple/app/hook/HookAPI.h b/src/ripple/app/hook/HookAPI.h index 04c534dd6..d9b8e19d2 100644 --- a/src/ripple/app/hook/HookAPI.h +++ b/src/ripple/app/hook/HookAPI.h @@ -1,9 +1,4 @@ -// A decoupled Hook host API helper for programmatic use and testing. -// Provides selected Hook APIs (emit-related and dependencies) without any -// dependency on WASM memory. It operates directly on ripple types. - -#pragma once - +#include #include #include #include @@ -14,6 +9,8 @@ #include namespace hook { +using namespace ripple; +using HookReturnCode = hook_api::hook_return_code; struct HookContext; // defined in applyHook.h @@ -26,21 +23,21 @@ public: // Emit a transaction from the running hook. On success, returns 32-byte // transaction ID bytes (same content written by the wasm host function). - ripple::Expected, std::int64_t> - emit(ripple::Slice txBlob); + Expected, HookReturnCode> + emit(Slice txBlob); // Dependencies (public so callers can compose): // etxn_generation == otxn_generation() + 1 - std::int64_t + uint32_t etxn_generation() const; - std::int64_t + Expected etxn_burden() const; - std::int64_t - etxn_fee_base(ripple::Slice txBlob) const; + Expected + etxn_fee_base(Slice txBlob) const; - std::int64_t + uint32_t otxn_generation() const; - std::int64_t + uint64_t otxn_burden() const; private: diff --git a/src/ripple/app/hook/impl/HookAPI.cpp b/src/ripple/app/hook/impl/HookAPI.cpp index d0a80352c..739a3ed2a 100644 --- a/src/ripple/app/hook/impl/HookAPI.cpp +++ b/src/ripple/app/hook/impl/HookAPI.cpp @@ -16,7 +16,7 @@ namespace hook { using namespace ripple; -std::int64_t +uint64_t HookAPI::otxn_burden() const { auto& applyCtx = hookCtx.applyCtx; @@ -41,13 +41,13 @@ HookAPI::otxn_burden() const return 1; } - std::uint64_t burden = pd.getFieldU64(sfEmitBurden); + uint64_t burden = pd.getFieldU64(sfEmitBurden); burden &= ((1ULL << 63) - 1); hookCtx.burden = burden; - return static_cast(burden); + return static_cast(burden); } -std::int64_t +uint32_t HookAPI::otxn_generation() const { auto& applyCtx = hookCtx.applyCtx; @@ -76,34 +76,34 @@ HookAPI::otxn_generation() const return hookCtx.generation; } -std::int64_t +uint32_t HookAPI::etxn_generation() const { return otxn_generation() + 1; } -std::int64_t +Expected HookAPI::etxn_burden() const { if (hookCtx.expected_etxn_count <= -1) - return hook_api::PREREQUISITE_NOT_MET; + return Unexpected(hook_api::PREREQUISITE_NOT_MET); - std::uint64_t last_burden = static_cast(otxn_burden()); - std::uint64_t burden = - last_burden * static_cast(hookCtx.expected_etxn_count); + uint64_t last_burden = static_cast(otxn_burden()); + uint64_t burden = + last_burden * static_cast(hookCtx.expected_etxn_count); if (burden < last_burden) - return hook_api::FEE_TOO_LARGE; - return static_cast(burden); + return Unexpected(hook_api::FEE_TOO_LARGE); + return burden; } -std::int64_t +Expected HookAPI::etxn_fee_base(ripple::Slice txBlob) const { auto& applyCtx = hookCtx.applyCtx; auto j = applyCtx.app.journal("View"); if (hookCtx.expected_etxn_count <= -1) - return hook_api::PREREQUISITE_NOT_MET; + return Unexpected(hook_api::PREREQUISITE_NOT_MET); try { @@ -118,11 +118,11 @@ HookAPI::etxn_fee_base(ripple::Slice txBlob) const { JLOG(j.trace()) << "HookInfo[" << HC_ACC() << "]: etxn_fee_base exception: " << e.what(); - return hook_api::INVALID_TXN; + return Unexpected(hook_api::INVALID_TXN); } } -ripple::Expected, std::int64_t> +Expected, HookReturnCode> HookAPI::emit(ripple::Slice txBlob) { auto& applyCtx = hookCtx.applyCtx; @@ -130,10 +130,10 @@ HookAPI::emit(ripple::Slice txBlob) auto& view = applyCtx.view(); if (hookCtx.expected_etxn_count < 0) - return ripple::Unexpected(hook_api::PREREQUISITE_NOT_MET); + return Unexpected(hook_api::PREREQUISITE_NOT_MET); if (hookCtx.result.emittedTxn.size() >= hookCtx.expected_etxn_count) - return ripple::Unexpected(hook_api::TOO_MANY_EMITTED_TXN); + return Unexpected(hook_api::TOO_MANY_EMITTED_TXN); std::shared_ptr stpTrans; try @@ -144,14 +144,14 @@ HookAPI::emit(ripple::Slice txBlob) catch (std::exception const& e) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: Failed " << e.what(); - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } if (isPseudoTx(*stpTrans)) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: Attempted to emit pseudo txn."; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } ripple::TxType txType = stpTrans->getTxnType(); @@ -161,7 +161,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: Hook cannot emit this txn."; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // check the emitted txn is valid @@ -184,7 +184,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfAccount does not match hook account"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // rule 1: sfSequence must be present and 0 @@ -193,7 +193,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfSequence missing or non-zero"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // rule 2: sfSigningPubKey must be present and 00...00 @@ -201,7 +201,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfSigningPubKey missing"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } auto const pk = stpTrans->getSigningPubKey(); @@ -209,7 +209,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfSigningPubKey present but wrong size"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } for (int i = 0; i < pk.size(); ++i) @@ -217,7 +217,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfSigningPubKey present but non-zero."; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // rule 2.a: no signers @@ -225,7 +225,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfSigners not allowed in emitted txns."; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // rule 2.b: ticketseq cannot be used @@ -233,7 +233,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfTicketSequence not allowed in emitted txns."; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // rule 2.c sfAccountTxnID not allowed @@ -241,7 +241,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfAccountTxnID not allowed in emitted txns."; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // rule 3: sfEmitDetails must be present and valid @@ -249,7 +249,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfEmitDetails missing."; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } auto const& emitDetails = const_cast(*stpTrans) @@ -264,7 +264,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfEmitDetails malformed."; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // rule 8: emit generation cannot exceed 10 @@ -272,7 +272,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfEmitGeneration was 10 or more."; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } auto const gen = emitDetails.getFieldU32(sfEmitGeneration); @@ -286,7 +286,7 @@ HookAPI::emit(ripple::Slice txBlob) auto const& hash = emitDetails.getFieldH256(sfEmitHookHash); - std::uint32_t gen_proper = static_cast(etxn_generation()); + uint32_t gen_proper = static_cast(etxn_generation()); if (gen != gen_proper) { @@ -294,17 +294,17 @@ HookAPI::emit(ripple::Slice txBlob) << "]: sfEmitGeneration provided in EmitDetails " << "not correct (" << gen << ") " << "should be " << gen_proper; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } - std::uint64_t bur_proper = static_cast(etxn_burden()); + uint64_t bur_proper = static_cast(etxn_burden().value()); if (bur != bur_proper) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfEmitBurden provided in EmitDetails " << "was not correct (" << bur << ") " << "should be " << bur_proper; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } if (pTxnID != applyCtx.tx.getTransactionID()) @@ -312,7 +312,7 @@ HookAPI::emit(ripple::Slice txBlob) JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfEmitParentTxnID provided in EmitDetails" << "was not correct"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } if (hookCtx.nonce_used.find(nonce) == hookCtx.nonce_used.end()) @@ -320,7 +320,7 @@ HookAPI::emit(ripple::Slice txBlob) JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfEmitNonce provided in EmitDetails was not " "generated by nonce api"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } if (callback && *callback != hookCtx.result.account) @@ -328,7 +328,7 @@ HookAPI::emit(ripple::Slice txBlob) JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfEmitCallback account must be the account of " "the emitting hook"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } if (hash != hookCtx.result.hookHash) @@ -336,7 +336,7 @@ HookAPI::emit(ripple::Slice txBlob) JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfEmitHookHash must be the hash of the emitting hook"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // rule 4: sfTxnSignature must be absent @@ -344,7 +344,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfTxnSignature is present but should not be"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // rule 5: LastLedgerSeq must be present and after current ledger @@ -352,17 +352,17 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfLastLedgerSequence missing"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } - std::uint32_t tx_lls = stpTrans->getFieldU32(sfLastLedgerSequence); - std::uint32_t ledgerSeq = view.info().seq; + uint32_t tx_lls = stpTrans->getFieldU32(sfLastLedgerSequence); + uint32_t ledgerSeq = view.info().seq; if (tx_lls < ledgerSeq + 1) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfLastLedgerSequence invalid (less than next ledger)"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } if (tx_lls > ledgerSeq + 5) @@ -370,7 +370,7 @@ HookAPI::emit(ripple::Slice txBlob) JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfLastLedgerSequence cannot be greater than current seq + 5"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // rule 6 @@ -380,32 +380,32 @@ HookAPI::emit(ripple::Slice txBlob) JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: sfFirstLedgerSequence must be present and <= " "LastLedgerSequence"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // rule 7 check the emitted txn pays the appropriate fee - std::int64_t minfee = etxn_fee_base(txBlob); + int64_t minfee = etxn_fee_base(txBlob).value(); if (minfee < 0) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: Fee could not be calculated"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } if (!stpTrans->isFieldPresent(sfFee)) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: Fee missing from emitted tx"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } - std::int64_t fee = stpTrans->getFieldAmount(sfFee).xrp().drops(); + int64_t fee = stpTrans->getFieldAmount(sfFee).xrp().drops(); if (fee < minfee) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: Fee less than minimum required"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } std::string reason; @@ -415,7 +415,7 @@ HookAPI::emit(ripple::Slice txBlob) { JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: tpTrans->getStatus() != NEW"; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } // preflight the transaction @@ -431,7 +431,7 @@ HookAPI::emit(ripple::Slice txBlob) JLOG(j.trace()) << "HookEmit[" << HC_ACC() << "]: Transaction preflight failure: " << preflightResult.ter; - return ripple::Unexpected(hook_api::EMISSION_FAILURE); + return Unexpected(hook_api::EMISSION_FAILURE); } return tpTrans; diff --git a/src/ripple/app/hook/impl/applyHook.cpp b/src/ripple/app/hook/impl/applyHook.cpp index e619b0a69..7790744fe 100644 --- a/src/ripple/app/hook/impl/applyHook.cpp +++ b/src/ripple/app/hook/impl/applyHook.cpp @@ -3490,7 +3490,10 @@ DEFINE_HOOK_FUNCNARG(int64_t, etxn_burden) { HOOK_SETUP(); hook::HookAPI api(hookCtx); - return api.etxn_burden(); + auto const burden = api.etxn_burden(); + if (!burden) + return burden.error(); + return burden.value(); HOOK_TEARDOWN(); } @@ -4280,7 +4283,10 @@ DEFINE_HOOK_FUNCTION( hook::HookAPI api(hookCtx); ripple::Slice tx{ reinterpret_cast(read_ptr + memory), read_len}; - return api.etxn_fee_base(tx); + auto const fee_base = api.etxn_fee_base(tx); + if (!fee_base) + return fee_base.error(); + return fee_base.value(); HOOK_TEARDOWN(); } diff --git a/src/ripple/basics/Expected.h b/src/ripple/basics/Expected.h index bb699579b..b919e9fd6 100644 --- a/src/ripple/basics/Expected.h +++ b/src/ripple/basics/Expected.h @@ -137,14 +137,14 @@ class [[nodiscard]] Expected public: template requires std::convertible_to constexpr Expected(U && r) - : Base(T(std::forward(r))) + : Base(boost::outcome_v2::success(T(std::forward(r)))) { } template requires std::convertible_to && (!std::is_reference_v)constexpr Expected(Unexpected e) - : Base(E(std::move(e.value()))) + : Base(boost::outcome_v2::failure(E(std::move(e.value())))) { } @@ -220,7 +220,7 @@ public: template requires std::convertible_to && (!std::is_reference_v)constexpr Expected(Unexpected e) - : Base(E(std::move(e.value()))) + : Base(boost::outcome_v2::failure(E(std::move(e.value())))) { }