mirror of
https://github.com/Xahau/xahaud.git
synced 2026-10-23 04:07:13 +00:00
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a6f5faacd | ||
|
|
4eba415e9b | ||
|
|
9d73b12713 | ||
|
|
d3d4f4dbad | ||
|
|
dd3b0447d5 | ||
|
|
bba014a27c | ||
|
|
617c896514 | ||
|
|
97ab309a09 | ||
|
|
6cb07b0000 | ||
|
|
049efbcdc0 | ||
|
|
9f449e97bc | ||
|
|
6561cd7f58 | ||
|
|
27b91f997c | ||
|
|
75b760debe | ||
|
|
3f7e15893e |
No files matched your search
@@ -45,5 +45,7 @@
|
||||
#define INVALID_KEY -41
|
||||
#define NOT_A_STRING -42
|
||||
#define MEM_OVERLAP -43
|
||||
#define TOO_MANY_STATE_MODIFICATIONS -44
|
||||
#define TOO_MANY_NAMESPACES -45
|
||||
#define HOOK_ERROR_CODES
|
||||
#endif //HOOK_ERROR_CODES
|
||||
@@ -54,6 +54,12 @@ maxHookChainLength(void)
|
||||
return 10;
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
maxNamespaces(void)
|
||||
{
|
||||
return 256;
|
||||
}
|
||||
|
||||
enum TSHFlags : uint8_t {
|
||||
tshNONE = 0b000,
|
||||
tshROLLBACK = 0b001,
|
||||
@@ -313,6 +319,7 @@ enum hook_return_code : int64_t {
|
||||
MEM_OVERLAP = -43, // one or more specified buffers are the same memory
|
||||
TOO_MANY_STATE_MODIFICATIONS = -44, // more than 5000 modified state
|
||||
// entires in the combined hook chains
|
||||
TOO_MANY_NAMESPACES = -45
|
||||
};
|
||||
|
||||
enum ExitType : uint8_t {
|
||||
|
||||
@@ -29,8 +29,9 @@ isEmittedTxn(ripple::STTx const& tx);
|
||||
// only upon tesSuccess for the otxn.
|
||||
class HookStateMap : public std::map<
|
||||
ripple::AccountID, // account that owns the state
|
||||
std::pair<
|
||||
std::tuple<
|
||||
int64_t, // remaining available ownercount
|
||||
int64_t, // total namespace count
|
||||
std::map<
|
||||
ripple::uint256, // namespace
|
||||
std::map<
|
||||
|
||||
@@ -71,6 +71,8 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
return rv.read(keylet::nftoffer(*id));
|
||||
};
|
||||
|
||||
bool const fixV1 = rv.rules().enabled(fixXahauV1);
|
||||
|
||||
switch (tt)
|
||||
{
|
||||
case ttIMPORT: {
|
||||
@@ -97,19 +99,36 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
// the burner is the issuer and not the owner of the token
|
||||
|
||||
if (issuer == owner)
|
||||
{
|
||||
// pass, already a TSH
|
||||
}
|
||||
else if (*otxnAcc == owner)
|
||||
break;
|
||||
// pass, already a TSH
|
||||
|
||||
// new logic
|
||||
if (fixV1)
|
||||
{
|
||||
// the owner burns their token, and the issuer is a weak TSH
|
||||
ADD_TSH(issuer, canRollback);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*otxnAcc == owner && rv.exists(keylet::account(issuer)))
|
||||
ADD_TSH(issuer, false);
|
||||
// the issuer burns the owner's token, and the owner is a weak
|
||||
// TSH
|
||||
ADD_TSH(owner, canRollback);
|
||||
else if (rv.exists(keylet::account(owner)))
|
||||
ADD_TSH(owner, false);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// old logic
|
||||
{
|
||||
if (*otxnAcc == owner)
|
||||
{
|
||||
// the owner burns their token, and the issuer is a weak TSH
|
||||
ADD_TSH(issuer, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the issuer burns the owner's token, and the owner is a
|
||||
// weak TSH
|
||||
ADD_TSH(owner, true);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -300,19 +319,59 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
|
||||
case ttESCROW_CANCEL:
|
||||
case ttESCROW_FINISH: {
|
||||
if (!tx.isFieldPresent(sfOwner) ||
|
||||
!tx.isFieldPresent(sfOfferSequence))
|
||||
return {};
|
||||
// new logic
|
||||
if (fixV1)
|
||||
{
|
||||
if (!tx.isFieldPresent(sfOwner))
|
||||
return {};
|
||||
|
||||
auto escrow = rv.read(keylet::escrow(
|
||||
tx.getAccountID(sfOwner), tx.getFieldU32(sfOfferSequence)));
|
||||
AccountID const owner = tx.getAccountID(sfOwner);
|
||||
|
||||
if (!escrow)
|
||||
return {};
|
||||
bool const hasSeq = tx.isFieldPresent(sfOfferSequence);
|
||||
bool const hasID = tx.isFieldPresent(sfEscrowID);
|
||||
if (!hasSeq && !hasID)
|
||||
return {};
|
||||
|
||||
ADD_TSH(escrow->getAccountID(sfAccount), true);
|
||||
ADD_TSH(escrow->getAccountID(sfDestination), canRollback);
|
||||
break;
|
||||
Keylet kl = hasSeq
|
||||
? keylet::escrow(owner, tx.getFieldU32(sfOfferSequence))
|
||||
: Keylet(ltESCROW, tx.getFieldH256(sfEscrowID));
|
||||
|
||||
auto escrow = rv.read(kl);
|
||||
|
||||
if (!escrow ||
|
||||
escrow->getFieldU16(sfLedgerEntryType) != ltESCROW)
|
||||
return {};
|
||||
|
||||
// this should always be the same as owner, but defensively...
|
||||
AccountID const src = escrow->getAccountID(sfAccount);
|
||||
AccountID const dst = escrow->getAccountID(sfDestination);
|
||||
|
||||
// the source account is a strong transacitonal stakeholder for
|
||||
// fin and can
|
||||
ADD_TSH(src, true);
|
||||
|
||||
// the dest acc is a strong tsh for fin and weak for can
|
||||
if (src != dst)
|
||||
ADD_TSH(dst, tt == ttESCROW_FINISH);
|
||||
|
||||
break;
|
||||
}
|
||||
// old logic
|
||||
{
|
||||
if (!tx.isFieldPresent(sfOwner) ||
|
||||
!tx.isFieldPresent(sfOfferSequence))
|
||||
return {};
|
||||
|
||||
auto escrow = rv.read(keylet::escrow(
|
||||
tx.getAccountID(sfOwner), tx.getFieldU32(sfOfferSequence)));
|
||||
|
||||
if (!escrow)
|
||||
return {};
|
||||
|
||||
ADD_TSH(escrow->getAccountID(sfAccount), true);
|
||||
ADD_TSH(escrow->getAccountID(sfDestination), canRollback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case ttPAYCHAN_FUND:
|
||||
@@ -1287,7 +1346,7 @@ lookup_state_cache(
|
||||
if (stateMap.find(acc) == stateMap.end())
|
||||
return std::nullopt;
|
||||
|
||||
auto& stateMapAcc = stateMap[acc].second;
|
||||
auto& stateMapAcc = std::get<2>(stateMap[acc]);
|
||||
if (stateMapAcc.find(ns) == stateMapAcc.end())
|
||||
return std::nullopt;
|
||||
|
||||
@@ -1312,18 +1371,22 @@ set_state_cache(
|
||||
bool modified)
|
||||
{
|
||||
auto& stateMap = hookCtx.result.stateMap;
|
||||
auto& view = hookCtx.applyCtx.view();
|
||||
|
||||
if (modified && stateMap.modified_entry_count >= max_state_modifications)
|
||||
return TOO_MANY_STATE_MODIFICATIONS;
|
||||
|
||||
bool const createNamespace = view.rules().enabled(fixXahauV1) &&
|
||||
!view.exists(keylet::hookStateDir(acc, ns));
|
||||
|
||||
if (stateMap.find(acc) == stateMap.end())
|
||||
{
|
||||
// if this is the first time this account has been interacted with
|
||||
// we will compute how many available reserve positions there are
|
||||
auto const& fees = hookCtx.applyCtx.view().fees();
|
||||
|
||||
auto const accSLE =
|
||||
hookCtx.applyCtx.view().read(ripple::keylet::account(acc));
|
||||
auto const accSLE = view.read(ripple::keylet::account(acc));
|
||||
|
||||
if (!accSLE)
|
||||
return DOESNT_EXIST;
|
||||
|
||||
@@ -1342,15 +1405,32 @@ set_state_cache(
|
||||
if (availableForReserves < 1 && modified)
|
||||
return RESERVE_INSUFFICIENT;
|
||||
|
||||
int64_t namespaceCount = accSLE->isFieldPresent(sfHookNamespaces)
|
||||
? accSLE->getFieldV256(sfHookNamespaces).size()
|
||||
: 0;
|
||||
|
||||
if (createNamespace)
|
||||
{
|
||||
// overflow should never ever happen but check anyway
|
||||
if (namespaceCount + 1 < namespaceCount)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
if (++namespaceCount > hook::maxNamespaces())
|
||||
return TOO_MANY_NAMESPACES;
|
||||
}
|
||||
|
||||
stateMap.modified_entry_count++;
|
||||
|
||||
stateMap[acc] = {
|
||||
availableForReserves - 1, {{ns, {{key, {modified, data}}}}}};
|
||||
availableForReserves - 1,
|
||||
namespaceCount,
|
||||
{{ns, {{key, {modified, data}}}}}};
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto& stateMapAcc = stateMap[acc].second;
|
||||
auto& availableForReserves = stateMap[acc].first;
|
||||
auto& availableForReserves = std::get<0>(stateMap[acc]);
|
||||
auto& namespaceCount = std::get<1>(stateMap[acc]);
|
||||
auto& stateMapAcc = std::get<2>(stateMap[acc]);
|
||||
bool const canReserveNew = availableForReserves > 0;
|
||||
|
||||
if (stateMapAcc.find(ns) == stateMapAcc.end())
|
||||
@@ -1360,6 +1440,18 @@ set_state_cache(
|
||||
if (!canReserveNew)
|
||||
return RESERVE_INSUFFICIENT;
|
||||
|
||||
if (createNamespace)
|
||||
{
|
||||
// overflow should never ever happen but check anyway
|
||||
if (namespaceCount + 1 < namespaceCount)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
if (namespaceCount + 1 > hook::maxNamespaces())
|
||||
return TOO_MANY_NAMESPACES;
|
||||
|
||||
namespaceCount++;
|
||||
}
|
||||
|
||||
availableForReserves--;
|
||||
stateMap.modified_entry_count++;
|
||||
}
|
||||
@@ -1488,6 +1580,13 @@ DEFINE_HOOK_FUNCTION(
|
||||
auto const key = make_state_key(
|
||||
std::string_view{(const char*)(memory + kread_ptr), (size_t)kread_len});
|
||||
|
||||
if (view.rules().enabled(fixXahauV1))
|
||||
{
|
||||
auto const sleAccount = view.peek(hookCtx.result.accountKeylet);
|
||||
if (!sleAccount)
|
||||
return tefINTERNAL;
|
||||
}
|
||||
|
||||
if (!key)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
@@ -1610,7 +1709,7 @@ hook::finalizeHookState(
|
||||
for (const auto& accEntry : stateMap)
|
||||
{
|
||||
const auto& acc = accEntry.first;
|
||||
for (const auto& nsEntry : accEntry.second.second)
|
||||
for (const auto& nsEntry : std::get<2>(accEntry.second))
|
||||
{
|
||||
const auto& ns = nsEntry.first;
|
||||
for (const auto& cacheEntry : nsEntry.second)
|
||||
|
||||
@@ -39,10 +39,26 @@ CancelOffer::preflight(PreflightContext const& ctx)
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
|
||||
if (!ctx.tx[sfOfferSequence])
|
||||
if (ctx.rules.enabled(fixXahauV1))
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "CancelOffer::preflight: missing sequence";
|
||||
return temBAD_SEQUENCE;
|
||||
if ((!ctx.tx.isFieldPresent(sfOfferSequence) &&
|
||||
!ctx.tx.isFieldPresent(sfOfferID)) ||
|
||||
(ctx.tx.isFieldPresent(sfOfferSequence) &&
|
||||
ctx.tx.isFieldPresent(sfOfferID)))
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "CancelOffer::preflight: invalid sequence or offer id";
|
||||
return temBAD_SEQUENCE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ctx.tx.isFieldPresent(sfOfferSequence) ||
|
||||
ctx.tx[sfOfferSequence] == 0)
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "CancelOffer::preflight: missing sequence";
|
||||
return temBAD_SEQUENCE;
|
||||
}
|
||||
}
|
||||
|
||||
return preflight2(ctx);
|
||||
@@ -54,29 +70,18 @@ TER
|
||||
CancelOffer::preclaim(PreclaimContext const& ctx)
|
||||
{
|
||||
auto const id = ctx.tx[sfAccount];
|
||||
auto const offerSequence = ctx.tx[sfOfferSequence];
|
||||
|
||||
auto const sle = ctx.view.read(keylet::account(id));
|
||||
if (!sle)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
bool hooksEnabled = ctx.view.rules().enabled(featureHooks);
|
||||
auto const offerSequence = ctx.tx[~sfOfferSequence];
|
||||
|
||||
auto const offerID = ctx.tx[~sfOfferID];
|
||||
|
||||
if ((*sle)[sfSequence] <= offerSequence)
|
||||
if (offerSequence && (*sle)[sfSequence] <= *offerSequence)
|
||||
{
|
||||
if (hooksEnabled && offerID && offerSequence == 0)
|
||||
{
|
||||
// pass, here the txn provides offerID instead of offerSequence
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "Malformed transaction: "
|
||||
<< "Sequence " << offerSequence << " is invalid.";
|
||||
return temBAD_SEQUENCE;
|
||||
}
|
||||
JLOG(ctx.j.trace()) << "Malformed transaction: "
|
||||
<< "Sequence " << *offerSequence << " is invalid.";
|
||||
return temBAD_SEQUENCE;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
@@ -87,36 +92,32 @@ CancelOffer::preclaim(PreclaimContext const& ctx)
|
||||
TER
|
||||
CancelOffer::doApply()
|
||||
{
|
||||
auto const offerSequence = ctx_.tx[sfOfferSequence];
|
||||
|
||||
auto const sle = view().read(keylet::account(account_));
|
||||
if (!sle)
|
||||
return tefINTERNAL;
|
||||
|
||||
auto const offerSequence = ctx_.tx[~sfOfferSequence];
|
||||
auto const offerID = ctx_.tx[~sfOfferID];
|
||||
|
||||
bool hooksEnabled = view().rules().enabled(featureHooks);
|
||||
|
||||
std::optional<uint256> offerID;
|
||||
|
||||
if (hooksEnabled)
|
||||
offerID = ctx_.tx[~sfOfferID];
|
||||
|
||||
Keylet cancel = hooksEnabled && offerID && offerSequence == 0
|
||||
Keylet cancel = hooksEnabled && offerID && !offerSequence
|
||||
? Keylet(ltOFFER, *offerID)
|
||||
: keylet::offer(account_, offerSequence);
|
||||
: keylet::offer(account_, *offerSequence);
|
||||
|
||||
if (auto sleOffer = view().peek(cancel))
|
||||
{
|
||||
if (offerID)
|
||||
JLOG(j_.debug()) << "Trying to cancel offer :" << *offerID;
|
||||
else
|
||||
JLOG(j_.debug()) << "Trying to cancel offer #" << offerSequence;
|
||||
JLOG(j_.debug()) << "Trying to cancel offer #" << *offerSequence;
|
||||
return offerDelete(view(), sleOffer, ctx_.app.journal("View"));
|
||||
}
|
||||
|
||||
if (offerID)
|
||||
JLOG(j_.debug()) << "Offer :" << *offerID << " can't be found.";
|
||||
else
|
||||
JLOG(j_.debug()) << "Offer #" << offerSequence << " can't be found.";
|
||||
JLOG(j_.debug()) << "Offer #" << *offerSequence << " can't be found.";
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -431,6 +431,10 @@ EscrowFinish::preflight(PreflightContext const& ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx.tx.isFieldPresent(sfEscrowID) &&
|
||||
!ctx.tx.isFieldPresent(sfOfferSequence))
|
||||
return temMALFORMED;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -456,13 +460,21 @@ EscrowFinish::doApply()
|
||||
return temDISABLED;
|
||||
|
||||
std::optional<uint256> escrowID = ctx_.tx[~sfEscrowID];
|
||||
std::optional<std::uint32_t> offerSequence = ctx_.tx[~sfOfferSequence];
|
||||
|
||||
if (escrowID && ctx_.tx[sfOfferSequence] != 0)
|
||||
return temMALFORMED;
|
||||
if (!view().rules().enabled(fixXahauV1))
|
||||
{
|
||||
if (escrowID && ctx_.tx[sfOfferSequence] != 0)
|
||||
return temMALFORMED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (escrowID && offerSequence)
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
Keylet k = escrowID
|
||||
? Keylet(ltESCROW, *escrowID)
|
||||
: keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
|
||||
Keylet k = escrowID ? Keylet(ltESCROW, *escrowID)
|
||||
: keylet::escrow(ctx_.tx[sfOwner], *offerSequence);
|
||||
|
||||
auto const slep = ctx_.view().peek(k);
|
||||
if (!slep)
|
||||
@@ -692,6 +704,10 @@ EscrowCancel::preflight(PreflightContext const& ctx)
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (!ctx.tx.isFieldPresent(sfEscrowID) &&
|
||||
!ctx.tx.isFieldPresent(sfOfferSequence))
|
||||
return temMALFORMED;
|
||||
|
||||
return preflight2(ctx);
|
||||
}
|
||||
|
||||
@@ -704,13 +720,21 @@ EscrowCancel::doApply()
|
||||
return temDISABLED;
|
||||
|
||||
std::optional<uint256> escrowID = ctx_.tx[~sfEscrowID];
|
||||
std::optional<std::uint32_t> offerSequence = ctx_.tx[~sfOfferSequence];
|
||||
|
||||
if (escrowID && ctx_.tx[sfOfferSequence] != 0)
|
||||
return temMALFORMED;
|
||||
if (!view().rules().enabled(fixXahauV1))
|
||||
{
|
||||
if (escrowID && ctx_.tx[sfOfferSequence] != 0)
|
||||
return temMALFORMED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (escrowID && offerSequence)
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
Keylet k = escrowID
|
||||
? Keylet(ltESCROW, *escrowID)
|
||||
: keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
|
||||
Keylet k = escrowID ? Keylet(ltESCROW, *escrowID)
|
||||
: keylet::escrow(ctx_.tx[sfOwner], *offerSequence);
|
||||
|
||||
auto const slep = ctx_.view().peek(k);
|
||||
if (!slep)
|
||||
|
||||
@@ -74,6 +74,8 @@ GenesisMint::preflight(PreflightContext const& ctx)
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
bool const allowDuplicates = ctx.rules.enabled(fixXahauV1);
|
||||
|
||||
std::unordered_set<AccountID> alreadySeen;
|
||||
for (auto const& dest : dests)
|
||||
{
|
||||
@@ -137,6 +139,9 @@ GenesisMint::preflight(PreflightContext const& ctx)
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (allowDuplicates)
|
||||
continue;
|
||||
|
||||
if (alreadySeen.find(accid) != alreadySeen.end())
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "GenesisMint: duplicate in destinations.";
|
||||
@@ -171,7 +176,114 @@ GenesisMint::doApply()
|
||||
{
|
||||
auto const& dests = ctx_.tx.getFieldArray(sfGenesisMints);
|
||||
|
||||
if (!view().rules().enabled(fixXahauV1))
|
||||
{
|
||||
STAmount dropsAdded{0};
|
||||
for (auto const& dest : dests)
|
||||
{
|
||||
auto const amt = dest[~sfAmount];
|
||||
|
||||
if (amt && !isXRP(*amt))
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: Non-xrp amount.";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
auto const flags = dest[~sfGovernanceFlags];
|
||||
auto const marks = dest[~sfGovernanceMarks];
|
||||
|
||||
auto const id = dest.getAccountID(sfDestination);
|
||||
auto const k = keylet::account(id);
|
||||
auto sle = view().peek(k);
|
||||
|
||||
bool const created = !sle;
|
||||
|
||||
if (created)
|
||||
{
|
||||
// Create the account.
|
||||
std::uint32_t const seqno{
|
||||
view().info().parentCloseTime.time_since_epoch().count()};
|
||||
|
||||
sle = std::make_shared<SLE>(k);
|
||||
sle->setAccountID(sfAccount, id);
|
||||
|
||||
sle->setFieldU32(sfSequence, seqno);
|
||||
|
||||
if (amt)
|
||||
{
|
||||
sle->setFieldAmount(sfBalance, *amt);
|
||||
dropsAdded += *amt;
|
||||
}
|
||||
else // give them 2 XRP if the account didn't exist, same as
|
||||
// ttIMPORT
|
||||
{
|
||||
XRPAmount const initialXrp =
|
||||
Import::computeStartingBonus(ctx_.view());
|
||||
sle->setFieldAmount(sfBalance, initialXrp);
|
||||
dropsAdded += initialXrp;
|
||||
}
|
||||
}
|
||||
else if (amt)
|
||||
{
|
||||
// Credit the account
|
||||
STAmount startBal = sle->getFieldAmount(sfBalance);
|
||||
STAmount finalBal = startBal + *amt;
|
||||
if (finalBal <= startBal)
|
||||
{
|
||||
JLOG(ctx_.journal.warn())
|
||||
<< "GenesisMint: cannot credit " << dest
|
||||
<< " due to balance overflow";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
sle->setFieldAmount(sfBalance, finalBal);
|
||||
dropsAdded += *amt;
|
||||
}
|
||||
|
||||
// set flags and marks as applicable
|
||||
if (flags)
|
||||
sle->setFieldH256(sfGovernanceFlags, *flags);
|
||||
|
||||
if (marks)
|
||||
sle->setFieldH256(sfGovernanceMarks, *marks);
|
||||
|
||||
if (created)
|
||||
view().insert(sle);
|
||||
else
|
||||
view().update(sle);
|
||||
}
|
||||
|
||||
// update ledger header
|
||||
if (dropsAdded < beast::zero ||
|
||||
dropsAdded.xrp() + view().info().drops < view().info().drops)
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: dropsAdded overflowed\n";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
if (dropsAdded > beast::zero)
|
||||
ctx_.rawView().rawDestroyXRP(-dropsAdded.xrp());
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
// RH NOTE:
|
||||
// As of fixXahauV1, duplicate accounts are allowed
|
||||
// so we first do a summation loop then an actioning loop
|
||||
// if amendment is not active then there's exactly one entry per
|
||||
|
||||
std::map<
|
||||
AccountID, // account to credit
|
||||
std::tuple<
|
||||
XRPAmount, // amount to credit
|
||||
std::optional<uint256>, // gov flags
|
||||
std::optional<uint256>>> // gov marks
|
||||
|
||||
mints;
|
||||
|
||||
STAmount dropsAdded{0};
|
||||
|
||||
// sum loop
|
||||
for (auto const& dest : dests)
|
||||
{
|
||||
auto const amt = dest[~sfAmount];
|
||||
@@ -182,13 +294,54 @@ GenesisMint::doApply()
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
XRPAmount toCredit = amt ? amt->xrp() : XRPAmount{0};
|
||||
|
||||
auto const flags = dest[~sfGovernanceFlags];
|
||||
auto const marks = dest[~sfGovernanceMarks];
|
||||
|
||||
auto const id = dest.getAccountID(sfDestination);
|
||||
auto const k = keylet::account(id);
|
||||
auto sle = view().peek(k);
|
||||
|
||||
bool const firstOccurance = mints.find(id) == mints.end();
|
||||
|
||||
dropsAdded += toCredit;
|
||||
|
||||
// if flags / marks appear more than once we just take the first
|
||||
// appearance
|
||||
if (firstOccurance)
|
||||
mints[id] = {toCredit, flags, marks};
|
||||
else
|
||||
{
|
||||
// duplicated entries accumulate in the map
|
||||
|
||||
auto& [accTotal, f, m] = mints[id];
|
||||
|
||||
// detect overflow
|
||||
if (accTotal + toCredit < accTotal)
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: cannot credit " << id
|
||||
<< " due to balance overflow";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
accTotal += toCredit;
|
||||
}
|
||||
}
|
||||
|
||||
// check for ledger header overflow
|
||||
if (dropsAdded < beast::zero ||
|
||||
dropsAdded.xrp() + view().info().drops < view().info().drops)
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: dropsAdded overflowed\n";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
// action loop
|
||||
for (auto const& [id, values] : mints)
|
||||
{
|
||||
auto const& [amt, flags, marks] = values;
|
||||
|
||||
auto const k = keylet::account(id);
|
||||
auto sle = view().peek(k);
|
||||
bool const created = !sle;
|
||||
|
||||
if (created)
|
||||
@@ -202,34 +355,21 @@ GenesisMint::doApply()
|
||||
|
||||
sle->setFieldU32(sfSequence, seqno);
|
||||
|
||||
if (amt)
|
||||
{
|
||||
sle->setFieldAmount(sfBalance, *amt);
|
||||
dropsAdded += *amt;
|
||||
}
|
||||
else // give them 2 XRP if the account didn't exist, same as
|
||||
// ttIMPORT
|
||||
{
|
||||
XRPAmount const initialXrp =
|
||||
Import::computeStartingBonus(ctx_.view());
|
||||
sle->setFieldAmount(sfBalance, initialXrp);
|
||||
dropsAdded += initialXrp;
|
||||
}
|
||||
sle->setFieldAmount(sfBalance, amt);
|
||||
}
|
||||
else if (amt)
|
||||
else if (amt > beast::zero)
|
||||
{
|
||||
// Credit the account
|
||||
STAmount startBal = sle->getFieldAmount(sfBalance);
|
||||
STAmount finalBal = startBal + *amt;
|
||||
STAmount finalBal = startBal + amt;
|
||||
if (finalBal <= startBal)
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: cannot credit "
|
||||
<< dest << " due to balance overflow";
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: cannot credit " << id
|
||||
<< " due to balance overflow";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
sle->setFieldAmount(sfBalance, finalBal);
|
||||
dropsAdded += *amt;
|
||||
}
|
||||
|
||||
// set flags and marks as applicable
|
||||
@@ -245,14 +385,6 @@ GenesisMint::doApply()
|
||||
view().update(sle);
|
||||
}
|
||||
|
||||
// update ledger header
|
||||
if (dropsAdded < beast::zero ||
|
||||
dropsAdded.xrp() + view().info().drops < view().info().drops)
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: dropsAdded overflowed\n";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
if (dropsAdded > beast::zero)
|
||||
ctx_.rawView().rawDestroyXRP(-dropsAdded.xrp());
|
||||
|
||||
|
||||
@@ -710,7 +710,6 @@ Import::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
auto const& data = (*xpop)[jss::validation][jss::data];
|
||||
std::set<std::string> used_key;
|
||||
|
||||
for (const auto& key : data.getMemberNames())
|
||||
{
|
||||
auto nodepub = key;
|
||||
@@ -818,7 +817,17 @@ Import::preflight(PreflightContext const& ctx)
|
||||
<< " validation count: " << validationCount;
|
||||
|
||||
// check if the validation count is adequate
|
||||
if (quorum >= validationCount)
|
||||
auto hasInsufficientQuorum = [&ctx](int quorum, int validationCount) {
|
||||
if (ctx.rules.enabled(fixXahauV1))
|
||||
{
|
||||
return quorum > validationCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
return quorum >= validationCount;
|
||||
}
|
||||
};
|
||||
if (hasInsufficientQuorum(quorum, validationCount))
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Import: xpop did not contain an 80% quorum for "
|
||||
"the txn it purports to prove. "
|
||||
|
||||
@@ -1856,6 +1856,10 @@ SetHook::setHook()
|
||||
else if (oldHookSLE && !newHooksEmpty)
|
||||
{
|
||||
// UPDATE ltHOOK
|
||||
if (view().rules().enabled(fixXahauV1))
|
||||
{
|
||||
(*newHookSLE)[sfOwnerNode] = (*oldHookSLE)[sfOwnerNode];
|
||||
}
|
||||
view().erase(oldHookSLE);
|
||||
view().insert(newHookSLE);
|
||||
}
|
||||
|
||||
@@ -130,6 +130,8 @@ ApplyStateTable::generateTxMeta(
|
||||
if (!hookEmission.empty())
|
||||
meta.setHookEmissions(STArray{hookEmission, sfHookEmissions});
|
||||
|
||||
bool const recordDefaultAmounts = to.rules().enabled(fixXahauV1);
|
||||
|
||||
Mods newMod;
|
||||
for (auto& item : items_)
|
||||
{
|
||||
@@ -232,8 +234,12 @@ ApplyStateTable::generateTxMeta(
|
||||
STObject news(sfNewFields);
|
||||
for (auto const& obj : *curNode)
|
||||
{
|
||||
bool const shouldRecord =
|
||||
(obj.getSType() == STI_AMOUNT && recordDefaultAmounts) ||
|
||||
!obj.isDefault();
|
||||
|
||||
// save non-default values
|
||||
if (!obj.isDefault() &&
|
||||
if (shouldRecord &&
|
||||
obj.getFName().shouldMeta(
|
||||
SField::sMD_Create | SField::sMD_Always))
|
||||
news.emplace_back(obj);
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace detail {
|
||||
// Feature.cpp. Because it's only used to reserve storage, and determine how
|
||||
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
|
||||
// the actual number of amendments. A LogicError on startup will verify this.
|
||||
static constexpr std::size_t numFeatures = 66;
|
||||
static constexpr std::size_t numFeatures = 67;
|
||||
|
||||
/** Amendments that this server supports and the default voting behavior.
|
||||
Whether they are enabled depends on the Rules defined in the validated
|
||||
@@ -354,6 +354,7 @@ extern uint256 const featureImport;
|
||||
extern uint256 const featureXahauGenesis;
|
||||
extern uint256 const featureHooksUpdate1;
|
||||
extern uint256 const fixURITokenV1;
|
||||
extern uint256 const fixXahauV1;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
|
||||
@@ -460,6 +460,7 @@ REGISTER_FEATURE(Import, Supported::yes, VoteBehavior::De
|
||||
REGISTER_FEATURE(XahauGenesis, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FEATURE(HooksUpdate1, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fixURITokenV1, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (fixXahauV1, Supported::yes, VoteBehavior::DefaultNo);
|
||||
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
|
||||
@@ -88,7 +88,7 @@ TxFormats::TxFormats()
|
||||
add(jss::OfferCancel,
|
||||
ttOFFER_CANCEL,
|
||||
{
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
{sfOfferSequence, soeOPTIONAL},
|
||||
{sfOfferID, soeOPTIONAL}, // keylet as alternative to offerseq
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
},
|
||||
@@ -133,7 +133,7 @@ TxFormats::TxFormats()
|
||||
ttESCROW_FINISH,
|
||||
{
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
{sfOfferSequence, soeOPTIONAL},
|
||||
{sfEscrowID, soeOPTIONAL}, // keylet as alternative to offerseq
|
||||
{sfFulfillment, soeOPTIONAL},
|
||||
{sfCondition, soeOPTIONAL},
|
||||
@@ -145,7 +145,7 @@ TxFormats::TxFormats()
|
||||
ttESCROW_CANCEL,
|
||||
{
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
{sfOfferSequence, soeOPTIONAL},
|
||||
{sfEscrowID, soeOPTIONAL}, // keylet as alternative to offerseq
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
},
|
||||
|
||||
+191
-103
@@ -4256,128 +4256,216 @@ struct Escrow_test : public beast::unit_test::suite
|
||||
auto const gw = Account{"gateway"};
|
||||
auto const USD = gw["USD"];
|
||||
|
||||
Env env{*this, features};
|
||||
env.fund(XRP(10000), alice, bob, gw);
|
||||
env.close();
|
||||
env.trust(USD(1000000), alice);
|
||||
env.trust(USD(1000000), bob);
|
||||
env.close();
|
||||
env(pay(gw, alice, USD(10000)));
|
||||
env(pay(gw, bob, USD(10000)));
|
||||
env.close();
|
||||
|
||||
// EscrowCancel - EscrowID
|
||||
for (bool const withXahauV1 : {true, false})
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
escrow::cancel_time(env.now() + 2s),
|
||||
fee(1500));
|
||||
auto const amend = withXahauV1 ? features : features - fixXahauV1;
|
||||
Env env{*this, amend};
|
||||
env.fund(XRP(10000), alice, bob, gw);
|
||||
env.close();
|
||||
env.trust(USD(1000000), alice);
|
||||
env.trust(USD(1000000), bob);
|
||||
env.close();
|
||||
env(pay(gw, alice, USD(10000)));
|
||||
env(pay(gw, bob, USD(10000)));
|
||||
env.close();
|
||||
|
||||
env(escrow::cancel(bob, alice, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500));
|
||||
env.close();
|
||||
// EscrowCancel - EscrowID
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
escrow::cancel_time(env.now() + 2s),
|
||||
fee(1500));
|
||||
env.close();
|
||||
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(!escrowLE);
|
||||
}
|
||||
if (withXahauV1)
|
||||
{
|
||||
// withXahauV1 - no OfferSequence
|
||||
env(escrow::cancel(bob, alice),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// !withXahauV1 - OfferSequence == 0
|
||||
env(escrow::cancel(bob, alice, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
}
|
||||
|
||||
// EscrowCancel - no EscrowID or OfferSequence
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
escrow::cancel_time(env.now() + 2s),
|
||||
fee(1500));
|
||||
env.close();
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(!escrowLE);
|
||||
}
|
||||
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::EscrowCancel;
|
||||
jv[jss::Flags] = tfUniversal;
|
||||
jv[jss::Account] = bob.human();
|
||||
jv[sfOwner.jsonName] = alice.human();
|
||||
env(jv, fee(1500), ter(temMALFORMED));
|
||||
env.close();
|
||||
// EscrowCancel - no EscrowID or OfferSequence
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
escrow::cancel_time(env.now() + 2s),
|
||||
fee(1500));
|
||||
env.close();
|
||||
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(escrowLE);
|
||||
}
|
||||
env(escrow::cancel(bob, alice), fee(1500), ter(temMALFORMED));
|
||||
env.close();
|
||||
|
||||
// EscrowCancel - EscrowID & OfferSequence
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
escrow::cancel_time(env.now() + 2s),
|
||||
fee(1500));
|
||||
env.close();
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(escrowLE);
|
||||
}
|
||||
|
||||
env(escrow::cancel(bob, alice, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
// EscrowCancel - EscrowID & OfferSequence
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
auto const seq = env.seq(alice);
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
escrow::cancel_time(env.now() + 2s),
|
||||
fee(1500));
|
||||
env.close();
|
||||
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(!escrowLE);
|
||||
}
|
||||
env(escrow::cancel(bob, alice, seq),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(temMALFORMED));
|
||||
env.close();
|
||||
|
||||
// EscrowFinish - EscrowID
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
fee(1500));
|
||||
env.close(5s);
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(escrowLE);
|
||||
}
|
||||
|
||||
env(escrow::finish(bob, alice, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500));
|
||||
env.close();
|
||||
// EscrowCancel - EscrowID & OfferSequence 0
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
escrow::cancel_time(env.now() + 2s),
|
||||
fee(1500));
|
||||
env.close();
|
||||
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(!escrowLE);
|
||||
}
|
||||
if (withXahauV1)
|
||||
{
|
||||
// withXahauV1 - OfferSequence 0 == temMALFORMED
|
||||
env(escrow::cancel(bob, alice, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(temMALFORMED));
|
||||
env.close();
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(escrowLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// withXahauV1 - OfferSequence 0 == tesSUCCESS
|
||||
env(escrow::cancel(bob, alice, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(!escrowLE);
|
||||
}
|
||||
}
|
||||
|
||||
// EscrowFinish - no EscrowID or OfferSequence
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
escrow::cancel_time(env.now() + 2s),
|
||||
fee(1500));
|
||||
env.close();
|
||||
// EscrowFinish - EscrowID
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
fee(1500));
|
||||
env.close(5s);
|
||||
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::EscrowFinish;
|
||||
jv[jss::Flags] = tfUniversal;
|
||||
jv[jss::Account] = bob.human();
|
||||
jv[sfOwner.jsonName] = alice.human();
|
||||
env(jv, fee(1500), ter(temMALFORMED));
|
||||
env.close();
|
||||
if (withXahauV1)
|
||||
{
|
||||
// withXahauV1 - no OfferSequence
|
||||
env(escrow::finish(bob, alice),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// !withXahauV1 - OfferSequence == 0
|
||||
env(escrow::finish(bob, alice, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
}
|
||||
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(escrowLE);
|
||||
}
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(!escrowLE);
|
||||
}
|
||||
|
||||
// EscrowFinish- EscrowID & OfferSequence
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
fee(1500));
|
||||
env.close(5s);
|
||||
// EscrowFinish - no EscrowID or OfferSequence
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
fee(1500));
|
||||
env.close();
|
||||
|
||||
env(escrow::finish(bob, alice, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
env(escrow::finish(bob, alice), fee(1500), ter(temMALFORMED));
|
||||
env.close();
|
||||
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(!escrowLE);
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(escrowLE);
|
||||
}
|
||||
|
||||
// EscrowFinish- EscrowID & OfferSequence
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
auto const seq = env.seq(alice);
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
fee(1500));
|
||||
env.close(5s);
|
||||
|
||||
env(escrow::finish(bob, alice, seq),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(temMALFORMED));
|
||||
env.close();
|
||||
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(escrowLE);
|
||||
}
|
||||
|
||||
// EscrowFinish- EscrowID & OfferSequence 0
|
||||
{
|
||||
uint256 const escrowId{getEscrowIndex(alice, env.seq(alice))};
|
||||
env(escrow::create(alice, bob, USD(1000)),
|
||||
escrow::finish_time(env.now() + 1s),
|
||||
fee(1500));
|
||||
env.close(5s);
|
||||
|
||||
if (withXahauV1)
|
||||
{
|
||||
// withXahauV1 - OfferSequence 0 == temMALFORMED
|
||||
env(escrow::finish(bob, alice, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(temMALFORMED));
|
||||
env.close();
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(escrowLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// !withXahauV1 - OfferSequence 0 == tesSUCCESS
|
||||
env(escrow::finish(bob, alice, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(1500),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
auto const escrowLE = env.le(keylet::unchecked(escrowId));
|
||||
BEAST_EXPECT(!escrowLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,34 @@ namespace ripple {
|
||||
namespace test {
|
||||
struct GenesisMint_test : public beast::unit_test::suite
|
||||
{
|
||||
void
|
||||
validateEmittedTxn(jtx::Env& env, std::string result, uint64_t lineno)
|
||||
{
|
||||
// get the emitted txn id
|
||||
Json::Value params;
|
||||
params[jss::transaction] =
|
||||
env.tx()->getJson(JsonOptions::none)[jss::hash];
|
||||
auto const jrr = env.rpc("json", "tx", to_string(params));
|
||||
auto const meta = jrr[jss::result][jss::meta];
|
||||
auto const emissions = meta[sfHookEmissions.jsonName];
|
||||
auto const emission = emissions[0u][sfHookEmission.jsonName];
|
||||
auto const txId = emission[sfEmittedTxnID.jsonName];
|
||||
env.close();
|
||||
|
||||
// verify emitted result
|
||||
Json::Value params1;
|
||||
params1[jss::transaction] = txId;
|
||||
auto const jrr1 = env.rpc("json", "tx", to_string(params1));
|
||||
auto const meta1 = jrr1[jss::result][jss::meta];
|
||||
BEAST_EXPECT(meta1[sfTransactionResult.jsonName] == result);
|
||||
if (meta1[sfTransactionResult.jsonName] != result)
|
||||
{
|
||||
std::cout << "validateEmittedTxn failed " << lineno
|
||||
<< " expected: " << result
|
||||
<< " result: " << meta1[sfTransactionResult.jsonName]
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
void
|
||||
testDisabled(FeatureBitset features)
|
||||
{
|
||||
@@ -151,7 +179,9 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
ter(tesSUCCESS));
|
||||
|
||||
env.close();
|
||||
env.close();
|
||||
|
||||
// validate emitted txn
|
||||
validateEmittedTxn(env, "tesSUCCESS", __LINE__);
|
||||
|
||||
{
|
||||
auto acc = env.le(keylet::account(bob.id()));
|
||||
@@ -190,7 +220,10 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
ter(tesSUCCESS));
|
||||
|
||||
env.close();
|
||||
env.close();
|
||||
|
||||
// validate emitted txn
|
||||
validateEmittedTxn(env, "tesSUCCESS", __LINE__);
|
||||
|
||||
env.close();
|
||||
|
||||
{
|
||||
@@ -229,7 +262,9 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
fee(XRP(1)));
|
||||
|
||||
env.close();
|
||||
env.close();
|
||||
|
||||
// validate emitted txn
|
||||
validateEmittedTxn(env, "tesSUCCESS", __LINE__);
|
||||
|
||||
for (auto const& [acc, amt, _, __] : mints)
|
||||
{
|
||||
@@ -242,7 +277,9 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
fee(XRP(1)));
|
||||
|
||||
env.close();
|
||||
env.close();
|
||||
|
||||
// validate emitted txn
|
||||
validateEmittedTxn(env, "tesSUCCESS", __LINE__);
|
||||
|
||||
for (auto const& [acc, amt, _, __] : mints)
|
||||
{
|
||||
@@ -295,23 +332,11 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
|
||||
env.close();
|
||||
|
||||
// get the emitted txn id
|
||||
Json::Value params;
|
||||
params[jss::transaction] =
|
||||
env.tx()->getJson(JsonOptions::none)[jss::hash];
|
||||
auto const jrr = env.rpc("json", "tx", to_string(params));
|
||||
auto const meta = jrr[jss::result][jss::meta];
|
||||
auto const emissions = meta[sfHookEmissions.jsonName];
|
||||
auto const emission = emissions[0u][sfHookEmission.jsonName];
|
||||
auto const txId = emission[sfEmittedTxnID.jsonName];
|
||||
env.close();
|
||||
|
||||
// verify emitted result
|
||||
Json::Value params1;
|
||||
params1[jss::transaction] = txId;
|
||||
auto const jrr1 = env.rpc("json", "tx", to_string(params1));
|
||||
auto const meta1 = jrr1[jss::result][jss::meta];
|
||||
BEAST_EXPECT(meta1[sfTransactionResult.jsonName] == "tecINTERNAL");
|
||||
// validate emitted txn
|
||||
auto const txResult = env.current()->rules().enabled(fixXahauV1)
|
||||
? "tesSUCCESS"
|
||||
: "tecINTERNAL";
|
||||
validateEmittedTxn(env, txResult, __LINE__);
|
||||
}
|
||||
|
||||
// missing an amount
|
||||
@@ -354,7 +379,9 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
fee(XRP(1)));
|
||||
|
||||
env.close();
|
||||
env.close();
|
||||
|
||||
// validate emitted txn
|
||||
validateEmittedTxn(env, "tesSUCCESS", __LINE__);
|
||||
}
|
||||
|
||||
// check that alice has the right balance, and Governance Flags set
|
||||
@@ -378,7 +405,9 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
fee(XRP(1)));
|
||||
|
||||
env.close();
|
||||
env.close();
|
||||
|
||||
// validate emitted txn
|
||||
validateEmittedTxn(env, "tesSUCCESS", __LINE__);
|
||||
}
|
||||
|
||||
// check that bob has the right balance, and Governance Marks set
|
||||
@@ -403,7 +432,9 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
fee(XRP(1)));
|
||||
|
||||
env.close();
|
||||
env.close();
|
||||
|
||||
// validate emitted txn
|
||||
validateEmittedTxn(env, "tesSUCCESS", __LINE__);
|
||||
}
|
||||
|
||||
// check
|
||||
@@ -430,9 +461,12 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
XRP(0).value(),
|
||||
std::nullopt,
|
||||
std::nullopt}})),
|
||||
fee(XRP(1)));
|
||||
env.close();
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// validate emitted txn
|
||||
validateEmittedTxn(env, "tesSUCCESS", __LINE__);
|
||||
}
|
||||
|
||||
// check
|
||||
@@ -500,7 +534,9 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
std::nullopt}})),
|
||||
fee(XRP(1)));
|
||||
env.close();
|
||||
env.close();
|
||||
|
||||
// validate emitted txn
|
||||
validateEmittedTxn(env, "tesSUCCESS", __LINE__);
|
||||
}
|
||||
|
||||
// check
|
||||
@@ -525,11 +561,19 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
env.close();
|
||||
|
||||
// validate emitted txn
|
||||
validateEmittedTxn(env, "tesSUCCESS", __LINE__);
|
||||
}
|
||||
|
||||
auto const amtResult = env.current()->rules().enabled(fixXahauV1)
|
||||
? 30000000ULL
|
||||
: 10000000ULL;
|
||||
// try to include the same destination twice
|
||||
{
|
||||
auto const txResult = env.current()->rules().enabled(fixXahauV1)
|
||||
? ter(tesSUCCESS)
|
||||
: ter(tecHOOK_REJECTED);
|
||||
env(invoke::invoke(
|
||||
invoker,
|
||||
env.master,
|
||||
@@ -544,7 +588,7 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
std::nullopt},
|
||||
})),
|
||||
fee(XRP(1)),
|
||||
ter(tecHOOK_REJECTED));
|
||||
txResult);
|
||||
env.close();
|
||||
env.close();
|
||||
}
|
||||
@@ -554,7 +598,7 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
auto const le = env.le(keylet::account(greg.id()));
|
||||
BEAST_EXPECT(
|
||||
!!le &&
|
||||
le->getFieldAmount(sfBalance).xrp().drops() == 10000000ULL);
|
||||
le->getFieldAmount(sfBalance).xrp().drops() == amtResult);
|
||||
}
|
||||
|
||||
// trip the supply cap invariant
|
||||
@@ -572,30 +616,14 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
fee(XRP(1)));
|
||||
env.close();
|
||||
|
||||
// get the emitted txn id
|
||||
Json::Value params;
|
||||
params[jss::transaction] =
|
||||
env.tx()->getJson(JsonOptions::none)[jss::hash];
|
||||
auto const jrr = env.rpc("json", "tx", to_string(params));
|
||||
auto const meta = jrr[jss::result][jss::meta];
|
||||
auto const emissions = meta[sfHookEmissions.jsonName];
|
||||
auto const emission = emissions[0u][sfHookEmission.jsonName];
|
||||
auto const txId = emission[sfEmittedTxnID.jsonName];
|
||||
env.close();
|
||||
|
||||
// verify emitted result
|
||||
Json::Value params1;
|
||||
params1[jss::transaction] = txId;
|
||||
auto const jrr1 = env.rpc("json", "tx", to_string(params1));
|
||||
auto const meta1 = jrr1[jss::result][jss::meta];
|
||||
BEAST_EXPECT(
|
||||
meta1[sfTransactionResult.jsonName] == "tecINVARIANT_FAILED");
|
||||
// validate emitted txn
|
||||
validateEmittedTxn(env, "tecINVARIANT_FAILED", __LINE__);
|
||||
|
||||
// check balance wasn't changed
|
||||
auto const le = env.le(keylet::account(greg.id()));
|
||||
BEAST_EXPECT(
|
||||
!!le &&
|
||||
le->getFieldAmount(sfBalance).xrp().drops() == 10000000ULL);
|
||||
le->getFieldAmount(sfBalance).xrp().drops() == amtResult);
|
||||
|
||||
auto const postCoins = env.current()->info().drops;
|
||||
BEAST_EXPECT(
|
||||
@@ -664,10 +692,11 @@ public:
|
||||
using namespace test::jtx;
|
||||
auto const sa = supported_amendments();
|
||||
testWithFeats(sa);
|
||||
testWithFeats(sa - fixXahauV1);
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(GenesisMint, app, ripple);
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
} // namespace ripple
|
||||
+51
-59
@@ -105,93 +105,85 @@ inline std::string ImportTCAccountSet::max = R"json({
|
||||
})json";
|
||||
inline std::string ImportTCAccountSet::w_seed = R"json({
|
||||
"ledger": {
|
||||
"acroot": "8D612AAAEA2C875978527851BB0727CE64B21D792E91B791FEC769C01410B405",
|
||||
"close": 743212280,
|
||||
"coins": "99999998999999832",
|
||||
"acroot": "3975FE3ACF65A9BCC64F07F49B5AEC93E9176CB8DDFE7B5AEDCDC191EA3A8B8C",
|
||||
"close": 754758421,
|
||||
"coins": "99999998000000000",
|
||||
"cres": 10,
|
||||
"flags": 0,
|
||||
"index": 21,
|
||||
"pclose": 743212272,
|
||||
"phash": "B94C4657B7529C72DDCE970A87E2EB9EE8EE12580ADFE6CF93B8672E4B289BBC",
|
||||
"txroot": "0B7479863581D57CB97867293AA2DD17C2DA4005FC139082925AA5806D956389"
|
||||
"index": 149,
|
||||
"pclose": 754758420,
|
||||
"phash": "8F84F7AB19B38FA4377B34E1234EA613A2A5FE522AF08F0B5E0B957C726A6B15",
|
||||
"txroot": "7B4454B7542F049427CE7A5148BDC385E741F2239C19E71E1CC7E4231A383589"
|
||||
},
|
||||
"transaction": {
|
||||
"blob": "12000322000000002400000014201B00000027201D0000535968400000003B9ACA0073210388935426E0D08083314842EDFBB2D517BD47699F9A4527318A8E10468C97C0527446304402205A21EE95C4EBAAC3BB6E438B86BE0FFF864D7EDAB0827F04621B3C5EB0F84B2002206A025D68D8112C87913F228ED47C7CDFE79E217186056876E3FE60C8D0D7BB5E8114AE123A8556F3CF91154711376AFB0F894F832B3D",
|
||||
"meta": "201C00000002F8E51100612500000014550664762F06918B9DDF5D8933481466D394E8D137DE112C9EFC74AE00F5B1BD0D5692FA6A9FC8EA6018D5D16532D7795C91BFB0831355BDFDA177E86C8BF997985FE624000000146240000002540BE400E1E7220000000024000000152D00000000624000000218711A008114AE123A8556F3CF91154711376AFB0F894F832B3DE1E1F1031000",
|
||||
"blob": "1200032200000000240000007D201B000000A7201D0000535968400000003B9ACA0073210388935426E0D08083314842EDFBB2D517BD47699F9A4527318A8E10468C97C05274473045022100BED5EC411AA84FF23B26D60673C1B42901E253C72DFD92B326DF11B94FAB653D022072B734E038F30D4693A392B1609DEFCE57508F6BB5A3FBD721CC55DDDE929BCD8114AE123A8556F3CF91154711376AFB0F894F832B3D",
|
||||
"meta": "201C00000003F8E5110061250000009555248470440C362FE1DA9C45D43C68583632588F8D5FAACC0038A60F1C292109875692FA6A9FC8EA6018D5D16532D7795C91BFB0831355BDFDA177E86C8BF997985FE6240000007D624000000218711A00E1E72200000000240000007E2D000000016240000001DCD650008114AE123A8556F3CF91154711376AFB0F894F832B3DE1E1F1031000",
|
||||
"proof": {
|
||||
"children": {
|
||||
"0": {
|
||||
"children": {},
|
||||
"hash": "509C0CFF6C808D0A97271FC67C694D95BF177AF4C47D86CD1182516BDDEB6025",
|
||||
"key": "005D3A84B6EF5A5BF673019F4C583E812F2429D2E6524119498803BD4D82B616"
|
||||
"children": {
|
||||
"2": {
|
||||
"children": {},
|
||||
"hash": "B19EFD49679890EA362F3938AFFC6FCC3D4B57AAE0054F42237E51ADEFC00E2A",
|
||||
"key": "02418867190CC2BBA46600E334985E6915C861DBB69E030D2939CFE1FC94D4CC"
|
||||
},
|
||||
"F": {
|
||||
"children": {},
|
||||
"hash": "48E8A4BAE146645DA9FB45AA126676BF94FA767DBE2FEB63D570175C5C6EABF6",
|
||||
"key": "0F84DB191B9B813AC94EC51EA58B69EB5B5C606A69075A64068F911246DFEFD5"
|
||||
}
|
||||
},
|
||||
"hash": "B9AC3B86E69AFE74C4AE62E2E2A82BBBC4578BE84C093A9E5ECF15FD6C85164D",
|
||||
"key": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"1": {
|
||||
"children": {},
|
||||
"hash": "7049738FBCD2A02C6424D2D0AED1E686525E72CBEE7E1E46665153D547152BEC",
|
||||
"key": "1B0C515B4719732CA8E192DCE7C853EC9FDCB555044C7DBF6304842D1131B3F8"
|
||||
"hash": "8521D6C26199F9F6D54E9522385C44C52E2E3EF48560AE64D3D089BC268A1311",
|
||||
"key": "1F7D6AC7280BA77EC0676E08111CA9FC552C48DA16662B49A197C2996A594574"
|
||||
},
|
||||
"4": {
|
||||
"2": {
|
||||
"children": {},
|
||||
"hash": "DF2BD3EE2061F7B6BA108AFD2E0879BBC7A416F004EC31721B1E35327AC84CC0",
|
||||
"key": "4636DAF80989AD827DB21924CCA58DA67188569631135A5E04E173B7142E2B4F"
|
||||
"hash": "01404B9BC507C42FC466B3BCC056B544DFEEB51E5C3030F90CC63D092DA9EDFF",
|
||||
"key": "248470440C362FE1DA9C45D43C68583632588F8D5FAACC0038A60F1C29210987"
|
||||
},
|
||||
"5": {
|
||||
"children": {},
|
||||
"hash": "E000CC0736630D66DAB573A2642E1BD0646DFB13A871B2CCFA6E4226F477D88C",
|
||||
"key": "52C1D70065FC14B118011B14B3936FF71D97F9F1D21891BBBD2293B27AC6F8BF"
|
||||
"hash": "8A05CC08E8238765E4B94C14E09C2AD218B81F7FDD0415D6FE7F57B9B626899B",
|
||||
"key": "5BC558F8699A824BE7C09A56E1D0A0FACA6F44F57AB7BC0306C8F1C4870FCE1E"
|
||||
},
|
||||
"7": {
|
||||
"children": {
|
||||
"1": {
|
||||
"children": {},
|
||||
"hash": "4156BB37D4BBA887A646879B3585065B95157FA15A0A68DDCA87CC90B6A8E370",
|
||||
"key": "71C688E6B6B99744C01D908E0C75D12D91090BB109E9E39AC08150A973A90810"
|
||||
},
|
||||
"2": {
|
||||
"children": {},
|
||||
"hash": "EA93162C432C54B8CEDA63184FA9F0ABC76C5CB547671AC4069A8EEF7CE1DD1A",
|
||||
"key": "72092AC8B4A50C6E191650344AFC93FE6EDCD00AD4B7D929A524DCCA7DA06074"
|
||||
}
|
||||
},
|
||||
"hash": "191973AFD8C1667F39C050554AC62D67311CD7DE1E406EE7DF8EB0407930D891",
|
||||
"key": "7000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"B": {
|
||||
"children": {
|
||||
"9": {
|
||||
"children": {},
|
||||
"hash": "5109702FDCFFAF311C0AD8E7D4BECE7FA350395A2EAF522A5A7D04337B136B31",
|
||||
"key": "B9448E0093010B019347E2D0BF9C2EB2B8F529877DABFAF7DF4672CFFEC642D8"
|
||||
},
|
||||
"C": {
|
||||
"children": {},
|
||||
"hash": "E80D50B1E6475C8588059C966BBEF247A15D7C8DE0674F0D7122316F9D424BFC",
|
||||
"key": "BCBB6F4F04F0B108630E5CB04E6C9927D2F2621FD83F5548F12D4E44233AC2AA"
|
||||
}
|
||||
},
|
||||
"hash": "01664A1CB97086A0E222BB2FEEE8CD5222E9535064C366CF3DF76A80A17BD7B2",
|
||||
"key": "B000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"F": {
|
||||
"C": {
|
||||
"children": {},
|
||||
"hash": "8C26E194C7B44E108EFF98082D19BB2B739C5F8E6BB0C281D9ECEE11F98C3770",
|
||||
"key": "F4DCF93061C61D249A16934AF83C3EFCE51AD98469AFC65B260C2100683CB761"
|
||||
"hash": "652BC7C2C0F3FBA842AD24BB92C9DBFC2ABBB47D11E5255BD10A5BF5A2F12DEF",
|
||||
"key": "C041798921B80DB9F9B017A27514BE6942ED00CDE078E7E7E1C9F011E0DD9B3D"
|
||||
},
|
||||
"D": {
|
||||
"children": {},
|
||||
"hash": "D4772ADC693366E7ADC55437496A80E0073556CCC6F34F28A3CA22F27B8FC804",
|
||||
"key": "D0F5762BD1D415558E1C825A0933E7A0B2AC648AB719CE224E25E6A1EAEFB51D"
|
||||
}
|
||||
},
|
||||
"hash": "0B7479863581D57CB97867293AA2DD17C2DA4005FC139082925AA5806D956389",
|
||||
"hash": "7B4454B7542F049427CE7A5148BDC385E741F2239C19E71E1CC7E4231A383589",
|
||||
"key": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"validation": {
|
||||
"data": {
|
||||
"n94QWAYxKUHacmyFTnzK4bvqVcUfr6RwtaNxCM2cJRY59UHmz1Fr": "22800000012600000015292C4C84F53A29EC0A36EDAB6C61510AD4F33846A123D86FDAD30CBF175E217BA7B5394A5A761DA5C6B7A45D678DA8501720806024F4F741C65B2E44B005CA293120889A6BC5F1E179335E20384AB3C6D15019B94C4657B7529C72DDCE970A87E2EB9EE8EE12580ADFE6CF93B8672E4B289BBC732103FCA947A7F08B146457BEF95AF0CF7C3ABF0D09CD1DC02099F7185C37BB32807576473045022100BBBE6EDE0B2B61CD369E2188C8FBFACCB35CA2D166FD29D5E3D7B2195083E74302201FAA160136301A43E518B9424A0DA5DC1E7EF8B90DAE2FA87310047498514EB4",
|
||||
"n9KqAeJTJEJaMZNN35SNrPDbs324rwjDPy6BFHjZ4oM4en4snKjf": "22800000012600000015292C4C84F53A434EDA585468FD92510AD4F33846A123D86FDAD30CBF175E217BA7B5394A5A761DA5C6B7A45D678DA8501720806024F4F741C65B2E44B005CA293120889A6BC5F1E179335E20384AB3C6D15019B94C4657B7529C72DDCE970A87E2EB9EE8EE12580ADFE6CF93B8672E4B289BBC732102AB4E3B7C53A4265C51952DD9D2CD2829219CDD4F55F63969E38C5C910F3C5F1C76473045022100A011F2C1F61E78CEF76007BB72CE076255027793052DCF7027B10C0C30BA07AC02202380E5FF8330592C594784C4752736D7177D121763D91795C3AD3FEB7AF3A0B5"
|
||||
"n94J5LCRu9bBWrJiwRWujvuVECVPWbXFcQ2VN38qLD378F5pDSDM": "22800000012600000095292CFCB3163A74499C839A2536F051CAD3AEA30BDAC743D24F91EEF18A03DFB7EDA477194429C9132656ACF85867FA501775530CC549425FB587CBEE269283F976D923CBF68A9AD5C636DE22A96F33FBB350198F84F7AB19B38FA4377B34E1234EA613A2A5FE522AF08F0B5E0B957C726A6B15732103EF7BD71691FE8352670866E018ACD21BE011971500485150AFA1A66DC564667676473045022100CD612D4D66388BC6F5B55C6FC79024419354F7C8F64421E18A2F92F8F12C044E02201E95057C863044378B94BD80D17022CE0FC6FEAF26482FA5C8A02C061BFB0529",
|
||||
"n94M7rLruFgtroHGaxjG81DYKssEfSk5kWK7aiyzcfYKrVVDfZfk": "22800000012600000095292CFCB3163A22A5D454FFFE67CD51CAD3AEA30BDAC743D24F91EEF18A03DFB7EDA477194429C9132656ACF85867FA501775530CC549425FB587CBEE269283F976D923CBF68A9AD5C636DE22A96F33FBB350198F84F7AB19B38FA4377B34E1234EA613A2A5FE522AF08F0B5E0B957C726A6B15732103F5BC074629DFF09DA827417F891FBDCB97B08BF4D4A17715C46D89BF36C8FC2876473045022100E2F7EB279A55545A2241E44BB440A3489612189D7F352FA7756F1C145D707C530220550206F6C48FB16D0C63CE4899BE5DF91DF330BA1CB47BB6310DAD0FC40A1461",
|
||||
"n94U45VGVjD4Gp9aZpuAKJHRF5AJXiARzHmmcR38i4cB3zbHKSWZ": "22800000012600000095292CFCB3163AFC08FE942F7912AF51CAD3AEA30BDAC743D24F91EEF18A03DFB7EDA477194429C9132656ACF85867FA501775530CC549425FB587CBEE269283F976D923CBF68A9AD5C636DE22A96F33FBB350198F84F7AB19B38FA4377B34E1234EA613A2A5FE522AF08F0B5E0B957C726A6B15732103E1177E8CC69B97B21B6C25813CC545BEEA49B03FD668F1701EC29C7FB8E609467647304502210089AD42057DF50C0324F1DC0B4935E124C0C58554369AEE7869E603B8C4AF686102205521AB9889240487CE9ADFE14F5844030D4C2A01B23EF49E53F3C4619A02AF15",
|
||||
"n9KZofcLaHcfujXR4a3E17jKSvyNp8SZHu9rWVjhB9mGFXxB2w4L": "22800000012600000095292CFCB3153ABFAC3C292F2B6FE551CAD3AEA30BDAC743D24F91EEF18A03DFB7EDA477194429C9132656ACF85867FA501775530CC549425FB587CBEE269283F976D923CBF68A9AD5C636DE22A96F33FBB350198F84F7AB19B38FA4377B34E1234EA613A2A5FE522AF08F0B5E0B957C726A6B1573210286A448918DA7F8BF7693552EF9E47AFC57C20D9E090132633D521D32889040C876473045022100D6A52670D463FD1994030A39CEA91E87BA26353B6384FD4218DDA8E3AC8B162E022011295AE9BDDBD41F9489FA3D7E8A36B40D946DC4B39FEA654A77EFEADD112AFA",
|
||||
"n9KjgPCVkmyJdWAVBCVKERdz5Xt6x7dLA1Y7ZqayZzJqVnnG982j": "22800000012600000095292CFCB3173AE187F1490B28C1FA51CAD3AEA30BDAC743D24F91EEF18A03DFB7EDA477194429C9132656ACF85867FA501775530CC549425FB587CBEE269283F976D923CBF68A9AD5C636DE22A96F33FBB350198F84F7AB19B38FA4377B34E1234EA613A2A5FE522AF08F0B5E0B957C726A6B157321029D15B24621B84804E7360DA1CC35F36B8A2771A316A3B83008F85CB370738C2876473045022100A3ECFC40D87E280D7FEDC184BA6DBBE6E77CF6FF08FCF7AE2D4B4FE8CD98B3BF0220726B6A7E9A6AB574EA82A6B5DF628B23C1193A094AF4CC2F28695FFA49CF22BC",
|
||||
"n9L7FECrrDnTTLRJHc7rVxyTsKnjLcQXea5uhTFWxKh3TqnSR2Rz": "22800000012600000095292CFCB3163A89DF43A5821D7C4851CAD3AEA30BDAC743D24F91EEF18A03DFB7EDA477194429C9132656ACF85867FA501775530CC549425FB587CBEE269283F976D923CBF68A9AD5C636DE22A96F33FBB350198F84F7AB19B38FA4377B34E1234EA613A2A5FE522AF08F0B5E0B957C726A6B15732102FF077FE93DDC6626CADE5DB5436B03DC4CE81B0387A2B56C078D5E413FE20DC576473045022100EFFD4EC7B5B003BC5CCF07BE6406EE2A218AA46C0FC51902B801EFBE45C8FB0102200FC2D21E57E785076AA6D2D749F5FBAC9B99FDD9259DD7B8F9EB2D058B434807",
|
||||
"n9LCBA8uJWJ2moif8wbm7SBhuR8uenVgBm7VxKSX4VmzcQH6Mw8j": "22800000012600000095292CFCB3163A6C13F3590B29FCC651CAD3AEA30BDAC743D24F91EEF18A03DFB7EDA477194429C9132656ACF85867FA501775530CC549425FB587CBEE269283F976D923CBF68A9AD5C636DE22A96F33FBB350198F84F7AB19B38FA4377B34E1234EA613A2A5FE522AF08F0B5E0B957C726A6B157321031695B0FB0D95F9C41931F14F49841F44997E76607D1E1D4FC57729F20E6C66397646304402203FAD0DF9CE9AD6A9987229E2AF83E80DACF5D0BFD14CC6ED2036CEAD068BB88002206F50EEA8AF44ACAB94100B0A6061396559D60C1D0E532EEA991F3D6E2B88C4D8",
|
||||
"n9LtFW3Hda5qBS8TUPP9NnNnxUYXbhiWSLaNsGXJKyEkEUiSLvtU": "22800000012600000095292CFCB3163AD3E2E9C72D6F8A9E51CAD3AEA30BDAC743D24F91EEF18A03DFB7EDA477194429C9132656ACF85867FA501775530CC549425FB587CBEE269283F976D923CBF68A9AD5C636DE22A96F33FBB350198F84F7AB19B38FA4377B34E1234EA613A2A5FE522AF08F0B5E0B957C726A6B157321033588B42423B7F797AF19ADDA19470D7F6C5DC384B26D3DA14D859345ADB496247646304402207A5ABA310A90FD46D7BB164172750AE752FA389C697BFACE75CE2E9F2842DC4402200A42A054462531CE381047C7FD47DB8F8AC83963F1E7F3091251437912F9BD06",
|
||||
"n9MNStvsHZxrCYnShytCfKMCXBcq8wJjR6fLTS7L2Q8qoFVNioQ8": "22800000012600000095292CFCB3163AA0E5E217DB17866851CAD3AEA30BDAC743D24F91EEF18A03DFB7EDA477194429C9132656ACF85867FA501775530CC549425FB587CBEE269283F976D923CBF68A9AD5C636DE22A96F33FBB350198F84F7AB19B38FA4377B34E1234EA613A2A5FE522AF08F0B5E0B957C726A6B157321036219BE1721FF5F57EBCB1997EA568BA8BED880ED0CF1FD81F25C888EC8E66D67764630440220467BE8918BBF65D201B705D0C83B0DE347ABC7E9353CEA8AEBE9495BC78AEFC602206FFCB1A2BD08B1F3ED18E3A737C83D9AD6CE20E4B90FF61621650E61F2A7A05A",
|
||||
"n9MTTavZe6EPqqyQ27pJbNWpfHw8ZNspVgznrwx5HWm7cdTjKQie": "22800000012600000095292CFCB3163A3E9A11AB5CFA712751CAD3AEA30BDAC743D24F91EEF18A03DFB7EDA477194429C9132656ACF85867FA501775530CC549425FB587CBEE269283F976D923CBF68A9AD5C636DE22A96F33FBB350198F84F7AB19B38FA4377B34E1234EA613A2A5FE522AF08F0B5E0B957C726A6B157321037FA072E183DC2822AF50EBC43280C9AADF0DFE3BCD57D2CB0DD1179034B07543764730450221008A3D649F423D4B3BB74B4943DD3B4841BA2EF281DC8D1F48C6D3A7E72966344302200C465A03A50F33BD04A9751F4261B96F8058710D18DFC7DCE09850C735FE8B12"
|
||||
},
|
||||
"unl": {
|
||||
"blob": "eyJzZXF1ZW5jZSI6MSwiZXhwaXJhdGlvbiI6NzY3Nzg0NjQ1LCJ2YWxpZGF0b3JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDExREMwN0E2REEzRDA3QzAxMkUxOUZGOUFDNjdBQ0U1MzlBMjk1MTQ1QzhEQTM5NjQzN0NBQ0FFQzM2NzA5RjYiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUwUjNBZW0yajBId0JMaG4vbXNaNnpsT2FLVkZGeU5vNVpEZkt5dXcyY0o5bk1oQXF0T08zeFRwQ1pjVVpVdDJkTE5LQ2tobk4xUFZmWTVhZU9NWEpFUFBGOGNka2N3UlFJaEFOYlBEZlZLUzdwSWFqejlOMlFNNEY4Q3hhd1dJcmF0c3QyQjd3ZWR5czFGQWlCR0s3L1YwRDRBMlp2VFJEQlVQb0JLUVhpQk83QUV3ckRiOFlvN2RUSTJTWEFTUU9lQTIrVGdGVlRwNzdlN3VFZGpYNU1BYk8yU0t2dk8zOW1POEFyQkNqemRPUElxVmIrWi9QMDJUTmYzNjUrYjVCOGc3V0xEY0x2VkNpZUxjemw4MHcwPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURBMTY0RjRCMzZDMkQ3MzA0NjJENUY3NjJCRkEyODA4QUE1MDkyQUJDRUNFQkIyNzA4OTUyNUQxRDA1NEJFMzNCIiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMmhaUFN6YkMxekJHTFY5Mksvb29DS3BRa3F2T3pyc25DSlVsMGRCVXZqTzNNaEEveXBSNmZ3aXhSa1Y3NzVXdkRQZkRxL0RRbk5IY0FnbWZjWVhEZTdNb0IxZGtjd1JRSWhBTjRldTFvSGV0bFVDUmZmZ2FaeTkvTWJrQ0prWlFZdlJoMFVJZWFCaVZodkFpQWhGWXZKTXBPeVFpNGxFdzdzM0pTVTBMRm5FckRWVlRnK3NYUVk0c3Zta25BU1FCSGswakIweG1yL1UwbnkyajNrRmVvdEJUVEExVzdXcHBKbXFvYmR4SXkyR0w0QXBRaEpPcm5aRy93bXZqeFJCNXV4Y05FNUdUR1NZekQ3azhhVEx3bz0ifV19",
|
||||
"blob": "eyJzZXF1ZW5jZSI6MSwiZXhwaXJhdGlvbiI6NzU3MzQ5NjI0LCJ2YWxpZGF0b3JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFREJBOUZGMzEzNjgyMzlGNDIxRjA0QkY2ODEzQkJGNzZDNkJCRDQ1NkMyRTEyNDg2MDY2MjdCOTkwRjA5MTc2ODkiLCJtYW5pZmVzdCI6IkpBQUFBRVJ4SWUyNm4vTVRhQ09mUWg4RXYyZ1R1L2RzYTcxRmJDNFNTR0JtSjdtUThKRjJpWE1oQTMrZ2N1R0QzQ2dpcjFEcnhES0F5YXJmRGY0N3pWZlN5dzNSRjVBMHNIVkRka1l3UkFJZ2J4bVdKWXoxMFI2RVh6OG1RRmxKazlMM1UwZkQxT2UzbDJYK3NVOGFqajBDSUNIb2RoNzRWaDJNL0oxRnlzS2NOUmp1YWpKaCtSN1dqeXVBNHFqWWwvSHVkeDEwWlhOMExYSnBjSEJzWlM1MmJtOWtaVEV1ZEhKaGJuTnBZUzVqYjNBU1FEcDJuUVVTbk9CYlVxMHpCU05wMzRhRktBWnRrWHRaS3BjejBlQitEVG12TXRGN3M0Y240ZW8veHhkZU5UbmxJK1FRVmloZUpLSkZKQlJ3NzZwdXdROD0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEQkJDRDNGRjdGRkVGOTc3REU0Mzg0QUMzODE0NTMwNEM1MUI5MTJDRUYxMTgwNjBGMzQzMTBGRjgwN0NDRUU3QiIsIm1hbmlmZXN0IjoiSkFBQUFEeHhJZTI3elQvMy8rK1hmZVE0U3NPQlJUQk1VYmtTenZFWUJnODBNUS80Qjh6dWUzTWhBMkladmhjaC8xOVg2OHNabCtwV2k2aSsySUR0RFBIOWdmSmNpSTdJNW0xbmRrY3dSUUloQUtMWnFVYjIyYWg0YmJzL3JtTU1VQjl4MXE3MDY0RzczcW5uSytmaU9UVHZBaUFNdUJ4QVFlcEw4a2owRVVlY3ZIT2dKOEo2TUFUdS9CVnFXVzk1alhRNUMzY2RkR1Z6ZEMxeWFYQndiR1V1ZG01dlpHVXlMblJ5WVc1emFXRXVZMjl3RWtCcXpTMmFmdm9XUGJOcWM2UGRxaGV4ZnNUVDBEdUJZd2ltN0c4Y0xvSzg1bktTTW1TQy9ZaGw1cXRTRzkzNWZnQUlqVm9YZXMrZS9Kd3FFU01xZ2ZZQiJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRUQ2N0ZFMkU1MTc1Njc2NjBCMTU0NUEzQjg0OUU2OThERTg5Q0Y4MTUxODg2MjIwMzAxNzc2OEUxMjJBMTM3N0JDIiwibWFuaWZlc3QiOiJKQUFBQUR4eEllMW4vaTVSZFdkbUN4VkZvN2hKNXBqZWljK0JVWWhpSURBWGRvNFNLaE4zdkhNaEEvVzhCMFlwMy9DZHFDZEJmNGtmdmN1WHNJdjAxS0YzRmNSdGliODJ5UHdvZGtZd1JBSWdZV3NQMVMwYzhvZkFlRWp1WjJ3a2NpM29idStLV0tuOWxqMmVqOEJ1YmxVQ0lHTGl2UmJxazRHUW9VWVk2bC9NS0hpeWkwbzBwbmtpSTFLRDV2UHRYRHRnZHgxMFpYTjBMWEpwY0hCc1pTNTJibTlrWlRNdWRISmhibk5wWVM1amIzQVNRSzdZZUtoYnQwNlc1QnpQODk1V09NT1p2SlJLakhaVGdtN0VqYUtjakNLRTQwWTQwaTczeTUreVFHQWpISFlrRGgydE5UdVExQ09HT1E2b2N1VEFpZ1U9In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDc1OUJFRTREQzIxQzVBMDYzMEZCODdENDJFQ0MzRDk1OUE3RkI0QkY0RUM3RkYxMkRDOUZDQjFCNkFCNDE5MTUiLCJtYW5pZmVzdCI6IkpBQUFBRHB4SWUxMW0rNU53aHhhQmpEN2g5UXV6RDJWbW4rMHYwN0gveExjbjhzYmFyUVpGWE1oQW9ha1NKR05wL2kvZHBOVkx2bmtldnhYd2cyZUNRRXlZejFTSFRLSWtFRElka1l3UkFJZ0JUTHFROXFna3VrVzFwYTBwQ0xRVld2QnFua09NVkVPK3JQTEVoL2praHdDSUZsQURXb3RLc0JBQ0hyWW1EY3N0dXczYjRkdWV4V3dXY0FCdTdkNmR1T3FkeDEwWlhOMExYSnBjSEJzWlM1MmJtOWtaVFF1ZEhKaGJuTnBZUzVqYjNBU1FBN0UrdHVzMHZ0aDk4eGQwWVdLb2FVOVJTL1VUZVQ1RUcwSURzbW9NVHdrN014VTRGVktTL0dXOTUrMHJ0cG0xV0NYM1VRWThaN1pIZmtGMVlxenZRUT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEMTFDQzhEQUZDREUxMTFGRDFCNTM4OUJFRDM1QjcwNkQzMUQwMDRGMjBGQUNERjEwQ0RGMTI2MjhDRkE0NUQ2RSIsIm1hbmlmZXN0IjoiSkFBQUFEcHhJZTBSekkydnplRVIvUnRUaWI3VFczQnRNZEFFOGcrczN4RE44U1lvejZSZGJuTWhBdjhIZitrOTNHWW15dDVkdFVOckE5eE02QnNEaDZLMWJBZU5Ya0UvNGczRmRrWXdSQUlnRS84cTI2R0lSaDlLd1ZvUjFLZVBnS3VGcUlyRjV5NnMrREUvaXNmWHJpSUNJR3hQdHZSUjNLZFI3d2haMzI3VXFpUXFvZnM3d2VVRzQ0dEpiZnhZWndCV2R4MTBaWE4wTFhKcGNIQnNaUzUyYm05a1pUVXVkSEpoYm5OcFlTNWpiM0FTUU5hRFNNSmdpU2kxNzRoazYrdnlBRlhzdUFYZkw0YnRFT3c5OVBSSVJwQVAvUGxRa1ZmMXpNdUJrLzJGNzdqai9BTzFnd09va3hjbEJHRmF5MC9jcGc4PSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRUQ5MjI5NDFEMjQwMEM4M0I3QjU1QzE4QkZFRDRCNzA5QkI4QzAxRkNGMEE3RTlCRTQ5RTA5RDBCOUIyNTRDRTU1IiwibWFuaWZlc3QiOiJKQUFBQURweEllMlNLVUhTUUF5RHQ3VmNHTC90UzNDYnVNQWZ6d3ArbStTZUNkQzVzbFRPVlhNaEF4YVZzUHNObGZuRUdUSHhUMG1FSDBTWmZuWmdmUjRkVDhWM0tmSU9iR1k1ZGtjd1JRSWhBUDBkOHRSZ0JlczNmKzl5Y2Y4c0FNdEdLcnUxN05neGN2azJpRXJQTks5MUFpQTI5WFM4VzNYYVZ4bS9xS0pmSzc0T1JTVlJFL3MzUmFZbGJhMmZoT3JCTDNjZGRHVnpkQzF5YVhCd2JHVXVkbTV2WkdVMkxuUnlZVzV6YVdFdVkyOXdFa0F6V2RkcGxHMkVKUmo2c1ZabEdxTFN6RWhqWEQ3VXFKV1pNSC9IMUZKaW9sWFVBbk5VOXVidjRsWDE0WVFlWmpJbitLR2gwekoxek5KS2YvbGhsRnNKIn0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDY1OThGNjYzRTNDRjQwRDczREMxOUU4NzUwRUQ2N0I4NjAzNTREQjhGMkEzMTVENUZFN0REMDY1MkY0OUQyMUUiLCJtYW5pZmVzdCI6IkpBQUFBRHB4SWUxbG1QWmo0ODlBMXozQm5vZFE3V2U0WURWTnVQS2pGZFgrZmRCbEwwblNIbk1oQSs5NzF4YVIvb05TWndobTRCaXMwaHZnRVpjVkFFaFJVSytocG0zRlpHWjJka1l3UkFJZ1VKbmg3VTNQV3U5LzVKblFBcFpOdmRZanhFTmZkcHIzcFUwY05NZHJ1eXdDSUVLVG5XSzB4RnM0UWVIMFhFZkNSQTFJdjQrMlJzSFhJZHZyR0I3NlVxSmdkeDEwWlhOMExYSnBjSEJzWlM1MmJtOWtaVGN1ZEhKaGJuTnBZUzVqYjNBU1FOakRvVTRjL2ZkbDJONCtFbnR0TXBQeTV5QlhqRldEbXVYZThrZ0FTaERaZllpVGNYZU5LT3RzU2xzQW5PVGIxbllzZzdFbFZpZTB6bGM5dTdQTWVBRT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEOTk5RkZGRUY1MUQ3MTJEN0Q0MjVCQTA4M0U3OUU2MDJGNzhBNDkyMDU0QThDMjM4RjRBOTQ0ODc2OTlFRDkwNyIsIm1hbmlmZXN0IjoiSkFBQUFEcHhJZTJabi8vdlVkY1MxOVFsdWdnK2VlWUM5NHBKSUZTb3dqajBxVVNIYVo3WkIzTWhBeldJdENRanQvZVhyeG10MmhsSERYOXNYY09Fc20wOW9VMkZrMFd0dEpZa2RrY3dSUUloQU9RMFRhbFlVYnE3aml0T2MybXMxQm5wUTdsWHJVc2x2WEJSbS9tRG1UZEVBaUE0KzdPSmhkN0pFSlV2QUhSYjByaG5GSkd3b3ZoWWNQNjBBTG81Zm8xaTJIY2RkR1Z6ZEMxeWFYQndiR1V1ZG01dlpHVTRMblJ5WVc1emFXRXVZMjl3RWtBVzR2TlRPMEU5ZEptRC93eFNmcG9qN0V6bUxMV1pFN1dTeWZuTFk0WTBTVEVLR09jK0FGZ251Ty9IekhhdnQ3aTJBUHJkckZhT3IySm1Zb2lIa1RVSiJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURGNjVFNTAwNkE1M0FGNzU2MTdFQUUyOUM3MzNDNUYzNDFBOTQxNzNDMjkyM0Y2MjY5Mjk2M0QxQTJGMTQwNzYyIiwibWFuaWZlc3QiOiJKQUFBQURweEllMzJYbEFHcFRyM1ZoZnE0cHh6UEY4MEdwUVhQQ2tqOWlhU2xqMGFMeFFIWW5NaEFwMFZza1lodUVnRTV6WU5vY3cxODJ1S0ozR2Line truncated
|
||||
"manifest": "JAAAAAFxIe101ANsZZGkvfnFTO+jm5lqXc5fhtEf2hh0SBzp1aHNwXMh7TN9+b62cZqTngaFYU5tbGpYHC8oYuI3G3vwj9OW2Z9gdkAnUjfY5zOEkhq31tU4338jcyUpVA5/VTsANFce7unDo+JeVoEhfuOb/Y8WA3Diu9XzuOD4U/ikfgf9SZOlOGcBcBJAw44PLjH+HUtEnwX45lIRmo0x5aINFMvZsBpE9QteSDBXKwYzLdnSW4e1bs21o+IILJIiIKU/+1Uxx0FRpQbMDA==",
|
||||
"public_key": "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1",
|
||||
"signature": "77809A0938EA47F3A03BA0B71DD2C6879416F06574F6B5DC0041C9D806D3D5971282EF99D9EF911F8F37B56DA7016679744EF042C7A98ED425EFFFC6CC8AEA05",
|
||||
"signature": "B7619B4AD763E7E59715C8710E1836558F9B0B3F216F30A7922CCE288434AFDA8C12993D716CE750E603F8A6B21EFB53448758F2D90F3FE5DFD1063350F7040C",
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1682,6 +1682,36 @@ class Import_test : public beast::unit_test::suite
|
||||
ter(temDISABLED));
|
||||
}
|
||||
|
||||
// temMALFORMED - Import: xpop did not contain an 80% quorum for the txn
|
||||
// it purports to prove.
|
||||
for (bool const withXahauV1 : {true, false})
|
||||
{
|
||||
auto const amend = withXahauV1 ? features : features - fixXahauV1;
|
||||
test::jtx::Env env{
|
||||
*this, network::makeNetworkVLConfig(21337, keys), amend};
|
||||
|
||||
auto const alice = Account("alice");
|
||||
env.fund(XRP(1000), alice);
|
||||
env.close();
|
||||
|
||||
Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed);
|
||||
Json::Value valData = tmpXpop[jss::validation][jss::data];
|
||||
valData["n9MNStvsHZxrCYnShytCfKMCXBcq8wJjR6fLTS7L2Q8qoFVNioQ8"] =
|
||||
"";
|
||||
valData["n9MTTavZe6EPqqyQ27pJbNWpfHw8ZNspVgznrwx5HWm7cdTjKQie"] =
|
||||
"";
|
||||
if (withXahauV1)
|
||||
{
|
||||
valData
|
||||
["n94J5LCRu9bBWrJiwRWujvuVECVPWbXFcQ2VN38qLD378F5pDSDM"] =
|
||||
"";
|
||||
}
|
||||
tmpXpop[jss::validation][jss::data] = valData;
|
||||
auto const txResult =
|
||||
withXahauV1 ? ter(temMALFORMED) : ter(temMALFORMED);
|
||||
env(import::import(alice, tmpXpop), txResult);
|
||||
}
|
||||
|
||||
test::jtx::Env env{*this, network::makeNetworkVLConfig(21337, keys)};
|
||||
|
||||
auto const feeDrops = env.current()->fees().base;
|
||||
@@ -2573,19 +2603,6 @@ class Import_test : public beast::unit_test::suite
|
||||
// parsed
|
||||
// DA: Catch All
|
||||
|
||||
// temMALFORMED - Import: xpop did not contain an 80% quorum for the txn
|
||||
// it purports to prove.
|
||||
{
|
||||
Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed);
|
||||
Json::Value valData;
|
||||
valData["n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN"] =
|
||||
"";
|
||||
valData["n9KXYzdZD8YpsNiChtMjP6yhvQAhkkh5XeSTbvYyV1waF8wkNnBT"] =
|
||||
"";
|
||||
tmpXpop[jss::validation][jss::data] = valData;
|
||||
env(import::import(alice, tmpXpop), ter(temMALFORMED));
|
||||
}
|
||||
|
||||
// temMALFORMED - Import: xpop inner txn did not contain a sequence
|
||||
// number or fee No Sequence
|
||||
{
|
||||
|
||||
+129
-68
@@ -5113,10 +5113,11 @@ public:
|
||||
|
||||
using namespace jtx;
|
||||
|
||||
// OfferCreate - OfferID
|
||||
// OfferCreate
|
||||
for (bool const withXahauV1 : {true, false})
|
||||
{
|
||||
Env env{*this, features};
|
||||
|
||||
auto const amend = withXahauV1 ? features : features - fixXahauV1;
|
||||
Env env{*this, amend};
|
||||
auto const gw = Account{"gateway"};
|
||||
auto const alice = Account{"alice"};
|
||||
auto const USD = gw["USD"];
|
||||
@@ -5130,58 +5131,80 @@ public:
|
||||
env(pay(gw, alice, USD(200)));
|
||||
env.close();
|
||||
|
||||
uint256 const offerId{getOfferIndex(alice, env.seq(alice))};
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
// sequence id - no offer id
|
||||
{
|
||||
std::uint32_t const offerSeqId{env.seq(alice)};
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
|
||||
auto offers = sortedOffersOnAccount(env, alice);
|
||||
BEAST_EXPECT(offers.size() == 1);
|
||||
auto tx = offer(alice, XRP(50), USD(50));
|
||||
tx[sfOfferSequence.jsonName] = offerSeqId;
|
||||
env(tx, ter(tesSUCCESS));
|
||||
env.close();
|
||||
auto const offerLE = env.le(keylet::offer(alice, offerSeqId));
|
||||
BEAST_EXPECT(!offerLE);
|
||||
}
|
||||
|
||||
auto tx = offer(alice, XRP(50), USD(50));
|
||||
tx[sfOfferID.jsonName] = to_string(offerId);
|
||||
env(tx, ter(tesSUCCESS));
|
||||
env.close();
|
||||
// no sequence id - offer id
|
||||
{
|
||||
uint256 const offerId{getOfferIndex(alice, env.seq(alice))};
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
|
||||
offers = sortedOffersOnAccount(env, alice);
|
||||
BEAST_EXPECT(offers.size() == 1);
|
||||
}
|
||||
auto tx = offer(alice, XRP(50), USD(50));
|
||||
env(tx, offer_id(offerId), ter(tesSUCCESS));
|
||||
env.close();
|
||||
auto const offerLE = env.le(keylet::unchecked(offerId));
|
||||
BEAST_EXPECT(!offerLE);
|
||||
}
|
||||
|
||||
// OfferCreate - OfferSequence
|
||||
{
|
||||
Env env{*this, features};
|
||||
auto const gw = Account{"gateway"};
|
||||
auto const alice = Account{"alice"};
|
||||
auto const USD = gw["USD"];
|
||||
// no offer id or offer sequence
|
||||
{
|
||||
uint256 const offerId{getOfferIndex(alice, env.seq(alice))};
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
|
||||
env.fund(XRP(10000), gw, alice);
|
||||
env.close();
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
auto const offerLE = env.le(keylet::unchecked(offerId));
|
||||
BEAST_EXPECT(offerLE);
|
||||
}
|
||||
|
||||
env(trust(alice, USD(1000)));
|
||||
env.close();
|
||||
// offer id and offer sequence
|
||||
{
|
||||
uint256 const offerId{getOfferIndex(alice, env.seq(alice))};
|
||||
std::uint32_t const offerSeqId{env.seq(alice)};
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
|
||||
env(pay(gw, alice, USD(200)));
|
||||
env.close();
|
||||
auto tx = offer(alice, XRP(50), USD(50));
|
||||
tx[sfOfferSequence.jsonName] = offerSeqId;
|
||||
env(tx, offer_id(offerId), ter(temBAD_SEQUENCE));
|
||||
env.close();
|
||||
auto const offerLE = env.le(keylet::unchecked(offerId));
|
||||
BEAST_EXPECT(offerLE);
|
||||
}
|
||||
|
||||
// OfferCreate - OfferID
|
||||
std::uint32_t const offerSeqId{env.seq(alice)};
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
// offer id and offer sequence 0
|
||||
{
|
||||
uint256 const offerId{getOfferIndex(alice, env.seq(alice))};
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
|
||||
auto offers = sortedOffersOnAccount(env, alice);
|
||||
BEAST_EXPECT(offers.size() == 1);
|
||||
|
||||
auto tx = offer(alice, XRP(50), USD(50));
|
||||
tx[sfOfferSequence.jsonName] = offerSeqId;
|
||||
env(tx, ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
offers = sortedOffersOnAccount(env, alice);
|
||||
BEAST_EXPECT(offers.size() == 1);
|
||||
auto tx = offer(alice, XRP(50), USD(50));
|
||||
tx[sfOfferSequence.jsonName] = 0;
|
||||
env(tx, offer_id(offerId), ter(temBAD_SEQUENCE));
|
||||
env.close();
|
||||
auto const offerLE = env.le(keylet::unchecked(offerId));
|
||||
BEAST_EXPECT(offerLE);
|
||||
}
|
||||
}
|
||||
|
||||
// OfferCancel
|
||||
for (bool const withXahauV1 : {true, false})
|
||||
{
|
||||
Env env{*this, features};
|
||||
auto const amend = withXahauV1 ? features : features - fixXahauV1;
|
||||
Env env{*this, amend};
|
||||
auto const gw = Account{"gateway"};
|
||||
auto const alice = Account{"alice"};
|
||||
auto const USD = gw["USD"];
|
||||
@@ -5203,36 +5226,46 @@ public:
|
||||
|
||||
env(offer_cancel(alice, offerSeqId), ter(tesSUCCESS));
|
||||
env.close();
|
||||
auto const offers = sortedOffersOnAccount(env, alice);
|
||||
BEAST_EXPECT(offers.size() == 0);
|
||||
auto const offerLE = env.le(keylet::offer(alice, offerSeqId));
|
||||
BEAST_EXPECT(!offerLE);
|
||||
}
|
||||
|
||||
// offer id (offer sequence required)
|
||||
// no sequence id - offer id
|
||||
{
|
||||
uint256 const offerId{getOfferIndex(alice, env.seq(alice))};
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
|
||||
env(offer_cancel(alice, 0),
|
||||
offer_id(offerId),
|
||||
ter(temBAD_SEQUENCE));
|
||||
env.close();
|
||||
auto const offers = sortedOffersOnAccount(env, alice);
|
||||
BEAST_EXPECT(offers.size() == 1);
|
||||
if (withXahauV1)
|
||||
{
|
||||
env(offer_cancel(alice),
|
||||
offer_id(offerId),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
auto const offerLE = env.le(keylet::unchecked(offerId));
|
||||
BEAST_EXPECT(!offerLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
env(offer_cancel(alice),
|
||||
offer_id(offerId),
|
||||
ter(temBAD_SEQUENCE));
|
||||
env.close();
|
||||
auto const offerLE = env.le(keylet::unchecked(offerId));
|
||||
BEAST_EXPECT(offerLE);
|
||||
}
|
||||
}
|
||||
|
||||
// no offer id or offer sequence
|
||||
{
|
||||
uint256 const offerId{getOfferIndex(alice, env.seq(alice))};
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
|
||||
Json::Value jv;
|
||||
jv[jss::Account] = alice.human();
|
||||
jv[jss::TransactionType] = jss::OfferCancel;
|
||||
env(jv, ter(temMALFORMED));
|
||||
env(offer_cancel(alice), ter(temBAD_SEQUENCE));
|
||||
env.close();
|
||||
auto const offers = sortedOffersOnAccount(env, alice);
|
||||
BEAST_EXPECT(offers.size() == 2);
|
||||
auto const offerLE = env.le(keylet::unchecked(offerId));
|
||||
BEAST_EXPECT(offerLE);
|
||||
}
|
||||
|
||||
// both offer id and offer sequence
|
||||
@@ -5242,12 +5275,39 @@ public:
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
|
||||
env(offer_cancel(alice, offerSeqId),
|
||||
offer_id(offerId),
|
||||
ter(tesSUCCESS));
|
||||
if (withXahauV1)
|
||||
{
|
||||
env(offer_cancel(alice, offerSeqId),
|
||||
offer_id(offerId),
|
||||
ter(temBAD_SEQUENCE));
|
||||
env.close();
|
||||
auto const offerLE = env.le(keylet::unchecked(offerId));
|
||||
BEAST_EXPECT(offerLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
env(offer_cancel(alice, offerSeqId),
|
||||
offer_id(offerId),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
auto const offerLE = env.le(keylet::unchecked(offerId));
|
||||
BEAST_EXPECT(!offerLE);
|
||||
}
|
||||
}
|
||||
|
||||
// both offer id and offer sequence 0
|
||||
{
|
||||
uint256 const offerId{getOfferIndex(alice, env.seq(alice))};
|
||||
std::uint32_t const offerSeqId{env.seq(alice)};
|
||||
env(offer(alice, XRP(50), USD(50)));
|
||||
env.close();
|
||||
auto const offers = sortedOffersOnAccount(env, alice);
|
||||
BEAST_EXPECT(offers.size() == 2);
|
||||
|
||||
env(offer_cancel(alice, 0),
|
||||
offer_id(offerId),
|
||||
ter(temBAD_SEQUENCE));
|
||||
env.close();
|
||||
auto const offerLE = env.le(keylet::unchecked(offerId));
|
||||
BEAST_EXPECT(offerLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5344,12 +5404,13 @@ public:
|
||||
FeatureBitset const rmSmallIncreasedQOffers{fixRmSmallIncreasedQOffers};
|
||||
FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
|
||||
|
||||
testAll(all - takerDryOffer - immediateOfferKilled);
|
||||
testAll(all - flowCross - takerDryOffer - immediateOfferKilled);
|
||||
testAll(all - flowCross - immediateOfferKilled);
|
||||
testAll(all - rmSmallIncreasedQOffers - immediateOfferKilled);
|
||||
testAll(all);
|
||||
testFalseAssert();
|
||||
// testAll(all - takerDryOffer - immediateOfferKilled);
|
||||
// testAll(all - flowCross - takerDryOffer - immediateOfferKilled);
|
||||
// testAll(all - flowCross - immediateOfferKilled);
|
||||
// testAll(all - rmSmallIncreasedQOffers - immediateOfferKilled);
|
||||
// testAll(all);
|
||||
// testFalseAssert();
|
||||
testOfferID(all);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1048,10 +1048,17 @@ private:
|
||||
env.close();
|
||||
|
||||
// cancel escrow
|
||||
env(escrow::cancel(account, account, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
Json::Value tx;
|
||||
if (!env.current()->rules().enabled(fixXahauV1))
|
||||
{
|
||||
tx = escrow::cancel(account, account, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx = escrow::cancel(account, account);
|
||||
}
|
||||
|
||||
env(tx, escrow::escrow_id(escrowId), fee(XRP(1)), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// verify tsh hook triggered
|
||||
@@ -1103,10 +1110,16 @@ private:
|
||||
env.close();
|
||||
|
||||
// cancel escrow
|
||||
env(escrow::cancel(account, account, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
Json::Value tx;
|
||||
if (!env.current()->rules().enabled(fixXahauV1))
|
||||
{
|
||||
tx = escrow::cancel(account, account, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx = escrow::cancel(account, account);
|
||||
}
|
||||
env(tx, escrow::escrow_id(escrowId), fee(XRP(1)), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// verify tsh hook triggered
|
||||
@@ -1156,10 +1169,16 @@ private:
|
||||
env.close();
|
||||
|
||||
// cancel escrow
|
||||
env(escrow::cancel(dest, account, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
Json::Value tx;
|
||||
if (!env.current()->rules().enabled(fixXahauV1))
|
||||
{
|
||||
tx = escrow::cancel(dest, account, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx = escrow::cancel(dest, account);
|
||||
}
|
||||
env(tx, escrow::escrow_id(escrowId), fee(XRP(1)), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// verify tsh hook triggered
|
||||
@@ -1211,10 +1230,16 @@ private:
|
||||
env.close();
|
||||
|
||||
// cancel escrow
|
||||
env(escrow::cancel(dest, account, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
Json::Value tx;
|
||||
if (!env.current()->rules().enabled(fixXahauV1))
|
||||
{
|
||||
tx = escrow::cancel(dest, account, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx = escrow::cancel(dest, account);
|
||||
}
|
||||
env(tx, escrow::escrow_id(escrowId), fee(XRP(1)), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// verify tsh hook triggered
|
||||
@@ -1565,10 +1590,16 @@ private:
|
||||
env.close();
|
||||
|
||||
// finish escrow
|
||||
env(escrow::finish(account, account, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
Json::Value tx;
|
||||
if (!env.current()->rules().enabled(fixXahauV1))
|
||||
{
|
||||
tx = escrow::finish(account, account, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx = escrow::finish(account, account);
|
||||
}
|
||||
env(tx, escrow::escrow_id(escrowId), fee(XRP(1)), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// verify tsh hook triggered
|
||||
@@ -1617,10 +1648,16 @@ private:
|
||||
env.close();
|
||||
|
||||
// finish escrow
|
||||
env(escrow::finish(account, account, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
Json::Value tx;
|
||||
if (!env.current()->rules().enabled(fixXahauV1))
|
||||
{
|
||||
tx = escrow::finish(account, account, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx = escrow::finish(account, account);
|
||||
}
|
||||
env(tx, escrow::escrow_id(escrowId), fee(XRP(1)), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// verify tsh hook triggered
|
||||
@@ -1663,10 +1700,16 @@ private:
|
||||
env.close();
|
||||
|
||||
// finish escrow
|
||||
env(escrow::finish(dest, account, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
Json::Value tx;
|
||||
if (!env.current()->rules().enabled(fixXahauV1))
|
||||
{
|
||||
tx = escrow::finish(dest, account, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx = escrow::finish(dest, account);
|
||||
}
|
||||
env(tx, escrow::escrow_id(escrowId), fee(XRP(1)), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// verify tsh hook triggered
|
||||
@@ -1715,10 +1758,16 @@ private:
|
||||
env.close();
|
||||
|
||||
// finish escrow
|
||||
env(escrow::finish(dest, account, 0),
|
||||
escrow::escrow_id(escrowId),
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
Json::Value tx;
|
||||
if (!env.current()->rules().enabled(fixXahauV1))
|
||||
{
|
||||
tx = escrow::finish(dest, account, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx = escrow::finish(dest, account);
|
||||
}
|
||||
env(tx, escrow::escrow_id(escrowId), fee(XRP(1)), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// verify tsh hook triggered
|
||||
@@ -4806,6 +4855,7 @@ public:
|
||||
using namespace test::jtx;
|
||||
auto const sa = supported_amendments();
|
||||
testWithFeats(sa);
|
||||
testWithFeats(sa - fixXahauV1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -89,6 +89,67 @@ public:
|
||||
// fee unit tests, the rest of the time we want to ignore it.
|
||||
#define HSFEE fee(100'000'000)
|
||||
#define M(m) memo(m, "", "")
|
||||
void
|
||||
testHooksOwnerDir()
|
||||
{
|
||||
testcase("Test owner directory");
|
||||
|
||||
using namespace jtx;
|
||||
|
||||
for (bool const withXahauV1 : {true, false})
|
||||
{
|
||||
auto const amend = withXahauV1
|
||||
? supported_amendments()
|
||||
: supported_amendments() - fixXahauV1;
|
||||
|
||||
Env env{*this, amend};
|
||||
|
||||
auto const alice = Account{"alice"};
|
||||
auto const gw = Account{"gateway"};
|
||||
auto const USD = gw["USD"];
|
||||
env.fund(XRP(10000), alice, gw);
|
||||
env.close();
|
||||
env.trust(USD(100000), alice);
|
||||
env.close();
|
||||
env(pay(gw, alice, USD(10000)));
|
||||
|
||||
for (int i = 1; i < 34; ++i)
|
||||
{
|
||||
std::string const uri(i, '?');
|
||||
env(uritoken::mint(alice, uri));
|
||||
}
|
||||
env.close();
|
||||
|
||||
env(ripple::test::jtx::hook(
|
||||
alice, {{hso(accept_wasm, overrideFlag)}}, 0),
|
||||
HSFEE,
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
env(ripple::test::jtx::hook(
|
||||
alice, {{hso(accept_wasm, overrideFlag)}}, 0),
|
||||
HSFEE,
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// delete hook
|
||||
Json::Value jv;
|
||||
jv[jss::Account] = alice.human();
|
||||
jv[jss::TransactionType] = jss::SetHook;
|
||||
jv[jss::Flags] = 0;
|
||||
jv[jss::Hooks] = Json::Value{Json::arrayValue};
|
||||
Json::Value iv;
|
||||
iv[jss::Flags] = 1;
|
||||
iv[jss::CreateCode] = "";
|
||||
jv[jss::Hooks][0U][jss::Hook] = iv;
|
||||
|
||||
auto const txResult =
|
||||
withXahauV1 ? ter(tesSUCCESS) : ter(tefBAD_LEDGER);
|
||||
env(jv, HSFEE, txResult);
|
||||
env.close();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testHooksDisabled()
|
||||
{
|
||||
@@ -100,7 +161,8 @@ public:
|
||||
|
||||
// RH TODO: does it matter that passing malformed txn here gives back
|
||||
// temMALFORMED (and not disabled)?
|
||||
env(ripple::test::jtx::hook(alice, {{hso(accept_wasm)}}, 0),
|
||||
env(ripple::test::jtx::hook(
|
||||
alice, {{hso(accept_wasm, overrideFlag)}}, 0),
|
||||
M("Hooks Disabled"),
|
||||
HSFEE,
|
||||
ter(temDISABLED));
|
||||
@@ -7764,6 +7826,134 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_state_foreign_set_max()
|
||||
{
|
||||
testcase("Test state_foreign_set max");
|
||||
using namespace jtx;
|
||||
|
||||
static const std::vector<uint8_t> ns_maxHook = {
|
||||
0x00U, 0x61U, 0x73U, 0x6dU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x36U, 0x07U, 0x60U, 0x02U, 0x7fU, 0x7fU, 0x01U, 0x7fU, 0x60U,
|
||||
0x02U, 0x7fU, 0x7fU, 0x01U, 0x7eU, 0x60U, 0x03U, 0x7fU, 0x7fU,
|
||||
0x7eU, 0x01U, 0x7eU, 0x60U, 0x04U, 0x7fU, 0x7fU, 0x7fU, 0x7fU,
|
||||
0x01U, 0x7eU, 0x60U, 0x05U, 0x7fU, 0x7fU, 0x7fU, 0x7fU, 0x7fU,
|
||||
0x01U, 0x7eU, 0x60U, 0x08U, 0x7fU, 0x7fU, 0x7fU, 0x7fU, 0x7fU,
|
||||
0x7fU, 0x7fU, 0x7fU, 0x01U, 0x7eU, 0x60U, 0x01U, 0x7fU, 0x01U,
|
||||
0x7eU, 0x02U, 0x79U, 0x08U, 0x03U, 0x65U, 0x6eU, 0x76U, 0x02U,
|
||||
0x5fU, 0x67U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6eU, 0x76U, 0x0cU,
|
||||
0x68U, 0x6fU, 0x6fU, 0x6bU, 0x5fU, 0x61U, 0x63U, 0x63U, 0x6fU,
|
||||
0x75U, 0x6eU, 0x74U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6eU, 0x76U,
|
||||
0x08U, 0x72U, 0x6fU, 0x6cU, 0x6cU, 0x62U, 0x61U, 0x63U, 0x6bU,
|
||||
0x00U, 0x02U, 0x03U, 0x65U, 0x6eU, 0x76U, 0x05U, 0x73U, 0x74U,
|
||||
0x61U, 0x74U, 0x65U, 0x00U, 0x03U, 0x03U, 0x65U, 0x6eU, 0x76U,
|
||||
0x05U, 0x74U, 0x72U, 0x61U, 0x63U, 0x65U, 0x00U, 0x04U, 0x03U,
|
||||
0x65U, 0x6eU, 0x76U, 0x11U, 0x73U, 0x74U, 0x61U, 0x74U, 0x65U,
|
||||
0x5fU, 0x66U, 0x6fU, 0x72U, 0x65U, 0x69U, 0x67U, 0x6eU, 0x5fU,
|
||||
0x73U, 0x65U, 0x74U, 0x00U, 0x05U, 0x03U, 0x65U, 0x6eU, 0x76U,
|
||||
0x09U, 0x73U, 0x74U, 0x61U, 0x74U, 0x65U, 0x5fU, 0x73U, 0x65U,
|
||||
0x74U, 0x00U, 0x03U, 0x03U, 0x65U, 0x6eU, 0x76U, 0x06U, 0x61U,
|
||||
0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x02U, 0x03U, 0x02U,
|
||||
0x01U, 0x06U, 0x05U, 0x03U, 0x01U, 0x00U, 0x02U, 0x06U, 0x2bU,
|
||||
0x07U, 0x7fU, 0x01U, 0x41U, 0xc0U, 0x88U, 0x04U, 0x0bU, 0x7fU,
|
||||
0x00U, 0x41U, 0x80U, 0x08U, 0x0bU, 0x7fU, 0x00U, 0x41U, 0xb2U,
|
||||
0x08U, 0x0bU, 0x7fU, 0x00U, 0x41U, 0x80U, 0x08U, 0x0bU, 0x7fU,
|
||||
0x00U, 0x41U, 0xc0U, 0x88U, 0x04U, 0x0bU, 0x7fU, 0x00U, 0x41U,
|
||||
0x00U, 0x0bU, 0x7fU, 0x00U, 0x41U, 0x01U, 0x0bU, 0x07U, 0x08U,
|
||||
0x01U, 0x04U, 0x68U, 0x6fU, 0x6fU, 0x6bU, 0x00U, 0x08U, 0x0aU,
|
||||
0xd4U, 0x81U, 0x00U, 0x01U, 0xd0U, 0x81U, 0x00U, 0x02U, 0x02U,
|
||||
0x7fU, 0x01U, 0x7eU, 0x23U, 0x00U, 0x41U, 0xe0U, 0x00U, 0x6bU,
|
||||
0x22U, 0x01U, 0x24U, 0x00U, 0x20U, 0x01U, 0x20U, 0x00U, 0x36U,
|
||||
0x02U, 0x5cU, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U, 0x00U, 0x1aU,
|
||||
0x20U, 0x01U, 0x41U, 0x40U, 0x6bU, 0x41U, 0x14U, 0x10U, 0x01U,
|
||||
0x42U, 0x14U, 0x52U, 0x04U, 0x40U, 0x41U, 0x00U, 0x41U, 0x00U,
|
||||
0x42U, 0x0cU, 0x10U, 0x02U, 0x1aU, 0x0bU, 0x20U, 0x01U, 0x41U,
|
||||
0x38U, 0x6aU, 0x41U, 0x08U, 0x20U, 0x01U, 0x41U, 0x40U, 0x6bU,
|
||||
0x22U, 0x00U, 0x41U, 0x14U, 0x10U, 0x03U, 0x1aU, 0x20U, 0x01U,
|
||||
0x20U, 0x01U, 0x29U, 0x03U, 0x38U, 0x42U, 0x01U, 0x7cU, 0x37U,
|
||||
0x03U, 0x38U, 0x20U, 0x01U, 0x41U, 0xabU, 0x01U, 0x3aU, 0x00U,
|
||||
0x19U, 0x20U, 0x01U, 0x20U, 0x01U, 0x29U, 0x03U, 0x38U, 0x3cU,
|
||||
0x00U, 0x1aU, 0x41U, 0x80U, 0x08U, 0x41U, 0x02U, 0x20U, 0x01U,
|
||||
0x41U, 0x10U, 0x6aU, 0x22U, 0x02U, 0x41U, 0x20U, 0x41U, 0x01U,
|
||||
0x10U, 0x04U, 0x1aU, 0x20U, 0x01U, 0x41U, 0xa9U, 0x08U, 0x41U,
|
||||
0x09U, 0x41U, 0xa4U, 0x08U, 0x41U, 0x05U, 0x20U, 0x02U, 0x41U,
|
||||
0x20U, 0x20U, 0x00U, 0x41U, 0x14U, 0x10U, 0x05U, 0x37U, 0x03U,
|
||||
0x08U, 0x20U, 0x01U, 0x29U, 0x03U, 0x08U, 0x42U, 0x00U, 0x53U,
|
||||
0x04U, 0x40U, 0x41U, 0x83U, 0x08U, 0x41U, 0x21U, 0x20U, 0x01U,
|
||||
0x29U, 0x03U, 0x08U, 0x10U, 0x02U, 0x1aU, 0x0bU, 0x20U, 0x01U,
|
||||
0x41U, 0x38U, 0x6aU, 0x41U, 0x08U, 0x20U, 0x01U, 0x41U, 0x40U,
|
||||
0x6bU, 0x41U, 0x14U, 0x10U, 0x06U, 0x1aU, 0x41U, 0x00U, 0x41U,
|
||||
0x00U, 0x20U, 0x01U, 0x29U, 0x03U, 0x08U, 0x10U, 0x07U, 0x20U,
|
||||
0x01U, 0x41U, 0xe0U, 0x00U, 0x6aU, 0x24U, 0x00U, 0x0bU, 0x0bU,
|
||||
0x38U, 0x01U, 0x00U, 0x41U, 0x80U, 0x08U, 0x0bU, 0x31U, 0x6eU,
|
||||
0x73U, 0x00U, 0x6eU, 0x73U, 0x5fU, 0x6dU, 0x61U, 0x78U, 0x2eU,
|
||||
0x63U, 0x3aU, 0x20U, 0x4dU, 0x61U, 0x78U, 0x20U, 0x4eU, 0x61U,
|
||||
0x6dU, 0x65U, 0x73U, 0x70U, 0x61U, 0x63U, 0x65U, 0x73U, 0x20U,
|
||||
0x52U, 0x65U, 0x61U, 0x63U, 0x68U, 0x65U, 0x64U, 0x00U, 0x6bU,
|
||||
0x65U, 0x79U, 0x32U, 0x00U, 0x63U, 0x6fU, 0x6eU, 0x74U, 0x65U,
|
||||
0x6eU, 0x74U, 0x32U};
|
||||
|
||||
// fixXahauV1
|
||||
{
|
||||
for (bool const withfixXahauV1 : {true, false})
|
||||
{
|
||||
auto const amend = withfixXahauV1
|
||||
? supported_amendments()
|
||||
: supported_amendments() - fixXahauV1;
|
||||
|
||||
Env env{*this, amend};
|
||||
|
||||
// Env env{*this, envconfig(), amend, nullptr,
|
||||
// // beast::severities::kWarning
|
||||
// beast::severities::kTrace
|
||||
// };
|
||||
|
||||
auto const bob = Account{"bob"};
|
||||
auto const alice = Account{"alice"};
|
||||
env.fund(XRP(10000000), alice);
|
||||
env.fund(XRP(10000000), bob);
|
||||
|
||||
// install the hook on alice
|
||||
env(ripple::test::jtx::hook(
|
||||
alice, {{hso(ns_maxHook, overrideFlag)}}, 0),
|
||||
M("set state_foreign_set_max"),
|
||||
HSFEE);
|
||||
env.close();
|
||||
|
||||
// invoke the hook
|
||||
for (uint32_t i = 0; i < 255; ++i)
|
||||
{
|
||||
env(pay(bob, alice, XRP(1)),
|
||||
M("test state_foreign_set_max"),
|
||||
fee(XRP(1)));
|
||||
}
|
||||
|
||||
auto const txResult =
|
||||
withfixXahauV1 ? ter(tecHOOK_REJECTED) : ter(tesSUCCESS);
|
||||
env(pay(bob, alice, XRP(1)),
|
||||
M("test state_foreign_set_max"),
|
||||
fee(XRP(1)),
|
||||
ter(txResult));
|
||||
env.close();
|
||||
|
||||
// verify hook result
|
||||
std::string const hookResult = withfixXahauV1
|
||||
? "800000000000002d" // TOO_MANY_NAMESPACES / -45
|
||||
: "9";
|
||||
|
||||
Json::Value params;
|
||||
params[jss::transaction] =
|
||||
env.tx()->getJson(JsonOptions::none)[jss::hash];
|
||||
auto const jrr = env.rpc("json", "tx", to_string(params));
|
||||
auto const meta = jrr[jss::result][jss::meta];
|
||||
auto const executions = meta[sfHookExecutions.jsonName];
|
||||
auto const execution = executions[0u][sfHookExecution.jsonName];
|
||||
BEAST_EXPECT(
|
||||
execution[sfHookReturnCode.jsonName] == hookResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_state_foreign_set()
|
||||
{
|
||||
@@ -11437,6 +11627,7 @@ public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testHooksOwnerDir();
|
||||
testHooksDisabled();
|
||||
testTxStructure();
|
||||
testInferHookSetOperation();
|
||||
@@ -11520,10 +11711,11 @@ public:
|
||||
test_slot_subfield(); //
|
||||
test_slot_type(); //
|
||||
|
||||
test_state(); //
|
||||
test_state_foreign(); //
|
||||
test_state_foreign_set(); //
|
||||
test_state_set(); //
|
||||
test_state(); //
|
||||
test_state_foreign(); //
|
||||
test_state_foreign_set(); //
|
||||
test_state_foreign_set_max(); //
|
||||
test_state_set(); //
|
||||
|
||||
test_sto_emplace(); //
|
||||
test_sto_erase(); //
|
||||
|
||||
@@ -4245,6 +4245,142 @@ struct XahauGenesis_test : public beast::unit_test::suite
|
||||
env, user, preLedger, preLedger + 1, postUser, preTime));
|
||||
}
|
||||
|
||||
void
|
||||
testValidL1WithUNLReport(FeatureBitset features)
|
||||
{
|
||||
using namespace jtx;
|
||||
using namespace std::chrono_literals;
|
||||
testcase("test claim reward valid for L1 with unl report");
|
||||
|
||||
for (bool const withXahauV1 : {true, false})
|
||||
{
|
||||
FeatureBitset _features = features - featureXahauGenesis;
|
||||
auto const amend = withXahauV1 ? _features : _features - fixXahauV1;
|
||||
Env env{*this, envconfig(), amend};
|
||||
|
||||
double const rateDrops = 0.00333333333 * 1'000'000;
|
||||
STAmount const feesXRP = XRP(1);
|
||||
|
||||
// setup governance
|
||||
Account const alice = Account("alice");
|
||||
Account const bob = Account("bob");
|
||||
Account const carol = Account("carol");
|
||||
Account const david = Account("david");
|
||||
Account const edward = Account("edward");
|
||||
|
||||
env.fund(XRP(10000), alice, bob, carol, david, edward);
|
||||
env.close();
|
||||
|
||||
std::vector<AccountID> initial_members_ids{
|
||||
alice.id(), bob.id(), carol.id(), david.id(), edward.id()};
|
||||
|
||||
setupGov(env, initial_members_ids);
|
||||
|
||||
// update reward delay
|
||||
{
|
||||
// this will be the new reward delay
|
||||
// 100
|
||||
std::vector<uint8_t> vote_data{
|
||||
0x00U, 0x80U, 0xC6U, 0xA4U, 0x7EU, 0x8DU, 0x03U, 0x55U};
|
||||
|
||||
updateTopic(
|
||||
env, alice, bob, carol, david, edward, 'R', 'D', vote_data);
|
||||
}
|
||||
|
||||
// setup unl report
|
||||
std::vector<std::string> const _ivlKeys = {
|
||||
"ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1"
|
||||
"CDC1",
|
||||
};
|
||||
std::vector<PublicKey> ivlKeys;
|
||||
for (auto const& strPk : _ivlKeys)
|
||||
{
|
||||
auto pkHex = strUnHex(strPk);
|
||||
ivlKeys.emplace_back(makeSlice(*pkHex));
|
||||
}
|
||||
std::vector<std::string> const _vlKeys = {
|
||||
"0388935426E0D08083314842EDFBB2D517BD47699F9A4527318A8E10468C97"
|
||||
"C05"
|
||||
"2",
|
||||
"02691AC5AE1C4C333AE5DF8A93BDC495F0EEBFC6DB0DA7EB6EF808F3AFC006"
|
||||
"E3F"
|
||||
"E",
|
||||
"028949021029D5CC87E78BCF053AFEC0CAFD15108EC119EAAFEC466F5C0954"
|
||||
"07B"
|
||||
"F",
|
||||
"027BAEF0CB02EA8B95F50DF4BC16C740B17B50C85F3757AA06A5DB6ADE0ED9"
|
||||
"210"
|
||||
"6",
|
||||
"0318E0D644F3D2911D7B7E1B0B17684E7E625A6C36AECCE851BD16A4AD628B"
|
||||
"213"
|
||||
"6"};
|
||||
std::vector<PublicKey> vlKeys;
|
||||
for (auto const& strPk : _vlKeys)
|
||||
{
|
||||
auto pkHex = strUnHex(strPk);
|
||||
vlKeys.emplace_back(makeSlice(*pkHex));
|
||||
}
|
||||
|
||||
// activate unl report
|
||||
activateUNLReport(env, ivlKeys, vlKeys);
|
||||
|
||||
// validate unl report
|
||||
BEAST_EXPECT(hasUNLReport(env) == true);
|
||||
|
||||
// opt in claim reward
|
||||
env(claimReward(alice, env.master), fee(feesXRP), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// close ledgers
|
||||
validateTime(lastClose(env), 90);
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
env.close(10s);
|
||||
}
|
||||
validateTime(lastClose(env), 180);
|
||||
|
||||
// define pre close values
|
||||
STAmount const preAlice = env.balance(alice);
|
||||
STAmount const preBob = env.balance(bob);
|
||||
STAmount const preCarol = env.balance(carol);
|
||||
STAmount const preDavid = env.balance(david);
|
||||
STAmount const preEdward = env.balance(edward);
|
||||
NetClock::time_point const preTime = lastClose(env);
|
||||
std::uint32_t const preLedger = env.current()->seq();
|
||||
auto const [acct, acctSle] =
|
||||
accountKeyAndSle(*env.current(), alice);
|
||||
|
||||
// claim reward
|
||||
auto const txResult =
|
||||
withXahauV1 ? ter(tesSUCCESS) : ter(tecHOOK_REJECTED);
|
||||
env(claimReward(alice, env.master), fee(feesXRP), txResult);
|
||||
env.close();
|
||||
|
||||
// trigger emitted txn
|
||||
env.close();
|
||||
|
||||
// calculate rewards
|
||||
STAmount const netReward =
|
||||
rewardUserAmount(*acctSle, preLedger, rateDrops);
|
||||
STAmount const l1Reward =
|
||||
withXahauV1 ? rewardL1Amount(netReward, 20) : STAmount(0);
|
||||
|
||||
// validate govern rewards
|
||||
BEAST_EXPECT(env.balance(bob) == preBob + l1Reward);
|
||||
BEAST_EXPECT(env.balance(carol) == preCarol + l1Reward);
|
||||
BEAST_EXPECT(env.balance(david) == preDavid + l1Reward);
|
||||
BEAST_EXPECT(env.balance(edward) == preEdward + l1Reward);
|
||||
|
||||
// validate account fields
|
||||
STAmount const postAlice = preAlice + netReward + l1Reward;
|
||||
bool const boolResult = withXahauV1 ? true : false;
|
||||
BEAST_EXPECT(
|
||||
expectAccountFields(
|
||||
env, alice, preLedger, preLedger + 1, postAlice, preTime) ==
|
||||
boolResult);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testOptInOptOut(FeatureBitset features)
|
||||
{
|
||||
@@ -4873,6 +5009,7 @@ struct XahauGenesis_test : public beast::unit_test::suite
|
||||
testInvalidBeforeTime(features);
|
||||
testValidWithoutUNLReport(features);
|
||||
testValidWithUNLReport(features);
|
||||
testValidL1WithUNLReport(features);
|
||||
testOptInOptOut(features);
|
||||
testValidLowBalance(features);
|
||||
testValidElapsed1(features);
|
||||
|
||||
@@ -43,12 +43,18 @@ finish(
|
||||
jtx::Account const& from,
|
||||
std::uint32_t seq);
|
||||
|
||||
Json::Value
|
||||
finish(jtx::Account const& account, jtx::Account const& from);
|
||||
|
||||
Json::Value
|
||||
cancel(
|
||||
jtx::Account const& account,
|
||||
jtx::Account const& from,
|
||||
std::uint32_t seq);
|
||||
|
||||
Json::Value
|
||||
cancel(jtx::Account const& account, jtx::Account const& from);
|
||||
|
||||
/** Set the "FinishAfter" time tag on a JTx */
|
||||
class finish_time
|
||||
{
|
||||
|
||||
@@ -84,6 +84,17 @@ finish(jtx::Account const& account, jtx::Account const& from, std::uint32_t seq)
|
||||
return jv;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
finish(jtx::Account const& account, jtx::Account const& from)
|
||||
{
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::EscrowFinish;
|
||||
jv[jss::Flags] = tfUniversal;
|
||||
jv[jss::Account] = account.human();
|
||||
jv[sfOwner.jsonName] = from.human();
|
||||
return jv;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
cancel(jtx::Account const& account, jtx::Account const& from, std::uint32_t seq)
|
||||
{
|
||||
@@ -96,6 +107,17 @@ cancel(jtx::Account const& account, jtx::Account const& from, std::uint32_t seq)
|
||||
return jv;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
cancel(jtx::Account const& account, jtx::Account const& from)
|
||||
{
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::EscrowCancel;
|
||||
jv[jss::Flags] = tfUniversal;
|
||||
jv[jss::Account] = account.human();
|
||||
jv[sfOwner.jsonName] = from.human();
|
||||
return jv;
|
||||
}
|
||||
|
||||
} // namespace escrow
|
||||
|
||||
} // namespace jtx
|
||||
|
||||
@@ -51,6 +51,15 @@ offer_cancel(Account const& account, std::uint32_t offerSeq)
|
||||
return jv;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
offer_cancel(Account const& account)
|
||||
{
|
||||
Json::Value jv;
|
||||
jv[jss::Account] = account.human();
|
||||
jv[jss::TransactionType] = jss::OfferCancel;
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
offer_id::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
|
||||
@@ -40,6 +40,10 @@ offer(
|
||||
Json::Value
|
||||
offer_cancel(Account const& account, std::uint32_t offerSeq);
|
||||
|
||||
/** Cancel an offer. */
|
||||
Json::Value
|
||||
offer_cancel(Account const& account);
|
||||
|
||||
/** Sets the optional "OfferID" on a JTx. */
|
||||
class offer_id
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user