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
0e75c22
Merge #7814: fix(qt): restore HTML escaping of send confirmation reci…
PastaPastaPasta Oct 7, 2026
00fc3b9
Merge #7851: fix(rpc): correct masternode status help for top-level s…
PastaPastaPasta Oct 7, 2026
886d5c4
Merge #7816: fix: check credit pool amount accumulation
PastaPastaPasta Oct 8, 2026
86a7737
Merge #7828: fix: omit recovery words from invalid mnemonic errors
PastaPastaPasta Oct 8, 2026
bcefee4
Merge #7822: fix: reject malformed detached quorum share batches
PastaPastaPasta Oct 8, 2026
0bf80f8
Merge #7810: fix(rpc): handle unavailable masternode payment inputs
PastaPastaPasta Oct 8, 2026
3c5c039
Merge #7838: fix(wallet): authenticate unlock deadline extensions
PastaPastaPasta Oct 9, 2026
2fea45f
Merge #7792: fix: treat missing snapshots during evodb repair as repa…
PastaPastaPasta Oct 9, 2026
e7e3daa
Merge #7821: fix: relock encrypted wallets after HD upgrade failures
PastaPastaPasta Oct 9, 2026
cb39369
Merge #7834: fix: validate Electrum import input boundaries
PastaPastaPasta Oct 9, 2026
2ff0103
Merge #7818: fix: return REST errors for unavailable deployment data
PastaPastaPasta Oct 9, 2026
50a5617
Merge #7829: fix: preserve wallet permissions when changing passphrases
PastaPastaPasta Oct 9, 2026
a1f37ea
Merge #7820: fix: hold chainstate lock during CoinJoin input validation
PastaPastaPasta Oct 9, 2026
b230657
Merge #7841: fix: authenticate cached InstantSend proof bytes
PastaPastaPasta Oct 9, 2026
0623182
Merge #7831: fix: bound governance object signatures and reset the go…
PastaPastaPasta Oct 10, 2026
efcef71
Merge #7521: fix: update masternode rate limit on failed governance t…
PastaPastaPasta Oct 10, 2026
861a579
Merge #7866: fix: stop `masternode payments` at the genesis block
PastaPastaPasta Oct 13, 2026
8348d22
Merge #7867: fix: refuse masternode list RPCs for blocks outside the …
PastaPastaPasta Oct 13, 2026
fe68ecb
Merge #7871: backport!: Merge bitcoin/bitcoin#27217: wallet: Replace …
PastaPastaPasta Oct 13, 2026
e4798ff
Merge #7876: fix(consensus): capture operator key scheme changes with…
PastaPastaPasta Oct 14, 2026
dc1a6b2
Merge #7875: docs(rpc): clarify getchainlockbyheight availability
PastaPastaPasta Oct 14, 2026
795c6f1
Merge #7839: fix: release InstantSend tracking after mempool eviction
PastaPastaPasta Oct 14, 2026
588e458
Merge #7827: backport: partial bitcoin#35984
PastaPastaPasta Oct 14, 2026
cc5716f
Merge #7824: fix: retain initialized DKG sessions during inventory reads
PastaPastaPasta Oct 15, 2026
cdf65d0
Merge #7836: backport: partial bitcoin#25812, bitcoin#29855
PastaPastaPasta Oct 15, 2026
95982f5
Merge #7782: fix(wallet): persist pending-observation coin locks once…
PastaPastaPasta Oct 15, 2026
904d73d
Merge #7881: fix: refuse to sign shared registrar updates that move t…
PastaPastaPasta Oct 15, 2026
35e6d18
Merge #7858: fix: do not InstantSend-lock provider transactions
PastaPastaPasta Oct 15, 2026
98d92f6
Merge #7817: backport: partial bitcoin#34156 restore cleanup ownership
PastaPastaPasta Oct 15, 2026
cdaea5f
Merge #7894: fix: due to logical conflicts feature_pruning.py had bee…
PastaPastaPasta Oct 15, 2026
a56ed47
fix(net): announce sporks to new peers instead of requesting them dur…
PastaPastaPasta Oct 15, 2026
79480ff
test: follow-up for #7821: check if wallet is locked after failed upg…
knst Oct 9, 2026
e56e6ae
Merge #7842: fix(wallet): reject mnemonic passphrases that seed deriv…
PastaPastaPasta Oct 15, 2026
8efdf5e
Merge #7857: fix: mine a pending ProUpServTx before a key change of i…
PastaPastaPasta Oct 15, 2026
cbb9500
Merge #7846: fix: treat pending owner keys and Platform node IDs as o…
PastaPastaPasta Oct 16, 2026
5633761
Merge #7895: test: cover retroactive provider tx refusal, fix wording
PastaPastaPasta Oct 16, 2026
08d8bca
Merge #7909: feat(mining): build the masternode list incrementally du…
PastaPastaPasta Oct 16, 2026
54cba5c
Merge #7537: fix: data races and check-then-act races in the CoinJoin…
PastaPastaPasta Oct 16, 2026
ce5dbf3
Merge #7888: fix(consensus): canonical ExtNetInfo encoding and strict…
PastaPastaPasta Oct 16, 2026
6c02b2b
ci: let DEPENDS_ARCH override the machine arch for multiprocess and tsan
PastaPastaPasta Oct 16, 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
4 changes: 3 additions & 1 deletion ci/test/00_setup_env_native_multiprocess.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
export LC_ALL=C.UTF-8

export CONTAINER_NAME=ci_native_multiprocess
case "$(uname -m)" in
# DEPENDS_ARCH overrides the machine arch (uname -m) when the depends are
# computed on a different machine than the one that builds them (CI check-cache).
case "${DEPENDS_ARCH:-$(uname -m)}" in
aarch64)
export HOST=aarch64-linux-gnu
;;
Expand Down
4 changes: 3 additions & 1 deletion ci/test/00_setup_env_native_tsan.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
export LC_ALL=C.UTF-8

export CONTAINER_NAME=ci_native_tsan
case "$(uname -m)" in
# DEPENDS_ARCH overrides the machine arch (uname -m) when the depends are
# computed on a different machine than the one that builds them (CI check-cache).
case "${DEPENDS_ARCH:-$(uname -m)}" in
aarch64)
export HOST=aarch64-linux-gnu
;;
Expand Down
6 changes: 6 additions & 0 deletions doc/release-notes-27217.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Wallet
------

* Address Purposes strings are now restricted to the currently known values of "send", "receive", and "refund".
Wallets that have unrecognized purpose strings will have loading warnings, and the `listlabels`
RPC will raise an error if an unrecognized purpose is requested.
8 changes: 8 additions & 0 deletions doc/release-notes-7831.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
P2P and network changes
-----------------------

- Governance object signatures larger than 96 bytes are now rejected, both from
the network and from the on-disk governance cache (`governance.dat`). The
cache format version was bumped for this: on the first start after
upgrading, the existing cache is discarded and governance objects and votes
are synced again from the network. (#7831)
21 changes: 21 additions & 0 deletions doc/release-notes-7842.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Wallet
------

- Creating an HD wallet with a mnemonic passphrase longer than 248 bytes (not characters) through `upgradetohd`,
`createwallet` or `-mnemonicpassphrase` is now rejected, and one longer than 256 bytes is always rejected.
Existing wallets are not affected. (#7842)

Seed derivation uses the BIP39 salt `"mnemonic"` followed by the passphrase. Dash Core 19.2.0 started cutting that
salt at 256 bytes to stop a crash, so every passphrase byte after the 248th has been ignored since then. Two
passphrases that differ only after that point derive the same seed. Before 23.0.0 the salt was also cut at the
first NUL byte.

The derivation is left as it is. Using the full passphrase would bring back the pre-19.2.0 derivation, and a wallet
created with a long passphrase on 19.2.0 or later could then no longer be recovered from its mnemonic. Instead, new
wallets can't be given a passphrase that the derivation would truncate.

To recover a wallet that was created on 19.2.0 or later with a passphrase of 249 to 256 bytes, start the node with
the new `-allow-deprecated-long-mnemonics` option, which accepts passphrases of up to 256 bytes and derives the same
(truncated) seed as before. A wallet created before 19.2.0 with a passphrase longer than 248 bytes can't be
recovered from its mnemonic on current versions, with or without the option. Restore it from a wallet backup
instead.
13 changes: 13 additions & 0 deletions doc/release-notes-7857.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Mining and mempool policy
-------------------------

- When a block template includes an operator key change or revocation for a masternode, it now
places the masternode's pending `ProUpServTx` signed with the key being replaced before it. Such
a service update could otherwise confirm after the change in the same block and restore the
previous operator's service and payout details. A service update that cannot be placed before
the change, or that does not fit in the block with it, is left out of that block. (#7857)
- The mempool now rejects with `protx-dup` a `ProUpServTx` that spends, directly or through other
pending transactions, an output of a pending operator key change or revocation, which it can only
confirm after, or of a pending asset lock, asset unlock or MNHF signal, which could keep it out of
a block. A service update funded from such outputs can be sent once they confirm, signed with the
operator key that is current then. (#7857)
8 changes: 8 additions & 0 deletions doc/release-notes-7858.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
InstantSend changes
-------------------

- Masternodes no longer InstantSend-lock provider transactions (ProRegTx, ProUpServTx, ProUpRegTx, ProUpRevTx and the
other provider special transactions). They are mined once they have been in the mempool for 10 minutes, and
transactions that spend their outputs can be locked once the block that includes the provider transaction is
ChainLocked. Software that waits for an islock on a provider transaction should wait for a ChainLock or confirmations
instead. (#7858)
2 changes: 1 addition & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,6 @@ BITCOIN_CORE_H = \
wallet/external_signer_scriptpubkeyman.h \
wallet/fees.h \
wallet/hdchain.h \
wallet/ismine.h \
wallet/load.h \
wallet/platformkeys.h \
wallet/platformtypes.h \
Expand All @@ -501,6 +500,7 @@ BITCOIN_CORE_H = \
wallet/spend.h \
wallet/sqlite.h \
wallet/transaction.h \
wallet/types.h \
wallet/wallet.h \
wallet/walletdb.h \
wallet/wallettool.h \
Expand Down
37 changes: 27 additions & 10 deletions src/active/dkgsessionhandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,23 @@ bool ActiveDKGSessionHandler::InitNewQuorum(gsl::not_null<const CBlockIndex*> pQ
return false;
}

curSession = std::make_unique<ActiveDKGSession>(m_bls_worker, m_dmnman, m_dkgdbgman, m_qdkgsman, m_mn_metaman,
m_qsnapman, m_mn_activeman, m_chainman, m_sporkman,
pQuorumBaseBlockIndex, params);
auto next_session = std::make_shared<ActiveDKGSession>(m_bls_worker, m_dmnman, m_dkgdbgman, m_qdkgsman,
m_mn_metaman, m_qsnapman, m_mn_activeman, m_chainman,
m_sporkman, pQuorumBaseBlockIndex, params);

if (!curSession->Init(m_mn_activeman.GetProTxHash(), quorumIndex)) {
{
std::shared_ptr<CDKGSession> previous_session;
WITH_LOCK(cs_session, previous_session.swap(curSession));
}

if (!next_session->Init(m_mn_activeman.GetProTxHash(), quorumIndex)) {
LogPrintf("ActiveDKGSessionHandler::%s -- height[%d] quorum initialization failed for %s qi[%d]\n", __func__,
pQuorumBaseBlockIndex->nHeight, params.name, quorumIndex);
return false;
}

WITH_LOCK(cs_session, curSession = std::move(next_session));

LogPrintf("ActiveDKGSessionHandler::%s -- height[%d] quorum initialization OK for %s qi[%d]\n", __func__, pQuorumBaseBlockIndex->nHeight, params.name, quorumIndex);
return true;
}
Expand Down Expand Up @@ -166,7 +173,8 @@ void ActiveDKGSessionHandler::WaitForNewQuorum(const uint256& oldQuorumHash) con
void ActiveDKGSessionHandler::SleepBeforePhase(QuorumPhase curPhase, const uint256& expectedQuorumHash,
double randomSleepFactor, const WhileWaitFunc& runWhileWaiting) const
{
if (!curSession->AreWeMember()) {
const auto session = GetCurSession();
if (!session || !session->AreWeMember()) {
// Non-members do not participate and do not create any network load, no need to sleep.
return;
}
Expand All @@ -187,7 +195,7 @@ void ActiveDKGSessionHandler::SleepBeforePhase(QuorumPhase curPhase, const uint2
// Don't expect perfect block times and thus reduce the phase time to be on the secure side (caller chooses factor)
double adjustedPhaseSleepTimePerMember = phaseSleepTimePerMember * randomSleepFactor;

int64_t sleepTime = static_cast<int64_t>(adjustedPhaseSleepTimePerMember * curSession->GetMyMemberIndex().value_or(0));
int64_t sleepTime = static_cast<int64_t>(adjustedPhaseSleepTimePerMember * session->GetMyMemberIndex().value_or(0));
const auto endTime = SteadyClock::now() + std::chrono::milliseconds{sleepTime};
int heightTmp{currentHeight.load()};
int heightStart{heightTmp};
Expand Down Expand Up @@ -248,22 +256,31 @@ void ActiveDKGSessionHandler::HandlePhase(QuorumPhase curPhase, QuorumPhase next

bool ActiveDKGSessionHandler::GetContribution(const uint256& hash, CDKGContribution& ret) const
{
return curSession && curSession->GetContribution(hash, ret);
const auto session = GetCurSession();
return session && session->GetContribution(hash, ret);
}

bool ActiveDKGSessionHandler::GetComplaint(const uint256& hash, CDKGComplaint& ret) const
{
return curSession && curSession->GetComplaint(hash, ret);
const auto session = GetCurSession();
return session && session->GetComplaint(hash, ret);
}

bool ActiveDKGSessionHandler::GetJustification(const uint256& hash, CDKGJustification& ret) const
{
return curSession && curSession->GetJustification(hash, ret);
const auto session = GetCurSession();
return session && session->GetJustification(hash, ret);
}

bool ActiveDKGSessionHandler::GetPrematureCommitment(const uint256& hash, CDKGPrematureCommitment& ret) const
{
return curSession && curSession->GetPrematureCommitment(hash, ret);
const auto session = GetCurSession();
return session && session->GetPrematureCommitment(hash, ret);
}

std::shared_ptr<CDKGSession> ActiveDKGSessionHandler::GetCurSession() const
{
return WITH_LOCK(cs_session, return curSession);
}

QuorumPhase ActiveDKGSessionHandler::GetPhase() const
Expand Down
22 changes: 13 additions & 9 deletions src/active/dkgsessionhandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ class ActiveDKGSessionHandler final : public llmq::CDKGSessionHandler
private:
std::atomic<bool> stopRequested{false};
std::atomic<int> currentHeight{-1};
std::unique_ptr<CDKGSession> curSession{nullptr};
mutable Mutex cs_session;
std::shared_ptr<CDKGSession> curSession GUARDED_BY(cs_session);

mutable Mutex cs_phase_qhash;
QuorumPhase phase GUARDED_BY(cs_phase_qhash){QuorumPhase::Idle};
Expand All @@ -81,10 +82,12 @@ class ActiveDKGSessionHandler final : public llmq::CDKGSessionHandler

public:
//! CDKGSessionHandler
bool GetContribution(const uint256& hash, CDKGContribution& ret) const override;
bool GetComplaint(const uint256& hash, CDKGComplaint& ret) const override;
bool GetJustification(const uint256& hash, CDKGJustification& ret) const override;
bool GetPrematureCommitment(const uint256& hash, CDKGPrematureCommitment& ret) const override;
bool GetContribution(const uint256& hash, CDKGContribution& ret) const override EXCLUSIVE_LOCKS_REQUIRED(!cs_session);
bool GetComplaint(const uint256& hash, CDKGComplaint& ret) const override EXCLUSIVE_LOCKS_REQUIRED(!cs_session);
bool GetJustification(const uint256& hash, CDKGJustification& ret) const override
EXCLUSIVE_LOCKS_REQUIRED(!cs_session);
bool GetPrematureCommitment(const uint256& hash, CDKGPrematureCommitment& ret) const override
EXCLUSIVE_LOCKS_REQUIRED(!cs_session);
QuorumPhase GetPhase() const override EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash);
void UpdatedBlockTip(const CBlockIndex* pindexNew) override EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash);

Expand All @@ -96,12 +99,12 @@ class ActiveDKGSessionHandler final : public llmq::CDKGSessionHandler
int QuorumIndex() const { return quorumIndex; }
bool QuorumsWatch() const { return m_quorums_watch; }
uint256 GetCurrentQuorumHash() const EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash);
CDKGSession* GetCurSession() { return curSession.get(); }
std::shared_ptr<CDKGSession> GetCurSession() const EXCLUSIVE_LOCKS_REQUIRED(!cs_session);

void RequestStop() { stopRequested = true; }
bool IsStopRequested() const { return stopRequested; }

bool InitNewQuorum(gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex);
bool InitNewQuorum(gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex) EXCLUSIVE_LOCKS_REQUIRED(!cs_session);

/**
* @param curPhase current QuorumPhase
Expand All @@ -114,10 +117,11 @@ class ActiveDKGSessionHandler final : public llmq::CDKGSessionHandler
const WhileWaitFunc& shouldNotWait = [] { return false; }) const EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash);
void WaitForNewQuorum(const uint256& oldQuorumHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash);
void SleepBeforePhase(QuorumPhase curPhase, const uint256& expectedQuorumHash, double randomSleepFactor,
const WhileWaitFunc& runWhileWaiting) const EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash);
const WhileWaitFunc& runWhileWaiting) const
EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash, !cs_session);
void HandlePhase(QuorumPhase curPhase, QuorumPhase nextPhase, const uint256& expectedQuorumHash,
double randomSleepFactor, const StartPhaseFunc& startPhaseFunc,
const WhileWaitFunc& runWhileWaiting) EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash);
const WhileWaitFunc& runWhileWaiting) EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash, !cs_session);

private:
std::pair<QuorumPhase, uint256> GetPhaseAndQuorumHash() const EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash);
Expand Down
Loading
Loading