Compare commits

...

9 Commits

Author SHA1 Message Date
Richard Holland
1f3382eac7 . 2023-12-27 12:47:51 +00:00
Richard Holland
76f61e56bf clang 2023-12-27 12:19:56 +00:00
Richard Holland
cb4111095c fixes 2023-12-27 12:09:32 +00:00
Richard Holland
c4be4be4e4 clang 2023-12-22 23:01:18 +00:00
Richard Holland
2484491736 compiling 2023-12-22 22:57:23 +00:00
Richard Holland
43c4616e32 . 2023-12-22 16:37:12 +00:00
Richard Holland
6735da10c4 fix wrong native purchase logic uritoken 2023-12-22 16:23:48 +00:00
Richard Holland
8c64749d62 change types on lambda to prevent any risk of overflow 2023-12-22 12:39:00 +00:00
Richard Holland
c3175e1fd4 disallow specifying both escrowid and offsersequence on escrow 2023-12-22 12:23:42 +00:00
4 changed files with 127 additions and 67 deletions

View File

@@ -437,11 +437,19 @@ EscrowFinish::preflight(PreflightContext const& ctx)
{ {
if (!ctx.tx.isFieldPresent(sfOfferSequence)) if (!ctx.tx.isFieldPresent(sfOfferSequence))
return temMALFORMED; return temMALFORMED;
}
if (!ctx.tx.isFieldPresent(sfEscrowID) && if (ctx.tx.isFieldPresent(sfEscrowID) &&
!ctx.tx.isFieldPresent(sfOfferSequence)) ctx.tx.getFieldU32(sfOfferSequence) != 0)
return temMALFORMED; return temMALFORMED;
}
else
{
if ((!ctx.tx.isFieldPresent(sfEscrowID) &&
!ctx.tx.isFieldPresent(sfOfferSequence)) ||
ctx.tx.isFieldPresent(sfEscrowID) &&
ctx.tx.isFieldPresent(sfOfferSequence))
return temMALFORMED;
}
return tesSUCCESS; return tesSUCCESS;
} }
@@ -472,17 +480,6 @@ EscrowFinish::doApply()
bool const fixV1 = view().rules().enabled(fixXahauV1); bool const fixV1 = view().rules().enabled(fixXahauV1);
if (!fixV1)
{
if (escrowID && ctx_.tx[sfOfferSequence] != 0)
return temMALFORMED;
}
else
{
if (escrowID && offerSequence)
return temMALFORMED;
}
Keylet k = escrowID ? Keylet(ltESCROW, *escrowID) Keylet k = escrowID ? Keylet(ltESCROW, *escrowID)
: keylet::escrow(ctx_.tx[sfOwner], *offerSequence); : keylet::escrow(ctx_.tx[sfOwner], *offerSequence);
@@ -723,11 +720,19 @@ EscrowCancel::preflight(PreflightContext const& ctx)
{ {
if (!ctx.tx.isFieldPresent(sfOfferSequence)) if (!ctx.tx.isFieldPresent(sfOfferSequence))
return temMALFORMED; return temMALFORMED;
}
if (!ctx.tx.isFieldPresent(sfEscrowID) && if (ctx.tx.isFieldPresent(sfEscrowID) &&
!ctx.tx.isFieldPresent(sfOfferSequence)) ctx.tx.getFieldU32(sfOfferSequence) != 0)
return temMALFORMED; return temMALFORMED;
}
else
{
if ((!ctx.tx.isFieldPresent(sfEscrowID) &&
!ctx.tx.isFieldPresent(sfOfferSequence)) ||
ctx.tx.isFieldPresent(sfEscrowID) &&
ctx.tx.isFieldPresent(sfOfferSequence))
return temMALFORMED;
}
return preflight2(ctx); return preflight2(ctx);
} }
@@ -744,16 +749,6 @@ EscrowCancel::doApply()
std::optional<std::uint32_t> offerSequence = ctx_.tx[~sfOfferSequence]; std::optional<std::uint32_t> offerSequence = ctx_.tx[~sfOfferSequence];
bool const fixV1 = view().rules().enabled(fixXahauV1); bool const fixV1 = view().rules().enabled(fixXahauV1);
if (!fixV1)
{
if (escrowID && ctx_.tx[sfOfferSequence] != 0)
return temMALFORMED;
}
else
{
if (escrowID && offerSequence)
return temMALFORMED;
}
Keylet k = escrowID ? Keylet(ltESCROW, *escrowID) Keylet k = escrowID ? Keylet(ltESCROW, *escrowID)
: keylet::escrow(ctx_.tx[sfOwner], *offerSequence); : keylet::escrow(ctx_.tx[sfOwner], *offerSequence);

View File

@@ -817,16 +817,17 @@ Import::preflight(PreflightContext const& ctx)
<< " validation count: " << validationCount; << " validation count: " << validationCount;
// check if the validation count is adequate // check if the validation count is adequate
auto hasInsufficientQuorum = [&ctx](int quorum, int validationCount) { auto hasInsufficientQuorum =
if (ctx.rules.enabled(fixXahauV1)) [&ctx](uint64_t quorum, uint64_t validationCount) {
{ if (ctx.rules.enabled(fixXahauV1))
return quorum > validationCount; {
} return quorum > validationCount;
else }
{ else
return quorum >= validationCount; {
} return quorum >= validationCount;
}; }
};
if (hasInsufficientQuorum(quorum, validationCount)) if (hasInsufficientQuorum(quorum, validationCount))
{ {
JLOG(ctx.j.warn()) << "Import: xpop did not contain an 80% quorum for " JLOG(ctx.j.warn()) << "Import: xpop did not contain an 80% quorum for "

View File

@@ -144,6 +144,8 @@ URIToken::preflight(PreflightContext const& ctx)
TER TER
URIToken::preclaim(PreclaimContext const& ctx) URIToken::preclaim(PreclaimContext const& ctx)
{ {
bool const fixV1 = ctx.view.rules().enabled(fixXahauV1);
std::shared_ptr<SLE const> sleU; std::shared_ptr<SLE const> sleU;
uint32_t leFlags; uint32_t leFlags;
std::optional<AccountID> issuer; std::optional<AccountID> issuer;
@@ -180,6 +182,11 @@ URIToken::preclaim(PreclaimContext const& ctx)
AccountID const acc = ctx.tx.getAccountID(sfAccount); AccountID const acc = ctx.tx.getAccountID(sfAccount);
uint16_t tt = ctx.tx.getFieldU16(sfTransactionType); uint16_t tt = ctx.tx.getFieldU16(sfTransactionType);
auto const sle =
ctx.view.read(keylet::account(ctx.tx.getAccountID(sfAccount)));
if (!sle)
return tefINTERNAL;
switch (tt) switch (tt)
{ {
case ttURITOKEN_MINT: { case ttURITOKEN_MINT: {
@@ -228,24 +235,75 @@ URIToken::preclaim(PreclaimContext const& ctx)
if (purchaseAmount < saleAmount) if (purchaseAmount < saleAmount)
return tecINSUFFICIENT_PAYMENT; return tecINSUFFICIENT_PAYMENT;
if (purchaseAmount.native() && saleAmount->native()) if (fixV1)
{ {
// if it's an xrp sale/purchase then no trustline needed if (purchaseAmount.native() && saleAmount->native())
if (purchaseAmount > {
(sleOwner->getFieldAmount(sfBalance) - ctx.tx[sfFee])) // native transfer
return tecINSUFFICIENT_FUNDS;
STAmount needed{ctx.view.fees().accountReserve(
sle->getFieldU32(sfOwnerCount) + 1)};
STAmount const fee = ctx.tx.getFieldAmount(sfFee).xrp();
if (needed + fee < needed)
return tecINTERNAL;
needed += fee;
if (needed + purchaseAmount < needed)
return tecINTERNAL;
needed += purchaseAmount;
if (needed > sle->getFieldAmount(sfBalance))
return tecINSUFFICIENT_FUNDS;
}
else if (purchaseAmount.native() || saleAmount->native())
{
// should not be able to happen
return tecINTERNAL;
}
else
{
// iou transfer
STAmount availableFunds{accountFunds(
ctx.view,
acc,
purchaseAmount,
fhZERO_IF_FROZEN,
ctx.j)};
if (purchaseAmount > availableFunds)
return tecINSUFFICIENT_FUNDS;
}
} }
else
{
// old logic
// execution to here means it's an IOU sale if (purchaseAmount.native() && saleAmount->native())
// check if the buyer has the right trustline with an adequate {
// balance // if it's an xrp sale/purchase then no trustline needed
if (purchaseAmount >
STAmount availableFunds{accountFunds( (sleOwner->getFieldAmount(sfBalance) - ctx.tx[sfFee]))
ctx.view, acc, purchaseAmount, fhZERO_IF_FROZEN, ctx.j)}; return tecINSUFFICIENT_FUNDS;
}
if (purchaseAmount > availableFunds) else
return tecINSUFFICIENT_FUNDS; {
// iou
STAmount availableFunds{accountFunds(
ctx.view,
acc,
purchaseAmount,
fhZERO_IF_FROZEN,
ctx.j)};
if (purchaseAmount > availableFunds)
return tecINSUFFICIENT_FUNDS;
}
}
return tesSUCCESS; return tesSUCCESS;
} }
@@ -412,17 +470,6 @@ URIToken::doApply()
} }
case ttURITOKEN_BUY: { case ttURITOKEN_BUY: {
if (account_ == *owner)
{
// this is a clear operation
sleU->makeFieldAbsent(sfAmount);
if (sleU->isFieldPresent(sfDestination))
sleU->makeFieldAbsent(sfDestination);
sb.update(sleU);
sb.apply(ctx_.rawView());
return tesSUCCESS;
}
STAmount const purchaseAmount = ctx_.tx.getFieldAmount(sfAmount); STAmount const purchaseAmount = ctx_.tx.getFieldAmount(sfAmount);
// check if the seller has listed it at all // check if the seller has listed it at all
@@ -446,8 +493,22 @@ URIToken::doApply()
// if it's an xrp sale/purchase then no trustline needed // if it's an xrp sale/purchase then no trustline needed
if (purchaseAmount.native()) if (purchaseAmount.native())
{ {
if (purchaseAmount > STAmount needed{sb.fees().accountReserve(
((*sleOwner)[sfBalance] - ctx_.tx[sfFee])) sle->getFieldU32(sfOwnerCount) + 1)};
STAmount const fee = ctx_.tx.getFieldAmount(sfFee).xrp();
if (needed + fee < needed)
return tecINTERNAL;
needed += fee;
if (needed + purchaseAmount < needed)
return tecINTERNAL;
needed += purchaseAmount;
if (needed > mPriorBalance)
return tecINSUFFICIENT_FUNDS; return tecINSUFFICIENT_FUNDS;
} }
else else

View File

@@ -454,7 +454,10 @@ struct URIToken_test : public beast::unit_test::suite
using namespace std::literals::chrono_literals; using namespace std::literals::chrono_literals;
// setup env // setup env
Env env{*this, features}; Env env{
*this, envconfig(), features, nullptr, beast::severities::kWarning
// beast::severities::kTrace
};
auto const alice = Account("alice"); auto const alice = Account("alice");
auto const bob = Account("bob"); auto const bob = Account("bob");
auto const carol = Account("carol"); auto const carol = Account("carol");