1#include <test/jtx/Env.h>
3#include <test/jtx/Account.h>
4#include <test/jtx/JSONRPCClient.h>
5#include <test/jtx/JTx.h>
6#include <test/jtx/ManualTimeKeeper.h>
7#include <test/jtx/amount.h>
8#include <test/jtx/balance.h>
9#include <test/jtx/fee.h>
10#include <test/jtx/flags.h>
11#include <test/jtx/pay.h>
12#include <test/jtx/seq.h>
13#include <test/jtx/sig.h>
14#include <test/jtx/tags.h>
15#include <test/jtx/trust.h>
16#include <test/jtx/utility.h>
17#include <test/unit_test/SuiteJournal.h>
19#include <xrpld/app/ledger/LedgerMaster.h>
20#include <xrpld/app/main/Application.h>
21#include <xrpld/core/Config.h>
22#include <xrpld/rpc/RPCCall.h>
24#include <xrpl/basics/Log.h>
25#include <xrpl/basics/Number.h>
26#include <xrpl/basics/chrono.h>
27#include <xrpl/basics/contract.h>
28#include <xrpl/basics/safe_cast.h>
29#include <xrpl/basics/scope.h>
30#include <xrpl/basics/strHex.h>
31#include <xrpl/beast/unit_test/suite.h>
32#include <xrpl/beast/utility/Journal.h>
33#include <xrpl/core/NetworkIDService.h>
34#include <xrpl/core/ServiceRegistry.h>
35#include <xrpl/json/to_string.h>
36#include <xrpl/net/HTTPClient.h>
37#include <xrpl/protocol/AccountID.h>
38#include <xrpl/protocol/Asset.h>
39#include <xrpl/protocol/ErrorCodes.h>
40#include <xrpl/protocol/Indexes.h>
41#include <xrpl/protocol/Issue.h>
42#include <xrpl/protocol/Keylet.h>
43#include <xrpl/protocol/MPTIssue.h>
44#include <xrpl/protocol/SField.h>
45#include <xrpl/protocol/STTx.h>
46#include <xrpl/protocol/Serializer.h>
47#include <xrpl/protocol/TER.h>
48#include <xrpl/protocol/TxFlags.h>
49#include <xrpl/protocol/UintTypes.h>
50#include <xrpl/protocol/jss.h>
51#include <xrpl/server/NetworkOPs.h>
60#include <source_location>
94 config->sslVerifyDir, config->sslVerifyFile, config->sslVerify,
debugLog());
97 app->getLogs().threshold(thresh);
100 timeKeeper->set(
app->getLedgerMaster().getClosedLedger()->header().closeTime);
114 app->getJobQueue().rendezvous();
115 app->signalStop(
"~AppBundle");
136 using namespace std::chrono_literals;
138 closeTime +=
closed()->header().closeTimeResolution - 1s;
148 auto resp =
rpc(
"ledger_accept");
149 if (resp[
"result"][
"status"] !=
std::string(
"success"))
152 if (resp.isMember(
"error_what"))
154 reason = resp[
"error_what"].asString();
156 else if (resp.isMember(
"error_message"))
158 reason = resp[
"error_message"].asString();
160 else if (resp.isMember(
"error"))
162 reason = resp[
"error"].asString();
165 JLOG(
journal.error()) <<
"Env::close() failed: " << reason;
176 map_.emplace(account.id(), account);
182 auto const iter =
map_.find(
id);
183 if (iter ==
map_.end())
185 std::cout <<
"Unknown account: " <<
id <<
"\n";
203 auto const sle =
le(account);
206 return {sle->getFieldAmount(sfBalance),
""};
218 return {
STAmount(issue, 0), account.name()};
219 auto amount = sle->getFieldAmount(sfBalance);
221 if (account.id() > issue.
account)
226 MPTID const&
id = mptIssue.getMptID();
228 return {
STAmount(mptIssue, 0), account.name()};
230 AccountID const& issuer = mptIssue.getIssuer();
231 if (account.id() == issuer)
236 return {
STAmount(mptIssue, 0), account.name()};
239 STAmount const amount{mptIssue, sle->getFieldU64(sfOutstandingAmount), 0,
true};
246 return {
STAmount(mptIssue, 0), account.name()};
248 STAmount const amount{mptIssue, sle->getFieldU64(sfMPTAmount)};
258 return {
STAmount(issue, 0), account.name()};
259 auto const aHigh = account.id() > issue.
account;
260 if (sle && sle->isFieldPresent(aHigh ? sfLowLimit : sfHighLimit))
261 return {(*sle)[aHigh ? sfLowLimit : sfHighLimit], account.name()};
262 return {
STAmount(issue, 0), account.name()};
268 auto const sle =
le(account);
271 return sle->getFieldU32(sfOwnerCount);
277 auto const sle =
le(account);
280 return sle->getFieldU32(sfSequence);
299 if (setDefaultRipple)
308 fset(account, asfDefaultRipple),
331 auto const start =
balance(account);
353 if (!
object.isObject())
355 if (
object.isMember(jss::error_code))
357 if (
object.isMember(jss::error_message))
358 parsed.
rpcMessage =
object[jss::error_message].asString();
359 if (
object.isMember(jss::error))
360 parsed.
rpcError =
object[jss::error].asString();
361 if (
object.isMember(jss::error_exception))
362 parsed.
rpcException =
object[jss::error_exception].asString();
367 auto const& result = jr[jss::result];
368 if (result.isMember(jss::engine_result_code))
375 error(parsed, result);
390 auto const jr = [&]() {
393 txid_ =
jt.stx->getTransactionID();
399 test.expect(parsedResult.
ter,
"ter uninitialized!");
417 auto const account =
lookup(
jt.jv[jss::Account].asString());
418 auto const& passphrase = account.name();
425 jr =
rpc(
"submit", passphrase, jv);
436 params[jss::secret] = passphrase;
438 params[jss::tx_json] =
jt.jv;
442 if (!
txid_.parseHex(jr[jss::result][jss::tx_json][jss::hash].
asString()))
446 test.expect(parsedResult.
ter,
"ter uninitialized!");
460 bool bad = !
test.expect(parsed.
ter,
"apply " + locStr +
": No ter result!");
462 (
jt.ter && parsed.
ter &&
464 *parsed.
ter == *
jt.ter,
465 "apply " + locStr +
": Got " +
transToken(*parsed.
ter) +
" (" +
468 using namespace std::string_literals;
473 "apply " + locStr +
": Got RPC result "s +
482 bad = (
jt.rpcException &&
486 (!
jt.rpcException->second || parsed.
rpcException == *
jt.rpcException->second)),
487 "apply " + locStr +
": Got RPC result "s + parsed.
rpcError +
" (" +
488 parsed.
rpcException +
"); Expected " +
jt.rpcException->first +
" (" +
489 jt.rpcException->second.value_or(
"n/a") +
")")) ||
506 for (
auto const& f :
jt.require)
520 auto const result = item.second;
521 if (result ==
nullptr)
524 test.log <<
"This is probably because the transaction failed with a "
545 for (
auto const& signer :
jt.postSigners)
550 if (!
jt.mainSigners.empty())
552 for (
auto const& signer :
jt.mainSigners)
560 auto const account = jv.isMember(sfDelegate.jsonName)
561 ?
lookup(jv[sfDelegate.jsonName].asString())
562 :
lookup(jv[jss::Account].asString());
563 if (!
app().checkSigs())
565 jv[jss::SigningPubKey] =
strHex(account.pk().slice());
567 jv[jss::TxnSignature] =
"00";
570 auto const ar =
le(account);
571 if (ar && ar->isFieldPresent(sfRegularKey))
593 if (!jv.isMember(jss::NetworkID) && networkID > 1024)
668 auto response =
rpcClient(args,
app().config(),
app().getLogs(), apiVersion, headers);
672 JLOG(
journal.error()) <<
"Env::doRpc error, retrying, attempt #" << ctr + 1 <<
" ...";
675 response =
rpcClient(args,
app().config(),
app().getLogs(), apiVersion, headers);
678 return response.second;
bool isNull() const
isNull() tests to see if this field is null.
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
virtual Config & config()=0
constexpr auto visit(Visitors &&... visitors) const -> decltype(auto)
std::unordered_set< uint256, beast::Uhash<> > features
static void initializeSSLContext(std::string const &sslVerifyDir, std::string const &sslVerifyFile, bool sslVerify, beast::Journal j)
A currency issued by an account.
std::shared_ptr< Ledger const > getClosedLedger()
std::chrono::time_point< NetClock > time_point
virtual std::uint32_t getNetworkID() const noexcept=0
Get the configured network ID.
virtual std::uint32_t acceptLedger(std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)=0
Accepts the current transaction tree, return the new ledger's sequence.
constexpr bool holds() const noexcept
std::shared_ptr< STLedgerEntry const > const_pointer
Slice slice() const noexcept
virtual NetworkOPs & getOPs()=0
virtual NetworkIDService & getNetworkIDService()=0
virtual LedgerMaster & getLedgerMaster()=0
static constexpr TERSubset fromInt(int from)
virtual json::Value invoke(std::string const &cmd, json::Value const ¶ms={})=0
Submit a command synchronously.
Immutable cryptographic account descriptor.
std::string const & name() const
Return the name.
std::shared_ptr< STTx const > st(JTx const &jt)
Create a STTx from a JTx The framework requires that JSON is valid.
SLE::const_pointer le(Account const &account) const
Return an account root.
std::uint32_t ownerCount(Account const &account) const
Return the number of objects owned by an account.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
static ParsedResult parseResult(json::Value const &jr)
Gets the TER result and didApply flag from a RPC Json result object.
Account const & lookup(AccountID const &id) const
Returns the Account given the AccountID.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
virtual void submit(JTx const &jt, std::source_location const &loc=std::source_location::current())
Submit an existing JTx.
void enableFeature(uint256 const feature)
PrettyAmount limit(Account const &account, Issue const &issue) const
Returns the IOU limit on an account.
void disableFeature(uint256 const feature)
json::Value doRpc(unsigned apiVersion, std::vector< std::string > const &args, std::unordered_map< std::string, std::string > const &headers={})
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
virtual void autofill(JTx &jt)
void postconditions(JTx const &jt, ParsedResult const &parsed, json::Value const &jr=json::Value(), std::source_location const &loc=std::source_location::current())
Check expected postconditions of JTx submission.
bool close()
Close and advance the ledger.
json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void autofillSig(JTx &jt)
void signAndSubmit(JTx const &jt, json::Value params=json::ValueType::Null, std::source_location const &loc=std::source_location::current())
Use the submit RPC command with a provided JTx object.
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
beast::unit_test::Suite & test
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
std::shared_ptr< STTx const > ust(JTx const &jt)
Create a STTx from a JTx without sanitizing Use to inject bogus values into test transactions by firs...
std::shared_ptr< STObject const > meta()
Return metadata for the last JTx.
Env & apply(WithSourceLocation< json::Value > jv, FN const &... fN)
Apply funclets and submit.
std::unordered_map< AccountID, Account > map_
ManualTimeKeeper & timeKeeper()
bool parseFailureExpected_
std::shared_ptr< STTx const > tx() const
Return the tx data for the last JTx.
void memoize(Account const &account)
Associate AccountID with account.
beast::Journal const journal
AbstractClient & client()
Returns the connected client.
void require(Args const &... args)
Check a set of requirements.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Match clear account flags.
Set the regular signature on a JTx.
Severity
Severity level / threshold of a Journal message.
ErrorInfo const & getErrorInfo(ErrorCodeI code)
Returns an ErrorInfo that reflects the error code.
Keylet mptokenIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet trustLine(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
void fillFee(json::Value &jv, ReadView const &view)
Set the fee automatically.
XrpT const XRP
Converts to XRP Issue or STAmount.
void sign(json::Value &jv, Account const &account, json::Value &sigObject)
Sign automatically into a specific Json field of the jv object.
json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
static AutofillT const kAutofill
STObject parse(json::Value const &jv)
Convert JSON to STObject.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
void fillSeq(json::Value &jv, ReadView const &view)
Set the sequence number automatically.
std::unique_ptr< AbstractClient > makeJSONRPCClient(Config const &cfg, unsigned rpcVersion)
Returns a client using JSON-RPC over HTTP/S.
bool isXRP(AccountID const &c)
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
beast::Journal debugLog()
Returns a debug journal.
std::unique_ptr< beast::Journal::Sink > setDebugLogSink(std::unique_ptr< beast::Journal::Sink > sink)
Set the sink for the debug journal.
std::string strHex(FwdIt begin, FwdIt end)
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > safeCast(Src s) noexcept
std::string transHuman(TER code)
std::string transToken(TER code)
std::string to_string(BaseUInt< Bits, Tag > const &a)
XRPL_NO_SANITIZE_ADDRESS void rethrow()
Rethrow the exception currently being handled.
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
std::pair< int, json::Value > rpcClient(std::vector< std::string > const &args, Config const &config, Logs &logs, unsigned int apiVersion, std::unordered_map< std::string, std::string > const &headers)
Internal invocation of RPC client.
std::unique_ptr< Application > makeApplication(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
std::shared_ptr< STTx const > sterilize(STTx const &stx)
Sterilize a transaction.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
A pair of SHAMap key and LedgerEntryType.
ManualTimeKeeper * timeKeeper
std::unique_ptr< AbstractClient > client
std::unique_ptr< Application > owned
Used by parseResult() and postConditions().
std::optional< ErrorCodeI > rpcCode
Execution context for applying a JSON transaction.
Represents an XRP, IOU, or MPT quantity This customizes the string conversion and supports XRP conver...
Set the sequence number on a JTx.