mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
Merge #6020: backport: bitcoin#21053, #22082, #22118, #22292, #22308, #22334, #22358, #22388, bitcoin-core/gui#271, #311
0bed7b4702
Merge bitcoin/bitcoin#22292: bench, doc: benchmarking updates and fixups (fanquake)c95df68637
Merge bitcoin/bitcoin#22388: ci: use Ubuntu 20.04 as the default Docker container (MarcoFalke)c586ca5b56
Merge bitcoin/bitcoin#22334: wallet: do not spam about non-existent spk managers (fanquake)62f9394374
Merge bitcoin/bitcoin#22308: wallet: Add missing BlockUntilSyncedToCurrentChain (MarcoFalke)240d8efb82
Merge bitcoin/bitcoin#22358: Remove unused wallet pointer from wallet signals (fanquake)9a1500ab47
Merge bitcoin/bitcoin#22118: test: check anchors.dat when node starts for the first time (MarcoFalke)262c8b6f44
Merge bitcoin/bitcoin#22082: test: update nanobench from release 4.0.0 to 4.3.4 (MarcoFalke)3d2cea667b
Merge bitcoin-core/gui#311: Peers Window rename 'Peer id' to 'Peer' (Hennadii Stepanov)dc498be3be
Merge bitcoin-core/gui#271: Don't clear console prompt when font resizing (W. J. van der Laan)1ed2d2d891
Merge #21053: rpc, test: document {previous,next}blockhash as optional (MarcoFalke) Pull request description: ## Issue being fixed or feature implemented Regular backports from bitcoin v22 ## What was done? - bitcoin/bitcoin#21053 - bitcoin-core/gui#271 - bitcoin-core/gui#311 - bitcoin/bitcoin#22082 - bitcoin/bitcoin#22118 - bitcoin/bitcoin#22358 - bitcoin/bitcoin#22308 - bitcoin/bitcoin#22334 - bitcoin/bitcoin#22388 - bitcoin/bitcoin#22292 ## How Has This Been Tested? Run unit/functional tests ## Breaking Changes N/A ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone ACKs for top commit: PastaPastaPasta: utACK0bed7b4702
Tree-SHA512: 8354297857516ddf94b242f2e50e1a28d999e613da2a7eb90c603e1fee7212e46d6e8a20ad42aa2945b48137e98fc7f589c9c77469c71cc01d032a33fa6da517
This commit is contained in:
commit
1fc62c81a0
@ -50,7 +50,7 @@ export RUN_SYMBOL_TESTS=${RUN_SYMBOL_TESTS:-false}
|
||||
export EXPECTED_TESTS_DURATION_IN_SECONDS=${EXPECTED_TESTS_DURATION_IN_SECONDS:-1000}
|
||||
|
||||
export CONTAINER_NAME=${CONTAINER_NAME:-ci_unnamed}
|
||||
export DOCKER_NAME_TAG=${DOCKER_NAME_TAG:-ubuntu:focal}
|
||||
export DOCKER_NAME_TAG=${DOCKER_NAME_TAG:-ubuntu:20.04}
|
||||
# Randomize test order.
|
||||
# See https://www.boost.org/doc/libs/1_71_0/libs/test/doc/html/boost_test/utf_reference/rt_param_reference/random.html
|
||||
export BOOST_TEST_RANDOM=${BOOST_TEST_RANDOM:-1}
|
||||
|
@ -8,8 +8,10 @@ thread queue, wallet balance.
|
||||
Running
|
||||
---------------------
|
||||
|
||||
For benchmarks purposes you only need to compile `dash_bench`. Beware of configuring without `--enable-debug` as this would impact
|
||||
benchmarking by unlatching log printers and lock analysis.
|
||||
For benchmarking, you only need to compile `dash_bench`. The bench runner
|
||||
warns if you configure with `--enable-debug`, but consider if building without
|
||||
it will impact the benchmark(s) you are interested in by unlatching log printers
|
||||
and lock analysis.
|
||||
|
||||
make -C src dash_bench
|
||||
|
||||
@ -19,19 +21,28 @@ After compiling Dash Core, the benchmarks can be run with:
|
||||
|
||||
The output will look similar to:
|
||||
```
|
||||
| ns/byte | byte/s | error % | benchmark
|
||||
|--------------------:|--------------------:|--------:|:----------------------------------------------
|
||||
| 64.13 | 15,592,356.01 | 0.1% | `Base58CheckEncode`
|
||||
| 24.56 | 40,722,672.68 | 0.2% | `Base58Decode`
|
||||
| ns/op | op/s | err% | total | benchmark
|
||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||
| 57,927,463.00 | 17.26 | 3.6% | 0.66 | `AddrManAdd`
|
||||
| 677,816.00 | 1,475.33 | 4.9% | 0.01 | `AddrManGetAddr`
|
||||
|
||||
...
|
||||
|
||||
| ns/byte | byte/s | err% | total | benchmark
|
||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||
| 127.32 | 7,854,302.69 | 0.3% | 0.00 | `Base58CheckEncode`
|
||||
| 31.95 | 31,303,226.99 | 0.2% | 0.00 | `Base58Decode`
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
Help
|
||||
---------------------
|
||||
|
||||
src/bench/bench_dash --help
|
||||
src/bench/bench_dash -?
|
||||
|
||||
To print options like scaling factor or per-benchmark filter.
|
||||
To print the various options, like listing the benchmarks without running them
|
||||
or using a regex filter to only run certain benchmarks.
|
||||
|
||||
Notes
|
||||
---------------------
|
||||
|
@ -18,16 +18,19 @@
|
||||
/*
|
||||
* Usage:
|
||||
|
||||
static void CODE_TO_TIME(benchmark::Bench& bench)
|
||||
static void NameOfYourBenchmarkFunction(benchmark::Bench& bench)
|
||||
{
|
||||
... do any setup needed...
|
||||
nanobench::Config().run([&] {
|
||||
... do stuff you want to time...
|
||||
...do any setup needed...
|
||||
|
||||
bench.run([&] {
|
||||
...do stuff you want to time; refer to src/bench/nanobench.h
|
||||
for more information and the options that can be passed here...
|
||||
});
|
||||
... do any cleanup needed...
|
||||
|
||||
...do any cleanup needed...
|
||||
}
|
||||
|
||||
BENCHMARK(CODE_TO_TIME);
|
||||
BENCHMARK(NameOfYourBenchmarkFunction);
|
||||
|
||||
*/
|
||||
|
||||
@ -55,7 +58,8 @@ public:
|
||||
|
||||
static void RunAll(const Args& args);
|
||||
};
|
||||
}
|
||||
} // namespace benchmark
|
||||
|
||||
// BENCHMARK(foo) expands to: benchmark::BenchRunner bench_11foo("foo", foo);
|
||||
#define BENCHMARK(n) \
|
||||
benchmark::BenchRunner PASTE2(bench_, PASTE2(__LINE__, n))(STRINGIZE(n), n);
|
||||
|
@ -17,11 +17,11 @@ static void SetupBenchArgs(ArgsManager& argsman)
|
||||
{
|
||||
SetupHelpOptions(argsman);
|
||||
|
||||
argsman.AddArg("-list", "List benchmarks without executing them", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-asymptote=n1,n2,n3,...", "Test asymptotic growth of the runtime of an algorithm, if supported by the benchmark", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-filter=<regex>", strprintf("Regular expression filter to select benchmark by name (default: %s)", DEFAULT_BENCH_FILTER), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-asymptote=n1,n2,n3,...", strprintf("Test asymptotic growth of the runtime of an algorithm, if supported by the benchmark"), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-output_csv=<output.csv>", "Generate CSV file with the most important benchmark results.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-output_json=<output.json>", "Generate JSON file with all benchmark results.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-list", "List benchmarks without executing them", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-output_csv=<output.csv>", "Generate CSV file with the most important benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-output_json=<output.json>", "Generate JSON file with all benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
}
|
||||
|
||||
// parses a comma separated list like "10,20,30,50"
|
||||
|
@ -7,7 +7,7 @@
|
||||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019-2020 Martin Ankerl <martin.ankerl@gmail.com>
|
||||
// Copyright (c) 2019-2021 Martin Ankerl <martin.ankerl@gmail.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@ -32,8 +32,8 @@
|
||||
|
||||
// see https://semver.org/
|
||||
#define ANKERL_NANOBENCH_VERSION_MAJOR 4 // incompatible API changes
|
||||
#define ANKERL_NANOBENCH_VERSION_MINOR 0 // backwards-compatible changes
|
||||
#define ANKERL_NANOBENCH_VERSION_PATCH 0 // backwards-compatible bug fixes
|
||||
#define ANKERL_NANOBENCH_VERSION_MINOR 3 // backwards-compatible changes
|
||||
#define ANKERL_NANOBENCH_VERSION_PATCH 4 // backwards-compatible bug fixes
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// public facing api - as minimal as possible
|
||||
@ -78,12 +78,20 @@
|
||||
|
||||
#if defined(ANKERL_NANOBENCH_LOG_ENABLED)
|
||||
# include <iostream>
|
||||
# define ANKERL_NANOBENCH_LOG(x) std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << x << std::endl
|
||||
# define ANKERL_NANOBENCH_LOG(x) \
|
||||
do { \
|
||||
std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << x << std::endl; \
|
||||
} while (0)
|
||||
#else
|
||||
# define ANKERL_NANOBENCH_LOG(x)
|
||||
# define ANKERL_NANOBENCH_LOG(x) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(ANKERL_NANOBENCH_DISABLE_PERF_COUNTERS)
|
||||
#if defined(__linux__) && defined(PERF_EVENT_IOC_ID) && defined(PERF_COUNT_HW_REF_CPU_CYCLES) && defined(PERF_FLAG_FD_CLOEXEC) && \
|
||||
!defined(ANKERL_NANOBENCH_DISABLE_PERF_COUNTERS)
|
||||
// only enable perf counters on kernel 3.14 which seems to have all the necessary defines. The three PERF_... defines are not in
|
||||
// kernel 2.6.32 (all others are).
|
||||
# define ANKERL_NANOBENCH_PRIVATE_PERF_COUNTERS() 1
|
||||
#else
|
||||
# define ANKERL_NANOBENCH_PRIVATE_PERF_COUNTERS() 0
|
||||
@ -173,7 +181,7 @@ class BigO;
|
||||
* `contextswitches`, `instructions`, `branchinstructions`, and `branchmisses`. All the measuers (except `iterations`) are
|
||||
* provided for a single iteration (so `elapsed` is the time a single iteration took). The following tags are available:
|
||||
*
|
||||
* * `{{median(<name>>)}}` Calculate median of a measurement data set, e.g. `{{median(elapsed)}}`.
|
||||
* * `{{median(<name>)}}` Calculate median of a measurement data set, e.g. `{{median(elapsed)}}`.
|
||||
*
|
||||
* * `{{average(<name>)}}` Average (mean) calculation.
|
||||
*
|
||||
@ -181,10 +189,11 @@ class BigO;
|
||||
* metric for the variation of measurements. It is more robust to outliers than the
|
||||
* [Mean absolute percentage error (M-APE)](https://en.wikipedia.org/wiki/Mean_absolute_percentage_error).
|
||||
* @f[
|
||||
* \mathrm{medianAbsolutePercentError}(e) = \mathrm{median}\{| \frac{e_i - \mathrm{median}\{e\}}{e_i}| \}
|
||||
* \mathrm{MdAPE}(e) = \mathrm{med}\{| \frac{e_i - \mathrm{med}\{e\}}{e_i}| \}
|
||||
* @f]
|
||||
* E.g. for *elapsed*: First, @f$ \mathrm{median}\{elapsed\} @f$ is calculated. This is used to calculate the absolute percentage
|
||||
* error to this median for each measurement, as in @f$ | \frac{e_i - \mathrm{median}\{e\}}{e_i}| @f$. All these results
|
||||
* E.g. for *elapsed*: First, @f$ \mathrm{med}\{e\} @f$ calculates the median by sorting and then taking the middle element
|
||||
* of all *elapsed* measurements. This is used to calculate the absolute percentage
|
||||
* error to this median for each measurement, as in @f$ | \frac{e_i - \mathrm{med}\{e\}}{e_i}| @f$. All these results
|
||||
* are sorted, and the middle value is chosen as the median absolute percent error.
|
||||
*
|
||||
* This measurement is a bit hard to interpret, but it is very robust against outliers. E.g. a value of 5% means that half of the
|
||||
@ -207,7 +216,7 @@ class BigO;
|
||||
*
|
||||
* * `{{#measurement}}` To access individual measurement results, open the begin tag for measurements.
|
||||
*
|
||||
* * `{{elapsed}}` Average elapsed time per iteration, in seconds.
|
||||
* * `{{elapsed}}` Average elapsed wall clock time per iteration, in seconds.
|
||||
*
|
||||
* * `{{iterations}}` Number of iterations in the measurement. The number of iterations will fluctuate due
|
||||
* to some applied randomness, to enhance accuracy.
|
||||
@ -261,6 +270,7 @@ class BigO;
|
||||
* :cpp:func:`templates::csv() <ankerl::nanobench::templates::csv()>`
|
||||
* :cpp:func:`templates::json() <ankerl::nanobench::templates::json()>`
|
||||
* :cpp:func:`templates::htmlBoxplot() <ankerl::nanobench::templates::htmlBoxplot()>`
|
||||
* :cpp:func:`templates::pyperf() <ankerl::nanobench::templates::pyperf()>`
|
||||
|
||||
@endverbatim
|
||||
*
|
||||
@ -269,6 +279,7 @@ class BigO;
|
||||
* @param out Output for the generated output.
|
||||
*/
|
||||
void render(char const* mustacheTemplate, Bench const& bench, std::ostream& out);
|
||||
void render(std::string const& mustacheTemplate, Bench const& bench, std::ostream& out);
|
||||
|
||||
/**
|
||||
* Same as render(char const* mustacheTemplate, Bench const& bench, std::ostream& out), but for when
|
||||
@ -279,6 +290,7 @@ void render(char const* mustacheTemplate, Bench const& bench, std::ostream& out)
|
||||
* @param out Output for the generated output.
|
||||
*/
|
||||
void render(char const* mustacheTemplate, std::vector<Result> const& results, std::ostream& out);
|
||||
void render(std::string const& mustacheTemplate, std::vector<Result> const& results, std::ostream& out);
|
||||
|
||||
// Contains mustache-like templates
|
||||
namespace templates {
|
||||
@ -297,7 +309,7 @@ char const* csv() noexcept;
|
||||
/*!
|
||||
@brief HTML output that uses plotly to generate an interactive boxplot chart. See the tutorial for an example output.
|
||||
|
||||
The output uses only the elapsed time, and displays each epoch as a single dot.
|
||||
The output uses only the elapsed wall clock time, and displays each epoch as a single dot.
|
||||
@verbatim embed:rst
|
||||
See the tutorial at :ref:`tutorial-template-html` for an example.
|
||||
@endverbatim
|
||||
@ -306,6 +318,14 @@ char const* csv() noexcept;
|
||||
*/
|
||||
char const* htmlBoxplot() noexcept;
|
||||
|
||||
/*!
|
||||
@brief Output in pyperf compatible JSON format, which can be used for more analyzations.
|
||||
@verbatim embed:rst
|
||||
See the tutorial at :ref:`tutorial-template-pyperf` for an example how to further analyze the output.
|
||||
@endverbatim
|
||||
*/
|
||||
char const* pyperf() noexcept;
|
||||
|
||||
/*!
|
||||
@brief Template to generate JSON data.
|
||||
|
||||
@ -369,6 +389,8 @@ struct Config {
|
||||
uint64_t mEpochIterations{0}; // If not 0, run *exactly* these number of iterations per epoch.
|
||||
uint64_t mWarmup = 0;
|
||||
std::ostream* mOut = nullptr;
|
||||
std::chrono::duration<double> mTimeUnit = std::chrono::nanoseconds{1};
|
||||
std::string mTimeUnitName = "ns";
|
||||
bool mShowPerformanceCounters = true;
|
||||
bool mIsRelative = false;
|
||||
|
||||
@ -504,6 +526,7 @@ public:
|
||||
*/
|
||||
explicit Rng(uint64_t seed) noexcept;
|
||||
Rng(uint64_t x, uint64_t y) noexcept;
|
||||
Rng(std::vector<uint64_t> const& data);
|
||||
|
||||
/**
|
||||
* Creates a copy of the Rng, thus the copy provides exactly the same random sequence as the original.
|
||||
@ -558,6 +581,14 @@ public:
|
||||
template <typename Container>
|
||||
void shuffle(Container& container) noexcept;
|
||||
|
||||
/**
|
||||
* Extracts the full state of the generator, e.g. for serialization. For this RNG this is just 2 values, but to stay API compatible
|
||||
* with future implementations that potentially use more state, we use a vector.
|
||||
*
|
||||
* @return Vector containing the full state:
|
||||
*/
|
||||
std::vector<uint64_t> state() const;
|
||||
|
||||
private:
|
||||
static constexpr uint64_t rotl(uint64_t x, unsigned k) noexcept;
|
||||
|
||||
@ -666,6 +697,19 @@ public:
|
||||
Bench& unit(std::string const& unit);
|
||||
ANKERL_NANOBENCH(NODISCARD) std::string const& unit() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Sets the time unit to be used for the default output.
|
||||
*
|
||||
* Nanobench defaults to using ns (nanoseconds) as output in the markdown. For some benchmarks this is too coarse, so it is
|
||||
* possible to configure this. E.g. use `timeUnit(1ms, "ms")` to show `ms/op` instead of `ns/op`.
|
||||
*
|
||||
* @param tu Time unit to display the results in, default is 1ns.
|
||||
* @param tuName Name for the time unit, default is "ns"
|
||||
*/
|
||||
Bench& timeUnit(std::chrono::duration<double> const& tu, std::string const& tuName);
|
||||
ANKERL_NANOBENCH(NODISCARD) std::string const& timeUnitName() const noexcept;
|
||||
ANKERL_NANOBENCH(NODISCARD) std::chrono::duration<double> const& timeUnit() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Set the output stream where the resulting markdown table will be printed to.
|
||||
*
|
||||
@ -916,6 +960,7 @@ public:
|
||||
@endverbatim
|
||||
*/
|
||||
Bench& render(char const* templateContent, std::ostream& os);
|
||||
Bench& render(std::string const& templateContent, std::ostream& os);
|
||||
|
||||
Bench& config(Config const& benchmarkConfig);
|
||||
ANKERL_NANOBENCH(NODISCARD) Config const& config() const noexcept;
|
||||
@ -945,23 +990,24 @@ void doNotOptimizeAway(T const& val);
|
||||
|
||||
#else
|
||||
|
||||
// see folly's Benchmark.h
|
||||
// These assembly magic is directly from what Google Benchmark is doing. I have previously used what facebook's folly was doing, but
|
||||
// this seemd to have compilation problems in some cases. Google Benchmark seemed to be the most well tested anyways.
|
||||
// see https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307
|
||||
template <typename T>
|
||||
constexpr bool doNotOptimizeNeedsIndirect() {
|
||||
using Decayed = typename std::decay<T>::type;
|
||||
return !ANKERL_NANOBENCH_IS_TRIVIALLY_COPYABLE(Decayed) || sizeof(Decayed) > sizeof(long) || std::is_pointer<Decayed>::value;
|
||||
void doNotOptimizeAway(T const& val) {
|
||||
// NOLINTNEXTLINE(hicpp-no-assembler)
|
||||
asm volatile("" : : "r,m"(val) : "memory");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!doNotOptimizeNeedsIndirect<T>()>::type doNotOptimizeAway(T const& val) {
|
||||
void doNotOptimizeAway(T& val) {
|
||||
# if defined(__clang__)
|
||||
// NOLINTNEXTLINE(hicpp-no-assembler)
|
||||
asm volatile("" ::"r"(val));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<doNotOptimizeNeedsIndirect<T>()>::type doNotOptimizeAway(T const& val) {
|
||||
asm volatile("" : "+r,m"(val) : : "memory");
|
||||
# else
|
||||
// NOLINTNEXTLINE(hicpp-no-assembler)
|
||||
asm volatile("" ::"m"(val) : "memory");
|
||||
asm volatile("" : "+m,r"(val) : : "memory");
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1067,7 +1113,7 @@ constexpr uint64_t(Rng::max)() {
|
||||
return (std::numeric_limits<uint64_t>::max)();
|
||||
}
|
||||
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer")
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined")
|
||||
uint64_t Rng::operator()() noexcept {
|
||||
auto x = mX;
|
||||
|
||||
@ -1077,7 +1123,7 @@ uint64_t Rng::operator()() noexcept {
|
||||
return x;
|
||||
}
|
||||
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer")
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined")
|
||||
uint32_t Rng::bounded(uint32_t range) noexcept {
|
||||
uint64_t r32 = static_cast<uint32_t>(operator()());
|
||||
auto multiresult = r32 * range;
|
||||
@ -1103,6 +1149,7 @@ void Rng::shuffle(Container& container) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined")
|
||||
constexpr uint64_t Rng::rotl(uint64_t x, unsigned k) noexcept {
|
||||
return (x << k) | (x >> (64U - k));
|
||||
}
|
||||
@ -1306,6 +1353,30 @@ char const* htmlBoxplot() noexcept {
|
||||
</html>)DELIM";
|
||||
}
|
||||
|
||||
char const* pyperf() noexcept {
|
||||
return R"DELIM({
|
||||
"benchmarks": [
|
||||
{
|
||||
"runs": [
|
||||
{
|
||||
"values": [
|
||||
{{#measurement}} {{elapsed}}{{^-last}},
|
||||
{{/last}}{{/measurement}}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"loops": {{sum(iterations)}},
|
||||
"inner_loops": {{batch}},
|
||||
"name": "{{title}}",
|
||||
"unit": "second"
|
||||
},
|
||||
"version": "1.0"
|
||||
})DELIM";
|
||||
}
|
||||
|
||||
char const* json() noexcept {
|
||||
return R"DELIM({
|
||||
"results": [
|
||||
@ -1410,6 +1481,7 @@ static std::vector<Node> parseMustacheTemplate(char const** tpl) {
|
||||
}
|
||||
|
||||
static bool generateFirstLast(Node const& n, size_t idx, size_t size, std::ostream& out) {
|
||||
ANKERL_NANOBENCH_LOG("n.type=" << static_cast<int>(n.type));
|
||||
bool matchFirst = n == "-first";
|
||||
bool matchLast = n == "-last";
|
||||
if (!matchFirst && !matchLast) {
|
||||
@ -1632,6 +1704,7 @@ namespace detail {
|
||||
|
||||
char const* getEnv(char const* name);
|
||||
bool isEndlessRunning(std::string const& name);
|
||||
bool isWarningsEnabled();
|
||||
|
||||
template <typename T>
|
||||
T parseFile(std::string const& filename);
|
||||
@ -1770,25 +1843,49 @@ void render(char const* mustacheTemplate, std::vector<Result> const& results, st
|
||||
for (size_t i = 0; i < nbResults; ++i) {
|
||||
generateResult(n.children, i, results, out);
|
||||
}
|
||||
} else if (n == "measurement") {
|
||||
if (results.size() != 1) {
|
||||
throw std::runtime_error(
|
||||
"render: can only use section 'measurement' here if there is a single result, but there are " +
|
||||
detail::fmt::to_s(results.size()));
|
||||
}
|
||||
// when we only have a single result, we can immediately go into its measurement.
|
||||
auto const& r = results.front();
|
||||
for (size_t i = 0; i < r.size(); ++i) {
|
||||
generateResultMeasurement(n.children, i, r, out);
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("unknown section '" + std::string(n.begin, n.end) + "'");
|
||||
throw std::runtime_error("render: unknown section '" + std::string(n.begin, n.end) + "'");
|
||||
}
|
||||
break;
|
||||
|
||||
case templates::Node::Type::tag:
|
||||
// This just uses the last result's config.
|
||||
if (!generateConfigTag(n, results.back().config(), out)) {
|
||||
throw std::runtime_error("unknown tag '" + std::string(n.begin, n.end) + "'");
|
||||
if (results.size() == 1) {
|
||||
// result & config are both supported there
|
||||
generateResultTag(n, results.front(), out);
|
||||
} else {
|
||||
// This just uses the last result's config.
|
||||
if (!generateConfigTag(n, results.back().config(), out)) {
|
||||
throw std::runtime_error("unknown tag '" + std::string(n.begin, n.end) + "'");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void render(std::string const& mustacheTemplate, std::vector<Result> const& results, std::ostream& out) {
|
||||
render(mustacheTemplate.c_str(), results, out);
|
||||
}
|
||||
|
||||
void render(char const* mustacheTemplate, const Bench& bench, std::ostream& out) {
|
||||
render(mustacheTemplate, bench.results(), out);
|
||||
}
|
||||
|
||||
void render(std::string const& mustacheTemplate, const Bench& bench, std::ostream& out) {
|
||||
render(mustacheTemplate.c_str(), bench.results(), out);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
PerformanceCounters& performanceCounters() {
|
||||
@ -1837,6 +1934,12 @@ bool isEndlessRunning(std::string const& name) {
|
||||
return nullptr != endless && endless == name;
|
||||
}
|
||||
|
||||
// True when environment variable NANOBENCH_SUPPRESS_WARNINGS is either not set at all, or set to "0"
|
||||
bool isWarningsEnabled() {
|
||||
auto suppression = getEnv("NANOBENCH_SUPPRESS_WARNINGS");
|
||||
return nullptr == suppression || suppression == std::string("0");
|
||||
}
|
||||
|
||||
void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<std::string>& recommendations) {
|
||||
warnings.clear();
|
||||
recommendations.clear();
|
||||
@ -1889,13 +1992,13 @@ void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<
|
||||
recommendations.emplace_back("Make sure you compile for Release");
|
||||
}
|
||||
if (recommendPyPerf) {
|
||||
recommendations.emplace_back("Use 'pyperf system tune' before benchmarking. See https://github.com/vstinner/pyperf");
|
||||
recommendations.emplace_back("Use 'pyperf system tune' before benchmarking. See https://github.com/psf/pyperf");
|
||||
}
|
||||
}
|
||||
|
||||
void printStabilityInformationOnce(std::ostream* outStream) {
|
||||
static bool shouldPrint = true;
|
||||
if (shouldPrint && outStream) {
|
||||
if (shouldPrint && outStream && isWarningsEnabled()) {
|
||||
auto& os = *outStream;
|
||||
shouldPrint = false;
|
||||
std::vector<std::string> warnings;
|
||||
@ -1923,16 +2026,7 @@ uint64_t& singletonHeaderHash() noexcept {
|
||||
return sHeaderHash;
|
||||
}
|
||||
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer")
|
||||
inline uint64_t fnv1a(std::string const& str) noexcept {
|
||||
auto val = UINT64_C(14695981039346656037);
|
||||
for (auto c : str) {
|
||||
val = (val ^ static_cast<uint8_t>(c)) * UINT64_C(1099511628211);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer")
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined")
|
||||
inline uint64_t hash_combine(uint64_t seed, uint64_t val) {
|
||||
return seed ^ (val + UINT64_C(0x9e3779b9) + (seed << 6U) + (seed >> 2U));
|
||||
}
|
||||
@ -2010,7 +2104,7 @@ struct IterationLogic::Impl {
|
||||
return static_cast<uint64_t>(doubleNewIters + 0.5);
|
||||
}
|
||||
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer") void upscale(std::chrono::nanoseconds elapsed) {
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") void upscale(std::chrono::nanoseconds elapsed) {
|
||||
if (elapsed * 10 < mTargetRuntimePerEpoch) {
|
||||
// we are far below the target runtime. Multiply iterations by 10 (with overflow check)
|
||||
if (mNumIters * 10 < mNumIters) {
|
||||
@ -2108,7 +2202,8 @@ struct IterationLogic::Impl {
|
||||
columns.emplace_back(14, 0, "complexityN", "", mBench.complexityN());
|
||||
}
|
||||
|
||||
columns.emplace_back(22, 2, "ns/" + mBench.unit(), "", 1e9 * rMedian / mBench.batch());
|
||||
columns.emplace_back(22, 2, mBench.timeUnitName() + "/" + mBench.unit(), "",
|
||||
rMedian / (mBench.timeUnit().count() * mBench.batch()));
|
||||
columns.emplace_back(22, 2, mBench.unit() + "/s", "", rMedian <= 0.0 ? 0.0 : mBench.batch() / rMedian);
|
||||
|
||||
double rErrorMedian = mResult.medianAbsolutePercentError(Result::Measure::elapsed);
|
||||
@ -2140,16 +2235,19 @@ struct IterationLogic::Impl {
|
||||
}
|
||||
}
|
||||
|
||||
columns.emplace_back(12, 2, "total", "", mResult.sum(Result::Measure::elapsed));
|
||||
columns.emplace_back(12, 2, "total", "", mResult.sumProduct(Result::Measure::iterations, Result::Measure::elapsed));
|
||||
|
||||
// write everything
|
||||
auto& os = *mBench.output();
|
||||
|
||||
// combine all elements that are relevant for printing the header
|
||||
uint64_t hash = 0;
|
||||
hash = hash_combine(fnv1a(mBench.unit()), hash);
|
||||
hash = hash_combine(fnv1a(mBench.title()), hash);
|
||||
hash = hash_combine(mBench.relative(), hash);
|
||||
hash = hash_combine(mBench.performanceCounters(), hash);
|
||||
hash = hash_combine(std::hash<std::string>{}(mBench.unit()), hash);
|
||||
hash = hash_combine(std::hash<std::string>{}(mBench.title()), hash);
|
||||
hash = hash_combine(std::hash<std::string>{}(mBench.timeUnitName()), hash);
|
||||
hash = hash_combine(std::hash<double>{}(mBench.timeUnit().count()), hash);
|
||||
hash = hash_combine(std::hash<bool>{}(mBench.relative()), hash);
|
||||
hash = hash_combine(std::hash<bool>{}(mBench.performanceCounters()), hash);
|
||||
|
||||
if (hash != singletonHeaderHash()) {
|
||||
singletonHeaderHash() = hash;
|
||||
@ -2177,7 +2275,7 @@ struct IterationLogic::Impl {
|
||||
os << col.value();
|
||||
}
|
||||
os << "| ";
|
||||
auto showUnstable = rErrorMedian >= 0.05;
|
||||
auto showUnstable = isWarningsEnabled() && rErrorMedian >= 0.05;
|
||||
if (showUnstable) {
|
||||
os << ":wavy_dash: ";
|
||||
}
|
||||
@ -2305,7 +2403,7 @@ public:
|
||||
}
|
||||
|
||||
template <typename Op>
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer")
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined")
|
||||
void calibrate(Op&& op) {
|
||||
// clear current calibration data,
|
||||
for (auto& v : mCalibratedOverhead) {
|
||||
@ -2411,7 +2509,7 @@ bool LinuxPerformanceCounters::monitor(perf_hw_id hwId, LinuxPerformanceCounters
|
||||
}
|
||||
|
||||
// overflow is ok, it's checked
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer")
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined")
|
||||
void LinuxPerformanceCounters::updateResults(uint64_t numIters) {
|
||||
// clear old data
|
||||
for (auto& id_value : mIdToTarget) {
|
||||
@ -2963,6 +3061,20 @@ std::string const& Bench::unit() const noexcept {
|
||||
return mConfig.mUnit;
|
||||
}
|
||||
|
||||
Bench& Bench::timeUnit(std::chrono::duration<double> const& tu, std::string const& tuName) {
|
||||
mConfig.mTimeUnit = tu;
|
||||
mConfig.mTimeUnitName = tuName;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string const& Bench::timeUnitName() const noexcept {
|
||||
return mConfig.mTimeUnitName;
|
||||
}
|
||||
|
||||
std::chrono::duration<double> const& Bench::timeUnit() const noexcept {
|
||||
return mConfig.mTimeUnit;
|
||||
}
|
||||
|
||||
// If benchmarkTitle differs from currently set title, the stored results will be cleared.
|
||||
Bench& Bench::title(const char* benchmarkTitle) {
|
||||
if (benchmarkTitle != mConfig.mBenchmarkTitle) {
|
||||
@ -3083,6 +3195,11 @@ Bench& Bench::render(char const* templateContent, std::ostream& os) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bench& Bench::render(std::string const& templateContent, std::ostream& os) {
|
||||
::ankerl::nanobench::render(templateContent, *this, os);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::vector<BigO> Bench::complexityBigO() const {
|
||||
std::vector<BigO> bigOs;
|
||||
auto rangeMeasure = BigO::collectRangeMeasure(mResults);
|
||||
@ -3119,7 +3236,7 @@ Rng::Rng()
|
||||
} while (mX == 0 && mY == 0);
|
||||
}
|
||||
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer")
|
||||
ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined")
|
||||
uint64_t splitMix64(uint64_t& state) noexcept {
|
||||
uint64_t z = (state += UINT64_C(0x9e3779b97f4a7c15));
|
||||
z = (z ^ (z >> 30U)) * UINT64_C(0xbf58476d1ce4e5b9);
|
||||
@ -3145,6 +3262,24 @@ Rng Rng::copy() const noexcept {
|
||||
return Rng{mX, mY};
|
||||
}
|
||||
|
||||
Rng::Rng(std::vector<uint64_t> const& data)
|
||||
: mX(0)
|
||||
, mY(0) {
|
||||
if (data.size() != 2) {
|
||||
throw std::runtime_error("ankerl::nanobench::Rng::Rng: needed exactly 2 entries in data, but got " +
|
||||
detail::fmt::to_s(data.size()));
|
||||
}
|
||||
mX = data[0];
|
||||
mY = data[1];
|
||||
}
|
||||
|
||||
std::vector<uint64_t> Rng::state() const {
|
||||
std::vector<uint64_t> data(2);
|
||||
data[0] = mX;
|
||||
data[1] = mY;
|
||||
return data;
|
||||
}
|
||||
|
||||
BigO::RangeMeasure BigO::collectRangeMeasure(std::vector<Result> const& results) {
|
||||
BigO::RangeMeasure rangeMeasure;
|
||||
for (auto const& result : results) {
|
||||
|
@ -83,7 +83,28 @@ public Q_SLOTS:
|
||||
|
||||
private:
|
||||
interfaces::Node& m_node;
|
||||
const QStringList columns{tr("Peer Id"), tr("Address"), tr("Network"), tr("Ping"), tr("Sent"), tr("Received"), tr("User Agent")};
|
||||
const QStringList columns{
|
||||
/*: Title of Peers Table column which contains a
|
||||
unique number used to identify a connection. */
|
||||
tr("Peer"),
|
||||
/*: Title of Peers Table column which contains the
|
||||
IP/Onion/I2P address of the connected peer. */
|
||||
tr("Address"),
|
||||
/*: Title of Peers Table column which states the network the peer
|
||||
connected through. */
|
||||
tr("Network"),
|
||||
/*: Title of Peers Table column which indicates the current latency
|
||||
of the connection with the peer. */
|
||||
tr("Ping"),
|
||||
/*: Title of Peers Table column which indicates the total amount of
|
||||
network information we have sent to the peer. */
|
||||
tr("Sent"),
|
||||
/*: Title of Peers Table column which indicates the total amount of
|
||||
network information we have received from the peer. */
|
||||
tr("Received"),
|
||||
/*: Title of Peers Table column which contains the peer's
|
||||
User Agent string. */
|
||||
tr("User Agent")};
|
||||
std::unique_ptr<PeerTablePriv> priv;
|
||||
QTimer *timer;
|
||||
};
|
||||
|
@ -489,7 +489,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, QWidget* parent, Qt::WindowFlags
|
||||
ui->lineEdit->setMaxLength(16 * 1024 * 1024);
|
||||
ui->messagesWidget->installEventFilter(this);
|
||||
|
||||
connect(ui->clearButton, &QPushButton::clicked, this, &RPCConsole::clear);
|
||||
connect(ui->clearButton, &QPushButton::clicked, [this] { clear(); });
|
||||
connect(ui->fontBiggerButton, &QPushButton::clicked, this, &RPCConsole::fontBigger);
|
||||
connect(ui->fontSmallerButton, &QPushButton::clicked, this, &RPCConsole::fontSmaller);
|
||||
connect(ui->btnClearTrafficGraph, &QPushButton::clicked, ui->trafficGraph, &TrafficGraphWidget::clear);
|
||||
@ -822,7 +822,7 @@ void RPCConsole::setFontSize(int newSize)
|
||||
|
||||
// clear console (reset icon sizes, default stylesheet) and re-add the content
|
||||
float oldPosFactor = 1.0 / ui->messagesWidget->verticalScrollBar()->maximum() * ui->messagesWidget->verticalScrollBar()->value();
|
||||
clear(false);
|
||||
clear(/* keep_prompt */ true);
|
||||
ui->messagesWidget->setHtml(str);
|
||||
ui->messagesWidget->verticalScrollBar()->setValue(oldPosFactor * ui->messagesWidget->verticalScrollBar()->maximum());
|
||||
}
|
||||
@ -873,15 +873,10 @@ void RPCConsole::buildParameterlist(QString arg)
|
||||
Q_EMIT handleRestart(args);
|
||||
}
|
||||
|
||||
void RPCConsole::clear(bool clearHistory)
|
||||
void RPCConsole::clear(bool keep_prompt)
|
||||
{
|
||||
ui->messagesWidget->clear();
|
||||
if(clearHistory)
|
||||
{
|
||||
history.clear();
|
||||
historyPtr = 0;
|
||||
}
|
||||
ui->lineEdit->clear();
|
||||
if (!keep_prompt) ui->lineEdit->clear();
|
||||
ui->lineEdit->setFocus();
|
||||
|
||||
// Set default style sheet
|
||||
@ -1232,7 +1227,7 @@ void RPCConsole::updateDetailWidget()
|
||||
const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected_rows.first().row());
|
||||
// update the detail ui with latest node information
|
||||
QString peerAddrDetails(QString::fromStdString(stats->nodeStats.m_addr_name) + " ");
|
||||
peerAddrDetails += tr("(peer id: %1)").arg(QString::number(stats->nodeStats.nodeid));
|
||||
peerAddrDetails += tr("(peer: %1)").arg(QString::number(stats->nodeStats.nodeid));
|
||||
if (!stats->nodeStats.addrLocal.empty())
|
||||
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
|
||||
ui->peerHeading->setText(peerAddrDetails);
|
||||
|
@ -103,7 +103,7 @@ private Q_SLOTS:
|
||||
void updateDetailWidget();
|
||||
|
||||
public Q_SLOTS:
|
||||
void clear(bool clearHistory = true);
|
||||
void clear(bool keep_prompt = false);
|
||||
void fontBigger();
|
||||
void fontSmaller();
|
||||
void setFontSize(int newSize);
|
||||
|
@ -64,7 +64,7 @@ uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDe
|
||||
entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(EncodeDestination(address)));
|
||||
entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
|
||||
uint256 txid;
|
||||
boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](CWallet*, const uint256& hash, ChangeType status) {
|
||||
boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](const uint256& hash, ChangeType status) {
|
||||
if (status == CT_NEW) txid = hash;
|
||||
}));
|
||||
ConfirmSend();
|
||||
|
@ -524,13 +524,13 @@ public:
|
||||
std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override
|
||||
{
|
||||
return MakeHandler(m_wallet->NotifyAddressBookChanged.connect(
|
||||
[fn](CWallet*, const CTxDestination& address, const std::string& label, bool is_mine,
|
||||
const std::string& purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); }));
|
||||
[fn](const CTxDestination& address, const std::string& label, bool is_mine,
|
||||
const std::string& purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); }));
|
||||
}
|
||||
std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override
|
||||
{
|
||||
return MakeHandler(m_wallet->NotifyTransactionChanged.connect(
|
||||
[fn](CWallet*, const uint256& txid, ChangeType status) { fn(txid, status); }));
|
||||
[fn](const uint256& txid, ChangeType status) { fn(txid, status); }));
|
||||
}
|
||||
std::unique_ptr<Handler> handleInstantLockReceived(InstantLockReceivedFn fn) override
|
||||
{
|
||||
|
@ -4381,9 +4381,13 @@ RPCHelpMan walletprocesspsbt()
|
||||
{
|
||||
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
|
||||
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
const CWallet& wallet{*pwallet};
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
wallet.BlockUntilSyncedToCurrentChain();
|
||||
|
||||
// Unserialize the transaction
|
||||
PartiallySignedTransaction psbtx;
|
||||
@ -4403,7 +4407,7 @@ RPCHelpMan walletprocesspsbt()
|
||||
bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
|
||||
bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool();
|
||||
bool complete = true;
|
||||
const TransactionError err = pwallet->FillPSBT(psbtx, complete, nHashType, sign, bip32derivs);
|
||||
const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs)};
|
||||
if (err != TransactionError::OK) {
|
||||
throw JSONRPCTransactionError(err);
|
||||
}
|
||||
@ -4500,9 +4504,13 @@ static RPCHelpMan walletcreatefundedpsbt()
|
||||
}, true
|
||||
);
|
||||
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
CWallet& wallet{*pwallet};
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
wallet.BlockUntilSyncedToCurrentChain();
|
||||
|
||||
CAmount fee;
|
||||
int change_position;
|
||||
@ -4511,7 +4519,7 @@ static RPCHelpMan walletcreatefundedpsbt()
|
||||
// Automatically select coins, unless at least one is manually selected. Can
|
||||
// be overridden by options.add_inputs.
|
||||
coin_control.m_add_inputs = rawTx.vin.size() == 0;
|
||||
FundTransaction(pwallet, rawTx, fee, change_position, request.params[3], coin_control);
|
||||
FundTransaction(&wallet, rawTx, fee, change_position, request.params[3], coin_control);
|
||||
|
||||
// Make a blank psbt
|
||||
PartiallySignedTransaction psbtx{rawTx};
|
||||
@ -4519,7 +4527,7 @@ static RPCHelpMan walletcreatefundedpsbt()
|
||||
// Fill transaction with out data but don't sign
|
||||
bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool();
|
||||
bool complete = true;
|
||||
const TransactionError err = pwallet->FillPSBT(psbtx, complete, 1, false, bip32derivs);
|
||||
const TransactionError err{wallet.FillPSBT(psbtx, complete, 1, false, bip32derivs)};
|
||||
if (err != TransactionError::OK) {
|
||||
throw JSONRPCTransactionError(err);
|
||||
}
|
||||
|
@ -918,7 +918,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
|
||||
wtx.MarkDirty();
|
||||
|
||||
// Notify UI of new or updated transaction
|
||||
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
|
||||
NotifyTransactionChanged(hash, fInsertedNew ? CT_NEW : CT_UPDATED);
|
||||
|
||||
#if HAVE_SYSTEM
|
||||
// notify an external script when a wallet transaction comes in or is updated
|
||||
@ -1101,7 +1101,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
|
||||
wtx.setAbandoned();
|
||||
wtx.MarkDirty();
|
||||
batch.WriteTx(wtx);
|
||||
NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
|
||||
NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED);
|
||||
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
|
||||
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
|
||||
while (iter != mapTxSpends.end() && iter->first.hash == now) {
|
||||
@ -3804,7 +3804,7 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
|
||||
|
||||
CWalletTx &coin = mapWallet.at(txin.prevout.hash);
|
||||
coin.MarkDirty();
|
||||
NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED);
|
||||
NotifyTransactionChanged(txin.prevout.hash, CT_UPDATED);
|
||||
updated_hahes.insert(txin.prevout.hash);
|
||||
}
|
||||
// Get the inserted-CWalletTx from mapWallet so that the
|
||||
@ -3901,7 +3901,7 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
|
||||
for (const auto& txin : it->second.tx->vin)
|
||||
mapTxSpends.erase(txin.prevout);
|
||||
mapWallet.erase(it);
|
||||
NotifyTransactionChanged(this, hash, CT_DELETED);
|
||||
NotifyTransactionChanged(hash, CT_DELETED);
|
||||
}
|
||||
|
||||
if (nZapSelectTxRet == DBErrors::NEED_REWRITE)
|
||||
@ -3936,8 +3936,8 @@ bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& add
|
||||
m_address_book[address].purpose = strPurpose;
|
||||
is_mine = IsMine(address) != ISMINE_NO;
|
||||
}
|
||||
NotifyAddressBookChanged(this, address, strName, is_mine,
|
||||
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
|
||||
NotifyAddressBookChanged(address, strName, is_mine,
|
||||
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW));
|
||||
if (!strPurpose.empty() && !batch.WritePurpose(EncodeDestination(address), strPurpose))
|
||||
return false;
|
||||
return batch.WriteName(EncodeDestination(address), strName);
|
||||
@ -3972,7 +3972,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
|
||||
is_mine = IsMine(address) != ISMINE_NO;
|
||||
}
|
||||
|
||||
NotifyAddressBookChanged(this, address, "", is_mine, "", CT_DELETED);
|
||||
NotifyAddressBookChanged(address, "", is_mine, "", CT_DELETED);
|
||||
|
||||
batch.ErasePurpose(EncodeDestination(address));
|
||||
return batch.EraseName(EncodeDestination(address));
|
||||
@ -5156,7 +5156,7 @@ void CWallet::notifyTransactionLock(const CTransactionRef &tx, const std::shared
|
||||
uint256 txHash = tx->GetHash();
|
||||
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txHash);
|
||||
if (mi != mapWallet.end()){
|
||||
NotifyTransactionChanged(this, txHash, CT_UPDATED);
|
||||
NotifyTransactionChanged(txHash, CT_UPDATED);
|
||||
NotifyISLockReceived();
|
||||
#if HAVE_SYSTEM
|
||||
// notify an external script
|
||||
@ -5477,7 +5477,6 @@ ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(bool internal) const
|
||||
{
|
||||
const auto spk_manager = internal ? m_internal_spk_managers : m_external_spk_managers;
|
||||
if (spk_manager == nullptr) {
|
||||
WalletLogPrintf("%s scriptPubKey Manager does not exist\n", internal ? "Internal" : "External");
|
||||
return nullptr;
|
||||
}
|
||||
return spk_manager;
|
||||
|
@ -1223,19 +1223,18 @@ public:
|
||||
|
||||
/**
|
||||
* Address book entry changed.
|
||||
* @note called with lock cs_wallet held.
|
||||
* @note called without lock cs_wallet held.
|
||||
*/
|
||||
boost::signals2::signal<void (CWallet *wallet, const CTxDestination
|
||||
&address, const std::string &label, bool isMine,
|
||||
const std::string &purpose,
|
||||
ChangeType status)> NotifyAddressBookChanged;
|
||||
boost::signals2::signal<void(const CTxDestination& address,
|
||||
const std::string& label, bool isMine,
|
||||
const std::string& purpose, ChangeType status)>
|
||||
NotifyAddressBookChanged;
|
||||
|
||||
/**
|
||||
* Wallet transaction added, removed or updated.
|
||||
* @note called with lock cs_wallet held.
|
||||
*/
|
||||
boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx,
|
||||
ChangeType status)> NotifyTransactionChanged;
|
||||
boost::signals2::signal<void(const uint256& hashTx, ChangeType status)> NotifyTransactionChanged;
|
||||
|
||||
/** Show progress e.g. for rescan */
|
||||
boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress;
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Copyright (c) 2020 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test Anchors functionality"""
|
||||
"""Test block-relay-only anchors functionality"""
|
||||
|
||||
import os
|
||||
|
||||
@ -10,6 +10,9 @@ from test_framework.p2p import P2PInterface
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal
|
||||
|
||||
INBOUND_CONNECTIONS = 5
|
||||
BLOCK_RELAY_CONNECTIONS = 2
|
||||
|
||||
|
||||
def check_node_connections(*, node, num_in, num_out):
|
||||
info = node.getnetworkinfo()
|
||||
@ -25,19 +28,26 @@ class AnchorsTest(BitcoinTestFramework):
|
||||
self.setup_nodes()
|
||||
|
||||
def run_test(self):
|
||||
self.log.info("Add 2 block-relay-only connections to node 0")
|
||||
for i in range(2):
|
||||
node_anchors_path = os.path.join(
|
||||
self.nodes[0].datadir, "regtest", "anchors.dat"
|
||||
)
|
||||
|
||||
self.log.info("When node starts, check if anchors.dat doesn't exist")
|
||||
assert not os.path.exists(node_anchors_path)
|
||||
|
||||
self.log.info(f"Add {BLOCK_RELAY_CONNECTIONS} block-relay-only connections to node")
|
||||
for i in range(BLOCK_RELAY_CONNECTIONS):
|
||||
self.log.debug(f"block-relay-only: {i}")
|
||||
self.nodes[0].add_outbound_p2p_connection(
|
||||
P2PInterface(), p2p_idx=i, connection_type="block-relay-only"
|
||||
)
|
||||
|
||||
self.log.info("Add 5 inbound connections to node 0")
|
||||
for i in range(5):
|
||||
self.log.info(f"Add {INBOUND_CONNECTIONS} inbound connections to node")
|
||||
for i in range(INBOUND_CONNECTIONS):
|
||||
self.log.debug(f"inbound: {i}")
|
||||
self.nodes[0].add_p2p_connection(P2PInterface())
|
||||
|
||||
self.log.info("Check node 0 connections")
|
||||
self.log.info("Check node connections")
|
||||
check_node_connections(node=self.nodes[0], num_in=5, num_out=2)
|
||||
|
||||
# 127.0.0.1
|
||||
@ -57,14 +67,10 @@ class AnchorsTest(BitcoinTestFramework):
|
||||
self.log.info("Stop node 0")
|
||||
self.stop_node(0)
|
||||
|
||||
node0_anchors_path = os.path.join(
|
||||
self.nodes[0].datadir, "regtest", "anchors.dat"
|
||||
)
|
||||
|
||||
# It should contain only the block-relay-only addresses
|
||||
self.log.info("Check the addresses in anchors.dat")
|
||||
|
||||
with open(node0_anchors_path, "rb") as file_handler:
|
||||
with open(node_anchors_path, "rb") as file_handler:
|
||||
anchors = file_handler.read().hex()
|
||||
|
||||
for port in block_relay_nodes_port:
|
||||
@ -74,11 +80,11 @@ class AnchorsTest(BitcoinTestFramework):
|
||||
ip_port = ip + port
|
||||
assert ip_port not in anchors
|
||||
|
||||
self.log.info("Start node 0")
|
||||
self.log.info("Start node")
|
||||
self.start_node(0)
|
||||
|
||||
self.log.info("When node starts, check if anchors.dat doesn't exist anymore")
|
||||
assert not os.path.exists(node0_anchors_path)
|
||||
assert not os.path.exists(node_anchors_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -456,6 +456,9 @@ class BlockchainTest(BitcoinTestFramework):
|
||||
# Restore chain state
|
||||
move_block_file('rev_wrong', 'rev00000.dat')
|
||||
|
||||
assert 'previousblockhash' not in node.getblock(node.getblockhash(0))
|
||||
assert 'nextblockhash' not in node.getblock(node.getbestblockhash())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
BlockchainTest().main()
|
||||
|
@ -223,11 +223,6 @@ def create_raw_transaction(node, txid, to_address, *, amount):
|
||||
signed_psbt = wrpc.walletprocesspsbt(psbt)
|
||||
psbt = signed_psbt['psbt']
|
||||
final_psbt = node.finalizepsbt(psbt)
|
||||
if not final_psbt["complete"]:
|
||||
node.log.info(f'final_psbt={final_psbt}')
|
||||
for w in node.listwallets():
|
||||
wrpc = node.get_wallet_rpc(w)
|
||||
node.log.info(f'listunspent={wrpc.listunspent()}')
|
||||
assert_equal(final_psbt["complete"], True)
|
||||
return final_psbt['hex']
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user