feat: add a GasUsed parameter to the metadata (#5456)

This commit is contained in:
Mayukha Vadari
2025-05-29 16:36:55 -04:00
committed by GitHub
parent 6c6f8cd4f9
commit 1f8aece8cd
10 changed files with 109 additions and 45 deletions

View File

@@ -46,10 +46,7 @@ private:
CtorHelper);
public:
TxMeta(
uint256 const& transactionID,
std::uint32_t ledger,
std::optional<uint256> parentBatchId = std::nullopt);
TxMeta(uint256 const& transactionID, std::uint32_t ledger);
TxMeta(uint256 const& txID, std::uint32_t ledger, Blob const&);
TxMeta(uint256 const& txID, std::uint32_t ledger, std::string const&);
TxMeta(uint256 const& txID, std::uint32_t ledger, STObject const&);
@@ -136,7 +133,7 @@ public:
void
setParentBatchId(uint256 const& parentBatchId)
{
mParentBatchId = parentBatchId;
parentBatchId_ = parentBatchId;
}
uint256
@@ -145,13 +142,33 @@ public:
XRPL_ASSERT(
hasParentBatchId(),
"ripple::TxMeta::getParentBatchId : non-null batch id");
return *mParentBatchId;
return *parentBatchId_;
}
bool
hasParentBatchId() const
{
return static_cast<bool>(mParentBatchId);
return static_cast<bool>(parentBatchId_);
}
void
setGasUsed(std::uint32_t const& gasUsed)
{
gasUsed_ = gasUsed;
}
std::uint32_t
getGasUsed() const
{
XRPL_ASSERT(
hasGasUsed(), "ripple::TxMeta::getGasUsed : non-null batch id");
return *gasUsed_;
}
bool
hasGasUsed() const
{
return static_cast<bool>(gasUsed_);
}
private:
@@ -161,7 +178,8 @@ private:
int mResult;
std::optional<STAmount> mDelivered;
std::optional<uint256> mParentBatchId;
std::optional<std::uint32_t> gasUsed_;
std::optional<uint256> parentBatchId_;
STArray mNodes;
};

View File

@@ -118,6 +118,7 @@ TYPED_SFIELD(sfExtensionComputeLimit, UINT32, 53)
TYPED_SFIELD(sfExtensionSizeLimit, UINT32, 54)
TYPED_SFIELD(sfGasPrice, UINT32, 55)
TYPED_SFIELD(sfComputationAllowance, UINT32, 56)
TYPED_SFIELD(sfGasUsed, UINT32, 57)
// 64-bit integers (common)
TYPED_SFIELD(sfIndexNext, UINT64, 1)

View File

@@ -56,9 +56,10 @@ TxMeta::TxMeta(
if (obj.isFieldPresent(sfDeliveredAmount))
setDeliveredAmount(obj.getFieldAmount(sfDeliveredAmount));
if (obj.isFieldPresent(sfParentBatchID))
setParentBatchId(obj.getFieldH256(sfParentBatchID));
if (obj.isFieldPresent(sfGasUsed))
setGasUsed(obj.getFieldU32(sfGasUsed));
}
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj)
@@ -82,6 +83,9 @@ TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj)
if (obj.isFieldPresent(sfParentBatchID))
setParentBatchId(obj.getFieldH256(sfParentBatchID));
if (obj.isFieldPresent(sfGasUsed))
setGasUsed(obj.getFieldU32(sfGasUsed));
}
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, Blob const& vec)
@@ -97,15 +101,11 @@ TxMeta::TxMeta(
{
}
TxMeta::TxMeta(
uint256 const& transactionID,
std::uint32_t ledger,
std::optional<uint256> parentBatchId)
TxMeta::TxMeta(uint256 const& transactionID, std::uint32_t ledger)
: mTransactionID(transactionID)
, mLedger(ledger)
, mIndex(static_cast<std::uint32_t>(-1))
, mResult(255)
, mParentBatchId(parentBatchId)
, mNodes(sfAffectedNodes)
{
mNodes.reserve(32);
@@ -241,9 +241,10 @@ TxMeta::getAsObject() const
metaData.emplace_back(mNodes);
if (hasDeliveredAmount())
metaData.setFieldAmount(sfDeliveredAmount, getDeliveredAmount());
if (hasParentBatchId())
metaData.setFieldH256(sfParentBatchID, getParentBatchId());
if (hasGasUsed())
metaData.setFieldU32(sfGasUsed, getGasUsed());
return metaData;
}

View File

@@ -1863,7 +1863,7 @@ struct Escrow_test : public beast::unit_test::suite
XRPAmount const txnFees = env.current()->fees().base + 1000;
env(finish(carol, alice, 1),
fee(txnFees),
comp_allowance(110),
comp_allowance(4),
ter(temDISABLED));
env.close();
}
@@ -1914,12 +1914,12 @@ struct Escrow_test : public beast::unit_test::suite
{
// not enough fees
// This function takes 110 gas
// This function takes 4 gas
// In testing, 1 gas costs 1 drop
auto const finishFee = env.current()->fees().base + 109;
auto const finishFee = env.current()->fees().base + 3;
env(finish(carol, alice, seq),
fee(finishFee),
comp_allowance(110),
comp_allowance(4),
ter(telINSUF_FEE_P));
}
@@ -1968,6 +1968,7 @@ struct Escrow_test : public beast::unit_test::suite
// unsafe { host_lib::getLedgerSqn() >= 5}
// }
static auto wasmHex = ledgerSqnHex;
std::uint32_t constexpr allowance = 4;
{
// basic FinishFunction situation
@@ -1990,31 +1991,34 @@ struct Escrow_test : public beast::unit_test::suite
env.require(balance(carol, XRP(5000)));
env(finish(carol, alice, seq),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tecWASM_REJECTED));
env(finish(alice, alice, seq),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tecWASM_REJECTED));
env(finish(alice, alice, seq),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tecWASM_REJECTED));
env(finish(carol, alice, seq),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tecWASM_REJECTED));
env(finish(carol, alice, seq),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tecWASM_REJECTED));
env.close();
env(finish(alice, alice, seq),
fee(txnFees),
comp_allowance(110),
comp_allowance(allowance),
ter(tesSUCCESS));
env.close();
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECT(txMeta->getFieldU32(sfGasUsed) == allowance);
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
}
@@ -2046,38 +2050,42 @@ struct Escrow_test : public beast::unit_test::suite
// no fulfillment provided, function fails
env(finish(carol, alice, seq),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tecCRYPTOCONDITION_ERROR));
// fulfillment provided, function fails
env(finish(carol, alice, seq),
condition(cb1),
fulfillment(fb1),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tecWASM_REJECTED));
env.close();
// no fulfillment provided, function succeeds
env(finish(alice, alice, seq),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tecCRYPTOCONDITION_ERROR));
// wrong fulfillment provided, function succeeds
env(finish(alice, alice, seq),
condition(cb1),
fulfillment(fb2),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tecCRYPTOCONDITION_ERROR));
// fulfillment provided, function succeeds, tx succeeds
env(finish(alice, alice, seq),
condition(cb1),
fulfillment(fb1),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tesSUCCESS));
env.close();
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECT(txMeta->getFieldU32(sfGasUsed) == allowance);
env.close();
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
}
}
@@ -2106,21 +2114,26 @@ struct Escrow_test : public beast::unit_test::suite
// finish time hasn't passed, function fails
env(finish(carol, alice, seq),
comp_allowance(110),
comp_allowance(4),
fee(txnFees + 1),
ter(tecNO_PERMISSION));
env.close();
// finish time hasn't passed, function succeeds
for (; env.now() < ts; env.close())
env(finish(carol, alice, seq),
comp_allowance(110),
comp_allowance(4),
fee(txnFees + 2),
ter(tecNO_PERMISSION));
env(finish(carol, alice, seq),
comp_allowance(110),
comp_allowance(4),
fee(txnFees + 1),
ter(tesSUCCESS));
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECT(txMeta->getFieldU32(sfGasUsed) == allowance);
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
}
}
@@ -2148,24 +2161,28 @@ struct Escrow_test : public beast::unit_test::suite
// finish time hasn't passed, function fails
env(finish(carol, alice, seq),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tecNO_PERMISSION));
env.close();
// finish time has passed, function fails
env(finish(carol, alice, seq),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tecWASM_REJECTED));
env.close();
// finish time has passed, function succeeds, tx succeeds
env(finish(carol, alice, seq),
comp_allowance(110),
comp_allowance(allowance),
fee(txnFees),
ter(tesSUCCESS));
env.close();
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECT(txMeta->getFieldU32(sfGasUsed) == allowance);
env.close();
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
}
}
@@ -2179,7 +2196,6 @@ struct Escrow_test : public beast::unit_test::suite
using namespace jtx;
using namespace std::chrono;
// TODO: figure out how to make this a fixture in a separate file
static auto wasmHex = allHostFunctionsHex;
// let sender = get_tx_account_id();
// let owner = get_current_escrow_account_id();
@@ -2218,7 +2234,8 @@ struct Escrow_test : public beast::unit_test::suite
env.require(balance(alice, XRP(4000) - txnFees));
env.require(balance(carol, XRP(5000)));
auto const allowance = 40'000;
// TODO: figure out why this can't be 2412
auto const allowance = 3'600;
// FinishAfter time hasn't passed
env(finish(carol, alice, seq),
@@ -2232,6 +2249,7 @@ struct Escrow_test : public beast::unit_test::suite
comp_allowance(allowance),
fee(txnFees),
ter(tecWASM_REJECTED));
env.close();
// destination balance is too high
env(finish(carol, alice, seq),
@@ -2256,8 +2274,12 @@ struct Escrow_test : public beast::unit_test::suite
comp_allowance(allowance),
fee(txnFees),
ter(tesSUCCESS));
env.close();
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECT(txMeta->getFieldU32(sfGasUsed) == 2412);
env.close();
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
}
}

View File

@@ -106,6 +106,13 @@ public:
view_->deliver(amount);
}
/** Sets the gas used in the metadata */
void
setGasUsed(std::uint32_t const& gasUsed)
{
view_->setGasUsed(gasUsed);
}
/** Discard changes and start fresh. */
void
discard();

View File

@@ -634,6 +634,8 @@ EscrowFinish::doApply()
if (re.has_value())
{
auto reValue = re.value().result;
// TODO: better error handling for this conversion
ctx_.setGasUsed(static_cast<uint32_t>(re.value().cost));
JLOG(j_.debug()) << "WASM Success: " + std::to_string(reValue)
<< ", cost: " << re.value().cost;
if (!reValue)

View File

@@ -75,6 +75,12 @@ public:
deliver_ = amount;
}
void
setGasUsed(std::uint32_t const& gasUsed)
{
gasUsed_ = gasUsed;
}
/** Get the number of modified entries
*/
std::size_t
@@ -93,6 +99,7 @@ public:
private:
std::optional<STAmount> deliver_;
std::optional<std::uint32_t> gasUsed_;
};
} // namespace ripple

View File

@@ -117,6 +117,7 @@ ApplyStateTable::apply(
TER ter,
std::optional<STAmount> const& deliver,
std::optional<uint256 const> const& parentBatchId,
std::optional<std::uint32_t> const& gasUsed,
bool isDryRun,
beast::Journal j)
{
@@ -127,11 +128,14 @@ ApplyStateTable::apply(
std::optional<TxMeta> metadata;
if (!to.open() || isDryRun)
{
TxMeta meta(tx.getTransactionID(), to.seq(), parentBatchId);
TxMeta meta(tx.getTransactionID(), to.seq());
if (deliver)
meta.setDeliveredAmount(*deliver);
if (parentBatchId)
meta.setParentBatchId(*parentBatchId);
if (gasUsed)
meta.setGasUsed(*gasUsed);
Mods newMod;
for (auto& item : items_)
{

View File

@@ -73,6 +73,7 @@ public:
TER ter,
std::optional<STAmount> const& deliver,
std::optional<uint256 const> const& parentBatchId,
std::optional<std::uint32_t> const& gasUsed,
bool isDryRun,
beast::Journal j);

View File

@@ -35,7 +35,8 @@ ApplyViewImpl::apply(
bool isDryRun,
beast::Journal j)
{
return items_.apply(to, tx, ter, deliver_, parentBatchId, isDryRun, j);
return items_.apply(
to, tx, ter, deliver_, parentBatchId, gasUsed_, isDryRun, j);
}
std::size_t