fix fee rpc to allow tx_blob

This commit is contained in:
Richard Holland
2022-03-21 10:17:26 +00:00
parent 7b834714c2
commit ee539fdea7
6 changed files with 89 additions and 57 deletions

View File

@@ -6,8 +6,8 @@ if (process.argv.length < 5)
const secret = process.argv[2]; const secret = process.argv[2];
const amount = BigInt(process.argv[3]) * 1000000n const amount = BigInt(process.argv[3]) * 1000000n
const dest = process.argv[4]; const dest = process.argv[4];
const server = 'ws://tn4:6005'
require('../utils-tests.js').TestRig('ws://localhost:6005').then(t=> require('../utils-tests.js').TestRig(server).then(t=>
{ {
t.pay(secret, amount, dest).then(x=> t.pay(secret, amount, dest).then(x=>
{ {

View File

@@ -48,6 +48,26 @@ module.exports = {
console.log(acc) console.log(acc)
return 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 => const hookHash = fn =>
{ {
@@ -93,7 +113,8 @@ module.exports = {
hsfNSDELETE: 2, hsfNSDELETE: 2,
hfsOVERRIDE: 1, hfsOVERRIDE: 1,
hfsNSDELETE: 2, hfsNSDELETE: 2,
hookHash: hookHash hookHash: hookHash,
pay: pay
}); });
}).catch(err); }).catch(err);
}); });

View File

@@ -358,7 +358,7 @@ public:
@returns a `Json objectvalue` @returns a `Json objectvalue`
*/ */
Json::Value Json::Value
doRPC(Application& app) const; doRPC(Application& app, std::optional<FeeUnit64> hookFeeUnits = std::nullopt) const;
private: private:
// Implementation for nextQueuableSeq(). The passed lock must be held. // Implementation for nextQueuableSeq(). The passed lock must be held.

View File

@@ -1914,7 +1914,7 @@ TxQ::getTxs(ReadView const& view) const
} }
Json::Value Json::Value
TxQ::doRPC(Application& app) const TxQ::doRPC(Application& app, std::optional<FeeUnit64> hookFeeUnits) const
{ {
auto const view = app.openLedger().current(); auto const view = app.openLedger().current();
if (!view) if (!view)
@@ -1941,7 +1941,7 @@ TxQ::doRPC(Application& app) const
levels[jss::median_level] = to_string(metrics.medFeeLevel); levels[jss::median_level] = to_string(metrics.medFeeLevel);
levels[jss::open_ledger_level] = to_string(metrics.openLedgerFeeLevel); 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(); auto& drops = ret[jss::drops] = Json::Value();
drops[jss::base_fee] = drops[jss::base_fee] =

View File

@@ -32,8 +32,8 @@ namespace hook
if (!tx.isFieldPresent(sfAccount)) if (!tx.isFieldPresent(sfAccount))
return {}; return {};
std::optional<AccountID> destAcc = tx.at(sfDestination); std::optional<AccountID> destAcc = tx.at(~sfDestination);
std::optional<AccountID> otxnAcc = tx.at(sfAccount); std::optional<AccountID> otxnAcc = tx.at(~sfAccount);
if (!otxnAcc) if (!otxnAcc)
return {}; return {};
@@ -183,7 +183,7 @@ namespace hook
for (auto& [a, e] : tshEntries) for (auto& [a, e] : tshEntries)
ret[e.first] = std::pair<AccountID, bool>{a, e.second}; ret[e.first] = std::pair<AccountID, bool>{a, e.second};
return std::move(ret); return ret;
} }
} }

View File

@@ -27,62 +27,73 @@
#include <ripple/rpc/GRPCHandlers.h> #include <ripple/rpc/GRPCHandlers.h>
#include <ripple/app/tx/applyHook.h> #include <ripple/app/tx/applyHook.h>
#include <ripple/app/tx/impl/Transactor.h> #include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/FeeUnits.h>
namespace ripple { namespace ripple {
inline
std::optional<FeeUnit64>
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<STTx const> stpTrans;
stpTrans = std::make_unique<STTx const>(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<std::pair<AccountID, bool>> 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 Json::Value
doFee(RPC::JsonContext& context) doFee(RPC::JsonContext& context)
{ {
Json::Value jvResult = context.app.getTxQ().doRPC(context.app); // get hook fees, if any
if (jvResult.type() == Json::objectValue) std::optional<FeeUnit64> hookFees;
try
{ {
auto const& params(context.params); hookFees = getHookFees(context);
if (params.isMember(jss::tx_blob)) }
{ catch (std::exception& e)
auto ret = strUnHex(context.params[jss::tx_blob].asString()); {
Json::Value jvResult;
if (!ret || !ret->size()) jvResult[jss::error] = "invalidTransaction";
return rpcError(rpcINVALID_PARAMS); jvResult[jss::error_exception] = e.what();
SerialIter sitTrans(makeSlice(*ret));
std::unique_ptr<STTx const> stpTrans;
try
{
stpTrans = std::make_unique<STTx const>(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<std::pair<AccountID, bool>> 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());
}
return jvResult; 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); assert(false);
RPC::inject_error(rpcINTERNAL, context.params); RPC::inject_error(rpcINTERNAL, context.params);
return context.params; return context.params;