20 #include <ripple/app/misc/NetworkOPs.h>
21 #include <ripple/app/misc/TxQ.h>
22 #include <ripple/beast/hash/uhash.h>
23 #include <ripple/beast/unit_test.h>
24 #include <ripple/json/to_string.h>
25 #include <ripple/protocol/Feature.h>
26 #include <ripple/protocol/TxFlags.h>
27 #include <ripple/protocol/jss.h>
30 #include <boost/lexical_cast.hpp>
38 class Env_test :
public beast::unit_test::suite
45 return boost::lexical_cast<std::string>(t);
65 auto const USD = gw[
"USD"];
98 fail(
"missing exception");
108 fail(
"missing exception");
129 BEAST_EXPECT(
XRP(1) ==
drops(1000000));
134 auto const USD = gw[
"USD"];
135 BEAST_EXPECT(
to_string(USD(0)) ==
"0/USD(gw)");
136 BEAST_EXPECT(
to_string(USD(10)) ==
"10/USD(gw)");
137 BEAST_EXPECT(
to_string(USD(-10)) ==
"-10/USD(gw)");
138 BEAST_EXPECT(USD(0) ==
STAmount(USD, 0));
139 BEAST_EXPECT(USD(1) ==
STAmount(USD, 1));
140 BEAST_EXPECT(USD(-1) ==
STAmount(USD, -1));
143 BEAST_EXPECT(!
get(USD(10)).is_any);
144 BEAST_EXPECT(
get(
any(USD(10))).is_any);
152 auto const n =
XRP(10000);
154 auto const USD = gw[
"USD"];
155 auto const alice =
Account(
"alice");
160 env(pay(
"alice",
"bob",
XRP(1000)),
172 env.
fund(n,
"alice");
173 env.
fund(n,
"bob",
"carol");
190 env.
fund(n,
"alice",
"bob", gw);
191 env(trust(
"alice", USD(100)),
require(
lines(
"alice", 1)));
197 BEAST_EXPECT(env.
balance(alice) == 0);
198 BEAST_EXPECT(env.
balance(alice, USD) != 0);
199 BEAST_EXPECT(env.
balance(alice, USD) == USD(0));
200 env.
fund(n, alice, gw);
201 BEAST_EXPECT(env.
balance(alice) == n);
202 BEAST_EXPECT(env.
balance(gw) == n);
203 env.
trust(USD(1000), alice);
204 env(pay(gw, alice, USD(10)));
214 BEAST_EXPECT(env.
seq(
"alice") == 3);
215 BEAST_EXPECT(env.
seq(gw) == 3);
221 env.
fund(n,
"alice");
228 env(
noop(
"alice"),
fee(autofill));
229 env(
noop(
"alice"),
fee(autofill),
seq(autofill));
230 env(
noop(
"alice"),
fee(autofill),
seq(autofill),
sig(autofill));
241 auto const USD = gw[
"USD"];
244 env.
fund(
XRP(10000),
"alice", gw);
246 env.
trust(USD(100),
"alice");
249 env(pay(gw,
"alice", USD(10)),
require(
balance(
"alice", USD(10))));
268 env.fund(
XRP(10000), alice, bob);
304 auto const gw =
Account(
"gateway");
305 auto const USD = gw[
"USD"];
307 env.
fund(
XRP(10000),
"alice",
"bob",
"carol", gw);
322 env.
trust(USD(100),
"alice",
"bob",
"carol");
326 env(pay(gw,
"carol", USD(50)));
332 env(pay(
"alice",
"bob",
any(USD(10))),
341 env(
regkey(
"alice",
"eric"));
343 env(
noop(
"alice"),
sig(
"alice"));
344 env(
noop(
"alice"),
sig(
"eric"));
356 env(
noop(
"alice"),
sig(
"eric"));
364 env(
regkey(
"alice", disabled));
377 auto const gw =
Account(
"gateway");
378 auto const USD = gw[
"USD"];
380 auto const alice =
Account{
"alice"};
384 auto const queueTxCount =
386 auto const openTxCount = env.
current()->txCount();
387 BEAST_EXPECT(localTxCnt == 2 && queueTxCount == 0 && openTxCount == 2);
389 auto applyTxn = [&env](
auto&&... txnArgs) {
390 auto jt = env.
jt(txnArgs...);
397 args[jss::fail_hard] =
true;
399 return env.
rpc(
"json",
"submit", args.toStyledString());
402 auto jr = applyTxn(
noop(alice),
fee(1));
404 BEAST_EXPECT(jr[jss::result][jss::engine_result] ==
"telINSUF_FEE_P");
409 BEAST_EXPECT(env.
current()->txCount() == openTxCount);
411 jr = applyTxn(
noop(alice),
sig(
"bob"));
413 BEAST_EXPECT(jr[jss::result][jss::engine_result] ==
"tefBAD_AUTH");
418 BEAST_EXPECT(env.
current()->txCount() == openTxCount);
420 jr = applyTxn(
noop(alice),
seq(20));
422 BEAST_EXPECT(jr[jss::result][jss::engine_result] ==
"terPRE_SEQ");
427 BEAST_EXPECT(env.
current()->txCount() == openTxCount);
429 jr = applyTxn(offer(alice,
XRP(1000), USD(1000)));
432 jr[jss::result][jss::engine_result] ==
"tecUNFUNDED_OFFER");
437 BEAST_EXPECT(env.
current()->txCount() == openTxCount);
441 BEAST_EXPECT(jr[jss::result][jss::engine_result] ==
"temBAD_FEE");
446 BEAST_EXPECT(env.
current()->txCount() == openTxCount);
448 jr = applyTxn(
noop(alice));
450 BEAST_EXPECT(jr[jss::result][jss::engine_result] ==
"tesSUCCESS");
452 BEAST_EXPECT(env.
current()->txCount() == openTxCount + 1);
463 env(signers(
"alice", 1, {{
"alice", 1}, {
"bob", 2}}),
465 env(signers(
"alice", 1, {{
"bob", 1}, {
"carol", 2}}));
468 auto const baseFee = env.
current()->fees().base;
470 env(
noop(
"alice"),
msig(
"carol"),
fee(2 * baseFee));
471 env(
noop(
"alice"),
msig(
"bob",
"carol"),
fee(3 * baseFee));
473 msig(
"bob",
"carol",
"dilbert"),
477 env(signers(
"alice",
none));
485 ticket::create(
"alice", 1);
492 env(ticket::create(
"alice", 1),
511 BEAST_EXPECT(!jt1.
get<
int>());
513 BEAST_EXPECT(jt1.
get<
int>());
514 BEAST_EXPECT(*jt1.
get<
int>() == 7);
515 BEAST_EXPECT(!jt1.
get<
UDT>());
520 BEAST_EXPECT(jt1.
get<
int>());
521 BEAST_EXPECT(*jt1.
get<
int>() == 17);
522 BEAST_EXPECT(!jt1.
get<
UDT>());
526 *jt1.
get<
int>() = 42;
527 BEAST_EXPECT(jt1.
get<
int>());
528 BEAST_EXPECT(*jt1.
get<
int>() == 42);
529 BEAST_EXPECT(!jt1.
get<
UDT>());
532 auto const& jt2 = jt1;
533 BEAST_EXPECT(jt2.get<
int>());
534 BEAST_EXPECT(*jt2.get<
int>() == 42);
535 BEAST_EXPECT(!jt2.get<
UDT>());
543 env.
fund(
XRP(100000),
"alice");
544 auto jt1 = env.
jt(
noop(
"alice"));
554 BEAST_EXPECT(*jt3.get<
std::string>() ==
"Hello, world!");
555 BEAST_EXPECT(jt3.get<
bool>());
556 BEAST_EXPECT(!*jt3.get<
bool>());
568 BEAST_EXPECT(jt1.
get<
int>());
569 BEAST_EXPECT(*jt1.
get<
int>() == 7);
570 BEAST_EXPECT(!jt1.
get<
UDT>());
572 BEAST_EXPECT(jt2.
get<
int>());
573 BEAST_EXPECT(*jt2.
get<
int>() == 7);
574 BEAST_EXPECT(!jt2.
get<
UDT>());
577 BEAST_EXPECT(jt3.
get<
int>());
578 BEAST_EXPECT(*jt3.
get<
int>() == 7);
579 BEAST_EXPECT(!jt3.
get<
UDT>());
591 BEAST_EXPECT(jt1.
get<
int>());
592 BEAST_EXPECT(*jt1.
get<
int>() == 7);
593 BEAST_EXPECT(!jt1.
get<
UDT>());
594 JTx jt2(std::move(jt1));
595 BEAST_EXPECT(!jt1.
get<
int>());
596 BEAST_EXPECT(!jt1.
get<
UDT>());
597 BEAST_EXPECT(jt2.
get<
int>());
598 BEAST_EXPECT(*jt2.
get<
int>() == 7);
599 BEAST_EXPECT(!jt2.
get<
UDT>());
600 jt1 = std::move(jt2);
601 BEAST_EXPECT(!jt2.
get<
int>());
602 BEAST_EXPECT(!jt2.
get<
UDT>());
603 BEAST_EXPECT(jt1.
get<
int>());
604 BEAST_EXPECT(*jt1.
get<
int>() == 7);
605 BEAST_EXPECT(!jt1.
get<
UDT>());
620 env(
noop(
"alice"),
memo(
"data",
"format",
"type"));
622 memo(
"data1",
"format1",
"type1"),
623 memo(
"data2",
"format2",
"type2"));
632 memo(
"data",
"format",
"type")(env, jt);
634 auto const&
memo = jt.
jv[
"Memos"][0u][
"Memo"];
649 BEAST_EXPECT(
seq == env.
closed()->seq() + 1);
651 BEAST_EXPECT(env.
closed()->seq() ==
seq);
652 BEAST_EXPECT(env.
current()->seq() ==
seq + 1);
654 BEAST_EXPECT(env.
closed()->seq() ==
seq + 1);
655 BEAST_EXPECT(env.
current()->seq() ==
seq + 2);
665 env.
fund(
XRP(100000),
"alice",
"bob");
667 env(pay(
"alice",
"bob",
XRP(100)));
680 auto const USD = gw[
"USD"];
681 env.
fund(
XRP(10000),
"alice",
"bob");
683 pay(
"alice",
"bob", USD(10)),
700 auto const baseFee = env.
current()->fees().base;
707 JTx jt = env.
jt(jsonNoop);
718 auto const alice =
Account(
"alice");
726 if (BEAST_EXPECT(tx))
728 BEAST_EXPECT(tx->getAccountID(
sfAccount) == alice.id());
739 if (BEAST_EXPECT(tx))
741 BEAST_EXPECT(tx->getAccountID(
sfAccount) == alice.id());
749 params[jss::fee_mult_max] = 1;
750 params[jss::fee_div_max] = 2;
762 testcase(
"Env features");
771 auto const n = supported.size();
772 for (
size_t i = 0; i < n; ++i)
779 if (!neverSupportedFeat)
781 log <<
"No unsupported features found - skipping test."
787 auto hasFeature = [](
Env& env,
uint256 const& f) {
799 this->BEAST_EXPECT(hasFeature(env, f));
810 this->BEAST_EXPECT(has == hasFeature(env, f));
814 auto const missingSomeFeatures =
816 BEAST_EXPECT(missingSomeFeatures.count() == (supported.count() - 2));
819 Env env{*
this, missingSomeFeatures};
825 this->BEAST_EXPECT(hasnot != hasFeature(env, f));
842 BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
846 this->BEAST_EXPECT(has == hasFeature(env, f));
862 (supported.count() - 2 + 1));
863 BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
867 this->BEAST_EXPECT(hasnot != hasFeature(env, f));
881 BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
883 this->BEAST_EXPECT(hasFeature(env, f));
895 (*cfg).deprecatedClearSection(
"port_rpc");
910 auto const alice =
Account{
"alice"};
911 auto const n =
XRP(10000);
913 BEAST_EXPECT(env.
balance(alice) == n);
916 auto applyBlobTxn = [&env](
char const* syncMode,
auto&&... txnArgs) {
917 auto jt = env.
jt(txnArgs...);
924 args[jss::fail_hard] =
true;
925 args[jss::sync_mode] = syncMode;
927 return env.
rpc(
"json",
"submit", args.toStyledString());
930 auto jr = applyBlobTxn(
"sync",
noop(alice));
931 BEAST_EXPECT(jr[jss::result][jss::engine_result] ==
"tesSUCCESS");
933 jr = applyBlobTxn(
"async",
noop(alice));
934 BEAST_EXPECT(jr[jss::result][jss::engine_result] ==
"terSUBMITTED");
938 auto applier = [&env]() {
944 jr = applyBlobTxn(
"wait",
noop(alice));
945 BEAST_EXPECT(jr[jss::result][jss::engine_result] ==
"tesSUCCESS");
948 jr = applyBlobTxn(
"scott",
noop(alice));
949 BEAST_EXPECT(jr[jss::result][jss::error] ==
"invalidParams");
952 auto applyJsonTxn = [&env](
953 char const* syncMode,
957 args[jss::secret] = secret;
958 args[jss::tx_json] = val;
959 args[jss::fail_hard] =
true;
960 args[jss::sync_mode] = syncMode;
962 return env.
rpc(
"json",
"submit", args.toStyledString());
967 payment =
noop(
"alice");
970 jr = applyJsonTxn(
"sync", secret, payment);
971 BEAST_EXPECT(jr[jss::result][jss::engine_result] ==
"tesSUCCESS");
974 jr = applyJsonTxn(
"async", secret, payment);
975 BEAST_EXPECT(jr[jss::result][jss::engine_result] ==
"terSUBMITTED");
980 auto aSeq = env.
seq(
"alice");
982 jr = applyJsonTxn(
"wait", secret, payment);
983 BEAST_EXPECT(jr[jss::result][jss::engine_result] ==
"tesSUCCESS");
986 BEAST_EXPECT(env.
seq(
"alice") == aSeq + 1);
989 jr = applyJsonTxn(
"scott", secret, payment);
990 BEAST_EXPECT(jr[jss::result][jss::error] ==
"invalidParams");
Json::Value noop(Account const &account)
The null transaction.
const XRP_t XRP
Converts to XRP Issue or STAmount.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
std::shared_ptr< STTx const > tx() const
Return the tx data for the last JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Match the number of items in the account's owner directory.
void require(Args const &... args)
Check a set of requirements.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
const SF_UINT32 sfSequence
const std::string fieldName
Amount specifier with an option for any issuer.
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Check a set of conditions.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
const uint256 featureMultiSignReserve
const SF_UINT32 sfSetFlag
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Set a multisignature on a JTx.
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
virtual NetworkOPs & getOPs()=0
void foreachFeature(FeatureBitset bs, F &&f)
constexpr std::uint32_t asfDisableMaster
@ objectValue
object value (collection of name/value pairs).
const any_t any
Returns an amount representing "any issuer".
void testExceptionalShutdown()
virtual Config & config()=0
void set(std::unique_ptr< basic_prop > p)
Set a property If the property already exists, it is replaced.
Sets the SendMax on a JTx.
Execution context for applying a JSON transaction.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Set Paths, SendMax on a JTx.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Slice slice() const noexcept
const uint256 fixMasterKeyAsRegularKey
FeatureBitset supported_amendments()
Set the regular signature on a JTx.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
virtual std::size_t getLocalTxCount()=0
A transaction testing environment wrapper.
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
virtual bool transactionBatch(bool drain)=0
Apply transactions in batches.
static std::string to_string(T const &t)
@ ttACCOUNT_SET
This transaction type adjusts various account settings.
Prop * get()
Return a property if it exists.
Set the sequence number on a JTx.
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::unordered_set< uint256, beast::uhash<> > features
std::array< Account, 1+sizeof...(Args)> noripple(Account const &account, Args const &... args)
Designate accounts as no-ripple in Env::fund.
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
const uint256 featureFlow
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
constexpr std::uint32_t asfDefaultRipple
constexpr std::uint32_t asfRequireDest
uint256 bitsetIndexToFeature(size_t i)
FeatureBitset & set(uint256 const &f, bool value=true)
std::size_t txCount
Number of transactions in the queue.
Match clear account flags.
Immutable cryptographic account descriptor.
const SF_ACCOUNT sfAccount
std::string strHex(FwdIt begin, FwdIt end)
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
void memoize(Account const &account)
Associate AccountID with account.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Json::Value json(JsonValue &&jv, FN const &... fN)
Create JSON from parameters.
A transaction testing environment.
Json::Value rpc(std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
T & get(EitherAmount &amt)
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)