mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
add gateway & uri test
This commit is contained in:
committed by
Richard Holland
parent
9998e33495
commit
bcdaca0f23
@@ -43,10 +43,11 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
inOwnerDir(
|
||||
ReadView const& view,
|
||||
jtx::Account const& acct,
|
||||
std::shared_ptr<SLE const> const& token)
|
||||
std::string const& uri)
|
||||
{
|
||||
auto const [urit, uritSle] = uriTokenKeyAndSle(view, acct, uri);
|
||||
ripple::Dir const ownerDir(view, keylet::ownerDir(acct.id()));
|
||||
return std::find(ownerDir.begin(), ownerDir.end(), token) !=
|
||||
return std::find(ownerDir.begin(), ownerDir.end(), uritSle) !=
|
||||
ownerDir.end();
|
||||
}
|
||||
|
||||
@@ -84,47 +85,59 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
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";
|
||||
std::cout << name << " BALANCE LINE: " << lineBalance(env, account, iou)
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void
|
||||
debugToken(
|
||||
ReadView const& view,
|
||||
uint256 const& id)
|
||||
debugToken(ReadView const& view, uint256 const& id)
|
||||
{
|
||||
// debugToken(*env.current(), tid);
|
||||
auto const slep = view.read({ltURI_TOKEN, id});
|
||||
if (!slep)
|
||||
return;
|
||||
|
||||
std::cout << " ---- DEBUG TOKEN ----" << "\n";
|
||||
std::cout << " ---- DEBUG TOKEN ----"
|
||||
<< "\n";
|
||||
std::cout << "BURNABLE: " << (slep->getFlags() & tfBurnable) << "\n";
|
||||
std::cout << "OWNER: " << slep->getAccountID(sfOwner)
|
||||
<< "\n";
|
||||
std::cout << "ISSUER: " << slep->getAccountID(sfIssuer)
|
||||
<< "\n";
|
||||
std::cout << "OWNER: " << slep->getAccountID(sfOwner) << "\n";
|
||||
std::cout << "ISSUER: " << slep->getAccountID(sfIssuer) << "\n";
|
||||
// std::cout << " sfURI: " << slep->getFieldVL(sfURI) << "\n";
|
||||
// std::cout << " sfDigest: " << (*slep)[sfDigest] << "\n";
|
||||
if (slep->getFieldAmount(sfAmount))
|
||||
std::cout << "AMOUNT: " << slep->getFieldAmount(sfAmount)
|
||||
<< "\n";
|
||||
std::cout << "AMOUNT: " << slep->getFieldAmount(sfAmount) << "\n";
|
||||
|
||||
if (slep->getFieldAmount(sfAmount))
|
||||
std::cout << "DESTINATION: " << slep->getAccountID(sfDestination)
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void
|
||||
debugLimit(
|
||||
jtx::Env const& env,
|
||||
std::string const& name,
|
||||
jtx::Account const& account,
|
||||
jtx::Account const& gw,
|
||||
jtx::IOU const& iou)
|
||||
{
|
||||
std::cout << " ---- DEBUG LINE ----" << "\n";
|
||||
auto const aHigh = account.id() > gw.id();
|
||||
auto const sle = env.le(keylet::line(account, gw, iou.currency));
|
||||
std::cout << name << " IS HIGH: " << aHigh << "\n";
|
||||
std::cout << name << " HIGH: " << (*sle)[sfHighLimit] << "\n";
|
||||
std::cout << name << " LOW: " << (*sle)[sfLowLimit] << "\n";
|
||||
std::cout << name << " BALANCE: " << (*sle)[sfBalance] << "\n";
|
||||
}
|
||||
|
||||
static STAmount
|
||||
limitAmount(
|
||||
jtx::Env const& env,
|
||||
jtx::Account const& account,
|
||||
jtx::Account const& gw,
|
||||
jtx::IOU const& iou)
|
||||
{
|
||||
auto const aHigh = account.id() > gw.id();
|
||||
auto const sle = env.le(keylet::line(account, gw, iou.currency));
|
||||
if (sle && sle->isFieldPresent(aHigh ? sfLowLimit : sfHighLimit))
|
||||
return (*sle)[aHigh ? sfLowLimit : sfHighLimit];
|
||||
return STAmount(iou, 0);
|
||||
}
|
||||
|
||||
void
|
||||
testToken(
|
||||
ReadView const& view,
|
||||
@@ -146,11 +159,11 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(slep->getAccountID(sfOwner) == owner);
|
||||
BEAST_EXPECT(slep->getAccountID(sfIssuer) == issuer);
|
||||
// BEAST_EXPECT(slep->getFieldVL(sfURI).size() > uri.size());
|
||||
|
||||
|
||||
// test the ledger object optionals
|
||||
if(burnable)
|
||||
if (burnable)
|
||||
BEAST_EXPECT(slep->getFlags() & tfBurnable);
|
||||
|
||||
|
||||
if (amount != STAmount{0})
|
||||
BEAST_EXPECT(slep->getFieldAmount(sfAmount) == amount);
|
||||
|
||||
@@ -186,23 +199,11 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
lineBalance(
|
||||
jtx::Env const& env,
|
||||
jtx::Account const& account,
|
||||
jtx::Account const& gw,
|
||||
jtx::IOU const& iou)
|
||||
{
|
||||
auto const sle =
|
||||
env.le(keylet::line(account, iou.account, iou.currency));
|
||||
if (sle && sle->isFieldPresent(sfBalance))
|
||||
return (*sle)[sfBalance];
|
||||
return STAmount(iou, 0);
|
||||
}
|
||||
|
||||
static STAmount
|
||||
gwBalance(
|
||||
jtx::Env const& env,
|
||||
jtx::Account const& account,
|
||||
jtx::IOU const& iou)
|
||||
{
|
||||
auto const sle =
|
||||
env.le(keylet::line(iou.account, account, iou.currency));
|
||||
env.le(keylet::line(account, gw, iou.currency));
|
||||
if (sle && sle->isFieldPresent(sfBalance))
|
||||
return (*sle)[sfBalance];
|
||||
return STAmount(iou, 0);
|
||||
@@ -399,16 +400,6 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
env.close();
|
||||
|
||||
// tecDIR_FULL - directory full
|
||||
// pay alice xrp - 251 * required reserve (50) + 1
|
||||
// env(pay(env.master, alice, XRP(1) + XRP(251 * 50)));
|
||||
// env.close();
|
||||
|
||||
// env(mint(alice, uri), ter(tecDIR_FULL));
|
||||
// env.close();
|
||||
// auto const reserveFee =
|
||||
// env.current()->fees().accountReserve(ownerDirCount(*env.current(), alice));
|
||||
// std::cout << "RESERVE FEE: " << reserveFee << "\n";
|
||||
// debugXrp(env, "alice", alice);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,7 +503,7 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
// temBAD_CURRENCY - bad currency
|
||||
IOU const BAD{gw, badCurrency()};
|
||||
env(sell(alice, id, BAD(10)), ter(temBAD_CURRENCY));
|
||||
|
||||
|
||||
// temMALFORMED - no destination and 0 value
|
||||
env(sell(alice, id, USD(0)), ter(temMALFORMED));
|
||||
env.close();
|
||||
@@ -863,6 +854,8 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
env.close();
|
||||
BEAST_EXPECT(!uritokenExists(*env.current(), tid));
|
||||
}
|
||||
// mint 10 burn random
|
||||
// mint 10 burn in order
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1257,17 +1250,17 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
env.close();
|
||||
auto const [urit, uritSle] =
|
||||
uriTokenKeyAndSle(*env.current(), alice, uri);
|
||||
BEAST_EXPECT(inOwnerDir(*env.current(), alice, uritSle));
|
||||
BEAST_EXPECT(inOwnerDir(*env.current(), alice, uri));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uritSle));
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uri));
|
||||
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(uritokenExists(*env.current(), urit));
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, uritSle));
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, uri));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uritSle));
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uri));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 2);
|
||||
}
|
||||
{
|
||||
@@ -1287,18 +1280,18 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
env.close();
|
||||
auto const [urit, uritSle] =
|
||||
uriTokenKeyAndSle(*env.current(), alice, uri);
|
||||
BEAST_EXPECT(inOwnerDir(*env.current(), alice, uritSle));
|
||||
BEAST_EXPECT(inOwnerDir(*env.current(), alice, uri));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uritSle));
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uri));
|
||||
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(uritokenExists(*env.current(), urit));
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, uritSle));
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, uri));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uritSle));
|
||||
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, uri));
|
||||
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 2);
|
||||
}
|
||||
}
|
||||
@@ -1466,26 +1459,24 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
bool negative;
|
||||
};
|
||||
|
||||
std::array<TestAccountData, 8> tests = {
|
||||
{
|
||||
// src > dst && src > issuer && dst no trustline
|
||||
{Account("alice2"), Account("bob0"), Account{"gw0"}, false, true},
|
||||
// src < dst && src < issuer && dst no trustline
|
||||
{Account("carol0"), Account("dan1"), Account{"gw1"}, false, false},
|
||||
// dst > src && dst > issuer && dst no trustline
|
||||
{Account("dan1"), Account("alice2"), Account{"gw0"}, false, true},
|
||||
// dst < src && dst < issuer && dst no trustline
|
||||
{Account("bob0"), Account("carol0"), Account{"gw1"}, false, false},
|
||||
// src > dst && src > issuer && dst has trustline
|
||||
{Account("alice2"), Account("bob0"), Account{"gw0"}, true, true},
|
||||
// src < dst && src < issuer && dst has trustline
|
||||
{Account("carol0"), Account("dan1"), Account{"gw1"}, true, false},
|
||||
// dst > src && dst > issuer && dst has trustline
|
||||
{Account("dan1"), Account("alice2"), Account{"gw0"}, true, true},
|
||||
// dst < src && dst < issuer && dst has trustline
|
||||
{Account("bob0"), Account("carol0"), Account{"gw1"}, true, false},
|
||||
}
|
||||
};
|
||||
std::array<TestAccountData, 8> tests = {{
|
||||
// src > dst && src > issuer && dst no trustline
|
||||
{Account("alice2"), Account("bob0"), Account{"gw0"}, false, true},
|
||||
// src < dst && src < issuer && dst no trustline
|
||||
{Account("carol0"), Account("dan1"), Account{"gw1"}, false, false},
|
||||
// dst > src && dst > issuer && dst no trustline
|
||||
{Account("dan1"), Account("alice2"), Account{"gw0"}, false, true},
|
||||
// dst < src && dst < issuer && dst no trustline
|
||||
{Account("bob0"), Account("carol0"), Account{"gw1"}, false, false},
|
||||
// src > dst && src > issuer && dst has trustline
|
||||
{Account("alice2"), Account("bob0"), Account{"gw0"}, true, true},
|
||||
// src < dst && src < issuer && dst has trustline
|
||||
{Account("carol0"), Account("dan1"), Account{"gw1"}, true, false},
|
||||
// dst > src && dst > issuer && dst has trustline
|
||||
{Account("dan1"), Account("alice2"), Account{"gw0"}, true, true},
|
||||
// dst < src && dst < issuer && dst has trustline
|
||||
{Account("bob0"), Account("carol0"), Account{"gw1"}, true, false},
|
||||
}};
|
||||
|
||||
for (auto const& t : tests)
|
||||
{
|
||||
@@ -1513,8 +1504,8 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
|
||||
// dst can create sell
|
||||
auto const delta = USD(1000);
|
||||
auto const preSrc = lineBalance(env, t.src, USD);
|
||||
auto const preDst = lineBalance(env, t.dst, USD);
|
||||
auto const preSrc = lineBalance(env, t.src, t.gw, USD);
|
||||
auto const preDst = lineBalance(env, t.dst, t.gw, USD);
|
||||
env(sell(t.dst, id, delta));
|
||||
env.close();
|
||||
BEAST_EXPECT(preDst == preDst);
|
||||
@@ -1522,8 +1513,12 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
// src can create buy
|
||||
env(buy(t.src, id, delta));
|
||||
env.close();
|
||||
BEAST_EXPECT(lineBalance(env, t.src, USD) == (t.negative ? (preSrc + delta) : (preSrc - delta)));
|
||||
BEAST_EXPECT(lineBalance(env, t.dst, USD) == (t.negative ? (preDst - delta) : (preDst + delta)));
|
||||
BEAST_EXPECT(
|
||||
lineBalance(env, t.src, t.gw, USD) ==
|
||||
(t.negative ? (preSrc + delta) : (preSrc - delta)));
|
||||
BEAST_EXPECT(
|
||||
lineBalance(env, t.dst, t.gw, USD) ==
|
||||
(t.negative ? (preDst - delta) : (preDst + delta)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1534,49 +1529,120 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
|
||||
// issuer -> src
|
||||
// src > issuer
|
||||
// dest no trustline
|
||||
// negative tl balance
|
||||
struct TestAccountData
|
||||
{
|
||||
auto const src = Account("alice2");
|
||||
auto const gw = Account{"gw0"};
|
||||
auto const USD = gw["USD"];
|
||||
Account acct;
|
||||
Account gw;
|
||||
bool hasTrustline;
|
||||
bool negative;
|
||||
};
|
||||
|
||||
std::array<TestAccountData, 4> tests = {
|
||||
{
|
||||
// acct no trustline
|
||||
// acct > issuer
|
||||
{Account("alice2"), Account{"gw0"}, false, true},
|
||||
// acct < issuer
|
||||
{Account("carol0"), Account{"gw1"}, false, false},
|
||||
|
||||
// acct has trustline
|
||||
// acct > issuer
|
||||
{Account("alice2"), Account{"gw0"}, true, true},
|
||||
// acct < issuer
|
||||
{Account("carol0"), Account{"gw1"}, true, false},
|
||||
}
|
||||
};
|
||||
|
||||
// test gateway is buyer
|
||||
for (auto const& t : tests)
|
||||
{
|
||||
Env env{*this, features};
|
||||
env.fund(XRP(10000), src, gw);
|
||||
auto const USD = t.gw["USD"];
|
||||
env.fund(XRP(5000), t.acct, t.gw);
|
||||
env.close();
|
||||
|
||||
if (t.hasTrustline)
|
||||
env.trust(USD(100000), t.acct);
|
||||
|
||||
env.close();
|
||||
|
||||
// src can create uritoken
|
||||
if (t.hasTrustline)
|
||||
env(pay(t.gw, t.acct, USD(10000)));
|
||||
|
||||
env.close();
|
||||
|
||||
// acct can create uritoken
|
||||
std::string const uri(maxTokenURILength, '?');
|
||||
std::string const id{strHex(tokenid(src, uri))};
|
||||
env(mint(src, uri));
|
||||
std::string const id{strHex(tokenid(t.acct, uri))};
|
||||
env(mint(t.acct, uri));
|
||||
env.close();
|
||||
|
||||
// src can create sell w/out token
|
||||
// acct can create sell w/out token
|
||||
auto const delta = USD(1000);
|
||||
auto const preSrc = lineBalance(env, src, USD);
|
||||
auto const preDst = lineBalance(env, gw, USD);
|
||||
env(sell(src, id, delta));
|
||||
auto const preAcct = lineBalance(env, t.acct, t.gw, USD);
|
||||
auto const preGw = lineBalance(env, t.gw, t.acct, USD);
|
||||
env(sell(t.acct, id, delta));
|
||||
env.close();
|
||||
BEAST_EXPECT(preDst == preDst);
|
||||
auto const preAmount = t.hasTrustline ? 10000 : 0;
|
||||
BEAST_EXPECT(preAcct == (t.negative ? -USD(preAmount) : USD(preAmount)));
|
||||
|
||||
// gw can create buy
|
||||
env(buy(gw, id, delta));
|
||||
env(buy(t.gw, id, delta));
|
||||
env.close();
|
||||
BEAST_EXPECT(lineBalance(env, src, USD) == preSrc - delta);
|
||||
BEAST_EXPECT(lineBalance(env, gw, USD) == preDst + delta);
|
||||
|
||||
auto const gwbal = gwBalance(env, src, USD);
|
||||
std::cout << "GW BAL: " << gwbal << "\n";
|
||||
std::cout << "ALICE BAL: " << env.balance(src, USD.issue()) << "\n";
|
||||
auto const postAmount = t.hasTrustline ? 11000 : 1000;
|
||||
BEAST_EXPECT(
|
||||
lineBalance(env, t.acct, t.gw, USD) ==
|
||||
(t.negative ? -USD(postAmount) : USD(postAmount)));
|
||||
BEAST_EXPECT(
|
||||
lineBalance(env, t.gw, t.acct, USD) ==
|
||||
(t.negative ? -USD(postAmount) : USD(postAmount)));
|
||||
}
|
||||
|
||||
// test gateway is seller
|
||||
// ignore hasTrustline
|
||||
for (auto const& t : tests)
|
||||
{
|
||||
Env env{*this, features};
|
||||
auto const USD = t.gw["USD"];
|
||||
env.fund(XRP(5000), t.acct, t.gw);
|
||||
env.close();
|
||||
env.trust(USD(100000), t.acct);
|
||||
env.close();
|
||||
env(pay(t.gw, t.acct, USD(10000)));
|
||||
env.close();
|
||||
|
||||
// gw can create uritoken
|
||||
std::string const uri(maxTokenURILength, '?');
|
||||
std::string const id{strHex(tokenid(t.gw, uri))};
|
||||
env(mint(t.gw, uri));
|
||||
env.close();
|
||||
|
||||
// gw can create sell w/out token
|
||||
auto const delta = USD(1000);
|
||||
auto const preAcct = lineBalance(env, t.acct, t.gw, USD);
|
||||
auto const preGw = lineBalance(env, t.gw, t.acct, USD);
|
||||
env(sell(t.gw, id, delta));
|
||||
env.close();
|
||||
auto const preAmount = 10000;
|
||||
BEAST_EXPECT(preAcct == (t.negative ? -USD(preAmount) : USD(preAmount)));
|
||||
|
||||
// acct can create buy
|
||||
env(buy(t.acct, id, delta));
|
||||
env.close();
|
||||
auto const postAmount = 9000;
|
||||
BEAST_EXPECT(
|
||||
lineBalance(env, t.acct, t.gw, USD) ==
|
||||
(t.negative ? -USD(postAmount) : USD(postAmount)));
|
||||
BEAST_EXPECT(
|
||||
lineBalance(env, t.gw, t.acct, USD) ==
|
||||
(t.negative ? -USD(postAmount) : USD(postAmount)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testRequireAuth(FeatureBitset features)
|
||||
{
|
||||
testcase("Require Auth");
|
||||
testcase("require_auth");
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
|
||||
@@ -1793,38 +1859,37 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(env.balance(alice, USD.issue()) == USD(10225));
|
||||
BEAST_EXPECT(env.balance(bob, USD.issue()) == preBob - delta);
|
||||
}
|
||||
// // test issuer doesnt pay own rate
|
||||
// {
|
||||
// Env env{*this, features};
|
||||
// env.fund(XRP(10000), alice, gw);
|
||||
// env(rate(gw, 1.25));
|
||||
// env.close();
|
||||
// env.trust(USD(100000), alice);
|
||||
// env.close();
|
||||
// env(pay(gw, alice, USD(10000)));
|
||||
// env.close();
|
||||
// test issuer doesnt pay own rate
|
||||
{
|
||||
Env env{*this, features};
|
||||
env.fund(XRP(10000), alice, gw);
|
||||
env(rate(gw, 1.25));
|
||||
env.close();
|
||||
env.trust(USD(100000), alice);
|
||||
env.close();
|
||||
env(pay(gw, alice, USD(10000)));
|
||||
env.close();
|
||||
|
||||
// // issuer with rate can create paychan
|
||||
// auto const pk = gw.pk();
|
||||
// auto const settleDelay = 100s;
|
||||
// auto const chan = channel(gw, alice, env.seq(gw));
|
||||
// env(create(gw, alice, USD(1000), settleDelay, pk));
|
||||
// env.close();
|
||||
std::string const uri(maxTokenURILength, '?');
|
||||
auto const tid = tokenid(alice, uri);
|
||||
std::string const hexid{strHex(tid)};
|
||||
|
||||
// // issuer can claim paychan, alice has trustline
|
||||
// auto const preLocked = -lockedAmount(env, alice, gw, USD);
|
||||
// auto const preAlice = env.balance(alice, USD.issue());
|
||||
// auto chanBal = channelBalance(*env.current(), chan);
|
||||
// auto chanAmt = channelAmount(*env.current(), chan);
|
||||
// auto const delta = USD(500);
|
||||
// auto const reqBal = chanBal + delta;
|
||||
// auto const authAmt = reqBal + USD(100);
|
||||
// env(claim(gw, chan, reqBal, authAmt));
|
||||
// env.close();
|
||||
// auto const postLocked = -lockedAmount(env, alice, gw, USD);
|
||||
// BEAST_EXPECT(postLocked == USD(0));
|
||||
// BEAST_EXPECT(env.balance(alice, USD.issue()) == preAlice + delta);
|
||||
// }
|
||||
auto const delta = USD(10);
|
||||
auto const preAlice = env.balance(alice, USD.issue());
|
||||
|
||||
// alice mints
|
||||
env(mint(alice, uri));
|
||||
env.close();
|
||||
|
||||
// alice sells
|
||||
env(sell(alice, hexid, delta));
|
||||
env.close();
|
||||
|
||||
// gw buys
|
||||
env(buy(gw, hexid, delta));
|
||||
env.close();
|
||||
BEAST_EXPECT(env.balance(alice, USD.issue()) == preAlice + delta);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1865,6 +1930,349 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testLimitAmount(FeatureBitset features)
|
||||
{
|
||||
testcase("limit_amount");
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const carol = Account("carol");
|
||||
auto const gw = Account{"gateway"};
|
||||
auto const USD = gw["USD"];
|
||||
{
|
||||
Env env{*this, features};
|
||||
env.fund(XRP(10000), alice, bob, carol, gw);
|
||||
env.close();
|
||||
env.trust(USD(1000), bob);
|
||||
env.trust(USD(1000), carol);
|
||||
env.close();
|
||||
env(pay(gw, bob, USD(1000)));
|
||||
env(pay(gw, carol, USD(1000)));
|
||||
env.close();
|
||||
std::string const uri(maxTokenURILength, '?');
|
||||
auto const tid = tokenid(alice, uri);
|
||||
std::string const hexid{strHex(tid)};
|
||||
env(mint(alice, uri));
|
||||
env.close();
|
||||
BEAST_EXPECT(inOwnerDir(*env.current(), alice, uri));
|
||||
env(sell(alice, hexid, USD(10)));
|
||||
env.close();
|
||||
auto preLimit = limitAmount(env, alice, gw, USD);
|
||||
BEAST_EXPECT(preLimit == USD(0));
|
||||
env(buy(bob, hexid, USD(10)));
|
||||
env.close();
|
||||
auto const postLimit = limitAmount(env, bob, gw, USD);
|
||||
BEAST_EXPECT(postLimit == preLimit);
|
||||
env(pay(alice, carol, USD(1)), ter(tecPATH_DRY));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testURIUTF8(FeatureBitset features)
|
||||
{
|
||||
// https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
|
||||
testcase("uri_utf8");
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
|
||||
Env env{*this, features};
|
||||
env.fund(XRP(10000), alice, bob);
|
||||
env.close();
|
||||
|
||||
std::string uri = "";
|
||||
|
||||
// test utf-8 success
|
||||
{
|
||||
|
||||
// case: kosme
|
||||
uri = "κόσμε";
|
||||
env(mint(alice, uri));
|
||||
|
||||
// case: single ASCII character
|
||||
uri = "a";
|
||||
env(mint(alice, uri));
|
||||
|
||||
// case: single non-ASCII character
|
||||
uri = "é";
|
||||
env(mint(alice, uri));
|
||||
|
||||
// case: valid multi-byte UTF-8 sequence
|
||||
uri = "€";
|
||||
env(mint(alice, uri));
|
||||
|
||||
// case: ipfs cid
|
||||
uri = "QmaCtDKZFVvvfufvbdy4estZbhQH7DXh16CTpv1howmBGy";
|
||||
env(mint(alice, uri));
|
||||
|
||||
// case: empty ipfs cid url
|
||||
uri = "ipfs://";
|
||||
env(mint(alice, uri));
|
||||
|
||||
// case: ipfs cid url
|
||||
uri = "ipfs://QmaCtDKZFVvvfufvbdy4estZbhQH7DXh16CTpv1howmBGy";
|
||||
env(mint(alice, uri));
|
||||
|
||||
// case: ipfs metadata url
|
||||
uri = "https://example.com/ipfs/";
|
||||
env(mint(alice, uri));
|
||||
|
||||
// // BOUNDRY - START
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// // case: 1 byte (U-00000000)
|
||||
// uri = "<22>";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 2 bytes (U-00000080)
|
||||
// uri = "";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 3 bytes (U-00000800)
|
||||
// uri = "ࠀ";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 4 bytes (U-00010000)
|
||||
// uri = "𐀀";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 5 bytes (U-00200000)
|
||||
// uri = "<22><><EFBFBD><EFBFBD><EFBFBD>";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 6 bytes (U-04000000)
|
||||
// uri = "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
|
||||
// env(mint(alice, uri));
|
||||
|
||||
// // BOUNDRY - END
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// // case: 1 byte (U-0000007F)
|
||||
// uri = "";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 2 bytes (U-000007FF)
|
||||
// uri = "߿";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 3 bytes (U-0000FFFF)
|
||||
// uri = "";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 4 bytes (U-001FFFFF)
|
||||
// uri = "<22><><EFBFBD><EFBFBD>";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 5 bytes (U-03FFFFFF)
|
||||
// uri = "<22><><EFBFBD><EFBFBD><EFBFBD>";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 6 bytes (U-7FFFFFFF)
|
||||
// uri = "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
|
||||
// env(mint(alice, uri));
|
||||
|
||||
// // BOUNDRY - OTHER
|
||||
// ----------------------------------------------------------------
|
||||
// // case: 1 bytes (U-0000D7FF)
|
||||
// uri = "";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 2 bytes (U-0000E000)
|
||||
// uri = "߿";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 3 bytes (U-0000FFFD)
|
||||
// uri = "";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 4 bytes (U-0010FFFF)
|
||||
// uri = "<22><><EFBFBD><EFBFBD>";
|
||||
// env(mint(alice, uri));
|
||||
// // case: 4 bytes (U-00110000)
|
||||
// uri = "<22><><EFBFBD><EFBFBD>";
|
||||
// env(mint(alice, uri));
|
||||
}
|
||||
// test utf8 malformed
|
||||
{
|
||||
// MALFORMED - END
|
||||
// ----------------------------------------------------------------
|
||||
// First continuation byte 0x80:
|
||||
// uri = "<22>";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// Last continuation byte 0xbf
|
||||
// uri = "<22>";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// 2 continuation bytes
|
||||
// uri = "<22><>";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// 3 continuation bytes
|
||||
// uri = "<22><><EFBFBD>";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// 4 continuation bytes
|
||||
// uri = "<22><><EFBFBD><EFBFBD>";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// 5 continuation bytes
|
||||
// uri = "<22><><EFBFBD><EFBFBD><EFBFBD>";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// 6 continuation bytes
|
||||
// uri = "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// 7 continuation bytes
|
||||
// uri = "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// Sequence of all 64 possible continuation bytes (0x80-0xbf)
|
||||
// uri = "\x80\xB7";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// All 32 first bytes of 2-byte sequences (0xc0-0xdf), each followed
|
||||
// by a space character
|
||||
// uri = "\xC0\xDF";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// All 16 first bytes of 3-byte sequences (0xe0-0xef), each followed
|
||||
// by a space character
|
||||
// uri = "\xE0\xEF";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// All 8 first bytes of 4-byte sequences (0xf0-0xf7), each followed
|
||||
// by a space character
|
||||
// uri = "\xF0\xF7";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// All 4 first bytes of 5-byte sequences (0xf8-0xfb), each followed
|
||||
// by a space character
|
||||
// uri = "\xF8\xFB";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// All 2 first bytes of 6-byte sequences (0xfc-0xfd), each followed
|
||||
// by a space character
|
||||
// uri = "\xFC\xFD";
|
||||
// env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// Sequences with last continuation byte missing
|
||||
|
||||
// Concatenation of incomplete sequences
|
||||
|
||||
// Impossible bytes
|
||||
uri = "\xFE";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
uri = "\xFF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
uri = "\xFE\xFE\xFF\xFF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// Examples of an overlong ASCII character
|
||||
// case: (U+002F)
|
||||
uri = "\xC0\xAF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+002F)
|
||||
uri = "\xE0\x80\xAF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+002F)
|
||||
uri = "\xF0\x80\x80\xAF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+002F)
|
||||
uri = "\xF0\x80\x80\x80\xAF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+002F)
|
||||
uri = "\xF0\x80\x80\x80\x80\xAF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// Maximum overlong sequences
|
||||
// case: (U+0000007F)
|
||||
uri = "\xC1\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+000007FF)
|
||||
uri = "\xE0\x9F\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+0000FFFF)
|
||||
uri = "\xF0\x8F\xBF\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+001FFFFF)
|
||||
uri = "\xF8\x87\xBF\xBF\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+03FFFFFF)
|
||||
uri = "\xFC\x83\xBF\xBF\xBF\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// Overlong representation of the NUL character
|
||||
// case: (U+0000)
|
||||
uri = "\xC0\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+0000)
|
||||
uri = "\xC0\x80\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+0000)
|
||||
uri = "\xC0\x80\x80\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+0000)
|
||||
uri = "\xC0\x80\x80\x80\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+0000)
|
||||
uri = "\xC0\x80\x80\x80\x80\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// Single UTF-16 surrogates
|
||||
// case: (U+D800)
|
||||
uri = "\xED\xA0\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DB7F)
|
||||
uri = "\xED\xAD\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DB80)
|
||||
uri = "\xED\xAE\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DBFF)
|
||||
uri = "\xED\xAF\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DC00)
|
||||
uri = "\xED\xB0\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DF80)
|
||||
uri = "\xED\xBE\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DFFF)
|
||||
uri = "\xED\xBF\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// Paired UTF-16 surrogates
|
||||
// case: (U+D800 U+DC00)
|
||||
uri = "\xED\xA0\x80\xED\xB0\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+D800 U+DFFF)
|
||||
uri = "\xED\xA0\x80\xED\xBF\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DB7F U+DC00)
|
||||
uri = "\xED\xAD\xBF\xED\xB0\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DB7F U+DFFF)
|
||||
uri = "\xED\xAD\xBF\xED\xBF\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DB80 U+DC00)
|
||||
uri = "\xED\xAE\x80\xED\xB0\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DB80 U+DFFF)
|
||||
uri = "\xED\xAE\x80\xED\xBF\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DBFF U+DC00)
|
||||
uri = "\xED\xAF\xBF\xED\xB0\x80";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+DBFF U+DFFF)
|
||||
uri = "\xED\xAF\xBF\xED\xBF\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
|
||||
// problematic noncharacters in 16-bit applications
|
||||
// case: (U+FFFE)
|
||||
uri = "\xEF\xBF\xBE";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
// case: (U+FFFF)
|
||||
uri = "\xEF\xBF\xBF";
|
||||
env(mint(alice, uri), ter(temMALFORMED));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
testWithFeats(FeatureBitset features)
|
||||
{
|
||||
@@ -1883,11 +2291,13 @@ struct URIToken_test : public beast::unit_test::suite
|
||||
testAccountDelete(features);
|
||||
testTickets(features);
|
||||
testRippleState(features);
|
||||
// testGateway(features);
|
||||
testGateway(features);
|
||||
testRequireAuth(features);
|
||||
testFreeze(features);
|
||||
testTransferRate(features);
|
||||
testDisallowXRP(features);
|
||||
testLimitAmount(features);
|
||||
testURIUTF8(features);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user