Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .github/workflows/semantic-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,15 @@ jobs:
# Configure which scopes are allowed (newline delimited).
scopes: |
consensus
interfaces
log
mining
net
qt
rest
rpc
scripts
stats
utils
wallet
zmq
stats
118 changes: 118 additions & 0 deletions contrib/devtools/gen_macos_icons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/usr/bin/env python3
# Copyright (c) 2026 The Dash Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

import os
import platform
import shutil
import subprocess
import sys
import tempfile

# Assuming 1024x1024 canvas, the squircle content area is ~864x864 with
# ~80px transparent padding on each side
CONTENT_RATIO = 864 / 1024

DIR_ROOT = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))
DIR_SRC = os.path.join(DIR_ROOT, "src", "qt", "res", "src")
DIR_OUT = os.path.join(DIR_ROOT, "src", "qt", "res", "icons")

# Icon Composer exports to runtime icon map
ICONS = [
("macos_devnet.png", "dash_macos_devnet.png"),
("macos_mainnet.png", "dash_macos_mainnet.png"),
("macos_regtest.png", "dash_macos_regtest.png"),
("macos_testnet.png", "dash_macos_testnet.png"),
]
TRAY = os.path.join(DIR_SRC, "tray.svg")

# Canvas to filename mapping for bundle icon
ICNS_MAP = [
(16, "icon_16x16.png"),
(32, "icon_16x16@2x.png"),
(32, "icon_32x32.png"),
(64, "icon_32x32@2x.png"),
(128, "icon_128x128.png"),
(256, "icon_128x128@2x.png"),
(256, "icon_256x256.png"),
(512, "icon_256x256@2x.png"),
(512, "icon_512x512.png"),
(1024, "icon_512x512@2x.png"),
]

# Maximum height of canvas is 22pt, we use max height instead of recommended
# 16pt canvas to prevent the icon from looking undersized due to icon width.
# See https://bjango.com/articles/designingmenubarextras/
TRAY_MAP = [
(22, "dash_macos_tray.png"),
(44, "dash_macos_tray@2x.png")
]


def sips_resample_padded(src, dst, canvas_size):
content_size = max(round(canvas_size * CONTENT_RATIO), 1)
subprocess.check_call(
["sips", "-z", str(content_size), str(content_size), "-p", str(canvas_size), str(canvas_size), src, "--out", dst],
stdout=subprocess.DEVNULL,
)


def sips_svg_to_png(svg_path, png_path, height):
subprocess.check_call(
["sips", "-s", "format", "png", "--resampleHeight", str(height), svg_path, "--out", png_path],
stdout=subprocess.DEVNULL,
)


def generate_icns(tmpdir):
iconset = os.path.join(tmpdir, "dash.iconset")
os.makedirs(iconset)

src_main = os.path.join(DIR_SRC, ICONS[1][0])
for canvas_px, filename in ICNS_MAP:
sips_resample_padded(src_main, os.path.join(iconset, filename), canvas_px)

icns_out = os.path.join(DIR_OUT, "dash.icns")
subprocess.check_call(["iconutil", "-c", "icns", iconset, "-o", icns_out])
print(f"Created: {icns_out}")


def check_source(path):
if not os.path.isfile(path):
sys.exit(f"Error: Source image not found: {path}")


def main():
if platform.system() != "Darwin":
sys.exit("Error: This script requires macOS (needs sips, iconutil).")

for tool in ("sips", "iconutil"):
if shutil.which(tool) is None:
sys.exit(f"Error: '{tool}' not found. Install Xcode command-line tools.")

check_source(TRAY)
for src_name, _ in ICONS:
check_source(os.path.join(DIR_SRC, src_name))

os.makedirs(DIR_OUT, exist_ok=True)

# Generate bundle icon
with tempfile.TemporaryDirectory(prefix="dash_icons_") as tmpdir:
generate_icns(tmpdir)

# Generate runtime icons
for src_name, dst_name in ICONS:
src = os.path.join(DIR_SRC, src_name)
dst = os.path.join(DIR_OUT, dst_name)
sips_resample_padded(src, dst, 256)
print(f"Created: {dst}")

# Generate tray icons
for canvas_px, filename in TRAY_MAP:
dst = os.path.join(DIR_OUT, filename)
sips_svg_to_png(TRAY, dst, canvas_px)
print(f"Created: {dst}")

if __name__ == "__main__":
main()
40 changes: 32 additions & 8 deletions src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,19 @@ QT_FORMS_UI = \
qt/forms/debugwindow.ui \
qt/forms/descriptiondialog.ui \
qt/forms/editaddressdialog.ui \
qt/forms/governancelist.ui \
qt/forms/helpmessagedialog.ui \
qt/forms/informationwidget.ui \
qt/forms/intro.ui \
qt/forms/masternodelist.ui \
qt/forms/mnemonicverificationdialog.ui \
qt/forms/modaloverlay.ui \
qt/forms/networkwidget.ui \
qt/forms/openuridialog.ui \
qt/forms/optionsdialog.ui \
qt/forms/overviewpage.ui \
qt/forms/proposalcreate.ui \
qt/forms/proposalinfo.ui \
qt/forms/proposallist.ui \
qt/forms/proposalresume.ui \
qt/forms/psbtoperationsdialog.ui \
qt/forms/qrdialog.ui \
Expand All @@ -53,15 +56,17 @@ QT_MOC_CPP = \
qt/moc_bitcoinamountfield.cpp \
qt/moc_bitcoingui.cpp \
qt/moc_bitcoinunits.cpp \
qt/moc_clientfeeds.cpp \
qt/moc_clientmodel.cpp \
qt/moc_coincontroldialog.cpp \
qt/moc_coincontroltreewidget.cpp \
qt/moc_createwalletdialog.cpp \
qt/moc_csvmodelwriter.cpp \
qt/moc_descriptiondialog.cpp \
qt/moc_donutchart.cpp \
qt/moc_editaddressdialog.cpp \
qt/moc_governancelist.cpp \
qt/moc_guiutil.cpp \
qt/moc_informationwidget.cpp \
qt/moc_initexecutor.cpp \
qt/moc_intro.cpp \
qt/moc_macdockiconhandler.cpp \
Expand All @@ -70,6 +75,7 @@ QT_MOC_CPP = \
qt/moc_masternodemodel.cpp \
qt/moc_mnemonicverificationdialog.cpp \
qt/moc_modaloverlay.cpp \
qt/moc_networkwidget.cpp \
qt/moc_notificator.cpp \
qt/moc_openuridialog.cpp \
qt/moc_optionsdialog.cpp \
Expand All @@ -78,8 +84,10 @@ QT_MOC_CPP = \
qt/moc_paymentserver.cpp \
qt/moc_peertablemodel.cpp \
qt/moc_peertablesortproxy.cpp \
qt/moc_proposalmodel.cpp \
qt/moc_proposalcreate.cpp \
qt/moc_proposalinfo.cpp \
qt/moc_proposallist.cpp \
qt/moc_proposalmodel.cpp \
qt/moc_proposalresume.cpp \
qt/moc_psbtoperationsdialog.cpp \
qt/moc_qrdialog.cpp \
Expand Down Expand Up @@ -133,17 +141,19 @@ BITCOIN_QT_H = \
qt/bitcoinamountfield.h \
qt/bitcoingui.h \
qt/bitcoinunits.h \
qt/clientfeeds.h \
qt/clientmodel.h \
qt/coincontroldialog.h \
qt/coincontroltreewidget.h \
qt/createwalletdialog.h \
qt/csvmodelwriter.h \
qt/descriptiondialog.h \
qt/donutchart.h \
qt/editaddressdialog.h \
qt/governancelist.h \
qt/guiconstants.h \
qt/guiutil.h \
qt/guiutil_font.h \
qt/guiutil.h \
qt/informationwidget.h \
qt/initexecutor.h \
qt/intro.h \
qt/macdockiconhandler.h \
Expand All @@ -154,6 +164,7 @@ BITCOIN_QT_H = \
qt/mnemonicverificationdialog.h \
qt/modaloverlay.h \
qt/networkstyle.h \
qt/networkwidget.h \
qt/notificator.h \
qt/openuridialog.h \
qt/optionsdialog.h \
Expand All @@ -163,6 +174,8 @@ BITCOIN_QT_H = \
qt/peertablemodel.h \
qt/peertablesortproxy.h \
qt/proposalcreate.h \
qt/proposalinfo.h \
qt/proposallist.h \
qt/proposalmodel.h \
qt/proposalresume.h \
qt/psbtoperationsdialog.h \
Expand Down Expand Up @@ -203,6 +216,12 @@ QT_RES_ICONS = \
qt/res/icons/connect4_16.png \
qt/res/icons/dash.ico \
qt/res/icons/dash.png \
qt/res/icons/dash_macos_devnet.png \
qt/res/icons/dash_macos_mainnet.png \
qt/res/icons/dash_macos_regtest.png \
qt/res/icons/dash_macos_testnet.png \
qt/res/icons/dash_macos_tray.png \
qt/res/icons/dash_macos_tray@2x.png \
qt/res/icons/dash_testnet.ico \
qt/res/icons/editcopy.png \
qt/res/icons/editpaste.png \
Expand Down Expand Up @@ -245,19 +264,26 @@ BITCOIN_QT_BASE_CPP = \
qt/bitcoinamountfield.cpp \
qt/bitcoingui.cpp \
qt/bitcoinunits.cpp \
qt/clientfeeds.cpp \
qt/clientmodel.cpp \
qt/csvmodelwriter.cpp \
qt/donutchart.cpp \
qt/guiutil.cpp \
qt/guiutil_font.cpp \
qt/informationwidget.cpp \
qt/initexecutor.cpp \
qt/intro.cpp \
qt/masternodemodel.cpp \
qt/modaloverlay.cpp \
qt/networkstyle.cpp \
qt/networkwidget.cpp \
qt/notificator.cpp \
qt/optionsdialog.cpp \
qt/optionsmodel.cpp \
qt/peertablemodel.cpp \
qt/peertablesortproxy.cpp \
qt/proposalinfo.cpp \
qt/proposalmodel.cpp \
qt/qvalidatedlineedit.cpp \
qt/qvaluecombobox.cpp \
qt/rpcconsole.cpp \
Expand All @@ -277,15 +303,13 @@ BITCOIN_QT_WALLET_CPP = \
qt/createwalletdialog.cpp \
qt/descriptiondialog.cpp \
qt/editaddressdialog.cpp \
qt/governancelist.cpp \
qt/masternodelist.cpp \
qt/masternodemodel.cpp \
qt/mnemonicverificationdialog.cpp \
qt/openuridialog.cpp \
qt/overviewpage.cpp \
qt/paymentserver.cpp \
qt/proposalcreate.cpp \
qt/proposalmodel.cpp \
qt/proposallist.cpp \
qt/proposalresume.cpp \
qt/psbtoperationsdialog.cpp \
qt/qrdialog.cpp \
Expand Down
2 changes: 1 addition & 1 deletion src/active/quorums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ size_t QuorumParticipant::GetQuorumRecoveryStartOffset(const CQuorum& quorum, gs
{
auto mns = m_dmnman.GetListForBlock(pIndex);
std::vector<uint256> vecProTxHashes;
vecProTxHashes.reserve(mns.GetValidMNsCount());
vecProTxHashes.reserve(mns.GetCounts().enabled());
mns.ForEachMN(/*onlyValid=*/true,
[&](const auto& pMasternode) { vecProTxHashes.emplace_back(pMasternode.proTxHash); });
std::sort(vecProTxHashes.begin(), vecProTxHashes.end());
Expand Down
15 changes: 8 additions & 7 deletions src/coinjoin/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ MessageProcessingResult CCoinJoinClientQueueManager::ProcessMessage(NodeId from,
LogPrint(BCLog::COINJOIN, "DSQUEUE -- CoinJoin queue is ready, masternode=%s, queue=%s\n", dmn->proTxHash.ToString(), dsq.ToString());
return ret;
} else {
if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, tip_mn_list.GetValidMNsCount())) {
if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, tip_mn_list.GetCounts().enabled())) {
LogPrint(BCLog::COINJOIN, "DSQUEUE -- Masternode %s is sending too many dsq messages\n",
dmn->proTxHash.ToString());
return ret;
Expand Down Expand Up @@ -826,7 +826,7 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(ChainstateManager& chainman
return false;
}

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

int nMnCountEnabled = m_dmnman.GetListAtChainTip().GetValidMNsCount();
int nMnCountEnabled = m_dmnman.GetListAtChainTip().GetCounts().enabled();

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

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

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

const auto mnList = m_dmnman.GetListAtChainTip();
const int nWeightedMnCount = mnList.GetValidWeightedMNsCount();
const int nWeightedMnCount = mnList.GetCounts().m_valid_weighted;

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

int nTries = 0;
const auto mnList = m_dmnman.GetListAtChainTip();
const int nMnCount = mnList.GetValidMNsCount();
const int nWeightedMnCount = mnList.GetValidWeightedMNsCount();
const auto mnCounts = mnList.GetCounts();
const int nMnCount = mnCounts.enabled();
const int nWeightedMnCount = mnCounts.m_valid_weighted;

// find available denominated amounts
std::set<CAmount> setAmounts;
Expand Down
4 changes: 2 additions & 2 deletions src/coinjoin/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void CCoinJoinServer::ProcessDSACCEPT(CNode& peer, CDataStream& vRecv)
}
}

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

if (!dsq.fReady) {
//don't allow a few nodes to dominate the queuing process
if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, tip_mn_list.GetValidMNsCount())) {
if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, tip_mn_list.GetCounts().enabled())) {
LogPrint(BCLog::COINJOIN, "DSQUEUE -- node sending too many dsq messages, masternode=%s\n", dmn->proTxHash.ToString());
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/dummywallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Loader;
} // namespace CoinJoin
} // namespace interfaces
namespace node {
class NodeContext;
struct NodeContext;
} // namespace node
namespace wallet {
class CWallet;
Expand Down
Loading
Loading