mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
debug & testing
This commit is contained in:
committed by
Richard Holland
parent
641b8c546d
commit
66105b6c68
@@ -63,6 +63,16 @@ inline URIOperation inferOperation(STTx const& tx)
|
||||
(hasBurnableFlag ? 0b000000010U : 0) +
|
||||
(blankFlags ? 0b000000001U : 0);
|
||||
|
||||
std::cout << "combination" << combination << "\n";
|
||||
std::cout << "mint" << (0b110000001U == combination) << "\n";
|
||||
std::cout << "mint" << (0b110000010U == combination) << "\n";
|
||||
std::cout << "mint" << (0b010000001U == combination) << "\n";
|
||||
std::cout << "mint" << (0b010000010U == combination) << "\n";
|
||||
std::cout << "burn" << (0b001100000U == combination) << "\n";
|
||||
std::cout << "buy" << (0b000110001U == combination) << "\n";
|
||||
std::cout << "sell" << (0b000110100U == combination) << "\n";
|
||||
std::cout << "sell" << (0b000111100U == combination) << "\n";
|
||||
std::cout << "clear" << (0b000100001U == combination) << "\n";
|
||||
switch (combination)
|
||||
{
|
||||
case 0b110000001U:
|
||||
@@ -281,6 +291,7 @@ URIToken::preclaim(PreclaimContext const& ctx)
|
||||
|
||||
default:
|
||||
{
|
||||
std::cout << "preclaim with URIOperation::Invalid\n " << "\n";
|
||||
JLOG(ctx.j.warn())
|
||||
<< "URIToken txid=" << ctx.tx.getTransactionID() << " preclaim with URIOperation::Invalid\n";
|
||||
return tecINTERNAL;
|
||||
@@ -321,10 +332,16 @@ URIToken::doApply()
|
||||
sleU = view().peek(*kl);
|
||||
|
||||
if (!sleU)
|
||||
{
|
||||
std::cout << "no entry object" << "\n";
|
||||
return tecNO_ENTRY;
|
||||
|
||||
}
|
||||
|
||||
if (sleU->getFieldU16(sfLedgerEntryType) != ltURI_TOKEN)
|
||||
{
|
||||
std::cout << "wrong uri token" << "\n";
|
||||
return tecNO_ENTRY;
|
||||
}
|
||||
|
||||
owner = (*sleU)[sfOwner];
|
||||
issuer = (*sleU)[sfIssuer];
|
||||
@@ -338,6 +355,7 @@ URIToken::doApply()
|
||||
|
||||
if (!sleOwner)
|
||||
{
|
||||
std::cout << "tecNO_ENTRY - no owner" << "\n";
|
||||
JLOG(j.warn())
|
||||
<< "Malformed transaction: owner of URIToken is not in the ledger.";
|
||||
return tecNO_ENTRY;
|
||||
@@ -450,7 +468,7 @@ URIToken::doApply()
|
||||
else
|
||||
{
|
||||
// IOU sale
|
||||
|
||||
std::cout << "IOU SALE" << "\n";
|
||||
STAmount availableFunds{accountFunds(
|
||||
view(),
|
||||
account_,
|
||||
@@ -458,6 +476,8 @@ URIToken::doApply()
|
||||
fhZERO_IF_FROZEN,
|
||||
j)};
|
||||
|
||||
// std::cout << "PURCHASE AMT: " << purchaseAmount << "\n";
|
||||
// std::cout << "AVAIL FUNDS: " << availableFunds << "\n";
|
||||
if (purchaseAmount > availableFunds)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
@@ -486,31 +506,39 @@ URIToken::doApply()
|
||||
}
|
||||
|
||||
// remove from buyer
|
||||
initBuyerBal = buyerLow ? (*sleSrcLine)[sfBalance] : -(*sleSrcLine)[sfBalance];
|
||||
initBuyerBal = buyerLow ? ((*sleSrcLine)[sfBalance]) : -((*sleSrcLine)[sfBalance]);
|
||||
// std::cout << "BUYER LOW: " << buyerLow << "\n";
|
||||
// std::cout << "BUYER BAL: " << *initBuyerBal << "\n";
|
||||
finBuyerBal = *initBuyerBal - purchaseAmount;
|
||||
|
||||
// std::cout << "FIN BUYER BAL: " << *finBuyerBal << "\n";
|
||||
|
||||
// compute amount to deliver
|
||||
static Rate const parityRate(QUALITY_ONE);
|
||||
auto xferRate = transferRate(view(), saleAmount->getIssuer());
|
||||
dstAmt =
|
||||
xferRate == parityRate
|
||||
dstAmt =
|
||||
xferRate == parityRate
|
||||
? purchaseAmount
|
||||
: multiplyRound(purchaseAmount, xferRate, purchaseAmount.issue(), true);
|
||||
|
||||
if (!sellerLow)
|
||||
dstAmt->negate();
|
||||
// std::cout << "SELLER LOW: " << sellerLow << "\n";
|
||||
// std::cout << "DEST AMT: " << *dstAmt << "\n";
|
||||
// if (!sellerLow)
|
||||
// dstAmt->negate();
|
||||
|
||||
initSellerBal = !sleDstLine
|
||||
? purchaseAmount.zeroed()
|
||||
: (sellerLow ? (*sleDstLine)[sfBalance] : -(*sleDstLine)[sfBalance]);
|
||||
// std::cout << "TRUE DEST AMT: " << *dstAmt << "\n";
|
||||
initSellerBal = !sleDstLine
|
||||
? purchaseAmount.zeroed()
|
||||
: sellerLow ? ((*sleDstLine)[sfBalance]) : -((*sleDstLine)[sfBalance]);
|
||||
|
||||
// std::cout << "INIT SELLER BAL: " << *initSellerBal << "\n";
|
||||
finSellerBal = *initSellerBal + *dstAmt;
|
||||
|
||||
// std::cout << "FINAL SELLER BAL: " << *finSellerBal << "\n";
|
||||
}
|
||||
|
||||
// sanity check balance mutations (xrp or iou, both are checked the same way now)
|
||||
if (*finSellerBal < *initSellerBal)
|
||||
{
|
||||
std::cout << "finSellerBal" << *finSellerBal << "< initSellerBal" << *initSellerBal << "\n";
|
||||
JLOG(j.warn())
|
||||
<< "URIToken txid=" << ctx_.tx.getTransactionID() << " "
|
||||
<< "finSellerBal < initSellerBal";
|
||||
@@ -519,6 +547,7 @@ URIToken::doApply()
|
||||
|
||||
if (*finBuyerBal > *initBuyerBal)
|
||||
{
|
||||
std::cout << "finBuyerBal > initBuyerBal\n " << "\n";
|
||||
JLOG(j.warn())
|
||||
<< "URIToken txid=" << ctx_.tx.getTransactionID() << " "
|
||||
<< "finBuyerBal > initBuyerBal";
|
||||
@@ -527,6 +556,7 @@ URIToken::doApply()
|
||||
|
||||
if (*finBuyerBal < beast::zero)
|
||||
{
|
||||
std::cout << "finBuyerBal < 0\n " << "\n";
|
||||
JLOG(j.warn())
|
||||
<< "URIToken txid=" << ctx_.tx.getTransactionID() << " "
|
||||
<< "finBuyerBal < 0";
|
||||
@@ -535,6 +565,7 @@ URIToken::doApply()
|
||||
|
||||
if (*finSellerBal < beast::zero)
|
||||
{
|
||||
std::cout << "finSellerBal < 0\n " << "\n";
|
||||
JLOG(j.warn())
|
||||
<< "URIToken txid=" << ctx_.tx.getTransactionID() << " "
|
||||
<< "finSellerBal < 0";
|
||||
@@ -693,7 +724,7 @@ URIToken::doApply()
|
||||
|
||||
view().update(sleU);
|
||||
view().update(sleOwner);
|
||||
|
||||
// std::cout << "BUY tecSUCCESS" << "\n";
|
||||
return tesSUCCESS;
|
||||
}
|
||||
case URIOperation::Burn:
|
||||
@@ -714,6 +745,7 @@ URIToken::doApply()
|
||||
auto const page = (*sleU)[sfOwnerNode];
|
||||
if (!view().dirRemove(keylet::ownerDir(*owner), page, kl->key, true))
|
||||
{
|
||||
|
||||
JLOG(j.fatal())
|
||||
<< "Could not remove URIToken from owner directory";
|
||||
return tefBAD_LEDGER;
|
||||
@@ -721,6 +753,7 @@ URIToken::doApply()
|
||||
|
||||
view().erase(sleU);
|
||||
adjustOwnerCount(view(), sle, -1, j);
|
||||
// std::cout << "BURN tecSUCCESS" << "\n";
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -740,6 +773,7 @@ URIToken::doApply()
|
||||
sleU->setFieldAmount(sfAmount, ctx_.tx[sfAmount]);
|
||||
|
||||
view().update(sleU);
|
||||
// std::cout << "SELL tecSUCCESS" << "\n";
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,23 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
return std::distance(ownerDir.begin(), ownerDir.end());
|
||||
};
|
||||
|
||||
static std::pair<uint256, std::shared_ptr<SLE const>>
|
||||
uriTokenKeyAndSle(
|
||||
ReadView const& view,
|
||||
jtx::Account const& account,
|
||||
std::string const& uri)
|
||||
{
|
||||
auto const k = keylet::uritoken(account, Blob(uri.begin(), uri.end()));
|
||||
return {k.key, view.read(k)};
|
||||
}
|
||||
|
||||
static bool
|
||||
uritExists(ReadView const& view, uint256 const& id)
|
||||
{
|
||||
auto const slep = view.read({ltURI_TOKEN, id});
|
||||
return bool(slep);
|
||||
}
|
||||
|
||||
static Json::Value
|
||||
mint(
|
||||
jtx::Account const& account,
|
||||
@@ -124,6 +141,30 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
debugBalance(
|
||||
jtx::Env const& env,
|
||||
std::string const& name,
|
||||
jtx::Account const& account,
|
||||
jtx::IOU const& iou)
|
||||
{
|
||||
std::cout << name << " BALANCE XRP: " << env.balance(account) << "\n";
|
||||
std::cout << name << " BALANCE USD: " << env.balance(account, iou.issue()) << "\n";
|
||||
}
|
||||
|
||||
// void
|
||||
// debugOwnerDir(
|
||||
// jtx::Env const& env,
|
||||
// std::string const& name,
|
||||
// jtx::Account const& account,
|
||||
// std::string const& uri)
|
||||
// {
|
||||
// auto const [urit, uritSle] = uriTokenKeyAndSle(env.current(), account, uri);
|
||||
// std::cout << "URIT: " << urit << "\n";
|
||||
// std::cout << name << "IN OWNER DIR: " << inOwnerDir(env.current(), account, uritSle) << "\n";
|
||||
// std::cout << name << "DIR: " << ownerDirCount(env.current(), account) << "\n";
|
||||
// }
|
||||
|
||||
void
|
||||
testEnabled(FeatureBitset features)
|
||||
{
|
||||
@@ -414,6 +455,7 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const carol = Account("carol");
|
||||
auto const dave = Account("dave");
|
||||
auto const gw = Account("gw");
|
||||
auto const USD = gw["USD"];
|
||||
auto const EUR = gw["EUR"];
|
||||
@@ -454,7 +496,7 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
// tecNO_PERMISSION - for sale to dest, you are not dest
|
||||
env(buy(carol, id, USD(10)), ter(tecNO_PERMISSION));
|
||||
env.close();
|
||||
|
||||
|
||||
// tecNFTOKEN_BUY_SELL_MISMATCH - invalid buy sell amounts
|
||||
env(buy(bob, id, EUR(10)), ter(tecNFTOKEN_BUY_SELL_MISMATCH));
|
||||
env.close();
|
||||
@@ -483,13 +525,63 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
//----------------------------------------------------------------------
|
||||
// doApply
|
||||
|
||||
// clear sell
|
||||
env(clear(alice, id));
|
||||
env.close();
|
||||
|
||||
// tecNO_PERMISSION - not listed
|
||||
env(buy(bob, id, USD(10)), ter(tecNO_PERMISSION));
|
||||
env.close();
|
||||
|
||||
// set sell
|
||||
env(sell(alice, id, USD(10)), txflags(tfSell), jtx::token::destination(bob));
|
||||
env.close();
|
||||
|
||||
// tecNO_PERMISSION - for sale to dest, you are not dest
|
||||
env(buy(carol, id, USD(10)), ter(tecNO_PERMISSION));
|
||||
env.close();
|
||||
|
||||
// tecNFTOKEN_BUY_SELL_MISMATCH - invalid buy sell amounts
|
||||
// tecINSUFFICIENT_PAYMENT - insuficient xrp
|
||||
env(buy(bob, id, EUR(10)), ter(tecNFTOKEN_BUY_SELL_MISMATCH));
|
||||
env.close();
|
||||
|
||||
// clear sell and set xrp sell
|
||||
env(clear(alice, id));
|
||||
env(sell(alice, id, XRP(1000)), txflags(tfSell));
|
||||
env.close();
|
||||
|
||||
// tecINSUFFICIENT_PAYMENT - insuficient xrp sent
|
||||
env(buy(bob, id, XRP(900)), ter(tecINSUFFICIENT_PAYMENT));
|
||||
env.close();
|
||||
// tecINSUFFICIENT_FUNDS - insuficient xrp - fees
|
||||
// tecINSUFFICIENT_FUNDS - insuficient amount
|
||||
// tecNO_LINE_INSUF_RESERVE - insuficient amount
|
||||
env(buy(bob, id, XRP(1000)), ter(tecINSUFFICIENT_FUNDS));
|
||||
env.close();
|
||||
|
||||
// clear sell and set usd sell
|
||||
env(clear(alice, id));
|
||||
env(sell(alice, id, USD(1000)), txflags(tfSell));
|
||||
env.close();
|
||||
|
||||
// tecINSUFFICIENT_PAYMENT - insuficient amount sent
|
||||
env(buy(bob, id, USD(900)), ter(tecINSUFFICIENT_PAYMENT));
|
||||
env.close();
|
||||
|
||||
// tecINSUFFICIENT_FUNDS - insuficient amount sent
|
||||
env(buy(bob, id, USD(10000)), ter(tecINSUFFICIENT_FUNDS));
|
||||
env.close();
|
||||
|
||||
// fund dave 200 xrp (not enough for reserve)
|
||||
env.fund(XRP(260), dave);
|
||||
env.trust(USD(10000), dave);
|
||||
env(pay(gw, dave, USD(1000)));
|
||||
env.close();
|
||||
|
||||
// auto const reserveFee = env.current()->fees().accountReserve(ownerDirCount(*env.current(), dave));
|
||||
// std::cout << "XRP RESERVE: " << reserveFee << "\n";
|
||||
// tecNO_LINE_INSUF_RESERVE - insuficient xrp to create line
|
||||
// env(buy(dave, id, USD(1000)), ter(tecNO_LINE_INSUF_RESERVE));
|
||||
// env.close();
|
||||
|
||||
// tecDIR_FULL - unknown how to test/handle
|
||||
// tecINTERNAL - unknown how to test/handle
|
||||
// tecINTERNAL - unknown how to test/handle
|
||||
@@ -501,14 +593,380 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
// tecINTERNAL - unknown how to test/handle
|
||||
}
|
||||
|
||||
void
|
||||
testClearInvalid(FeatureBitset features)
|
||||
{
|
||||
testcase("clear_invalid");
|
||||
using namespace jtx;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
// setup env
|
||||
Env env{*this, features};
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const gw = Account("gw");
|
||||
auto const USD = gw["USD"];
|
||||
auto const EUR = gw["EUR"];
|
||||
env.fund(XRP(1000), alice, bob, gw);
|
||||
env.trust(USD(10000), alice);
|
||||
env.trust(USD(10000), bob);
|
||||
env.close();
|
||||
env(pay(gw, alice, USD(1000)));
|
||||
env(pay(gw, bob, USD(1000)));
|
||||
env.close();
|
||||
|
||||
// mint token
|
||||
std::string const uri(2, '?');
|
||||
std::string const id{strHex(tokenid(alice, uri))};
|
||||
env(mint(alice, uri));
|
||||
env.close();
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// operator preflight
|
||||
// temDISABLED
|
||||
|
||||
// temMALFORMED - invalid buy flag
|
||||
env(clear(alice, id), txflags(0b000100011U), ter(temMALFORMED));
|
||||
env.close();
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// preclaim
|
||||
|
||||
// tecNO_PERMISSION - not your uritoken
|
||||
env(clear(bob, id), ter(tecNO_PERMISSION));
|
||||
env.close();
|
||||
}
|
||||
|
||||
void
|
||||
testMetaAndOwnership(FeatureBitset features)
|
||||
{
|
||||
testcase("Metadata & Ownership");
|
||||
|
||||
using namespace jtx;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const gw = Account("gw");
|
||||
auto const USD = gw["USD"];
|
||||
|
||||
std::string const uri(maxTokenURILength, '?');
|
||||
std::string const id{strHex(tokenid(alice, uri))};
|
||||
|
||||
{
|
||||
// Test without adding the uritoken to the recipient's owner
|
||||
// directory
|
||||
Env env{*this, features};
|
||||
env.fund(XRP(1000), alice, bob, gw);
|
||||
env.trust(USD(10000), alice);
|
||||
env.trust(USD(10000), bob);
|
||||
env.close();
|
||||
env(pay(gw, alice, USD(1000)));
|
||||
env(pay(gw, bob, USD(1000)));
|
||||
env.close();
|
||||
|
||||
env(mint(alice, uri));
|
||||
env(sell(alice, id, USD(10)), txflags(tfSell));
|
||||
env.close();
|
||||
auto const [urit, uritSle] = uriTokenKeyAndSle(*env.current(), alice, uri);
|
||||
BEAST_EXPECT(inOwnerDir(*env.current(), alice, uritSle));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uritSle));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
|
||||
// // alice sets the sell offer
|
||||
// // bob sets the buy offer
|
||||
env(buy(bob, id, USD(10)));
|
||||
BEAST_EXPECT(uritExists(*env.current(), urit));
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, uritSle));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uritSle));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 2);
|
||||
}
|
||||
{
|
||||
// Test with adding the uritoken to the recipient's owner
|
||||
// directory
|
||||
Env env{*this, features};
|
||||
env.fund(XRP(1000), alice, bob, gw);
|
||||
env.trust(USD(10000), alice);
|
||||
env.trust(USD(10000), bob);
|
||||
env.close();
|
||||
env(pay(gw, alice, USD(1000)));
|
||||
env(pay(gw, bob, USD(1000)));
|
||||
env.close();
|
||||
|
||||
env(mint(alice, uri));
|
||||
env(sell(alice, id, USD(10)), txflags(tfSell));
|
||||
env.close();
|
||||
auto const [urit, uritSle] = uriTokenKeyAndSle(*env.current(), alice, uri);
|
||||
BEAST_EXPECT(inOwnerDir(*env.current(), alice, uritSle));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uritSle));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
|
||||
// // alice sets the sell offer
|
||||
// // bob sets the buy offer
|
||||
env(buy(bob, id, USD(10)));
|
||||
env.close();
|
||||
BEAST_EXPECT(uritExists(*env.current(), urit));
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, uritSle));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uritSle));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testAccountDelete(FeatureBitset features)
|
||||
{
|
||||
testcase("Account Delete");
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals::chrono_literals;
|
||||
auto rmAccount = [this](
|
||||
Env& env,
|
||||
Account const& toRm,
|
||||
Account const& dst,
|
||||
TER expectedTer = tesSUCCESS) {
|
||||
// only allow an account to be deleted if the account's sequence
|
||||
// number is at least 256 less than the current ledger sequence
|
||||
for (auto minRmSeq = env.seq(toRm) + 257;
|
||||
env.current()->seq() < minRmSeq;
|
||||
env.close())
|
||||
{
|
||||
}
|
||||
|
||||
env(acctdelete(toRm, dst),
|
||||
fee(drops(env.current()->fees().increment)),
|
||||
ter(expectedTer));
|
||||
env.close();
|
||||
this->BEAST_EXPECT(
|
||||
isTesSuccess(expectedTer) ==
|
||||
!env.closed()->exists(keylet::account(toRm.id())));
|
||||
};
|
||||
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const carol = Account("carol");
|
||||
auto const gw = Account("gw");
|
||||
auto const USD = gw["USD"];
|
||||
|
||||
std::string const uri(maxTokenURILength, '?');
|
||||
std::string const id{strHex(tokenid(alice, uri))};
|
||||
|
||||
{
|
||||
Env env{*this, features};
|
||||
env.fund(XRP(1000), alice, bob, carol, gw);
|
||||
env.trust(USD(10000), alice);
|
||||
env.trust(USD(10000), bob);
|
||||
env.trust(USD(10000), carol);
|
||||
env.close();
|
||||
env(pay(gw, alice, USD(1000)));
|
||||
env(pay(gw, bob, USD(1000)));
|
||||
env(pay(gw, carol, USD(1000)));
|
||||
env.close();
|
||||
|
||||
auto const feeDrops = env.current()->fees().base;
|
||||
|
||||
// debugBalance(env, "alice", alice, USD);
|
||||
// debugBalance(env, "bob", bob, USD);
|
||||
|
||||
// mint a uritoken from alice
|
||||
env(mint(alice, uri));
|
||||
env.close();
|
||||
BEAST_EXPECT(uritExists(*env.current(), tokenid(alice, uri)));
|
||||
env(sell(alice, id, USD(10)), txflags(tfSell));
|
||||
env.close();
|
||||
|
||||
// alice has trustline + mint + sell
|
||||
rmAccount(env, alice, bob, tecHAS_OBLIGATIONS);
|
||||
|
||||
env(clear(alice, id));
|
||||
env(burn(alice, id), txflags(tfBurn));
|
||||
env.close();
|
||||
|
||||
// alice still has a trustline
|
||||
rmAccount(env, alice, bob, tecHAS_OBLIGATIONS);
|
||||
|
||||
BEAST_EXPECT(uritExists(*env.current(), tokenid(alice, uri)));
|
||||
|
||||
// buy should fail if the uri token was removed
|
||||
auto preBob = env.balance(bob, USD.issue());
|
||||
env(buy(bob, id, USD(10)), ter(tecNO_ENTRY));
|
||||
env.close();
|
||||
BEAST_EXPECT(env.balance(bob, USD.issue()) == preBob);
|
||||
|
||||
env(mint(bob, uri));
|
||||
BEAST_EXPECT(uritExists(*env.current(), tokenid(bob, uri)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testUsingTickets(FeatureBitset features)
|
||||
{
|
||||
testcase("using tickets");
|
||||
using namespace jtx;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
Env env{*this, features};
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const gw = Account("gw");
|
||||
auto USD = gw["USD"];
|
||||
env.fund(XRP(1000), alice, bob, gw);
|
||||
env.trust(USD(10000), alice);
|
||||
env.trust(USD(10000), bob);
|
||||
env.close();
|
||||
env(pay(gw, alice, USD(1000)));
|
||||
env(pay(gw, bob, USD(1000)));
|
||||
env.close();
|
||||
|
||||
// alice and bob grab enough tickets for all of the following
|
||||
// transactions. Note that once the tickets are acquired alice's
|
||||
// and bob's account sequence numbers should not advance.
|
||||
std::uint32_t aliceTicketSeq{env.seq(alice) + 1};
|
||||
env(ticket::create(alice, 10));
|
||||
std::uint32_t const aliceSeq{env.seq(alice)};
|
||||
|
||||
std::uint32_t bobTicketSeq{env.seq(bob) + 1};
|
||||
env(ticket::create(bob, 10));
|
||||
std::uint32_t const bobSeq{env.seq(bob)};
|
||||
|
||||
std::string const uri(maxTokenURILength, '?');
|
||||
std::string const id{strHex(tokenid(alice, uri))};
|
||||
|
||||
env(mint(alice, uri), ticket::use(aliceTicketSeq++));
|
||||
|
||||
env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
|
||||
BEAST_EXPECT(env.seq(alice) == aliceSeq);
|
||||
|
||||
BEAST_EXPECT(uritExists(*env.current(), tokenid(alice, uri)));
|
||||
|
||||
// {
|
||||
// auto const preAlice = env.balance(alice);
|
||||
// env(sell(alice, id, XRP(1000)), ticket::use(aliceTicketSeq++));
|
||||
|
||||
// env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
|
||||
// BEAST_EXPECT(env.seq(alice) == aliceSeq);
|
||||
|
||||
// auto const feeDrops = env.current()->fees().base;
|
||||
// BEAST_EXPECT(env.balance(alice) == preAlice - XRP(1000) - feeDrops);
|
||||
// }
|
||||
|
||||
// BEAST_EXPECT(uritExists(*env.current(), tokenid(alice, uri)));
|
||||
|
||||
// {
|
||||
// // No signature needed since the bob is buying
|
||||
// auto const preBob = env.balance(bob);
|
||||
// env(buy(bob, id, USD(10)), ticket::use(bobTicketSeq++));
|
||||
|
||||
// env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
|
||||
// BEAST_EXPECT(env.seq(bob) == bobSeq);
|
||||
|
||||
// BEAST_EXPECT(uritExists(*env.current(), tokenid(alice, uri)));
|
||||
// BEAST_EXPECT(env.balance(bob) == preBob + USD(10));
|
||||
// }
|
||||
// {
|
||||
// // Claim with signature
|
||||
// auto preBob = env.balance(bob);
|
||||
// auto const delta = XRP(500);
|
||||
// auto const reqBal = chanBal + delta;
|
||||
// auto const authAmt = reqBal + XRP(100);
|
||||
// assert(reqBal <= chanAmt);
|
||||
// auto const sig =
|
||||
// signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
|
||||
// env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()),
|
||||
// ticket::use(bobTicketSeq++));
|
||||
|
||||
// env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
|
||||
// BEAST_EXPECT(env.seq(bob) == bobSeq);
|
||||
|
||||
// BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
|
||||
// BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
|
||||
// auto const feeDrops = env.current()->fees().base;
|
||||
// BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops);
|
||||
// chanBal = reqBal;
|
||||
|
||||
// // claim again
|
||||
// preBob = env.balance(bob);
|
||||
// // A transaction that generates a tec still consumes its ticket.
|
||||
// env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()),
|
||||
// ticket::use(bobTicketSeq++),
|
||||
// ter(tecUNFUNDED_PAYMENT));
|
||||
|
||||
// env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
|
||||
// BEAST_EXPECT(env.seq(bob) == bobSeq);
|
||||
|
||||
// BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
|
||||
// BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
|
||||
// BEAST_EXPECT(env.balance(bob) == preBob - feeDrops);
|
||||
// }
|
||||
// {
|
||||
// // Try to claim more than authorized
|
||||
// auto const preBob = env.balance(bob);
|
||||
// STAmount const authAmt = chanBal + XRP(500);
|
||||
// STAmount const reqAmt = authAmt + drops(1);
|
||||
// assert(reqAmt <= chanAmt);
|
||||
// // Note that since claim() returns a tem (neither tec nor tes),
|
||||
// // the ticket is not consumed. So we don't increment bobTicket.
|
||||
// auto const sig =
|
||||
// signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
|
||||
// env(claim(bob, chan, reqAmt, authAmt, Slice(sig), alice.pk()),
|
||||
// ticket::use(bobTicketSeq),
|
||||
// ter(temBAD_AMOUNT));
|
||||
|
||||
// env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
|
||||
// BEAST_EXPECT(env.seq(bob) == bobSeq);
|
||||
|
||||
// BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
|
||||
// BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
|
||||
// BEAST_EXPECT(env.balance(bob) == preBob);
|
||||
// }
|
||||
|
||||
// // Dst tries to fund the channel
|
||||
// env(fund(bob, chan, XRP(1000)),
|
||||
// ticket::use(bobTicketSeq++),
|
||||
// ter(tecNO_PERMISSION));
|
||||
|
||||
// env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
|
||||
// BEAST_EXPECT(env.seq(bob) == bobSeq);
|
||||
|
||||
// BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
|
||||
// BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
|
||||
|
||||
// {
|
||||
// // Dst closes channel
|
||||
// auto const preAlice = env.balance(alice);
|
||||
// auto const preBob = env.balance(bob);
|
||||
// env(claim(bob, chan),
|
||||
// txflags(tfClose),
|
||||
// ticket::use(bobTicketSeq++));
|
||||
|
||||
// env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
|
||||
// BEAST_EXPECT(env.seq(bob) == bobSeq);
|
||||
|
||||
// BEAST_EXPECT(!channelExists(*env.current(), chan));
|
||||
// auto const feeDrops = env.current()->fees().base;
|
||||
// auto const delta = chanAmt - chanBal;
|
||||
// assert(delta > beast::zero);
|
||||
// BEAST_EXPECT(env.balance(alice) == preAlice + delta);
|
||||
// BEAST_EXPECT(env.balance(bob) == preBob - feeDrops);
|
||||
// }
|
||||
// env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
|
||||
// BEAST_EXPECT(env.seq(alice) == aliceSeq);
|
||||
// env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
|
||||
// BEAST_EXPECT(env.seq(bob) == bobSeq);
|
||||
}
|
||||
|
||||
void
|
||||
testWithFeats(FeatureBitset features)
|
||||
{
|
||||
testEnabled(features);
|
||||
testMintInvalid(features);
|
||||
testBurnInvalid(features);
|
||||
testSellInvalid(features);
|
||||
testBuyInvalid(features);
|
||||
// testEnabled(features);
|
||||
// testMintInvalid(features);
|
||||
// testBurnInvalid(features);
|
||||
// testSellInvalid(features);
|
||||
// testBuyInvalid(features);
|
||||
// testClearInvalid(features);
|
||||
// testMetaAndOwnership(features);
|
||||
// testAccountDelete(features);
|
||||
testUsingTickets(features);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user