Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/dashpay/dash into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
PastaPastaPasta committed Oct 22, 2024
2 parents b17eead + cd6598f commit 59d82be
Show file tree
Hide file tree
Showing 111 changed files with 1,749 additions and 674 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/guix-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: Guix Build

permissions:
packages: write
id-token: write
attestations: write

on:
pull_request_target:
Expand Down Expand Up @@ -127,3 +129,7 @@ jobs:
path: |
${{ github.workspace }}/dash/guix-build*/output/${{ matrix.build_target }}/
- name: Attest build provenance
uses: actions/attest-build-provenance@v1
with:
subject-path: ${{ github.workspace }}/dash/guix-build*/output/${{ matrix.build_target }}/*
47 changes: 47 additions & 0 deletions doc/developer-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,53 @@ the upper cycle, etc.
Threads and synchronization
----------------------------
- Prefer `Mutex` type to `RecursiveMutex` one
- Consistently use [Clang Thread Safety Analysis](https://clang.llvm.org/docs/ThreadSafetyAnalysis.html) annotations to
get compile-time warnings about potential race conditions in code. Combine annotations in function declarations with
run-time asserts in function definitions:
```C++
// txmempool.h
class CTxMemPool
{
public:
...
mutable RecursiveMutex cs;
...
void UpdateTransactionsFromBlock(...) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, cs);
...
}
// txmempool.cpp
void CTxMemPool::UpdateTransactionsFromBlock(...)
{
AssertLockHeld(::cs_main);
AssertLockHeld(cs);
...
}
```

```C++
// validation.h
class ChainstateManager
{
public:
...
bool ProcessNewBlock(...) LOCKS_EXCLUDED(::cs_main);
...
}

// validation.cpp
bool ChainstateManager::ProcessNewBlock(...)
{
AssertLockNotHeld(::cs_main);
...
LOCK(::cs_main);
...
}
```
- Build and run tests with `-DDEBUG_LOCKORDER` to verify that no potential
deadlocks are introduced.
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.bench.include
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ bench_bench_dash_SOURCES = \
bench/ccoins_caching.cpp \
bench/gcs_filter.cpp \
bench/hashpadding.cpp \
bench/load_external.cpp \
bench/merkle_root.cpp \
bench/mempool_eviction.cpp \
bench/mempool_stress.cpp \
Expand All @@ -44,6 +45,7 @@ bench_bench_dash_SOURCES = \
bench/pool.cpp \
bench/rpc_blockchain.cpp \
bench/rpc_mempool.cpp \
bench/strencodings.cpp \
bench/util_time.cpp \
bench/base58.cpp \
bench/bech32.cpp \
Expand Down
1 change: 1 addition & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ BITCOIN_TESTS =\
test/blockencodings_tests.cpp \
test/blockfilter_tests.cpp \
test/blockfilter_index_tests.cpp \
test/blockmanager_tests.cpp \
test/bloom_tests.cpp \
test/bls_tests.cpp \
test/bswap_tests.cpp \
Expand Down
4 changes: 2 additions & 2 deletions src/bench/block_assemble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static void AssembleBlock(benchmark::Bench& bench)
std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY + 1> txs;
for (size_t b{0}; b < NUM_BLOCKS; ++b) {
CMutableTransaction tx;
tx.vin.push_back(MineBlock(test_setup->m_node, P2SH_OP_TRUE));
tx.vin.push_back(MineBlock(test_setup->m_node, SCRIPT_PUB));
tx.vin.back().scriptSig = scriptSig;
tx.vout.emplace_back(1337, SCRIPT_PUB);
if (NUM_BLOCKS - b >= COINBASE_MATURITY)
Expand All @@ -48,7 +48,7 @@ static void AssembleBlock(benchmark::Bench& bench)
}

bench.minEpochIterations(700).run([&] {
PrepareBlock(test_setup->m_node, P2SH_OP_TRUE);
PrepareBlock(test_setup->m_node, SCRIPT_PUB);
});
}

Expand Down
80 changes: 63 additions & 17 deletions src/bench/gcs_filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,84 @@
#include <bench/bench.h>
#include <blockfilter.h>

static void ConstructGCSFilter(benchmark::Bench& bench)
static const GCSFilter::ElementSet GenerateGCSTestElements()
{
GCSFilter::ElementSet elements;
for (int i = 0; i < 10000; ++i) {

// Testing the benchmarks with different number of elements show that a filter
// with at least 100,000 elements results in benchmarks that have the same
// ns/op. This makes it easy to reason about how long (in nanoseconds) a single
// filter element takes to process.
for (int i = 0; i < 100000; ++i) {
GCSFilter::Element element(32);
element[0] = static_cast<unsigned char>(i);
element[1] = static_cast<unsigned char>(i >> 8);
elements.insert(std::move(element));
}

return elements;
}

static void GCSBlockFilterGetHash(benchmark::Bench& bench)
{
auto elements = GenerateGCSTestElements();

GCSFilter filter({0, 0, BASIC_FILTER_P, BASIC_FILTER_M}, elements);
BlockFilter block_filter(BlockFilterType::BASIC_FILTER, {}, filter.GetEncoded(), /*skip_decode_check=*/false);

bench.run([&] {
block_filter.GetHash();
});
}

static void GCSFilterConstruct(benchmark::Bench& bench)
{
auto elements = GenerateGCSTestElements();

uint64_t siphash_k0 = 0;
bench.batch(elements.size()).unit("elem").run([&] {
GCSFilter filter({siphash_k0, 0, 20, 1 << 20}, elements);
bench.run([&]{
GCSFilter filter({siphash_k0, 0, BASIC_FILTER_P, BASIC_FILTER_M}, elements);

siphash_k0++;
});
}

static void MatchGCSFilter(benchmark::Bench& bench)
static void GCSFilterDecode(benchmark::Bench& bench)
{
GCSFilter::ElementSet elements;
for (int i = 0; i < 10000; ++i) {
GCSFilter::Element element(32);
element[0] = static_cast<unsigned char>(i);
element[1] = static_cast<unsigned char>(i >> 8);
elements.insert(std::move(element));
}
GCSFilter filter({0, 0, 20, 1 << 20}, elements);
auto elements = GenerateGCSTestElements();

bench.unit("elem").run([&] {
filter.Match(GCSFilter::Element());
GCSFilter filter({0, 0, BASIC_FILTER_P, BASIC_FILTER_M}, elements);
auto encoded = filter.GetEncoded();

bench.run([&] {
GCSFilter filter({0, 0, BASIC_FILTER_P, BASIC_FILTER_M}, encoded, /*skip_decode_check=*/false);
});
}

static void GCSFilterDecodeSkipCheck(benchmark::Bench& bench)
{
auto elements = GenerateGCSTestElements();

GCSFilter filter({0, 0, BASIC_FILTER_P, BASIC_FILTER_M}, elements);
auto encoded = filter.GetEncoded();

bench.run([&] {
GCSFilter filter({0, 0, BASIC_FILTER_P, BASIC_FILTER_M}, encoded, /*skip_decode_check=*/true);
});
}

BENCHMARK(ConstructGCSFilter);
BENCHMARK(MatchGCSFilter);
static void GCSFilterMatch(benchmark::Bench& bench)
{
auto elements = GenerateGCSTestElements();

GCSFilter filter({0, 0, BASIC_FILTER_P, BASIC_FILTER_M}, elements);

bench.run([&] {
filter.Match(GCSFilter::Element());
});
}
BENCHMARK(GCSBlockFilterGetHash);
BENCHMARK(GCSFilterConstruct);
BENCHMARK(GCSFilterDecode);
BENCHMARK(GCSFilterDecodeSkipCheck);
BENCHMARK(GCSFilterMatch);
63 changes: 63 additions & 0 deletions src/bench/load_external.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) 2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php.

#include <bench/bench.h>
#include <bench/data.h>
#include <chainparams.h>
#include <test/util/setup_common.h>
#include <validation.h>

/**
* The LoadExternalBlockFile() function is used during -reindex and -loadblock.
*
* Create a test file that's similar to a datadir/blocks/blk?????.dat file,
* It contains around 134 copies of the same block (typical size of real block files).
* For each block in the file, LoadExternalBlockFile() won't find its parent,
* and so will skip the block. (In the real system, it will re-read the block
* from disk later when it encounters its parent.)
*
* This benchmark measures the performance of deserializing the block (or just
* its header, beginning with PR 16981).
*/
static void LoadExternalBlockFile(benchmark::Bench& bench)
{
const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(CBaseChainParams::MAIN)};

// Create a single block as in the blocks files (magic bytes, block size,
// block data) as a stream object.
const fs::path blkfile{testing_setup.get()->m_path_root / "blk.dat"};
CDataStream ss(SER_DISK, 0);
auto params{Params()};
ss << params.MessageStart();
ss << static_cast<uint32_t>(benchmark::data::block813851.size());
// We can't use the streaming serialization (ss << benchmark::data::block813851)
// because that first writes a compact size.
ss.write(MakeByteSpan(benchmark::data::block813851));

// Create the test file.
{
// "wb+" is "binary, O_RDWR | O_CREAT | O_TRUNC".
FILE* file{fsbridge::fopen(blkfile, "wb+")};
// Make the test block file about 128 MB in length.
for (size_t i = 0; i < MAX_BLOCKFILE_SIZE / ss.size(); ++i) {
if (fwrite(ss.data(), 1, ss.size(), file) != ss.size()) {
throw std::runtime_error("write to test file failed\n");
}
}
fclose(file);
}

CChainState& chainstate{testing_setup->m_node.chainman->ActiveChainstate()};
std::multimap<uint256, FlatFilePos> blocks_with_unknown_parent;
FlatFilePos pos;
bench.run([&] {
// "rb" is "binary, O_RDONLY", positioned to the start of the file.
// The file will be closed by LoadExternalBlockFile().
FILE* file{fsbridge::fopen(blkfile, "rb")};
chainstate.LoadExternalBlockFile(file, &pos, &blocks_with_unknown_parent);
});
fs::remove(blkfile);
}

BENCHMARK(LoadExternalBlockFile);
18 changes: 18 additions & 0 deletions src/bench/strencodings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bench/bench.h>
#include <bench/data.h>
#include <util/strencodings.h>

static void HexStrBench(benchmark::Bench& bench)
{
auto const& data = benchmark::data::block813851;
bench.batch(data.size()).unit("byte").run([&] {
auto hex = HexStr(data);
ankerl::nanobench::doNotOptimizeAway(hex);
});
}

BENCHMARK(HexStrBench);
8 changes: 4 additions & 4 deletions src/bitcoin-cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ class NetinfoRequestHandler : public BaseRequestHandler
const std::string addr{peer["addr"].get_str()};
const std::string age{conn_time == 0 ? "" : ToString((m_time_now - conn_time) / 60)};
const std::string sub_version{peer["subver"].get_str()};
const std::string transport{peer["transport_protocol_type"].get_str()};
const std::string transport{peer["transport_protocol_type"].isNull() ? "v1" : peer["transport_protocol_type"].get_str()};
const bool is_addr_relay_enabled{peer["addr_relay_enabled"].isNull() ? false : peer["addr_relay_enabled"].get_bool()};
const bool is_bip152_hb_from{peer["bip152_hb_from"].get_bool()};
const bool is_bip152_hb_to{peer["bip152_hb_to"].get_bool()};
Expand All @@ -538,7 +538,7 @@ class NetinfoRequestHandler : public BaseRequestHandler
// Report detailed peer connections list sorted by direction and minimum ping time.
if (DetailsRequested() && !m_peers.empty()) {
std::sort(m_peers.begin(), m_peers.end());
result += strprintf("<-> type net tp mping ping send recv txn blk hb %*s%*s%*s ",
result += strprintf("<-> type net v mping ping send recv txn blk hb %*s%*s%*s ",
m_max_addr_processed_length, "addrp",
m_max_addr_rate_limited_length, "addrl",
m_max_age_length, "age");
Expand All @@ -551,7 +551,7 @@ class NetinfoRequestHandler : public BaseRequestHandler
peer.is_outbound ? "out" : "in",
ConnectionTypeForNetinfo(peer.conn_type),
peer.network,
peer.transport_protocol_type == "detecting" ? "*" : peer.transport_protocol_type,
peer.transport_protocol_type.rfind('v', 0) == 0 ? peer.transport_protocol_type[1] : ' ',
PingTimeToString(peer.min_ping),
PingTimeToString(peer.ping),
peer.last_send ? ToString(m_time_now - peer.last_send) : "",
Expand Down Expand Up @@ -660,7 +660,7 @@ class NetinfoRequestHandler : public BaseRequestHandler
" \"feeler\" - short-lived connection for testing addresses\n"
" \"addr\" - address fetch; short-lived connection for requesting addresses\n"
" net Network the peer connected through (\"ipv4\", \"ipv6\", \"onion\", \"i2p\", \"cjdns\", or \"npr\" (not publicly routable))\n"
" tp Transport protocol used for the connection (\"v1\", \"v2\" or \"*\" if detecting)\n"
" v Version of transport protocol used for the connection\n"
" mping Minimum observed ping time, in milliseconds (ms)\n"
" ping Last observed ping time, in milliseconds (ms)\n"
" send Time since last message sent to the peer, in seconds\n"
Expand Down
8 changes: 5 additions & 3 deletions src/blockfilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ GCSFilter::GCSFilter(const Params& params)
: m_params(params), m_N(0), m_F(0), m_encoded{0}
{}

GCSFilter::GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter)
GCSFilter::GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter, bool skip_decode_check)
: m_params(params), m_encoded(std::move(encoded_filter))
{
SpanReader stream{GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0};
Expand All @@ -59,6 +59,8 @@ GCSFilter::GCSFilter(const Params& params, std::vector<unsigned char> encoded_fi
}
m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_params.m_M);

if (skip_decode_check) return;

// Verify that the encoded filter contains exactly N elements. If it has too much or too little
// data, a std::ios_base::failure exception will be raised.
BitStreamReader<SpanReader> bitreader{stream};
Expand Down Expand Up @@ -219,14 +221,14 @@ static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
}

BlockFilter::BlockFilter(BlockFilterType filter_type, const uint256& block_hash,
std::vector<unsigned char> filter)
std::vector<unsigned char> filter, bool skip_decode_check)
: m_filter_type(filter_type), m_block_hash(block_hash)
{
GCSFilter::Params params;
if (!BuildParams(params)) {
throw std::invalid_argument("unknown filter_type");
}
m_filter = GCSFilter(params, std::move(filter));
m_filter = GCSFilter(params, std::move(filter), skip_decode_check);
}

BlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo)
Expand Down
6 changes: 3 additions & 3 deletions src/blockfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class GCSFilter
explicit GCSFilter(const Params& params = Params());

/** Reconstructs an already-created filter from an encoding. */
GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter);
GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter, bool skip_decode_check);

/** Builds a new filter from the params and set of elements. */
GCSFilter(const Params& params, const ElementSet& elements);
Expand Down Expand Up @@ -123,7 +123,7 @@ class BlockFilter

//! Reconstruct a BlockFilter from parts.
BlockFilter(BlockFilterType filter_type, const uint256& block_hash,
std::vector<unsigned char> filter);
std::vector<unsigned char> filter, bool skip_decode_check);

//! Construct a new BlockFilter of the specified type from a block.
BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo);
Expand Down Expand Up @@ -165,7 +165,7 @@ class BlockFilter
if (!BuildParams(params)) {
throw std::ios_base::failure("unknown filter_type");
}
m_filter = GCSFilter(params, std::move(encoded_filter));
m_filter = GCSFilter(params, std::move(encoded_filter), /*skip_decode_check=*/false);
}
};

Expand Down
Loading

0 comments on commit 59d82be

Please sign in to comment.