LCOV - code coverage report
Current view: top level - src/test/fuzz - utxo_total_supply.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 97.9 % 97 95
Test Date: 2025-01-22 04:09:46 Functions: 100.0 % 10 10
Branches: 55.5 % 146 81

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2020 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 <chainparams.h>
       6                 :             : #include <consensus/consensus.h>
       7                 :             : #include <consensus/merkle.h>
       8                 :             : #include <kernel/coinstats.h>
       9                 :             : #include <node/miner.h>
      10                 :             : #include <script/interpreter.h>
      11                 :             : #include <streams.h>
      12                 :             : #include <test/fuzz/FuzzedDataProvider.h>
      13                 :             : #include <test/fuzz/fuzz.h>
      14                 :             : #include <test/fuzz/util.h>
      15                 :             : #include <test/util/mining.h>
      16                 :             : #include <test/util/setup_common.h>
      17                 :             : #include <util/chaintype.h>
      18                 :             : #include <util/time.h>
      19                 :             : #include <validation.h>
      20                 :             : 
      21                 :             : using node::BlockAssembler;
      22                 :             : 
      23         [ +  - ]:        1983 : FUZZ_TARGET(utxo_total_supply)
      24                 :             : {
      25                 :        1569 :     SeedRandomStateForTest(SeedRand::ZEROS);
      26                 :        1569 :     FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
      27                 :        1569 :     const auto mock_time{ConsumeTime(fuzzed_data_provider, /*min=*/1296688602)}; // regtest genesis block timestamp
      28                 :             :     /** The testing setup that creates a chainman only (no chainstate) */
      29                 :        1569 :     ChainTestingSetup test_setup{
      30                 :             :         ChainType::REGTEST,
      31                 :             :         {
      32                 :             :             .extra_args = {
      33                 :             :                 "-testactivationheight=bip34@2",
      34         [ +  - ]:        1569 :                 strprintf("-mocktime=%d", mock_time).c_str()
      35                 :             :             },
      36                 :             :         },
      37         [ +  - ]:        3138 :     };
      38                 :             :     // Create chainstate
      39         [ +  - ]:        1569 :     test_setup.LoadVerifyActivateChainstate();
      40                 :        1569 :     auto& node{test_setup.m_node};
      41   [ +  -  +  - ]:        1569 :     auto& chainman{*Assert(test_setup.m_node.chainman)};
      42                 :             : 
      43                 :      203278 :     const auto ActiveHeight = [&]() {
      44                 :      201709 :         LOCK(chainman.GetMutex());
      45   [ +  -  +  - ]:      201709 :         return chainman.ActiveHeight();
      46                 :      203278 :     };
      47         [ +  - ]:        1569 :     BlockAssembler::Options options;
      48         [ +  - ]:        1569 :     options.coinbase_output_script = CScript() << OP_FALSE;
      49                 :      147669 :     const auto PrepareNextBlock = [&]() {
      50                 :             :         // Use OP_FALSE to avoid BIP30 check from hitting early
      51                 :      146100 :         auto block = PrepareBlock(node, options);
      52                 :             :         // Replace OP_FALSE with OP_TRUE
      53                 :      146100 :         {
      54         [ +  - ]:      146100 :             CMutableTransaction tx{*block->vtx.back()};
      55   [ +  -  +  - ]:      146100 :             tx.vout.at(0).scriptPubKey = CScript{} << OP_TRUE;
      56   [ +  -  -  + ]:      292200 :             block->vtx.back() = MakeTransactionRef(tx);
      57                 :           0 :         }
      58                 :      146100 :         return block;
      59                 :        1569 :     };
      60                 :             : 
      61                 :             :     /** The block template this fuzzer is working on */
      62         [ +  - ]:        1569 :     auto current_block = PrepareNextBlock();
      63                 :             :     /** Append-only set of tx outpoints, entries are not removed when spent */
      64                 :        1569 :     std::vector<std::pair<COutPoint, CTxOut>> txos;
      65                 :             :     /** The utxo stats at the chain tip */
      66                 :        1569 :     kernel::CCoinsStats utxo_stats;
      67                 :             :     /** The total amount of coins in the utxo set */
      68                 :        1569 :     CAmount circulation{0};
      69                 :             : 
      70                 :             : 
      71                 :             :     // Store the tx out in the txo map
      72                 :      189095 :     const auto StoreLastTxo = [&]() {
      73                 :             :         // get last tx
      74                 :      187526 :         const CTransaction& tx = *current_block->vtx.back();
      75                 :             :         // get last out
      76                 :      187526 :         const uint32_t i = tx.vout.size() - 1;
      77                 :             :         // store it
      78                 :      187526 :         txos.emplace_back(COutPoint{tx.GetHash(), i}, tx.vout.at(i));
      79   [ +  +  +  +  :      343518 :         if (current_block->vtx.size() == 1 && tx.vout.at(i).scriptPubKey[0] == OP_RETURN) {
                   +  + ]
      80                 :             :             // also store coinbase
      81                 :      152759 :             const uint32_t i = tx.vout.size() - 2;
      82                 :      152759 :             txos.emplace_back(COutPoint{tx.GetHash(), i}, tx.vout.at(i));
      83                 :             :         }
      84                 :      189095 :     };
      85                 :       42995 :     const auto AppendRandomTxo = [&](CMutableTransaction& tx) {
      86                 :       41426 :         const auto& txo = txos.at(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, txos.size() - 1));
      87                 :       41426 :         tx.vin.emplace_back(txo.first);
      88                 :       41426 :         tx.vout.emplace_back(txo.second.nValue, txo.second.scriptPubKey); // "Forward" coin with no fee
      89                 :       42995 :     };
      90                 :      146100 :     const auto UpdateUtxoStats = [&]() {
      91                 :      144531 :         LOCK(chainman.GetMutex());
      92   [ +  -  +  - ]:      144531 :         chainman.ActiveChainstate().ForceFlushStateToDisk();
      93         [ +  - ]:      289062 :         utxo_stats = std::move(
      94   [ +  -  +  -  :      144531 :             *Assert(kernel::ComputeUTXOStats(kernel::CoinStatsHashType::NONE, &chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, {})));
             +  -  +  - ]
      95                 :             :         // Check that miner can't print more money than they are allowed to
      96   [ +  -  +  - ]:      289062 :         assert(circulation == utxo_stats.total_amount);
      97                 :      146100 :     };
      98                 :             : 
      99                 :             : 
     100                 :             :     // Update internal state to chain tip
     101         [ +  - ]:        1569 :     StoreLastTxo();
     102         [ +  - ]:        1569 :     UpdateUtxoStats();
     103   [ +  -  -  + ]:        1569 :     assert(ActiveHeight() == 0);
     104                 :             :     // Get at which height we duplicate the coinbase
     105                 :             :     // Assuming that the fuzzer will mine relatively short chains (less than 200 blocks), we want the duplicate coinbase to be not too high.
     106                 :             :     // Up to 300 seems reasonable.
     107                 :        1569 :     int64_t duplicate_coinbase_height = fuzzed_data_provider.ConsumeIntegralInRange(0, 300);
     108                 :             :     // Always pad with OP_0 at the end to avoid bad-cb-length error
     109   [ +  -  +  - ]:        1569 :     const CScript duplicate_coinbase_script = CScript() << duplicate_coinbase_height << OP_0;
     110                 :             :     // Mine the first block with this duplicate
     111   [ +  -  -  + ]:        3138 :     current_block = PrepareNextBlock();
     112         [ +  - ]:        1569 :     StoreLastTxo();
     113                 :             : 
     114                 :        1569 :     {
     115                 :             :         // Create duplicate (CScript should match exact format as in CreateNewBlock)
     116         [ +  - ]:        1569 :         CMutableTransaction tx{*current_block->vtx.front()};
     117         [ +  - ]:        1569 :         tx.vin.at(0).scriptSig = duplicate_coinbase_script;
     118                 :             : 
     119                 :             :         // Mine block and create next block template
     120   [ +  -  -  + ]:        3138 :         current_block->vtx.front() = MakeTransactionRef(tx);
     121                 :           0 :     }
     122         [ +  - ]:        1569 :     current_block->hashMerkleRoot = BlockMerkleRoot(*current_block);
     123   [ +  -  -  + ]:        1569 :     assert(!MineBlock(node, current_block).IsNull());
     124   [ +  -  +  -  :        1569 :     circulation += GetBlockSubsidy(ActiveHeight(), Params().GetConsensus());
                   +  - ]
     125                 :             : 
     126   [ +  -  -  + ]:        1569 :     assert(ActiveHeight() == 1);
     127         [ +  - ]:        1569 :     UpdateUtxoStats();
     128   [ +  -  -  + ]:        3138 :     current_block = PrepareNextBlock();
     129         [ +  - ]:        1569 :     StoreLastTxo();
     130                 :             : 
     131                 :             :     // Limit to avoid timeout, but enough to cover duplicate_coinbase_height
     132                 :             :     // and CVE-2018-17144.
     133   [ +  +  +  + ]:      184388 :     LIMITED_WHILE(fuzzed_data_provider.remaining_bytes(), 2'00)
     134                 :             :     {
     135         [ +  - ]:      182819 :         CallOneOf(
     136                 :             :             fuzzed_data_provider,
     137                 :       17452 :             [&] {
     138                 :             :                 // Append an input-output pair to the last tx in the current block
     139                 :       17452 :                 CMutableTransaction tx{*current_block->vtx.back()};
     140         [ +  - ]:       17452 :                 AppendRandomTxo(tx);
     141   [ +  -  -  + ]:       34904 :                 current_block->vtx.back() = MakeTransactionRef(tx);
     142         [ +  - ]:       17452 :                 StoreLastTxo();
     143                 :       17452 :             },
     144                 :       23974 :             [&] {
     145                 :             :                 // Append a tx to the list of txs in the current block
     146                 :       23974 :                 CMutableTransaction tx{};
     147         [ +  - ]:       23974 :                 AppendRandomTxo(tx);
     148   [ +  -  +  -  :       47948 :                 current_block->vtx.push_back(MakeTransactionRef(tx));
                   -  + ]
     149         [ +  - ]:       23974 :                 StoreLastTxo();
     150                 :       23974 :             },
     151                 :      141393 :             [&] {
     152                 :             :                 // Append the current block to the active chain
     153                 :      141393 :                 node::RegenerateCommitments(*current_block, chainman);
     154                 :      141393 :                 const bool was_valid = !MineBlock(node, current_block).IsNull();
     155                 :             : 
     156                 :      141393 :                 const auto prev_utxo_stats = utxo_stats;
     157         [ +  + ]:      141393 :                 if (was_valid) {
     158         [ +  + ]:       98501 :                     if (duplicate_coinbase_height == ActiveHeight()) {
     159                 :             :                         // we mined the duplicate coinbase
     160         [ -  + ]:          14 :                         assert(current_block->vtx.at(0)->vin.at(0).scriptSig == duplicate_coinbase_script);
     161                 :             :                     }
     162                 :             : 
     163                 :       98501 :                     circulation += GetBlockSubsidy(ActiveHeight(), Params().GetConsensus());
     164                 :             :                 }
     165                 :             : 
     166                 :      141393 :                 UpdateUtxoStats();
     167                 :             : 
     168         [ +  + ]:      141393 :                 if (!was_valid) {
     169                 :             :                     // utxo stats must not change
     170         [ -  + ]:       42892 :                     assert(prev_utxo_stats.hashSerialized == utxo_stats.hashSerialized);
     171                 :             :                 }
     172                 :             : 
     173         [ -  + ]:      141393 :                 current_block = PrepareNextBlock();
     174                 :      141393 :                 StoreLastTxo();
     175                 :      141393 :             });
     176                 :             :     }
     177   [ +  -  +  - ]:        4707 : }
        

Generated by: LCOV version 2.0-1