Bitcoin Core  24.1.0
P2P Digital Currency
validation_flush_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2021 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 //
5 #include <sync.h>
7 #include <validation.h>
8 
9 #include <boost/test/unit_test.hpp>
10 
11 BOOST_FIXTURE_TEST_SUITE(validation_flush_tests, TestingSetup)
12 
13 BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
19 {
20  Chainstate& chainstate{m_node.chainman->ActiveChainstate()};
21 
22  constexpr bool is_64_bit = sizeof(void*) == 8;
23 
24  LOCK(::cs_main);
25  auto& view = chainstate.CoinsTip();
26 
28  auto add_coin = [](CCoinsViewCache& coins_view) -> COutPoint {
29  Coin newcoin;
30  uint256 txid = InsecureRand256();
31  COutPoint outp{txid, 0};
32  newcoin.nHeight = 1;
33  newcoin.out.nValue = InsecureRand32();
34  newcoin.out.scriptPubKey.assign((uint32_t)56, 1);
35  coins_view.AddCoin(outp, std::move(newcoin), false);
36 
37  return outp;
38  };
39 
40  // The number of bytes consumed by coin's heap data, i.e. CScript
41  // (prevector<28, unsigned char>) when assigned 56 bytes of data per above.
42  //
43  // See also: Coin::DynamicMemoryUsage().
44  constexpr unsigned int COIN_SIZE = is_64_bit ? 80 : 64;
45 
46  auto print_view_mem_usage = [](CCoinsViewCache& view) {
47  BOOST_TEST_MESSAGE("CCoinsViewCache memory usage: " << view.DynamicMemoryUsage());
48  };
49 
50  constexpr size_t MAX_COINS_CACHE_BYTES = 1024;
51 
52  // Without any coins in the cache, we shouldn't need to flush.
54  chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0),
56 
57  // If the initial memory allocations of cacheCoins don't match these common
58  // cases, we can't really continue to make assertions about memory usage.
59  // End the test early.
60  if (view.DynamicMemoryUsage() != 32 && view.DynamicMemoryUsage() != 16) {
61  // Add a bunch of coins to see that we at least flip over to CRITICAL.
62 
63  for (int i{0}; i < 1000; ++i) {
64  COutPoint res = add_coin(view);
65  BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE);
66  }
67 
69  chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0),
71 
72  BOOST_TEST_MESSAGE("Exiting cache flush tests early due to unsupported arch");
73  return;
74  }
75 
76  print_view_mem_usage(view);
77  BOOST_CHECK_EQUAL(view.DynamicMemoryUsage(), is_64_bit ? 32U : 16U);
78 
79  // We should be able to add COINS_UNTIL_CRITICAL coins to the cache before going CRITICAL.
80  // This is contingent not only on the dynamic memory usage of the Coins
81  // that we're adding (COIN_SIZE bytes per), but also on how much memory the
82  // cacheCoins (unordered_map) preallocates.
83  constexpr int COINS_UNTIL_CRITICAL{3};
84 
85  for (int i{0}; i < COINS_UNTIL_CRITICAL; ++i) {
86  COutPoint res = add_coin(view);
87  print_view_mem_usage(view);
88  BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE);
90  chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0),
92  }
93 
94  // Adding some additional coins will push us over the edge to CRITICAL.
95  for (int i{0}; i < 4; ++i) {
96  add_coin(view);
97  print_view_mem_usage(view);
98  if (chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0) ==
100  break;
101  }
102  }
103 
105  chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0),
107 
108  // Passing non-zero max mempool usage should allow us more headroom.
110  chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/1 << 10),
112 
113  for (int i{0}; i < 3; ++i) {
114  add_coin(view);
115  print_view_mem_usage(view);
117  chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/1 << 10),
119  }
120 
121  // Adding another coin with the additional mempool room will put us >90%
122  // but not yet critical.
123  add_coin(view);
124  print_view_mem_usage(view);
125 
126  // Only perform these checks on 64 bit hosts; I haven't done the math for 32.
127  if (is_64_bit) {
128  float usage_percentage = (float)view.DynamicMemoryUsage() / (MAX_COINS_CACHE_BYTES + (1 << 10));
129  BOOST_TEST_MESSAGE("CoinsTip usage percentage: " << usage_percentage);
130  BOOST_CHECK(usage_percentage >= 0.9);
131  BOOST_CHECK(usage_percentage < 1);
133  chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, 1 << 10),
135  }
136 
137  // Using the default max_* values permits way more coins to be added.
138  for (int i{0}; i < 1000; ++i) {
139  add_coin(view);
141  chainstate.GetCoinsCacheSizeState(),
143  }
144 
145  // Flushing the view doesn't take us back to OK because cacheCoins has
146  // preallocated memory that doesn't get reclaimed even after flush.
147 
149  chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, 0),
151 
152  view.SetBestBlock(InsecureRand256());
153  BOOST_CHECK(view.Flush());
154  print_view_mem_usage(view);
155 
157  chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, 0),
159 }
160 
CAmount nValue
Definition: transaction.h:159
void assign(size_type n, const T &val)
Definition: prevector.h:220
CScript scriptPubKey
Definition: transaction.h:160
A UTXO entry.
Definition: coins.h:30
The cache is at >= 90% capacity.
node::NodeContext m_node
Definition: bitcoin-gui.cpp:37
CTxOut out
unspent transaction output
Definition: coins.h:34
The coins cache is in immediate need of a flush.
static uint32_t InsecureRand32()
Definition: setup_common.h:72
uint32_t nHeight
at which height this containing transaction was included in the active block chain ...
Definition: coins.h:40
Chainstate stores and provides an API to update our local knowledge of the current best chain...
Definition: validation.h:437
#define LOCK(cs)
Definition: sync.h:261
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
Test utilities for detecting when we need to flush the coins cache based on estimated memory usage...
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:34
static void add_coin(const CAmount &nValue, int nInput, std::vector< OutputGroup > &set)
256-bit opaque blob.
Definition: uint256.h:119
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:17
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: validation.cpp:121
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:212
static uint256 InsecureRand256()
Definition: setup_common.h:73
std::unique_ptr< ChainstateManager > chainman
Definition: context.h:54
Testing setup that configures a complete environment.
Definition: setup_common.h:109
#define BOOST_CHECK(expr)
Definition: object.cpp:16