1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2019 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <node/coinstats.h>
7 
8 #include <coins.h>
9 #include <hash.h>
10 #include <serialize.h>
11 #include <validation.h>
12 #include <uint256.h>
13 #include <util/system.h>
14 
15 #include <map>
16 
ApplyStats(CCoinsStats & stats,CHashWriter & ss,const uint256 & hash,const std::map<uint32_t,Coin> & outputs)17 static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
18 {
19     assert(!outputs.empty());
20     ss << hash;
21     ss << VARINT((outputs.begin()->second.nHeight << 2) + (outputs.begin()->second.fCoinBase ? 1u : 0u) + (outputs.begin()->second.fCoinStake ? 2u : 0u));
22     stats.nTransactions++;
23     for (const auto& output : outputs) {
24         ss << VARINT(output.first + 1);
25         ss << *(const CScriptBase*)(&output.second.out.scriptPubKey);
26         ss << VARINT_MODE(output.second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
27         stats.nTransactionOutputs++;
28         stats.nTotalAmount += output.second.out.nValue;
29         stats.nBogoSize += 32 /* txid */ + 4 /* vout index */ + 4 /* height + coinbase */ + 8 /* amount */ +
30                            2 /* scriptPubKey len */ + output.second.out.scriptPubKey.size() /* scriptPubKey */;
31     }
32     ss << VARINT(0u);
33 }
34 
35 //! Calculate statistics about the unspent transaction output set
GetUTXOStats(CCoinsView * view,CCoinsStats & stats)36 bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
37 {
38     stats = CCoinsStats();
39     std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
40     assert(pcursor);
41 
42     CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
43     stats.hashBlock = pcursor->GetBestBlock();
44     {
45         LOCK(cs_main);
46         stats.nHeight = LookupBlockIndex(stats.hashBlock)->nHeight;
47     }
48     ss << stats.hashBlock;
49     uint256 prevkey;
50     std::map<uint32_t, Coin> outputs;
51     while (pcursor->Valid()) {
52         COutPoint key;
53         Coin coin;
54         if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
55             if (!outputs.empty() && key.hash != prevkey) {
56                 ApplyStats(stats, ss, prevkey, outputs);
57                 outputs.clear();
58             }
59             prevkey = key.hash;
60             outputs[key.n] = std::move(coin);
61             stats.coins_count++;
62         } else {
63             return error("%s: unable to read value", __func__);
64         }
65         pcursor->Next();
66     }
67     if (!outputs.empty()) {
68         ApplyStats(stats, ss, prevkey, outputs);
69     }
70     stats.hashSerialized = ss.GetHash();
71     stats.nDiskSize = view->EstimateSize();
72     return true;
73 }
74