add halving tests

This commit is contained in:
Denis Angell
2023-09-05 12:23:27 +02:00
parent ed6c25d093
commit 4d06d898ee
4 changed files with 591 additions and 67 deletions

View File

@@ -1105,8 +1105,11 @@ private:
std::shared_ptr<Ledger>
loadLedgerFromFile(std::string const& ledgerID);
std::shared_ptr<Ledger>
loadLedgerFromJson(std::string const& jsonValue);
bool
loadOldLedger(std::string const& ledgerID, bool replay, bool isFilename);
loadOldLedger(std::string const& ledgerID, bool replay, bool isFilename, bool isJson);
void
setMaxDisallowedLedger();
@@ -1234,14 +1237,15 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline)
}
else if (
startUp == Config::LOAD || startUp == Config::LOAD_FILE ||
startUp == Config::REPLAY)
startUp == Config::REPLAY || startUp == Config::LOAD_JSON)
{
JLOG(m_journal.info()) << "Loading specified Ledger";
if (!loadOldLedger(
config_->START_LEDGER,
startUp == Config::REPLAY,
startUp == Config::LOAD_FILE))
startUp == Config::LOAD_FILE,
startUp == Config::LOAD_JSON))
{
JLOG(m_journal.error())
<< "The specified ledger could not be loaded.";
@@ -1907,17 +1911,153 @@ ApplicationImp::loadLedgerFromFile(std::string const& name)
}
}
std::shared_ptr<Ledger>
ApplicationImp::loadLedgerFromJson(std::string const& jsonValue)
{
try
{
Json::Reader reader;
Json::Value jLedger;
if (!reader.parse(jsonValue, jLedger))
{
JLOG(m_journal.fatal()) << "Unable to parse ledger JSON";
return nullptr;
}
std::reference_wrapper<Json::Value> ledger(jLedger);
// accept a wrapped ledger
if (ledger.get().isMember("result"))
ledger = ledger.get()["result"];
if (ledger.get().isMember("ledger"))
ledger = ledger.get()["ledger"];
std::uint32_t seq = 1;
auto closeTime = timeKeeper().closeTime();
using namespace std::chrono_literals;
auto closeTimeResolution = 30s;
bool closeTimeEstimated = false;
std::uint64_t totalDrops = 0;
if (ledger.get().isMember("accountState"))
{
if (ledger.get().isMember(jss::ledger_index))
{
seq = ledger.get()[jss::ledger_index].asUInt();
}
if (ledger.get().isMember("close_time"))
{
using tp = NetClock::time_point;
using d = tp::duration;
closeTime = tp{d{ledger.get()["close_time"].asUInt()}};
}
if (ledger.get().isMember("close_time_resolution"))
{
using namespace std::chrono;
closeTimeResolution =
seconds{ledger.get()["close_time_resolution"].asUInt()};
}
if (ledger.get().isMember("close_time_estimated"))
{
closeTimeEstimated =
ledger.get()["close_time_estimated"].asBool();
}
if (ledger.get().isMember("total_coins"))
{
totalDrops = beast::lexicalCastThrow<std::uint64_t>(
ledger.get()["total_coins"].asString());
}
ledger = ledger.get()["accountState"];
}
if (!ledger.get().isArrayOrNull())
{
JLOG(m_journal.fatal()) << "State nodes must be an array";
return nullptr;
}
auto loadLedger =
std::make_shared<Ledger>(seq, closeTime, *config_, nodeFamily_);
loadLedger->setTotalDrops(totalDrops);
for (Json::UInt index = 0; index < ledger.get().size(); ++index)
{
Json::Value& entry = ledger.get()[index];
if (!entry.isObjectOrNull())
{
JLOG(m_journal.fatal()) << "Invalid entry in ledger";
return nullptr;
}
uint256 uIndex;
if (!uIndex.parseHex(entry[jss::index].asString()))
{
JLOG(m_journal.fatal()) << "Invalid entry in ledger";
return nullptr;
}
entry.removeMember(jss::index);
STParsedJSONObject stp("sle", ledger.get()[index]);
if (!stp.object || uIndex.isZero())
{
JLOG(m_journal.fatal()) << "Invalid entry in ledger";
return nullptr;
}
// VFALCO TODO This is the only place that
// constructor is used, try to remove it
STLedgerEntry sle(*stp.object, uIndex);
if (!loadLedger->addSLE(sle))
{
JLOG(m_journal.fatal())
<< "Couldn't add serialized ledger: " << uIndex;
return nullptr;
}
}
loadLedger->stateMap().flushDirty(hotACCOUNT_NODE);
assert(
loadLedger->info().seq < XRP_LEDGER_EARLIEST_FEES ||
loadLedger->read(keylet::fees()));
loadLedger->setAccepted(
closeTime, closeTimeResolution, !closeTimeEstimated);
return loadLedger;
}
catch (std::exception const& x)
{
JLOG(m_journal.fatal()) << "Ledger contains invalid data: " << x.what();
return nullptr;
}
}
bool
ApplicationImp::loadOldLedger(
std::string const& ledgerID,
bool replay,
bool isFileName)
bool isFileName,
bool isJson)
{
try
{
std::shared_ptr<Ledger const> loadLedger, replayLedger;
if (isFileName)
if (isJson)
{
if (!ledgerID.empty())
loadLedger = loadLedgerFromJson(ledgerID);
}
else if (isFileName)
{
if (!ledgerID.empty())
loadLedger = loadLedgerFromFile(ledgerID);
@@ -1999,7 +2139,7 @@ ApplicationImp::loadOldLedger(
using namespace std::chrono_literals;
using namespace date;
static constexpr NetClock::time_point ledgerWarnTimePoint{
sys_days{January / 1 / 2018} - sys_days{January / 1 / 2000}};
sys_days{January / 1 / 2000} - sys_days{January / 1 / 2000}};
if (loadLedger->info().closeTime < ledgerWarnTimePoint)
{
JLOG(m_journal.fatal())

View File

@@ -153,7 +153,7 @@ public:
std::map<std::string, PublicKey> IMPORT_VL_KEYS; // hex string -> class PublicKey (for caching purposes)
enum StartUpType { FRESH, NORMAL, LOAD, LOAD_FILE, REPLAY, NETWORK };
enum StartUpType { FRESH, NORMAL, LOAD, LOAD_FILE, REPLAY, NETWORK, LOAD_JSON };
StartUpType START_UP = NORMAL;
bool START_VALID = false;

View File

@@ -1158,10 +1158,10 @@ std::string ImportTCPayment::w_seed = R"json({
class ImportTCHalving
{
public:
static std::string one_one;
static std::string base_genesis;
};
std::string ImportTCHalving::one_one = R"json({
std::string ImportTCHalving::base_genesis = R"json({
"ledger": {
"accepted": true,
"accountState": [
@@ -1177,56 +1177,20 @@ std::string ImportTCHalving::one_one = R"json({
"index": "2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8"
},
{
"Amendments": [
"740352F2412A9909880C23A559FCECEDA3BE2126FED62FC7660D628A06927F11",
"3012E8230864E95A58C60FD61430D7E1B4D3353195F2981DC12B0C7C0950FFAC",
"67A34F2CF55BFC0F93AACD5B281413176FEE195269FA6D95219A2DF738671172",
"F64E1EABBE79D55B3BB82020516CEC2C582A98A6BFE20FBE9BB6A0D233418064",
"157D2D480E006395B76F948E3E07A45A05FE10230D88A7993C71F97AE4B1F2D1",
"7117E2EC2DBF119CA55181D69819F1999ECEE1A0225A7FD2B9ED47940968479C",
"CA7C02118BA27599528543DFE77BA6838D1B0F43B447D4D7F53523CE6A0E9AC2",
"58BE9B5968C4DA7C59BA900961828B113E5490699B21877DEF9A31E9D0FE5D5F",
"3CBC5C4E630A1B82380295CDA84B32B49DD066602E74E39B85EF64137FA65194",
"5D08145F0A4983F23AFFFF514E83FAD355C5ABFBB6CAB76FB5BC8519FF5F33BE",
"FBD513F1B893AC765B78F250E6FFA6A11B573209D1842ADC787C850696741288",
"586480873651E106F1D6339B0C4A8945BA705A777F3F4524626FF1FC07EFE41D",
"2CD5286D8D687E98B41102BDD797198E81EA41DF7BD104E6561FEB104EFF2561",
"C4483A1896170C66C098DEA5B0E024309C60DC960DE5F01CD7AF986AA3D9AD37",
"8F81B066ED20DAECA20DF57187767685EEF3980B228E0667A650BAF24426D3B4",
"621A0B264970359869E3C0363A899909AAB7A887C8B73519E4ECF952D33258A8",
"89308AF3B8B10B7192C4E613E1D2E4D9BA64B2EE2D5232402AE82A6A7220D953",
"00C1FC4A53E60AB02C864641002B3172F38677E29C26C5406685179B37E1EDAC",
"25BA44241B3BD880770BFA4DA21C7180576831855368CBEC6A3154FDE4A7676E",
"1F4AFA8FA1BC8827AD4C0F682C03A8B671DCDF6B5C4DE36D44243A684103EF88",
"4F46DF03559967AC60F2EB272FEFE3928A7594A45FF774B87A7E540DB0F8F068",
"B4E4F5D2D6FB84DF7399960A732309C9FD530EAE5941838160042833625A6076",
"955DF3FA5891195A9DAEFA1DDC6BB244B545DDE1BAA84CBB25D5F12A8DA68A0C",
"AF8DF7465C338AE64B1E937D6C8DA138C0D63AD5134A68792BBBE1F63356C422",
"452F5906C46D46F407883344BFDD90E672B672C5E9943DB4891E3A34FEEEB9DB",
"B6B3EEDC0267AB50491FDC450A398AF30DBCD977CECED8BEF2499CAB5DAC19E2",
"98DECF327BF79997AEC178323AD51A830E457BFC6D454DAF3E46E5EC42DC619F",
"B2A4DB846F0891BF2C76AB2F2ACC8F5B4EC64437135C6E56F3F859DE5FFD5856",
"32A122F1352A4C7B3A6D790362CC34749C5E57FCE896377BFDC6CCD14F6CD627",
"F1ED6B4A411D8B872E65B9DCB4C8B100375B0DD3D62D07192E011D6D7F339013",
"75A7E01C505DD5A179DFE3E000A9B6F1EDDEB55A12F95579A23E15B15DC8BE5A",
"47C3002ABA31628447E8E9A8B315FAA935CE30183F9A9B86845E469CA2CDC3DF",
"93E516234E35E08CA689FA33A6D38E103881F8DCB53023F728C307AA89D515A7",
"2E2FB9CF8A44EB80F4694D38AADAE9B8B7ADAFD2F092E10068E61C98C4F092B0",
"73761231F7F3D94EC3D8C63D91BDD0D89045C6F71B917D1925C01253515A6669",
"AE35ABDEFBDE520372B31C957020B34A7A4A9DC3115A69803A44016477C84D6E",
"ECE6819DBA5DB528F1A241695F5A9811EF99467CDE22510954FD357780BBD078",
"42F8B586B357ABBAAAA1C733C3E7D3B75761395340D0CDF600179E8737E22478",
"919857E4B902A20216E4819B9BD9FD1FD19A66ECF63151C18A4C48C873DB9578",
"ECF412BE0964EC2E71DCF807EEEA6EA8470D3DB15173D46F28AB6E234860AC32",
"86E83A7D2ECE3AD5FA87AB2195AE015C950469ABF0B72EAACED318F74886AE90",
"3C43D9A973AA4443EF3FC38E42DD306160FBFFDAB901CD8BAA15D09F2597EB87",
"0285B7E5E08E1A8E4C15636F0591D87F73CB6A7B6452A932AD72BBC8E5D1CBE3",
"36799EA497B1369B170805C078AEFE6188345F9B3E324C21E9CA3FF574E3C3D6",
"F5751842D26FC057B92CAA435ABF4F1428C2BCC4180D18775ADE92CB2643BBA3"
],
"Amendments": [],
"Flags": 0,
"LedgerEntryType": "Amendments",
"index": "7DB0788C020F02780A673DC74757F23823FA3014C1866E72CC4CD8B226CD6EF4"
},
{
"BaseFee": "A",
"Flags": 0,
"LedgerEntryType": "FeeSettings",
"ReferenceFeeUnits": 10,
"ReserveBase": 1000000,
"ReserveIncrement": 200000,
"XahauActivationLgrSeq": 0,
"index": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A651"
}
],
"account_hash": "5DF3A98772FB73E782B8740E87885C6BAD9BA486422E3626DEF968AD2CB2C514",
@@ -1237,16 +1201,16 @@ std::string ImportTCHalving::one_one = R"json({
"closed": true,
"hash": "56DA0940767AC2F17F0E384F04816002403D0756432B9D503DDA20128A2AAF11",
"ledger_hash": "56DA0940767AC2F17F0E384F04816002403D0756432B9D503DDA20128A2AAF11",
"ledger_index": "1999998",
"ledger_index": "0",
"parent_close_time": 0,
"parent_hash": "56DA0940767AC2F17F0E384F04816002403D0756432B9D503DDA20128A2AAF11",
"seqNum": "1999998",
"seqNum": "0",
"totalCoins": "0",
"total_coins": "0",
"transaction_hash": "9A77D1D1A4B36DA77B9C4DC63FDEB8F821741D157802F9C42A6ED86003D8B4A0",
"transactions": []
},
"ledger_current_index": 1999998,
"ledger_current_index": 0,
"status": "success",
"validated": true
})json";

View File

@@ -29,6 +29,7 @@
#include <ripple/protocol/jss.h>
#include <test/jtx.h>
#include <test/app/Import_json.h>
#include <ripple/app/misc/AmendmentTable.h>
#define BEAST_REQUIRE(x) \
{ \
@@ -4554,6 +4555,73 @@ class Import_test : public beast::unit_test::suite
});
}
std::unique_ptr<Config>
makeGenesisConfig(
FeatureBitset features,
uint32_t networkID,
std::string fee,
std::string a_res,
std::string o_res,
uint32_t ledgerID)
{
using namespace jtx;
// IMPORT VL KEY
std::vector<std::string> const keys = {
"ED74D4036C6591A4BDF9C54CEFA39B996A"
"5DCE5F86D11FDA1874481CE9D5A1CDC1"};
Json::Value jsonValue;
Json::Reader reader;
reader.parse(ImportTCHalving::base_genesis, jsonValue);
for (size_t i = 0; i < features.size(); ++i)
{
uint256 const& feature = bitsetIndexToFeature(i);
std::string featureName = featureToName(feature);
std::optional<uint256> featureHash = getRegisteredFeature(featureName);
if (featureHash.has_value() && feature != featureOwnerPaysFee)
{
std::string hashString = to_string(featureHash.value());
jsonValue["ledger"]["accountState"][1]["Amendments"].append(hashString);
}
}
jsonValue["ledger_current_index"] = ledgerID;
jsonValue["ledger"]["ledger_index"] = to_string(ledgerID);
jsonValue["ledger"]["seqNum"] = to_string(ledgerID);
return envconfig([&](std::unique_ptr<Config> cfg) {
cfg->NETWORK_ID = networkID;
cfg->START_LEDGER = jsonValue.toStyledString();
cfg->START_UP = Config::LOAD_JSON;
Section config;
config.append(
{"reference_fee = " + fee,
"account_reserve = " + a_res,
"owner_reserve = " + o_res});
auto setup = setup_FeeVote(config);
cfg->FEES = setup;
for (auto const& strPk : keys)
{
auto pkHex = strUnHex(strPk);
if (!pkHex)
Throw<std::runtime_error>(
"Import VL Key '" + strPk + "' was not valid hex.");
auto const pkType = publicKeyType(makeSlice(*pkHex));
if (!pkType)
Throw<std::runtime_error>(
"Import VL Key '" + strPk +
"' was not a valid key type.");
cfg->IMPORT_VL_KEYS.emplace(strPk, makeSlice(*pkHex));
}
return cfg;
});
}
void
testHalving(FeatureBitset features)
{
@@ -4562,16 +4630,17 @@ class Import_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
// Halving 1:1
// Halving @ ledger seq 1'999'999
{
test::jtx::Env env{
*this,
makeGenesisConfig(
features,
21337,
"10",
"1000000",
"200000",
"../src/test/app/halve_1_1.json"
1999998
)
};
@@ -4581,7 +4650,6 @@ class Import_test : public beast::unit_test::suite
auto initCoins = env.current()->info().drops;
BEAST_EXPECT(initCoins == 0);
auto initSeq = env.current()->info().seq;
std::cout << "initSeq: " << initSeq << "\n";
BEAST_EXPECT(initSeq == 1'999'999);
// init env
@@ -4593,7 +4661,7 @@ class Import_test : public beast::unit_test::suite
BEAST_EXPECT(preAlice == XRP(0));
// import tx
auto const xpopJson = loadXpop(ImportTCAccountSet::min);
auto const xpopJson = loadXpop(ImportTCAccountSet::w_seed);
Json::Value tx = import(alice, xpopJson);
tx[jss::Sequence] = 0;
tx[jss::Fee] = 0;
@@ -4601,8 +4669,361 @@ class Import_test : public beast::unit_test::suite
env.close();
// total burn = burn drops + Init Reward
auto const creditDrops = drops(10) + XRP(2);
std::cout << "creditDrops: " << creditDrops << "\n";
auto const creditDrops = XRP(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,
makeGenesisConfig(
features,
21337,
"10",
"1000000",
"200000",
1999998
)
};
auto const feeDrops = env.current()->fees().base;
// confirm total coins header
auto initCoins = env.current()->info().drops;
BEAST_EXPECT(initCoins == 0);
env.close();
auto 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 = loadXpop(ImportTCAccountSet::w_seed);
Json::Value tx = 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 = XRP(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,
makeGenesisConfig(
features,
21337,
"10",
"1000000",
"200000",
1999998
)
};
auto const feeDrops = env.current()->fees().base;
// confirm total coins header
auto initCoins = env.current()->info().drops;
BEAST_EXPECT(initCoins == 0);
env.close();
env.close();
auto 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 = loadXpop(ImportTCAccountSet::w_seed);
Json::Value tx = 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(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,
makeGenesisConfig(
features,
21337,
"10",
"1000000",
"200000",
4999999
)
};
auto const feeDrops = env.current()->fees().base;
// confirm total coins header
auto initCoins = env.current()->info().drops;
BEAST_EXPECT(initCoins == 0);
auto 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 = loadXpop(ImportTCAccountSet::w_seed);
Json::Value tx = 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(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,
makeGenesisConfig(
features,
21337,
"10",
"1000000",
"200000",
19999999
)
};
auto const feeDrops = env.current()->fees().base;
// confirm total coins header
auto initCoins = env.current()->info().drops;
BEAST_EXPECT(initCoins == 0);
auto 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 = loadXpop(ImportTCAccountSet::w_seed);
Json::Value tx = 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(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,
makeGenesisConfig(
features,
21337,
"10",
"1000000",
"200000",
29999998
)
};
auto const feeDrops = env.current()->fees().base;
// confirm total coins header
auto initCoins = env.current()->info().drops;
BEAST_EXPECT(initCoins == 0);
auto 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 = loadXpop(ImportTCAccountSet::w_seed);
Json::Value tx = 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(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,
makeGenesisConfig(
features,
21337,
"10",
"1000000",
"200000",
29999998
)
};
auto const feeDrops = env.current()->fees().base;
// confirm total coins header
auto initCoins = env.current()->info().drops;
BEAST_EXPECT(initCoins == 0);
env.close();
auto 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 = loadXpop(ImportTCAccountSet::w_seed);
Json::Value tx = 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,
makeGenesisConfig(
features,
21337,
"10",
"1000000",
"200000",
50000000
)
};
auto const feeDrops = env.current()->fees().base;
// confirm total coins header
auto initCoins = env.current()->info().drops;
BEAST_EXPECT(initCoins == 0);
auto 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 = loadXpop(ImportTCAccountSet::w_seed);
Json::Value tx = 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);
@@ -4614,7 +5035,6 @@ class Import_test : public beast::unit_test::suite
}
}
public:
void
run() override
@@ -4647,7 +5067,7 @@ public:
testImportSequence(features);
testMaxSupply(features);
testMinMax(features);
testHalving(features);
testHalving(features - featureOwnerPaysFee);
}
};