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 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=>
{

View File

@@ -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);
});

View File

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

View File

@@ -1914,7 +1914,7 @@ TxQ::getTxs(ReadView const& view) const
}
Json::Value
TxQ::doRPC(Application& app) const
TxQ::doRPC(Application& app, std::optional<FeeUnit64> 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] =

View File

@@ -32,8 +32,8 @@ namespace hook
if (!tx.isFieldPresent(sfAccount))
return {};
std::optional<AccountID> destAcc = tx.at(sfDestination);
std::optional<AccountID> otxnAcc = tx.at(sfAccount);
std::optional<AccountID> destAcc = tx.at(~sfDestination);
std::optional<AccountID> otxnAcc = tx.at(~sfAccount);
if (!otxnAcc)
return {};
@@ -183,7 +183,7 @@ namespace hook
for (auto& [a, e] : tshEntries)
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/app/tx/applyHook.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/FeeUnits.h>
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
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<FeeUnit64> 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<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());
}
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;