mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-04 18:55:49 +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& 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))
|
if (sle && sle->isFieldPresent(sfImportSequence))
|
||||||
{
|
{
|
||||||
uint32_t sleImportSequence = sle->getFieldU32(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
|
// 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
|
// 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.
|
// 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.
|
/** Amendments that this server supports and the default voting behavior.
|
||||||
Whether they are enabled depends on the Rules defined in the validated
|
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 fixPageCap;
|
||||||
extern uint256 const fix240911;
|
extern uint256 const fix240911;
|
||||||
extern uint256 const fixFloatDivide;
|
extern uint256 const fixFloatDivide;
|
||||||
|
extern uint256 const fixReduceImport;
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ enum TEFcodes : TERUnderlyingType {
|
|||||||
tefPAST_IMPORT_SEQ,
|
tefPAST_IMPORT_SEQ,
|
||||||
tefPAST_IMPORT_VL_SEQ,
|
tefPAST_IMPORT_VL_SEQ,
|
||||||
tefNONDIR_EMIT,
|
tefNONDIR_EMIT,
|
||||||
|
tefIMPORT_BLACKHOLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -468,6 +468,7 @@ REGISTER_FIX (fix240819, Supported::yes, VoteBehavior::De
|
|||||||
REGISTER_FIX (fixPageCap, Supported::yes, VoteBehavior::DefaultYes);
|
REGISTER_FIX (fixPageCap, Supported::yes, VoteBehavior::DefaultYes);
|
||||||
REGISTER_FIX (fix240911, Supported::yes, VoteBehavior::DefaultYes);
|
REGISTER_FIX (fix240911, Supported::yes, VoteBehavior::DefaultYes);
|
||||||
REGISTER_FIX (fixFloatDivide, 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
|
// The following amendments are obsolete, but must remain supported
|
||||||
// because they could potentially get enabled.
|
// because they could potentially get enabled.
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ transResults()
|
|||||||
MAKE_ERROR(tefNO_TICKET, "Ticket is not in ledger."),
|
MAKE_ERROR(tefNO_TICKET, "Ticket is not in ledger."),
|
||||||
MAKE_ERROR(tefNFTOKEN_IS_NOT_TRANSFERABLE, "The specified NFToken is not transferable."),
|
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(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(telLOCAL_ERROR, "Local failure."),
|
||||||
MAKE_ERROR(telBAD_DOMAIN, "Domain too long."),
|
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)
|
importVLSequence(jtx::Env const& env, PublicKey const& pk)
|
||||||
{
|
{
|
||||||
auto const sle = env.le(keylet::import_vlseq(pk));
|
auto const sle = env.le(keylet::import_vlseq(pk));
|
||||||
if (sle->isFieldPresent(sfImportSequence))
|
if (sle && sle->isFieldPresent(sfImportSequence))
|
||||||
return (*sle)[sfImportSequence];
|
return (*sle)[sfImportSequence];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2672,6 +2672,134 @@ class Import_test : public beast::unit_test::suite
|
|||||||
env(import::import(alice, tmpXpop), ter(temMALFORMED));
|
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
|
// tefPAST_IMPORT_SEQ
|
||||||
{
|
{
|
||||||
test::jtx::Env env{
|
test::jtx::Env env{
|
||||||
@@ -4580,14 +4708,22 @@ class Import_test : public beast::unit_test::suite
|
|||||||
// confirm signers set
|
// confirm signers set
|
||||||
auto const [signers, signersSle] =
|
auto const [signers, signersSle] =
|
||||||
signersKeyAndSle(*env.current(), alice);
|
signersKeyAndSle(*env.current(), alice);
|
||||||
auto const signerEntries =
|
|
||||||
signersSle->getFieldArray(sfSignerEntries);
|
|
||||||
BEAST_EXPECT(signerEntries.size() == 2);
|
|
||||||
BEAST_EXPECT(signerEntries[0u].getFieldU16(sfSignerWeight) == 1);
|
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
signerEntries[0u].getAccountID(sfAccount) == carol.id());
|
signersSle && signersSle->isFieldPresent(sfSignerEntries));
|
||||||
BEAST_EXPECT(signerEntries[1u].getFieldU16(sfSignerWeight) == 1);
|
if (signersSle && signersSle->isFieldPresent(sfSignerEntries))
|
||||||
BEAST_EXPECT(signerEntries[1u].getAccountID(sfAccount) == bob.id());
|
{
|
||||||
|
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
|
// confirm multisign tx
|
||||||
env.close();
|
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:
|
public:
|
||||||
void
|
void
|
||||||
run() override
|
run() override
|
||||||
@@ -6026,6 +6225,7 @@ public:
|
|||||||
testMaxSupply(features);
|
testMaxSupply(features);
|
||||||
testMinMax(features);
|
testMinMax(features);
|
||||||
testHalving(features - featureOwnerPaysFee);
|
testHalving(features - featureOwnerPaysFee);
|
||||||
|
testBlackhole(features);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user