From ee539fdea7f519c361b2ad49cb92d0fa72fd41bf Mon Sep 17 00:00:00 2001 From: Richard Holland Date: Mon, 21 Mar 2022 10:17:26 +0000 Subject: [PATCH] fix fee rpc to allow tx_blob --- hook-api-examples/accept/pay.js | 4 +- hookstests/hookset/utils-tests.js | 23 +++++- src/ripple/app/misc/TxQ.h | 2 +- src/ripple/app/misc/impl/TxQ.cpp | 4 +- src/ripple/app/tx/impl/applyHook.cpp | 6 +- src/ripple/rpc/handlers/Fee1.cpp | 107 +++++++++++++++------------ 6 files changed, 89 insertions(+), 57 deletions(-) diff --git a/hook-api-examples/accept/pay.js b/hook-api-examples/accept/pay.js index 3cfe9aed7..e867fd63f 100644 --- a/hook-api-examples/accept/pay.js +++ b/hook-api-examples/accept/pay.js @@ -6,8 +6,8 @@ if (process.argv.length < 5) const secret = process.argv[2]; const amount = BigInt(process.argv[3]) * 1000000n const dest = process.argv[4]; - -require('../utils-tests.js').TestRig('ws://localhost:6005').then(t=> +const server = 'ws://tn4:6005' +require('../utils-tests.js').TestRig(server).then(t=> { t.pay(secret, amount, dest).then(x=> { diff --git a/hookstests/hookset/utils-tests.js b/hookstests/hookset/utils-tests.js index f2b5c2ea5..ec5a2471c 100644 --- a/hookstests/hookset/utils-tests.js +++ b/hookstests/hookset/utils-tests.js @@ -48,6 +48,26 @@ module.exports = { console.log(acc) return acc }; + + const pay = (seed, amt, dest) => + { + return new Promise((resolve, reject) => + { + let wal = xrpljs.Wallet.fromSeed(seed); + + api.submit({ + Account: wal.classicAddress, + TransactionType: "Payment", + Amount: ''+amt, + Destination: dest, + Fee: "10000" + }, {wallet: wal}).then(x=> + { + assertTxnSuccess(x); + resolve(x); + }).catch(err); + }); + }; const hookHash = fn => { @@ -93,7 +113,8 @@ module.exports = { hsfNSDELETE: 2, hfsOVERRIDE: 1, hfsNSDELETE: 2, - hookHash: hookHash + hookHash: hookHash, + pay: pay }); }).catch(err); }); diff --git a/src/ripple/app/misc/TxQ.h b/src/ripple/app/misc/TxQ.h index 8c1cb2688..adeadb1ba 100644 --- a/src/ripple/app/misc/TxQ.h +++ b/src/ripple/app/misc/TxQ.h @@ -358,7 +358,7 @@ public: @returns a `Json objectvalue` */ Json::Value - doRPC(Application& app) const; + doRPC(Application& app, std::optional hookFeeUnits = std::nullopt) const; private: // Implementation for nextQueuableSeq(). The passed lock must be held. diff --git a/src/ripple/app/misc/impl/TxQ.cpp b/src/ripple/app/misc/impl/TxQ.cpp index 85f5463be..c005b3d43 100644 --- a/src/ripple/app/misc/impl/TxQ.cpp +++ b/src/ripple/app/misc/impl/TxQ.cpp @@ -1914,7 +1914,7 @@ TxQ::getTxs(ReadView const& view) const } Json::Value -TxQ::doRPC(Application& app) const +TxQ::doRPC(Application& app, std::optional hookFeeUnits) const { auto const view = app.openLedger().current(); if (!view) @@ -1941,7 +1941,7 @@ TxQ::doRPC(Application& app) const levels[jss::median_level] = to_string(metrics.medFeeLevel); levels[jss::open_ledger_level] = to_string(metrics.openLedgerFeeLevel); - auto const baseFee = view->fees().base; + auto const baseFee = view->fees().base + (hookFeeUnits ? hookFeeUnits->fee() : 0); auto& drops = ret[jss::drops] = Json::Value(); drops[jss::base_fee] = diff --git a/src/ripple/app/tx/impl/applyHook.cpp b/src/ripple/app/tx/impl/applyHook.cpp index a99af3d23..be448f08e 100644 --- a/src/ripple/app/tx/impl/applyHook.cpp +++ b/src/ripple/app/tx/impl/applyHook.cpp @@ -32,8 +32,8 @@ namespace hook if (!tx.isFieldPresent(sfAccount)) return {}; - std::optional destAcc = tx.at(sfDestination); - std::optional otxnAcc = tx.at(sfAccount); + std::optional destAcc = tx.at(~sfDestination); + std::optional otxnAcc = tx.at(~sfAccount); if (!otxnAcc) return {}; @@ -183,7 +183,7 @@ namespace hook for (auto& [a, e] : tshEntries) ret[e.first] = std::pair{a, e.second}; - return std::move(ret); + return ret; } } diff --git a/src/ripple/rpc/handlers/Fee1.cpp b/src/ripple/rpc/handlers/Fee1.cpp index e30f3cbb2..da33fe21b 100644 --- a/src/ripple/rpc/handlers/Fee1.cpp +++ b/src/ripple/rpc/handlers/Fee1.cpp @@ -27,62 +27,73 @@ #include #include #include +#include namespace ripple { + +inline +std::optional +getHookFees(RPC::JsonContext const& context) +{ + auto const& params(context.params); + if (params.isMember(jss::tx_blob)) + { + auto ret = strUnHex(context.params[jss::tx_blob].asString()); + + if (!ret || !ret->size()) + throw std::invalid_argument("Invalid tx_blob"); + + SerialIter sitTrans(makeSlice(*ret)); + + std::unique_ptr stpTrans; + stpTrans = std::make_unique(std::ref(sitTrans)); + + if (!stpTrans->isFieldPresent(sfAccount)) + throw std::invalid_argument("No sfAccount specified"); + + FeeUnit64 hookFees = + Transactor::calculateHookChainFee(*(context.app.openLedger().current()), + *stpTrans, keylet::hook(stpTrans->getAccountID(sfAccount))); + + auto const view = context.app.openLedger().current(); + + std::vector> tsh = + hook::getTransactionalStakeHolders(*stpTrans, *view); + + for (auto const& [tshAccount, canRollback] : tsh) + if (canRollback) + hookFees += + Transactor::calculateHookChainFee(*view, *stpTrans, keylet::hook(tshAccount)); + return hookFees; + } + + return std::nullopt; +} + Json::Value doFee(RPC::JsonContext& context) { - Json::Value jvResult = context.app.getTxQ().doRPC(context.app); - if (jvResult.type() == Json::objectValue) + // get hook fees, if any + std::optional hookFees; + try { - auto const& params(context.params); - if (params.isMember(jss::tx_blob)) - { - auto ret = strUnHex(context.params[jss::tx_blob].asString()); - - if (!ret || !ret->size()) - return rpcError(rpcINVALID_PARAMS); - - SerialIter sitTrans(makeSlice(*ret)); - - std::unique_ptr stpTrans; - try - { - stpTrans = std::make_unique(std::ref(sitTrans)); - } - catch (std::exception& e) - { - jvResult[jss::error] = "invalidTransaction"; - jvResult[jss::error_exception] = e.what(); - return jvResult; - } - - if (!stpTrans->isFieldPresent(sfAccount)) - { - jvResult[jss::error] = "invalidTransaction"; - jvResult[jss::error_exception] = "No sfAccount specified"; - return jvResult; - } - - FeeUnit64 hookFees = - Transactor::calculateHookChainFee(*(context.app.openLedger().current()), - *stpTrans, keylet::hook(stpTrans->getAccountID(sfAccount))); - - auto const view = context.app.openLedger().current(); - - std::vector> tsh = - hook::getTransactionalStakeHolders(*stpTrans, *view); - - for (auto const& [tshAccount, canRollback] : tsh) - if (canRollback) - hookFees += - Transactor::calculateHookChainFee(*view, *stpTrans, keylet::hook(tshAccount)); - - jvResult[jss::fee_hooks_feeunits] = to_string(hookFees.value()); - } - + hookFees = getHookFees(context); + } + catch (std::exception& e) + { + Json::Value jvResult; + jvResult[jss::error] = "invalidTransaction"; + jvResult[jss::error_exception] = e.what(); return jvResult; } + + Json::Value jvResult = context.app.getTxQ().doRPC(context.app, hookFees); + if (jvResult.type() == Json::objectValue && hookFees) + { + jvResult[jss::fee_hooks_feeunits] = to_string(*hookFees); + return jvResult; + } + assert(false); RPC::inject_error(rpcINTERNAL, context.params); return context.params;