Skip to content

Commit 7ee5caa

Browse files
committed
Add fee estimator class.
1 parent 385fa6e commit 7ee5caa

10 files changed

Lines changed: 505 additions & 2 deletions

File tree

Makefile.am

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ src_libbitcoin_server_la_LIBADD = ${bitcoin_node_LIBS}
3737
src_libbitcoin_server_la_SOURCES = \
3838
src/configuration.cpp \
3939
src/error.cpp \
40+
src/estimator.cpp \
4041
src/parser.cpp \
4142
src/server_node.cpp \
4243
src/settings.cpp \
@@ -65,6 +66,7 @@ test_libbitcoin_server_test_LDADD = src/libbitcoin-server.la ${boost_unit_test_f
6566
test_libbitcoin_server_test_SOURCES = \
6667
test/configuration.cpp \
6768
test/error.cpp \
69+
test/estimator.cpp \
6870
test/main.cpp \
6971
test/settings.cpp \
7072
test/test.cpp \
@@ -128,6 +130,7 @@ include_bitcoin_server_HEADERS = \
128130
include/bitcoin/server/configuration.hpp \
129131
include/bitcoin/server/define.hpp \
130132
include/bitcoin/server/error.hpp \
133+
include/bitcoin/server/estimator.hpp \
131134
include/bitcoin/server/parser.hpp \
132135
include/bitcoin/server/server_node.hpp \
133136
include/bitcoin/server/settings.hpp \

builds/cmake/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ add_definitions(
236236
add_library( ${CANONICAL_LIB_NAME}
237237
"../../src/configuration.cpp"
238238
"../../src/error.cpp"
239+
"../../src/estimator.cpp"
239240
"../../src/parser.cpp"
240241
"../../src/server_node.cpp"
241242
"../../src/settings.cpp"
@@ -288,10 +289,17 @@ if (with-tests)
288289
add_executable( libbitcoin-server-test
289290
"../../test/configuration.cpp"
290291
"../../test/error.cpp"
292+
"../../test/estimator.cpp"
291293
"../../test/main.cpp"
292294
"../../test/settings.cpp"
293295
"../../test/test.cpp"
294296
"../../test/test.hpp"
297+
"../../test/endpoints/README.md"
298+
"../../test/endpoints/bitcoind_rpc.py"
299+
"../../test/endpoints/configuration.py"
300+
"../../test/endpoints/electrum.py"
301+
"../../test/endpoints/native.py"
302+
"../../test/endpoints/utils.py"
295303
"../../test/parsers/bitcoind_query.cpp"
296304
"../../test/parsers/bitcoind_target.cpp"
297305
"../../test/parsers/native_query.cpp"

builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,11 @@
118118
<Import Project="$(ProjectDir)$(ProjectName).props" />
119119
</ImportGroup>
120120
<ItemGroup>
121-
<ClCompile Include="..\..\..\..\test\configuration.cpp" />
121+
<ClCompile Include="..\..\..\..\test\configuration.cpp">
122+
<ObjectFileName>$(IntDir)test_configuration.obj</ObjectFileName>
123+
</ClCompile>
122124
<ClCompile Include="..\..\..\..\test\error.cpp" />
125+
<ClCompile Include="..\..\..\..\test\estimator.cpp" />
123126
<ClCompile Include="..\..\..\..\test\main.cpp" />
124127
<ClCompile Include="..\..\..\..\test\parsers\bitcoind_query.cpp" />
125128
<ClCompile Include="..\..\..\..\test\parsers\bitcoind_target.cpp" />

builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010
<Filter Include="src">
1111
<UniqueIdentifier>{66A0E586-2E3A-448F-0000-000000000000}</UniqueIdentifier>
1212
</Filter>
13-
<Filter Include="src\parsers">
13+
<Filter Include="src\endpoints">
1414
<UniqueIdentifier>{66A0E586-2E3A-448F-0000-000000000001}</UniqueIdentifier>
1515
</Filter>
16+
<Filter Include="src\parsers">
17+
<UniqueIdentifier>{66A0E586-2E3A-448F-0000-000000000002}</UniqueIdentifier>
18+
</Filter>
1619
</ItemGroup>
1720
<ItemGroup>
1821
<ClCompile Include="..\..\..\..\test\configuration.cpp">
@@ -21,6 +24,9 @@
2124
<ClCompile Include="..\..\..\..\test\error.cpp">
2225
<Filter>src</Filter>
2326
</ClCompile>
27+
<ClCompile Include="..\..\..\..\test\estimator.cpp">
28+
<Filter>src</Filter>
29+
</ClCompile>
2430
<ClCompile Include="..\..\..\..\test\main.cpp">
2531
<Filter>src</Filter>
2632
</ClCompile>

builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@
123123
<ItemGroup>
124124
<ClCompile Include="..\..\..\..\src\configuration.cpp" />
125125
<ClCompile Include="..\..\..\..\src\error.cpp" />
126+
<ClCompile Include="..\..\..\..\src\estimator.cpp" />
126127
<ClCompile Include="..\..\..\..\src\parser.cpp" />
127128
<ClCompile Include="..\..\..\..\src\parsers\bitcoind_query.cpp" />
128129
<ClCompile Include="..\..\..\..\src\parsers\bitcoind_target.cpp" />
@@ -151,6 +152,7 @@
151152
<ClInclude Include="..\..\..\..\include\bitcoin\server\configuration.hpp" />
152153
<ClInclude Include="..\..\..\..\include\bitcoin\server\define.hpp" />
153154
<ClInclude Include="..\..\..\..\include\bitcoin\server\error.hpp" />
155+
<ClInclude Include="..\..\..\..\include\bitcoin\server\estimator.hpp" />
154156
<ClInclude Include="..\..\..\..\include\bitcoin\server\interfaces\bitcoind_rest.hpp" />
155157
<ClInclude Include="..\..\..\..\include\bitcoin\server\interfaces\bitcoind_rpc.hpp" />
156158
<ClInclude Include="..\..\..\..\include\bitcoin\server\interfaces\electrum.hpp" />

builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
<ClCompile Include="..\..\..\..\src\error.cpp">
5858
<Filter>src</Filter>
5959
</ClCompile>
60+
<ClCompile Include="..\..\..\..\src\estimator.cpp">
61+
<Filter>src</Filter>
62+
</ClCompile>
6063
<ClCompile Include="..\..\..\..\src\parser.cpp">
6164
<Filter>src</Filter>
6265
</ClCompile>
@@ -137,6 +140,9 @@
137140
<ClInclude Include="..\..\..\..\include\bitcoin\server\error.hpp">
138141
<Filter>include\bitcoin\server</Filter>
139142
</ClInclude>
143+
<ClInclude Include="..\..\..\..\include\bitcoin\server\estimator.hpp">
144+
<Filter>include\bitcoin\server</Filter>
145+
</ClInclude>
140146
<ClInclude Include="..\..\..\..\include\bitcoin\server\interfaces\bitcoind_rest.hpp">
141147
<Filter>include\bitcoin\server\interfaces</Filter>
142148
</ClInclude>

include/bitcoin/server.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <bitcoin/server/configuration.hpp>
1919
#include <bitcoin/server/define.hpp>
2020
#include <bitcoin/server/error.hpp>
21+
#include <bitcoin/server/estimator.hpp>
2122
#include <bitcoin/server/parser.hpp>
2223
#include <bitcoin/server/server_node.hpp>
2324
#include <bitcoin/server/settings.hpp>
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/**
2+
* Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
3+
*
4+
* This file is part of libbitcoin.
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Affero General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Affero General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
#ifndef LIBBITCOIN_SERVER_ESTIMATOR_HPP
20+
#define LIBBITCOIN_SERVER_ESTIMATOR_HPP
21+
22+
#include <atomic>
23+
#include <bitcoin/server.hpp>
24+
25+
namespace libbitcoin {
26+
namespace server {
27+
28+
class BCS_API estimator
29+
{
30+
public:
31+
DELETE_COPY_MOVE_DESTRUCT(estimator);
32+
33+
/// Estimation modes.
34+
enum class mode
35+
{
36+
basic,
37+
markov,
38+
economical,
39+
conservative
40+
};
41+
42+
estimator() NOEXCEPT {};
43+
44+
/// Fee estimation in satoshis / transaction virtual size.
45+
/// Pass zero to target next block for confirmation, range:0..1007.
46+
uint64_t estimate(size_t target, mode mode) const NOEXCEPT;
47+
48+
/// Populate accumulator.
49+
bool initialize(std::atomic_bool& cancel, const node::query& query,
50+
size_t top, size_t count) NOEXCEPT;
51+
52+
/// Update accumulator.
53+
bool push(const node::query& query) NOEXCEPT;
54+
bool pop(const node::query& query) NOEXCEPT;
55+
56+
/// Top height of accumulator.
57+
size_t top_height() const NOEXCEPT;
58+
59+
protected:
60+
using rates = database::fee_rates;
61+
using rate_sets = database::fee_rate_sets;
62+
63+
/// Bucket count sizing parameters.
64+
enum horizon : size_t
65+
{
66+
small = 12,
67+
medium = 48,
68+
large = 1008
69+
};
70+
71+
/// Estimation confidences.
72+
struct confidence
73+
{
74+
static constexpr double low = 0.60;
75+
static constexpr double mid = 0.85;
76+
static constexpr double high = 0.95;
77+
};
78+
79+
/// Bucket count sizing parameters.
80+
struct sizing
81+
{
82+
static constexpr double min = 0.1;
83+
static constexpr double max = 100'000.0;
84+
static constexpr double step = 1.05;
85+
86+
/// Derived from min/max/step above.
87+
static constexpr size_t count = 283;
88+
};
89+
90+
/// Accumulator (persistent, decay-weighted counters).
91+
struct accumulator
92+
{
93+
template <size_t Depth>
94+
struct bucket
95+
{
96+
/// Total scaled txs in bucket.
97+
std::atomic<size_t> total{};
98+
99+
/// confirmed[n]: scaled txs confirmed in > n blocks.
100+
std::array<std::atomic<size_t>, Depth> confirmed;
101+
};
102+
103+
/// Current block height of accumulated state.
104+
size_t top_height{};
105+
106+
/// Accumulated scaled fee in decayed buckets by horizon.
107+
/// Array count is the half life of the decay it implies.
108+
std::array<bucket<horizon::small>, sizing::count> small{};
109+
std::array<bucket<horizon::medium>, sizing::count> medium{};
110+
std::array<bucket<horizon::large>, sizing::count> large{};
111+
};
112+
113+
// C++23: make consteval (std::pow).
114+
static inline double decay_rate() NOEXCEPT
115+
{
116+
static const auto rate = std::pow(0.5, 1.0 / sizing::count);
117+
return rate;
118+
}
119+
120+
static inline double to_scale_term(size_t age) NOEXCEPT
121+
{
122+
return std::pow(decay_rate(), age);
123+
}
124+
125+
static inline double to_scale_factor(bool push) NOEXCEPT
126+
{
127+
return std::pow(decay_rate(), push ? +1.0 : -1.0);
128+
}
129+
130+
const accumulator& history() const NOEXCEPT;
131+
bool initialize(const rate_sets& blocks) NOEXCEPT;
132+
bool push(const rates& block) NOEXCEPT;
133+
bool pop(const rates& block) NOEXCEPT;
134+
uint64_t compute(size_t target, double confidence,
135+
bool markov=false) const NOEXCEPT;
136+
137+
private:
138+
bool update(const rates& block, size_t height, bool push) NOEXCEPT;
139+
void decay(auto& buckets, double factor) NOEXCEPT;
140+
void decay(bool push) NOEXCEPT;
141+
142+
accumulator fees_{};
143+
};
144+
145+
} // namespace server
146+
} // namespace libbitcoin
147+
148+
#endif

0 commit comments

Comments
 (0)