@@ -24,14 +24,14 @@ struct DBVal {
24
24
uint64_t bogo_size;
25
25
CAmount total_amount;
26
26
CAmount total_subsidy;
27
- CAmount block_unspendable_amount ;
28
- CAmount block_prevout_spent_amount ;
29
- CAmount block_new_outputs_ex_coinbase_amount ;
30
- CAmount block_coinbase_amount ;
31
- CAmount unspendables_genesis_block ;
32
- CAmount unspendables_bip30 ;
33
- CAmount unspendables_scripts ;
34
- CAmount unspendables_unclaimed_rewards ;
27
+ CAmount total_unspendable_amount ;
28
+ CAmount total_prevout_spent_amount ;
29
+ CAmount total_new_outputs_ex_coinbase_amount ;
30
+ CAmount total_coinbase_amount ;
31
+ CAmount total_unspendables_genesis_block ;
32
+ CAmount total_unspendables_bip30 ;
33
+ CAmount total_unspendables_scripts ;
34
+ CAmount total_unspendables_unclaimed_rewards ;
35
35
36
36
SERIALIZE_METHODS (DBVal, obj)
37
37
{
@@ -40,14 +40,14 @@ struct DBVal {
40
40
READWRITE (obj.bogo_size );
41
41
READWRITE (obj.total_amount );
42
42
READWRITE (obj.total_subsidy );
43
- READWRITE (obj.block_unspendable_amount );
44
- READWRITE (obj.block_prevout_spent_amount );
45
- READWRITE (obj.block_new_outputs_ex_coinbase_amount );
46
- READWRITE (obj.block_coinbase_amount );
47
- READWRITE (obj.unspendables_genesis_block );
48
- READWRITE (obj.unspendables_bip30 );
49
- READWRITE (obj.unspendables_scripts );
50
- READWRITE (obj.unspendables_unclaimed_rewards );
43
+ READWRITE (obj.total_unspendable_amount );
44
+ READWRITE (obj.total_prevout_spent_amount );
45
+ READWRITE (obj.total_new_outputs_ex_coinbase_amount );
46
+ READWRITE (obj.total_coinbase_amount );
47
+ READWRITE (obj.total_unspendables_genesis_block );
48
+ READWRITE (obj.total_unspendables_bip30 );
49
+ READWRITE (obj.total_unspendables_scripts );
50
+ READWRITE (obj.total_unspendables_unclaimed_rewards );
51
51
}
52
52
};
53
53
@@ -122,9 +122,12 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
122
122
123
123
uint256 expected_block_hash{pindex->pprev ->GetBlockHash ()};
124
124
if (read_out.first != expected_block_hash) {
125
+ LogPrintf (" WARNING: previous block header belongs to unexpected block %s; expected %s\n " ,
126
+ read_out.first .ToString (), expected_block_hash.ToString ());
127
+
125
128
if (!m_db->Read (DBHashKey (expected_block_hash), read_out)) {
126
- return error (" %s: previous block header belongs to unexpected block %s ; expected %s" ,
127
- __func__, read_out. first . ToString (), expected_block_hash.ToString ());
129
+ return error (" %s: previous block header not found ; expected %s" ,
130
+ __func__, expected_block_hash.ToString ());
128
131
}
129
132
}
130
133
@@ -138,29 +141,29 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
138
141
139
142
// Skip duplicate txid coinbase transactions (BIP30).
140
143
if (is_bip30_block && tx->IsCoinBase ()) {
141
- m_block_unspendable_amount += block_subsidy;
142
- m_unspendables_bip30 += block_subsidy;
144
+ m_total_unspendable_amount += block_subsidy;
145
+ m_total_unspendables_bip30 += block_subsidy;
143
146
continue ;
144
147
}
145
148
146
- for (size_t j = 0 ; j < tx->vout .size (); ++j) {
149
+ for (uint32_t j = 0 ; j < tx->vout .size (); ++j) {
147
150
const CTxOut& out{tx->vout [j]};
148
151
Coin coin{out, pindex->nHeight , tx->IsCoinBase ()};
149
- COutPoint outpoint{tx->GetHash (), static_cast < uint32_t >(j) };
152
+ COutPoint outpoint{tx->GetHash (), j };
150
153
151
154
// Skip unspendable coins
152
155
if (coin.out .scriptPubKey .IsUnspendable ()) {
153
- m_block_unspendable_amount += coin.out .nValue ;
154
- m_unspendables_scripts += coin.out .nValue ;
156
+ m_total_unspendable_amount += coin.out .nValue ;
157
+ m_total_unspendables_scripts += coin.out .nValue ;
155
158
continue ;
156
159
}
157
160
158
161
m_muhash.Insert (MakeUCharSpan (TxOutSer (outpoint, coin)));
159
162
160
163
if (tx->IsCoinBase ()) {
161
- m_block_coinbase_amount += coin.out .nValue ;
164
+ m_total_coinbase_amount += coin.out .nValue ;
162
165
} else {
163
- m_block_new_outputs_ex_coinbase_amount += coin.out .nValue ;
166
+ m_total_new_outputs_ex_coinbase_amount += coin.out .nValue ;
164
167
}
165
168
166
169
++m_transaction_output_count;
@@ -178,7 +181,7 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
178
181
179
182
m_muhash.Remove (MakeUCharSpan (TxOutSer (outpoint, coin)));
180
183
181
- m_block_prevout_spent_amount += coin.out .nValue ;
184
+ m_total_prevout_spent_amount += coin.out .nValue ;
182
185
183
186
--m_transaction_output_count;
184
187
m_total_amount -= coin.out .nValue ;
@@ -188,38 +191,41 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
188
191
}
189
192
} else {
190
193
// genesis block
191
- m_block_unspendable_amount += block_subsidy;
192
- m_unspendables_genesis_block += block_subsidy;
194
+ m_total_unspendable_amount += block_subsidy;
195
+ m_total_unspendables_genesis_block += block_subsidy;
193
196
}
194
197
195
198
// If spent prevouts + block subsidy are still a higher amount than
196
199
// new outputs + coinbase + current unspendable amount this means
197
200
// the miner did not claim the full block reward. Unclaimed block
198
201
// rewards are also unspendable.
199
- const CAmount unclaimed_rewards{(m_block_prevout_spent_amount + m_total_subsidy) - (m_block_new_outputs_ex_coinbase_amount + m_block_coinbase_amount + m_block_unspendable_amount )};
200
- m_block_unspendable_amount += unclaimed_rewards;
201
- m_unspendables_unclaimed_rewards += unclaimed_rewards;
202
+ const CAmount unclaimed_rewards{(m_total_prevout_spent_amount + m_total_subsidy) - (m_total_new_outputs_ex_coinbase_amount + m_total_coinbase_amount + m_total_unspendable_amount )};
203
+ m_total_unspendable_amount += unclaimed_rewards;
204
+ m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
202
205
203
206
std::pair<uint256, DBVal> value;
204
207
value.first = pindex->GetBlockHash ();
205
208
value.second .transaction_output_count = m_transaction_output_count;
206
209
value.second .bogo_size = m_bogo_size;
207
210
value.second .total_amount = m_total_amount;
208
211
value.second .total_subsidy = m_total_subsidy;
209
- value.second .block_unspendable_amount = m_block_unspendable_amount ;
210
- value.second .block_prevout_spent_amount = m_block_prevout_spent_amount ;
211
- value.second .block_new_outputs_ex_coinbase_amount = m_block_new_outputs_ex_coinbase_amount ;
212
- value.second .block_coinbase_amount = m_block_coinbase_amount ;
213
- value.second .unspendables_genesis_block = m_unspendables_genesis_block ;
214
- value.second .unspendables_bip30 = m_unspendables_bip30 ;
215
- value.second .unspendables_scripts = m_unspendables_scripts ;
216
- value.second .unspendables_unclaimed_rewards = m_unspendables_unclaimed_rewards ;
212
+ value.second .total_unspendable_amount = m_total_unspendable_amount ;
213
+ value.second .total_prevout_spent_amount = m_total_prevout_spent_amount ;
214
+ value.second .total_new_outputs_ex_coinbase_amount = m_total_new_outputs_ex_coinbase_amount ;
215
+ value.second .total_coinbase_amount = m_total_coinbase_amount ;
216
+ value.second .total_unspendables_genesis_block = m_total_unspendables_genesis_block ;
217
+ value.second .total_unspendables_bip30 = m_total_unspendables_bip30 ;
218
+ value.second .total_unspendables_scripts = m_total_unspendables_scripts ;
219
+ value.second .total_unspendables_unclaimed_rewards = m_total_unspendables_unclaimed_rewards ;
217
220
218
221
uint256 out;
219
222
m_muhash.Finalize (out);
220
223
value.second .muhash = out;
221
224
222
- return m_db->Write (DBHeightKey (pindex->nHeight ), value) && m_db->Write (DB_MUHASH, m_muhash);
225
+ CDBBatch batch (*m_db);
226
+ batch.Write (DBHeightKey (pindex->nHeight ), value);
227
+ batch.Write (DB_MUHASH, m_muhash);
228
+ return m_db->WriteBatch (batch);
223
229
}
224
230
225
231
static bool CopyHeightIndexToHashIndex (CDBIterator& db_it, CDBBatch& batch,
@@ -317,14 +323,14 @@ bool CoinStatsIndex::LookUpStats(const CBlockIndex* block_index, CCoinsStats& co
317
323
coins_stats.nBogoSize = entry.bogo_size ;
318
324
coins_stats.nTotalAmount = entry.total_amount ;
319
325
coins_stats.total_subsidy = entry.total_subsidy ;
320
- coins_stats.block_unspendable_amount = entry.block_unspendable_amount ;
321
- coins_stats.block_prevout_spent_amount = entry.block_prevout_spent_amount ;
322
- coins_stats.block_new_outputs_ex_coinbase_amount = entry.block_new_outputs_ex_coinbase_amount ;
323
- coins_stats.block_coinbase_amount = entry.block_coinbase_amount ;
324
- coins_stats.unspendables_genesis_block = entry.unspendables_genesis_block ;
325
- coins_stats.unspendables_bip30 = entry.unspendables_bip30 ;
326
- coins_stats.unspendables_scripts = entry.unspendables_scripts ;
327
- coins_stats.unspendables_unclaimed_rewards = entry.unspendables_unclaimed_rewards ;
326
+ coins_stats.total_unspendable_amount = entry.total_unspendable_amount ;
327
+ coins_stats.total_prevout_spent_amount = entry.total_prevout_spent_amount ;
328
+ coins_stats.total_new_outputs_ex_coinbase_amount = entry.total_new_outputs_ex_coinbase_amount ;
329
+ coins_stats.total_coinbase_amount = entry.total_coinbase_amount ;
330
+ coins_stats.total_unspendables_genesis_block = entry.total_unspendables_genesis_block ;
331
+ coins_stats.total_unspendables_bip30 = entry.total_unspendables_bip30 ;
332
+ coins_stats.total_unspendables_scripts = entry.total_unspendables_scripts ;
333
+ coins_stats.total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards ;
328
334
329
335
return true ;
330
336
}
@@ -341,33 +347,31 @@ bool CoinStatsIndex::Init()
341
347
}
342
348
}
343
349
344
- if (BaseIndex::Init ()) {
345
- const CBlockIndex* pindex{CurrentIndex ()};
350
+ if (!BaseIndex::Init ()) return false ;
346
351
347
- if (pindex) {
348
- DBVal entry;
349
- if (!LookUpOne (*m_db, pindex, entry)) {
350
- return false ;
351
- }
352
+ const CBlockIndex* pindex{CurrentIndex ()};
352
353
353
- m_transaction_output_count = entry.transaction_output_count ;
354
- m_bogo_size = entry.bogo_size ;
355
- m_total_amount = entry.total_amount ;
356
- m_total_subsidy = entry.total_subsidy ;
357
- m_block_unspendable_amount = entry.block_unspendable_amount ;
358
- m_block_prevout_spent_amount = entry.block_prevout_spent_amount ;
359
- m_block_new_outputs_ex_coinbase_amount = entry.block_new_outputs_ex_coinbase_amount ;
360
- m_block_coinbase_amount = entry.block_coinbase_amount ;
361
- m_unspendables_genesis_block = entry.unspendables_genesis_block ;
362
- m_unspendables_bip30 = entry.unspendables_bip30 ;
363
- m_unspendables_scripts = entry.unspendables_scripts ;
364
- m_unspendables_unclaimed_rewards = entry.unspendables_unclaimed_rewards ;
354
+ if (pindex) {
355
+ DBVal entry;
356
+ if (!LookUpOne (*m_db, pindex, entry)) {
357
+ return false ;
365
358
}
366
359
367
- return true ;
360
+ m_transaction_output_count = entry.transaction_output_count ;
361
+ m_bogo_size = entry.bogo_size ;
362
+ m_total_amount = entry.total_amount ;
363
+ m_total_subsidy = entry.total_subsidy ;
364
+ m_total_unspendable_amount = entry.total_unspendable_amount ;
365
+ m_total_prevout_spent_amount = entry.total_prevout_spent_amount ;
366
+ m_total_new_outputs_ex_coinbase_amount = entry.total_new_outputs_ex_coinbase_amount ;
367
+ m_total_coinbase_amount = entry.total_coinbase_amount ;
368
+ m_total_unspendables_genesis_block = entry.total_unspendables_genesis_block ;
369
+ m_total_unspendables_bip30 = entry.total_unspendables_bip30 ;
370
+ m_total_unspendables_scripts = entry.total_unspendables_scripts ;
371
+ m_total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards ;
368
372
}
369
373
370
- return false ;
374
+ return true ;
371
375
}
372
376
373
377
// Reverse a single block as part of a reorg
@@ -391,9 +395,12 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
391
395
392
396
uint256 expected_block_hash{pindex->pprev ->GetBlockHash ()};
393
397
if (read_out.first != expected_block_hash) {
398
+ LogPrintf (" WARNING: previous block header belongs to unexpected block %s; expected %s\n " ,
399
+ read_out.first .ToString (), expected_block_hash.ToString ());
400
+
394
401
if (!m_db->Read (DBHashKey (expected_block_hash), read_out)) {
395
- return error (" %s: previous block header belongs to unexpected block %s ; expected %s" ,
396
- __func__, read_out. first . ToString (), expected_block_hash.ToString ());
402
+ return error (" %s: previous block header not found ; expected %s" ,
403
+ __func__, expected_block_hash.ToString ());
397
404
}
398
405
}
399
406
}
@@ -402,24 +409,24 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
402
409
for (size_t i = 0 ; i < block.vtx .size (); ++i) {
403
410
const auto & tx{block.vtx .at (i)};
404
411
405
- for (size_t j = 0 ; j < tx->vout .size (); ++j) {
412
+ for (uint32_t j = 0 ; j < tx->vout .size (); ++j) {
406
413
const CTxOut& out{tx->vout [j]};
407
- COutPoint outpoint{tx->GetHash (), static_cast < uint32_t >(j) };
414
+ COutPoint outpoint{tx->GetHash (), j };
408
415
Coin coin{out, pindex->nHeight , tx->IsCoinBase ()};
409
416
410
417
// Skip unspendable coins
411
418
if (coin.out .scriptPubKey .IsUnspendable ()) {
412
- m_block_unspendable_amount -= coin.out .nValue ;
413
- m_unspendables_scripts -= coin.out .nValue ;
419
+ m_total_unspendable_amount -= coin.out .nValue ;
420
+ m_total_unspendables_scripts -= coin.out .nValue ;
414
421
continue ;
415
422
}
416
423
417
424
m_muhash.Remove (MakeUCharSpan (TxOutSer (outpoint, coin)));
418
425
419
426
if (tx->IsCoinBase ()) {
420
- m_block_coinbase_amount -= coin.out .nValue ;
427
+ m_total_coinbase_amount -= coin.out .nValue ;
421
428
} else {
422
- m_block_new_outputs_ex_coinbase_amount -= coin.out .nValue ;
429
+ m_total_new_outputs_ex_coinbase_amount -= coin.out .nValue ;
423
430
}
424
431
425
432
--m_transaction_output_count;
@@ -437,7 +444,7 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
437
444
438
445
m_muhash.Insert (MakeUCharSpan (TxOutSer (outpoint, coin)));
439
446
440
- m_block_prevout_spent_amount -= coin.out .nValue ;
447
+ m_total_prevout_spent_amount -= coin.out .nValue ;
441
448
442
449
m_transaction_output_count++;
443
450
m_total_amount += coin.out .nValue ;
@@ -446,9 +453,9 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
446
453
}
447
454
}
448
455
449
- const CAmount unclaimed_rewards{(m_block_new_outputs_ex_coinbase_amount + m_block_coinbase_amount + m_block_unspendable_amount ) - (m_block_prevout_spent_amount + m_total_subsidy)};
450
- m_block_unspendable_amount -= unclaimed_rewards;
451
- m_unspendables_unclaimed_rewards -= unclaimed_rewards;
456
+ const CAmount unclaimed_rewards{(m_total_new_outputs_ex_coinbase_amount + m_total_coinbase_amount + m_total_unspendable_amount ) - (m_total_prevout_spent_amount + m_total_subsidy)};
457
+ m_total_unspendable_amount -= unclaimed_rewards;
458
+ m_total_unspendables_unclaimed_rewards -= unclaimed_rewards;
452
459
453
460
// Check that the rolled back internal values are consistent with the DB read out
454
461
uint256 out;
@@ -459,14 +466,14 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
459
466
Assert (m_total_amount == read_out.second .total_amount );
460
467
Assert (m_bogo_size == read_out.second .bogo_size );
461
468
Assert (m_total_subsidy == read_out.second .total_subsidy );
462
- Assert (m_block_unspendable_amount == read_out.second .block_unspendable_amount );
463
- Assert (m_block_prevout_spent_amount == read_out.second .block_prevout_spent_amount );
464
- Assert (m_block_new_outputs_ex_coinbase_amount == read_out.second .block_new_outputs_ex_coinbase_amount );
465
- Assert (m_block_coinbase_amount == read_out.second .block_coinbase_amount );
466
- Assert (m_unspendables_genesis_block == read_out.second .unspendables_genesis_block );
467
- Assert (m_unspendables_bip30 == read_out.second .unspendables_bip30 );
468
- Assert (m_unspendables_scripts == read_out.second .unspendables_scripts );
469
- Assert (m_unspendables_unclaimed_rewards == read_out.second .unspendables_unclaimed_rewards );
469
+ Assert (m_total_unspendable_amount == read_out.second .total_unspendable_amount );
470
+ Assert (m_total_prevout_spent_amount == read_out.second .total_prevout_spent_amount );
471
+ Assert (m_total_new_outputs_ex_coinbase_amount == read_out.second .total_new_outputs_ex_coinbase_amount );
472
+ Assert (m_total_coinbase_amount == read_out.second .total_coinbase_amount );
473
+ Assert (m_total_unspendables_genesis_block == read_out.second .total_unspendables_genesis_block );
474
+ Assert (m_total_unspendables_bip30 == read_out.second .total_unspendables_bip30 );
475
+ Assert (m_total_unspendables_scripts == read_out.second .total_unspendables_scripts );
476
+ Assert (m_total_unspendables_unclaimed_rewards == read_out.second .total_unspendables_unclaimed_rewards );
470
477
471
478
return m_db->Write (DB_MUHASH, m_muhash);
472
479
}
0 commit comments