Skip to content
Open
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
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
2 changes: 2 additions & 0 deletions src/qt/bitcoingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,8 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled)
openAction->setEnabled(enabled);
m_close_wallet_action->setEnabled(enabled);
m_close_all_wallets_action->setEnabled(enabled);

updateWidth();
}

void BitcoinGUI::createTrayIcon()
Expand Down
16 changes: 14 additions & 2 deletions src/qt/masternodelist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ bool MasternodeListSortFilterProxyModel::filterAcceptsRow(int source_row, const
// Banned filter
if (m_hide_banned) {
QModelIndex idx = sourceModel()->index(source_row, MasternodeModel::STATUS, source_parent);
int banned = sourceModel()->data(idx, Qt::EditRole).toInt();
if (banned != 0) {
int status_value = sourceModel()->data(idx, Qt::EditRole).toInt();
if (status_value > 0) {
return false;
}
Comment on lines +48 to 51
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n "poseBanHeight|pose_ban_height|PoSeBanHeight" --type=cpp --type=h -B2 -A2 | head -100

Repository: dashpay/dash

Length of output: 6749


🏁 Script executed:

# Find masternodemodel.cpp and examine the data() function around line 294
fd "masternodemodel.cpp" --type f

Repository: dashpay/dash

Length of output: 82


🏁 Script executed:

# Look for the STATUS column handling and ban logic
rg -n "STATUS.*EditRole|isBanned|ban_height" src/qt/ --type=cpp --type=h -B2 -A2 | head -150

Repository: dashpay/dash

Length of output: 4689


Banned nodes with unknown ban height will escape the "hide banned" filter.

When m_current_height > 0 and a banned node has no valid poseBanHeight() (nullopt or invalid value), the EditRole returns 0 at line 294. Since the filter checks status_value > 0 to hide banned nodes, a value of 0 won't be filtered out.

This is a real edge case: if the node state JSON lacks or has invalid PoSeBanHeight data, a banned node will display even when "Hide banned" is checked. While the node displays correctly with a banned icon, the filter logic should be consistent. Consider checking entry->isBanned() directly for the filter instead of relying on the EditRole value, or use >= 0 with a different sentinel for unknown ban times.

🤖 Prompt for AI Agents
In `@src/qt/masternodelist.cpp` around lines 48 - 51, The current filter uses the
EditRole integer (status_value) from sourceModel()->data(idx, Qt::EditRole) and
only hides nodes when status_value > 0, which lets banned nodes with
unknown/invalid poseBanHeight() (that return 0) slip through; update the filter
logic in masternodelist.cpp to explicitly check the model entry's ban state
instead of relying solely on the EditRole integer: fetch the underlying entry
(use the same lookup path you use elsewhere in this file to map idx to the
masternode entry), call entry->isBanned() or inspect entry->poseBanHeight()
(std::optional) and treat unknown/invalid values as banned when m_current_height
> 0, ensuring the "Hide banned" branch hides any entry where entry->isBanned()
is true or poseBanHeight() indicates a ban rather than relying on status_value >
0.

}
Expand All @@ -72,6 +72,18 @@ bool MasternodeListSortFilterProxyModel::filterAcceptsRow(int source_row, const
return true;
}

bool MasternodeListSortFilterProxyModel::lessThan(const QModelIndex& lhs, const QModelIndex& rhs) const
{
if (lhs.column() == MasternodeModel::SERVICE) {
QVariant lhs_data{sourceModel()->data(lhs, sortRole())};
QVariant rhs_data{sourceModel()->data(rhs, sortRole())};
if (lhs_data.userType() == QMetaType::QByteArray && rhs_data.userType() == QMetaType::QByteArray) {
return lhs_data.toByteArray() < rhs_data.toByteArray();
}
}
return QSortFilterProxyModel::lessThan(lhs, rhs);
}

MasternodeList::MasternodeList(QWidget* parent) :
QWidget(parent),
ui(new Ui::MasternodeList),
Expand Down
1 change: 1 addition & 0 deletions src/qt/masternodelist.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class MasternodeListSortFilterProxyModel : public QSortFilterProxyModel

protected:
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
bool lessThan(const QModelIndex& lhs, const QModelIndex& rhs) const override;

private:
bool m_hide_banned{true};
Expand Down
16 changes: 16 additions & 0 deletions src/qt/masternodemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,22 @@ QVariant MasternodeModel::data(const QModelIndex& index, int role) const
case Column::TYPE:
return static_cast<int>(entry->type());
case Column::STATUS:
if (m_current_height > 0) {
if (entry->isBanned()) {
// Banned nodes use positive values
if (auto ban_height = entry->poseBanHeight(); ban_height && *ban_height > 0) {
return m_current_height - *ban_height;
}
return 0; // Unknown ban time, treat as freshly banned
} else {
// Active nodes use negative values
int32_t active_height = entry->registeredHeight();
if (auto revived_height = entry->poseRevivedHeight(); revived_height && *revived_height > 0) {
active_height = *revived_height;
}
return -(m_current_height - active_height);
}
}
return entry->isBanned() ? 1 : 0;
case Column::POSE:
return entry->posePenalty();
Expand Down
8 changes: 3 additions & 5 deletions src/qt/overviewpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class TxViewDelegate : public QAbstractItemDelegate
QRect rectBottomHalf(mainRect.left() + xspace, mainRect.top() + ypad + halfheight + 5, mainRect.width() - xspace, halfheight);
QRect rectBounding;
QColor colorForeground;
qreal initialFontSize = painter->font().pointSizeF();
constexpr auto initial_size{GUIUtil::FontRegistry::DEFAULT_FONT_SIZE};

// Grab model indexes for desired data from TransactionTableModel
QModelIndex indexDate = index.sibling(index.row(), TransactionTableModel::Date);
Expand All @@ -72,7 +72,7 @@ class TxViewDelegate : public QAbstractItemDelegate

// Draw first line (with slightly bigger font than the second line will get)
// Content: Date/Time, Optional IS indicator, Amount
painter->setFont(GUIUtil::getScaledFont(/*baseSize=*/initialFontSize, /*bold=*/false, /*multiplier=*/1.17));
painter->setFont(GUIUtil::getScaledFont(/*baseSize=*/initial_size, /*bold=*/false, /*multiplier=*/1.17));
// Date/Time
colorForeground = qvariant_cast<QColor>(indexDate.data(Qt::ForegroundRole));
QString strDate = indexDate.data(Qt::DisplayRole).toString();
Expand All @@ -93,7 +93,7 @@ class TxViewDelegate : public QAbstractItemDelegate

// Draw second line (with the initial font)
// Content: Address/label, Optional Watchonly indicator
painter->setFont(GUIUtil::getScaledFont(/*baseSize=*/initialFontSize, /*bold=*/false));
painter->setFont(GUIUtil::getScaledFont(/*baseSize=*/initial_size, /*bold=*/false));
// Address/Label
colorForeground = qvariant_cast<QColor>(indexAddress.data(Qt::ForegroundRole));
QString address = indexAddress.data(Qt::DisplayRole).toString();
Expand Down Expand Up @@ -756,8 +756,6 @@ void OverviewPage::SetupTransactionList(int nNumItems)
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
filter->setShowInactive(false);
// Exclude dust receive transactions from overview
filter->setTypeFilter(TransactionFilterProxy::ALL_TYPES & ~TransactionFilterProxy::TYPE(TransactionRecord::DustReceive));
filter->sort(TransactionTableModel::Date, Qt::DescendingOrder);
ui->listTransactions->setModel(filter.get());
}
Expand Down
20 changes: 16 additions & 4 deletions src/qt/transactionfilterproxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
#define BITCOIN_QT_TRANSACTIONFILTERPROXY_H

#include <consensus/amount.h>
#include <qt/transactionrecord.h>

#include <QDateTime>
#include <QSortFilterProxyModel>

#include <optional>

/** Helper function to convert transaction type enum to bit field */
constexpr quint32 TransactionTypeToBit(int type) { return 1u << type; }

/** Filter the transaction list according to pre-specified rules. */
class TransactionFilterProxy : public QSortFilterProxyModel
{
Expand All @@ -20,12 +24,20 @@ class TransactionFilterProxy : public QSortFilterProxyModel
public:
explicit TransactionFilterProxy(QObject *parent = nullptr);

/** Types to exclude from common transaction lists (CoinJoin internal transactions and dust) */
static constexpr quint32 EXCLUDED_TYPES =
TransactionTypeToBit(TransactionRecord::CoinJoinCollateralPayment) |
TransactionTypeToBit(TransactionRecord::CoinJoinCreateDenominations) |
TransactionTypeToBit(TransactionRecord::CoinJoinMakeCollaterals) |
TransactionTypeToBit(TransactionRecord::CoinJoinMixing) |
TransactionTypeToBit(TransactionRecord::DustReceive) |
TransactionTypeToBit(TransactionRecord::RecvWithCoinJoin);
/** Type filter bit field (all types) */
static const quint32 ALL_TYPES = 0xFFFFFFFF;
/** Type filter bit field (all types but Darksend-SPAM) */
static const quint32 COMMON_TYPES = 0x307f;
static constexpr quint32 ALL_TYPES = 0xFFFFFFFF;
/** Type filter bit field (all types except excluded) */
static constexpr quint32 COMMON_TYPES = ALL_TYPES & ~EXCLUDED_TYPES;

static quint32 TYPE(int type) { return 1<<type; }
static constexpr quint32 TYPE(int type) { return TransactionTypeToBit(type); }

enum WatchOnlyFilter
{
Expand Down
2 changes: 1 addition & 1 deletion src/qt/transactionrecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ struct TransactionStatus {
class TransactionRecord
{
public:
// Update COMMON_TYPES in TransactionFilterProxyWhen when adding a new type
// Update EXCLUDED_TYPES in TransactionFilterProxy when adding a new type
enum Type
{
Other,
Expand Down
Loading