//------------------------------------------------------------------------------ /* This file is part of rippled: https://github.com/ripple/rippled Copyright (c) 2023 XRPL Labs Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== #include #include #include #include #include #include #include #include #include #include #include #include #include #define BEAST_REQUIRE(x) \ { \ BEAST_EXPECT(!!(x)); \ if (!(x)) \ return; \ } #define M(m) memo(m, "", "") namespace ripple { namespace test { class Import_test : public beast::unit_test::suite { std::vector const keys = { "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1"}; static std::pair> accountKeyAndSle(ReadView const& view, jtx::Account const& account) { auto const k = keylet::account(account); return {k.key, view.read(k)}; } static std::pair> feesKeyAndSle(ReadView const& view) { auto const k = keylet::fees(); return {k.key, view.read(k)}; } static std::pair> signersKeyAndSle(ReadView const& view, jtx::Account const& account) { auto const k = keylet::signers(account); return {k.key, view.read(k)}; } static std::size_t ownerDirCount(ReadView const& view, jtx::Account const& acct) { ripple::Dir const ownerDir(view, keylet::ownerDir(acct.id())); return std::distance(ownerDir.begin(), ownerDir.end()); }; static std::uint32_t importVLSequence(jtx::Env const& env, PublicKey const& pk) { auto const sle = env.le(keylet::import_vlseq(pk)); if (sle && sle->isFieldPresent(sfImportSequence)) return (*sle)[sfImportSequence]; return 0; } bool hasUNLReport(jtx::Env const& env) { auto const slep = env.le(keylet::UNLReport()); return slep != nullptr; } void incLgrSeqForAccDel( jtx::Env& env, jtx::Account const& acc, std::uint32_t margin = 0) { int const delta = [&]() -> int { if (env.seq(acc) + 255 > env.current()->seq()) return env.seq(acc) - env.current()->seq() + 255 - margin; return 0; }(); BEAST_EXPECT(margin == 0 || delta >= 0); for (int i = 0; i < delta; ++i) env.close(); BEAST_EXPECT(env.current()->seq() == env.seq(acc) + 255 - margin); } void testComputeStartingBalance(FeatureBitset features) { testcase("import header - computeStartingBonus"); using namespace test::jtx; using namespace std::literals; test::jtx::Env env{*this, network::makeNetworkVLConfig(21337, keys)}; // old fee XRPAmount const value = Import::computeStartingBonus(*env.current()); BEAST_EXPECT(value == drops(2000000)); // todo: new fee } void testIsHex(FeatureBitset features) { testcase("import utils - isHex"); bool const result = isHex("DEADBEEF"); BEAST_EXPECT(result == true); bool const result1 = isHex("Hello world"); BEAST_EXPECT(result1 == false); } void testIsBase58(FeatureBitset features) { testcase("import utils - isBase58"); bool const result = isBase58("hE45rTtDcGvFz"); BEAST_EXPECT(result == true); bool const result1 = isBase58("Hello world"); BEAST_EXPECT(result1 == false); } void testIsBase64(FeatureBitset features) { testcase("import utils - isBase64"); bool const result = isBase64("SGVsbG8gV29ybGQh"); BEAST_EXPECT(result == true); bool const result1 = isBase64("Hello world"); BEAST_EXPECT(result1 == false); } void testParseUint64(FeatureBitset features) { testcase("import utils - parseUint64"); std::optional result1 = parse_uint64("1234"); BEAST_EXPECT(result1 == 1234); // std::optional result2 = parse_uint64("0xFFAABBCCDD22"); // BEAST_EXPECT(result2 == 0xFFAABBCCDD22); std::optional result3 = parse_uint64("2147483647"); BEAST_EXPECT(result3 == 2147483647); std::optional result4 = parse_uint64("18446744073709551615"); BEAST_EXPECT(result4 == 18446744073709551615ull); } void testSyntaxCheckProofArray(FeatureBitset features) { testcase("import utils - syntaxCheckProof: is array"); using namespace test::jtx; using namespace std::literals; test::jtx::Env env{*this, network::makeNetworkVLConfig(21337, keys)}; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); // XPOP.transaction.proof list xpop is disabled { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::proof] = Json::arrayValue; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // // XPOP.transaction.proof list should be exactly 16 entries // { // Json::Value tmpXpop = // import::loadXpop(ImportTCAccountSet::w_seed); // tmpXpop[jss::transaction][jss::proof] = Json::arrayValue; // for(int i = 0; i < 16; i++) { // tmpXpop[jss::transaction][jss::proof].append("E000CC0736630D66DAB573A2642E1BD0646DFB13A871B2CCFA6E4226F477D88C"); // } // Json::Value const tx = import::import(alice, tmpXpop); // env(tx, ter(temMALFORMED)); // } // // XPOP.transaction.proof list entry missing or wrong format (should // be hex string with 64 characters) // { // Json::Value tmpXpop = // import::loadXpop(ImportTCAccountSet::w_seed); // tmpXpop[jss::transaction][jss::proof] = Json::arrayValue; // for(int i = 0; i < 16; i++) { // tmpXpop[jss::transaction][jss::proof].append("wrong format"); // } // Json::Value const tx = import::import(alice, tmpXpop); // env(tx, ter(temMALFORMED)); // } // // XPOP.transaction.proof list entry has wrong format // { // Json::Value tmpXpop = // import::loadXpop(ImportTCAccountSet::w_seed); // tmpXpop[jss::transaction][jss::proof] = Json::arrayValue; // Json::Value child1; // child1["children"] = Json::arrayValue; // child1["hash"] = // "31C2D27644F0E6D81AF332F466F71D43C25946A45FE43F121A500E22003F39A4"; // child1["key"] = // "60748F98318DB6A39737D0C1BE5614AEBD7F1ACEE5FB16E82D49F16BB13BA87F"; // tmpXpop[jss::transaction][jss::proof].append(child1); // Json::Value const tx = import::import(alice, tmpXpop); // env(tx, ter(temMALFORMED)); // } } void testSyntaxCheckProofObject(FeatureBitset features) { testcase("import utils - syntaxCheckProof: is object"); using namespace test::jtx; using namespace std::literals; test::jtx::Env env{*this, network::makeNetworkVLConfig(21337, keys)}; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); std::string strJson = R"json({ "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" })json"; Json::Value proof; Json::Reader reader; reader.parse(strJson, proof); // XPOP.transaction.proof list entry has wrong format { BEAST_EXPECT(syntaxCheckProof(proof, env.journal, 65) == false); } // XPOP.transaction.proof invalid branch size { Json::Value tmpProof = proof; tmpProof[jss::children]["30"] = tmpProof[jss::children]["3"]; BEAST_EXPECT(syntaxCheckProof(tmpProof, env.journal) == false); } // XPOP.transaction.proof child node was not 0-F { Json::Value tmpProof = proof; tmpProof[jss::children]["not a hex"] = tmpProof[jss::children]["3"]; BEAST_EXPECT(syntaxCheckProof(tmpProof, env.journal) == false); } // XPOP.transaction.proof tree node has wrong format // invalid child (must be object) { Json::Value tmpProof = proof; tmpProof[jss::children]["3"] = "not object"; BEAST_EXPECT(syntaxCheckProof(tmpProof, env.journal) == false); } // XPOP.transaction.proof tree node has wrong format // invalid hash (must be string) { Json::Value tmpProof = proof; tmpProof[jss::children]["3"][jss::hash] = 1234; BEAST_EXPECT(syntaxCheckProof(tmpProof, env.journal) == false); } // XPOP.transaction.proof tree node has wrong format // invalid hash size (must be 64) { Json::Value tmpProof = proof; tmpProof[jss::children]["3"][jss::hash] = "00000000000000000000000000000000000000000000000000000000000000" "000"; BEAST_EXPECT(syntaxCheckProof(tmpProof, env.journal) == false); } // XPOP.transaction.proof tree node has wrong format // invalid key (must be string) { Json::Value tmpProof = proof; tmpProof[jss::children]["3"][jss::key] = 1234; BEAST_EXPECT(syntaxCheckProof(tmpProof, env.journal) == false); } // XPOP.transaction.proof tree node has wrong format // invalid key size (must be 64) { Json::Value tmpProof = proof; tmpProof[jss::children]["3"][jss::key] = "00000000000000000000000000000000000000000000000000000000000000" "000"; BEAST_EXPECT(syntaxCheckProof(tmpProof, env.journal) == false); } // XPOP.transaction.proof tree node has wrong format // invalid node children (must be object) { Json::Value tmpProof = proof; tmpProof[jss::children]["3"][jss::children] = "bad object"; BEAST_EXPECT(syntaxCheckProof(tmpProof, env.journal) == false); } // XPOP.transaction.proof bad children format // invalid node child children (must be hex) { Json::Value tmpProof = proof; tmpProof[jss::children]["3"][jss::children] = tmpProof[jss::children]["3"]; BEAST_EXPECT(syntaxCheckProof(tmpProof, env.journal) == false); } // success { BEAST_EXPECT(syntaxCheckProof(proof, env.journal) == true); } } void testSyntaxCheckXPOP(FeatureBitset features) { testcase("import utils - syntaxCheckXPOP"); using namespace test::jtx; using namespace std::literals; test::jtx::Env env{*this, network::makeNetworkVLConfig(21337, keys)}; // blob empty { Blob raw{}; BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // blob string empty { Blob raw{0}; BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP failed to parse string json { Blob raw{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP is not a JSON object { std::string strJson = R"json([])json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger is not a JSON object { std::string strJson = R"json({ "ledger": "not object" })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.transaction is not a JSON object { std::string strJson = R"json({ "ledger": {}, "transaction": "not object" })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation is not a JSON object { std::string strJson = R"json({ "ledger": {}, "transaction": {}, "validation": "not object" })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.LEDGER // XPOP.ledger.acroot missing or wrong format // invalid xpop.ledger.acroot (must be string) { std::string strJson = R"json({ "ledger": { "acroot": {} }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.acroot missing or wrong format // invalid xpop.ledger.acroot (must be 64) { std::string strJson = R"json({ "ledger": { "acroot": "00000000000000000000000000000000000000000000000000000000000000000" }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.acroot missing or wrong format // invalid xpop.ledger.acroot (must be hex) { std::string strJson = R"json({ "ledger": { "acroot": "this string will pass a length check but fail when checking hex." }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.txroot missing or wrong format // invalid xpop.ledger.txroot (must be string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": {} }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.txroot missing or wrong format // invalid xpop.ledger.txroot (must be 64) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "00000000000000000000000000000000000000000000000000000000000000000" }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.txroot missing or wrong format // invalid xpop.ledger.txroot (must be hex) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "this string will pass a length check but fail when checking hex." }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.phash missing or wrong format // invalid xpop.ledger.phash (must be string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": {} }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.phash missing or wrong format // invalid xpop.ledger.phash (must be 64) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "00000000000000000000000000000000000000000000000000000000000000000" }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.phash missing or wrong format // invalid xpop.ledger.phash (must be hex) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "this string will pass a length check but fail when checking hex." }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.close missing or wrong format // invalid xpop.ledger.close (must be int) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": "738786851" }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.coins missing or wrong format // invalid xpop.ledger.coins (must be int or string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": {} }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.coins missing or wrong format // invalid xpop.ledger.coins (must be int or string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "not an int string" }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.cres missing or wrong format // invalid xpop.ledger.cres (must be int) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": "not an int" }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.flags missing or wrong format // invalid xpop.ledger.flags (must be int) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": "not an int" }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.index missing or wrong format // invalid xpop.ledger.index (must be int) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": "not an int", "index": "1" }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.ledger.pclose missing or wrong format // invalid xpop.ledger.pclose (must be int) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": "not an int" }, "transaction": {}, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.TRANSACTION // XPOP.transaction.blob missing or wrong format // invalid xpop.transaction.blob (must be hex string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": {} }, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.transaction.blob missing or wrong format // invalid xpop.transaction.blob (must be hex string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "not a hex" }, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.transaction.meta missing or wrong format // invalid xpop.transaction.meta (must be hex string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": {} }, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.transaction.meta missing or wrong format // invalid xpop.transaction.meta (must be hex string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "not a hex" }, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.transaction.proof failed syntax check // invalid xpop.transaction.proof (must pass syntaxCheckProof) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": {} }, "validation": {} })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.data missing or wrong format // invalid xpop.validation.data (must be object) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": "not an object" } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl missing or wrong format // invalid xpop.validation.unl (must be object) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": "not an object" } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.TRANSACTION.DATA // XPOP.validation.data entry has wrong format // invalid xpop.validation.data key/value (must be base58 hex string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A" "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "not base 58": "", }, "unl": {} } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl.public_key missing or // invalid xpop.validation.data key/value (must be base58 hex string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": 1, }, "unl": {} } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl.public_key invalid key type. // invalid xpop.validation.data key/value (must be base58 hex string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "not a hex", }, "unl": {} } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.TRANSACTION.UNL // XPOP.validation.unl.public_key missing or // invalid xpop.validation.unl.public_key (must be hex string with valid // key type) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": { "public_key": 1 } } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl.public_key missing or // invalid xpop.validation.unl.public_key (must be hex string with valid // key type) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": { "public_key": "not a hex" } } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl.public_key missing or // invalid xpop.validation.unl.public_key (must be hex string with valid // key type) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": { "public_key": "0074D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1" } } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl.manifest missing or wrong // invalid xpop.validation.unl.manifest (must be string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": { "public_key": "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1", "manifest": 1 } } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl.blob missing or wrong // invalid xpop.validation.unl.blob (must be base 64 string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": { "public_key": "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1", "manifest": "JAAAAAFxIe101ANsZZGkvfnFTO+jm5lqXc5fhtEf2hh0SBzp1aHNwXMh7TN9+b62cZqTngaFYU5tbGpYHC8oYuI3G3vwj9OW2Z9gdkAnUjfY5zOEkhq31tU4338jcyUpVA5/VTsANFce7unDo+JeVoEhfuOb/Y8WA3Diu9XzuOD4U/ikfgf9SZOlOGcBcBJAw44PLjH+HUtEnwX45lIRmo0x5aINFMvZsBpE9QteSDBXKwYzLdnSW4e1bs21o+IILJIiIKU/+1Uxx0FRpQbMDA==", "blob": 1 } } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl.blob missing or wrong // invalid xpop.validation.unl.blob (must be base 64 string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": { "public_key": "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1", "manifest": "JAAAAAFxIe101ANsZZGkvfnFTO+jm5lqXc5fhtEf2hh0SBzp1aHNwXMh7TN9+b62cZqTngaFYU5tbGpYHC8oYuI3G3vwj9OW2Z9gdkAnUjfY5zOEkhq31tU4338jcyUpVA5/VTsANFce7unDo+JeVoEhfuOb/Y8WA3Diu9XzuOD4U/ikfgf9SZOlOGcBcBJAw44PLjH+HUtEnwX45lIRmo0x5aINFMvZsBpE9QteSDBXKwYzLdnSW4e1bs21o+IILJIiIKU/+1Uxx0FRpQbMDA==", "blob": "not a base 64 string" } } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl.signature missing or wrong // invalid xpop.validation.unl.signature (must be hex string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": { "public_key": "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1", "manifest": "JAAAAAFxIe101ANsZZGkvfnFTO+jm5lqXc5fhtEf2hh0SBzp1aHNwXMh7TN9+b62cZqTngaFYU5tbGpYHC8oYuI3G3vwj9OW2Z9gdkAnUjfY5zOEkhq31tU4338jcyUpVA5/VTsANFce7unDo+JeVoEhfuOb/Y8WA3Diu9XzuOD4U/ikfgf9SZOlOGcBcBJAw44PLjH+HUtEnwX45lIRmo0x5aINFMvZsBpE9QteSDBXKwYzLdnSW4e1bs21o+IILJIiIKU/+1Uxx0FRpQbMDA==", "blob": "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMTFDMTIwNERFNUMiLCJtYW5pZmVzdCI6IkpBQUFBQUp4SWUwNHZVUmEvV0lWbGlETUdXd21hS0pyYjdzMnNKbnJWYk9LV01FY0VnVGVYSE1oQW9HTU5jc2dVVU53S28raDd6aGFYS0YrSEd3NlhoRWpvREtyYWxrWW5Naktka2N3UlFJaEFKN2NONEo2TmRWZnBudkVJL1pldVdDVHZucGFKaXJLTkZjQzN6TU9qZ3dqQWlBYktJMGZiWGdTMVJMbG9OaHhkSGhWcTlvekVXVkU5Y0l3WEROM0F4cXlZM0FTUUN0MCt1L2lOU0RENmJYdlVUdGRtdDROcnRsYng0Vnp1bVRwZmpSWXA0bE1vSS9oNDNwVVRqcDdWRm9YYm5LV2pWaHFOYUdtNTc3SzZKNjk3WFo3VFFFPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURCRUUzMEZBRTkyRUVFODhFMUM0OTgwRDA5RUNGREU5OUExMTZEMDc4RUMyMTg1N0RCMUI0N0I0MjY0MThFNDI4IiwibWFuaWZlc3QiOiJKQUFBQUFKeEllMis0dyt1a3U3b2poeEpnTkNlejk2Wm9SYlFlT3doaFgyeHRIdENaQmprS0hNaEE5U21IRHhPaUNNVFpsNW5SeHJwMnlqV1o1Z2p4MkRyb1VGclU0bnJFcVU3ZGtjd1JRSWhBTGRFRmVqWStwVW5nbGk3c1R2aWIwQm1ESFA3TjZpa1ZFQkk2SDdJd1UxekFpQmRzeW9TcVBjQzJOTXFnQW5IWEhHZGtBSXdCUUQxQVVnOVg4WkpMeWZjd0hBU1FDdDFiS1Z6T014UlFtUjN3Tks0ZEtkb2ZJR3J4RTlTanVMUjZQYThCNW4wOFNZSjhLNjJnZSs5YTZCdFphbEVtL0hPZGN6ME5BRk9jeWNyRi9DdFNBND0ifV19", "signature": 1 } } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl.signature missing or wrong // invalid xpop.validation.unl.signature (must be hex string) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": { "public_key": "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1", "manifest": "JAAAAAFxIe101ANsZZGkvfnFTO+jm5lqXc5fhtEf2hh0SBzp1aHNwXMh7TN9+b62cZqTngaFYU5tbGpYHC8oYuI3G3vwj9OW2Z9gdkAnUjfY5zOEkhq31tU4338jcyUpVA5/VTsANFce7unDo+JeVoEhfuOb/Y8WA3Diu9XzuOD4U/ikfgf9SZOlOGcBcBJAw44PLjH+HUtEnwX45lIRmo0x5aINFMvZsBpE9QteSDBXKwYzLdnSW4e1bs21o+IILJIiIKU/+1Uxx0FRpQbMDA==", "blob": "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMTFDMTIwNERFNUMiLCJtYW5pZmVzdCI6IkpBQUFBQUp4SWUwNHZVUmEvV0lWbGlETUdXd21hS0pyYjdzMnNKbnJWYk9LV01FY0VnVGVYSE1oQW9HTU5jc2dVVU53S28raDd6aGFYS0YrSEd3NlhoRWpvREtyYWxrWW5Naktka2N3UlFJaEFKN2NONEo2TmRWZnBudkVJL1pldVdDVHZucGFKaXJLTkZjQzN6TU9qZ3dqQWlBYktJMGZiWGdTMVJMbG9OaHhkSGhWcTlvekVXVkU5Y0l3WEROM0F4cXlZM0FTUUN0MCt1L2lOU0RENmJYdlVUdGRtdDROcnRsYng0Vnp1bVRwZmpSWXA0bE1vSS9oNDNwVVRqcDdWRm9YYm5LV2pWaHFOYUdtNTc3SzZKNjk3WFo3VFFFPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURCRUUzMEZBRTkyRUVFODhFMUM0OTgwRDA5RUNGREU5OUExMTZEMDc4RUMyMTg1N0RCMUI0N0I0MjY0MThFNDI4IiwibWFuaWZlc3QiOiJKQUFBQUFKeEllMis0dyt1a3U3b2poeEpnTkNlejk2Wm9SYlFlT3doaFgyeHRIdENaQmprS0hNaEE5U21IRHhPaUNNVFpsNW5SeHJwMnlqV1o1Z2p4MkRyb1VGclU0bnJFcVU3ZGtjd1JRSWhBTGRFRmVqWStwVW5nbGk3c1R2aWIwQm1ESFA3TjZpa1ZFQkk2SDdJd1UxekFpQmRzeW9TcVBjQzJOTXFnQW5IWEhHZGtBSXdCUUQxQVVnOVg4WkpMeWZjd0hBU1FDdDFiS1Z6T014UlFtUjN3Tks0ZEtkb2ZJR3J4RTlTanVMUjZQYThCNW4wOFNZSjhLNjJnZSs5YTZCdFphbEVtL0hPZGN6ME5BRk9jeWNyRi9DdFNBND0ifV19", "signature": "not a hex" } } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl.version missing or // invalid xpop.validation.unl.version (must be int) { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": { "public_key": "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1", "manifest": "JAAAAAFxIe101ANsZZGkvfnFTO+jm5lqXc5fhtEf2hh0SBzp1aHNwXMh7TN9+b62cZqTngaFYU5tbGpYHC8oYuI3G3vwj9OW2Z9gdkAnUjfY5zOEkhq31tU4338jcyUpVA5/VTsANFce7unDo+JeVoEhfuOb/Y8WA3Diu9XzuOD4U/ikfgf9SZOlOGcBcBJAw44PLjH+HUtEnwX45lIRmo0x5aINFMvZsBpE9QteSDBXKwYzLdnSW4e1bs21o+IILJIiIKU/+1Uxx0FRpQbMDA==", "blob": "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMTFDMTIwNERFNUMiLCJtYW5pZmVzdCI6IkpBQUFBQUp4SWUwNHZVUmEvV0lWbGlETUdXd21hS0pyYjdzMnNKbnJWYk9LV01FY0VnVGVYSE1oQW9HTU5jc2dVVU53S28raDd6aGFYS0YrSEd3NlhoRWpvREtyYWxrWW5Naktka2N3UlFJaEFKN2NONEo2TmRWZnBudkVJL1pldVdDVHZucGFKaXJLTkZjQzN6TU9qZ3dqQWlBYktJMGZiWGdTMVJMbG9OaHhkSGhWcTlvekVXVkU5Y0l3WEROM0F4cXlZM0FTUUN0MCt1L2lOU0RENmJYdlVUdGRtdDROcnRsYng0Vnp1bVRwZmpSWXA0bE1vSS9oNDNwVVRqcDdWRm9YYm5LV2pWaHFOYUdtNTc3SzZKNjk3WFo3VFFFPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURCRUUzMEZBRTkyRUVFODhFMUM0OTgwRDA5RUNGREU5OUExMTZEMDc4RUMyMTg1N0RCMUI0N0I0MjY0MThFNDI4IiwibWFuaWZlc3QiOiJKQUFBQUFKeEllMis0dyt1a3U3b2poeEpnTkNlejk2Wm9SYlFlT3doaFgyeHRIdENaQmprS0hNaEE5U21IRHhPaUNNVFpsNW5SeHJwMnlqV1o1Z2p4MkRyb1VGclU0bnJFcVU3ZGtjd1JRSWhBTGRFRmVqWStwVW5nbGk3c1R2aWIwQm1ESFA3TjZpa1ZFQkk2SDdJd1UxekFpQmRzeW9TcVBjQzJOTXFnQW5IWEhHZGtBSXdCUUQxQVVnOVg4WkpMeWZjd0hBU1FDdDFiS1Z6T014UlFtUjN3Tks0ZEtkb2ZJR3J4RTlTanVMUjZQYThCNW4wOFNZSjhLNjJnZSs5YTZCdFphbEVtL0hPZGN6ME5BRk9jeWNyRi9DdFNBND0ifV19", "signature": "849F6B8DA6E11C213B561659C16F13D35385E8EA9E775483ADC84578F6D578943DE5EB681584B2C03EFFFDFD216F9E0B21576E482F941C7195893B72B5B1F70D", "version": "not an int" } } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT( syntaxCheckXPOP(raw, env.journal).has_value() == false); } // XPOP.validation.unl entry has wrong format // valid xpop { std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": { "public_key": "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1", "manifest": "JAAAAAFxIe101ANsZZGkvfnFTO+jm5lqXc5fhtEf2hh0SBzp1aHNwXMh7TN9+b62cZqTngaFYU5tbGpYHC8oYuI3G3vwj9OW2Z9gdkAnUjfY5zOEkhq31tU4338jcyUpVA5/VTsANFce7unDo+JeVoEhfuOb/Y8WA3Diu9XzuOD4U/ikfgf9SZOlOGcBcBJAw44PLjH+HUtEnwX45lIRmo0x5aINFMvZsBpE9QteSDBXKwYzLdnSW4e1bs21o+IILJIiIKU/+1Uxx0FRpQbMDA==", "blob": "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMTFDMTIwNERFNUMiLCJtYW5pZmVzdCI6IkpBQUFBQUp4SWUwNHZVUmEvV0lWbGlETUdXd21hS0pyYjdzMnNKbnJWYk9LV01FY0VnVGVYSE1oQW9HTU5jc2dVVU53S28raDd6aGFYS0YrSEd3NlhoRWpvREtyYWxrWW5Naktka2N3UlFJaEFKN2NONEo2TmRWZnBudkVJL1pldVdDVHZucGFKaXJLTkZjQzN6TU9qZ3dqQWlBYktJMGZiWGdTMVJMbG9OaHhkSGhWcTlvekVXVkU5Y0l3WEROM0F4cXlZM0FTUUN0MCt1L2lOU0RENmJYdlVUdGRtdDROcnRsYng0Vnp1bVRwZmpSWXA0bE1vSS9oNDNwVVRqcDdWRm9YYm5LV2pWaHFOYUdtNTc3SzZKNjk3WFo3VFFFPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURCRUUzMEZBRTkyRUVFODhFMUM0OTgwRDA5RUNGREU5OUExMTZEMDc4RUMyMTg1N0RCMUI0N0I0MjY0MThFNDI4IiwibWFuaWZlc3QiOiJKQUFBQUFKeEllMis0dyt1a3U3b2poeEpnTkNlejk2Wm9SYlFlT3doaFgyeHRIdENaQmprS0hNaEE5U21IRHhPaUNNVFpsNW5SeHJwMnlqV1o1Z2p4MkRyb1VGclU0bnJFcVU3ZGtjd1JRSWhBTGRFRmVqWStwVW5nbGk3c1R2aWIwQm1ESFA3TjZpa1ZFQkk2SDdJd1UxekFpQmRzeW9TcVBjQzJOTXFnQW5IWEhHZGtBSXdCUUQxQVVnOVg4WkpMeWZjd0hBU1FDdDFiS1Z6T014UlFtUjN3Tks0ZEtkb2ZJR3J4RTlTanVMUjZQYThCNW4wOFNZSjhLNjJnZSs5YTZCdFphbEVtL0hPZGN6ME5BRk9jeWNyRi9DdFNBND0ifV19", "signature": "849F6B8DA6E11C213B561659C16F13D35385E8EA9E775483ADC84578F6D578943DE5EB681584B2C03EFFFDFD216F9E0B21576E482F941C7195893B72B5B1F70D", "version": 1 } } })json"; Blob raw = Blob(strJson.begin(), strJson.end()); BEAST_EXPECT(syntaxCheckXPOP(raw, env.journal).has_value() == true); } } void testGetVLInfo(FeatureBitset features) { testcase("import utils - getVLInfo"); using namespace test::jtx; using namespace std::literals; test::jtx::Env env{*this, network::makeNetworkVLConfig(21337, keys)}; std::string strJson = R"json({ "ledger": { "acroot": "DCE36DCACDCFCB3441866E09A183B7B8064B3F5E06593CD6AA8ACCC1B284B477", "txroot": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "phash": "BAB19E13B25251A83493073F424FD986EA7BA49F9F4C83A061700131460D747D", "close": 738786851, "coins": "99999998999999868", "cres": 10, "flags": 10, "index": 1, "pclose": 738786851 }, "transaction": { "blob": "12000322000000002400000002201B0000006C201D0000535968400000003B9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519560F81148EA87CA747AF74EE03A7E36C0F8EB1C1568D588A", "meta": "201C00000000F8E51100612500000052553CEFE169D8DB251A7757C8A80214D7466E81FB2EF6A91E0970B428326B2134EB56A92E4B1340C656FE01A66D529BB7957EAD34D9E193D190EA62AAE4764B5B08C5E624000000026240000000773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481148EA87CA747AF74EE03A7E36C0F8EB1C1568D588AE1E1F1031000", "proof": { "children": { "3": { "children": {}, "hash": "AA126BA0486ADAE575BBC5335E42E236275A452037CA9A876D1A8CDACA1AE542", "key": "39D6F6AB7D0A827DD1502B7B9571626A2B601DBE5BC786EF8ADD00E0CB7FCEB3" } }, "hash": "409C8D073DDB5AB07FD2CD4F14467A8F3BC8FFBA16A0032D12D823D8511C12F4", "key": "0000000000000000000000000000000000000000000000000000000000000000" } }, "validation": { "data": { "n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN": "22800000012600000059292C08FE225149FB62BB67011E9C3F641848E32A209CEAD98BD4D73A78A11F2F92E4AFA65F6A50177BC1723CF6FEDBE539067FF3EA2CF5ADF8FD611DA22B682617DB782041BCA913732103D4A61C3C4E882313665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76473045022100E53006BDE6CB3ECB7FD08711B103DFD793438751DDFBED5DC421A3C7DE3545C4022045A2332222261A55153A338930545A5F463DAC2E1BF56C4CE5E02726E919A714" }, "unl": { "public_key": "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1", "manifest": "JAAAAAFxIe101ANsZZGkvfnFTO+jm5lqXc5fhtEf2hh0SBzp1aHNwXMh7TN9+b62cZqTngaFYU5tbGpYHC8oYuI3G3vwj9OW2Z9gdkAnUjfY5zOEkhq31tU4338jcyUpVA5/VTsANFce7unDo+JeVoEhfuOb/Y8WA3Diu9XzuOD4U/ikfgf9SZOlOGcBcBJAw44PLjH+HUtEnwX45lIRmo0x5aINFMvZsBpE9QteSDBXKwYzLdnSW4e1bs21o+IILJIiIKU/+1Uxx0FRpQbMDA==", "blob": "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMTFDMTIwNERFNUMiLCJtYW5pZmVzdCI6IkpBQUFBQUp4SWUwNHZVUmEvV0lWbGlETUdXd21hS0pyYjdzMnNKbnJWYk9LV01FY0VnVGVYSE1oQW9HTU5jc2dVVU53S28raDd6aGFYS0YrSEd3NlhoRWpvREtyYWxrWW5Naktka2N3UlFJaEFKN2NONEo2TmRWZnBudkVJL1pldVdDVHZucGFKaXJLTkZjQzN6TU9qZ3dqQWlBYktJMGZiWGdTMVJMbG9OaHhkSGhWcTlvekVXVkU5Y0l3WEROM0F4cXlZM0FTUUN0MCt1L2lOU0RENmJYdlVUdGRtdDROcnRsYng0Vnp1bVRwZmpSWXA0bE1vSS9oNDNwVVRqcDdWRm9YYm5LV2pWaHFOYUdtNTc3SzZKNjk3WFo3VFFFPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURCRUUzMEZBRTkyRUVFODhFMUM0OTgwRDA5RUNGREU5OUExMTZEMDc4RUMyMTg1N0RCMUI0N0I0MjY0MThFNDI4IiwibWFuaWZlc3QiOiJKQUFBQUFKeEllMis0dyt1a3U3b2poeEpnTkNlejk2Wm9SYlFlT3doaFgyeHRIdENaQmprS0hNaEE5U21IRHhPaUNNVFpsNW5SeHJwMnlqV1o1Z2p4MkRyb1VGclU0bnJFcVU3ZGtjd1JRSWhBTGRFRmVqWStwVW5nbGk3c1R2aWIwQm1ESFA3TjZpa1ZFQkk2SDdJd1UxekFpQmRzeW9TcVBjQzJOTXFnQW5IWEhHZGtBSXdCUUQxQVVnOVg4WkpMeWZjd0hBU1FDdDFiS1Z6T014UlFtUjN3Tks0ZEtkb2ZJR3J4RTlTanVMUjZQYThCNW4wOFNZSjhLNjJnZSs5YTZCdFphbEVtL0hPZGN6ME5BRk9jeWNyRi9DdFNBND0ifV19", "signature": "849F6B8DA6E11C213B561659C16F13D35385E8EA9E775483ADC84578F6D578943DE5EB681584B2C03EFFFDFD216F9E0B21576E482F941C7195893B72B5B1F70D", "version": 1 } } })json"; Json::Value xpop; Json::Reader reader; reader.parse(strJson, xpop); Json::FastWriter writer; // Import: unl blob was not valid json (after base64 decoding) { Json::Value tmpXpop = xpop; tmpXpop[jss::validation][jss::unl][jss::blob] = "YmFkSnNvbg=="; std::string strJson = writer.write(tmpXpop); Blob raw(strJson.begin(), strJson.end()); auto const xpop = syntaxCheckXPOP(raw, env.journal); BEAST_EXPECT(getVLInfo(*xpop, env.journal).has_value() == false); } // Import: failed to deserialize manifest { Json::Value tmpXpop = xpop; tmpXpop[jss::validation][jss::unl][jss::manifest] = "YmFkSnNvbg=="; std::string strJson = writer.write(tmpXpop); Blob raw(strJson.begin(), strJson.end()); auto const xpop = syntaxCheckXPOP(raw, env.journal); BEAST_EXPECT(getVLInfo(*xpop, env.journal).has_value() == false); } // Import: valid unl blob { Json::Value tmpXpop = xpop; std::string strJson = writer.write(tmpXpop); Blob raw(strJson.begin(), strJson.end()); auto const xpop = syntaxCheckXPOP(raw, env.journal); auto const [seq, masterKey] = *getVLInfo(*xpop, env.journal); BEAST_EXPECT(std::to_string(seq) == "2"); BEAST_EXPECT( strHex(masterKey) == "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1" "CDC1"); } } void testEnabled(FeatureBitset features) { testcase("enabled"); using namespace jtx; using namespace std::literals::chrono_literals; for (bool const withImport : {false, true}) { // If the Import amendment is not enabled, you should not be able // to import. auto const amend = withImport ? features : features - featureImport; Env env{*this, network::makeNetworkVLConfig(21337, keys), amend}; auto const feeDrops = env.current()->fees().base; // setup env auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); // burn 1000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(1'000'000'000), ter(tesSUCCESS)); env.close(); auto const txResult = withImport ? ter(tesSUCCESS) : ter(temDISABLED); // IMPORT - Account Set env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), fee(feeDrops * 10), txResult); env.close(); } } void testInvalidPreflight(FeatureBitset features) { testcase("import invalid preflight"); using namespace test::jtx; using namespace std::literals; //---------------------------------------------------------------------- // preflight // temDISABLED - disabled // !ctx.rules.enabled(featureImport) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys), features - featureImport}; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), ter(temDISABLED)); } // temDISABLED - disabled // !ctx.rules.enabled(featureHooksUpdate1) && // ctx.tx.isFieldPresent(sfIssuer) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys), features - featureHooksUpdate1}; auto const alice = Account("alice"); auto const issuer = Account("issuer"); env.fund(XRP(1000), alice, issuer); env.close(); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), import::issuer(issuer), ter(temDISABLED)); } // temMALFORMED - Import: xpop did not contain an 80% quorum for the txn // it purports to prove. for (bool const withXahauV1 : {true, false}) { auto const amend = withXahauV1 ? features : features - fixXahauV1; test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys), amend}; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value valData = tmpXpop[jss::validation][jss::data]; valData["n9MNStvsHZxrCYnShytCfKMCXBcq8wJjR6fLTS7L2Q8qoFVNioQ8"] = ""; valData["n9MTTavZe6EPqqyQ27pJbNWpfHw8ZNspVgznrwx5HWm7cdTjKQie"] = ""; if (withXahauV1) { valData ["n94J5LCRu9bBWrJiwRWujvuVECVPWbXFcQ2VN38qLD378F5pDSDM"] = ""; } tmpXpop[jss::validation][jss::data] = valData; auto const txResult = withXahauV1 ? ter(temMALFORMED) : ter(temMALFORMED); env(import::import(alice, tmpXpop), txResult); } test::jtx::Env env{*this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // burn 1000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(1'000'000'000), ter(tesSUCCESS)); env.close(); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); auto const dave = Account("dave"); env.fund(XRP(1000), alice, bob, carol, dave); env.close(); // temMALFORMED // Issuer cannot be the source account. { env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), import::issuer(alice), ter(temMALFORMED)); } // telINSUF_FEE_P - sfFee cannot be 0 { Json::Value tx = import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)); STAmount const& fee = XRP(0); tx[jss::Fee] = fee.getJson(JsonOptions::none); env(tx, ter(telINSUF_FEE_P)); } // temMALFORMED - blob was more than 512kib // DA: blob.resize(513 * 1024); fails with Boost // { // ripple::Blob blob; // blob.resize(513 * 1024); // Json::Value tx = import::import(alice, // import::loadXpop(ImportTCAccountSet::w_seed)); // tx[sfBlob.jsonName] = strHex(blob); env(tx, ter(temMALFORMED)); // } // temMALFORMED - sfAmount field must be in drops { Json::Value tx = import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)); STAmount const& amount = XRP(-1); tx[jss::Amount] = amount.getJson(JsonOptions::none); env(tx, ter(temMALFORMED)); } // temMALFORMED - !xpop | XPOP.validation is not a JSON object { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation] = {}; // one of many ways to throw error env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: validation.unl.public_key was not valid hex { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::public_key] = "not a hex"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: validation.unl.public_key was not a recognised // public key type { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::public_key] = "0084D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1" "CDC1"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // getInnerTxn - !xpop // DA: Duplicate - // getInnerTxn - failed to deserialize tx blob inside xpop (invalid hex) // DA: Duplicate - "XPOP.transaction.blob missing or wrong format" // getInnerTxn - failed to deserialize tx meta inside xpop (invalid hex) // DA: Duplicate - "XPOP.transaction.meta missing or wrong format" // getInnerTxn - failed to deserialize tx blob/meta inside xpop { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::blob] = "DEADBEEF"; tmpXpop[jss::transaction][jss::meta] = "DEADBEEF"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - !stpTrans // DA: Duplicate - getInnerTxn (Any Failure) // temMALFORMED - Import: attempted to import xpop containing an emitted // or pseudo txn. { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::blob] = "12000322000000002400000002201B00000069201D0000535968400000003B" "9ACA0073210388935426E0D08083314842EDFBB2D517BD47699F9A4527318A" "8E10468C97C0527446304402200E40CA821A7BFE347448FFA6540F67C7FFBF" "0287756D324DFBADCEDE2B23782C02207BE1B1294F1A1D5AC21990740B78F9" "C0693431237D6E07FE84228082986E50FF8114AE123A8556F3CF9115471137" "6AFB0F894F832B3DED202E000000013D00000000000000015B2200676F4B9B" "45C5ADE9DE3C8CD01200CB12DFF8C792220DB088FE615BE5C2905C207064D8" "1954F6A7225A8BAADF5A3042016BFB87355D1D0AFEDBAA8FB22F98355D745F" "398EEE9E6B294BBE6A5681A31A6107243D19384E277B5A7B1F23B8C83DE78A" "14AE123A8556F3CF91154711376AFB0F894F832B3DE1"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: inner txn lacked transaction result { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::meta] = "201C00000006F8E5110061250000005655463E39A6AFDDA77DBF3591BF3C2A" "4BE9BB8D9113BF6D0797EB403C3D0D894FEF5692FA6A9FC8EA6018D5D16532" "D7795C91BFB0831355BDFDA177E86C8BF997985FE624000000026240000000" "773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481" "14AE123A8556F3CF91154711376AFB0F894F832B3DE1E1F1"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: inner txn did not have a tesSUCCESS or tec // result { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::meta] = "201C00000006F8E5110061250000005655463E39A6AFDDA77DBF3591BF3C2A" "4BE9BB8D9113BF6D0797EB403C3D0D894FEF5692FA6A9FC8EA6018D5D16532" "D7795C91BFB0831355BDFDA177E86C8BF997985FE624000000026240000000" "773593F4E1E7220000000024000000032D0000000162400000003B9AC9F481" "14AE123A8556F3CF91154711376AFB0F894F832B3DE1E1F103103C"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: import and txn inside xpop must be signed by // the same account { Json::Value const tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); env(import::import(bob, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: attempted to import xpop containing a txn with // a sfNetworkID field. { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::blob] = "120003210000535922000000002400000002201B00000069201D0000535968" "400000003B9ACA0073210388935426E0D08083314842EDFBB2D517BD47699F" "9A4527318A8E10468C97C0527446304402200E40CA821A7BFE347448FFA654" "0F67C7FFBF0287756D324DFBADCEDE2B23782C02207BE1B1294F1A1D5AC219" "90740B78F9C0693431237D6E07FE84228082986E50FF8114AE123A8556F3CF" "91154711376AFB0F894F832B3D"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: OperationLimit missing from inner xpop txn. // outer txid: { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::blob] = "12000322000000002400000002201B0000006C68400000003B9ACA007321ED" "A8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C" "747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F" "232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C51" "77C519560F8114AE123A8556F3CF91154711376AFB0F894F832B3D"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: Wrong network ID for OperationLimit in inner // txn. outer txid: { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::blob] = "12000322000000002400000002201B0000006C201D0000535A68400000003B" "9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62" "ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593EC" "C21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF" "3EC206AD3C5177C519560F8114AE123A8556F3CF91154711376AFB0F894F83" "2B3D"; env(import::import(alice, tmpXpop), ter(telWRONG_NETWORK)); } // temMALFORMED - Import: inner txn must be an AccountSet, SetRegularKey // or SignerListSet transaction. { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::blob] = "12006322000000002400000002201B0000006C201D0000535968400000003B" "9ACA007321EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62" "ECAD0AE4A96C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593EC" "C21B3C79EF0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF" "3EC206AD3C5177C519560F8114AE123A8556F3CF91154711376AFB0F894F83" "2B3D"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: outer and inner txns were (multi) signed with // different keys. { auto const xpopJson = import::loadXpop(ImportTCSignersListSet::w_signers); env(import::import(alice, xpopJson), msig(bob, dave), fee((3 * feeDrops) * 10), ter(temMALFORMED)); env.close(); } // temMALFORMED - Import: outer and inner txns were (multi) signed with // different keys. - empty innerSigners { Json::Value xpopJson = import::loadXpop(ImportTCSignersListSet::w_signers); xpopJson[jss::transaction][jss::blob] = "12000C22000000002400000014201B0000002B201D00005359202300000002" "6840000000001E84B073008114AE123A8556F3CF91154711376AFB0F894F83" "2B3DF3F1F4EB1300018114AA266540F7DACC27E264B75ED0A5ED7330BFB614" "E1EB1300018114D91B8EE5C7ABF632469D4C0907C5E40C8B8F79B3E1F1"; env(import::import(alice, xpopJson), msig(bob, carol), fee((3 * feeDrops) * 10), ter(temMALFORMED)); env.close(); } // temMALFORMED - Import: outer or inner txn was missing signers. // different keys. { Json::Value xpopJson = import::loadXpop(ImportTCSignersListSet::w_signers); xpopJson[jss::transaction][jss::blob] = "12000C22000000002400000014201B0000002B201D00005359202300000002" "6840000000001E84B073008114AE123A8556F3CF91154711376AFB0F894F83" "2B3DF4EB1300018114AA266540F7DACC27E264B75ED0A5ED7330BFB614E1EB" "1300018114D91B8EE5C7ABF632469D4C0907C5E40C8B8F79B3E1F1"; env(import::import(alice, xpopJson), fee((3 * feeDrops) * 10), ter(temMALFORMED)); env.close(); } // temMALFORMED - Import: outer and inner txns were signed with // different keys. { auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_regular_key); env(import::import(alice, xpopJson), fee(feeDrops * 10), sig(carol), ter(temMALFORMED)); } // temMALFORMED - Import: inner txn signature verify failed { Json::Value xpopJson = import::loadXpop(ImportTCSignersListSet::w_signers); xpopJson[jss::transaction][jss::blob] = "12000C2200000008240000001A201B000003B9201D00005359202300000000" "6840000000001E84B073008114AE123A8556F3CF91154711376AFB0F894F83" "2B3DF3E0107321028949021029D5CC87E78BCF053AFEC0CAFD15108EC119EA" "AFEC466F5C095407BF74473045022100BE132424E6E6304574F4BB5F6E287A" "63429482CE7E0437B443FC1457F4A3830002204B909A44FF9DFFD99AF751B0" "40830E53830FE3CA591449600372BED85FDBC33C8114B389FBCED0AF9DCDFF" "62900BFAEFA3EB872D8A96E1E010732102691AC5AE1C4C333AE5DF8A93BDC4" "95F0EEBFC6DB0DA7EB6EF808F3AFC006E3FE74473045022100D235706A0AB2" "407EC5D62F9130E9A98A70D90CE0D69D749C37272DFC975BD79002207D8AED" "0BF31A5E3290920B72EAFE22AB6B09814466372E09B067779C4E103FBE8114" "F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B90FE1F1"; env(import::import(alice, xpopJson), msig(bob, carol), fee((3 * feeDrops) * 10), ter(temMALFORMED)); env.close(); } // temMALFORMED - Import: failed to deserialize manifest on txid { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::manifest] = "YmFkSnNvbg=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: manifest master key did not match top level // master key in unl section of xpop { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::manifest] = "JAAAAAFxIe2E1ANsZZGkvfnFTO+jm5lqXc5fhtEf2hh0SBzp1aHNwXMh7TN9+" "b62cZqTngaFYU5tbGpYHC8oYuI3G3vwj9OW2Z9gdkAnUjfY5zOEkhq31tU4338" "jcyUpVA5/VTsANFce7unDo+JeVoEhfuOb/Y8WA3Diu9XzuOD4U/" "ikfgf9SZOlOGcBcBJAw44PLjH+" "HUtEnwX45lIRmo0x5aINFMvZsBpE9QteSDBXKwYzLdnSW4e1bs21o+" "IILJIiIKU/+1Uxx0FRpQbMDA=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: manifest signature invalid { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::manifest] = "JAAAAAFxIe101ANsZZGkvfnFTO+jm5lqXc5fhtEf2hh0SBzp1aHNwXMh7TN9+" "b62cZqTngaFYU5tbGpYHC8oYuI3G3vwj9OW2Z9gdkA3UjfY5zOEkhq31tU4338" "jcyUpVA5/VTsANFce7unDo+JeVoEhfuOb/Y8WA3Diu9XzuOD4U/" "ikfgf9SZOlOGcBcBJAw34PLjH+" "HUtEnwX45lIRmo0x5aINFMvZsBpE9QteSDBXKwYzLdnSW4e1bs21o+" "IILJIiIKU/+1Uxx0FRpQbMDA=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob not signed correctly { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::signature] = "949F6B8DA6E11C213B561659C16F13D35385E8EA9E775483ADC84578F6D578" "943DE5EB681584B2C03EFFFDFD216F9E0B21576E482F941C7195893B72B5B1" "F70D"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob not signed correctly { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::signature] = "not a hex"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob was not valid json (after base64 // decoding) { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "YmFkSnNvbg=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob json (after base64 decoding) lacked // required field (sequence) and/or types { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJleHBpcmF0aW9uIjo3NDEzOTg0MDAsInZhbGlkYXRvcnMiOlt7InZhbGlkYX" "Rpb25fcHVibGljX2tleSI6IkVEMzhCRDQ0NUFGRDYyMTU5NjIwQ0MxOTZDMjY2" "OEEyNkI2RkJCMzZCMDk5RUI1NUIzOEE1OEMxMUMxMjA0REU1QyIsIm1hbmlmZX" "N0IjoiSkFBQUFBSnhJZTA0dlVSYS9XSVZsaURNR1d3bWFLSnJiN3Myc0puclZi" "T0tXTUVjRWdUZVhITWhBb0dNTmNzZ1VVTndLbytoN3poYVhLRitIR3c2WGhFam" "9ES3JhbGtZbk1qS2RrY3dSUUloQUo3Y040SjZOZFZmcG52RUkvWmV1V0NUdm5w" "YUppcktORmNDM3pNT2pnd2pBaUFiS0kwZmJYZ1MxUkxsb05oeGRIaFZxOW96RV" "dWRTljSXdYRE4zQXhxeVkzQVNRQ3QwK3UvaU5TREQ2Ylh2VVR0ZG10NE5ydGxi" "eDRWenVtVHBmalJZcDRsTW9JL2g0M3BVVGpwN1ZGb1hibktXalZocU5hR201Nz" "dLNko2OTdYWjdUUUU9In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFREJF" "RTMwRkFFOTJFRUU4OEUxQzQ5ODBEMDlFQ0ZERTk5QTExNkQwNzhFQzIxODU3RE" "IxQjQ3QjQyNjQxOEU0MjgiLCJtYW5pZmVzdCI6IkpBQUFBQUp4SWUwNHZVUmEv" "V0lWbGlETUdXd21hS0pyYjdzMnNKbnJWYk9LV01FY0VnVGVYSE1oQW9HTU5jc2" "dVVU53S28raDd6aGFYS0YrSEd3NlhoRWpvREtyYWxrWW5Naktka2N3UlFJaEFK" "N2NONEo2TmRWZnBudkVJL1pldVdDVHZucGFKaXJLTkZjQzN6TU9qZ3dqQWlBYk" "tJMGZiWGdTMVJMbG9OaHhkSGhWcTlvekVXVkU5Y0l3WEROM0F4cXlZM0FTUUN0" "MCt1L2lOU0RENmJYdlVUdGRtdDROcnRsYng0Vnp1bVRwZmpSWXA0bE1vSS9oND" "NwVVRqcDdWRm9YYm5LV2pWaHFOYUdtNTc3SzZKNjk3WFo3VFFFPSJ9XX0="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob json (after base64 decoding) wrong // required field (sequence) and/or types { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6IjIiLCJleHBpcmF0aW9uIjo3NDEzOTg0MDAsInZhbGlkYX" "RvcnMiOlt7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEMzhCRDQ0NUFGRDYy" "MTU5NjIwQ0MxOTZDMjY2OEEyNkI2RkJCMzZCMDk5RUI1NUIzOEE1OEMxMUMxMj" "A0REU1QyIsIm1hbmlmZXN0IjoiSkFBQUFBSnhJZTA0dlVSYS9XSVZsaURNR1d3" "bWFLSnJiN3Myc0puclZiT0tXTUVjRWdUZVhITWhBb0dNTmNzZ1VVTndLbytoN3" "poYVhLRitIR3c2WGhFam9ES3JhbGtZbk1qS2RrY3dSUUloQUo3Y040SjZOZFZm" "cG52RUkvWmV1V0NUdm5wYUppcktORmNDM3pNT2pnd2pBaUFiS0kwZmJYZ1MxUk" "xsb05oeGRIaFZxOW96RVdWRTljSXdYRE4zQXhxeVkzQVNRQ3QwK3UvaU5TREQ2" "Ylh2VVR0ZG10NE5ydGxieDRWenVtVHBmalJZcDRsTW9JL2g0M3BVVGpwN1ZGb1" "hibktXalZocU5hR201NzdLNko2OTdYWjdUUUU9In0seyJ2YWxpZGF0aW9uX3B1" "YmxpY19rZXkiOiJFREJFRTMwRkFFOTJFRUU4OEUxQzQ5ODBEMDlFQ0ZERTk5QT" "ExNkQwNzhFQzIxODU3REIxQjQ3QjQyNjQxOEU0MjgiLCJtYW5pZmVzdCI6IkpB" "QUFBQUp4SWUwNHZVUmEvV0lWbGlETUdXd21hS0pyYjdzMnNKbnJWYk9LV01FY0" "VnVGVYSE1oQW9HTU5jc2dVVU53S28raDd6aGFYS0YrSEd3NlhoRWpvREtyYWxr" "WW5Naktka2N3UlFJaEFKN2NONEo2TmRWZnBudkVJL1pldVdDVHZucGFKaXJLTk" "ZjQzN6TU9qZ3dqQWlBYktJMGZiWGdTMVJMbG9OaHhkSGhWcTlvekVXVkU5Y0l3" "WEROM0F4cXlZM0FTUUN0MCt1L2lOU0RENmJYdlVUdGRtdDROcnRsYng0Vnp1bV" "RwZmpSWXA0bE1vSS9oNDNwVVRqcDdWRm9YYm5LV2pWaHFOYUdtNTc3SzZKNjk3" "WFo3VFFFPSJ9XX0="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob json (after base64 decoding) // lacked required field (expiration) and/or types { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwidmFsaWRhdG9ycyI6W3sidmFsaWRhdGlvbl9wdWJsaW" "Nfa2V5IjoiRUQzOEJENDQ1QUZENjIxNTk2MjBDQzE5NkMyNjY4QTI2QjZGQkIz" "NkIwOTlFQjU1QjM4QTU4QzExQzEyMDRERTVDIiwibWFuaWZlc3QiOiJKQUFBQU" "FKeEllMDR2VVJhL1dJVmxpRE1HV3dtYUtKcmI3czJzSm5yVmJPS1dNRWNFZ1Rl" "WEhNaEFvR01OY3NnVVVOd0tvK2g3emhhWEtGK0hHdzZYaEVqb0RLcmFsa1luTW" "pLZGtjd1JRSWhBSjdjTjRKNk5kVmZwbnZFSS9aZXVXQ1R2bnBhSmlyS05GY0Mz" "ek1Pamd3akFpQWJLSTBmYlhnUzFSTGxvTmh4ZEhoVnE5b3pFV1ZFOWNJd1hETj" "NBeHF5WTNBU1FDdDArdS9pTlNERDZiWHZVVHRkbXQ0TnJ0bGJ4NFZ6dW1UcGZq" "UllwNGxNb0kvaDQzcFVUanA3VkZvWGJuS1dqVmhxTmFHbTU3N0s2SjY5N1haN1" "RRRT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEQkVFMzBGQUU5MkVF" "RTg4RTFDNDk4MEQwOUVDRkRFOTlBMTE2RDA3OEVDMjE4NTdEQjFCNDdCNDI2ND" "E4RTQyOCIsIm1hbmlmZXN0IjoiSkFBQUFBSnhJZTA0dlVSYS9XSVZsaURNR1d3" "bWFLSnJiN3Myc0puclZiT0tXTUVjRWdUZVhITWhBb0dNTmNzZ1VVTndLbytoN3" "poYVhLRitIR3c2WGhFam9ES3JhbGtZbk1qS2RrY3dSUUloQUo3Y040SjZOZFZm" "cG52RUkvWmV1V0NUdm5wYUppcktORmNDM3pNT2pnd2pBaUFiS0kwZmJYZ1MxUk" "xsb05oeGRIaFZxOW96RVdWRTljSXdYRE4zQXhxeVkzQVNRQ3QwK3UvaU5TREQ2" "Ylh2VVR0ZG10NE5ydGxieDRWenVtVHBmalJZcDRsTW9JL2g0M3BVVGpwN1ZGb1" "hibktXalZocU5hR201NzdLNko2OTdYWjdUUUU9In1dfQ=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob json (after base64 decoding) wrong // required field (expiration) and/or types { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6Ijc0MTM5ODQwMCIsInZhbGlkYX" "RvcnMiOlt7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEMzhCRDQ0NUFGRDYy" "MTU5NjIwQ0MxOTZDMjY2OEEyNkI2RkJCMzZCMDk5RUI1NUIzOEE1OEMxMUMxMj" "A0REU1QyIsIm1hbmlmZXN0IjoiSkFBQUFBSnhJZTA0dlVSYS9XSVZsaURNR1d3" "bWFLSnJiN3Myc0puclZiT0tXTUVjRWdUZVhITWhBb0dNTmNzZ1VVTndLbytoN3" "poYVhLRitIR3c2WGhFam9ES3JhbGtZbk1qS2RrY3dSUUloQUo3Y040SjZOZFZm" "cG52RUkvWmV1V0NUdm5wYUppcktORmNDM3pNT2pnd2pBaUFiS0kwZmJYZ1MxUk" "xsb05oeGRIaFZxOW96RVdWRTljSXdYRE4zQXhxeVkzQVNRQ3QwK3UvaU5TREQ2" "Ylh2VVR0ZG10NE5ydGxieDRWenVtVHBmalJZcDRsTW9JL2g0M3BVVGpwN1ZGb1" "hibktXalZocU5hR201NzdLNko2OTdYWjdUUUU9In0seyJ2YWxpZGF0aW9uX3B1" "YmxpY19rZXkiOiJFREJFRTMwRkFFOTJFRUU4OEUxQzQ5ODBEMDlFQ0ZERTk5QT" "ExNkQwNzhFQzIxODU3REIxQjQ3QjQyNjQxOEU0MjgiLCJtYW5pZmVzdCI6IkpB" "QUFBQUp4SWUwNHZVUmEvV0lWbGlETUdXd21hS0pyYjdzMnNKbnJWYk9LV01FY0" "VnVGVYSE1oQW9HTU5jc2dVVU53S28raDd6aGFYS0YrSEd3NlhoRWpvREtyYWxr" "WW5Naktka2N3UlFJaEFKN2NONEo2TmRWZnBudkVJL1pldVdDVHZucGFKaXJLTk" "ZjQzN6TU9qZ3dqQWlBYktJMGZiWGdTMVJMbG9OaHhkSGhWcTlvekVXVkU5Y0l3" "WEROM0F4cXlZM0FTUUN0MCt1L2lOU0RENmJYdlVUdGRtdDROcnRsYng0Vnp1bV" "RwZmpSWXA0bE1vSS9oNDNwVVRqcDdWRm9YYm5LV2pWaHFOYUdtNTc3SzZKNjk3" "WFo3VFFFPSJ9XX0="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob json (after base64 decoding) // lacked required field (effective) and/or types { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJlZmZlY3Rpdm" "UiOiI3NDEzOTg0MDAiLCJ2YWxpZGF0b3JzIjpbeyJ2YWxpZGF0aW9uX3B1Ymxp" "Y19rZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1OTYyMENDMTk2QzI2NjhBMjZCNkZCQj" "M2QjA5OUVCNTVCMzhBNThDMTFDMTIwNERFNUMiLCJtYW5pZmVzdCI6IkpBQUFB" "QUp4SWUwNHZVUmEvV0lWbGlETUdXd21hS0pyYjdzMnNKbnJWYk9LV01FY0VnVG" "VYSE1oQW9HTU5jc2dVVU53S28raDd6aGFYS0YrSEd3NlhoRWpvREtyYWxrWW5N" "aktka2N3UlFJaEFKN2NONEo2TmRWZnBudkVJL1pldVdDVHZucGFKaXJLTkZjQz" "N6TU9qZ3dqQWlBYktJMGZiWGdTMVJMbG9OaHhkSGhWcTlvekVXVkU5Y0l3WERO" "M0F4cXlZM0FTUUN0MCt1L2lOU0RENmJYdlVUdGRtdDROcnRsYng0Vnp1bVRwZm" "pSWXA0bE1vSS9oNDNwVVRqcDdWRm9YYm5LV2pWaHFOYUdtNTc3SzZKNjk3WFo3" "VFFFPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURCRUUzMEZBRTkyRU" "VFODhFMUM0OTgwRDA5RUNGREU5OUExMTZEMDc4RUMyMTg1N0RCMUI0N0I0MjY0" "MThFNDI4IiwibWFuaWZlc3QiOiJKQUFBQUFKeEllMDR2VVJhL1dJVmxpRE1HV3" "dtYUtKcmI3czJzSm5yVmJPS1dNRWNFZ1RlWEhNaEFvR01OY3NnVVVOd0tvK2g3" "emhhWEtGK0hHdzZYaEVqb0RLcmFsa1luTWpLZGtjd1JRSWhBSjdjTjRKNk5kVm" "ZwbnZFSS9aZXVXQ1R2bnBhSmlyS05GY0Mzek1Pamd3akFpQWJLSTBmYlhnUzFS" "TGxvTmh4ZEhoVnE5b3pFV1ZFOWNJd1hETjNBeHF5WTNBU1FDdDArdS9pTlNERD" "ZiWHZVVHRkbXQ0TnJ0bGJ4NFZ6dW1UcGZqUllwNGxNb0kvaDQzcFVUanA3VkZv" "WGJuS1dqVmhxTmFHbTU3N0s2SjY5N1haN1RRRT0ifV19"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob json (after base64 decoding) // lacked required field (validators) and/or types { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwfQ=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob json (after base64 decoding) wrong // required field (validators) and/or types { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3" "JzIjoid3JvbmcifQ=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob validUntil <= validFrom { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MSwiZWZmZWN0aXZlIjowLCJleHBpcmF0aW9uIjowLCJ2YW" "xpZGF0b3JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVB" "RkQ2MjE1OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMT" "FDMTIwNERFNUMiLCJtYW5pZmVzdCI6IkpBQUFBQUp4SWUwNHZVUmEvV0lWbGlE" "TUdXd21hS0pyYjdzMnNKbnJWYk9LV01FY0VnVGVYSE1oQW9HTU5jc2dVVU53S2" "8raDd6aGFYS0YrSEd3NlhoRWpvREtyYWxrWW5Naktka2N3UlFJaEFKN2NONEo2" "TmRWZnBudkVJL1pldVdDVHZucGFKaXJLTkZjQzN6TU9qZ3dqQWlBYktJMGZiWG" "dTMVJMbG9OaHhkSGhWcTlvekVXVkU5Y0l3WEROM0F4cXlZM0FTUUN0MCt1L2lO" "U0RENmJYdlVUdGRtdDROcnRsYng0Vnp1bVRwZmpSWXA0bE1vSS9oNDNwVVRqcD" "dWRm9YYm5LV2pWaHFOYUdtNTc3SzZKNjk3WFo3VFFFPSJ9LHsidmFsaWRhdGlv" "bl9wdWJsaWNfa2V5IjoiRURCRUUzMEZBRTkyRUVFODhFMUM0OTgwRDA5RUNGRE" "U5OUExMTZEMDc4RUMyMTg1N0RCMUI0N0I0MjY0MThFNDI4IiwibWFuaWZlc3Qi" "OiJKQUFBQUFKeEllMis0dyt1a3U3b2poeEpnTkNlejk2Wm9SYlFlT3doaFgyeH" "RIdENaQmprS0hNaEE5U21IRHhPaUNNVFpsNW5SeHJwMnlqV1o1Z2p4MkRyb1VG" "clU0bnJFcVU3ZGtjd1JRSWhBTGRFRmVqWStwVW5nbGk3c1R2aWIwQm1ESFA3Tj" "Zpa1ZFQkk2SDdJd1UxekFpQmRzeW9TcVBjQzJOTXFnQW5IWEhHZGtBSXdCUUQx" "QVVnOVg4WkpMeWZjd0hBU1FDdDFiS1Z6T014UlFtUjN3Tks0ZEtkb2ZJR3J4RT" "lTanVMUjZQYThCNW4wOFNZSjhLNjJnZSs5YTZCdFphbEVtL0hPZGN6ME5BRk9j" "eWNyRi9DdFNBND0ifV19"; tmpXpop[jss::validation][jss::unl][jss::signature] = "2B3C0ECB63C82454522188337354C480693A9BCD64E776B4DBAD4C61B9E72D" "D4CC1DC237B06891E57C623C38506FE8E01B1914C9413471BCC160111E2829" "7606"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob expired { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MSwiZWZmZWN0aXZlIjowLCJleHBpcmF0aW9uIjoxLCJ2YW" "xpZGF0b3JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVB" "RkQ2MjE1OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMT" "FDMTIwNERFNUMiLCJtYW5pZmVzdCI6IkpBQUFBQUp4SWUwNHZVUmEvV0lWbGlE" "TUdXd21hS0pyYjdzMnNKbnJWYk9LV01FY0VnVGVYSE1oQW9HTU5jc2dVVU53S2" "8raDd6aGFYS0YrSEd3NlhoRWpvREtyYWxrWW5Naktka2N3UlFJaEFKN2NONEo2" "TmRWZnBudkVJL1pldVdDVHZucGFKaXJLTkZjQzN6TU9qZ3dqQWlBYktJMGZiWG" "dTMVJMbG9OaHhkSGhWcTlvekVXVkU5Y0l3WEROM0F4cXlZM0FTUUN0MCt1L2lO" "U0RENmJYdlVUdGRtdDROcnRsYng0Vnp1bVRwZmpSWXA0bE1vSS9oNDNwVVRqcD" "dWRm9YYm5LV2pWaHFOYUdtNTc3SzZKNjk3WFo3VFFFPSJ9LHsidmFsaWRhdGlv" "bl9wdWJsaWNfa2V5IjoiRURCRUUzMEZBRTkyRUVFODhFMUM0OTgwRDA5RUNGRE" "U5OUExMTZEMDc4RUMyMTg1N0RCMUI0N0I0MjY0MThFNDI4IiwibWFuaWZlc3Qi" "OiJKQUFBQUFKeEllMis0dyt1a3U3b2poeEpnTkNlejk2Wm9SYlFlT3doaFgyeH" "RIdENaQmprS0hNaEE5U21IRHhPaUNNVFpsNW5SeHJwMnlqV1o1Z2p4MkRyb1VG" "clU0bnJFcVU3ZGtjd1JRSWhBTGRFRmVqWStwVW5nbGk3c1R2aWIwQm1ESFA3Tj" "Zpa1ZFQkk2SDdJd1UxekFpQmRzeW9TcVBjQzJOTXFnQW5IWEhHZGtBSXdCUUQx" "QVVnOVg4WkpMeWZjd0hBU1FDdDFiS1Z6T014UlFtUjN3Tks0ZEtkb2ZJR3J4RT" "lTanVMUjZQYThCNW4wOFNZSjhLNjJnZSs5YTZCdFphbEVtL0hPZGN6ME5BRk9j" "eWNyRi9DdFNBND0ifV19"; tmpXpop[jss::validation][jss::unl][jss::signature] = "FA82662A23EC78E9644C65F752B7A58F61F35AC36C260F9E9D5CAC7D53D16D" "5D615A02A6462F2618C162D089AD2E3BA7D656728392180517A81B4C47F86A" "640D"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob not yet valid { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MSwiZWZmZWN0aXZlIjozNjAwLCJleHBpcmF0aW9uIjo4Nj" "QwMCwidmFsaWRhdG9ycyI6W3sidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRUQz" "OEJENDQ1QUZENjIxNTk2MjBDQzE5NkMyNjY4QTI2QjZGQkIzNkIwOTlFQjU1Qj" "M4QTU4QzExQzEyMDRERTVDIiwibWFuaWZlc3QiOiJKQUFBQUFKeEllMDR2VVJh" "L1dJVmxpRE1HV3dtYUtKcmI3czJzSm5yVmJPS1dNRWNFZ1RlWEhNaEFvR01OY3" "NnVVVOd0tvK2g3emhhWEtGK0hHdzZYaEVqb0RLcmFsa1luTWpLZGtjd1JRSWhB" "SjdjTjRKNk5kVmZwbnZFSS9aZXVXQ1R2bnBhSmlyS05GY0Mzek1Pamd3akFpQW" "JLSTBmYlhnUzFSTGxvTmh4ZEhoVnE5b3pFV1ZFOWNJd1hETjNBeHF5WTNBU1FD" "dDArdS9pTlNERDZiWHZVVHRkbXQ0TnJ0bGJ4NFZ6dW1UcGZqUllwNGxNb0kvaD" "QzcFVUanA3VkZvWGJuS1dqVmhxTmFHbTU3N0s2SjY5N1haN1RRRT0ifSx7InZh" "bGlkYXRpb25fcHVibGljX2tleSI6IkVEQkVFMzBGQUU5MkVFRTg4RTFDNDk4ME" "QwOUVDRkRFOTlBMTE2RDA3OEVDMjE4NTdEQjFCNDdCNDI2NDE4RTQyOCIsIm1h" "bmlmZXN0IjoiSkFBQUFBSnhJZTIrNHcrdWt1N29qaHhKZ05DZXo5NlpvUmJRZU" "93aGhYMnh0SHRDWkJqa0tITWhBOVNtSER4T2lDTVRabDVuUnhycDJ5aldaNWdq" "eDJEcm9VRnJVNG5yRXFVN2RrY3dSUUloQUxkRUZlalkrcFVuZ2xpN3NUdmliME" "JtREhQN042aWtWRUJJNkg3SXdVMXpBaUJkc3lvU3FQY0MyTk1xZ0FuSFhIR2Rr" "QUl3QlFEMUFVZzlYOFpKTHlmY3dIQVNRQ3QxYktWek9NeFJRbVIzd05LNGRLZG" "9mSUdyeEU5U2p1TFI2UGE4QjVuMDhTWUo4SzYyZ2UrOWE2QnRaYWxFbS9IT2Rj" "ejBOQUZPY3ljckYvQ3RTQTQ9In1dfQ"; tmpXpop[jss::validation][jss::unl][jss::signature] = "9CCA07A3EDD1334D5ADCB3730D8F3F9BD1E0C338100384C7B15B6A910F96BE" "4F46E3052B37E9FE2E7DC9918BD85B9E871923AE1BDD7144EE2A92F625064C" "570C"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: depth > 32 // DA: Impossible test // temMALFORMED - Import: !proof->isObject() && !proof->isArray() { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::proof] = "not object"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: return false // temMALFORMED - Import : xpop proof did not contain the specified txn // hash { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::proof][jss::children]["D"] [jss::children]["7"][jss::hash] = "12D47E7D543E15F1EDBA91CDF335722727851BDDA8C2FF8924772AD" "C6B522A29"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: depth > 32 // DA: Impossible test // temMALFORMED - Import: !proof.isObject() && !proof.isArray() { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::proof] = "not a object"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: computed txroot does not match xpop txroot, // invalid xpop. { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::proof][jss::children]["3"] [jss::hash] = "22D47E7D543E15F1EDBA91CDF335722727851BDDA8C2FF8924772AD" "C6B522A29"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: error parsing coins | phash | acroot in the // ledger section of XPOP. // DA: Duplicate - syntaxCheckXPOP // temMALFORMED - Import: unl blob contained invalid validator entry, // skipping - not object { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3" "JzIjpbIndyb25nIiwid3JvbmciXX0="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob contained invalid validator entry, // skipping - no manifest { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3" "JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1" "OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMTFDMTIwNE" "RFNUMifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEQkVFMzBGQUU5MkVF" "RTg4RTFDNDk4MEQwOUVDRkRFOTlBMTE2RDA3OEVDMjE4NTdEQjFCNDdCNDI2ND" "E4RTQyOCJ9XX0="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob contained invalid validator entry, // skipping - wrong type validation_public_key { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3" "JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOjEsIm1hbmlmZXN0IjoiSkFB" "QUFBSnhJZTA0dlVSYS9XSVZsaURNR1d3bWFLSnJiN3Myc0puclZiT0tXTUVjRW" "dUZVhITWhBb0dNTmNzZ1VVTndLbytoN3poYVhLRitIR3c2WGhFam9ES3JhbGtZ" "bk1qS2RrY3dSUUloQUo3Y040SjZOZFZmcG52RUkvWmV1V0NUdm5wYUppcktORm" "NDM3pNT2pnd2pBaUFiS0kwZmJYZ1MxUkxsb05oeGRIaFZxOW96RVdWRTljSXdY" "RE4zQXhxeVkzQVNRQ3QwK3UvaU5TREQ2Ylh2VVR0ZG10NE5ydGxieDRWenVtVH" "BmalJZcDRsTW9JL2g0M3BVVGpwN1ZGb1hibktXalZocU5hR201NzdLNko2OTdY" "WjdUUUU9In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOjEsIm1hbmlmZXN0Ij" "oiSkFBQUFBSnhJZTIrNHcrdWt1N29qaHhKZ05DZXo5NlpvUmJRZU93aGhYMnh0" "SHRDWkJqa0tITWhBOVNtSER4T2lDTVRabDVuUnhycDJ5aldaNWdqeDJEcm9VRn" "JVNG5yRXFVN2RrY3dSUUloQUxkRUZlalkrcFVuZ2xpN3NUdmliMEJtREhQN042" "aWtWRUJJNkg3SXdVMXpBaUJkc3lvU3FQY0MyTk1xZ0FuSFhIR2RrQUl3QlFEMU" "FVZzlYOFpKTHlmY3dIQVNRQ3QxYktWek9NeFJRbVIzd05LNGRLZG9mSUdyeEU5" "U2p1TFI2UGE4QjVuMDhTWUo4SzYyZ2UrOWE2QnRaYWxFbS9IT2RjejBOQUZPY3" "ljckYvQ3RTQTQ9In1dfQ=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob contained invalid validator entry, // skipping - wrong type { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3" "JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1" "OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMTFDMTIwNE" "RFNUMiLCJtYW5pZmVzdCI6MX0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJF" "REJFRTMwRkFFOTJFRUU4OEUxQzQ5ODBEMDlFQ0ZERTk5QTExNkQwNzhFQzIxOD" "U3REIxQjQ3QjQyNjQxOEU0MjgiLCJtYW5pZmVzdCI6MX1dfQ=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob contained an invalid validator key, // skipping - invalid format { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3" "JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRCIsIm1hbmlmZXN0Ijoi" "SkFBQUFBSnhJZTA0dlVSYS9XSVZsaURNR1d3bWFLSnJiN3Myc0puclZiT0tXTU" "VjRWdUZVhITWhBb0dNTmNzZ1VVTndLbytoN3poYVhLRitIR3c2WGhFam9ES3Jh" "bGtZbk1qS2RrY3dSUUloQUo3Y040SjZOZFZmcG52RUkvWmV1V0NUdm5wYUppck" "tORmNDM3pNT2pnd2pBaUFiS0kwZmJYZ1MxUkxsb05oeGRIaFZxOW96RVdWRTlj" "SXdYRE4zQXhxeVkzQVNRQ3QwK3UvaU5TREQ2Ylh2VVR0ZG10NE5ydGxieDRWen" "VtVHBmalJZcDRsTW9JL2g0M3BVVGpwN1ZGb1hibktXalZocU5hR201NzdLNko2" "OTdYWjdUUUU9In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRCIsIm1hbm" "lmZXN0IjoiSkFBQUFBSnhJZTIrNHcrdWt1N29qaHhKZ05DZXo5NlpvUmJRZU93" "aGhYMnh0SHRDWkJqa0tITWhBOVNtSER4T2lDTVRabDVuUnhycDJ5aldaNWdqeD" "JEcm9VRnJVNG5yRXFVN2RrY3dSUUloQUxkRUZlalkrcFVuZ2xpN3NUdmliMEJt" "REhQN042aWtWRUJJNkg3SXdVMXpBaUJkc3lvU3FQY0MyTk1xZ0FuSFhIR2RrQU" "l3QlFEMUFVZzlYOFpKTHlmY3dIQVNRQ3QxYktWek9NeFJRbVIzd05LNGRLZG9m" "SUdyeEU5U2p1TFI2UGE4QjVuMDhTWUo4SzYyZ2UrOWE2QnRaYWxFbS9IT2Rjej" "BOQUZPY3ljckYvQ3RTQTQ9In1dfQ=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob contained an invalid validator key, // skipping - missing { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3" "JzIjpbeyJtYW5pZmVzdCI6IkpBQUFBQUp4SWUwNHZVUmEvV0lWbGlETUdXd21h" "S0pyYjdzMnNKbnJWYk9LV01FY0VnVGVYSE1oQW9HTU5jc2dVVU53S28raDd6aG" "FYS0YrSEd3NlhoRWpvREtyYWxrWW5Naktka2N3UlFJaEFKN2NONEo2TmRWZnBu" "dkVJL1pldVdDVHZucGFKaXJLTkZjQzN6TU9qZ3dqQWlBYktJMGZiWGdTMVJMbG" "9OaHhkSGhWcTlvekVXVkU5Y0l3WEROM0F4cXlZM0FTUUN0MCt1L2lOU0RENmJY" "dlVUdGRtdDROcnRsYng0Vnp1bVRwZmpSWXA0bE1vSS9oNDNwVVRqcDdWRm9YYm" "5LV2pWaHFOYUdtNTc3SzZKNjk3WFo3VFFFPSJ9LHsibWFuaWZlc3QiOiJKQUFB" "QUFKeEllMis0dyt1a3U3b2poeEpnTkNlejk2Wm9SYlFlT3doaFgyeHRIdENaQm" "prS0hNaEE5U21IRHhPaUNNVFpsNW5SeHJwMnlqV1o1Z2p4MkRyb1VGclU0bnJF" "cVU3ZGtjd1JRSWhBTGRFRmVqWStwVW5nbGk3c1R2aWIwQm1ESFA3TjZpa1ZFQk" "k2SDdJd1UxekFpQmRzeW9TcVBjQzJOTXFnQW5IWEhHZGtBSXdCUUQxQVVnOVg4" "WkpMeWZjd0hBU1FDdDFiS1Z6T014UlFtUjN3Tks0ZEtkb2ZJR3J4RTlTanVMUj" "ZQYThCNW4wOFNZSjhLNjJnZSs5YTZCdFphbEVtL0hPZGN6ME5BRk9jeWNyRi9D" "dFNBND0ifV19"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob contained an invalid manifest, // skipping { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3" "JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1" "OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMTFDMTIwNE" "RFNUMiLCJtYW5pZmVzdCI6Indyb25nIn0seyJ2YWxpZGF0aW9uX3B1YmxpY19r" "ZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2Qj" "A5OUVCNTVCMzhBNThDMTFDMTIwNERFNUMiLCJtYW5pZmVzdCI6Indyb25nIn1d" "fQ=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob list entry manifest master key did // not match master key, skipping { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3" "JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1" "OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMTFDMTIwNE" "RFNUMiLCJtYW5pZmVzdCI6IkpBQUFBQUp4SWUyKzR3K3VrdTdvamh4SmdOQ2V6" "OTZab1JiUWVPd2hoWDJ4dEh0Q1pCamtLSE1oQTlTbUhEeE9pQ01UWmw1blJ4cn" "AyeWpXWjVnangyRHJvVUZyVTRuckVxVTdka2N3UlFJaEFMZEVGZWpZK3BVbmds" "aTdzVHZpYjBCbURIUDdONmlrVkVCSTZIN0l3VTF6QWlCZHN5b1NxUGNDMk5NcW" "dBbkhYSEdka0FJd0JRRDFBVWc5WDhaSkx5ZmN3SEFTUUN0MWJLVnpPTXhSUW1S" "M3dOSzRkS2RvZklHcnhFOVNqdUxSNlBhOEI1bjA4U1lKOEs2MmdlKzlhNkJ0Wm" "FsRW0vSE9kY3owTkFGT2N5Y3JGL0N0U0E0PSJ9LHsidmFsaWRhdGlvbl9wdWJs" "aWNfa2V5IjoiRURBRUUzMEZBRTkyRUVFODhFMUM0OTgwRDA5RUNGREU5OUExMT" "ZEMDc4RUMyMTg1N0RCMUI0N0I0MjY0MThFNDI4IiwibWFuaWZlc3QiOiJKQUFB" "QUFKeEllMis0dyt1a3U3b2poeEpnTkNlejk2Wm9SYlFlT3doaFgyeHRIdENaQm" "prS0hNaEE5U21IRHhPaUNNVFpsNW5SeHJwMnlqV1o1Z2p4MkRyb1VGclU0bnJF" "cVU3ZGtjd1JRSWhBTGRFRmVqWStwVW5nbGk3c1R2aWIwQm1ESFA3TjZpa1ZFQk" "k2SDdJd1UxekFpQmRzeW9TcVBjQzJOTXFnQW5IWEhHZGtBSXdCUUQxQVVnOVg4" "WkpMeWZjd0hBU1FDdDFiS1Z6T014UlFtUjN3Tks0ZEtkb2ZJR3J4RTlTanVMUj" "ZQYThCNW4wOFNZSjhLNjJnZSs5YTZCdFphbEVtL0hPZGN6ME5BRk9jeWNyRi9D" "dFNBND0ifV19"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: unl blob list entry manifest signature // invalid, skipping { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "eyJzZXF1ZW5jZSI6MiwiZXhwaXJhdGlvbiI6NzQxMzk4NDAwLCJ2YWxpZGF0b3" "JzIjpbeyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDM4QkQ0NDVBRkQ2MjE1" "OTYyMENDMTk2QzI2NjhBMjZCNkZCQjM2QjA5OUVCNTVCMzhBNThDMTFDMTIwNE" "RFNUMiLCJtYW5pZmVzdCI6IkpBQUFBQVZ4SWUwNHZVUmEvV0lWbGlETUdXd21h" "S0pyYjdzMnNKbnJWYk9LV01FY0VnVGVYSE1oQW9HTU5jc2dVVU53S28raDd6aG" "FYS0YrSEd3NlhoRWpvREtyYWxrWW5Naktka2N3UlFJaEFKN2NONEo2TmRWZnBu" "dkVJL1pldVdDVHZucGFKaXJLTkZjQzN6TU9qZ3dqQWlBYktJMGZiWGdTMVJMbG" "9OaHhkSGhWcTlvekVXVkU5Y0l3WEROM0F4cXlZM0FTUUN0MCt1L2lOU0RENmJY" "dlVUdGRtdDROcnRsYng0Vnp1bVRwZmpSWXA0bE1vSS9oNDNwVVRqcDdWRm9YYm" "5LV2pWaHFOYUdtNTc3SzZKNjk3WFo3VFFFPSJ9LHsidmFsaWRhdGlvbl9wdWJs" "aWNfa2V5IjoiRURCRUUzMEZBRTkyRUVFODhFMUM0OTgwRDA5RUNGREU5OUExMT" "ZEMDc4RUMyMTg1N0RCMUI0N0I0MjY0MThFNDI4IiwibWFuaWZlc3QiOiJKQUFB" "QUFKeEllMis0dyt1a3U3b2poeEpnTkNlejk2Wm9SYlFlT3doaFgyeHRIdENaQm" "prS0hNaEE5U21IRHhPaUNNVFpsNW5SeHJwMnlqV1o1Z2p4MkRyb1VGclU0bnJF" "cVU3ZGtjd1JRSWhBTGRFRmVqWStwVW5nbGk3c1R2aWIwQm1ESFA3TjZpa1ZFQk" "k2SDdJd1UxekFpQmRzeW9TcVBjQzJOTXFnQW5IWEhHZGtBSXdCUUQxQVVnOVg4" "WkpMeWZjd0hBU1FDdDFiS1Z6T014UlFtUjN3Tks0ZEtkb2ZJR3J4RTlTanVMUj" "ZQYThCNW4wOFNZSjhLNjJnZSs5YTZCdFphbEVtL0hPZGN6ME5BRk9jeWNyRi9D" "dFNBND0ifV19"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: validator nodepub did not appear in // validator list but did appear in data section { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value valData; valData["n84QWAYxKUHacmyFTnzK4bvqVcUfr6RwtaNxCM2cJRY59UHmz1Fr"] = "22800000012600000015292C4C84F53A29EC0A36EDAB6C61510AD4F33846A1" "23D86FDAD30CBF175E217BA7B5394A5A761DA5C6B7A45D678DA85017208060" "24F4F741C65B2E44B005CA293120889A6BC5F1E179335E20384AB3C6D15019" "B94C4657B7529C72DDCE970A87E2EB9EE8EE12580ADFE6CF93B8672E4B289B" "BC732103FCA947A7F08B146457BEF95AF0CF7C3ABF0D09CD1DC02099F7185C" "37BB32807576473045022100BBBE6EDE0B2B61CD369E2188C8FBFACCB35CA2" "D166FD29D5E3D7B2195083E74302201FAA160136301A43E518B9424A0DA5DC" "1E7EF8B90DAE2FA87310047498514EB4"; tmpXpop[jss::validation][jss::data] = valData; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: validator nodepub key appears more than // once in data section // DA: Impossible - Cannot serialize duplicate json fields // temMALFORMED - Import: validation inside xpop was not valid hex { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value valData; valData["n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN"] = "not a hex"; tmpXpop[jss::validation][jss::data] = valData; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: validation message was not for computed ledger // hash { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value valData; valData["n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN"] = "22800000012600000056292C0D012051A0829745427488A59B6525231634DC" "327F91589EB03F469ABF1C3CA32070625A501790AD68E9045001FDEED03F0A" "C8277F11F6E46E0ABD2DC38B1F8240D56B22E4F2732103D4A61C3C4E882313" "665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76463044022072" "427336342AE80B7AAE407CEA611B0DA680426B3C5894E52EE2D23641D09A73" "02203B131B68D3C5B6C5482312CC7D90D2CE131A9C46458967F2F98688B726" "C16719"; tmpXpop[jss::validation][jss::data] = valData; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: validation inside xpop was not signed with a // signing key we recognise { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value valData; valData["n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN"] = "22800000012600000056292C0D012051B0829745427488A59B6525231634DC" "327F91589EB03F469ABF1C3CA32070625A501790BD68E9045001FDEED03F0A" "C8277F11F6E46E0ABD2DC38B1F8240D56B22E4F2732103E4A61C3C4E882313" "665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76463054022072" "427336342AE80B7AAE407CEA611B0DA680426B3C5894E52EE2D23641D09A73" "02203B131B68D3C5B6C5482312CC7D90D2CE131A9C46458967F2F98688B726" "C16719"; tmpXpop[jss::validation][jss::data] = valData; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: validation inside xpop was not correctly // signed { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value valData; valData["n94at1vSdHSBEun25yT4ZfgqD1tVQNsx1nqRZG3T6ygbuvwgcMZN"] = "22800000012600000056292C0D012051B0829745427488A59B6525231634DC" "327F91589EB03F469ABF1C3CA32070625A501790BD68E9045001FDEED03F0A" "C8277F11F6E46E0ABD2DC38B1F8240D56B22E4F2732103D4A61C3C4E882313" "665E67471AE9DB28D6679823C760EBA1416B5389EB12A53B76463044022072" "427336342AE80B7AAE407CEA611B0DA680426B3C5894E52EE2D23641D09A73" "02203B131B68D3C5B6C5482312CC7D90D2CE131A9C46458967F2F98688B726" "C16719"; tmpXpop[jss::validation][jss::data] = valData; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // temMALFORMED - Import: validation inside xpop was not able to be // parsed // DA: Catch All // temMALFORMED - Import: xpop inner txn did not contain a sequence // number or fee No Sequence { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::blob] = "1200632200000000201B0000006C201D0000535968400000003B9ACA007321" "EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A9" "6C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF" "0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C" "5177C519560F8114AE123A8556F3CF91154711376AFB0F894F832B3D"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // No Fee { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::blob] = "12006322000000002400000002201B0000006C201D000053597321EDA8D46E" "11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A96C747440" "549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF0F232EB4" "375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C5177C519" "560F8114AE123A8556F3CF91154711376AFB0F894F832B3D"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // Bad Fee // DA: Impossible - Cannot serialize negative number } void testInvalidPreclaim(FeatureBitset features) { testcase("import invalid preclaim"); using namespace test::jtx; using namespace std::literals; // ---------------------------------------------------------------------- // preclaim // temDISABLED { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys), features - featureImport}; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), ter(temDISABLED)); } // tefINTERNAL // during preclaim could not parse xpop, bailing. { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation] = {}; // DA: Sanity Check - tefINTERNAL(preclaim) env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // tefINTERNAL // during preclaim could not find importSequence, bailing. { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::blob] = "1200632200000000201B0000006C201D0000535968400000003B9ACA007321" "EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A9" "6C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF" "0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C" "5177C519560F8114AE123A8556F3CF91154711376AFB0F894F832B3D"; // DA: Sanity Check - tefINTERNAL(preclaim) env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // tefIMPORT_BLACKHOLED - SetRegularKey (w/seed) AccountZero { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); // Set Regular Key Json::Value jv; jv[jss::Account] = alice.human(); const AccountID ACCOUNT_ZERO(0); jv["RegularKey"] = to_string(ACCOUNT_ZERO); jv[jss::TransactionType] = jss::SetRegularKey; env(jv, alice); // Disable Master Key env(fset(alice, asfDisableMaster), sig(alice)); env.close(); // Import with Master Key Json::Value tmpXpop = import::loadXpop(ImportTCSetRegularKey::w_seed); env(import::import(alice, tmpXpop), ter(tefIMPORT_BLACKHOLED), fee(feeDrops * 10), sig(alice)); env.close(); } // tefIMPORT_BLACKHOLED - SetRegularKey (w/seed) AccountOne { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); // Set Regular Key Json::Value jv; jv[jss::Account] = alice.human(); const AccountID ACCOUNT_ONE(1); jv["RegularKey"] = to_string(ACCOUNT_ONE); jv[jss::TransactionType] = jss::SetRegularKey; env(jv, alice); // Disable Master Key env(fset(alice, asfDisableMaster), sig(alice)); env.close(); // Import with Master Key Json::Value tmpXpop = import::loadXpop(ImportTCSetRegularKey::w_seed); env(import::import(alice, tmpXpop), ter(tefIMPORT_BLACKHOLED), fee(feeDrops * 10), sig(alice)); env.close(); } // tefIMPORT_BLACKHOLED - SetRegularKey (w/seed) AccountTwo { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); // Set Regular Key Json::Value jv; jv[jss::Account] = alice.human(); const AccountID ACCOUNT_TWO(2); jv["RegularKey"] = to_string(ACCOUNT_TWO); jv[jss::TransactionType] = jss::SetRegularKey; env(jv, alice); // Disable Master Key env(fset(alice, asfDisableMaster), sig(alice)); env.close(); // Import with Master Key Json::Value tmpXpop = import::loadXpop(ImportTCSetRegularKey::w_seed); env(import::import(alice, tmpXpop), ter(tefIMPORT_BLACKHOLED), fee(feeDrops * 10), sig(alice)); env.close(); } // tefIMPORT_BLACKHOLED - SignersListSet (w/seed) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); // Set Regular Key Json::Value jv; jv[jss::Account] = alice.human(); const AccountID ACCOUNT_ZERO(0); jv["RegularKey"] = to_string(ACCOUNT_ZERO); jv[jss::TransactionType] = jss::SetRegularKey; env(jv, alice); // Disable Master Key env(fset(alice, asfDisableMaster), sig(alice)); env.close(); // Import with Master Key Json::Value tmpXpop = import::loadXpop(ImportTCSignersListSet::w_seed); env(import::import(alice, tmpXpop), ter(tefIMPORT_BLACKHOLED), fee(feeDrops * 10), sig(alice)); env.close(); } // tefPAST_IMPORT_SEQ { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), fee(feeDrops * 10), ter(tesSUCCESS)); env(import::import( alice, import::loadXpop(ImportTCAccountSet::min)), fee(feeDrops * 10), ter(tefPAST_IMPORT_SEQ)); } // temBAD_FEE { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const alice = Account("alice"); env.memoize(alice); Json::Value tx = import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)); tx[jss::Sequence] = 0; tx[jss::Fee] = 10; env(tx, ter(temBAD_FEE)); } // tefINTERNAL // during preclaim could not parse vlInfo, bailing. { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "YmFkSnNvbg=="; // DA: Sanity Check - tefINTERNAL(preclaim) env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // tefPAST_IMPORT_VL_SEQ // import vl sequence already used, bailing. { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; std::string const pkString = "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1" "CDC1"; auto const pkHex = strUnHex(pkString); PublicKey const pk{makeSlice(*pkHex)}; auto const alice = Account("alice"); auto const bob = Account("bob"); env.fund(XRP(1000), alice, bob); env.close(); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); Json::Value const xpop1_1 = import::loadXpop(ImportTCAccountSet::unl_seq_1_1); Json::Value const tx_1_1 = import::import(alice, xpop1_1); env(tx_1_1, fee(feeDrops * 10), ter(tesSUCCESS)); BEAST_EXPECT(importVLSequence(env, pk) == 1); Json::Value const xpop2_1 = import::loadXpop(ImportTCAccountSet::unl_seq_2_1); Json::Value const tx_2_1 = import::import(bob, xpop2_1); env(tx_2_1, fee(feeDrops * 10), ter(tesSUCCESS)); BEAST_EXPECT(importVLSequence(env, pk) == 2); Json::Value const xpop1_2 = import::loadXpop(ImportTCAccountSet::unl_seq_1_2); Json::Value const tx_1_2 = import::import(alice, xpop1_2); env(tx_1_2, fee(feeDrops * 10), ter(tefPAST_IMPORT_VL_SEQ)); } // tesSUCCESS // DA: testImportSequence // tefINTERNAL // DA: Impossible Test // tefINTERNAL // DA: Impossible Test // tesSUCCESS // DA: testImportSequence // telIMPORT_VL_KEY_NOT_RECOGNISED // import vl key not recognized, bailing. { test::jtx::Env env{*this, network::makeNetworkConfig(21337)}; auto const feeDrops = env.current()->fees().base; auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); Json::Value const tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); env(import::import(alice, tmpXpop), fee(feeDrops * 10), ter(telIMPORT_VL_KEY_NOT_RECOGNISED)); } } void testInvalidDoApply(FeatureBitset features) { testcase("import invalid doApply"); using namespace test::jtx; using namespace std::literals; test::jtx::Env env{*this, network::makeNetworkVLConfig(21337, keys)}; auto const alice = Account("alice"); auto const bob = Account("bob"); env.fund(XRP(1000), alice, bob); env.close(); // burn 1000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(1'000'000'000), ter(tesSUCCESS)); env.close(); //---------------------------------------------------------------------- // doApply // temDISABLED // tefINTERNAL/temMALFORMED - ctx_.tx.isFieldPresent(sfBlob) { Json::Value tx; tx[jss::TransactionType] = jss::Import; tx[jss::Account] = alice.human(); env(tx, ter(temMALFORMED)); } // tefINTERNAL/temMALFORMED - !xpop { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation] = {}; // one of many ways to throw error env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // tefINTERNAL/temMALFORMED // during apply could not find importSequence or fee, bailing. // No Fee { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::transaction][jss::blob] = "1200632200000000201B0000006C201D0000535968400000003B9ACA007321" "EDA8D46E11FD5D2082A4E6FF3039EB6259FBC2334983D015FC62ECAD0AE4A9" "6C747440549A370E68DBB1947419D4CCDF90CAE0BCA9121593ECC21B3C79EF" "0F232EB4375F95F1EBCED78B94D09838B5E769D43F041019ADEF3EC206AD3C" "5177C519560F8114AE123A8556F3CF91154711376AFB0F894F832B3D"; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // No Sequence // tefINTERNAL // initBal <= beast::zero // Sanity Check // tefINTERNAL // ImportSequence passed // Sanity Check (tefPAST_IMPORT_SEQ) // tefINTERNAL/temMALFORMED // !infoVL { Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); tmpXpop[jss::validation][jss::unl][jss::blob] = "YmFkSnNvbg=="; env(import::import(alice, tmpXpop), ter(temMALFORMED)); } // tefINTERNAL // current > infoVL->first // Sanity Check (tefPAST_IMPORT_VL_SEQ) } void testAccountSet(FeatureBitset features) { testcase("account set tx"); using namespace test::jtx; using namespace std::literals; // w/ seed -> dne (bad signer) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); env.memoize(alice); env.memoize(bob); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(bob, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, bob, ter(temMALFORMED)); env.close(); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins); // confirm account does not exist auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle == nullptr); } // w/ seed -> dne { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); env.memoize(alice); env.memoize(bob); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx Json::Value tx = import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops - feeDrops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = XRP(zeroBurn ? 0 : 1000) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm account exists auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle != nullptr); env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } // w/ regular key other -> dne (bad signer) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.memoize(alice); env.memoize(bob); env.memoize(carol); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == 99'999'990'000'000'000); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx - wrong regular key Json::Value txBad = import::import( alice, import::loadXpop(ImportTCAccountSet::w_regular_key)); txBad[jss::Sequence] = 0; txBad[jss::Fee] = 0; env(txBad, alice, sig(carol), ter(temMALFORMED)); env.close(); // confirm fee was not minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice); auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins); // confirm account does not exist auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle == nullptr); } // w/ regular key -> dne { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); env.memoize(alice); env.memoize(bob); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == 99'999'990'000'000'000); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx Json::Value tx = import::import( alice, import::loadXpop(ImportTCAccountSet::w_regular_key)); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, sig(bob), ter(tesSUCCESS)); env.close(); // total burn = burn drops - feeDrops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = XRP(zeroBurn ? 0 : 1000) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm account exists auto const [acct, acctSle1] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle1 != nullptr); // alice cannnot sign env(noop(alice), sig(alice), fee(feeDrops), ter(tefMASTER_DISABLED)); // bob cannot sign env(noop(alice), sig(bob), fee(feeDrops), ter(tefBAD_AUTH)); } // w/ signers list -> dne { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.memoize(alice); env.memoize(bob); env.memoize(carol); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_signers); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, msig(bob, carol), ter(tesSUCCESS)); env.close(); // total burn = burn drops - feeDrops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 48) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm signers not set auto const k = keylet::signers(alice); BEAST_EXPECT(env.current()->read(k) == nullptr); env(noop(alice), msig(bob, carol), fee(3 * feeDrops), ter(tefNOT_MULTI_SIGNING)); env.close(); // alice cannnot sign env(noop(alice), sig(alice), fee(feeDrops), ter(tefMASTER_DISABLED)); } // w/ seed -> funded { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10,000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins - (2 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(1000)); // import tx env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), fee(10 * 10), ter(tesSUCCESS)); env.close(); // total burn = burn drops - feeDrops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = XRP(zeroBurn ? 0 : 1000) - (feeDrops * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm account exists auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle != nullptr); env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } // w/ regular key -> funded { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); env.fund(XRP(1000), alice, bob); env.close(); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins - (4 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(1000)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_regular_key); Json::Value const tx = import::import(alice, xpopJson); env(tx, alice, sig(bob), fee(10 * 10), ter(tesSUCCESS)); env.close(); // total burn = burn drops - feeDrops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = XRP(zeroBurn ? 0 : 1000) - (feeDrops * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm account exists bob can sign auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle != nullptr); BEAST_EXPECT(!acctSle->isFieldPresent(sfRegularKey)); env(noop(alice), sig(bob), fee(feeDrops), ter(tefBAD_AUTH)); env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } // w/ signers -> funded { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.fund(XRP(1000), alice, bob, carol); env.close(); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins - (6 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(1000)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_signers); Json::Value const tx = import::import(alice, xpopJson); env(tx, alice, msig(bob, carol), fee((3 * feeDrops) * 10), ter(tesSUCCESS)); env.close(); // total burn = burn drops - feeDrops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 48) - ((3 * feeDrops) * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm signers not set auto const k = keylet::signers(alice); BEAST_EXPECT(env.current()->read(k) == nullptr); env(noop(alice), msig(bob, carol), fee(3 * feeDrops), ter(tefNOT_MULTI_SIGNING)); env.close(); // alice cannnot sign env(noop(alice), sig(alice), fee(feeDrops), ter(tesSUCCESS)); } } void testAccountSetFlags(FeatureBitset features) { testcase("account set flags"); using namespace test::jtx; using namespace std::literals; // account set flags not migrated { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins - (2 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(1000)); // import tx env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_flags)), fee(feeDrops * 10), ter(tesSUCCESS)); env.close(); // total burn = burn drops - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 10) - (feeDrops * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm account exists auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle != nullptr); env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } } void testSetRegularKey(FeatureBitset features) { testcase("set regular key tx"); using namespace test::jtx; using namespace std::literals; // w/ seed -> dne { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm env auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); env.memoize(alice); env.memoize(bob); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + reward amount bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 12) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm regular key auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle->getAccountID(sfRegularKey) == bob.id()); env(noop(alice), sig(bob), fee(feeDrops), ter(tesSUCCESS)); } // w/ regular key -> dne { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm env auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.memoize(alice); env.memoize(bob); env.memoize(carol); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_regular_key); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, sig(bob), ter(tesSUCCESS)); env.close(); // total burn = burn drops - initial value bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 12) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm regular key auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle->getAccountID(sfRegularKey) == carol.id()); env(noop(alice), sig(carol), fee(feeDrops), ter(tesSUCCESS)); } // w/ signers -> dne { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm env auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); auto const dave = Account("dave"); env.memoize(alice); env.memoize(bob); env.memoize(carol); env.memoize(dave); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_signers); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, msig(bob, carol), ter(tesSUCCESS)); env.close(); // total burn = burn drops + reward amount bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 48) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm signers not set auto const k = keylet::signers(alice); BEAST_EXPECT(env.current()->read(k) == nullptr); // confirm regular key auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT( acctSle && acctSle->isFieldPresent(sfRegularKey) && acctSle->getAccountID(sfRegularKey) == dave.id()); env(noop(alice), sig(dave), fee(feeDrops), ter(tesSUCCESS)); } // w/ seed -> funded { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm env auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const bob = Account("bob"); env.fund(XRP(1000), alice, bob); env.close(); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins - (4 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(1000)); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_seed); env(import::import(alice, xpopJson), fee(feeDrops * 10), ter(tesSUCCESS)); env.close(); // total burn = burn drops - feeDrops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 12) - (feeDrops * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm regular key auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle->getAccountID(sfRegularKey) == bob.id()); env(noop(alice), sig(bob), fee(feeDrops), ter(tesSUCCESS)); } // w/ seed -> funded (update regular key) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.fund(XRP(1000), alice, bob, carol); env.close(); // confirm env auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == burnCoins - (6 * feeDrops)); auto const envAlice = env.balance(alice); BEAST_EXPECT(envAlice == XRP(1000)); // set the regular key env(regkey(alice, carol)); env(noop(alice), sig(carol), fee(feeDrops), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == envCoins - (2 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == envAlice - (2 * feeDrops)); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_seed); env(import::import(alice, xpopJson), fee(feeDrops * 10), sig(alice), ter(tesSUCCESS)); env.close(); // total burn = burn drops - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 12) - (feeDrops * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm regular key set auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle->getAccountID(sfRegularKey) == bob.id()); env(noop(alice), sig(bob), fee(feeDrops), ter(tesSUCCESS)); } // w/ regular key -> funded (update regular key) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); auto const dave = Account("dave"); env.fund(XRP(1000), alice, bob, carol, dave); env.close(); // confirm env auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == burnCoins - (8 * feeDrops)); auto const envAlice = env.balance(alice); BEAST_EXPECT(envAlice == XRP(1000)); // set the regular key env(regkey(alice, dave)); env(noop(alice), sig(dave), fee(feeDrops), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == envCoins - (2 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == envAlice - (2 * feeDrops)); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_regular_key); env(import::import(alice, xpopJson), fee(feeDrops * 10), sig(bob), ter(tesSUCCESS)); env.close(); // total burn = burn drops - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 12) - (feeDrops * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm regular key auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle->getAccountID(sfRegularKey) == carol.id()); env(noop(alice), sig(carol), fee(feeDrops), ter(tesSUCCESS)); } // w/ signers list -> funded (update regular key) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); auto const dave = Account("dave"); auto const elsa = Account("elsa"); env.fund(XRP(1000), alice, bob, carol, dave, elsa); env.close(); // confirm env auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == burnCoins - (10 * feeDrops)); auto const envAlice = env.balance(alice); BEAST_EXPECT(envAlice == XRP(1000)); // set the regular key env(regkey(alice, elsa)); env(noop(alice), sig(elsa), fee(feeDrops), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == envCoins - (2 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == envAlice - (2 * feeDrops)); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_signers); env(import::import(alice, xpopJson), msig(bob, carol), fee((3 * feeDrops) * 10), ter(tesSUCCESS)); env.close(); // total burn = burn drops - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 48) - ((3 * feeDrops) * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm regular key auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle->getAccountID(sfRegularKey) == dave.id()); env(noop(alice), sig(dave), fee(feeDrops), ter(tesSUCCESS)); // confirm signers list not set auto const k = keylet::signers(alice); BEAST_EXPECT(env.current()->read(k) == nullptr); } // seed -> funded (empty regular key) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.fund(XRP(1000), alice, bob, carol); env.close(); // confirm env auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == burnCoins - (6 * feeDrops)); auto const envAlice = env.balance(alice); BEAST_EXPECT(envAlice == XRP(1000)); // set the regular key env(regkey(alice, carol)); env(noop(alice), sig(carol), fee(feeDrops), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == envCoins - (2 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == envAlice - (2 * feeDrops)); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_seed_empty); env(import::import(alice, xpopJson), fee(feeDrops * 10), sig(alice), ter(tesSUCCESS)); env.close(); // total burn = burn drops - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 12) - (feeDrops * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm regular key auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(!acctSle->isFieldPresent(sfRegularKey)); } // w/ regular key -> funded (empty regular key) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.fund(XRP(1000), alice, bob, carol); env.close(); // confirm env auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == burnCoins - (6 * feeDrops)); auto const envAlice = env.balance(alice); BEAST_EXPECT(envAlice == XRP(1000)); // set the regular key env(regkey(alice, carol)); env(noop(alice), sig(carol), fee(feeDrops), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == envCoins - (2 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == envAlice - (2 * feeDrops)); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_regular_key_empty); env(import::import(alice, xpopJson), fee(feeDrops * 10), sig(bob), ter(tesSUCCESS)); env.close(); // total burn = burn drops - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 12) - (feeDrops * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm regular key auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(!acctSle->isFieldPresent(sfRegularKey)); env(noop(alice), sig(alice), fee(feeDrops), ter(tesSUCCESS)); env(noop(alice), sig(bob), fee(feeDrops), ter(tefBAD_AUTH)); env(noop(alice), sig(carol), fee(feeDrops), ter(tefBAD_AUTH)); } // w/ signers -> funded (empty regular key) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); auto const dave = Account("dave"); env.fund(XRP(1000), alice, bob, carol, dave); env.close(); // confirm env auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == burnCoins - (8 * feeDrops)); auto const envAlice = env.balance(alice); BEAST_EXPECT(envAlice == XRP(1000)); // set the regular key env(regkey(alice, dave)); env(noop(alice), sig(dave), fee(feeDrops), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == envCoins - (2 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == envAlice - (2 * feeDrops)); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_signers_empty); env(import::import(alice, xpopJson), msig(bob, carol), fee((3 * feeDrops) * 10), ter(tesSUCCESS)); env.close(); // total burn = burn drops - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 48) - ((3 * feeDrops) * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm regular key auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(!acctSle->isFieldPresent(sfRegularKey)); env(noop(alice), sig(alice), fee(feeDrops), ter(tesSUCCESS)); env(noop(alice), sig(bob), fee(feeDrops), ter(tefBAD_AUTH)); env(noop(alice), sig(carol), fee(feeDrops), ter(tefBAD_AUTH)); env(noop(alice), sig(dave), fee(feeDrops), ter(tefBAD_AUTH)); } } void testSetRegularKeyFlags(FeatureBitset features) { testcase("set regular key flags"); using namespace test::jtx; using namespace std::literals; // dne -> dont set flag { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); auto const alice = Account("alice"); auto const bob = Account("bob"); env.memoize(alice); env.memoize(bob); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // confirm lsfPasswordSpent is set auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT( (acctSle->getFieldU32(sfFlags) & lsfPasswordSpent) == lsfPasswordSpent); } // funded -> set flag { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); auto const alice = Account("alice"); auto const bob = Account("bob"); env.fund(XRP(1000), alice, bob); env.close(); // import tx auto const xpopJson = import::loadXpop(ImportTCSetRegularKey::w_seed_zero); env(import::import(alice, xpopJson), fee(feeDrops * 10), ter(tesSUCCESS)); env.close(); // confirm lsfPasswordSpent is not set auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT( (acctSle->getFieldU32(sfFlags) & lsfPasswordSpent) == 0); } } void testSignersListSet(FeatureBitset features) { testcase("signers list set tx"); using namespace test::jtx; using namespace std::literals; // w/ seed -> dne w/ seed (Bad Fee) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.memoize(alice); env.memoize(bob); env.memoize(carol); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins); // confirm total coins header auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCSignersListSet::w_seed_bad_fee); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; // tx[jss::Fee] = 0; env(tx, alice, ter(temBAD_FEE)); env.close(); } // w/ seed -> dne w/ seed { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.memoize(alice); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins); // confirm alice balance auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCSignersListSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = (burn drops + burn fee drops) - reward bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = XRP(zeroBurn ? 0 : 2) + drops(zeroBurn ? 0 : 12) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm fee was minted auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm signers set auto const [signers, signersSle] = signersKeyAndSle(*env.current(), alice); auto const signerEntries = signersSle->getFieldArray(sfSignerEntries); BEAST_EXPECT(signerEntries.size() == 2); BEAST_EXPECT(signerEntries[0u].getFieldU16(sfSignerWeight) == 1); BEAST_EXPECT( signerEntries[0u].getAccountID(sfAccount) == carol.id()); BEAST_EXPECT(signerEntries[1u].getFieldU16(sfSignerWeight) == 1); BEAST_EXPECT(signerEntries[1u].getAccountID(sfAccount) == bob.id()); // confirm multisign tx env.close(); auto const aliceSeq = env.seq(alice); env(noop(alice), msig(bob, carol), fee(3 * feeDrops), ter(tesSUCCESS)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); // confirm noop master disabled env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } // w/ regular key -> dne { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); auto const dave = Account("dave"); env.memoize(alice); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins); // confirm alice balance auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const burnAmt = XRP(2); auto const xpopJson = import::loadXpop(ImportTCSignersListSet::w_regular_key); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, sig(bob), ter(tesSUCCESS)); env.close(); // total burn = (burn drops + burn fee drops) - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = XRP(zeroBurn ? 0 : 2) + drops(zeroBurn ? 0 : 12) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm fee was minted auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm signers set auto const [signers, signersSle] = signersKeyAndSle(*env.current(), alice); auto const signerEntries = signersSle->getFieldArray(sfSignerEntries); BEAST_EXPECT(signerEntries.size() == 2); BEAST_EXPECT(signerEntries[0u].getFieldU16(sfSignerWeight) == 1); BEAST_EXPECT( signerEntries[0u].getAccountID(sfAccount) == dave.id()); BEAST_EXPECT(signerEntries[1u].getFieldU16(sfSignerWeight) == 1); BEAST_EXPECT( signerEntries[1u].getAccountID(sfAccount) == carol.id()); // confirm multisign tx env.close(); auto const aliceSeq = env.seq(alice); env(noop(alice), msig(carol, dave), fee(3 * feeDrops), ter(tesSUCCESS)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); // confirm regular key bad auth env(noop(alice), sig(bob), fee(feeDrops), ter(tefBAD_AUTH)); // confirm noop master disabled env(noop(alice), fee(feeDrops), ter(tefMASTER_DISABLED)); } // w/ signers -> dne { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 100,000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); auto const dave = Account("dave"); auto const elsa = Account("elsa"); env.memoize(alice); env.memoize(dave); env.memoize(elsa); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins); // confirm alice balance auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCSignersListSet::w_signers); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, msig(bob, carol), ter(tesSUCCESS)); env.close(); // confirm signers set auto const [signers, signersSle] = signersKeyAndSle(*env.current(), alice); auto const signerEntries = signersSle->getFieldArray(sfSignerEntries); BEAST_EXPECT(signerEntries.size() == 2); BEAST_EXPECT(signerEntries[0u].getFieldU16(sfSignerWeight) == 1); BEAST_EXPECT( signerEntries[0u].getAccountID(sfAccount) == dave.id()); BEAST_EXPECT(signerEntries[1u].getFieldU16(sfSignerWeight) == 1); BEAST_EXPECT( signerEntries[1u].getAccountID(sfAccount) == elsa.id()); // confirm multisign tx env.close(); auto const aliceSeq = env.seq(alice); env(noop(alice), msig(dave, elsa), fee(3 * feeDrops), ter(tesSUCCESS)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); // confirm regular key bad auth env(noop(alice), sig(bob), fee(feeDrops), ter(tefBAD_AUTH)); // confirm noop master disabled env(noop(alice), fee(feeDrops), ter(tefMASTER_DISABLED)); } // w/ seed -> funded { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.fund(XRP(1000), alice, bob, carol); env.close(); // confirm env auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == burnCoins - (6 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(1000)); // import tx auto const xpopJson = import::loadXpop(ImportTCSignersListSet::w_seed); env(import::import(alice, xpopJson), fee(feeDrops * 10), ter(tesSUCCESS)); env.close(); // total burn = (burn drops + burn fee drops) - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = XRP(zeroBurn ? 0 : 2) + drops(zeroBurn ? 0 : 12) - (feeDrops * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm signers set auto const [signers, signersSle] = signersKeyAndSle(*env.current(), alice); BEAST_EXPECT( signersSle && signersSle->isFieldPresent(sfSignerEntries)); if (signersSle && signersSle->isFieldPresent(sfSignerEntries)) { auto const signerEntries = signersSle->getFieldArray(sfSignerEntries); BEAST_EXPECT(signerEntries.size() == 2); BEAST_EXPECT( signerEntries[0u].getFieldU16(sfSignerWeight) == 1); BEAST_EXPECT( signerEntries[0u].getAccountID(sfAccount) == carol.id()); BEAST_EXPECT( signerEntries[1u].getFieldU16(sfSignerWeight) == 1); BEAST_EXPECT( signerEntries[1u].getAccountID(sfAccount) == bob.id()); } // confirm multisign tx env.close(); auto const aliceSeq = env.seq(alice); env(noop(alice), msig(bob, carol), fee(3 * feeDrops), ter(tesSUCCESS)); env.close(); BEAST_EXPECT(env.seq(alice) == aliceSeq + 1); // confirm noop alice tx env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } // w/ seed (empty) -> funded (has entries) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.fund(XRP(1000), alice, bob, carol); env.close(); // confirm env auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == burnCoins - (6 * feeDrops)); auto const envAlice = env.balance(alice); BEAST_EXPECT(envAlice == XRP(1000)); // set the signers list env(signers(alice, 2, {{bob, 1}, {carol, 1}})); env(noop(alice), msig(bob, carol), fee(3 * feeDrops), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == envCoins - (4 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == envAlice - (4 * feeDrops)); // import tx auto const xpopJson = import::loadXpop(ImportTCSignersListSet::w_seed_empty); env(import::import(alice, xpopJson), fee(feeDrops * 10), ter(tesSUCCESS)); env.close(); // total burn = (burn drops + burn fee drops) - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = XRP(zeroBurn ? 0 : 2) + drops(zeroBurn ? 0 : 12) - (feeDrops * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm signers not set auto const k = keylet::signers(alice); BEAST_EXPECT(env.current()->read(k) == nullptr); // confirm noop master success env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } // w/ regular key (empty) -> funded (has entries) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.fund(XRP(1000), alice, bob, carol); env.close(); // confirm env auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == burnCoins - (6 * feeDrops)); auto const envAlice = env.balance(alice); BEAST_EXPECT(envAlice == XRP(1000)); // set the regular key env(regkey(alice, bob)); env(noop(alice), sig(bob), fee(feeDrops), ter(tesSUCCESS)); env.close(); // set the signers list env(signers(alice, 2, {{bob, 1}, {carol, 1}})); env(noop(alice), msig(bob, carol), fee(3 * feeDrops), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == envCoins - (6 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == envAlice - (6 * feeDrops)); // import tx auto const xpopJson = import::loadXpop(ImportTCSignersListSet::w_regular_key_empty); env(import::import(alice, xpopJson), fee(feeDrops * 10), sig(bob), ter(tesSUCCESS)); env.close(); // total burn = (burn drops + burn fee drops) - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = XRP(zeroBurn ? 0 : 2) + drops(zeroBurn ? 0 : 12) - (feeDrops * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm regular key auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle->getAccountID(sfRegularKey) == bob.id()); env(noop(alice), sig(bob), fee(feeDrops), ter(tesSUCCESS)); // confirm signers not set auto const k = keylet::signers(alice); BEAST_EXPECT(env.current()->read(k) == nullptr); // confirm noop master success env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } // w/ signers (empty) -> funded (has entries) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.fund(XRP(1000), alice, bob, carol); env.close(); // confirm env auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == burnCoins - (6 * feeDrops)); auto const envAlice = env.balance(alice); BEAST_EXPECT(envAlice == XRP(1000)); // set the signers list env(signers(alice, 2, {{bob, 1}, {carol, 1}})); env(noop(alice), msig(bob, carol), fee(3 * feeDrops), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == envCoins - (4 * feeDrops)); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == envAlice - (4 * feeDrops)); // import tx auto const xpopJson = import::loadXpop(ImportTCSignersListSet::w_signers_empty); env(import::import(alice, xpopJson), msig(bob, carol), fee((3 * feeDrops) * 10), ter(tesSUCCESS)); env.close(); // total burn = (burn drops + burn fee drops) - fee drops bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = XRP(zeroBurn ? 0 : 2) + drops(zeroBurn ? 0 : 48) - ((3 * feeDrops) * 10); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm signers not set auto const k = keylet::signers(alice); BEAST_EXPECT(env.current()->read(k) == nullptr); // confirm noop master success env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } } void testUsingTickets(FeatureBitset features) { testcase("using tickets"); using namespace test::jtx; using namespace std::literals; { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); std::uint32_t aliceTicketSeq{env.seq(alice) + 1}; env(ticket::create(alice, 10)); std::uint32_t const aliceSeq{env.seq(alice)}; env.require(owners(alice, 10)); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), fee(feeDrops * 10), ticket::use(aliceTicketSeq++), ter(tesSUCCESS)); env.close(); env.require(tickets(alice, env.seq(alice) - aliceTicketSeq)); BEAST_EXPECT(env.seq(alice) == aliceSeq); env.require(owners(alice, 9)); } } void testAccountIndex(FeatureBitset features) { testcase("account index"); using namespace test::jtx; using namespace std::literals; // Account Index from Import { for (std::uint32_t const withFeature : {0, 1, 2}) { auto const amend = withFeature == 0 ? features : withFeature == 1 ? features - featureXahauGenesis : features - featureDeletableAccounts; test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys), amend}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), fee(feeDrops * 10), ter(tesSUCCESS)); env.close(); // confirm account index was set auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); // confirm sequence if (withFeature == 0) { BEAST_EXPECT((*acctSle)[sfAccountIndex] == 0); } std::uint64_t const seq = withFeature == 0 ? 12 : withFeature == 1 ? 6 : 12; BEAST_EXPECT((*acctSle)[sfSequence] == seq); // confirm account count was set if (withFeature == 0) { auto const [fee, feeSle] = feesKeyAndSle(*env.current()); BEAST_EXPECT((*feeSle)[sfAccountCount] == 1); } } } // Account Index from Payment { for (std::uint32_t const withFeature : {0, 1, 2}) { auto const amend = withFeature == 0 ? features : withFeature == 1 ? features - featureXahauGenesis : features - featureDeletableAccounts; test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys), amend}; env.close(); auto const alice = Account("alice"); auto const bob = Account("bob"); auto const carol = Account("carol"); env.fund(XRP(1000), alice, bob, carol); env.close(); struct TestAccountData { Account acct; std::uint32_t index; std::uint64_t sequence; }; std::uint64_t const seq = withFeature == 0 ? 11 : withFeature == 1 ? 5 : 11; std::array acctTests = {{ {alice, 0, seq}, {bob, 1, seq}, {carol, 2, seq}, }}; for (auto const& t : acctTests) { // confirm index was set auto const [acct, acctSle] = accountKeyAndSle(*env.current(), t.acct); // confirm sequence if (withFeature == 0) { BEAST_EXPECT((*acctSle)[sfAccountIndex] == t.index); } BEAST_EXPECT((*acctSle)[sfSequence] == t.sequence); } if (withFeature == 0) { // confirm count was updated auto const [fee, feeSle] = feesKeyAndSle(*env.current()); BEAST_EXPECT((*feeSle)[sfAccountCount] == 3); } } } } void testHookIssuer(FeatureBitset features) { testcase("hook issuer tx"); using namespace test::jtx; using namespace std::literals; // Test that hook can reject and does NOT mint the funds. { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; bool const fixV2 = env.current()->rules().enabled(fixXahauV2); // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); auto const issuer = Account("issuer"); env.fund(XRP(10000), alice, issuer); env.close(); // fixXahauV2 - tshWEAK env(fset(issuer, asfTshCollect)); env.close(); std::string const createCodeHex = "0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F" "017F60017F017E02250303656E76057472616365000003656E7608726F6C6C" "6261636B000103656E76025F670002030201030503010002062B077F0141C0" "88040B7F004180080B7F0041BE080B7F004180080B7F0041C088040B7F0041" "000B7F0041010B07080104686F6F6B00030AC3800001BF800001017F230041" "106B220124002001200036020C41940841154180084114410010001A41AA08" "4114420A10011A41012200200010021A200141106A240042000B0B44010041" "80080B3D526F6C6C6261636B2E633A2043616C6C65642E0022526F6C6C6261" "636B2E633A2043616C6C65642E2200526F6C6C6261636B3A20526F6C6C6261" "636B21"; std::string ns_str = "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECA" "FE"; Json::Value jv = ripple::test::jtx::hook(issuer, {{hso(createCodeHex)}}, 0); jv[jss::Hooks][0U][jss::Hook][jss::HookNamespace] = ns_str; jv[jss::Hooks][0U][jss::Hook][jss::HookOn] = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFFFFBFFF" "FF"; env(jv, fee(1'000'000)); env.close(); auto const preAlice = env.balance(alice); auto const preCoins = env.current()->info().drops; auto const result = fixV2 ? ter(tesSUCCESS) : ter(tecHOOK_REJECTED); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), import::issuer(issuer), fee(1'000'000), result); env.close(); // fixXahauV2 bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const mintXAH = fixV2 ? XRP(zeroBurn ? 0 : 1000) : XRP(0); // confirm fee was burned mint / no mint auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice - XRP(1) + mintXAH); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins - XRP(1) + mintXAH); // resubmit import without issuer auto const result2 = fixV2 ? ter(tefPAST_IMPORT_SEQ) : ter(tesSUCCESS); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), fee(feeDrops * 10), result2); env.close(); // total burn auto const totalBurn = fixV2 ? XRP(0) : XRP(zeroBurn ? 0 : 1000) - (feeDrops * 10); // confirm fee was minted / not minted auto const postAlice2 = env.balance(alice); BEAST_EXPECT(postAlice2 == postAlice + totalBurn); // confirm total coins header auto const postCoins2 = env.current()->info().drops; BEAST_EXPECT(postCoins2 == postCoins + totalBurn); env.close(); } } void testAccountDelete(FeatureBitset features) { testcase("account delete"); using namespace test::jtx; using namespace std::literals; { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; auto const alice = Account("alice"); auto const bob = Account("bob"); env.fund(XRP(1000), alice, bob); env.close(); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); Json::Value const xpop = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value const tx = import::import(alice, xpop); env(tx, fee(feeDrops * 10), ter(tesSUCCESS)); // Close enough ledgers to be able to delete alices's account. incLgrSeqForAccDel(env, alice); // alice cannot delete account after import auto const acctDelFee{drops(env.current()->fees().increment)}; env(acctdelete(alice, bob), fee(acctDelFee), ter(tecHAS_OBLIGATIONS)); } } void testImportSequence(FeatureBitset features) { testcase("import sequence"); using namespace test::jtx; using namespace std::literals; // test bad IMPORT_VL_KEYS no UNLReport { std::vector const badVLKeys = { "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1" "CDC2"}; test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, badVLKeys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); auto preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(1000)); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), fee(feeDrops * 10), ter(telIMPORT_VL_KEY_NOT_RECOGNISED)); env.close(); } // test good IMPORT_VL_KEYS no UNLReport { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); auto preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(1000)); env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), fee(feeDrops * 10), ter(tesSUCCESS)); env.close(); } // test no IMPORT_VL_KEYS has UNLReport { test::jtx::Env env{*this, network::makeNetworkConfig(21337)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); auto preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(1000)); // ADD UNL REPORT std::vector const _ivlKeys = { "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1" "CDC1", "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1" "CDC2", }; std::vector ivlKeys; for (auto const& strPk : _ivlKeys) { auto pkHex = strUnHex(strPk); ivlKeys.emplace_back(makeSlice(*pkHex)); } std::vector const _vlKeys = { "ED8E43A943A174190BA2FAE91F44AC6E2D1D8202EFDCC2EA3DBB39814576D6" "90F7", "ED45D1840EE724BE327ABE9146503D5848EFD5F38B6D5FEDE71E80ACCE5E6E" "738B"}; std::vector vlKeys; for (auto const& strPk : _vlKeys) { auto pkHex = strUnHex(strPk); vlKeys.emplace_back(makeSlice(*pkHex)); } // insert a ttUNL_REPORT pseudo into the open ledger env.app().openLedger().modify( [&](OpenView& view, beast::Journal j) -> bool { STTx tx = unl::createUNLReportTx( env.current()->seq() + 1, ivlKeys[0], vlKeys[0]); uint256 txID = tx.getTransactionID(); auto s = std::make_shared(); tx.add(*s); env.app().getHashRouter().setFlags(txID, SF_PRIVATE2); view.rawTxInsert(txID, std::move(s), nullptr); return true; }); // close the ledger env.close(); BEAST_EXPECT(hasUNLReport(env) == true); // Test Import env(import::import( alice, import::loadXpop(ImportTCAccountSet::w_seed)), fee(feeDrops * 10), ter(tesSUCCESS)); env.close(); } } void testMaxSupply(FeatureBitset features) { testcase("max supply"); using namespace test::jtx; using namespace std::literals; // burn 100'000 coins { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys), nullptr, beast::severities::kDisabled, }; auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == 100'000'000'000'000'000); // 100'000'000'000'000'000 - drops // 100'000'000'000 - xrp // burn 100,000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(100'000'000'000), ter(tesSUCCESS)); env.close(); auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == envCoins - drops(100'000'000'000)); auto const alice = Account("alice"); env.memoize(alice); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); STAmount burnFee = XRP(zeroBurn ? 0 : 1000) + XRP(2); auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + burnFee); auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + burnFee); } // burn all coins { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys), nullptr, beast::severities::kDisabled, }; auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == 100'000'000'000'000'000); // burn all but 1,000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(envCoins - drops(1'000'000'000)), ter(tesSUCCESS)); env.close(); auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == XRP(1000)); auto const alice = Account("alice"); env.memoize(alice); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); STAmount burnFee = XRP(zeroBurn ? 0 : 1000) + XRP(2); auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + burnFee); auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + burnFee); } // burn no coins { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys), nullptr, beast::severities::kDisabled, }; auto const envCoins = env.current()->info().drops; BEAST_EXPECT(envCoins == 100'000'000'000'000'000); auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == XRP(100'000'000'000)); auto const alice = Account("alice"); env.memoize(alice); auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); STAmount burnFee = XRP(zeroBurn ? 0 : 1000) + XRP(2); auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tefINTERNAL)); env.close(); auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice); auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins); } } void testMinMax(FeatureBitset features) { testcase("min max"); using namespace test::jtx; using namespace std::literals; // w/ seed -> dne (min) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); env.memoize(alice); // confirm env auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::min); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + reward amount bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 10) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm account exists auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle != nullptr); env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } // w/ seed -> dne (min) (Reserve/Reference/Fee) // Owner Fee = 20 xrp { test::jtx::Env env{ *this, network::makeNetworkVLConfig( 21337, keys, "50", "10000000", "2000000")}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == initCoins - 10'000'000'000); // init env auto const alice = Account("alice"); env.memoize(alice); // confirm env auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::min); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + reward amount bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 10) + XRP(20); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm account exists auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle != nullptr); env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } // w/ seed -> dne (max) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 99'999'998'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(99'999'998'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const preCoins = env.current()->info().drops; BEAST_EXPECT(preCoins == initCoins - 99'999'998'000'000'000); // init env auto const alice = Account("alice"); env.memoize(alice); // confirm env auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::max); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + reward amount bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const totalBurn = drops(zeroBurn ? 0 : 99'999'939'799'000'000) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + totalBurn); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == preCoins + totalBurn); // confirm account exists auto const [acct, acctSle] = accountKeyAndSle(*env.current(), alice); BEAST_EXPECT(acctSle != nullptr); env(noop(alice), fee(feeDrops), ter(tesSUCCESS)); } } void testHalving(FeatureBitset features) { testcase("halving"); using namespace test::jtx; using namespace std::literals; // Halving @ ledger seq 1'999'999 { test::jtx::Env env{ *this, network::makeGenesisConfig( features, 21337, keys, "10", "1000000", "200000", 1999998), features}; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 0); auto const initSeq = env.current()->info().seq; BEAST_EXPECT(initSeq == 1'999'999); // init env auto const alice = Account("alice"); env.memoize(alice); // confirm env auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + Init Reward bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const creditDrops = XRP(zeroBurn ? 0 : 1'000) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + creditDrops); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == initCoins + creditDrops); } // Halving @ ledger seq 2'000'000 { test::jtx::Env env{ *this, network::makeGenesisConfig( features, 21337, keys, "10", "1000000", "200000", 1999998), features}; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 0); env.close(); auto const initSeq = env.current()->info().seq; BEAST_EXPECT(initSeq == 2'000'000); // init env auto const alice = Account("alice"); env.memoize(alice); // confirm env auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + Init Reward bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const creditDrops = XRP(zeroBurn ? 0 : 1'000) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + creditDrops); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == initCoins + creditDrops); } // Halving @ ledger seq 2'000'001 { test::jtx::Env env{ *this, network::makeGenesisConfig( features, 21337, keys, "10", "1000000", "200000", 1999998), features}; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 0); env.close(); env.close(); auto const initSeq = env.current()->info().seq; BEAST_EXPECT(initSeq == 2'000'001); // init env auto const alice = Account("alice"); env.memoize(alice); // confirm env auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + Init Reward bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const creditDrops = drops(zeroBurn ? 0 : 999999964) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + creditDrops); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == initCoins + creditDrops); } // Halving @ ledger seq 5'000'000 { test::jtx::Env env{ *this, network::makeGenesisConfig( features, 21337, keys, "10", "1000000", "200000", 4999999), features}; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 0); auto const initSeq = env.current()->info().seq; BEAST_EXPECT(initSeq == 5'000'000); // init env auto const alice = Account("alice"); env.memoize(alice); // confirm env auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + Init Reward bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const creditDrops = drops(zeroBurn ? 0 : 892857142) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + creditDrops); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == initCoins + creditDrops); } // Halving @ ledger seq 20'000'000 { test::jtx::Env env{ *this, network::makeGenesisConfig( features, 21337, keys, "10", "1000000", "200000", 19999999), features}; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 0); auto const initSeq = env.current()->info().seq; BEAST_EXPECT(initSeq == 20'000'000); // init env auto const alice = Account("alice"); env.memoize(alice); // confirm env auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + Init Reward bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const creditDrops = drops(zeroBurn ? 0 : 357142857) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + creditDrops); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == initCoins + creditDrops); } // Halving @ ledger seq 29'999'998 { test::jtx::Env env{ *this, network::makeGenesisConfig( features, 21337, keys, "10", "1000000", "200000", 29999998), features}; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 0); auto const initSeq = env.current()->info().seq; BEAST_EXPECT(initSeq == 29'999'999); // init env auto const alice = Account("alice"); env.memoize(alice); // confirm env auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + Init Reward bool const zeroBurn = env.current()->rules().enabled(featureZeroB2M); auto const creditDrops = drops(zeroBurn ? 0 : 35) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + creditDrops); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == initCoins + creditDrops); } // Halving @ ledger seq 30'000'000 { test::jtx::Env env{ *this, network::makeGenesisConfig( features, 21337, keys, "10", "1000000", "200000", 29999998), features}; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 0); env.close(); auto const initSeq = env.current()->info().seq; BEAST_EXPECT(initSeq == 30'000'000); // init env auto const alice = Account("alice"); env.memoize(alice); // confirm env auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + Init Reward auto const creditDrops = drops(0) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + creditDrops); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == initCoins + creditDrops); } // Halving @ ledger seq 50'000'001 { test::jtx::Env env{ *this, network::makeGenesisConfig( features, 21337, keys, "10", "1000000", "200000", 50000000), features}; // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 0); auto const initSeq = env.current()->info().seq; BEAST_EXPECT(initSeq == 50'000'001); // init env auto const alice = Account("alice"); env.memoize(alice); // confirm env auto const preAlice = env.balance(alice); BEAST_EXPECT(preAlice == XRP(0)); // import tx auto const xpopJson = import::loadXpop(ImportTCAccountSet::w_seed); Json::Value tx = import::import(alice, xpopJson); tx[jss::Sequence] = 0; tx[jss::Fee] = 0; env(tx, alice, ter(tesSUCCESS)); env.close(); // total burn = burn drops + Init Reward auto const creditDrops = drops(0) + XRP(2); // confirm fee was minted auto const postAlice = env.balance(alice); BEAST_EXPECT(postAlice == preAlice + creditDrops); // confirm total coins header auto const postCoins = env.current()->info().drops; BEAST_EXPECT(postCoins == initCoins + creditDrops); } } void testBlackhole(FeatureBitset features) { testcase("blackhole"); using namespace test::jtx; using namespace std::literals; auto blackholeAccount = [&](Env& env, Account const& acct) { // Set Regular Key Json::Value jv; jv[jss::Account] = acct.human(); const AccountID ACCOUNT_ZERO(0); jv["RegularKey"] = to_string(ACCOUNT_ZERO); jv[jss::TransactionType] = jss::SetRegularKey; env(jv, acct); // Disable Master Key env(fset(acct, asfDisableMaster), sig(acct)); env.close(); }; auto burnHeader = [&](Env& env) { // confirm total coins header auto const initCoins = env.current()->info().drops; BEAST_EXPECT(initCoins == 100'000'000'000'000'000); // burn 10'000 xrp auto const master = Account("masterpassphrase"); env(noop(master), fee(100'000'000'000'000), ter(tesSUCCESS)); env.close(); // confirm total coins header auto const burnCoins = env.current()->info().drops; BEAST_EXPECT(burnCoins == initCoins - 100'000'000'000'000); }; // AccountSet (w/seed) { test::jtx::Env env{ *this, network::makeNetworkVLConfig(21337, keys)}; auto const feeDrops = env.current()->fees().base; // Burn Header burnHeader(env); auto const alice = Account("alice"); env.fund(XRP(1000), alice); env.close(); // Blackhole Account blackholeAccount(env, alice); // Import with Master Key Json::Value tmpXpop = import::loadXpop(ImportTCAccountSet::w_seed); env(import::import(alice, tmpXpop), ter(tesSUCCESS), fee(feeDrops * 10), sig(alice)); env.close(); } } public: void run() override { using namespace test::jtx; FeatureBitset const all{supported_amendments()}; testWithFeats(all - fixXahauV2); testWithFeats(all - featureZeroB2M); testWithFeats(all); } void testWithFeats(FeatureBitset features) { testComputeStartingBalance(features); testIsHex(features); testIsBase58(features); testIsBase64(features); testParseUint64(features); testSyntaxCheckProofArray(features); testSyntaxCheckProofObject(features); testSyntaxCheckXPOP(features); testGetVLInfo(features); testEnabled(features); testInvalidPreflight(features); testInvalidPreclaim(features); testInvalidDoApply(features); testAccountSet(features); testAccountSetFlags(features); testSetRegularKey(features); testSetRegularKeyFlags(features); testSignersListSet(features); testUsingTickets(features); testAccountIndex(features); testHookIssuer(features); testImportSequence(features); testAccountDelete(features); testMaxSupply(features); testMinMax(features); testHalving(features - featureOwnerPaysFee); testBlackhole(features); } }; BEAST_DEFINE_TESTSUITE(Import, app, ripple); } // namespace test } // namespace ripple