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.8 % 92 90
Test Date: 2024-12-04 04:00:22 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 <validation.h>
      19                 :             : 
      20         [ +  - ]:        1561 : FUZZ_TARGET(utxo_total_supply)
      21                 :             : {
      22                 :             :     /** The testing setup that creates a chainman only (no chainstate) */
      23                 :        1149 :     ChainTestingSetup test_setup{
      24                 :             :         ChainType::REGTEST,
      25                 :             :         {
      26                 :             :             .extra_args = {"-testactivationheight=bip34@2"},
      27                 :             :         },
      28   [ +  -  +  - ]:        2298 :     };
      29                 :             :     // Create chainstate
      30         [ +  - ]:        1149 :     test_setup.LoadVerifyActivateChainstate();
      31                 :        1149 :     auto& node{test_setup.m_node};
      32   [ +  -  +  - ]:        1149 :     auto& chainman{*Assert(test_setup.m_node.chainman)};
      33         [ +  - ]:        1149 :     FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
      34                 :             : 
      35                 :      164424 :     const auto ActiveHeight = [&]() {
      36                 :      163275 :         LOCK(chainman.GetMutex());
      37   [ +  -  +  - ]:      163275 :         return chainman.ActiveHeight();
      38                 :      164424 :     };
      39                 :      110630 :     const auto PrepareNextBlock = [&]() {
      40                 :             :         // Use OP_FALSE to avoid BIP30 check from hitting early
      41   [ +  -  +  - ]:      109481 :         auto block = PrepareBlock(node, CScript{} << OP_FALSE);
      42                 :             :         // Replace OP_FALSE with OP_TRUE
      43                 :      109481 :         {
      44         [ +  - ]:      109481 :             CMutableTransaction tx{*block->vtx.back()};
      45   [ +  -  +  - ]:      109481 :             tx.vout.at(0).scriptPubKey = CScript{} << OP_TRUE;
      46   [ +  -  -  + ]:      218962 :             block->vtx.back() = MakeTransactionRef(tx);
      47                 :           0 :         }
      48                 :      109481 :         return block;
      49                 :        1149 :     };
      50                 :             : 
      51                 :             :     /** The block template this fuzzer is working on */
      52         [ +  - ]:        1149 :     auto current_block = PrepareNextBlock();
      53                 :             :     /** Append-only set of tx outpoints, entries are not removed when spent */
      54                 :        1149 :     std::vector<std::pair<COutPoint, CTxOut>> txos;
      55                 :             :     /** The utxo stats at the chain tip */
      56                 :        1149 :     kernel::CCoinsStats utxo_stats;
      57                 :             :     /** The total amount of coins in the utxo set */
      58                 :        1149 :     CAmount circulation{0};
      59                 :             : 
      60                 :             : 
      61                 :             :     // Store the tx out in the txo map
      62                 :      141830 :     const auto StoreLastTxo = [&]() {
      63                 :             :         // get last tx
      64                 :      140681 :         const CTransaction& tx = *current_block->vtx.back();
      65                 :             :         // get last out
      66                 :      140681 :         const uint32_t i = tx.vout.size() - 1;
      67                 :             :         // store it
      68                 :      140681 :         txos.emplace_back(COutPoint{tx.GetHash(), i}, tx.vout.at(i));
      69   [ +  +  +  +  :      257523 :         if (current_block->vtx.size() == 1 && tx.vout.at(i).scriptPubKey[0] == OP_RETURN) {
                   +  + ]
      70                 :             :             // also store coinbase
      71                 :      113875 :             const uint32_t i = tx.vout.size() - 2;
      72                 :      113875 :             txos.emplace_back(COutPoint{tx.GetHash(), i}, tx.vout.at(i));
      73                 :             :         }
      74                 :      141830 :     };
      75                 :       32349 :     const auto AppendRandomTxo = [&](CMutableTransaction& tx) {
      76                 :       31200 :         const auto& txo = txos.at(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, txos.size() - 1));
      77                 :       31200 :         tx.vin.emplace_back(txo.first);
      78                 :       31200 :         tx.vout.emplace_back(txo.second.nValue, txo.second.scriptPubKey); // "Forward" coin with no fee
      79                 :       32349 :     };
      80                 :      109481 :     const auto UpdateUtxoStats = [&]() {
      81                 :      108332 :         LOCK(chainman.GetMutex());
      82   [ +  -  +  - ]:      108332 :         chainman.ActiveChainstate().ForceFlushStateToDisk();
      83         [ +  - ]:      216664 :         utxo_stats = std::move(
      84   [ +  -  +  -  :      108332 :             *Assert(kernel::ComputeUTXOStats(kernel::CoinStatsHashType::NONE, &chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, {})));
             +  -  +  - ]
      85                 :             :         // Check that miner can't print more money than they are allowed to
      86   [ +  -  +  - ]:      216664 :         assert(circulation == utxo_stats.total_amount);
      87                 :      109481 :     };
      88                 :             : 
      89                 :             : 
      90                 :             :     // Update internal state to chain tip
      91         [ +  - ]:        1149 :     StoreLastTxo();
      92         [ +  - ]:        1149 :     UpdateUtxoStats();
      93   [ +  -  -  + ]:        1149 :     assert(ActiveHeight() == 0);
      94                 :             :     // Get at which height we duplicate the coinbase
      95                 :             :     // Assuming that the fuzzer will mine relatively short chains (less than 200 blocks), we want the duplicate coinbase to be not too high.
      96                 :             :     // Up to 300 seems reasonable.
      97                 :        1149 :     int64_t duplicate_coinbase_height = fuzzed_data_provider.ConsumeIntegralInRange(0, 300);
      98                 :             :     // Always pad with OP_0 at the end to avoid bad-cb-length error
      99   [ +  -  +  - ]:        1149 :     const CScript duplicate_coinbase_script = CScript() << duplicate_coinbase_height << OP_0;
     100                 :             :     // Mine the first block with this duplicate
     101   [ +  -  -  + ]:        2298 :     current_block = PrepareNextBlock();
     102         [ +  - ]:        1149 :     StoreLastTxo();
     103                 :             : 
     104                 :        1149 :     {
     105                 :             :         // Create duplicate (CScript should match exact format as in CreateNewBlock)
     106         [ +  - ]:        1149 :         CMutableTransaction tx{*current_block->vtx.front()};
     107         [ +  - ]:        1149 :         tx.vin.at(0).scriptSig = duplicate_coinbase_script;
     108                 :             : 
     109                 :             :         // Mine block and create next block template
     110   [ +  -  -  + ]:        2298 :         current_block->vtx.front() = MakeTransactionRef(tx);
     111                 :           0 :     }
     112         [ +  - ]:        1149 :     current_block->hashMerkleRoot = BlockMerkleRoot(*current_block);
     113   [ +  -  -  + ]:        1149 :     assert(!MineBlock(node, current_block).IsNull());
     114   [ +  -  +  -  :        1149 :     circulation += GetBlockSubsidy(ActiveHeight(), Params().GetConsensus());
                   +  - ]
     115                 :             : 
     116   [ +  -  -  + ]:        1149 :     assert(ActiveHeight() == 1);
     117         [ +  - ]:        1149 :     UpdateUtxoStats();
     118   [ +  -  -  + ]:        2298 :     current_block = PrepareNextBlock();
     119         [ +  - ]:        1149 :     StoreLastTxo();
     120                 :             : 
     121                 :             :     // Limit to avoid timeout, but enough to cover duplicate_coinbase_height
     122                 :             :     // and CVE-2018-17144.
     123   [ +  +  +  + ]:      138383 :     LIMITED_WHILE(fuzzed_data_provider.remaining_bytes(), 2'00)
     124                 :             :     {
     125         [ +  - ]:      137234 :         CallOneOf(
     126                 :             :             fuzzed_data_provider,
     127                 :       13279 :             [&] {
     128                 :             :                 // Append an input-output pair to the last tx in the current block
     129                 :       13279 :                 CMutableTransaction tx{*current_block->vtx.back()};
     130         [ +  - ]:       13279 :                 AppendRandomTxo(tx);
     131   [ +  -  -  + ]:       26558 :                 current_block->vtx.back() = MakeTransactionRef(tx);
     132         [ +  - ]:       13279 :                 StoreLastTxo();
     133                 :       13279 :             },
     134                 :       17921 :             [&] {
     135                 :             :                 // Append a tx to the list of txs in the current block
     136                 :       17921 :                 CMutableTransaction tx{};
     137         [ +  - ]:       17921 :                 AppendRandomTxo(tx);
     138   [ +  -  +  -  :       35842 :                 current_block->vtx.push_back(MakeTransactionRef(tx));
                   -  + ]
     139         [ +  - ]:       17921 :                 StoreLastTxo();
     140                 :       17921 :             },
     141                 :      106034 :             [&] {
     142                 :             :                 // Append the current block to the active chain
     143                 :      106034 :                 node::RegenerateCommitments(*current_block, chainman);
     144                 :      106034 :                 const bool was_valid = !MineBlock(node, current_block).IsNull();
     145                 :             : 
     146                 :      106034 :                 const auto prev_utxo_stats = utxo_stats;
     147         [ +  + ]:      106034 :                 if (was_valid) {
     148         [ +  + ]:       79914 :                     if (duplicate_coinbase_height == ActiveHeight()) {
     149                 :             :                         // we mined the duplicate coinbase
     150         [ -  + ]:          22 :                         assert(current_block->vtx.at(0)->vin.at(0).scriptSig == duplicate_coinbase_script);
     151                 :             :                     }
     152                 :             : 
     153                 :       79914 :                     circulation += GetBlockSubsidy(ActiveHeight(), Params().GetConsensus());
     154                 :             :                 }
     155                 :             : 
     156                 :      106034 :                 UpdateUtxoStats();
     157                 :             : 
     158         [ +  + ]:      106034 :                 if (!was_valid) {
     159                 :             :                     // utxo stats must not change
     160         [ -  + ]:       26120 :                     assert(prev_utxo_stats.hashSerialized == utxo_stats.hashSerialized);
     161                 :             :                 }
     162                 :             : 
     163         [ -  + ]:      106034 :                 current_block = PrepareNextBlock();
     164                 :      106034 :                 StoreLastTxo();
     165                 :      106034 :             });
     166                 :             :     }
     167         [ +  - ]:        3447 : }
        

Generated by: LCOV version 2.0-1