fix merge issues

This commit is contained in:
Mayukha Vadari
2026-04-02 19:22:52 -04:00
parent 309fdfc3f2
commit 0acfa1c4f2
11 changed files with 345 additions and 41 deletions

View File

@@ -3,7 +3,6 @@
#include <xrpl/basics/Blob.h>
#include <xrpl/basics/SHAMapHash.h>
#include <xrpl/basics/TaggedCache.h>
#include <xrpl/ledger/CachedSLEs.h>
#include <xrpl/protocol/Fees.h>
#include <boost/asio.hpp>

View File

@@ -174,6 +174,54 @@ public:
return this->sle_->isFieldPresent(sfFinishAfter);
}
/**
* @brief Get sfFinishFunction (soeOPTIONAL)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_VL::type::value_type>
getFinishFunction() const
{
if (hasFinishFunction())
return this->sle_->at(sfFinishFunction);
return std::nullopt;
}
/**
* @brief Check if sfFinishFunction is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasFinishFunction() const
{
return this->sle_->isFieldPresent(sfFinishFunction);
}
/**
* @brief Get sfData (soeOPTIONAL)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_VL::type::value_type>
getData() const
{
if (hasData())
return this->sle_->at(sfData);
return std::nullopt;
}
/**
* @brief Check if sfData is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasData() const
{
return this->sle_->isFieldPresent(sfData);
}
/**
* @brief Get sfSourceTag (soeOPTIONAL)
* @return The field value, or std::nullopt if not present.
@@ -451,6 +499,28 @@ public:
return *this;
}
/**
* @brief Set sfFinishFunction (soeOPTIONAL)
* @return Reference to this builder for method chaining.
*/
EscrowBuilder&
setFinishFunction(std::decay_t<typename SF_VL::type::value_type> const& value)
{
object_[sfFinishFunction] = value;
return *this;
}
/**
* @brief Set sfData (soeOPTIONAL)
* @return Reference to this builder for method chaining.
*/
EscrowBuilder&
setData(std::decay_t<typename SF_VL::type::value_type> const& value)
{
object_[sfData] = value;
return *this;
}
/**
* @brief Set sfSourceTag (soeOPTIONAL)
* @return Reference to this builder for method chaining.

View File

@@ -58,6 +58,32 @@ public:
return this->tx_->at(sfDestination);
}
/**
* @brief Get sfDestinationTag (soeOPTIONAL)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT32::type::value_type>
getDestinationTag() const
{
if (hasDestinationTag())
{
return this->tx_->at(sfDestinationTag);
}
return std::nullopt;
}
/**
* @brief Check if sfDestinationTag is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasDestinationTag() const
{
return this->tx_->isFieldPresent(sfDestinationTag);
}
/**
* @brief Get sfAmount (soeREQUIRED)
* @note This field supports MPT (Multi-Purpose Token) amounts.
@@ -149,29 +175,55 @@ public:
}
/**
* @brief Get sfDestinationTag (soeOPTIONAL)
* @brief Get sfFinishFunction (soeOPTIONAL)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT32::type::value_type>
getDestinationTag() const
protocol_autogen::Optional<SF_VL::type::value_type>
getFinishFunction() const
{
if (hasDestinationTag())
if (hasFinishFunction())
{
return this->tx_->at(sfDestinationTag);
return this->tx_->at(sfFinishFunction);
}
return std::nullopt;
}
/**
* @brief Check if sfDestinationTag is present.
* @brief Check if sfFinishFunction is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasDestinationTag() const
hasFinishFunction() const
{
return this->tx_->isFieldPresent(sfDestinationTag);
return this->tx_->isFieldPresent(sfFinishFunction);
}
/**
* @brief Get sfData (soeOPTIONAL)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_VL::type::value_type>
getData() const
{
if (hasData())
{
return this->tx_->at(sfData);
}
return std::nullopt;
}
/**
* @brief Check if sfData is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasData() const
{
return this->tx_->isFieldPresent(sfData);
}
};
@@ -230,6 +282,17 @@ public:
return *this;
}
/**
* @brief Set sfDestinationTag (soeOPTIONAL)
* @return Reference to this builder for method chaining.
*/
EscrowCreateBuilder&
setDestinationTag(std::decay_t<typename SF_UINT32::type::value_type> const& value)
{
object_[sfDestinationTag] = value;
return *this;
}
/**
* @brief Set sfAmount (soeREQUIRED)
* @note This field supports MPT (Multi-Purpose Token) amounts.
@@ -276,13 +339,24 @@ public:
}
/**
* @brief Set sfDestinationTag (soeOPTIONAL)
* @brief Set sfFinishFunction (soeOPTIONAL)
* @return Reference to this builder for method chaining.
*/
EscrowCreateBuilder&
setDestinationTag(std::decay_t<typename SF_UINT32::type::value_type> const& value)
setFinishFunction(std::decay_t<typename SF_VL::type::value_type> const& value)
{
object_[sfDestinationTag] = value;
object_[sfFinishFunction] = value;
return *this;
}
/**
* @brief Set sfData (soeOPTIONAL)
* @return Reference to this builder for method chaining.
*/
EscrowCreateBuilder&
setData(std::decay_t<typename SF_VL::type::value_type> const& value)
{
object_[sfData] = value;
return *this;
}

View File

@@ -146,6 +146,32 @@ public:
{
return this->tx_->isFieldPresent(sfCredentialIDs);
}
/**
* @brief Get sfComputationAllowance (soeOPTIONAL)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT32::type::value_type>
getComputationAllowance() const
{
if (hasComputationAllowance())
{
return this->tx_->at(sfComputationAllowance);
}
return std::nullopt;
}
/**
* @brief Check if sfComputationAllowance is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasComputationAllowance() const
{
return this->tx_->isFieldPresent(sfComputationAllowance);
}
};
/**
@@ -247,6 +273,17 @@ public:
return *this;
}
/**
* @brief Set sfComputationAllowance (soeOPTIONAL)
* @return Reference to this builder for method chaining.
*/
EscrowFinishBuilder&
setComputationAllowance(std::decay_t<typename SF_UINT32::type::value_type> const& value)
{
object_[sfComputationAllowance] = value;
return *this;
}
/**
* @brief Build and return the EscrowFinish wrapper.
* @param publicKey The public key for signing.

View File

@@ -1254,7 +1254,8 @@ Transactor::operator()()
}
if (result == tecWASM_REJECTED)
modifyWasmDataFields(view(), modifiedWasmObjects, ctx_.registry.journal("View"));
modifyWasmDataFields(
view(), modifiedWasmObjects, ctx_.registry.get().getJournal("View"));
applied = isTecClaim(result);
}

View File

@@ -14,6 +14,10 @@
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/tx/transactors/escrow/EscrowCreate.h>
#include <xrpl/tx/wasm/HostFunc.h>
#include <xrpl/tx/wasm/WasmVM.h>
#include <libxrpl/tx/transactors/escrow/EscrowHelpers.h>
namespace xrpl {
@@ -191,7 +195,7 @@ EscrowCreate::preflight(PreflightContext const& ctx)
if (ctx.tx.isFieldPresent(sfFinishFunction))
{
auto const fees(ctx.registry.getFees());
auto const fees(ctx.registry.get().getFees());
if (fees.extensionSizeLimit == 0 || fees.extensionComputeLimit == 0)
{
JLOG(ctx.j.debug()) << "WASM runtime deactivated by fee voting";
@@ -462,17 +466,6 @@ escrowLockApplyHelper<MPTIssue>(
return tesSUCCESS;
}
template <class T>
static uint32_t
calculateAdditionalReserve(T const& finishFunction)
{
if (!finishFunction)
return 1;
// First 500 bytes included in the normal reserve
// Each additional 500 bytes requires an additional reserve
return 1 + (finishFunction->size() / 500);
}
TER
EscrowCreate::doApply()
{

View File

@@ -14,6 +14,8 @@
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/tx/transactors/escrow/EscrowFinish.h>
#include <xrpl/tx/wasm/HostFuncImpl.h>
#include <xrpl/tx/wasm/WasmVM.h>
#include <libxrpl/tx/transactors/escrow/EscrowHelpers.h>
@@ -74,7 +76,7 @@ EscrowFinish::preflight(PreflightContext const& ctx)
if (auto const allowance = ctx.tx[~sfComputationAllowance]; allowance)
{
auto const fees(ctx.registry.getFees());
auto const fees(ctx.registry.get().getFees());
if (fees.extensionComputeLimit == 0)
{
JLOG(ctx.j.debug()) << "WASM runtime deactivated by fee voting";

View File

@@ -227,4 +227,15 @@ escrowUnlockApplyHelper<MPTIssue>(
journal);
}
template <class T>
static uint32_t
calculateAdditionalReserve(T const& finishFunction)
{
if (!finishFunction)
return 1;
// First 500 bytes included in the normal reserve
// Each additional 500 bytes requires an additional reserve
return 1 + (finishFunction->size() / 500);
}
} // namespace xrpl

View File

@@ -27,6 +27,8 @@ TEST(EscrowTests, BuilderSettersRoundTrip)
auto const conditionValue = canonical_VL();
auto const cancelAfterValue = canonical_UINT32();
auto const finishAfterValue = canonical_UINT32();
auto const finishFunctionValue = canonical_VL();
auto const dataValue = canonical_VL();
auto const sourceTagValue = canonical_UINT32();
auto const destinationTagValue = canonical_UINT32();
auto const ownerNodeValue = canonical_UINT64();
@@ -49,6 +51,8 @@ TEST(EscrowTests, BuilderSettersRoundTrip)
builder.setCondition(conditionValue);
builder.setCancelAfter(cancelAfterValue);
builder.setFinishAfter(finishAfterValue);
builder.setFinishFunction(finishFunctionValue);
builder.setData(dataValue);
builder.setSourceTag(sourceTagValue);
builder.setDestinationTag(destinationTagValue);
builder.setDestinationNode(destinationNodeValue);
@@ -132,6 +136,22 @@ TEST(EscrowTests, BuilderSettersRoundTrip)
EXPECT_TRUE(entry.hasFinishAfter());
}
{
auto const& expected = finishFunctionValue;
auto const actualOpt = entry.getFinishFunction();
ASSERT_TRUE(actualOpt.has_value());
expectEqualField(expected, *actualOpt, "sfFinishFunction");
EXPECT_TRUE(entry.hasFinishFunction());
}
{
auto const& expected = dataValue;
auto const actualOpt = entry.getData();
ASSERT_TRUE(actualOpt.has_value());
expectEqualField(expected, *actualOpt, "sfData");
EXPECT_TRUE(entry.hasData());
}
{
auto const& expected = sourceTagValue;
auto const actualOpt = entry.getSourceTag();
@@ -192,6 +212,8 @@ TEST(EscrowTests, BuilderFromSleRoundTrip)
auto const conditionValue = canonical_VL();
auto const cancelAfterValue = canonical_UINT32();
auto const finishAfterValue = canonical_UINT32();
auto const finishFunctionValue = canonical_VL();
auto const dataValue = canonical_VL();
auto const sourceTagValue = canonical_UINT32();
auto const destinationTagValue = canonical_UINT32();
auto const ownerNodeValue = canonical_UINT64();
@@ -210,6 +232,8 @@ TEST(EscrowTests, BuilderFromSleRoundTrip)
sle->at(sfCondition) = conditionValue;
sle->at(sfCancelAfter) = cancelAfterValue;
sle->at(sfFinishAfter) = finishAfterValue;
sle->at(sfFinishFunction) = finishFunctionValue;
sle->at(sfData) = dataValue;
sle->at(sfSourceTag) = sourceTagValue;
sle->at(sfDestinationTag) = destinationTagValue;
sle->at(sfOwnerNode) = ownerNodeValue;
@@ -340,6 +364,32 @@ TEST(EscrowTests, BuilderFromSleRoundTrip)
expectEqualField(expected, *fromBuilderOpt, "sfFinishAfter");
}
{
auto const& expected = finishFunctionValue;
auto const fromSleOpt = entryFromSle.getFinishFunction();
auto const fromBuilderOpt = entryFromBuilder.getFinishFunction();
ASSERT_TRUE(fromSleOpt.has_value());
ASSERT_TRUE(fromBuilderOpt.has_value());
expectEqualField(expected, *fromSleOpt, "sfFinishFunction");
expectEqualField(expected, *fromBuilderOpt, "sfFinishFunction");
}
{
auto const& expected = dataValue;
auto const fromSleOpt = entryFromSle.getData();
auto const fromBuilderOpt = entryFromBuilder.getData();
ASSERT_TRUE(fromSleOpt.has_value());
ASSERT_TRUE(fromBuilderOpt.has_value());
expectEqualField(expected, *fromSleOpt, "sfData");
expectEqualField(expected, *fromBuilderOpt, "sfData");
}
{
auto const& expected = sourceTagValue;
@@ -477,6 +527,10 @@ TEST(EscrowTests, OptionalFieldsReturnNullopt)
EXPECT_FALSE(entry.getCancelAfter().has_value());
EXPECT_FALSE(entry.hasFinishAfter());
EXPECT_FALSE(entry.getFinishAfter().has_value());
EXPECT_FALSE(entry.hasFinishFunction());
EXPECT_FALSE(entry.getFinishFunction().has_value());
EXPECT_FALSE(entry.hasData());
EXPECT_FALSE(entry.getData().has_value());
EXPECT_FALSE(entry.hasSourceTag());
EXPECT_FALSE(entry.getSourceTag().has_value());
EXPECT_FALSE(entry.hasDestinationTag());

View File

@@ -30,11 +30,13 @@ TEST(TransactionsEscrowCreateTests, BuilderSettersRoundTrip)
// Transaction-specific field values
auto const destinationValue = canonical_ACCOUNT();
auto const destinationTagValue = canonical_UINT32();
auto const amountValue = canonical_AMOUNT();
auto const conditionValue = canonical_VL();
auto const cancelAfterValue = canonical_UINT32();
auto const finishAfterValue = canonical_UINT32();
auto const destinationTagValue = canonical_UINT32();
auto const finishFunctionValue = canonical_VL();
auto const dataValue = canonical_VL();
EscrowCreateBuilder builder{
accountValue,
@@ -45,10 +47,12 @@ TEST(TransactionsEscrowCreateTests, BuilderSettersRoundTrip)
};
// Set optional fields
builder.setDestinationTag(destinationTagValue);
builder.setCondition(conditionValue);
builder.setCancelAfter(cancelAfterValue);
builder.setFinishAfter(finishAfterValue);
builder.setDestinationTag(destinationTagValue);
builder.setFinishFunction(finishFunctionValue);
builder.setData(dataValue);
auto tx = builder.build(publicKey, secretKey);
@@ -78,6 +82,14 @@ TEST(TransactionsEscrowCreateTests, BuilderSettersRoundTrip)
}
// Verify optional fields
{
auto const& expected = destinationTagValue;
auto const actualOpt = tx.getDestinationTag();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present";
expectEqualField(expected, *actualOpt, "sfDestinationTag");
EXPECT_TRUE(tx.hasDestinationTag());
}
{
auto const& expected = conditionValue;
auto const actualOpt = tx.getCondition();
@@ -103,11 +115,19 @@ TEST(TransactionsEscrowCreateTests, BuilderSettersRoundTrip)
}
{
auto const& expected = destinationTagValue;
auto const actualOpt = tx.getDestinationTag();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present";
expectEqualField(expected, *actualOpt, "sfDestinationTag");
EXPECT_TRUE(tx.hasDestinationTag());
auto const& expected = finishFunctionValue;
auto const actualOpt = tx.getFinishFunction();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfFinishFunction should be present";
expectEqualField(expected, *actualOpt, "sfFinishFunction");
EXPECT_TRUE(tx.hasFinishFunction());
}
{
auto const& expected = dataValue;
auto const actualOpt = tx.getData();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present";
expectEqualField(expected, *actualOpt, "sfData");
EXPECT_TRUE(tx.hasData());
}
}
@@ -127,11 +147,13 @@ TEST(TransactionsEscrowCreateTests, BuilderFromStTxRoundTrip)
// Transaction-specific field values
auto const destinationValue = canonical_ACCOUNT();
auto const destinationTagValue = canonical_UINT32();
auto const amountValue = canonical_AMOUNT();
auto const conditionValue = canonical_VL();
auto const cancelAfterValue = canonical_UINT32();
auto const finishAfterValue = canonical_UINT32();
auto const destinationTagValue = canonical_UINT32();
auto const finishFunctionValue = canonical_VL();
auto const dataValue = canonical_VL();
// Build an initial transaction
EscrowCreateBuilder initialBuilder{
@@ -142,10 +164,12 @@ TEST(TransactionsEscrowCreateTests, BuilderFromStTxRoundTrip)
feeValue
};
initialBuilder.setDestinationTag(destinationTagValue);
initialBuilder.setCondition(conditionValue);
initialBuilder.setCancelAfter(cancelAfterValue);
initialBuilder.setFinishAfter(finishAfterValue);
initialBuilder.setDestinationTag(destinationTagValue);
initialBuilder.setFinishFunction(finishFunctionValue);
initialBuilder.setData(dataValue);
auto initialTx = initialBuilder.build(publicKey, secretKey);
@@ -176,6 +200,13 @@ TEST(TransactionsEscrowCreateTests, BuilderFromStTxRoundTrip)
}
// Verify optional fields
{
auto const& expected = destinationTagValue;
auto const actualOpt = rebuiltTx.getDestinationTag();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present";
expectEqualField(expected, *actualOpt, "sfDestinationTag");
}
{
auto const& expected = conditionValue;
auto const actualOpt = rebuiltTx.getCondition();
@@ -198,10 +229,17 @@ TEST(TransactionsEscrowCreateTests, BuilderFromStTxRoundTrip)
}
{
auto const& expected = destinationTagValue;
auto const actualOpt = rebuiltTx.getDestinationTag();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present";
expectEqualField(expected, *actualOpt, "sfDestinationTag");
auto const& expected = finishFunctionValue;
auto const actualOpt = rebuiltTx.getFinishFunction();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfFinishFunction should be present";
expectEqualField(expected, *actualOpt, "sfFinishFunction");
}
{
auto const& expected = dataValue;
auto const actualOpt = rebuiltTx.getData();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present";
expectEqualField(expected, *actualOpt, "sfData");
}
}
@@ -263,14 +301,18 @@ TEST(TransactionsEscrowCreateTests, OptionalFieldsReturnNullopt)
auto tx = builder.build(publicKey, secretKey);
// Verify optional fields are not present
EXPECT_FALSE(tx.hasDestinationTag());
EXPECT_FALSE(tx.getDestinationTag().has_value());
EXPECT_FALSE(tx.hasCondition());
EXPECT_FALSE(tx.getCondition().has_value());
EXPECT_FALSE(tx.hasCancelAfter());
EXPECT_FALSE(tx.getCancelAfter().has_value());
EXPECT_FALSE(tx.hasFinishAfter());
EXPECT_FALSE(tx.getFinishAfter().has_value());
EXPECT_FALSE(tx.hasDestinationTag());
EXPECT_FALSE(tx.getDestinationTag().has_value());
EXPECT_FALSE(tx.hasFinishFunction());
EXPECT_FALSE(tx.getFinishFunction().has_value());
EXPECT_FALSE(tx.hasData());
EXPECT_FALSE(tx.getData().has_value());
}
}

View File

@@ -34,6 +34,7 @@ TEST(TransactionsEscrowFinishTests, BuilderSettersRoundTrip)
auto const fulfillmentValue = canonical_VL();
auto const conditionValue = canonical_VL();
auto const credentialIDsValue = canonical_VECTOR256();
auto const computationAllowanceValue = canonical_UINT32();
EscrowFinishBuilder builder{
accountValue,
@@ -47,6 +48,7 @@ TEST(TransactionsEscrowFinishTests, BuilderSettersRoundTrip)
builder.setFulfillment(fulfillmentValue);
builder.setCondition(conditionValue);
builder.setCredentialIDs(credentialIDsValue);
builder.setComputationAllowance(computationAllowanceValue);
auto tx = builder.build(publicKey, secretKey);
@@ -100,6 +102,14 @@ TEST(TransactionsEscrowFinishTests, BuilderSettersRoundTrip)
EXPECT_TRUE(tx.hasCredentialIDs());
}
{
auto const& expected = computationAllowanceValue;
auto const actualOpt = tx.getComputationAllowance();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfComputationAllowance should be present";
expectEqualField(expected, *actualOpt, "sfComputationAllowance");
EXPECT_TRUE(tx.hasComputationAllowance());
}
}
// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper,
@@ -121,6 +131,7 @@ TEST(TransactionsEscrowFinishTests, BuilderFromStTxRoundTrip)
auto const fulfillmentValue = canonical_VL();
auto const conditionValue = canonical_VL();
auto const credentialIDsValue = canonical_VECTOR256();
auto const computationAllowanceValue = canonical_UINT32();
// Build an initial transaction
EscrowFinishBuilder initialBuilder{
@@ -134,6 +145,7 @@ TEST(TransactionsEscrowFinishTests, BuilderFromStTxRoundTrip)
initialBuilder.setFulfillment(fulfillmentValue);
initialBuilder.setCondition(conditionValue);
initialBuilder.setCredentialIDs(credentialIDsValue);
initialBuilder.setComputationAllowance(computationAllowanceValue);
auto initialTx = initialBuilder.build(publicKey, secretKey);
@@ -185,6 +197,13 @@ TEST(TransactionsEscrowFinishTests, BuilderFromStTxRoundTrip)
expectEqualField(expected, *actualOpt, "sfCredentialIDs");
}
{
auto const& expected = computationAllowanceValue;
auto const actualOpt = rebuiltTx.getComputationAllowance();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfComputationAllowance should be present";
expectEqualField(expected, *actualOpt, "sfComputationAllowance");
}
}
// 3) Verify wrapper throws when constructed from wrong transaction type.
@@ -250,6 +269,8 @@ TEST(TransactionsEscrowFinishTests, OptionalFieldsReturnNullopt)
EXPECT_FALSE(tx.getCondition().has_value());
EXPECT_FALSE(tx.hasCredentialIDs());
EXPECT_FALSE(tx.getCredentialIDs().has_value());
EXPECT_FALSE(tx.hasComputationAllowance());
EXPECT_FALSE(tx.getComputationAllowance().has_value());
}
}