Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
11c8140
Merge dashpay/dash#8019: fix(qt): stop reporting refused shared maste…
PastaPastaPasta Nov 3, 2026
0e3f653
docs: correct operator guidance in the v24.0.0 release notes for rc.7
PastaPastaPasta Nov 3, 2026
2fe41fb
docs: add ecosystem notes on Asset Unlock txids, coinbase payees and …
PastaPastaPasta Nov 3, 2026
3af6f63
Merge bitcoin/bitcoin#28038: wallet: address book migration bug fixes
DCG-Claude Oct 13, 2026
608ff63
Merge bitcoin/bitcoin#28542: wallet: Check for uninitialized last pro…
DCG-Claude Sep 28, 2026
1b1ea95
Merge dashpay/dash#8014: backport: bitcoin/bitcoin#28609, #34215, #34…
PastaPastaPasta Nov 3, 2026
6030ea0
docs: add the #8014 migratewallet fixes to the v24.0.0 release notes
PastaPastaPasta Nov 3, 2026
e33d9b1
Merge dashpay/dash#8037: docs: list the config file path each Linux i…
knst Nov 3, 2026
2b5bf30
Merge dashpay/dash#8029: fix: let dashd -version, -help and first sta…
PastaPastaPasta Nov 3, 2026
df6083a
Merge dashpay/dash#8032: fix(qt): don't offer a new operator key when…
PastaPastaPasta Nov 3, 2026
6a5d2dc
Merge dashpay/dash#8035: fix(qt): don't strand coins reserved for a s…
PastaPastaPasta Nov 3, 2026
0026e3e
Merge dashpay/dash#8027: fix(qt): fund a shared masternode's service …
PastaPastaPasta Nov 3, 2026
974aaa3
Merge dashpay/dash#8034: fix(qt): check a shared masternode's service…
PastaPastaPasta Nov 3, 2026
590ad0a
Merge dashpay/dash#8021: fix(qt): don't load a newer shared masternod…
PastaPastaPasta Nov 3, 2026
246a465
Merge dashpay/dash#8024: fix(qt): keep the shared masternode dissolve…
PastaPastaPasta Nov 3, 2026
9fa3df3
Merge dashpay/dash#8020: fix(rpc): make protx shared_sign sign only d…
PastaPastaPasta Nov 3, 2026
e1b826e
Merge dashpay/dash#8026: fix(qt): keep shared masternode contribution…
PastaPastaPasta Nov 3, 2026
775d31c
Merge dashpay/dash#8018: fix(consensus): require IPv4 masternode prim…
PastaPastaPasta Nov 3, 2026
62d0cef
Merge dashpay/dash#8036: fix(qt): let a shared masternode participant…
PastaPastaPasta Nov 3, 2026
0127df8
Merge #8045: test: scale the mempool-loaded wait by timeout_factor so…
PastaPastaPasta Nov 4, 2026
4d17947
Merge bitcoin/bitcoin#25193: indexes: Read the locator's top block du…
knst May 17, 2023
8e0b1e8
partial Merge bitcoin/bitcoin#32069: test: fix intermittent failure i…
knst Nov 3, 2026
94f5c58
partial Merge bitcoin/bitcoin#30221: wallet: Ensure best block matche…
knst Nov 3, 2026
31c7d8f
partial Merge bitcoin/bitcoin#32580: wallet, test: best block locator…
knst Nov 3, 2026
d5ff431
Merge bitcoin/bitcoin#32878: index: fix wrong assert of current_tip =…
knst Nov 3, 2026
bb724c6
Merge bitcoin/bitcoin#33212: index: Don't commit state in BaseIndex::…
knst Nov 3, 2026
399125c
Merge bitcoin/bitcoin#32882: index: remove unnecessary locator cleani…
knst Nov 3, 2026
3eba84c
Merge bitcoin/bitcoin#32875: index: handle case where pindex_prev equ…
knst Nov 3, 2026
2edeb98
partial Merge bitcoin/bitcoin#34897: indexes: Don't commit ahead of t…
knst Nov 3, 2026
e9f9c8a
Merge bitcoin/bitcoin#36150: indexes: set prune lock to genesis befor…
knst Nov 3, 2026
252acbe
fix(index): move the committed locator below the entries a rewind erases
knst Nov 3, 2026
2dbf5ca
fix(index): write a rewound block's erasures in one batch with its lo…
PastaPastaPasta Nov 3, 2026
baff347
fix(index): resume from the tip a skipped commit leaves behind
PastaPastaPasta Nov 3, 2026
9198962
fix(index): check the blocks governance resumes from at startup
PastaPastaPasta Nov 4, 2026
e3bafdb
fix(index): reject an uncommitted tip the block index lost
PastaPastaPasta Nov 4, 2026
d2f2a1f
fix(index): don't adopt an empty or rebuilt async index as migrated l…
PastaPastaPasta Nov 3, 2026
19a90bb
test: blocks orphaned while the address index is disabled are removed…
PastaPastaPasta Nov 3, 2026
ad4e5d6
docs: drop the index caveat from the -reindex-chainstate man page entry
PastaPastaPasta Nov 3, 2026
8aa11f6
docs: add the v24.0.0-rc.7 picks and index fixes to the v24.0.0 relea…
PastaPastaPasta Nov 4, 2026
2bf133c
docs: cite #8042 for the index fixes in the v24.0.0 release notes
PastaPastaPasta Nov 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions doc/init.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ Paths
All three configurations assume several paths that might need to be adjusted.

Binary: /usr/bin/dashd
Configuration file: /etc/dashcore/dash.conf
Configuration file: /etc/dash/dash.conf (systemd), /etc/dashcore/dash.conf (OpenRC and Upstart)
or <datadir>/dash.conf (CentOS, whose init script passes no -conf)
Data directory: /var/lib/dashd
PID file: /var/run/dashd/dashd.pid (OpenRC and Upstart) or /run/dashd/dashd.pid (systemd)
Lock file: /var/lock/subsys/dashd (CentOS)
Expand All @@ -73,10 +74,10 @@ dashcore user and group to do so. This does not allow
for the listing of files under the directory.

NOTE: It is not currently possible to override `datadir` in
`/etc/dash/dash.conf` with the current systemd, OpenRC, and Upstart init
the configuration file with the current systemd, OpenRC, and Upstart init
files out-of-the-box. This is because the command line options specified in the
init files take precedence over the configurations in
`/etc/dash/dash.conf`. However, some init systems have their own
the configuration file. However, some init systems have their own
configuration mechanisms that would allow for overriding the command line
options specified in the init files (e.g. setting `BITCOIND_DATADIR` for
OpenRC).
Expand Down
2 changes: 1 addition & 1 deletion doc/man/dash-qt.1
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ This will also rebuild active optional indexes.
.IP
Rebuild chain state from the currently indexed blocks. When in pruning
mode or if blocks on disk might be corrupted, use full \fB\-reindex\fR
instead. Deactivate all optional indexes before running this.
instead.
.HP
\fB\-spentindex\fR
.IP
Expand Down
2 changes: 1 addition & 1 deletion doc/man/dashd.1
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ This will also rebuild active optional indexes.
.IP
Rebuild chain state from the currently indexed blocks. When in pruning
mode or if blocks on disk might be corrupted, use full \fB\-reindex\fR
instead. Deactivate all optional indexes before running this.
instead.
.HP
\fB\-spentindex\fR
.IP
Expand Down
202 changes: 182 additions & 20 deletions doc/release-notes.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ BITCOIN_TESTS =\
test/base32_tests.cpp \
test/base58_tests.cpp \
test/base64_tests.cpp \
test/baseindex_tests.cpp \
test/bech32_tests.cpp \
test/bip32_tests.cpp \
test/bip324_tests.cpp \
Expand Down Expand Up @@ -138,6 +139,7 @@ BITCOIN_TESTS =\
test/hash_tests.cpp \
test/httpserver_tests.cpp \
test/i2p_tests.cpp \
test/index_migration_tests.cpp \
test/interfaces_tests.cpp \
test/key_io_tests.cpp \
test/key_tests.cpp \
Expand Down
8 changes: 7 additions & 1 deletion src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ class CMainParams : public CChainParams {
consensus.V20Height = 1987776; // 000000000000001bf41cff06b76780050682ca29e61a91c391893d4745579777
consensus.MN_RRHeight = 2128896; // 0000000000000009a9696da93d3807eb14eb00a4ff449206d689156a21b27f26
consensus.WithdrawalsHeight = 2201472; // 00000000000000210518749e17c00b035a2a4982c906236c28c41ea2231bf7ef
consensus.IPv4OptionalHeight = std::numeric_limits<int>::max(); // Not scheduled
consensus.MinBIP9WarningHeight = 2201472 + 2016; // withdrawals activation height + miner confirmation window
consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 20
consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day
Expand Down Expand Up @@ -405,6 +406,7 @@ class CTestNetParams : public CChainParams {
consensus.V20Height = 905100; // 0000020c5e0f86f385cbf8e90210de9a9fd63633f01433bf47a6b3227a2851fd
consensus.MN_RRHeight = 1066900; // 000000d05d445958a9a4ad6bdc0f4bfb25af124b2326060703373ff2d3b397e9
consensus.WithdrawalsHeight = 1148500; // 000000212a6fec2ee2af040c6d7a176360b154cbaa998888170cfd9ae7dd632d
consensus.IPv4OptionalHeight = 0; // Version 3 ProTxs without IPv4 primary addresses are already mined
consensus.MinBIP9WarningHeight = 1148500 + 2016; // withdrawals activation height + miner confirmation window
consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 20
consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day
Expand Down Expand Up @@ -589,6 +591,7 @@ class CDevNetParams : public CChainParams {
consensus.V20Height = 2; // V20 activated immediately on devnet
consensus.MN_RRHeight = 2; // MN_RR activated immediately on devnet
consensus.WithdrawalsHeight = 2; // withdrawals activated immediately on devnet
consensus.IPv4OptionalHeight = 0; // same as testnet
consensus.MinBIP9WarningHeight = 2 + 2016; // withdrawals activation height + miner confirmation window
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1
consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day
Expand Down Expand Up @@ -833,6 +836,7 @@ class CRegTestParams : public CChainParams {
consensus.V20Height = consensus.DIP0003Height; // Active not earlier than dip0003. Functional tests (DashTestFramework) uses height 100 (same as coinbase maturity)
consensus.MN_RRHeight = consensus.V20Height; // MN_RR does not really have effect before v20 activation
consensus.WithdrawalsHeight = 600;
consensus.IPv4OptionalHeight = std::numeric_limits<int>::max(); // see -testactivationheight
consensus.MinBIP9WarningHeight = 0;
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1
consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day
Expand Down Expand Up @@ -1082,6 +1086,8 @@ static void MaybeUpdateHeights(const ArgsManager& args, Consensus::Params& conse
consensus.V20Height = int{height};
} else if (name == "mn_rr") {
consensus.MN_RRHeight = int{height};
} else if (name == "ipv4_optional") {
consensus.IPv4OptionalHeight = int{height};
} else {
throw std::runtime_error(strprintf("Invalid name (%s) for -testactivationheight=name@height.", arg));
}
Expand Down Expand Up @@ -1444,7 +1450,7 @@ void SetupChainParamsOptions(ArgsManager& argsman)
argsman.AddArg("-llmqtestplatformparams=<size>:<threshold>", "Override the default LLMQ size for the LLMQ_TEST_PLATFORM quorum (default: 3:2, regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-minimumdifficultyblocks=<n>", "The number of blocks that can be mined with the minimum difficulty at the start of a chain (default: 0, devnet-only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-powtargetspacing=<n>", "Override the default PowTargetSpacing value in seconds (default: 2.5 minutes, devnet-only)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (bip147, bip34, dersig, cltv, csv, brr, dip0001, dip0008, dip0024, v19, v20, mn_rr). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (bip147, bip34, dersig, cltv, csv, brr, dip0001, dip0008, dip0024, v19, v20, mn_rr, ipv4_optional). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-vbparams=<deployment>:<start>:<end>(:min_activation_height(:<window>:<threshold/thresholdstart>(:<thresholdmin>:<falloffcoeff>:<mnactivation>)))",
"Use given start/end times and min_activation_height for specified version bits deployment (regtest-only). "
"Specifying window, threshold/thresholdstart, thresholdmin, falloffcoeff and mnactivation is optional.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
Expand Down
11 changes: 10 additions & 1 deletion src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ enum BuriedDeployment : int16_t {
DEPLOYMENT_V20,
DEPLOYMENT_MN_RR,
DEPLOYMENT_WITHDRAWALS,
DEPLOYMENT_IPV4_OPTIONAL, // Masternodes may operate without IPv4
};
constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_WITHDRAWALS; }
constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_IPV4_OPTIONAL; }

enum DeploymentPos : uint16_t {
DEPLOYMENT_TESTDUMMY,
Expand Down Expand Up @@ -151,6 +152,12 @@ struct Params {
int MN_RRHeight;
/** Block height at which WITHDRAWALS (Deployment of quorum fix and higher limits for withdrawals) becomes active */
int WithdrawalsHeight;
/** Block height from which a masternode's primary addresses no longer need to be IPv4.
* std::numeric_limits<int>::max() while no activation is scheduled. A placeholder: a version bits (EHF)
* deployment replacing it must stay always active on testnet and devnets. The mainnet primary port pins
* don't depend on it, so a first entry that can't use the standard port (such as I2P, which uses port 0)
* stays invalid there. */
int IPv4OptionalHeight;
/** Don't warn about unknown BIP 9 activations below this height.
* This prevents us from warning about the CSV and DIP activations. */
int MinBIP9WarningHeight;
Expand Down Expand Up @@ -232,6 +239,8 @@ struct Params {
return MN_RRHeight;
case DEPLOYMENT_WITHDRAWALS:
return WithdrawalsHeight;
case DEPLOYMENT_IPV4_OPTIONAL:
return IPv4OptionalHeight;
} // no default case, so the compiler can warn about missing cases
return std::numeric_limits<int>::max();
}
Expand Down
2 changes: 2 additions & 0 deletions src/deploymentinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ std::string DeploymentName(Consensus::BuriedDeployment dep)
return "mn_rr";
case Consensus::DEPLOYMENT_WITHDRAWALS:
return "withdrawals";
case Consensus::DEPLOYMENT_IPV4_OPTIONAL:
return "ipv4_optional";
} // no default case, so the compiler can warn about missing cases
return "";
}
10 changes: 3 additions & 7 deletions src/evo/core_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,9 @@ template UniValue GetNetInfoWithLegacyFields(const CDeterministicMNState& obj, c
template <bool is_p2p, typename Obj>
int32_t GetPlatformPort(const Obj& obj)
{
// Currently, there is nothing that prevents PLATFORM_{HTTPS,P2P} to be registered to
// an addr *different* from the primary addr for CORE_P2P. This breaks the assumptions
// under which platform{HTTP,P2P}Port operate under (i.e. all three are hosted with the
// same addr).
//
// TODO: Introduce restrictions that enforce this assumption *until* we remove legacy
// fields for good.
// Until DEPLOYMENT_IPV4_OPTIONAL is active, consensus requires the first PLATFORM_{HTTPS,P2P} entries to
// use the primary addr for CORE_P2P, as platform{HTTP,P2P}Port assume (i.e. all three are hosted with the
// same addr). Once it is (always on testnet and devnets), the ports reported here may belong to another addr.
//
bool is_legacy{!(CHECK_NONFATAL(obj.netInfo)->CanStorePlatform())};
if constexpr (is_p2p) {
Expand Down
31 changes: 31 additions & 0 deletions src/evo/netinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,27 @@ bool IsAllowedPlatformHTTPPort(uint16_t port)
}
return false;
}

uint16_t GetPrimaryAddrPort(NetInfoPurpose purpose)
{
switch (purpose) {
case NetInfoPurpose::CORE_P2P:
return MainParams().GetDefaultPort();
case NetInfoPurpose::PLATFORM_P2P:
return MainParams().GetDefaultPlatformP2PPort();
case NetInfoPurpose::PLATFORM_HTTPS:
return MainParams().GetDefaultPlatformHTTPPort();
} // no default case, so the compiler can warn about missing cases
Assume(false);
return 0;
}

//! On mainnet, the first entry of a purpose must use that purpose's standard port
NetInfoStatus ValidateMainnetPrimaryPort(NetInfoPurpose purpose, const NetInfoEntry& primary)
{
if (!IsNodeOnMainnet() || primary.GetPort() == GetPrimaryAddrPort(purpose)) return NetInfoStatus::Success;
return NetInfoStatus::BadPort;
}
} // anonymous namespace

bool IsNodeOnMainnet() { return Params().NetworkIDString() == CBaseChainParams::MAIN; }
Expand Down Expand Up @@ -427,6 +448,11 @@ NetInfoStatus ExtNetInfo::ProcessCandidate(const NetInfoPurpose purpose, const N
// Domains only allowed for Platform HTTPS API
return NetInfoStatus::BadInput;
}
if (!HasEntries(purpose)) {
if (const auto ret{ValidateMainnetPrimaryPort(purpose, candidate)}; ret != NetInfoStatus::Success) {
return ret;
}
}
if (auto it{m_data.find(purpose)}; it != m_data.end()) {
// Existing entries list found, check limit
auto& [_, entries] = *it;
Expand Down Expand Up @@ -619,6 +645,11 @@ NetInfoStatus ExtNetInfo::Validate() const
}
}
}
for (const auto& [purpose, entries] : m_data) {
if (const auto ret{ValidateMainnetPrimaryPort(purpose, entries.front())}; ret != NetInfoStatus::Success) {
return ret;
}
}
return NetInfoStatus::Success;
}

Expand Down
32 changes: 31 additions & 1 deletion src/evo/providertx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,35 @@ static bool CheckNetInfo(const NetInfoInterface& net_info, TxValidationState& st
assert(false);
}

//! The primary Core P2P address must be IPv4, and Platform's primary addresses must be on that same address
static bool CheckIPv4Primaries(const NetInfoInterface& net_info, TxValidationState& state)
{
const CService core_primary{net_info.GetPrimary()};
if (!core_primary.IsIPv4()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-addr-type",
strprintf("first %s entry must be IPv4", PurposeToString(NetInfoPurpose::CORE_P2P)));
}
for (const auto purpose : {NetInfoPurpose::PLATFORM_P2P, NetInfoPurpose::PLATFORM_HTTPS}) {
const auto entries{net_info.GetEntries(purpose)};
if (entries.empty()) continue;
const auto service_opt{entries.front().GetAddrPort()};
if (!service_opt || !service_opt->IsIPv4()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-addr-type",
strprintf("first %s entry must be IPv4", PurposeToString(purpose)));
}
if (CNetAddr{*service_opt} != CNetAddr{core_primary}) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-addr",
strprintf("first %s entry must use the first %s address", PurposeToString(purpose),
PurposeToString(NetInfoPurpose::CORE_P2P)));
}
}
return true;
}

bool CheckProviderNetworkFields(const std::shared_ptr<NetInfoInterface>& net_info, MnType type, uint16_t version,
const uint160* platform_node_id, uint16_t platform_p2p_port,
uint16_t platform_http_port, bool allow_empty, TxValidationState& state)
uint16_t platform_http_port, bool allow_empty, bool ipv4_optional,
TxValidationState& state)
{
if (!net_info || net_info->CanStorePlatform() != (version >= ProTxVersion::ExtAddr)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-netinfo-version");
Expand All @@ -244,6 +270,10 @@ bool CheckProviderNetworkFields(const std::shared_ptr<NetInfoInterface>& net_inf
if (!IsNetInfoTriviallyValid(net_info, type, state) || !CheckNetInfo(*net_info, state)) {
return false;
}
// Checked here rather than in Validate(), which also checks stored masternode states without a height
if (!ipv4_optional && !CheckIPv4Primaries(*net_info, state)) {
return false;
}
}

if (type != MnType::Evo) return true;
Expand Down
6 changes: 4 additions & 2 deletions src/evo/providertx.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,12 @@ template<class T>
[[nodiscard]] UniValue PayoutListToJson(const MasternodePayoutShares& payouts);

/** Validate all provider network fields using the same rules as special transaction validation.
* Pass nullptr for platform_node_id when validating endpoint input separately from the rest of a payload. */
* Pass nullptr for platform_node_id when validating endpoint input separately from the rest of a payload.
* ipv4_optional is SpecialTxRules::ipv4_optional for the block the transaction would be included in. */
[[nodiscard]] bool CheckProviderNetworkFields(const std::shared_ptr<NetInfoInterface>& net_info, MnType type,
uint16_t version, const uint160* platform_node_id, uint16_t platform_p2p_port,
uint16_t platform_http_port, bool allow_empty, TxValidationState& state);
uint16_t platform_http_port, bool allow_empty, bool ipv4_optional,
TxValidationState& state);

/** The count, per-share bound and sum rules of IsShareListTriviallyValid, usable before any share address exists */
[[nodiscard]] bool AreShareAmountsValid(const std::vector<CAmount>& amounts, CAmount required_collateral,
Expand Down
Loading
Loading