Skip to content

Commit 8424411

Browse files
Merge dashpay#7182: chore: backport 12 PRs to v23.1.x for v23.1.1 release
00f590d Merge dashpay#7180: qt: add Tahoe styled icons for macOS, runtime styling for each network type, update bundle icon, add mask-based tray icon, generation scripts (pasta) 60dda51 Merge dashpay#7176: perf: do linear lookup instead building 2 heavy Hash-Maps (pasta) df1ca87 Merge dashpay#7159: feat(qt): UI refresh (5/n, add proposal information widget to information, donut chart for proposal allocation) (pasta) 9061ad0 Merge dashpay#7118: feat(qt): UI refresh (4/n, introduce distinct widgets for Dash-specific reporting in debug window) (pasta) 64cc4f2 Merge dashpay#7160: feat(interfaces): consolidate masternode counts into one struct, expose chainlock, instantsend, credit pool, quorum statistics (pasta) 5d28a69 Merge dashpay#7157: fix(qt): prevent banned masternodes from returning status=0 (pasta) e0b7386 Merge dashpay#7146: feat(qt): introduce framework for sourcing and applying data, use for `{Masternode,Proposal}List`s (pasta) 8fd53cd Merge dashpay#7144: feat(qt): add support for reporting `OP_RETURN` payloads as Data Transactions (pasta) cc6f0bb Merge dashpay#7154: fix: MN update notifications had old_list/new_list swapped (pasta) 33f0138 Merge dashpay#7145: fix(qt): move labelError styling from proposalcreate.ui into general.css (pasta) 1bdbde6 Merge dashpay#7148: feat(qt): persist filter preferences in masternode list (pasta) 96bb601 Merge dashpay#7147: fix(qt): prevent overview page font double scaling, recalculate minimum width correctly, `SERVICE` and `STATUS` sorting, fix common types filtering (pasta) Pull request description: ## Backport PRs for v23.1.1 Cherry-picks the following 12 PRs (labeled `backport-candidate-23.1.x`) from `develop` onto `v23.1.x`, in merge order: | PR | Title | |---|---| | dashpay#7147 | fix(qt): prevent overview page font double scaling, recalculate minimum width correctly, `SERVICE` and `STATUS` sorting, fix common types filtering | | dashpay#7148 | feat(qt): persist filter preferences in masternode list | | dashpay#7145 | fix(qt): move labelError styling from proposalcreate.ui into general.css | | dashpay#7154 | fix: MN update notifications had old_list/new_list swapped | | dashpay#7144 | feat(qt): add support for reporting `OP_RETURN` payloads as Data Transactions | | dashpay#7146 | feat(qt): introduce framework for sourcing and applying data, use for `{Masternode,Proposal}List`s | | dashpay#7157 | fix(qt): prevent banned masternodes from returning status=0 | | dashpay#7160 | feat(interfaces): consolidate masternode counts into one struct, expose chainlock, instantsend, credit pool, quorum statistics | | dashpay#7118 | feat(qt): UI refresh (4/n, introduce distinct widgets for Dash-specific reporting in debug window) | | dashpay#7159 | feat(qt): UI refresh (5/n, add proposal information widget to information, donut chart for proposal allocation) | | dashpay#7176 | perf: do linear lookup instead building 2 heavy Hash-Maps | | dashpay#7180 | qt: add Tahoe styled icons for macOS, runtime styling for each network type, update bundle icon, add mask-based tray icon, generation scripts | All 12 cherry-picked cleanly (no conflicts). ## Notes - Used `git cherry-pick -m 1 <merge-sha>` for each (all were merge commits on develop) - Applied in chronological merge order to respect dependency chains - Version bump and release notes are separate steps per the release process ACKs for top commit: kwvg: utACK 00f590d UdjinM6: utACK 00f590d Tree-SHA512: 90d2a0660db8daa69b3e3b33a8a790fb0ea7d9a04656a2e27955575e76b6f4c9a379c435ef1c573ef6669c36cb6e205ba9701716d3dc303b01f19c719516b6d1
2 parents 888e99d + 00f590d commit 8424411

File tree

96 files changed

+4462
-1462
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+4462
-1462
lines changed

.github/workflows/semantic-pull-request.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@ jobs:
3838
# Configure which scopes are allowed (newline delimited).
3939
scopes: |
4040
consensus
41+
interfaces
4142
log
4243
mining
4344
net
4445
qt
4546
rest
4647
rpc
4748
scripts
49+
stats
4850
utils
4951
wallet
5052
zmq
51-
stats
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2026 The Dash Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
import os
7+
import platform
8+
import shutil
9+
import subprocess
10+
import sys
11+
import tempfile
12+
13+
# Assuming 1024x1024 canvas, the squircle content area is ~864x864 with
14+
# ~80px transparent padding on each side
15+
CONTENT_RATIO = 864 / 1024
16+
17+
DIR_ROOT = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))
18+
DIR_SRC = os.path.join(DIR_ROOT, "src", "qt", "res", "src")
19+
DIR_OUT = os.path.join(DIR_ROOT, "src", "qt", "res", "icons")
20+
21+
# Icon Composer exports to runtime icon map
22+
ICONS = [
23+
("macos_devnet.png", "dash_macos_devnet.png"),
24+
("macos_mainnet.png", "dash_macos_mainnet.png"),
25+
("macos_regtest.png", "dash_macos_regtest.png"),
26+
("macos_testnet.png", "dash_macos_testnet.png"),
27+
]
28+
TRAY = os.path.join(DIR_SRC, "tray.svg")
29+
30+
# Canvas to filename mapping for bundle icon
31+
ICNS_MAP = [
32+
(16, "icon_16x16.png"),
33+
(32, "icon_16x16@2x.png"),
34+
(32, "icon_32x32.png"),
35+
(64, "icon_32x32@2x.png"),
36+
(128, "icon_128x128.png"),
37+
(256, "icon_128x128@2x.png"),
38+
(256, "icon_256x256.png"),
39+
(512, "icon_256x256@2x.png"),
40+
(512, "icon_512x512.png"),
41+
(1024, "icon_512x512@2x.png"),
42+
]
43+
44+
# Maximum height of canvas is 22pt, we use max height instead of recommended
45+
# 16pt canvas to prevent the icon from looking undersized due to icon width.
46+
# See https://bjango.com/articles/designingmenubarextras/
47+
TRAY_MAP = [
48+
(22, "dash_macos_tray.png"),
49+
(44, "dash_macos_tray@2x.png")
50+
]
51+
52+
53+
def sips_resample_padded(src, dst, canvas_size):
54+
content_size = max(round(canvas_size * CONTENT_RATIO), 1)
55+
subprocess.check_call(
56+
["sips", "-z", str(content_size), str(content_size), "-p", str(canvas_size), str(canvas_size), src, "--out", dst],
57+
stdout=subprocess.DEVNULL,
58+
)
59+
60+
61+
def sips_svg_to_png(svg_path, png_path, height):
62+
subprocess.check_call(
63+
["sips", "-s", "format", "png", "--resampleHeight", str(height), svg_path, "--out", png_path],
64+
stdout=subprocess.DEVNULL,
65+
)
66+
67+
68+
def generate_icns(tmpdir):
69+
iconset = os.path.join(tmpdir, "dash.iconset")
70+
os.makedirs(iconset)
71+
72+
src_main = os.path.join(DIR_SRC, ICONS[1][0])
73+
for canvas_px, filename in ICNS_MAP:
74+
sips_resample_padded(src_main, os.path.join(iconset, filename), canvas_px)
75+
76+
icns_out = os.path.join(DIR_OUT, "dash.icns")
77+
subprocess.check_call(["iconutil", "-c", "icns", iconset, "-o", icns_out])
78+
print(f"Created: {icns_out}")
79+
80+
81+
def check_source(path):
82+
if not os.path.isfile(path):
83+
sys.exit(f"Error: Source image not found: {path}")
84+
85+
86+
def main():
87+
if platform.system() != "Darwin":
88+
sys.exit("Error: This script requires macOS (needs sips, iconutil).")
89+
90+
for tool in ("sips", "iconutil"):
91+
if shutil.which(tool) is None:
92+
sys.exit(f"Error: '{tool}' not found. Install Xcode command-line tools.")
93+
94+
check_source(TRAY)
95+
for src_name, _ in ICONS:
96+
check_source(os.path.join(DIR_SRC, src_name))
97+
98+
os.makedirs(DIR_OUT, exist_ok=True)
99+
100+
# Generate bundle icon
101+
with tempfile.TemporaryDirectory(prefix="dash_icons_") as tmpdir:
102+
generate_icns(tmpdir)
103+
104+
# Generate runtime icons
105+
for src_name, dst_name in ICONS:
106+
src = os.path.join(DIR_SRC, src_name)
107+
dst = os.path.join(DIR_OUT, dst_name)
108+
sips_resample_padded(src, dst, 256)
109+
print(f"Created: {dst}")
110+
111+
# Generate tray icons
112+
for canvas_px, filename in TRAY_MAP:
113+
dst = os.path.join(DIR_OUT, filename)
114+
sips_svg_to_png(TRAY, dst, canvas_px)
115+
print(f"Created: {dst}")
116+
117+
if __name__ == "__main__":
118+
main()

src/Makefile.qt.include

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,19 @@ QT_FORMS_UI = \
2323
qt/forms/debugwindow.ui \
2424
qt/forms/descriptiondialog.ui \
2525
qt/forms/editaddressdialog.ui \
26-
qt/forms/governancelist.ui \
2726
qt/forms/helpmessagedialog.ui \
27+
qt/forms/informationwidget.ui \
2828
qt/forms/intro.ui \
2929
qt/forms/masternodelist.ui \
3030
qt/forms/mnemonicverificationdialog.ui \
3131
qt/forms/modaloverlay.ui \
32+
qt/forms/networkwidget.ui \
3233
qt/forms/openuridialog.ui \
3334
qt/forms/optionsdialog.ui \
3435
qt/forms/overviewpage.ui \
3536
qt/forms/proposalcreate.ui \
37+
qt/forms/proposalinfo.ui \
38+
qt/forms/proposallist.ui \
3639
qt/forms/proposalresume.ui \
3740
qt/forms/psbtoperationsdialog.ui \
3841
qt/forms/qrdialog.ui \
@@ -53,15 +56,17 @@ QT_MOC_CPP = \
5356
qt/moc_bitcoinamountfield.cpp \
5457
qt/moc_bitcoingui.cpp \
5558
qt/moc_bitcoinunits.cpp \
59+
qt/moc_clientfeeds.cpp \
5660
qt/moc_clientmodel.cpp \
5761
qt/moc_coincontroldialog.cpp \
5862
qt/moc_coincontroltreewidget.cpp \
5963
qt/moc_createwalletdialog.cpp \
6064
qt/moc_csvmodelwriter.cpp \
6165
qt/moc_descriptiondialog.cpp \
66+
qt/moc_donutchart.cpp \
6267
qt/moc_editaddressdialog.cpp \
63-
qt/moc_governancelist.cpp \
6468
qt/moc_guiutil.cpp \
69+
qt/moc_informationwidget.cpp \
6570
qt/moc_initexecutor.cpp \
6671
qt/moc_intro.cpp \
6772
qt/moc_macdockiconhandler.cpp \
@@ -70,6 +75,7 @@ QT_MOC_CPP = \
7075
qt/moc_masternodemodel.cpp \
7176
qt/moc_mnemonicverificationdialog.cpp \
7277
qt/moc_modaloverlay.cpp \
78+
qt/moc_networkwidget.cpp \
7379
qt/moc_notificator.cpp \
7480
qt/moc_openuridialog.cpp \
7581
qt/moc_optionsdialog.cpp \
@@ -78,8 +84,10 @@ QT_MOC_CPP = \
7884
qt/moc_paymentserver.cpp \
7985
qt/moc_peertablemodel.cpp \
8086
qt/moc_peertablesortproxy.cpp \
81-
qt/moc_proposalmodel.cpp \
8287
qt/moc_proposalcreate.cpp \
88+
qt/moc_proposalinfo.cpp \
89+
qt/moc_proposallist.cpp \
90+
qt/moc_proposalmodel.cpp \
8391
qt/moc_proposalresume.cpp \
8492
qt/moc_psbtoperationsdialog.cpp \
8593
qt/moc_qrdialog.cpp \
@@ -133,17 +141,19 @@ BITCOIN_QT_H = \
133141
qt/bitcoinamountfield.h \
134142
qt/bitcoingui.h \
135143
qt/bitcoinunits.h \
144+
qt/clientfeeds.h \
136145
qt/clientmodel.h \
137146
qt/coincontroldialog.h \
138147
qt/coincontroltreewidget.h \
139148
qt/createwalletdialog.h \
140149
qt/csvmodelwriter.h \
141150
qt/descriptiondialog.h \
151+
qt/donutchart.h \
142152
qt/editaddressdialog.h \
143-
qt/governancelist.h \
144153
qt/guiconstants.h \
145-
qt/guiutil.h \
146154
qt/guiutil_font.h \
155+
qt/guiutil.h \
156+
qt/informationwidget.h \
147157
qt/initexecutor.h \
148158
qt/intro.h \
149159
qt/macdockiconhandler.h \
@@ -154,6 +164,7 @@ BITCOIN_QT_H = \
154164
qt/mnemonicverificationdialog.h \
155165
qt/modaloverlay.h \
156166
qt/networkstyle.h \
167+
qt/networkwidget.h \
157168
qt/notificator.h \
158169
qt/openuridialog.h \
159170
qt/optionsdialog.h \
@@ -163,6 +174,8 @@ BITCOIN_QT_H = \
163174
qt/peertablemodel.h \
164175
qt/peertablesortproxy.h \
165176
qt/proposalcreate.h \
177+
qt/proposalinfo.h \
178+
qt/proposallist.h \
166179
qt/proposalmodel.h \
167180
qt/proposalresume.h \
168181
qt/psbtoperationsdialog.h \
@@ -203,6 +216,12 @@ QT_RES_ICONS = \
203216
qt/res/icons/connect4_16.png \
204217
qt/res/icons/dash.ico \
205218
qt/res/icons/dash.png \
219+
qt/res/icons/dash_macos_devnet.png \
220+
qt/res/icons/dash_macos_mainnet.png \
221+
qt/res/icons/dash_macos_regtest.png \
222+
qt/res/icons/dash_macos_testnet.png \
223+
qt/res/icons/dash_macos_tray.png \
224+
qt/res/icons/dash_macos_tray@2x.png \
206225
qt/res/icons/dash_testnet.ico \
207226
qt/res/icons/editcopy.png \
208227
qt/res/icons/editpaste.png \
@@ -245,19 +264,26 @@ BITCOIN_QT_BASE_CPP = \
245264
qt/bitcoinamountfield.cpp \
246265
qt/bitcoingui.cpp \
247266
qt/bitcoinunits.cpp \
267+
qt/clientfeeds.cpp \
248268
qt/clientmodel.cpp \
249269
qt/csvmodelwriter.cpp \
270+
qt/donutchart.cpp \
250271
qt/guiutil.cpp \
251272
qt/guiutil_font.cpp \
273+
qt/informationwidget.cpp \
252274
qt/initexecutor.cpp \
253275
qt/intro.cpp \
276+
qt/masternodemodel.cpp \
254277
qt/modaloverlay.cpp \
255278
qt/networkstyle.cpp \
279+
qt/networkwidget.cpp \
256280
qt/notificator.cpp \
257281
qt/optionsdialog.cpp \
258282
qt/optionsmodel.cpp \
259283
qt/peertablemodel.cpp \
260284
qt/peertablesortproxy.cpp \
285+
qt/proposalinfo.cpp \
286+
qt/proposalmodel.cpp \
261287
qt/qvalidatedlineedit.cpp \
262288
qt/qvaluecombobox.cpp \
263289
qt/rpcconsole.cpp \
@@ -277,15 +303,13 @@ BITCOIN_QT_WALLET_CPP = \
277303
qt/createwalletdialog.cpp \
278304
qt/descriptiondialog.cpp \
279305
qt/editaddressdialog.cpp \
280-
qt/governancelist.cpp \
281306
qt/masternodelist.cpp \
282-
qt/masternodemodel.cpp \
283307
qt/mnemonicverificationdialog.cpp \
284308
qt/openuridialog.cpp \
285309
qt/overviewpage.cpp \
286310
qt/paymentserver.cpp \
287311
qt/proposalcreate.cpp \
288-
qt/proposalmodel.cpp \
312+
qt/proposallist.cpp \
289313
qt/proposalresume.cpp \
290314
qt/psbtoperationsdialog.cpp \
291315
qt/qrdialog.cpp \

src/active/quorums.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ size_t QuorumParticipant::GetQuorumRecoveryStartOffset(const CQuorum& quorum, gs
8989
{
9090
auto mns = m_dmnman.GetListForBlock(pIndex);
9191
std::vector<uint256> vecProTxHashes;
92-
vecProTxHashes.reserve(mns.GetValidMNsCount());
92+
vecProTxHashes.reserve(mns.GetCounts().enabled());
9393
mns.ForEachMN(/*onlyValid=*/true,
9494
[&](const auto& pMasternode) { vecProTxHashes.emplace_back(pMasternode.proTxHash); });
9595
std::sort(vecProTxHashes.begin(), vecProTxHashes.end());

src/coinjoin/client.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ MessageProcessingResult CCoinJoinClientQueueManager::ProcessMessage(NodeId from,
124124
LogPrint(BCLog::COINJOIN, "DSQUEUE -- CoinJoin queue is ready, masternode=%s, queue=%s\n", dmn->proTxHash.ToString(), dsq.ToString());
125125
return ret;
126126
} else {
127-
if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, tip_mn_list.GetValidMNsCount())) {
127+
if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, tip_mn_list.GetCounts().enabled())) {
128128
LogPrint(BCLog::COINJOIN, "DSQUEUE -- Masternode %s is sending too many dsq messages\n",
129129
dmn->proTxHash.ToString());
130130
return ret;
@@ -826,7 +826,7 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(ChainstateManager& chainman
826826
return false;
827827
}
828828

829-
if (m_dmnman.GetListAtChainTip().GetValidMNsCount() == 0 &&
829+
if (m_dmnman.GetListAtChainTip().GetCounts().enabled() == 0 &&
830830
Params().NetworkIDString() != CBaseChainParams::REGTEST) {
831831
strAutoDenomResult = _("No Masternodes detected.");
832832
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::DoAutomaticDenominating -- %s\n", strAutoDenomResult.original);
@@ -988,7 +988,7 @@ bool CCoinJoinClientManager::DoAutomaticDenominating(ChainstateManager& chainman
988988
return false;
989989
}
990990

991-
int nMnCountEnabled = m_dmnman.GetListAtChainTip().GetValidMNsCount();
991+
int nMnCountEnabled = m_dmnman.GetListAtChainTip().GetCounts().enabled();
992992

993993
// If we've used 90% of the Masternode list then drop the oldest first ~30%
994994
int nThreshold_high = nMnCountEnabled * 0.9;
@@ -1033,7 +1033,7 @@ CDeterministicMNCPtr CCoinJoinClientManager::GetRandomNotUsedMasternode()
10331033
{
10341034
auto mnList = m_dmnman.GetListAtChainTip();
10351035

1036-
size_t nCountEnabled = mnList.GetValidMNsCount();
1036+
size_t nCountEnabled = mnList.GetCounts().enabled();
10371037
size_t nCountNotExcluded{nCountEnabled - m_mn_metaman.GetUsedMasternodesCount()};
10381038

10391039
WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::%s -- %d enabled masternodes, %d masternodes to choose from\n", __func__, nCountEnabled, nCountNotExcluded);
@@ -1078,7 +1078,7 @@ bool CCoinJoinClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized,
10781078
if (m_queueman == nullptr) return false;
10791079

10801080
const auto mnList = m_dmnman.GetListAtChainTip();
1081-
const int nWeightedMnCount = mnList.GetValidWeightedMNsCount();
1081+
const int nWeightedMnCount = mnList.GetCounts().m_valid_weighted;
10821082

10831083
// Look through the queues and see if anything matches
10841084
CCoinJoinQueue dsq;
@@ -1143,8 +1143,9 @@ bool CCoinJoinClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CCon
11431143

11441144
int nTries = 0;
11451145
const auto mnList = m_dmnman.GetListAtChainTip();
1146-
const int nMnCount = mnList.GetValidMNsCount();
1147-
const int nWeightedMnCount = mnList.GetValidWeightedMNsCount();
1146+
const auto mnCounts = mnList.GetCounts();
1147+
const int nMnCount = mnCounts.enabled();
1148+
const int nWeightedMnCount = mnCounts.m_valid_weighted;
11481149

11491150
// find available denominated amounts
11501151
std::set<CAmount> setAmounts;

src/coinjoin/server.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ void CCoinJoinServer::ProcessDSACCEPT(CNode& peer, CDataStream& vRecv)
100100
}
101101
}
102102

103-
if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, mnList.GetValidMNsCount())) {
103+
if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, mnList.GetCounts().enabled())) {
104104
if (fLogIPs) {
105105
LogPrint(BCLog::COINJOIN, "DSACCEPT -- last dsq too recent, must wait: peer=%d, addr=%s\n",
106106
peer.GetId(), peer.addr.ToStringAddrPort());
@@ -193,7 +193,7 @@ void CCoinJoinServer::ProcessDSQUEUE(NodeId from, CDataStream& vRecv)
193193

194194
if (!dsq.fReady) {
195195
//don't allow a few nodes to dominate the queuing process
196-
if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, tip_mn_list.GetValidMNsCount())) {
196+
if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, tip_mn_list.GetCounts().enabled())) {
197197
LogPrint(BCLog::COINJOIN, "DSQUEUE -- node sending too many dsq messages, masternode=%s\n", dmn->proTxHash.ToString());
198198
return;
199199
}

src/dummywallet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class Loader;
1818
} // namespace CoinJoin
1919
} // namespace interfaces
2020
namespace node {
21-
class NodeContext;
21+
struct NodeContext;
2222
} // namespace node
2323
namespace wallet {
2424
class CWallet;

0 commit comments

Comments
 (0)