moved acceptunlimitedissuances to chainparams and set defaults
What changed, and why it matters
This commit moves a network rule about unblinded asset issuances above 21 million units from a global node setting into per-chain parameters. Before the change, the default was to accept unlimited issuances globally. After the change, the default is to reject such issuances unless a chain explicitly opts in. This is a policy/consensus-adjacent change that could affect which transactions nodes accept, but it is not presented as a security fix and does not by itself create a new exploit.
Treat as a routine policy refactor with a behavior change in defaults. Operators relying on unblinded issuances above 21 million units should verify they now pass `-acceptunlimitedissuances=1` on the correct chain. Reviewers should confirm that custom chain parameter overrides behave as intended and that no consensus-critical path was altered.
Security signals we found
Default policy tightened: unblinded issuances exceeding MoneyRange are now rejected by default on all built-in chains.
Global mutable flag removed in favor of chain-parameter lookup, reducing risk of inconsistent policy state.
No bounds-check or parsing changes; the issuance range check itself is unchanged.
No explicit security relevance, CVE, or advisory language in commit or supplied references.
Evidence from the diff
The change relocates the acceptunlimitedissuances option from a global ArgsManager/fAcceptUnlimitedIssuances flag in init/validation to a per-chain parameter accept_unlimited_issuances in CChainParams. Defaults are set to false for the built-in chains (main, test, regtest, custom) except where explicitly configured. The mempool precheck now consults chainparams.GetAcceptUnlimitedIssuances() instead of the global flag. The functional test is updated so nodes 0 and 1 explicitly enable unlimited issuances while node 2 relies on the new default (false).
Changed components
src/chainparams.cppsrc/chainparams.hsrc/chainparamsbase.cppsrc/init.cppsrc/validation.cppsrc/validation.htest/functional/wallet_elements_21million.pyInspect captured patch +18 / −8
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 02ee914..4b51aca 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -227,6 +227,7 @@ public:
consensus.connect_genesis_outputs = false;
consensus.subsidy_asset = CAsset();
anyonecanspend_aremine = false;
+ accept_unlimited_issuances = false;
enforce_pak = false;
multi_data_permitted = false;
accept_discount_ct = false;
@@ -374,6 +375,7 @@ public:
consensus.subsidy_asset = CAsset();
anyonecanspend_aremine = false;
enforce_pak = false;
+ accept_unlimited_issuances = false;
multi_data_permitted = false;
accept_discount_ct = false;
create_discount_ct = false;
@@ -538,6 +540,7 @@ public:
consensus.subsidy_asset = CAsset();
anyonecanspend_aremine = false;
enforce_pak = false;
+ accept_unlimited_issuances = false;
multi_data_permitted = false;
accept_discount_ct = false;
create_discount_ct = false;
@@ -641,6 +644,7 @@ public:
consensus.subsidy_asset = CAsset();
anyonecanspend_aremine = false;
enforce_pak = false;
+ accept_unlimited_issuances = false;
multi_data_permitted = false;
accept_discount_ct = false;
create_discount_ct = false;
@@ -909,6 +913,8 @@ protected:
enforce_pak = args.GetBoolArg("-enforce_pak", false);
+ accept_unlimited_issuances = args.GetBoolArg("-acceptunlimitedissuances", false);
+
// Allow multiple op_return outputs by relay policy
multi_data_permitted = args.GetBoolArg("-multi_data_permitted", enforce_pak);
@@ -1167,6 +1173,8 @@ public:
enforce_pak = true;
+ accept_unlimited_issuances = false;
+
multi_data_permitted = true;
create_discount_ct = args.GetBoolArg("-creatediscountct", false);
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", true) || create_discount_ct;
@@ -1525,6 +1533,8 @@ public:
enforce_pak = args.GetBoolArg("-enforce_pak", enforce_pak);
+ accept_unlimited_issuances = false;
+
multi_data_permitted = args.GetBoolArg("-multi_data_permitted", multi_data_permitted);
create_discount_ct = args.GetBoolArg("-creatediscountct", create_discount_ct);
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", accept_discount_ct) || create_discount_ct;
diff --git a/src/chainparams.h b/src/chainparams.h
index a80807a..840a22b 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -134,6 +134,7 @@ public:
const std::string& ParentBech32HRP() const { return parent_bech32_hrp; }
const std::string& ParentBlech32HRP() const { return parent_blech32_hrp; }
bool GetEnforcePak() const { return enforce_pak; }
+ bool GetAcceptUnlimitedIssuances() const { return accept_unlimited_issuances; }
bool GetMultiDataPermitted() const { return multi_data_permitted; }
bool GetAcceptDiscountCT() const { return accept_discount_ct; }
bool GetCreateDiscountCT() const { return create_discount_ct; }
@@ -168,6 +169,7 @@ protected:
std::string parent_bech32_hrp;
std::string parent_blech32_hrp;
bool enforce_pak;
+ bool accept_unlimited_issuances;
bool multi_data_permitted;
bool accept_discount_ct;
bool create_discount_ct;
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index e3eb7dd..40a1078 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -61,6 +61,7 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman)
argsman.AddArg("-total_valid_epochs", "Per-chain parameter that sets how long a particular fedpegscript is in effect for.", ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
argsman.AddArg("-evbparams=deployment:start:end:period:threshold", "Use given start/end times for specified version bits deployment (regtest or custom only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::ELEMENTS);
argsman.AddArg("-con_start_p2wsh_script", "Create p2wsh addresses when starting in dynafed mode (regtest or custom only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::ELEMENTS);
+ argsman.AddArg("-acceptunlimitedissuances", "Allow unblinded issuance amounts to exceed 21 million units", ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
// END ELEMENTS
//
}
diff --git a/src/init.cpp b/src/init.cpp
index 714b517..27addf2 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -621,7 +621,6 @@ void SetupServerArgs(ArgsManager& argsman)
std::vector<std::string> elements_hidden_args = {"-con_fpowallowmindifficultyblocks", "-con_fpownoretargeting", "-con_nsubsidyhalvinginterval", "-con_bip16exception", "-con_bip34height", "-con_bip65height", "-con_bip66height", "-con_npowtargettimespan", "-con_npowtargetspacing", "-con_nrulechangeactivationthreshold", "-con_nminerconfirmationwindow", "-con_powlimit", "-con_bip34hash", "-con_nminimumchainwork", "-con_defaultassumevalid", "-npruneafterheight", "-fdefaultconsistencychecks", "-fmineblocksondemand", "-fallback_fee_enabled", "-pchmessagestart"};
- argsman.AddArg("-acceptunlimitedissuances", strprintf("Relay and mine unblinded issuance transactions (default: %u)", DEFAULT_ACCEPT_UNLIMITED_ISSUANCES), ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
argsman.AddArg("-initialfreecoins", strprintf("The amount of OP_TRUE coins created in the genesis block. Primarily for testing. (default: %d)", 0), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-validatepegin", "Validate peg-in claims. An RPC connection will be attempted to the trusted mainchain daemon using the `mainchain*` settings below. All functionaries must run this enabled. (default: 1 if chain has federated peg)", ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
argsman.AddArg("-mainchainrpchost=<host>", "The address which the daemon will try to connect to the trusted mainchain daemon to validate peg-ins, if enabled. (default: 127.0.0.1)", ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
@@ -1077,7 +1076,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
fIsBareMultisigStd = args.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
fAcceptDatacarrier = args.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
nMaxDatacarrierBytes = args.GetIntArg("-datacarriersize", nMaxDatacarrierBytes);
- fAcceptUnlimitedIssuances = args.GetBoolArg("-acceptunlimitedissuances", DEFAULT_ACCEPT_UNLIMITED_ISSUANCES);
// Option to startup with mocktime set (used for regression testing):
SetMockTime(args.GetIntArg("-mocktime", 0)); // SetMockTime(0) is a no-op
diff --git a/src/validation.cpp b/src/validation.cpp
index a566ccd..6ac82e3 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -151,7 +151,6 @@ bool g_parallel_script_checks{false};
bool fRequireStandard = true;
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
-bool fAcceptUnlimitedIssuances = true;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
uint256 hashAssumeValid;
@@ -724,8 +723,9 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
// Check unblinded issuance is in MoneyRange if configured
- if (!fAcceptUnlimitedIssuances && !IsIssuanceInMoneyRange(tx))
+ if (!chainparams.GetAcceptUnlimitedIssuances() && !IsIssuanceInMoneyRange(tx)) {
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "issuance-out-of-range", "Issuance is greater than 21 million and acceptunlimitedissuances is not enabled.");
+ }
// Do not work on transactions that are too small.
// A transaction with 1 segwit input and 1 P2WPHK output has non-witness size of 82 bytes.
diff --git a/src/validation.h b/src/validation.h
index f66ea65..78fa8be 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -130,7 +130,6 @@ extern bool g_parallel_script_checks;
extern bool fRequireStandard;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
-extern bool fAcceptUnlimitedIssuances;
/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
extern CFeeRate minRelayTxFee;
/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
diff --git a/test/functional/wallet_elements_21million.py b/test/functional/wallet_elements_21million.py
index 063832d..fb4d4a4 100755
--- a/test/functional/wallet_elements_21million.py
+++ b/test/functional/wallet_elements_21million.py
@@ -18,9 +18,9 @@ class WalletTest(BitcoinTestFramework):
"-blindedaddresses=1"
]
self.extra_args = [
- args,
- args,
- args + ["-acceptunlimitedissuances=0"], # node 2 blocks unblinded issuances out of moneyrange
+ args + ["-acceptunlimitedissuances=1"],
+ args + ["-acceptunlimitedissuances=1"],
+ args, # node 2 blocks unblinded issuances out of moneyrange
]
def setup_network(self, split=False):
Why this scored 36/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.