BSHA3  0.17.99
P2P Blockchain, based on Bitcoin
wallet_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012-2018 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 <wallet/wallet.h>
6 
7 #include <memory>
8 #include <set>
9 #include <stdint.h>
10 #include <utility>
11 #include <vector>
12 
13 #include <consensus/validation.h>
14 #include <rpc/server.h>
15 #include <test/test_bitcoin.h>
16 #include <validation.h>
17 #include <wallet/coincontrol.h>
19 
20 #include <boost/test/unit_test.hpp>
21 #include <univalue.h>
22 
23 extern UniValue importmulti(const JSONRPCRequest& request);
24 extern UniValue dumpwallet(const JSONRPCRequest& request);
25 extern UniValue importwallet(const JSONRPCRequest& request);
26 
28 
29 static void AddKey(CWallet& wallet, const CKey& key)
30 {
31  LOCK(wallet.cs_wallet);
32  wallet.AddKeyPubKey(key, key.GetPubKey());
33 }
34 
35 BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
36 {
37  // Cap last block file size, and mine new block in a new block file.
38  CBlockIndex* const nullBlock = nullptr;
39  CBlockIndex* oldTip = chainActive.Tip();
40  GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
41  CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
42  CBlockIndex* newTip = chainActive.Tip();
43 
44  LOCK(cs_main);
45 
46  // Verify ScanForWalletTransactions picks up transactions in both the old
47  // and new block files.
48  {
49  CWallet wallet("dummy", WalletDatabase::CreateDummy());
50  AddKey(wallet, coinbaseKey);
51  WalletRescanReserver reserver(&wallet);
52  reserver.reserve();
53  BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
54  BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
55  }
56 
57  // Prune the older block file.
59  UnlinkPrunedFiles({oldTip->GetBlockPos().nFile});
60 
61  // Verify ScanForWalletTransactions only picks transactions in the new block
62  // file.
63  {
64  CWallet wallet("dummy", WalletDatabase::CreateDummy());
65  AddKey(wallet, coinbaseKey);
66  WalletRescanReserver reserver(&wallet);
67  reserver.reserve();
68  BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
69  BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
70  }
71 
72  // Verify importmulti RPC returns failure for a key whose creation time is
73  // before the missing block, and success for a key whose creation time is
74  // after.
75  {
76  std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("dummy", WalletDatabase::CreateDummy());
77  AddWallet(wallet);
78  UniValue keys;
79  keys.setArray();
80  UniValue key;
81  key.setObject();
82  key.pushKV("scriptPubKey", HexStr(GetScriptForRawPubKey(coinbaseKey.GetPubKey())));
83  key.pushKV("timestamp", 0);
84  key.pushKV("internal", UniValue(true));
85  keys.push_back(key);
86  key.clear();
87  key.setObject();
88  CKey futureKey;
89  futureKey.MakeNewKey(true);
90  key.pushKV("scriptPubKey", HexStr(GetScriptForRawPubKey(futureKey.GetPubKey())));
91  key.pushKV("timestamp", newTip->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1);
92  key.pushKV("internal", UniValue(true));
93  keys.push_back(key);
94  JSONRPCRequest request;
95  request.params.setArray();
96  request.params.push_back(keys);
97 
98  UniValue response = importmulti(request);
99  BOOST_CHECK_EQUAL(response.write(),
100  strprintf("[{\"success\":false,\"error\":{\"code\":-1,\"message\":\"Rescan failed for key with creation "
101  "timestamp %d. There was an error reading a block from time %d, which is after or within %d "
102  "seconds of key creation, and could contain transactions pertaining to the key. As a result, "
103  "transactions and coins using this key may not appear in the wallet. This error could be caused "
104  "by pruning or data corruption (see bsha3d log for details) and could be dealt with by "
105  "downloading and rescanning the relevant blocks (see -reindex and -rescan "
106  "options).\"}},{\"success\":true}]",
107  0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW));
108  RemoveWallet(wallet);
109  }
110 }
111 
112 // Verify importwallet RPC starts rescan at earliest block with timestamp
113 // greater or equal than key birthday. Previously there was a bug where
114 // importwallet RPC would start the scan at the latest block with timestamp less
115 // than or equal to key birthday.
116 BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
117 {
118  // Create two blocks with same timestamp to verify that importwallet rescan
119  // will pick up both blocks, not just the first.
120  const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5;
121  SetMockTime(BLOCK_TIME);
122  m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
123  m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
124 
125  // Set key birthday to block time increased by the timestamp window, so
126  // rescan will start at the block time.
127  const int64_t KEY_TIME = BLOCK_TIME + TIMESTAMP_WINDOW;
128  SetMockTime(KEY_TIME);
129  m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
130 
131  LOCK(cs_main);
132 
133  std::string backup_file = (SetDataDir("importwallet_rescan") / "wallet.backup").string();
134 
135  // Import key into wallet and call dumpwallet to create backup file.
136  {
137  std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("dummy", WalletDatabase::CreateDummy());
138  LOCK(wallet->cs_wallet);
139  wallet->mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
140  wallet->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
141 
142  JSONRPCRequest request;
143  request.params.setArray();
144  request.params.push_back(backup_file);
145  AddWallet(wallet);
146  ::dumpwallet(request);
147  RemoveWallet(wallet);
148  }
149 
150  // Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
151  // were scanned, and no prior blocks were scanned.
152  {
153  std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("dummy", WalletDatabase::CreateDummy());
154 
155  JSONRPCRequest request;
156  request.params.setArray();
157  request.params.push_back(backup_file);
158  AddWallet(wallet);
159  ::importwallet(request);
160  RemoveWallet(wallet);
161 
162  LOCK(wallet->cs_wallet);
163  BOOST_CHECK_EQUAL(wallet->mapWallet.size(), 3U);
164  BOOST_CHECK_EQUAL(m_coinbase_txns.size(), 103U);
165  for (size_t i = 0; i < m_coinbase_txns.size(); ++i) {
166  bool found = wallet->GetWalletTx(m_coinbase_txns[i]->GetHash());
167  bool expected = i >= 100;
168  BOOST_CHECK_EQUAL(found, expected);
169  }
170  }
171 
172  SetMockTime(0);
173 }
174 
175 // Check that GetImmatureCredit() returns a newly calculated value instead of
176 // the cached value after a MarkDirty() call.
177 //
178 // This is a regression test written to verify a bugfix for the immature credit
179 // function. Similar tests probably should be written for the other credit and
180 // debit functions.
181 BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
182 {
183  CWallet wallet("dummy", WalletDatabase::CreateDummy());
184  CWalletTx wtx(&wallet, m_coinbase_txns.back());
185  LOCK2(cs_main, wallet.cs_wallet);
186  wtx.hashBlock = chainActive.Tip()->GetBlockHash();
187  wtx.nIndex = 0;
188 
189  // Call GetImmatureCredit() once before adding the key to the wallet to
190  // cache the current immature credit amount, which is 0.
191  BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 0);
192 
193  // Invalidate the cached value, add the key, and make sure a new immature
194  // credit amount is calculated.
195  wtx.MarkDirty();
196  wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
197  BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 50*COIN);
198 }
199 
200 static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
201 {
203  tx.nLockTime = lockTime;
204  SetMockTime(mockTime);
205  CBlockIndex* block = nullptr;
206  if (blockTime > 0) {
207  LOCK(cs_main);
208  auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
209  assert(inserted.second);
210  const uint256& hash = inserted.first->first;
211  block = inserted.first->second;
212  block->nTime = blockTime;
213  block->phashBlock = &hash;
214  }
215 
216  CWalletTx wtx(&wallet, MakeTransactionRef(tx));
217  if (block) {
218  wtx.SetMerkleBranch(block, 0);
219  }
220  {
221  LOCK(cs_main);
222  wallet.AddToWallet(wtx);
223  }
224  LOCK(wallet.cs_wallet);
225  return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;
226 }
227 
228 // Simple test to verify assignment of CWalletTx::nSmartTime value. Could be
229 // expanded to cover more corner cases of smart time logic.
230 BOOST_AUTO_TEST_CASE(ComputeTimeSmart)
231 {
232  // New transaction should use clock time if lower than block time.
233  BOOST_CHECK_EQUAL(AddTx(m_wallet, 1, 100, 120), 100);
234 
235  // Test that updating existing transaction does not change smart time.
236  BOOST_CHECK_EQUAL(AddTx(m_wallet, 1, 200, 220), 100);
237 
238  // New transaction should use clock time if there's no block time.
239  BOOST_CHECK_EQUAL(AddTx(m_wallet, 2, 300, 0), 300);
240 
241  // New transaction should use block time if lower than clock time.
242  BOOST_CHECK_EQUAL(AddTx(m_wallet, 3, 420, 400), 400);
243 
244  // New transaction should use latest entry time if higher than
245  // min(block time, clock time).
246  BOOST_CHECK_EQUAL(AddTx(m_wallet, 4, 500, 390), 400);
247 
248  // If there are future entries, new transaction should use time of the
249  // newest entry that is no more than 300 seconds ahead of the clock time.
250  BOOST_CHECK_EQUAL(AddTx(m_wallet, 5, 50, 600), 300);
251 
252  // Reset mock time for other tests.
253  SetMockTime(0);
254 }
255 
256 BOOST_AUTO_TEST_CASE(LoadReceiveRequests)
257 {
258  CTxDestination dest = CKeyID();
260  m_wallet.AddDestData(dest, "misc", "val_misc");
261  m_wallet.AddDestData(dest, "rr0", "val_rr0");
262  m_wallet.AddDestData(dest, "rr1", "val_rr1");
263 
264  auto values = m_wallet.GetDestValues("rr");
265  BOOST_CHECK_EQUAL(values.size(), 2U);
266  BOOST_CHECK_EQUAL(values[0], "val_rr0");
267  BOOST_CHECK_EQUAL(values[1], "val_rr1");
268 }
269 
270 class ListCoinsTestingSetup : public TestChain100Setup
271 {
272 public:
274  {
275  CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
276  wallet = MakeUnique<CWallet>("mock", WalletDatabase::CreateMock());
277  bool firstRun;
278  wallet->LoadWallet(firstRun);
279  AddKey(*wallet, coinbaseKey);
280  WalletRescanReserver reserver(wallet.get());
281  reserver.reserve();
282  wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver);
283  }
284 
286  {
287  wallet.reset();
288  }
289 
291  {
292  CTransactionRef tx;
293  CReserveKey reservekey(wallet.get());
294  CAmount fee;
295  int changePos = -1;
296  std::string error;
297  CCoinControl dummy;
298  BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, reservekey, fee, changePos, error, dummy));
299  CValidationState state;
300  BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, nullptr, state));
301  CMutableTransaction blocktx;
302  {
303  LOCK(wallet->cs_wallet);
304  blocktx = CMutableTransaction(*wallet->mapWallet.at(tx->GetHash()).tx);
305  }
306  CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
307  LOCK(wallet->cs_wallet);
308  auto it = wallet->mapWallet.find(tx->GetHash());
309  BOOST_CHECK(it != wallet->mapWallet.end());
310  it->second.SetMerkleBranch(chainActive.Tip(), 1);
311  return it->second;
312  }
313 
314  std::unique_ptr<CWallet> wallet;
315 };
316 
318 {
319  std::string coinbaseAddress = coinbaseKey.GetPubKey().GetID().ToString();
320 
321  // Confirm ListCoins initially returns 1 coin grouped under coinbaseKey
322  // address.
323  std::map<CTxDestination, std::vector<COutput>> list;
324  {
325  LOCK2(cs_main, wallet->cs_wallet);
326  list = wallet->ListCoins();
327  }
328  BOOST_CHECK_EQUAL(list.size(), 1U);
329  BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
330  BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U);
331 
332  // Check initial balance from one mature coinbase transaction.
333  BOOST_CHECK_EQUAL(50 * COIN, wallet->GetAvailableBalance());
334 
335  // Add a transaction creating a change address, and confirm ListCoins still
336  // returns the coin associated with the change address underneath the
337  // coinbaseKey pubkey, even though the change address has a different
338  // pubkey.
339  AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */});
340  {
341  LOCK2(cs_main, wallet->cs_wallet);
342  list = wallet->ListCoins();
343  }
344  BOOST_CHECK_EQUAL(list.size(), 1U);
345  BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
346  BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U);
347 
348  // Lock both coins. Confirm number of available coins drops to 0.
349  {
350  LOCK2(cs_main, wallet->cs_wallet);
351  std::vector<COutput> available;
352  wallet->AvailableCoins(available);
353  BOOST_CHECK_EQUAL(available.size(), 2U);
354  }
355  for (const auto& group : list) {
356  for (const auto& coin : group.second) {
357  LOCK(wallet->cs_wallet);
358  wallet->LockCoin(COutPoint(coin.tx->GetHash(), coin.i));
359  }
360  }
361  {
362  LOCK2(cs_main, wallet->cs_wallet);
363  std::vector<COutput> available;
364  wallet->AvailableCoins(available);
365  BOOST_CHECK_EQUAL(available.size(), 0U);
366  }
367  // Confirm ListCoins still returns same result as before, despite coins
368  // being locked.
369  {
370  LOCK2(cs_main, wallet->cs_wallet);
371  list = wallet->ListCoins();
372  }
373  BOOST_CHECK_EQUAL(list.size(), 1U);
374  BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
375  BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U);
376 }
377 
378 BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
379 {
380  std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("dummy", WalletDatabase::CreateDummy());
382  BOOST_CHECK(!wallet->TopUpKeyPool(1000));
383  CPubKey pubkey;
384  BOOST_CHECK(!wallet->GetKeyFromPool(pubkey, false));
385 }
386 
static std::unique_ptr< BerkeleyDatabase > CreateDummy()
Return object for accessing dummy database with no read/write capabilities.
Definition: db.h:132
CDiskBlockPos GetBlockPos() const
Definition: chain.h:261
static std::unique_ptr< BerkeleyDatabase > CreateMock()
Return object for accessing temporary in-memory database.
Definition: db.h:138
uint256 GetRandHash()
Definition: random.cpp:374
CAmount GetImmatureBalance() const
Definition: wallet.cpp:2054
void AvailableCoins(std::vector< COutput > &vCoins, bool fOnlySafe=true, const CCoinControl *coinControl=nullptr, const CAmount &nMinimumAmount=1, const CAmount &nMaximumAmount=MAX_MONEY, const CAmount &nMinimumSumAmount=MAX_MONEY, const uint64_t nMaximumCount=0, const int nMinDepth=0, const int nMaxDepth=9999999) const EXCLUSIVE_LOCKS_REQUIRED(cs_main
populate vCoins with vector of available COutputs.
Definition: wallet.cpp:2151
CAmount GetAvailableBalance(const CCoinControl *coinControl=nullptr) const
Definition: wallet.cpp:2136
std::vector< std::string > GetDestValues(const std::string &prefix) const
Get all destination values matching a prefix.
Definition: wallet.cpp:3792
#define strprintf
Definition: tinyformat.h:1066
bool AddWallet(const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:43
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:179
BlockMap & mapBlockIndex
Definition: validation.cpp:218
void SetMockTime(int64_t nMockTimeIn)
Definition: utiltime.cpp:30
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
Definition: standard.cpp:296
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or nullptr if none.
Definition: chain.h:440
uint32_t nTime
Definition: chain.h:212
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:402
Coin Control Features.
Definition: coincontrol.h:16
CWalletTx & AddTx(CRecipient recipient)
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
uint256 GetBlockHash() const
Definition: chain.h:292
BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
#define LOCK2(cs1, cs2)
Definition: sync.h:182
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
void PruneOneBlockFile(const int fileNumber)
Mark one block file as pruned.
CCriticalSection cs_main
Definition: validation.cpp:216
std::unique_ptr< CWallet > wallet
UniValue params
Definition: server.h:44
boost::variant< CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:123
#define LOCK(cs)
Definition: sync.h:181
An encapsulated public key.
Definition: pubkey.h:30
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:158
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Adds a key to the store, and saves it to disk.
Definition: wallet.cpp:296
int64_t GetBlockTimeMax() const
Definition: chain.h:302
void UnlinkPrunedFiles(const std::set< int > &setFilesToPrune)
Actually unlink the specified files.
std::map< CTxDestination, std::vector< COutput > > ListCoins() const EXCLUSIVE_LOCKS_REQUIRED(cs_main
Return list of available coins and locked coins grouped by non-change output address.
Definition: wallet.cpp:2260
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:18
CCriticalSection cs_wallet
Definition: wallet.h:709
CBlockFileInfo * GetBlockFileInfo(size_t n)
Get block file info entry for one block file.
bool AddToWallet(const CWalletTx &wtxIn, bool fFlushOnClose=true)
Definition: wallet.cpp:843
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1176
BOOST_AUTO_TEST_CASE(ComputeTimeSmart)
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:295
UniValue importmulti(const JSONRPCRequest &request)
Definition: rpcdump.cpp:1062
CBlockIndex * ScanForWalletTransactions(CBlockIndex *pindexStart, CBlockIndex *pindexStop, const WalletRescanReserver &reserver, bool fUpdate=false)
Scan the block chain (starting in pindexStart) for transactions from or to us.
Definition: wallet.cpp:1629
void LockCoin(const COutPoint &output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:3606
UniValue dumpwallet(const JSONRPCRequest &request)
Definition: rpcdump.cpp:677
Capture information about block/transaction validation.
Definition: validation.h:26
256-bit opaque blob.
Definition: uint256.h:122
bool setArray()
Definition: univalue.cpp:94
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
void SetWalletFlag(uint64_t flags)
set a single wallet flag
Definition: wallet.cpp:1423
A key allocated from the key pool.
Definition: wallet.h:1145
Testing setup and teardown for wallet.
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:170
CWallet & m_wallet
Definition: wallet.cpp:54
A reference to a CKey: the Hash360 of its serialized public key.
Definition: pubkey.h:20
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:445
#define BOOST_AUTO_TEST_SUITE_END()
Definition: object.cpp:16
bool RemoveWallet(const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:53
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:599
bool setObject()
Definition: univalue.cpp:101
bool error(const char *fmt, const Args &... args)
Definition: util.h:59
A mutable version of CTransaction.
Definition: transaction.h:360
void clear()
Definition: univalue.cpp:15
An encapsulated private key.
Definition: key.h:27
bool AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
Adds a destination data tuple to the store, and saves it to disk.
Definition: wallet.cpp:3755
CChain & chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:219
int nFile
Definition: chain.h:87
UniValue importwallet(const JSONRPCRequest &request)
Definition: rpcdump.cpp:504
#define BOOST_CHECK(expr)
Definition: object.cpp:17
const uint256 * phashBlock
pointer to the hash of the block, if any. Memory is owned by this CBlockIndex
Definition: chain.h:174