2#include <test/jtx/Env.h> 
    3#include <test/jtx/envconfig.h> 
    5#include <xrpld/app/rdb/backend/SQLiteDatabase.h> 
    6#include <xrpld/rpc/CTID.h> 
    8#include <xrpl/protocol/ErrorCodes.h> 
    9#include <xrpl/protocol/STBase.h> 
   10#include <xrpl/protocol/STParsedJSON.h> 
   11#include <xrpl/protocol/jss.h> 
   12#include <xrpl/protocol/serialize.h> 
   27        int const expectedSequence,
 
   30        BEAST_EXPECT(result[jss::applied] == 
false);
 
   31        BEAST_EXPECT(result.
isMember(jss::engine_result));
 
   32        BEAST_EXPECT(result.
isMember(jss::engine_result_code));
 
   33        BEAST_EXPECT(result.
isMember(jss::engine_result_message));
 
   40            tx_json = result[jss::tx_json];
 
   44            auto const unHexed = 
strUnHex(result[jss::tx_blob].asString());
 
   49        BEAST_EXPECT(tx_json[jss::TransactionType] == tx[jss::TransactionType]);
 
   50        BEAST_EXPECT(tx_json[jss::Account] == tx[jss::Account]);
 
   52            tx_json[jss::SigningPubKey] == tx.
get(jss::SigningPubKey, 
""));
 
   54            tx_json[jss::TxnSignature] == tx.
get(jss::TxnSignature, 
""));
 
   55        BEAST_EXPECT(tx_json[jss::Fee] == tx.
get(jss::Fee, expectedFee));
 
   57            tx_json[jss::Sequence] == tx.
get(jss::Sequence, expectedSequence));
 
 
   64        int const expectedSequence,
 
 
   77        bool testSerialized = 
true)
 
   82        params[jss::tx_json] = tx;
 
   83        validate(env.
rpc(
"json", 
"simulate", 
to_string(params)), tx);
 
   85        params[jss::binary] = 
true;
 
   86        validate(env.
rpc(
"json", 
"simulate", 
to_string(params)), tx);
 
   88        validate(env.
rpc(
"simulate", 
to_string(tx), 
"binary"), tx);
 
   98            if (BEAST_EXPECT(parsed.
object.has_value()))
 
  101                params[jss::tx_blob] = tx_blob;
 
  102                validate(env.
rpc(
"json", 
"simulate", 
to_string(params)), tx);
 
  103                params[jss::binary] = 
true;
 
  104                validate(env.
rpc(
"json", 
"simulate", 
to_string(params)), tx);
 
  106            validate(env.
rpc(
"simulate", tx_blob), tx);
 
  107            validate(env.
rpc(
"simulate", tx_blob, 
"binary"), tx);
 
 
  130        params[jss::tx_json] = tx;
 
  135            expectedMetadataValue);
 
  140            expectedMetadataValue);
 
 
  150        if (txResult.
isMember(jss::meta_blob))
 
  152            auto unHexed = 
strUnHex(txResult[jss::meta_blob].asString());
 
  158        return txResult[jss::meta];
 
 
  173            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  175                resp[jss::result][jss::error_message] ==
 
  176                "Neither `tx_blob` nor `tx_json` included.");
 
  182            params[jss::tx_blob] = 
"1200";
 
  184            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  186                resp[jss::result][jss::error_message] ==
 
  187                "Can only include one of `tx_blob` and `tx_json`.");
 
  192            params[jss::tx_blob] = 
"1200";
 
  193            params[jss::binary] = 
"100";
 
  194            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  196                resp[jss::result][jss::error_message] ==
 
  197                "Invalid field 'binary'.");
 
  202            params[jss::tx_blob] = 
"12";
 
  204            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  206                resp[jss::result][jss::error_message] ==
 
  207                "Invalid field 'tx_blob'.");
 
  214            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  216                resp[jss::result][jss::error_message] ==
 
  217                "Missing field 'tx.TransactionType'.");
 
  223            tx_json[jss::TransactionType] = jss::Payment;
 
  224            params[jss::tx_json] = tx_json;
 
  226            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  228                resp[jss::result][jss::error_message] ==
 
  229                "Missing field 'tx.Account'.");
 
  234            params[jss::tx_blob] = 
"";
 
  236            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  238                resp[jss::result][jss::error_message] ==
 
  239                "Invalid field 'tx_blob'.");
 
  244            params[jss::tx_blob] = 1.1;
 
  246            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  248                resp[jss::result][jss::error_message] ==
 
  249                "Invalid field 'tx_blob'.");
 
  254            params[jss::tx_json] = 
"";
 
  256            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  258                resp[jss::result][jss::error_message] ==
 
  259                "Invalid field 'tx_json', not object.");
 
  264            params[jss::seed] = 
"doesnt_matter";
 
  266            tx_json[jss::TransactionType] = jss::AccountSet;
 
  268            params[jss::tx_json] = tx_json;
 
  269            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  271                resp[jss::result][jss::error_message] ==
 
  272                "Invalid field 'seed'.");
 
  277            params[jss::secret] = 
"doesnt_matter";
 
  279            tx_json[jss::TransactionType] = jss::AccountSet;
 
  281            params[jss::tx_json] = tx_json;
 
  282            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  284                resp[jss::result][jss::error_message] ==
 
  285                "Invalid field 'secret'.");
 
  290            params[jss::seed_hex] = 
"doesnt_matter";
 
  292            tx_json[jss::TransactionType] = jss::AccountSet;
 
  294            params[jss::tx_json] = tx_json;
 
  295            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  297                resp[jss::result][jss::error_message] ==
 
  298                "Invalid field 'seed_hex'.");
 
  303            params[jss::passphrase] = 
"doesnt_matter";
 
  305            tx_json[jss::TransactionType] = jss::AccountSet;
 
  307            params[jss::tx_json] = tx_json;
 
  308            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  310                resp[jss::result][jss::error_message] ==
 
  311                "Invalid field 'passphrase'.");
 
  317            tx_json[jss::TransactionType] = jss::Payment;
 
  319            params[jss::tx_json] = tx_json;
 
  321            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  323                resp[jss::result][jss::error_exception] ==
 
  324                "Field 'Destination' is required but missing.");
 
  330            tx_json[jss::TransactionType] = jss::AccountSet;
 
  331            tx_json[jss::Account] = 
"badAccount";
 
  332            params[jss::tx_json] = tx_json;
 
  334            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  336                resp[jss::result][jss::error] == 
"srcActMalformed",
 
  337                resp[jss::result][jss::error].toStyledString());
 
  339                resp[jss::result][jss::error_message] ==
 
  340                "Invalid field 'tx.Account'.");
 
  346            tx_json[jss::TransactionType] = jss::AccountSet;
 
  347            tx_json[jss::Account] = alice.
human();
 
  348            params[jss::tx_json] = tx_json;
 
  350            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  352                resp[jss::result][jss::error_message] ==
 
  353                "Source account not found.");
 
  359            tx_json[jss::TransactionType] = jss::AccountSet;
 
  361            tx_json[sfSigners] = 
"1";
 
  362            params[jss::tx_json] = tx_json;
 
  364            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  366                resp[jss::result][jss::error_message] ==
 
  367                "Invalid field 'tx.Signers'.");
 
  373            tx_json[jss::TransactionType] = jss::AccountSet;
 
  376            tx_json[sfSigners].
append(
"1");
 
  377            params[jss::tx_json] = tx_json;
 
  379            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  381                resp[jss::result][jss::error_message] ==
 
  382                "Invalid field 'tx.Signers[0]'.");
 
  388            tx_json[jss::TransactionType] = jss::AccountSet;
 
  390            tx_json[
"foo"] = 
"bar";
 
  391            params[jss::tx_json] = tx_json;
 
  393            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  395                resp[jss::result][jss::error_message] ==
 
  396                "Field 'tx_json.foo' is unknown.");
 
  401            tx_json[jss::TransactionType] = jss::AccountSet;
 
  402            tx_json[jss::Account] = alice.
human();
 
  403            auto const resp = env.
rpc(
"simulate", 
to_string(tx_json), 
"1");
 
  404            BEAST_EXPECT(resp[jss::error_message] == 
"Invalid parameters.");
 
  410            tx_json[jss::TransactionType] = jss::AccountSet;
 
  412            tx_json[jss::TxnSignature] = 
"1200ABCD";
 
  413            params[jss::tx_json] = tx_json;
 
  415            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  417                resp[jss::result][jss::error_message] ==
 
  418                "Transaction should not be signed.");
 
  424            tx_json[jss::TransactionType] = jss::AccountSet;
 
  431                signer[jss::TxnSignature] = 
"1200ABCD";
 
  433                signerOuter[sfSigner] = 
signer;
 
  434                tx_json[sfSigners].
append(signerOuter);
 
  436            params[jss::tx_json] = tx_json;
 
  438            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  440                resp[jss::result][jss::error_message] ==
 
  441                "Transaction should not be signed.");
 
 
  453            cfg->section(
"transaction_queue")
 
  454                .
set(
"minimum_txn_in_ledger_standalone", 
"3");
 
  464        for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
 
  469            params[jss::tx_json] = 
noop(alice);
 
  471            auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  472            auto const result = resp[jss::result];
 
  473            if (BEAST_EXPECT(result.isMember(jss::error)))
 
  475                BEAST_EXPECT(result[jss::error] == 
"highFee");
 
  476                BEAST_EXPECT(result[jss::error_code] == 
rpcHIGH_FEE);
 
 
  484        testcase(
"Invalid transaction type");
 
  492        env.
fund(
XRP(1000000), alice, bob);
 
  496        auto const seq = env.
seq(alice);
 
  504        params[jss::tx_json] = jt.jv;
 
  505        auto const resp = env.
rpc(
"json", 
"simulate", 
to_string(params));
 
  506        BEAST_EXPECT(resp[jss::result][jss::error] == 
"notImpl");
 
  508            resp[jss::result][jss::error_message] == 
"Not implemented.");
 
 
  521        static auto const newDomain = 
"123ABC";
 
  526                auto result = resp[jss::result];
 
  528                    result, tx, 1, env.
current()->fees().base);
 
  530                BEAST_EXPECT(result[jss::engine_result] == 
"tesSUCCESS");
 
  531                BEAST_EXPECT(result[jss::engine_result_code] == 0);
 
  533                    result[jss::engine_result_message] ==
 
  534                    "The simulated transaction would have been applied.");
 
  537                        result.isMember(jss::meta) ||
 
  538                        result.isMember(jss::meta_blob)))
 
  543                            metadata.
isMember(sfAffectedNodes.jsonName)))
 
  546                            metadata[sfAffectedNodes.jsonName].
size() == 1);
 
  547                        auto node = metadata[sfAffectedNodes.jsonName][0u];
 
  549                                node.isMember(sfModifiedNode.jsonName)))
 
  551                            auto modifiedNode = node[sfModifiedNode];
 
  553                                modifiedNode[sfLedgerEntryType] ==
 
  555                            auto finalFields = modifiedNode[sfFinalFields];
 
  556                            BEAST_EXPECT(finalFields[sfDomain] == newDomain);
 
  559                    BEAST_EXPECT(metadata[sfTransactionIndex.jsonName] == 0);
 
  561                        metadata[sfTransactionResult.jsonName] == 
"tesSUCCESS");
 
  568            tx[jss::TransactionType] = jss::AccountSet;
 
  569            tx[sfDomain] = newDomain;
 
  572            testTx(env, tx, validateOutput);
 
  574            tx[sfSigningPubKey] = 
"";
 
  575            tx[sfTxnSignature] = 
"";
 
  577            tx[sfFee] = env.
current()->fees().base.jsonClipped().asString();
 
  580            testTx(env, tx, validateOutput);
 
 
  587        testcase(
"Transaction non-tec failure");
 
  597                    auto result = resp[jss::result];
 
  599                        result, tx, 1, env.
current()->fees().base);
 
  601                    BEAST_EXPECT(result[jss::engine_result] == 
"temBAD_AMOUNT");
 
  602                    BEAST_EXPECT(result[jss::engine_result_code] == -298);
 
  604                        result[jss::engine_result_message] ==
 
  605                        "Malformed: Bad amount.");
 
  608                        !result.isMember(jss::meta) &&
 
  609                        !result.isMember(jss::meta_blob));
 
  615            tx[jss::TransactionType] = jss::Payment;
 
  616            tx[sfDestination] = alice.
human();
 
  620            testTx(env, tx, testSimulation);
 
  622            tx[sfSigningPubKey] = 
"";
 
  623            tx[sfTxnSignature] = 
"";
 
  625            tx[sfFee] = env.
current()->fees().base.jsonClipped().asString();
 
  628            testTx(env, tx, testSimulation);
 
 
  635        testcase(
"Transaction tec failure");
 
  645                    auto result = resp[jss::result];
 
  647                        result, tx, 1, env.
current()->fees().base);
 
  650                        result[jss::engine_result] == 
"tecNO_DST_INSUF_XRP");
 
  651                    BEAST_EXPECT(result[jss::engine_result_code] == 125);
 
  653                        result[jss::engine_result_message] ==
 
  654                        "Destination does not exist. Too little XRP sent to " 
  659                            result.isMember(jss::meta) ||
 
  660                            result.isMember(jss::meta_blob)))
 
  665                                metadata.
isMember(sfAffectedNodes.jsonName)))
 
  668                                metadata[sfAffectedNodes.jsonName].
size() == 1);
 
  669                            auto node = metadata[sfAffectedNodes.jsonName][0u];
 
  671                                    node.isMember(sfModifiedNode.jsonName)))
 
  673                                auto modifiedNode = node[sfModifiedNode];
 
  675                                    modifiedNode[sfLedgerEntryType] ==
 
  677                                auto finalFields = modifiedNode[sfFinalFields];
 
  679                                    finalFields[sfBalance] ==
 
  681                                        100'000'000'000'000'000 -
 
  682                                        env.
current()->fees().base.drops()));
 
  686                            metadata[sfTransactionIndex.jsonName] == 0);
 
  688                            metadata[sfTransactionResult.jsonName] ==
 
  689                            "tecNO_DST_INSUF_XRP");
 
  696            tx[jss::TransactionType] = jss::Payment;
 
  697            tx[sfDestination] = alice.
human();
 
  701            testTx(env, tx, testSimulation);
 
  703            tx[sfSigningPubKey] = 
"";
 
  704            tx[sfTxnSignature] = 
"";
 
  706            tx[sfFee] = env.
current()->fees().base.jsonClipped().asString();
 
  709            testTx(env, tx, testSimulation);
 
 
  716        testcase(
"Successful multi-signed transaction");
 
  720        static auto const newDomain = 
"123ABC";
 
  728        env(
signers(alice, 1, {{becky, 1}, {carol, 1}}));
 
  734                auto result = resp[jss::result];
 
  742                BEAST_EXPECT(result[jss::engine_result] == 
"tesSUCCESS");
 
  743                BEAST_EXPECT(result[jss::engine_result_code] == 0);
 
  745                    result[jss::engine_result_message] ==
 
  746                    "The simulated transaction would have been applied.");
 
  749                        result.isMember(jss::meta) ||
 
  750                        result.isMember(jss::meta_blob)))
 
  755                            metadata.
isMember(sfAffectedNodes.jsonName)))
 
  758                            metadata[sfAffectedNodes.jsonName].
size() == 1);
 
  759                        auto node = metadata[sfAffectedNodes.jsonName][0u];
 
  761                                node.isMember(sfModifiedNode.jsonName)))
 
  763                            auto modifiedNode = node[sfModifiedNode];
 
  765                                modifiedNode[sfLedgerEntryType] ==
 
  767                            auto finalFields = modifiedNode[sfFinalFields];
 
  768                            BEAST_EXPECT(finalFields[sfDomain] == newDomain);
 
  771                    BEAST_EXPECT(metadata[sfTransactionIndex.jsonName] == 0);
 
  773                        metadata[sfTransactionResult.jsonName] == 
"tesSUCCESS");
 
  779            tx[jss::Account] = alice.
human();
 
  780            tx[jss::TransactionType] = jss::AccountSet;
 
  781            tx[sfDomain] = newDomain;
 
  784            testTx(env, tx, validateOutput, 
false);
 
  791                signerOuter[sfSigner] = 
signer;
 
  792                tx[sfSigners].
append(signerOuter);
 
  796            testTx(env, tx, validateOutput, 
false);
 
  798            tx[sfSigningPubKey] = 
"";
 
  799            tx[sfTxnSignature] = 
"";
 
  800            tx[sfSequence] = env.
seq(alice);
 
  804            tx[sfSigners][0u][sfSigner][jss::SigningPubKey] = 
"";
 
  805            tx[sfSigners][0u][sfSigner][jss::TxnSignature] = 
"";
 
  808            testTx(env, tx, validateOutput);
 
 
  815        testcase(
"Transaction with a key-related failure");
 
  819        static auto const newDomain = 
"123ABC";
 
  829                        auto result = resp[jss::result];
 
  837                            result[jss::engine_result] == 
"tefMASTER_DISABLED");
 
  838                        BEAST_EXPECT(result[jss::engine_result_code] == -188);
 
  840                            result[jss::engine_result_message] ==
 
  841                            "Master key is disabled.");
 
  844                            !result.isMember(jss::meta) &&
 
  845                            !result.isMember(jss::meta_blob));
 
  851            tx[jss::TransactionType] = jss::AccountSet;
 
  852            tx[sfDomain] = newDomain;
 
  857            testTx(env, tx, testSimulation);
 
  859            tx[sfTxnSignature] = 
"";
 
  861            tx[sfFee] = env.
current()->fees().base.jsonClipped().asString();
 
  864            testTx(env, tx, testSimulation);
 
 
  872            "Transaction with both single-signing SigningPubKey and " 
  873            "multi-signing Signers");
 
  877        static auto const newDomain = 
"123ABC";
 
  885        env(
signers(alice, 1, {{becky, 1}, {carol, 1}}));
 
  892                    auto result = resp[jss::result];
 
  897                        env.
current()->fees().base * 2);
 
  899                    BEAST_EXPECT(result[jss::engine_result] == 
"temINVALID");
 
  900                    BEAST_EXPECT(result[jss::engine_result_code] == -277);
 
  902                        result[jss::engine_result_message] ==
 
  903                        "The transaction is ill-formed.");
 
  906                        !result.isMember(jss::meta) &&
 
  907                        !result.isMember(jss::meta_blob));
 
  913            tx[jss::TransactionType] = jss::AccountSet;
 
  914            tx[sfDomain] = newDomain;
 
  922                signerOuter[sfSigner] = 
signer;
 
  923                tx[sfSigners].
append(signerOuter);
 
  927            testTx(env, tx, testSimulation, 
false);
 
  929            tx[sfTxnSignature] = 
"";
 
  931            tx[sfFee] = env.
current()->fees().base.jsonClipped().asString();
 
  932            tx[sfSigners][0u][sfSigner][jss::SigningPubKey] =
 
  934            tx[sfSigners][0u][sfSigner][jss::TxnSignature] = 
"";
 
  937            testTx(env, tx, testSimulation);
 
 
  944        testcase(
"Multi-signed transaction with a bad public key");
 
  948        static auto const newDomain = 
"123ABC";
 
  957        env(
signers(alice, 1, {{becky, 1}, {carol, 1}}));
 
  962                auto result = resp[jss::result];
 
  964                    result, tx, env.
seq(alice), env.
current()->fees().base * 2);
 
  967                    result[jss::engine_result] == 
"tefBAD_SIGNATURE",
 
  968                    result[jss::engine_result].toStyledString());
 
  969                BEAST_EXPECT(result[jss::engine_result_code] == -186);
 
  971                    result[jss::engine_result_message] ==
 
  972                    "A signature is provided for a non-signer.");
 
  975                    !result.isMember(jss::meta) &&
 
  976                    !result.isMember(jss::meta_blob));
 
  981            tx[jss::Account] = alice.
human();
 
  982            tx[jss::TransactionType] = jss::AccountSet;
 
  983            tx[sfDomain] = newDomain;
 
  990                signerOuter[sfSigner] = 
signer;
 
  991                tx[sfSigners].
append(signerOuter);
 
  995            testTx(env, tx, validateOutput, 
false);
 
  997            tx[sfSigningPubKey] = 
"";
 
  998            tx[sfTxnSignature] = 
"";
 
  999            tx[sfSequence] = env.
seq(alice);
 
 1003            tx[sfSigners][0u][sfSigner][jss::TxnSignature] = 
"";
 
 1006            testTx(env, tx, validateOutput);
 
 
 1013        testcase(
"Credentials aren't actually deleted on `tecEXPIRED`");
 
 1017        using namespace jtx;
 
 1020        Account const subject{
"subject"};
 
 1021        Account const issuer{
"issuer"};
 
 1023        env.
fund(
XRP(10000), subject, issuer);
 
 1026        auto const credType = 
"123ABC";
 
 1030            env.
current()->info().parentCloseTime.time_since_epoch().count();
 
 1031        jv[sfExpiration.jsonName] = t;
 
 1036            auto validateOutput = [&](
Json::Value const& resp,
 
 1038                auto result = resp[jss::result];
 
 1040                    result, tx, env.
seq(subject), env.
current()->fees().base);
 
 1042                BEAST_EXPECT(result[jss::engine_result] == 
"tecEXPIRED");
 
 1043                BEAST_EXPECT(result[jss::engine_result_code] == 148);
 
 1045                    result[jss::engine_result_message] ==
 
 1046                    "Expiration time is passed.");
 
 1049                        result.isMember(jss::meta) ||
 
 1050                        result.isMember(jss::meta_blob)))
 
 1055                            metadata.
isMember(sfAffectedNodes.jsonName)))
 
 1058                            metadata[sfAffectedNodes.jsonName].
size() == 5);
 
 1063                            for (
auto const& node :
 
 1064                                 metadata[sfAffectedNodes.jsonName])
 
 1066                                if (node.isMember(sfDeletedNode.jsonName) &&
 
 1067                                    node[sfDeletedNode.jsonName]
 
 1068                                        [sfLedgerEntryType.jsonName]
 
 1069                                            .asString() == 
"Credential")
 
 1071                                    auto const deleted =
 
 1072                                        node[sfDeletedNode.jsonName]
 
 1073                                            [sfFinalFields.jsonName];
 
 1074                                    found = deleted[jss::Issuer] ==
 
 1076                                        deleted[jss::Subject] ==
 
 1078                                        deleted[
"CredentialType"] ==
 
 1083                            BEAST_EXPECT(found);
 
 1090                    BEAST_EXPECT(metadata[sfTransactionIndex.jsonName] == 0);
 
 1092                        metadata[sfTransactionResult.jsonName] == 
"tecEXPIRED");
 
 1099            testTx(env, tx, validateOutput);
 
 1101            tx[sfSigningPubKey] = 
"";
 
 1102            tx[sfTxnSignature] = 
"";
 
 1103            tx[sfSequence] = env.
seq(subject);
 
 1104            tx[sfFee] = env.
current()->fees().base.jsonClipped().asString();
 
 1107            testTx(env, tx, validateOutput);
 
 1114            jle.isObject() && jle.isMember(jss::result) &&
 
 1115            !jle[jss::result].isMember(jss::error) &&
 
 1116            jle[jss::result].isMember(jss::node) &&
 
 1117            jle[jss::result][jss::node].isMember(
"LedgerEntryType") &&
 
 1118            jle[jss::result][jss::node][
"LedgerEntryType"] == jss::Credential &&
 
 1119            jle[jss::result][jss::node][jss::Issuer] == issuer.human() &&
 
 1120            jle[jss::result][jss::node][jss::Subject] == subject.human() &&
 
 1121            jle[jss::result][jss::node][
"CredentialType"] ==
 
 
 1131        testcase(
"Successful transaction with a custom network ID");
 
 1133        using namespace jtx;
 
 1135                    cfg->NETWORK_ID = 1025;
 
 1138        static auto const newDomain = 
"123ABC";
 
 1141            auto validateOutput = [&](
Json::Value const& resp,
 
 1143                auto result = resp[jss::result];
 
 1145                    result, tx, 1, env.
current()->fees().base);
 
 1147                BEAST_EXPECT(result[jss::engine_result] == 
"tesSUCCESS");
 
 1148                BEAST_EXPECT(result[jss::engine_result_code] == 0);
 
 1150                    result[jss::engine_result_message] ==
 
 1151                    "The simulated transaction would have been applied.");
 
 1154                        result.isMember(jss::meta) ||
 
 1155                        result.isMember(jss::meta_blob)))
 
 1160                            metadata.
isMember(sfAffectedNodes.jsonName)))
 
 1163                            metadata[sfAffectedNodes.jsonName].
size() == 1);
 
 1164                        auto node = metadata[sfAffectedNodes.jsonName][0u];
 
 1166                                node.isMember(sfModifiedNode.jsonName)))
 
 1168                            auto modifiedNode = node[sfModifiedNode];
 
 1170                                modifiedNode[sfLedgerEntryType] ==
 
 1172                            auto finalFields = modifiedNode[sfFinalFields];
 
 1173                            BEAST_EXPECT(finalFields[sfDomain] == newDomain);
 
 1176                    BEAST_EXPECT(metadata[sfTransactionIndex.jsonName] == 0);
 
 1178                        metadata[sfTransactionResult.jsonName] == 
"tesSUCCESS");
 
 1185            tx[jss::TransactionType] = jss::AccountSet;
 
 1186            tx[sfDomain] = newDomain;
 
 1189            testTx(env, tx, validateOutput);
 
 1191            tx[sfSigningPubKey] = 
"";
 
 1192            tx[sfTxnSignature] = 
"";
 
 1194            tx[sfFee] = env.
current()->fees().base.jsonClipped().asString();
 
 1195            tx[sfNetworkID] = 1025;
 
 1198            testTx(env, tx, validateOutput);
 
 
 1205        testcase(
"Successful transaction with additional metadata");
 
 1207        using namespace jtx;
 
 1208        using namespace std::chrono_literals;
 
 1210                    cfg->NETWORK_ID = 1025;
 
 1217        env.
fund(
XRP(10000), alice, bob);
 
 1224            auto validateOutput =
 
 1229                    auto result = resp[jss::result];
 
 1231                    BEAST_EXPECT(result[jss::engine_result] == 
"tesSUCCESS");
 
 1232                    BEAST_EXPECT(result[jss::engine_result_code] == 0);
 
 1234                        result[jss::engine_result_message] ==
 
 1235                        "The simulated transaction would have been applied.");
 
 1238                            result.isMember(jss::meta) ||
 
 1239                            result.isMember(jss::meta_blob)))
 
 1244                            metadata[sfTransactionIndex.jsonName] == 0);
 
 1246                            metadata[sfTransactionResult.jsonName] ==
 
 1249                            metadata.
isMember(expectedMetadataKey.asString()));
 
 1251                            metadata[expectedMetadataKey.asString()] ==
 
 1252                            expectedMetadataValue);
 
 1258                tx[jss::Account] = alice.
human();
 
 1259                tx[jss::TransactionType] = jss::Payment;
 
 1260                tx[sfDestination] = bob.
human();
 
 1261                tx[sfAmount] = 
"100";
 
 1265                    env, tx, validateOutput, jss::delivered_amount, 
"100");
 
 1270                tx[jss::Account] = alice.
human();
 
 1271                tx[jss::TransactionType] = jss::NFTokenMint;
 
 1272                tx[sfNFTokenTaxon] = 1;
 
 1278                    env, tx, validateOutput, jss::nftoken_id, nftokenId);
 
 1283                tx[jss::Account] = alice.
human();
 
 1284                tx[jss::TransactionType] = jss::MPTokenIssuanceCreate;
 
 1293                    jss::mpt_issuance_id,
 
 
 
Value & append(Value const &value)
Append value to array at the end.
 
UInt size() const
Number of values in array or object.
 
Value removeMember(char const *key)
Remove and return the named member.
 
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.
 
Value get(UInt index, Value const &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
 
testcase_t testcase
Memberspace for declaring test cases.
 
void fail(String const &reason, char const *file, int line)
Record a failure.
 
Slice slice() const noexcept
 
Json::Value getJson(JsonOptions=JsonOptions::none) const override
 
Holds the serialized result of parsing an input JSON object.
 
std::optional< STObject > object
The STObject if the parse was successful.
 
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
 
Json::Value jsonClipped() const
 
Json::Value getJsonMetadata(Json::Value txResult) const
 
void testTransactionNonTecFailure()
 
void testTx(jtx::Env &env, Json::Value const &tx, std::function< void(Json::Value const &, Json::Value const &)> const &validate, bool testSerialized=true)
 
void testSuccessfulTransactionAdditionalMetadata()
 
void testInvalidTransactionType()
 
void testSuccessfulTransactionNetworkID()
 
void run() override
Runs the suite.
 
void testInvalidSingleAndMultiSigningTransaction()
 
void testSuccessfulTransaction()
 
void testTxJsonMetadataField(jtx::Env &env, Json::Value const &tx, std::function< void(Json::Value const &, Json::Value const &, Json::Value const &, Json::Value const &)> const &validate, Json::Value const &expectedMetadataKey, Json::Value const &expectedMetadataValue)
 
void testTransactionTecFailure()
 
void testMultisignedBadPubKey()
 
void testSuccessfulTransactionMultisigned()
 
void testDeleteExpiredCredentials()
 
void testTransactionSigningFailure()
 
void checkBasicReturnValidity(Json::Value const &result, Json::Value const &tx, int const expectedSequence, XRPAmount const &expectedFee)
 
void checkBasicReturnValidity(Json::Value const &result, Json::Value const &tx, int const expectedSequence, std::string const &expectedFee)
 
Immutable cryptographic account descriptor.
 
PublicKey const & pk() const
Return the public key.
 
std::string const & human() const
Returns the human readable public key.
 
A transaction testing environment.
 
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
 
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
 
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
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 fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
 
JTx jtnofill(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
 
Adds a new Batch Txn on a JTx and autofills.
 
Set the expected result code for a JTx The test will fail if the code doesn't match.
 
Set the regular signature on a JTx.
 
@ arrayValue
array value (ordered list)
 
@ objectValue
object value (collection of name/value pairs).
 
Json::Value outer(jtx::Account const &account, uint32_t seq, STAmount const &fee, std::uint32_t flags)
Batch.
 
XRPAmount calcBatchFee(jtx::Env const &env, uint32_t const &numSigners, uint32_t const &txns=0)
Calculate Batch Fee.
 
Json::Value create(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
 
Json::Value accept(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
 
Json::Value ledgerEntry(jtx::Env &env, jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
 
uint256 getNextID(jtx::Env const &env, jtx::Account const &issuer, std::uint32_t nfTokenTaxon, std::uint16_t flags, std::uint16_t xferFee)
Get the next NFTokenID that will be issued.
 
std::uint32_t ownerCount(Env const &env, Account const &account)
 
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
 
Json::Value signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
 
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
 
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
 
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
 
XRP_t const XRP
Converts to XRP Issue or STAmount.
 
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
 
constexpr std::uint32_t tfAllOrNothing
 
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
 
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
 
constexpr std::uint32_t asfDisableMaster
 
std::string strHex(FwdIt begin, FwdIt end)
 
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
 
std::string to_string(base_uint< Bits, Tag > const &a)
 
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
 
Set the sequence number on a JTx.
 
A signer in a SignerList.