Coverage Report

Created: 2026-08-25 19:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/banman.cpp
Line
Count
Source
1
// Copyright (c) 2009-2010 Satoshi Nakamoto
2
// Copyright (c) 2009-present The Bitcoin 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
#include <banman.h>
7
8
#include <common/system.h>
9
#include <netaddress.h>
10
#include <node/interface_ui.h>
11
#include <sync.h>
12
#include <util/log.h>
13
#include <util/time.h>
14
#include <util/translation.h>
15
16
17
BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
18
4.61k
    : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
19
4.61k
{
20
4.61k
    LoadBanlist();
21
4.61k
    DumpBanlist();
22
4.61k
}
23
24
BanMan::~BanMan()
25
4.64k
{
26
4.64k
    DumpBanlist();
27
4.64k
}
28
29
void BanMan::LoadBanlist()
30
4.61k
{
31
4.61k
    LOCK(m_banned_mutex);
32
33
4.61k
    if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…"));
  Branch (33:9): [True: 0, False: 4.61k]
34
35
4.61k
    const auto start{SteadyClock::now()};
36
4.61k
    if (m_ban_db.Read(m_banned)) {
  Branch (36:9): [True: 2.61k, False: 1.99k]
37
2.61k
        SweepBanned(); // sweep out unused entries
38
39
2.61k
        LogDebug(BCLog::NET, "Loaded %d banned node addresses/subnets %dms", m_banned.size(),
40
2.61k
                 Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
41
2.61k
    } else {
42
1.99k
        LogInfo("Recreating the banlist database");
43
1.99k
        m_banned = {};
44
1.99k
        m_is_dirty = true;
45
1.99k
    }
46
4.61k
}
47
48
void BanMan::DumpBanlist()
49
50.2k
{
50
50.2k
    static Mutex dump_mutex;
51
50.2k
    LOCK(dump_mutex);
52
53
50.2k
    banmap_t banmap;
54
50.2k
    {
55
50.2k
        LOCK(m_banned_mutex);
56
50.2k
        SweepBanned();
57
50.2k
        if (!m_is_dirty) return;
  Branch (57:13): [True: 10.2k, False: 40.0k]
58
40.0k
        banmap = m_banned;
59
40.0k
        m_is_dirty = false;
60
40.0k
    }
61
62
0
    const auto start{SteadyClock::now()};
63
40.0k
    if (!m_ban_db.Write(banmap)) {
  Branch (63:9): [True: 8.56k, False: 31.4k]
64
8.56k
        LOCK(m_banned_mutex);
65
8.56k
        m_is_dirty = true;
66
8.56k
    }
67
68
40.0k
    LogDebug(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms", banmap.size(),
69
40.0k
             Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
70
40.0k
}
71
72
void BanMan::ClearBanned()
73
4.98k
{
74
4.98k
    {
75
4.98k
        LOCK(m_banned_mutex);
76
4.98k
        m_banned.clear();
77
4.98k
        m_is_dirty = true;
78
4.98k
    }
79
4.98k
    DumpBanlist(); //store banlist to disk
80
4.98k
    if (m_client_interface) m_client_interface->BannedListChanged();
  Branch (80:9): [True: 0, False: 4.98k]
81
4.98k
}
82
83
bool BanMan::IsDiscouraged(const CNetAddr& net_addr)
84
6.44k
{
85
6.44k
    LOCK(m_banned_mutex);
86
6.44k
    return m_discouraged.contains(net_addr.GetAddrBytes());
87
6.44k
}
88
89
bool BanMan::IsBanned(const CNetAddr& net_addr)
90
6.43k
{
91
6.43k
    auto current_time = GetTime();
92
6.43k
    LOCK(m_banned_mutex);
93
103k
    for (const auto& it : m_banned) {
  Branch (93:25): [True: 103k, False: 4.57k]
94
103k
        CSubNet sub_net = it.first;
95
103k
        CBanEntry ban_entry = it.second;
96
97
103k
        if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
  Branch (97:13): [True: 94.8k, False: 8.34k]
  Branch (97:51): [True: 1.85k, False: 93.0k]
98
1.85k
            return true;
99
1.85k
        }
100
103k
    }
101
4.57k
    return false;
102
6.43k
}
103
104
bool BanMan::IsBanned(const CSubNet& sub_net)
105
4.59k
{
106
4.59k
    auto current_time = GetTime();
107
4.59k
    LOCK(m_banned_mutex);
108
4.59k
    banmap_t::iterator i = m_banned.find(sub_net);
109
4.59k
    if (i != m_banned.end()) {
  Branch (109:9): [True: 1.81k, False: 2.78k]
110
1.81k
        CBanEntry ban_entry = (*i).second;
111
1.81k
        if (current_time < ban_entry.nBanUntil) {
  Branch (111:13): [True: 1.08k, False: 728]
112
1.08k
            return true;
113
1.08k
        }
114
1.81k
    }
115
3.51k
    return false;
116
4.59k
}
117
118
void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch)
119
34.6k
{
120
34.6k
    CSubNet sub_net(net_addr);
121
34.6k
    Ban(sub_net, ban_time_offset, since_unix_epoch);
122
34.6k
}
123
124
void BanMan::Discourage(const CNetAddr& net_addr)
125
4.72k
{
126
4.72k
    LOCK(m_banned_mutex);
127
4.72k
    m_discouraged.insert(net_addr.GetAddrBytes());
128
4.72k
}
129
130
void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch)
131
42.2k
{
132
42.2k
    CBanEntry ban_entry(GetTime());
133
134
42.2k
    int64_t normalized_ban_time_offset = ban_time_offset;
135
42.2k
    bool normalized_since_unix_epoch = since_unix_epoch;
136
42.2k
    if (ban_time_offset <= 0) {
  Branch (136:9): [True: 41.1k, False: 1.08k]
137
41.1k
        normalized_ban_time_offset = m_default_ban_time;
138
41.1k
        normalized_since_unix_epoch = false;
139
41.1k
    }
140
42.2k
    ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset;
  Branch (140:28): [True: 716, False: 41.5k]
141
142
42.2k
    {
143
42.2k
        LOCK(m_banned_mutex);
144
42.2k
        if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) {
  Branch (144:13): [True: 25.8k, False: 16.4k]
145
25.8k
            m_banned[sub_net] = ban_entry;
146
25.8k
            m_is_dirty = true;
147
25.8k
        } else
148
16.4k
            return;
149
42.2k
    }
150
25.8k
    if (m_client_interface) m_client_interface->BannedListChanged();
  Branch (150:9): [True: 0, False: 25.8k]
151
152
    //store banlist to disk immediately
153
25.8k
    DumpBanlist();
154
25.8k
}
155
156
bool BanMan::Unban(const CNetAddr& net_addr)
157
6.05k
{
158
6.05k
    CSubNet sub_net(net_addr);
159
6.05k
    return Unban(sub_net);
160
6.05k
}
161
162
bool BanMan::Unban(const CSubNet& sub_net)
163
8.83k
{
164
8.83k
    {
165
8.83k
        LOCK(m_banned_mutex);
166
8.83k
        if (m_banned.erase(sub_net) == 0) return false;
  Branch (166:13): [True: 6.77k, False: 2.05k]
167
2.05k
        m_is_dirty = true;
168
2.05k
    }
169
2.05k
    if (m_client_interface) m_client_interface->BannedListChanged();
  Branch (169:9): [True: 0, False: 2.05k]
170
2.05k
    DumpBanlist(); //store banlist to disk immediately
171
2.05k
    return true;
172
8.83k
}
173
174
void BanMan::GetBanned(banmap_t& banmap)
175
6.53k
{
176
6.53k
    LOCK(m_banned_mutex);
177
    // Sweep the banlist so expired bans are not returned
178
6.53k
    SweepBanned();
179
6.53k
    banmap = m_banned; //create a thread safe copy
180
6.53k
}
181
182
void BanMan::SweepBanned()
183
59.3k
{
184
59.3k
    AssertLockHeld(m_banned_mutex);
185
186
59.3k
    int64_t now = GetTime();
187
59.3k
    bool notify_ui = false;
188
59.3k
    banmap_t::iterator it = m_banned.begin();
189
1.61M
    while (it != m_banned.end()) {
  Branch (189:12): [True: 1.55M, False: 59.3k]
190
1.55M
        CSubNet sub_net = (*it).first;
191
1.55M
        CBanEntry ban_entry = (*it).second;
192
1.55M
        if (!sub_net.IsValid() || now > ban_entry.nBanUntil) {
  Branch (192:13): [True: 2.69k, False: 1.55M]
  Branch (192:35): [True: 5.93k, False: 1.54M]
193
8.62k
            m_banned.erase(it++);
194
8.62k
            m_is_dirty = true;
195
8.62k
            notify_ui = true;
196
8.62k
            LogDebug(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString());
197
1.54M
        } else {
198
1.54M
            ++it;
199
1.54M
        }
200
1.55M
    }
201
202
    // update UI
203
59.3k
    if (notify_ui && m_client_interface) {
  Branch (203:9): [True: 4.48k, False: 54.8k]
  Branch (203:22): [True: 0, False: 4.48k]
204
0
        m_client_interface->BannedListChanged();
205
0
    }
206
59.3k
}