mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
debugging, bug fixes
This commit is contained in:
@@ -235,12 +235,24 @@ EscrowCreate::doApply()
|
|||||||
return tecUNFUNDED;
|
return tecUNFUNDED;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// preflight will prevent this ever firing, included
|
||||||
|
// defensively for completeness
|
||||||
if (!ctx_.view().rules().enabled(featurePaychanAndEscrowForTokens))
|
if (!ctx_.view().rules().enabled(featurePaychanAndEscrowForTokens))
|
||||||
return tefINTERNAL;
|
return tefINTERNAL;
|
||||||
|
|
||||||
sleLine = ctx_.view().peek(keylet::line(account, amount.getIssuer(), amount.getCurrency()));
|
// check if the escrow is capable of being
|
||||||
|
// finished before we allow it to be created
|
||||||
|
if (TER result =
|
||||||
|
trustXferAllowed(
|
||||||
|
ctx_.view(),
|
||||||
|
{account, ctx_.tx[sfDestination]},
|
||||||
|
amount.issue());
|
||||||
|
result != tesSUCCESS)
|
||||||
|
return result;
|
||||||
|
|
||||||
// perform the lock as a dry run first
|
// perform the lock as a dry run before
|
||||||
|
// we modify anything on-ledger
|
||||||
|
sleLine = ctx_.view().peek(keylet::line(account, amount.getIssuer(), amount.getCurrency()));
|
||||||
if (TER result = trustAdjustLockedBalance(ctx_.view(), sleLine, amount, true);
|
if (TER result = trustAdjustLockedBalance(ctx_.view(), sleLine, amount, true);
|
||||||
result != tesSUCCESS)
|
result != tesSUCCESS)
|
||||||
return result;
|
return result;
|
||||||
@@ -301,16 +313,17 @@ EscrowCreate::doApply()
|
|||||||
// Deduct owner's balance, increment owner count
|
// Deduct owner's balance, increment owner count
|
||||||
if (isXRP(amount))
|
if (isXRP(amount))
|
||||||
(*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount];
|
(*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount];
|
||||||
else if (ctx_.view().rules().enabled(featurePaychanAndEscrowForTokens) && sleLine)
|
else
|
||||||
{
|
{
|
||||||
|
if (!ctx_.view().rules().enabled(featurePaychanAndEscrowForTokens) || !sleLine)
|
||||||
|
return tefINTERNAL;
|
||||||
|
|
||||||
// do the lock-up for real now
|
// do the lock-up for real now
|
||||||
TER result =
|
TER result =
|
||||||
trustAdjustLockedBalance(ctx_.view(), sleLine, amount, true);
|
trustAdjustLockedBalance(ctx_.view(), sleLine, amount, false);
|
||||||
if (result != tesSUCCESS)
|
if (result != tesSUCCESS)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return tecINTERNAL; // should never happen
|
|
||||||
|
|
||||||
adjustOwnerCount(ctx_.view(), sle, 1, ctx_.journal);
|
adjustOwnerCount(ctx_.view(), sle, 1, ctx_.journal);
|
||||||
ctx_.view().update(sle);
|
ctx_.view().update(sle);
|
||||||
@@ -540,8 +553,10 @@ EscrowFinish::doApply()
|
|||||||
|
|
||||||
if (isXRP(amount))
|
if (isXRP(amount))
|
||||||
(*sled)[sfBalance] = (*sled)[sfBalance] + (*slep)[sfAmount];
|
(*sled)[sfBalance] = (*sled)[sfBalance] + (*slep)[sfAmount];
|
||||||
else if (ctx_.view().rules().enabled(featurePaychanAndEscrowForTokens))
|
else
|
||||||
{
|
{
|
||||||
|
if (!ctx_.view().rules().enabled(featurePaychanAndEscrowForTokens))
|
||||||
|
return tefINTERNAL;
|
||||||
|
|
||||||
// all the significant complexity of checking the validity of this
|
// all the significant complexity of checking the validity of this
|
||||||
// transfer and ensuring the lines exist etc is hidden away in this
|
// transfer and ensuring the lines exist etc is hidden away in this
|
||||||
@@ -558,8 +573,6 @@ EscrowFinish::doApply()
|
|||||||
if (result != tesSUCCESS)
|
if (result != tesSUCCESS)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return tecINTERNAL; // should never happen
|
|
||||||
|
|
||||||
ctx_.view().update(sled);
|
ctx_.view().update(sled);
|
||||||
|
|
||||||
@@ -670,8 +683,11 @@ EscrowCancel::doApply()
|
|||||||
// Transfer amount back to the owner (or unlock it in TL case)
|
// Transfer amount back to the owner (or unlock it in TL case)
|
||||||
if (isXRP(amount))
|
if (isXRP(amount))
|
||||||
(*sle)[sfBalance] = (*sle)[sfBalance] + (*slep)[sfAmount];
|
(*sle)[sfBalance] = (*sle)[sfBalance] + (*slep)[sfAmount];
|
||||||
else if (ctx_.view().rules().enabled(featurePaychanAndEscrowForTokens))
|
else
|
||||||
{
|
{
|
||||||
|
if (!ctx_.view().rules().enabled(featurePaychanAndEscrowForTokens))
|
||||||
|
return tefINTERNAL;
|
||||||
|
|
||||||
// unlock previously locked tokens from source line
|
// unlock previously locked tokens from source line
|
||||||
TER result = trustAdjustLockedBalance(
|
TER result = trustAdjustLockedBalance(
|
||||||
ctx_.view(),
|
ctx_.view(),
|
||||||
@@ -681,8 +697,6 @@ EscrowCancel::doApply()
|
|||||||
if (result != tesSUCCESS)
|
if (result != tesSUCCESS)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return tecINTERNAL;
|
|
||||||
|
|
||||||
// Decrement owner count
|
// Decrement owner count
|
||||||
adjustOwnerCount(ctx_.view(), sle, -1, ctx_.journal);
|
adjustOwnerCount(ctx_.view(), sle, -1, ctx_.journal);
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include <ripple/protocol/STTx.h>
|
#include <ripple/protocol/STTx.h>
|
||||||
#include <ripple/protocol/Serializer.h>
|
#include <ripple/protocol/Serializer.h>
|
||||||
#include <ripple/protocol/TER.h>
|
#include <ripple/protocol/TER.h>
|
||||||
|
#include <ripple/protocol/Feature.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -303,12 +304,6 @@ bool isTrustDefault(
|
|||||||
std::shared_ptr<SLE> const& acc,
|
std::shared_ptr<SLE> const& acc,
|
||||||
std::shared_ptr<SLE> const& line);
|
std::shared_ptr<SLE> const& line);
|
||||||
|
|
||||||
[[nodiscard]] TER
|
|
||||||
trustXferAllowed(
|
|
||||||
ReadView const& view,
|
|
||||||
std::vector<AccountID> const& parties,
|
|
||||||
Issue const& issue);
|
|
||||||
|
|
||||||
template<class V, class S>
|
template<class V, class S>
|
||||||
[[nodiscard]] TER
|
[[nodiscard]] TER
|
||||||
trustAdjustLockedBalance(
|
trustAdjustLockedBalance(
|
||||||
@@ -322,13 +317,10 @@ trustAdjustLockedBalance(
|
|||||||
(std::is_same<V, ReadView const>::value && std::is_same<S, std::shared_ptr<SLE const>>::value) ||
|
(std::is_same<V, ReadView const>::value && std::is_same<S, std::shared_ptr<SLE const>>::value) ||
|
||||||
(std::is_same<V, ApplyView>::value && std::is_same<S, std::shared_ptr<SLE>>::value));
|
(std::is_same<V, ApplyView>::value && std::is_same<S, std::shared_ptr<SLE>>::value));
|
||||||
|
|
||||||
constexpr bool bReadView = std::is_same<V, ReadView const>::value;
|
|
||||||
|
|
||||||
// dry runs are explicit in code, but really the view type determines
|
// dry runs are explicit in code, but really the view type determines
|
||||||
// what occurs here, so this combination is invalid.
|
// what occurs here, so this combination is invalid.
|
||||||
|
|
||||||
if (bReadView && !dryRun)
|
assert(!(std::is_same<V, ReadView const>::value && !dryRun));
|
||||||
return tefINTERNAL;
|
|
||||||
|
|
||||||
auto const currency = deltaAmt.getCurrency();
|
auto const currency = deltaAmt.getCurrency();
|
||||||
auto const issuer = deltaAmt.getIssuer();
|
auto const issuer = deltaAmt.getIssuer();
|
||||||
@@ -350,7 +342,10 @@ trustAdjustLockedBalance(
|
|||||||
parties,
|
parties,
|
||||||
deltaAmt.issue());
|
deltaAmt.issue());
|
||||||
result != tesSUCCESS)
|
result != tesSUCCESS)
|
||||||
|
{
|
||||||
|
printf("trustXferAllowed failed on trustAdjustLockedBalance\n");
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// pull the TL balance from the account's perspective
|
// pull the TL balance from the account's perspective
|
||||||
STAmount balance =
|
STAmount balance =
|
||||||
@@ -395,6 +390,156 @@ trustAdjustLockedBalance(
|
|||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class V>
|
||||||
|
ReadView const&
|
||||||
|
forceReadView(V& view)
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
std::is_same<V, std::shared_ptr<ReadView const>>::value ||
|
||||||
|
std::is_same<V, std::shared_ptr<ApplyView>>::value ||
|
||||||
|
std::is_same<V, ApplyView>::value ||
|
||||||
|
std::is_same<V, ReadView const>::value);
|
||||||
|
|
||||||
|
ReadView const* rv = NULL;
|
||||||
|
|
||||||
|
if constexpr (
|
||||||
|
std::is_same<V, std::shared_ptr<ReadView const>>::value ||
|
||||||
|
std::is_same<V, std::shared_ptr<ApplyView>>::value)
|
||||||
|
rv = dynamic_cast<ReadView const*>(&(*view));
|
||||||
|
else if constexpr(
|
||||||
|
std::is_same<V, ApplyView>::value ||
|
||||||
|
std::is_same<V, ReadView const>::value)
|
||||||
|
rv = dynamic_cast<ReadView const*>(&view);
|
||||||
|
|
||||||
|
return *rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if movement of a particular token between 1 or more accounts
|
||||||
|
// (including unlocking) is forbidden by any flag or condition.
|
||||||
|
// If parties contains 1 entry then noRipple is not a bar to xfer.
|
||||||
|
// Part of featurePaychanAndEscrowForTokens, but can be callled without guard
|
||||||
|
|
||||||
|
template<class V>
|
||||||
|
[[nodiscard]]TER
|
||||||
|
trustXferAllowed(
|
||||||
|
V& view_,
|
||||||
|
std::vector<AccountID> const& parties,
|
||||||
|
Issue const& issue)
|
||||||
|
{
|
||||||
|
|
||||||
|
ReadView const& view = forceReadView(view_);
|
||||||
|
|
||||||
|
if (isFakeXRP(issue.currency))
|
||||||
|
return tecNO_PERMISSION;
|
||||||
|
|
||||||
|
auto const sleIssuerAcc = view.read(keylet::account(issue.account));
|
||||||
|
|
||||||
|
bool lockedBalanceAllowed =
|
||||||
|
view.rules().enabled(featurePaychanAndEscrowForTokens);
|
||||||
|
|
||||||
|
// missing issuer is always a bar to xfer
|
||||||
|
if (!sleIssuerAcc)
|
||||||
|
return tecNO_ISSUER;
|
||||||
|
|
||||||
|
// issuer global freeze is always a bar to xfer
|
||||||
|
if (isGlobalFrozen(view, issue.account))
|
||||||
|
return tecFROZEN;
|
||||||
|
|
||||||
|
uint32_t issuerFlags = sleIssuerAcc->getFieldU32(sfFlags);
|
||||||
|
|
||||||
|
bool requireAuth = issuerFlags & lsfRequireAuth;
|
||||||
|
|
||||||
|
for (AccountID const& p: parties)
|
||||||
|
{
|
||||||
|
auto line = view.read(keylet::line(p, issue.account, issue.currency));
|
||||||
|
if (!line)
|
||||||
|
{
|
||||||
|
if (requireAuth)
|
||||||
|
{
|
||||||
|
// the line doesn't exist, i.e. it is in default state
|
||||||
|
// default state means the line has not been authed
|
||||||
|
// therefore if auth is required by issuer then
|
||||||
|
// this is now a bar to xfer
|
||||||
|
return tecNO_AUTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// missing line is a line in default state, this is not
|
||||||
|
// a general bar to xfer, however additional conditions
|
||||||
|
// do attach to completing an xfer into a default line
|
||||||
|
// but these are checked in trustXferLockedBalance at
|
||||||
|
// the point of transfer.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanity check the line, insane lines are a bar to xfer
|
||||||
|
{
|
||||||
|
// these "strange" old lines, if they even exist anymore are
|
||||||
|
// always a bar to xfer
|
||||||
|
if (line->getFieldAmount(sfLowLimit).getIssuer() ==
|
||||||
|
line->getFieldAmount(sfHighLimit).getIssuer())
|
||||||
|
return tecINTERNAL;
|
||||||
|
|
||||||
|
if (line->isFieldPresent(sfLockedBalance))
|
||||||
|
{
|
||||||
|
if (!lockedBalanceAllowed)
|
||||||
|
{
|
||||||
|
printf("lockedBalanceAllowed was false\n");
|
||||||
|
return tecINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
STAmount lockedBalance = line->getFieldAmount(sfLockedBalance);
|
||||||
|
STAmount balance = line->getFieldAmount(sfBalance);
|
||||||
|
|
||||||
|
if (lockedBalance.getCurrency() != balance.getCurrency())
|
||||||
|
{
|
||||||
|
printf("lockedBalance issuer/currency did not match balance issuer/currency\n");
|
||||||
|
return tecINTERNAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the bars to xfer ... these are:
|
||||||
|
// any TL in the set has noRipple on the issuer's side
|
||||||
|
// any TL in the set has a freeze on the issuer's side
|
||||||
|
// any TL in the set has RequireAuth and the TL lacks lsf*Auth
|
||||||
|
{
|
||||||
|
bool pHigh = p > issue.account;
|
||||||
|
|
||||||
|
auto const flagIssuerNoRipple { pHigh ? lsfLowNoRipple : lsfHighNoRipple };
|
||||||
|
auto const flagIssuerFreeze { pHigh ? lsfLowFreeze : lsfHighFreeze };
|
||||||
|
auto const flagIssuerAuth { pHigh ? lsfLowAuth : lsfHighAuth };
|
||||||
|
|
||||||
|
uint32_t flags = line->getFieldU32(sfFlags);
|
||||||
|
|
||||||
|
if (flags & flagIssuerFreeze)
|
||||||
|
{
|
||||||
|
printf("trustXferAllowed: issuerFreeze\n");
|
||||||
|
return tecFROZEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if called with more than one party then any party
|
||||||
|
// that has a noripple on the issuer side of their tl
|
||||||
|
// blocks any possible xfer
|
||||||
|
if (parties.size() > 1 && (flags & flagIssuerNoRipple))
|
||||||
|
{
|
||||||
|
printf("trustXferAllowed: issuerNoRipple\n");
|
||||||
|
return tecPATH_DRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// every party involved must be on an authed trustline if
|
||||||
|
// the issuer has specified lsfRequireAuth
|
||||||
|
if (requireAuth && !(flags & flagIssuerAuth))
|
||||||
|
{
|
||||||
|
printf("trustXferAllowed: issuerRequireAuth\n");
|
||||||
|
return tecNO_AUTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tesSUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] TER
|
[[nodiscard]] TER
|
||||||
trustXferLockedBalance(
|
trustXferLockedBalance(
|
||||||
ApplyView& view,
|
ApplyView& view,
|
||||||
|
|||||||
@@ -961,114 +961,6 @@ bool isTrustDefault(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check if movement of a particular token between 1 or more accounts
|
|
||||||
// (including unlocking) is forbidden by any flag or condition.
|
|
||||||
// If parties contains 1 entry then noRipple is not a bar to xfer.
|
|
||||||
// Part of featurePaychanAndEscrowForTokens, but can be callled without guard
|
|
||||||
TER
|
|
||||||
trustXferAllowed(
|
|
||||||
ReadView const& view,
|
|
||||||
std::vector<AccountID> const& parties,
|
|
||||||
Issue const& issue)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (isFakeXRP(issue.currency))
|
|
||||||
return tecNO_PERMISSION;
|
|
||||||
|
|
||||||
auto const sleIssuerAcc = view.read(keylet::account(issue.account));
|
|
||||||
|
|
||||||
bool lockedBalanceAllowed =
|
|
||||||
view.rules().enabled(featurePaychanAndEscrowForTokens);
|
|
||||||
|
|
||||||
// missing issuer is always a bar to xfer
|
|
||||||
if (!sleIssuerAcc)
|
|
||||||
return tecNO_ISSUER;
|
|
||||||
|
|
||||||
// issuer global freeze is always a bar to xfer
|
|
||||||
if (isGlobalFrozen(view, issue.account))
|
|
||||||
return tecFROZEN;
|
|
||||||
|
|
||||||
uint32_t issuerFlags = sleIssuerAcc->getFieldU32(sfFlags);
|
|
||||||
|
|
||||||
bool requireAuth = issuerFlags & lsfRequireAuth;
|
|
||||||
|
|
||||||
for (AccountID const& p: parties)
|
|
||||||
{
|
|
||||||
auto line = view.read(keylet::line(p, issue.account, issue.currency));
|
|
||||||
if (!line)
|
|
||||||
{
|
|
||||||
if (requireAuth)
|
|
||||||
{
|
|
||||||
// the line doesn't exist, i.e. it is in default state
|
|
||||||
// default state means the line has not been authed
|
|
||||||
// therefore if auth is required by issuer then
|
|
||||||
// this is now a bar to xfer
|
|
||||||
return tecNO_AUTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
// missing line is a line in default state, this is not
|
|
||||||
// a general bar to xfer, however additional conditions
|
|
||||||
// do attach to completing an xfer into a default line
|
|
||||||
// but these are checked in trustXferLockedBalance at
|
|
||||||
// the point of transfer.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sanity check the line, insane lines are a bar to xfer
|
|
||||||
{
|
|
||||||
// these "strange" old lines, if they even exist anymore are
|
|
||||||
// always a bar to xfer
|
|
||||||
if (line->getFieldAmount(sfLowLimit).getIssuer() ==
|
|
||||||
line->getFieldAmount(sfHighLimit).getIssuer())
|
|
||||||
return tecINTERNAL;
|
|
||||||
|
|
||||||
if (line->isFieldPresent(sfLockedBalance))
|
|
||||||
{
|
|
||||||
if (!lockedBalanceAllowed)
|
|
||||||
return tecINTERNAL;
|
|
||||||
|
|
||||||
STAmount lockedBalance = line->getFieldAmount(sfLockedBalance);
|
|
||||||
STAmount balance = line->getFieldAmount(sfBalance);
|
|
||||||
|
|
||||||
if (lockedBalance.getIssuer() != balance.getIssuer() ||
|
|
||||||
lockedBalance.getCurrency() != balance.getCurrency())
|
|
||||||
return tecINTERNAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the bars to xfer ... these are:
|
|
||||||
// any TL in the set has noRipple on the issuer's side
|
|
||||||
// any TL in the set has a freeze on the issuer's side
|
|
||||||
// any TL in the set has RequireAuth and the TL lacks lsf*Auth
|
|
||||||
{
|
|
||||||
bool pHigh = p > issue.account;
|
|
||||||
|
|
||||||
auto const flagIssuerNoRipple { pHigh ? lsfLowNoRipple : lsfHighNoRipple };
|
|
||||||
auto const flagIssuerFreeze { pHigh ? lsfLowFreeze : lsfHighFreeze };
|
|
||||||
auto const flagIssuerAuth { pHigh ? lsfLowAuth : lsfHighAuth };
|
|
||||||
|
|
||||||
uint32_t flags = line->getFieldU32(sfFlags);
|
|
||||||
|
|
||||||
if (flags & flagIssuerFreeze)
|
|
||||||
return tecFROZEN;
|
|
||||||
|
|
||||||
// if called with more than one party then any party
|
|
||||||
// that has a noripple on the issuer side of their tl
|
|
||||||
// blocks any possible xfer
|
|
||||||
if (parties.size() > 1 && (flags & flagIssuerNoRipple))
|
|
||||||
return tecPATH_DRY;
|
|
||||||
|
|
||||||
// every party involved must be on an authed trustline if
|
|
||||||
// the issuer has specified lsfRequireAuth
|
|
||||||
if (requireAuth && !(flags & flagIssuerAuth))
|
|
||||||
return tecNO_AUTH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tesSUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
TER
|
TER
|
||||||
trustXferLockedBalance(
|
trustXferLockedBalance(
|
||||||
ApplyView& view,
|
ApplyView& view,
|
||||||
|
|||||||
Reference in New Issue
Block a user