mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-28 06:25:49 +00:00
Add book_offers RPC tests (RIPD-1283):
Migrate orderbook-test.js to cpp tests. Provide coverage for error conditions in book_offers RPC method.
This commit is contained in:
committed by
Vinnie Falco
parent
bb0b97f46b
commit
05e7373086
@@ -277,9 +277,9 @@ public:
|
||||
// Book functions.
|
||||
//
|
||||
|
||||
void getBookPage (bool bUnlimited, std::shared_ptr<ReadView const>& lpLedger,
|
||||
void getBookPage (std::shared_ptr<ReadView const>& lpLedger,
|
||||
Book const&, AccountID const& uTakerID, const bool bProof,
|
||||
const unsigned int iLimit,
|
||||
unsigned int iLimit,
|
||||
Json::Value const& jvMarker, Json::Value& jvResult)
|
||||
override;
|
||||
|
||||
@@ -2832,14 +2832,12 @@ InfoSub::pointer NetworkOPsImp::addRpcSub (
|
||||
// NIKB FIXME this should be looked at. There's no reason why this shouldn't
|
||||
// work, but it demonstrated poor performance.
|
||||
//
|
||||
// FIXME : support iLimit.
|
||||
void NetworkOPsImp::getBookPage (
|
||||
bool bUnlimited,
|
||||
std::shared_ptr<ReadView const>& lpLedger,
|
||||
Book const& book,
|
||||
AccountID const& uTakerID,
|
||||
bool const bProof,
|
||||
const unsigned int iLimit,
|
||||
unsigned int iLimit,
|
||||
Json::Value const& jvMarker,
|
||||
Json::Value& jvResult)
|
||||
{ // CAUTION: This is the old get book page logic
|
||||
@@ -2876,11 +2874,7 @@ void NetworkOPsImp::getBookPage (
|
||||
auto const rate = transferRate(view, book.out.account);
|
||||
auto viewJ = app_.journal ("View");
|
||||
|
||||
unsigned int left (iLimit == 0 ? 300 : iLimit);
|
||||
if (! bUnlimited && left > 300)
|
||||
left = 300;
|
||||
|
||||
while (!bDone && left-- > 0)
|
||||
while (! bDone && iLimit-- > 0)
|
||||
{
|
||||
if (bDirectAdvance)
|
||||
{
|
||||
@@ -3048,14 +3042,12 @@ void NetworkOPsImp::getBookPage (
|
||||
// This is the new code that uses the book iterators
|
||||
// It has temporarily been disabled
|
||||
|
||||
// FIXME : support iLimit.
|
||||
void NetworkOPsImp::getBookPage (
|
||||
bool bUnlimited,
|
||||
std::shared_ptr<ReadView const> lpLedger,
|
||||
Book const& book,
|
||||
AccountID const& uTakerID,
|
||||
bool const bProof,
|
||||
const unsigned int iLimit,
|
||||
unsigned int iLimit,
|
||||
Json::Value const& jvMarker,
|
||||
Json::Value& jvResult)
|
||||
{
|
||||
@@ -3071,11 +3063,7 @@ void NetworkOPsImp::getBookPage (
|
||||
const bool bGlobalFreeze = lesActive.isGlobalFrozen (book.out.account) ||
|
||||
lesActive.isGlobalFrozen (book.in.account);
|
||||
|
||||
unsigned int left (iLimit == 0 ? 300 : iLimit);
|
||||
if (! bUnlimited && left > 300)
|
||||
left = 300;
|
||||
|
||||
while (left-- > 0 && obIterator.nextOffer ())
|
||||
while (iLimit-- > 0 && obIterator.nextOffer ())
|
||||
{
|
||||
|
||||
SLE::pointer sleOffer = obIterator.getCurrentOffer();
|
||||
|
||||
@@ -139,12 +139,11 @@ public:
|
||||
//
|
||||
|
||||
virtual void getBookPage (
|
||||
bool bUnlimited,
|
||||
std::shared_ptr<ReadView const>& lpLedger,
|
||||
Book const& book,
|
||||
AccountID const& uTakerID,
|
||||
bool const bProof,
|
||||
const unsigned int iLimit,
|
||||
unsigned int iLimit,
|
||||
Json::Value const& jvMarker,
|
||||
Json::Value& jvResult) = 0;
|
||||
|
||||
|
||||
@@ -182,7 +182,6 @@ Json::Value doBookOffers (RPC::Context& context)
|
||||
: Json::Value (Json::nullValue));
|
||||
|
||||
context.netOps.getBookPage (
|
||||
isUnlimited (context.role),
|
||||
lpLedger,
|
||||
{{pay_currency, pay_issuer}, {get_currency, get_issuer}},
|
||||
takerID ? *takerID : zero, bProof, limit, jvMarker, jvResult);
|
||||
|
||||
@@ -287,10 +287,12 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
|
||||
auto add = [&](Json::StaticString field)
|
||||
{
|
||||
context.netOps.getBookPage (isUnlimited (context.role),
|
||||
lpLedger, field == jss::asks ? reversed (book) : book,
|
||||
takerID ? *takerID : noAccount(), false, 0, jvMarker,
|
||||
jvOffers);
|
||||
context.netOps.getBookPage (
|
||||
lpLedger,
|
||||
field == jss::asks ? reversed (book) : book,
|
||||
takerID ? *takerID : noAccount(),
|
||||
false, RPC::Tuning::bookOffers.rdefault,
|
||||
jvMarker, jvOffers);
|
||||
|
||||
if (jvResult.isMember (field))
|
||||
{
|
||||
|
||||
@@ -45,7 +45,7 @@ static LimitRange const accountObjects = {10, 200, 400};
|
||||
static LimitRange const accountOffers = {10, 200, 400};
|
||||
|
||||
/** Limits for the book_offers command. */
|
||||
static LimitRange const bookOffers = {0, 0, 400};
|
||||
static LimitRange const bookOffers = {0, 300, 400};
|
||||
|
||||
/** Limits for the no_ripple_check command. */
|
||||
static LimitRange const noRippleCheck = {10, 300, 400};
|
||||
|
||||
@@ -17,19 +17,41 @@
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/test/WSClient.h>
|
||||
#include <ripple/test/jtx.h>
|
||||
#include <ripple/beast/unit_test.h>
|
||||
#include <ripple/rpc/impl/Tuning.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
class Book_test : public beast::unit_test::suite
|
||||
{
|
||||
std::string getBookDir(jtx::Env & env, Issue const& in, Issue const& out)
|
||||
{
|
||||
std::string dir;
|
||||
auto uBookBase = getBookBase({in, out});
|
||||
auto uBookEnd = getQualityNext(uBookBase);
|
||||
auto view = env.closed();
|
||||
auto key = view->succ(uBookBase, uBookEnd);
|
||||
if (key)
|
||||
{
|
||||
auto sleOfferDir = view->read(keylet::page(key.value()));
|
||||
uint256 offerIndex;
|
||||
unsigned int bookEntry;
|
||||
cdirFirst(*view, sleOfferDir->key(), sleOfferDir, bookEntry, offerIndex, env.journal);
|
||||
auto sleOffer = view->read(keylet::offer(offerIndex));
|
||||
dir = to_string(sleOffer->getFieldH256(sfBookDirectory));
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
testOneSideEmptyBook()
|
||||
{
|
||||
testcase("One Side Empty Book");
|
||||
using namespace std::chrono_literals;
|
||||
using namespace jtx;
|
||||
Env env(*this);
|
||||
@@ -50,7 +72,8 @@ public:
|
||||
}
|
||||
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if(! BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
return;
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::offers) &&
|
||||
jv[jss::result][jss::offers].size() == 0);
|
||||
BEAST_EXPECT(! jv[jss::result].isMember(jss::asks));
|
||||
@@ -90,6 +113,7 @@ public:
|
||||
void
|
||||
testOneSideOffersInBook()
|
||||
{
|
||||
testcase("One Side Offers In Book");
|
||||
using namespace std::chrono_literals;
|
||||
using namespace jtx;
|
||||
Env env(*this);
|
||||
@@ -119,7 +143,8 @@ public:
|
||||
}
|
||||
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if(! BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
return;
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::offers) &&
|
||||
jv[jss::result][jss::offers].size() == 1);
|
||||
BEAST_EXPECT(jv[jss::result][jss::offers][0u][jss::TakerGets] ==
|
||||
@@ -163,6 +188,7 @@ public:
|
||||
void
|
||||
testBothSidesEmptyBook()
|
||||
{
|
||||
testcase("Both Sides Empty Book");
|
||||
using namespace std::chrono_literals;
|
||||
using namespace jtx;
|
||||
Env env(*this);
|
||||
@@ -184,7 +210,8 @@ public:
|
||||
}
|
||||
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if(! BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
return;
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::asks) &&
|
||||
jv[jss::result][jss::asks].size() == 0);
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::bids) &&
|
||||
@@ -234,6 +261,7 @@ public:
|
||||
void
|
||||
testBothSidesOffersInBook()
|
||||
{
|
||||
testcase("Both Sides Offers In Book");
|
||||
using namespace std::chrono_literals;
|
||||
using namespace jtx;
|
||||
Env env(*this);
|
||||
@@ -264,7 +292,8 @@ public:
|
||||
}
|
||||
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if(! BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
return;
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::asks) &&
|
||||
jv[jss::result][jss::asks].size() == 1);
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::bids) &&
|
||||
@@ -322,6 +351,7 @@ public:
|
||||
void
|
||||
testMultipleBooksOneSideEmptyBook()
|
||||
{
|
||||
testcase("Multiple Books, One Side Empty");
|
||||
using namespace std::chrono_literals;
|
||||
using namespace jtx;
|
||||
Env env(*this);
|
||||
@@ -352,7 +382,8 @@ public:
|
||||
}
|
||||
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if(! BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
return;
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::offers) &&
|
||||
jv[jss::result][jss::offers].size() == 0);
|
||||
BEAST_EXPECT(! jv[jss::result].isMember(jss::asks));
|
||||
@@ -417,6 +448,7 @@ public:
|
||||
void
|
||||
testMultipleBooksOneSideOffersInBook()
|
||||
{
|
||||
testcase("Multiple Books, One Side Offers In Book");
|
||||
using namespace std::chrono_literals;
|
||||
using namespace jtx;
|
||||
Env env(*this);
|
||||
@@ -464,7 +496,8 @@ public:
|
||||
}
|
||||
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if(! BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
return;
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::offers) &&
|
||||
jv[jss::result][jss::offers].size() == 2);
|
||||
BEAST_EXPECT(jv[jss::result][jss::offers][0u][jss::TakerGets] ==
|
||||
@@ -537,6 +570,7 @@ public:
|
||||
void
|
||||
testMultipleBooksBothSidesEmptyBook()
|
||||
{
|
||||
testcase("Multiple Books, Both Sides Empty Book");
|
||||
using namespace std::chrono_literals;
|
||||
using namespace jtx;
|
||||
Env env(*this);
|
||||
@@ -569,7 +603,8 @@ public:
|
||||
}
|
||||
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if(! BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
return;
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::asks) &&
|
||||
jv[jss::result][jss::asks].size() == 0);
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::bids) &&
|
||||
@@ -653,6 +688,7 @@ public:
|
||||
void
|
||||
testMultipleBooksBothSidesOffersInBook()
|
||||
{
|
||||
testcase("Multiple Books, Both Sides Offers In Book");
|
||||
using namespace std::chrono_literals;
|
||||
using namespace jtx;
|
||||
Env env(*this);
|
||||
@@ -703,7 +739,8 @@ public:
|
||||
}
|
||||
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if(! BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
return;
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::asks) &&
|
||||
jv[jss::result][jss::asks].size() == 2);
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::bids) &&
|
||||
@@ -800,20 +837,525 @@ public:
|
||||
books)[jss::status] == "success");
|
||||
}
|
||||
|
||||
void
|
||||
testTrackOffers()
|
||||
{
|
||||
testcase("TrackOffers");
|
||||
using namespace jtx;
|
||||
Env env(*this);
|
||||
Account gw {"gw"};
|
||||
Account alice {"alice"};
|
||||
Account bob {"bob"};
|
||||
auto wsc = makeWSClient(env.app().config());
|
||||
env.fund(XRP(20000), alice, bob, gw);
|
||||
env.close();
|
||||
auto USD = gw["USD"];
|
||||
|
||||
Json::Value books;
|
||||
{
|
||||
books[jss::books] = Json::arrayValue;
|
||||
{
|
||||
auto &j = books[jss::books].append(Json::objectValue);
|
||||
j[jss::snapshot] = true;
|
||||
j[jss::taker_gets][jss::currency] = "XRP";
|
||||
j[jss::taker_pays][jss::currency] = "USD";
|
||||
j[jss::taker_pays][jss::issuer] = gw.human();
|
||||
}
|
||||
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
if(! BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
return;
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::offers) &&
|
||||
jv[jss::result][jss::offers].size() == 0);
|
||||
BEAST_EXPECT(! jv[jss::result].isMember(jss::asks));
|
||||
BEAST_EXPECT(! jv[jss::result].isMember(jss::bids));
|
||||
}
|
||||
|
||||
env(rate(gw, 1.1));
|
||||
env.close();
|
||||
env.trust(USD(1000), alice);
|
||||
env.trust(USD(1000), bob);
|
||||
env(pay(gw, alice, USD(100)));
|
||||
env(pay(gw, bob, USD(50)));
|
||||
env(offer(alice, XRP(4000), USD(10)));
|
||||
env.close();
|
||||
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::taker] = env.master.human();
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
jvParams[jss::taker_gets][jss::issuer] = gw.human();
|
||||
auto jrr = wsc->invoke("book_offers", jvParams)[jss::result];
|
||||
|
||||
BEAST_EXPECT(jrr[jss::offers].isArray());
|
||||
BEAST_EXPECT(jrr[jss::offers].size() == 1);
|
||||
auto const jrOffer = jrr[jss::offers][0u];
|
||||
BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
|
||||
BEAST_EXPECT(jrOffer[sfBookDirectory.fieldName] ==
|
||||
getBookDir(env, XRP, USD.issue()));
|
||||
BEAST_EXPECT(jrOffer[sfBookNode.fieldName] == "0000000000000000");
|
||||
BEAST_EXPECT(jrOffer[jss::Flags] == 0);
|
||||
BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == "Offer");
|
||||
BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] == "0000000000000000");
|
||||
BEAST_EXPECT(jrOffer[sfSequence.fieldName] == 3);
|
||||
BEAST_EXPECT(jrOffer[jss::TakerGets] == USD(10).value().getJson(0));
|
||||
BEAST_EXPECT(jrOffer[jss::TakerPays] == XRP(4000).value().getJson(0));
|
||||
BEAST_EXPECT(jrOffer[jss::owner_funds] == "100");
|
||||
BEAST_EXPECT(jrOffer[jss::quality] == "400000000");
|
||||
|
||||
BEAST_EXPECT(wsc->findMsg(5s,
|
||||
[&](auto const& jv)
|
||||
{
|
||||
auto const& t = jv[jss::transaction];
|
||||
return t[jss::TransactionType] == "OfferCreate" &&
|
||||
t[jss::TakerGets] == USD(10).value().getJson(0) &&
|
||||
t[jss::owner_funds] == "100" &&
|
||||
t[jss::TakerPays] == XRP(4000).value().getJson(0);
|
||||
}));
|
||||
|
||||
env(offer(bob, XRP(2000), USD(5)));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT(wsc->findMsg(5s,
|
||||
[&](auto const& jv)
|
||||
{
|
||||
auto const& t = jv[jss::transaction];
|
||||
return t[jss::TransactionType] == "OfferCreate" &&
|
||||
t[jss::TakerGets] == USD(5).value().getJson(0) &&
|
||||
t[jss::owner_funds] == "50" &&
|
||||
t[jss::TakerPays] == XRP(2000).value().getJson(0);
|
||||
}));
|
||||
|
||||
jrr = wsc->invoke("book_offers", jvParams)[jss::result];
|
||||
|
||||
BEAST_EXPECT(jrr[jss::offers].isArray());
|
||||
BEAST_EXPECT(jrr[jss::offers].size() == 2);
|
||||
auto const jrNextOffer = jrr[jss::offers][1u];
|
||||
BEAST_EXPECT(jrNextOffer[sfAccount.fieldName] == bob.human());
|
||||
BEAST_EXPECT(jrNextOffer[sfBookDirectory.fieldName] ==
|
||||
getBookDir(env, XRP, USD.issue()));
|
||||
BEAST_EXPECT(jrNextOffer[sfBookNode.fieldName] == "0000000000000000");
|
||||
BEAST_EXPECT(jrNextOffer[jss::Flags] == 0);
|
||||
BEAST_EXPECT(jrNextOffer[sfLedgerEntryType.fieldName] == "Offer");
|
||||
BEAST_EXPECT(jrNextOffer[sfOwnerNode.fieldName] == "0000000000000000");
|
||||
BEAST_EXPECT(jrNextOffer[sfSequence.fieldName] == 3);
|
||||
BEAST_EXPECT(jrNextOffer[jss::TakerGets] == USD(5).value().getJson(0));
|
||||
BEAST_EXPECT(jrNextOffer[jss::TakerPays] ==
|
||||
XRP(2000).value().getJson(0));
|
||||
BEAST_EXPECT(jrNextOffer[jss::owner_funds] == "50");
|
||||
BEAST_EXPECT(jrNextOffer[jss::quality] == "400000000");
|
||||
|
||||
BEAST_EXPECT(wsc->invoke("unsubscribe",
|
||||
books)[jss::status] == "success");
|
||||
}
|
||||
|
||||
void
|
||||
testBookOfferErrors()
|
||||
{
|
||||
testcase("BookOffersRPC Errors");
|
||||
using namespace jtx;
|
||||
Env env(*this);
|
||||
Account gw {"gw"};
|
||||
Account alice {"alice"};
|
||||
env.fund(XRP(10000), alice, gw);
|
||||
env.close();
|
||||
auto USD = gw["USD"];
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = 10u;
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
|
||||
BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Missing field 'taker_pays'.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays] = Json::objectValue;
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Missing field 'taker_gets'.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays] = "not an object";
|
||||
jvParams[jss::taker_gets] = Json::objectValue;
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_pays', not object.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays] = Json::objectValue;
|
||||
jvParams[jss::taker_gets] = "not an object";
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_gets', not object.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays] = Json::objectValue;
|
||||
jvParams[jss::taker_gets] = Json::objectValue;
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Missing field 'taker_pays.currency'.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = 1;
|
||||
jvParams[jss::taker_gets] = Json::objectValue;
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_pays.currency', not string.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_gets] = Json::objectValue;
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Missing field 'taker_gets.currency'.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_gets][jss::currency] = 1;
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_gets.currency', not string.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "NOT_VALID";
|
||||
jvParams[jss::taker_gets][jss::currency] = "XRP";
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "srcCurMalformed");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_pays.currency', bad currency.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_gets][jss::currency] = "NOT_VALID";
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "dstAmtMalformed");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_gets.currency', bad currency.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
jvParams[jss::taker_gets][jss::issuer] = 1;
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_gets.issuer', not string.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_pays][jss::issuer] = 1;
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_pays.issuer', not string.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_pays][jss::issuer] = gw.human() + "DEAD";
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_pays.issuer', bad issuer.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_pays][jss::issuer] = toBase58(noAccount());
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_pays.issuer', bad issuer account one.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
jvParams[jss::taker_gets][jss::issuer] = gw.human() + "DEAD";
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_gets.issuer', bad issuer.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
jvParams[jss::taker_gets][jss::issuer] = toBase58(noAccount());
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_gets.issuer', bad issuer account one.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_pays][jss::issuer] = alice.human();
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
jvParams[jss::taker_gets][jss::issuer] = gw.human();
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Unneeded field 'taker_pays.issuer' "
|
||||
"for XRP currency specification.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "USD";
|
||||
jvParams[jss::taker_pays][jss::issuer] = toBase58(xrpAccount());
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
jvParams[jss::taker_gets][jss::issuer] = gw.human();
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_pays.issuer', expected non-XRP issuer.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker] = 1;
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
jvParams[jss::taker_gets][jss::issuer] = gw.human();
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker', not string.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker] = env.master.human() + "DEAD";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
jvParams[jss::taker_gets][jss::issuer] = gw.human();
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker'.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker] = env.master.human();
|
||||
jvParams[jss::taker_pays][jss::currency] = "USD";
|
||||
jvParams[jss::taker_pays][jss::issuer] = gw.human();
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
jvParams[jss::taker_gets][jss::issuer] = gw.human();
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "badMarket");
|
||||
BEAST_EXPECT(jrr[jss::error_message] == "No such market.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker] = env.master.human();
|
||||
jvParams[jss::limit] = "0"; // NOT an integer
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
jvParams[jss::taker_gets][jss::issuer] = gw.human();
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'limit', not unsigned integer.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "USD";
|
||||
jvParams[jss::taker_pays][jss::issuer] = gw.human();
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Invalid field 'taker_gets.issuer', "
|
||||
"expected non-XRP issuer.");
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "USD";
|
||||
jvParams[jss::taker_pays][jss::issuer] = gw.human();
|
||||
jvParams[jss::taker_gets][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_gets][jss::issuer] = gw.human();
|
||||
auto const jrr = env.rpc(
|
||||
"json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed");
|
||||
BEAST_EXPECT(jrr[jss::error_message] ==
|
||||
"Unneeded field 'taker_gets.issuer' "
|
||||
"for XRP currency specification.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
testBookOfferLimits(bool asAdmin)
|
||||
{
|
||||
testcase("BookOffer Limits");
|
||||
using namespace jtx;
|
||||
Env env(*this, [asAdmin]() {
|
||||
auto p = std::make_unique<Config>();
|
||||
setupConfigForUnitTests(*p);
|
||||
if(! asAdmin)
|
||||
{
|
||||
(*p)["port_rpc"].set("admin","");
|
||||
(*p)["port_ws"].set("admin","");
|
||||
}
|
||||
return p;
|
||||
}());
|
||||
Account gw {"gw"};
|
||||
env.fund(XRP(200000), gw);
|
||||
env.close();
|
||||
auto USD = gw["USD"];
|
||||
|
||||
for(auto i = 0; i <= RPC::Tuning::bookOffers.rmax; i++)
|
||||
env(offer(gw, XRP(50 + 1*i), USD(1.0 + 0.1*i)));
|
||||
env.close();
|
||||
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::limit] = 1;
|
||||
jvParams[jss::ledger_index] = "validated";
|
||||
jvParams[jss::taker_pays][jss::currency] = "XRP";
|
||||
jvParams[jss::taker_gets][jss::currency] = "USD";
|
||||
jvParams[jss::taker_gets][jss::issuer] = gw.human();
|
||||
auto jrr =
|
||||
env.rpc("json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::offers].isArray());
|
||||
BEAST_EXPECT(jrr[jss::offers].size() == (asAdmin ? 1u : 0u));
|
||||
// NOTE - a marker field is not returned for this method
|
||||
|
||||
jvParams[jss::limit] = 0u;
|
||||
jrr =
|
||||
env.rpc("json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::offers].isArray());
|
||||
BEAST_EXPECT(jrr[jss::offers].size() == 0u);
|
||||
|
||||
jvParams[jss::limit] = RPC::Tuning::bookOffers.rmax + 1;
|
||||
jrr =
|
||||
env.rpc("json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::offers].isArray());
|
||||
BEAST_EXPECT(jrr[jss::offers].size() ==
|
||||
(asAdmin ? RPC::Tuning::bookOffers.rmax + 1 : 0u));
|
||||
|
||||
jvParams[jss::limit] = Json::nullValue;
|
||||
jrr =
|
||||
env.rpc("json", "book_offers", to_string(jvParams)) [jss::result];
|
||||
BEAST_EXPECT(jrr[jss::offers].isArray());
|
||||
BEAST_EXPECT(jrr[jss::offers].size() ==
|
||||
(asAdmin ? RPC::Tuning::bookOffers.rdefault : 0u));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testOneSideEmptyBook();
|
||||
testOneSideOffersInBook();
|
||||
|
||||
testBothSidesEmptyBook();
|
||||
testBothSidesOffersInBook();
|
||||
|
||||
testMultipleBooksOneSideEmptyBook();
|
||||
testMultipleBooksOneSideOffersInBook();
|
||||
|
||||
testMultipleBooksBothSidesEmptyBook();
|
||||
testMultipleBooksBothSidesOffersInBook();
|
||||
testTrackOffers();
|
||||
testBookOfferErrors();
|
||||
testBookOfferLimits(true);
|
||||
testBookOfferLimits(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -821,3 +1363,4 @@ BEAST_DEFINE_TESTSUITE(Book,app,ripple);
|
||||
|
||||
} // test
|
||||
} // ripple
|
||||
|
||||
|
||||
Reference in New Issue
Block a user