mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-04 10:45:50 +00:00
fixReduceImport (#398)
Co-authored-by: Denis Angell <dangell@transia.co>
This commit is contained in:
@@ -889,6 +889,45 @@ Import::preclaim(PreclaimContext const& ctx)
|
||||
}
|
||||
|
||||
auto const& sle = ctx.view.read(keylet::account(ctx.tx[sfAccount]));
|
||||
|
||||
auto const tt = stpTrans->getTxnType();
|
||||
if ((tt == ttSIGNER_LIST_SET || tt == ttREGULAR_KEY_SET) &&
|
||||
ctx.view.rules().enabled(fixReduceImport) && sle)
|
||||
{
|
||||
// blackhole check
|
||||
do
|
||||
{
|
||||
// if master key is not set then it is not blackholed
|
||||
if (!(sle->getFlags() & lsfDisableMaster))
|
||||
break;
|
||||
|
||||
// if a regular key is set then it must be acc 0, 1, or 2 otherwise
|
||||
// not blackholed
|
||||
if (sle->isFieldPresent(sfRegularKey))
|
||||
{
|
||||
AccountID rk = sle->getAccountID(sfRegularKey);
|
||||
static const AccountID ACCOUNT_ZERO(0);
|
||||
static const AccountID ACCOUNT_ONE(1);
|
||||
static const AccountID ACCOUNT_TWO(2);
|
||||
|
||||
if (rk != ACCOUNT_ZERO && rk != ACCOUNT_ONE &&
|
||||
rk != ACCOUNT_TWO)
|
||||
break;
|
||||
}
|
||||
|
||||
// if a signer list is set then it's not blackholed
|
||||
auto const signerListKeylet = keylet::signers(ctx.tx[sfAccount]);
|
||||
if (ctx.view.exists(signerListKeylet))
|
||||
break;
|
||||
|
||||
// execution to here means it's blackholed
|
||||
JLOG(ctx.j.warn())
|
||||
<< "Import: during preclaim target account is blackholed "
|
||||
<< ctx.tx[sfAccount] << ", bailing.";
|
||||
return tefIMPORT_BLACKHOLED;
|
||||
} while (0);
|
||||
}
|
||||
|
||||
if (sle && sle->isFieldPresent(sfImportSequence))
|
||||
{
|
||||
uint32_t sleImportSequence = sle->getFieldU32(sfImportSequence);
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace detail {
|
||||
// Feature.cpp. Because it's only used to reserve storage, and determine how
|
||||
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
|
||||
// the actual number of amendments. A LogicError on startup will verify this.
|
||||
static constexpr std::size_t numFeatures = 74;
|
||||
static constexpr std::size_t numFeatures = 75;
|
||||
|
||||
/** Amendments that this server supports and the default voting behavior.
|
||||
Whether they are enabled depends on the Rules defined in the validated
|
||||
@@ -362,6 +362,7 @@ extern uint256 const fix240819;
|
||||
extern uint256 const fixPageCap;
|
||||
extern uint256 const fix240911;
|
||||
extern uint256 const fixFloatDivide;
|
||||
extern uint256 const fixReduceImport;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
|
||||
@@ -184,6 +184,7 @@ enum TEFcodes : TERUnderlyingType {
|
||||
tefPAST_IMPORT_SEQ,
|
||||
tefPAST_IMPORT_VL_SEQ,
|
||||
tefNONDIR_EMIT,
|
||||
tefIMPORT_BLACKHOLED,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -468,6 +468,7 @@ REGISTER_FIX (fix240819, Supported::yes, VoteBehavior::De
|
||||
REGISTER_FIX (fixPageCap, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fix240911, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fixFloatDivide, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fixReduceImport, Supported::yes, VoteBehavior::DefaultYes);
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
// because they could potentially get enabled.
|
||||
|
||||
@@ -116,6 +116,7 @@ transResults()
|
||||
MAKE_ERROR(tefNO_TICKET, "Ticket is not in ledger."),
|
||||
MAKE_ERROR(tefNFTOKEN_IS_NOT_TRANSFERABLE, "The specified NFToken is not transferable."),
|
||||
MAKE_ERROR(tefNONDIR_EMIT, "An emitted txn was injected into the ledger without a corresponding directory entry."),
|
||||
MAKE_ERROR(tefIMPORT_BLACKHOLED, "Cannot import keying because target account is blackholed."),
|
||||
|
||||
MAKE_ERROR(telLOCAL_ERROR, "Local failure."),
|
||||
MAKE_ERROR(telBAD_DOMAIN, "Domain too long."),
|
||||
|
||||
@@ -79,7 +79,7 @@ class Import_test : public beast::unit_test::suite
|
||||
importVLSequence(jtx::Env const& env, PublicKey const& pk)
|
||||
{
|
||||
auto const sle = env.le(keylet::import_vlseq(pk));
|
||||
if (sle->isFieldPresent(sfImportSequence))
|
||||
if (sle && sle->isFieldPresent(sfImportSequence))
|
||||
return (*sle)[sfImportSequence];
|
||||
return 0;
|
||||
}
|
||||
@@ -2672,6 +2672,134 @@ class Import_test : public beast::unit_test::suite
|
||||
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{
|
||||
@@ -4580,14 +4708,22 @@ class Import_test : public beast::unit_test::suite
|
||||
// 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());
|
||||
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();
|
||||
@@ -5986,6 +6122,69 @@ class Import_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@@ -6026,6 +6225,7 @@ public:
|
||||
testMaxSupply(features);
|
||||
testMinMax(features);
|
||||
testHalving(features - featureOwnerPaysFee);
|
||||
testBlackhole(features);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user