Electroneum
Loading...
Searching...
No Matches
blockchain.cpp
Go to the documentation of this file.
1// Copyrights(c) 2017-2021, The Electroneum Project
2// Copyrights(c) 2014-2019, The Monero Project
3//
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without modification, are
7// permitted provided that the following conditions are met:
8//
9// 1. Redistributions of source code must retain the above copyright notice, this list of
10// conditions and the following disclaimer.
11//
12// 2. Redistributions in binary form must reproduce the above copyright notice, this list
13// of conditions and the following disclaimer in the documentation and/or other
14// materials provided with the distribution.
15//
16// 3. Neither the name of the copyright holder nor the names of its contributors may be
17// used to endorse or promote products derived from this software without specific
18// prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29//
30// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
31
32#include <algorithm>
33#include <cstdio>
34#include <boost/filesystem.hpp>
35#include <boost/range/adaptor/reversed.hpp>
36
37#include "include_base_utils.h"
39#include "tx_pool.h"
40#include "blockchain.h"
43#include "cryptonote_config.h"
45#include "misc_language.h"
46#include "profile_tools.h"
47#include "file_io_utils.h"
48#include "int-util.h"
49#include "common/threadpool.h"
51#include "warnings.h"
52#include "crypto/hash.h"
53#include "cryptonote_core.h"
54#include "ringct/rctSigs.h"
55#include "common/perf_timer.h"
56#include "common/notify.h"
57#include "common/varint.h"
58#include "common/pruning.h"
59
60#undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
61#define ELECTRONEUM_DEFAULT_LOG_CATEGORY "blockchain"
62
63#define FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE (100*1024*1024) // 100 MB
64
65#define FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE (100*1024*1024) // 100 MB
66
67using namespace crypto;
68
69//#include "serialization/json_archive.h"
70
71/* TODO:
72 * Clean up code:
73 * Possibly change how outputs are referred to/indexed in blockchain and wallets
74 *
75 */
76
77using namespace cryptonote;
79extern "C" void slow_hash_allocate_state();
80extern "C" void slow_hash_free_state();
81
83
84#define MERROR_VER(x) MCERROR("verify", x)
85
86// used to overestimate the block reward when estimating a per kB to use
87#define BLOCK_REWARD_OVERESTIMATE (10 * 1000000000000)
88
89static const struct {
93 time_t time;
94} mainnet_hard_forks[] = {
95 // version 1 from the start of the blockchain
96 { 1, 1, 0, 1341378000 },
97 { 6, 307500, 0, 1538815057 }, //1538815057
98 { 7, 324500, 0, 1538985600 }, // Estimated July 5th, 8:30AM UTC
99 { 8, 589169, 0, 1562547600 },
100 { 9, 862866, 0, 1595615809 }, // Estimated July 22th, 2020
101 { 10, 1175315, 0, 1632999041 }, // Estimated Sep 30th 2021
102 { 11, 1811310, 0, 1709652642 }, // Estimated 5th March 2024 //
103};
104static const uint64_t mainnet_hard_fork_version_1_till = 307499;
105
106static const struct {
110 time_t time;
111} testnet_hard_forks[] = {
112 // version 1 from the start of the blockchain
113 { 1, 1, 0, 1341378000 },
114 { 6, 190060, 0, 1523263057 },
115 { 7, 215000, 0, 1530615600 },
116 { 8, 446674, 0, 1562889600 },
117 { 9, 707121, 0, 1595615809 },
118 { 10, 1086402, 0, 1631789441 }, // Estimated Sep 16th 2021
119 { 11, 1455270, 0, 1693256672 } // Estimated Aug 30th 2023
120};
121static const uint64_t testnet_hard_fork_version_1_till = 190059;
122
123static const struct {
127 time_t time;
128} stagenet_hard_forks[] = {
129 // version 1 from the start of the blockchain
130 { 1, 1, 0, 1341378000 },
131
132 // versions 2-9 in rapid succession from March 13th, 2018
133 { 2, 32000, 0, 1521000000 },
134 { 3, 33000, 0, 1521120000 },
135 { 4, 34000, 0, 1521240000 },
136 { 5, 35000, 0, 1521360000 },
137 { 6, 36000, 0, 1521480000 },
138 { 7, 37000, 0, 1521600000 },
139 { 8, 38000, 0, 1521800000 },
140 { 9, 39000, 0, 1522000000 },
141 { 10, 1086402, 0, 1631789441 }, // Estimated Sep 16th 2021
142 // TODO { 11, XXXXXXX, 0, XXXXXXXXXX }, // Estimated XXXXXXX
143};
144
145//------------------------------------------------------------------
147 m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_weight_limit(0), m_current_block_cumul_weight_median(0),
148 m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_sync_on_blocks(true), m_db_sync_threshold(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_bytes_to_sync(0), m_cancel(false),
149 m_long_term_block_weights_window(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE),
150 m_long_term_effective_median_block_weight(0),
151 m_long_term_block_weights_cache_tip_hash(crypto::null_hash),
152 m_long_term_block_weights_cache_rolling_median(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE),
153 m_difficulty_for_next_block_top_hash(crypto::null_hash),
154 m_difficulty_for_next_block(1),
155 m_btc_valid(false),
156 m_batch_success(true)
157{
158 LOG_PRINT_L3("Blockchain::" << __func__);
159}
160//------------------------------------------------------------------
162{
163 try { deinit(); }
164 catch (const std::exception &e) { /* ignore */ }
165}
166//------------------------------------------------------------------
168{
169 LOG_PRINT_L3("Blockchain::" << __func__);
170 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
171 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
172 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
173 // lock if it is otherwise needed.
174 return m_db->tx_exists(id);
175}
176//------------------------------------------------------------------
178{
179 LOG_PRINT_L3("Blockchain::" << __func__);
180 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
181 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
182 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
183 // lock if it is otherwise needed.
184 return m_db->has_key_image(key_im);
185}
186//------------------------------------------------------------------
187// This function makes sure that each "input" in an input (mixins) exists
188// and collects the public key for each from the transaction it was included in
189// via the visitor passed to it.
190template <class visitor_t>
191bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const txin_to_key& tx_in_to_key, visitor_t &vis, const crypto::hash &tx_prefix_hash, uint64_t* pmax_related_block_height) const
192{
193 LOG_PRINT_L3("Blockchain::" << __func__);
194
195 // ND: Disable locking and make method private.
196 //CRITICAL_REGION_LOCAL(m_blockchain_lock);
197
198 // verify that the input has key offsets (that it exists properly, really)
199 if(!tx_in_to_key.key_offsets.size())
200 return false;
201
202 // cryptonote_format_utils uses relative offsets for indexing to the global
203 // outputs list. that is to say that absolute offset #2 is absolute offset
204 // #1 plus relative offset #2.
205 // TODO: Investigate if this is necessary / why this is done.
206 std::vector<uint64_t> absolute_offsets = relative_output_offsets_to_absolute(tx_in_to_key.key_offsets);
207 std::vector<output_data_t> outputs;
208
209 bool found = false;
210 auto it = m_scan_table.find(tx_prefix_hash);
211 if (it != m_scan_table.end())
212 {
213 auto its = it->second.find(tx_in_to_key.k_image);
214 if (its != it->second.end())
215 {
216 outputs = its->second;
217 found = true;
218 }
219 }
220
221 if (!found)
222 {
223 try
224 {
225 m_db->get_output_key(epee::span<const uint64_t>(&tx_in_to_key.amount, 1), absolute_offsets, outputs, true);
226 if (absolute_offsets.size() != outputs.size())
227 {
228 MERROR_VER("Output does not exist! amount = " << tx_in_to_key.amount);
229 return false;
230 }
231 }
232 catch (...)
233 {
234 MERROR_VER("Output does not exist! amount = " << tx_in_to_key.amount);
235 return false;
236 }
237 }
238 else
239 {
240 // check for partial results and add the rest if needed;
241 if (outputs.size() < absolute_offsets.size() && outputs.size() > 0)
242 {
243 MDEBUG("Additional outputs needed: " << absolute_offsets.size() - outputs.size());
244 std::vector < uint64_t > add_offsets;
245 std::vector<output_data_t> add_outputs;
246 add_outputs.reserve(absolute_offsets.size() - outputs.size());
247 for (size_t i = outputs.size(); i < absolute_offsets.size(); i++)
248 add_offsets.push_back(absolute_offsets[i]);
249 try
250 {
251 m_db->get_output_key(epee::span<const uint64_t>(&tx_in_to_key.amount, 1), add_offsets, add_outputs, true);
252 if (add_offsets.size() != add_outputs.size())
253 {
254 MERROR_VER("Output does not exist! amount = " << tx_in_to_key.amount);
255 return false;
256 }
257 }
258 catch (...)
259 {
260 MERROR_VER("Output does not exist! amount = " << tx_in_to_key.amount);
261 return false;
262 }
263 outputs.insert(outputs.end(), add_outputs.begin(), add_outputs.end());
264 }
265 }
266
267 size_t count = 0;
268 for (const uint64_t& i : absolute_offsets)
269 {
270 try
271 {
272 output_data_t output_index;
273 try
274 {
275 // get tx hash and output index for output
276 if (count < outputs.size())
277 output_index = outputs.at(count);
278 else
279 output_index = m_db->get_output_key(tx_in_to_key.amount, i);
280
281 // call to the passed boost visitor to grab the public key for the output
282 if (!vis.handle_output(output_index.unlock_time, output_index.pubkey, output_index.commitment))
283 {
284 MERROR_VER("Failed to handle_output for output no = " << count << ", with absolute offset " << i);
285 return false;
286 }
287 }
288 catch (...)
289 {
290 MERROR_VER("Output does not exist! amount = " << tx_in_to_key.amount << ", absolute_offset = " << i);
291 return false;
292 }
293
294 // if on last output and pmax_related_block_height not null pointer
295 if(++count == absolute_offsets.size() && pmax_related_block_height)
296 {
297 // set *pmax_related_block_height to tx block height for this output
298 auto h = output_index.height;
299 if(*pmax_related_block_height < h)
300 {
301 *pmax_related_block_height = h;
302 }
303 }
304
305 }
306 catch (const OUTPUT_DNE& e)
307 {
308 MERROR_VER("Output does not exist: " << e.what());
309 return false;
310 }
311 catch (const TX_DNE& e)
312 {
313 MERROR_VER("Transaction does not exist: " << e.what());
314 return false;
315 }
316
317 }
318
319 return true;
320}
321//------------------------------------------------------------------
323{
324 LOG_PRINT_L3("Blockchain::" << __func__);
325 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
326 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
327 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
328 // lock if it is otherwise needed.
329 return m_db->height();
330}
331//------------------------------------------------------------------
332//FIXME: possibly move this into the constructor, to avoid accidentally
333// dereferencing a null BlockchainDB pointer
334bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline, const cryptonote::test_options *test_options, difficulty_type fixed_difficulty, const GetCheckpointsCallback& get_checkpoints/* = nullptr*/, bool ignore_bsig, bool fallback_to_pow)
335{
336 LOG_PRINT_L3("Blockchain::" << __func__);
337
338 CHECK_AND_ASSERT_MES(nettype != FAKECHAIN || test_options, false, "fake chain network type used without options");
339
340 CRITICAL_REGION_LOCAL(m_tx_pool);
341 CRITICAL_REGION_LOCAL1(m_blockchain_lock);
342
343 if (db == nullptr)
344 {
345 LOG_ERROR("Attempted to init Blockchain with null DB");
346 return false;
347 }
348 if (!db->is_open())
349 {
350 LOG_ERROR("Attempted to init Blockchain with unopened DB");
351 delete db;
352 return false;
353 }
354
355 m_db = db;
356
357 m_nettype = test_options != NULL ? FAKECHAIN : nettype;
358 m_offline = offline;
359 m_fixed_difficulty = fixed_difficulty;
360 m_ignore_bsig = ignore_bsig;
361 m_fallback_to_pow = fallback_to_pow;
362 if (m_hardfork == nullptr)
363 {
364 if (m_nettype == FAKECHAIN || m_nettype == STAGENET)
365 m_hardfork = new HardFork(*db, 1, 0);
366 else if (m_nettype == TESTNET)
367 m_hardfork = new HardFork(*db, 1, testnet_hard_fork_version_1_till);
368 else
369 m_hardfork = new HardFork(*db, 1, mainnet_hard_fork_version_1_till);
370 }
371 if (m_nettype == FAKECHAIN)
372 {
373 for (size_t n = 0; test_options->hard_forks[n].first; ++n)
374 m_hardfork->add_fork(test_options->hard_forks[n].first, test_options->hard_forks[n].second, 0, n + 1);
375 }
376 else if (m_nettype == TESTNET)
377 {
378 for (size_t n = 0; n < sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]); ++n)
379 m_hardfork->add_fork(testnet_hard_forks[n].version, testnet_hard_forks[n].height, testnet_hard_forks[n].threshold, testnet_hard_forks[n].time);
380 }
381 else if (m_nettype == STAGENET)
382 {
383 for (size_t n = 0; n < sizeof(stagenet_hard_forks) / sizeof(stagenet_hard_forks[0]); ++n)
384 m_hardfork->add_fork(stagenet_hard_forks[n].version, stagenet_hard_forks[n].height, stagenet_hard_forks[n].threshold, stagenet_hard_forks[n].time);
385 }
386 else
387 {
388 for (size_t n = 0; n < sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]); ++n)
389 m_hardfork->add_fork(mainnet_hard_forks[n].version, mainnet_hard_forks[n].height, mainnet_hard_forks[n].threshold, mainnet_hard_forks[n].time);
390 }
391 m_hardfork->init();
392
393 m_db->set_hard_fork(m_hardfork);
394
395 // if the blockchain is new, add the genesis block
396 // this feels kinda kludgy to do it this way, but can be looked at later.
397 // TODO: add function to create and store genesis block,
398 // taking testnet into account
399 if(!m_db->height())
400 {
401 MINFO("Blockchain not loaded, generating genesis block.");
402 block bl;
403 block_verification_context bvc = boost::value_initialized<block_verification_context>();
404 generate_genesis_block(bl, get_config(m_nettype).GENESIS_TX, get_config(m_nettype).GENESIS_NONCE);
405 db_wtxn_guard wtxn_guard(m_db);
406 add_new_block(bl, bvc);
407 CHECK_AND_ASSERT_MES(!bvc.m_verification_failed, false, "Failed to add genesis block to blockchain");
408 }
409 // TODO: if blockchain load successful, verify blockchain against both
410 // hard-coded and runtime-loaded (and enforced) checkpoints.
411 else
412 {
413 }
414
415 if (m_nettype != FAKECHAIN)
416 {
417 m_db->set_batch_transactions(true);
418 }
419
420 db_rtxn_guard rtxn_guard(m_db);
421
422 // check how far behind we are
423 uint64_t top_block_timestamp = m_db->get_top_block_timestamp();
424 uint64_t timestamp_diff = time(NULL) - top_block_timestamp;
425
426 // genesis block has no timestamp, could probably change it to have timestamp of 1397818133...
427 if(!top_block_timestamp)
428 timestamp_diff = time(NULL) - 1397818133;
429
430 // create general purpose async service queue
431
432 m_async_work_idle = std::unique_ptr < boost::asio::io_service::work > (new boost::asio::io_service::work(m_async_service));
433 // we only need 1
434 m_async_pool.create_thread(boost::bind(&boost::asio::io_service::run, &m_async_service));
435
436#if defined(PER_BLOCK_CHECKPOINT)
437 if (m_nettype != FAKECHAIN)
438 load_compiled_in_block_hashes(get_checkpoints);
439#endif
440
441 MINFO("Blockchain initialized. last block: " << m_db->height() - 1 << ", " << epee::misc_utils::get_time_interval_string(timestamp_diff) << " time ago, current difficulty: " << get_difficulty_for_next_block());
442
443 rtxn_guard.stop();
444
445 uint64_t num_popped_blocks = 0;
446 while (!m_db->is_read_only())
447 {
448 uint64_t top_height;
449 const crypto::hash top_id = m_db->top_block_hash(&top_height);
450 const block top_block = m_db->get_top_block();
451 const uint8_t ideal_hf_version = get_ideal_hard_fork_version(top_height);
452 if (ideal_hf_version <= 1 || ideal_hf_version == top_block.major_version)
453 {
454 if (num_popped_blocks > 0)
455 MGINFO("Initial popping done, top block: " << top_id << ", top height: " << top_height << ", block version: " << (uint64_t)top_block.major_version);
456 break;
457 }
458 else
459 {
460 if (num_popped_blocks == 0)
461 MGINFO("Current top block " << top_id << " at height " << top_height << " has version " << (uint64_t)top_block.major_version << " which disagrees with the ideal version " << (uint64_t)ideal_hf_version);
462 if (num_popped_blocks % 100 == 0)
463 MGINFO("Popping blocks... " << top_height);
464 ++num_popped_blocks;
465 block popped_block;
466 std::vector<transaction> popped_txs;
467 try
468 {
469 m_db->pop_block(popped_block, popped_txs);
470 }
471 // anything that could cause this to throw is likely catastrophic,
472 // so we re-throw
473 catch (const std::exception& e)
474 {
475 MERROR("Error popping block from blockchain: " << e.what());
476 throw;
477 }
478 catch (...)
479 {
480 MERROR("Error popping block from blockchain, throwing!");
481 throw;
482 }
483 }
484 }
485
486 if (num_popped_blocks > 0)
487 {
488 m_timestamps_and_difficulties_height = 0;
489 m_hardfork->reorganize_from_chain_height(get_current_blockchain_height());
490 uint64_t top_block_height;
491 crypto::hash top_block_hash = get_tail_id(top_block_height);
492 m_tx_pool.on_blockchain_dec(top_block_height, top_block_hash);
493 }
494
496 {
497 m_long_term_block_weights_window = test_options->long_term_block_weight_window;
498 m_long_term_block_weights_cache_rolling_median = epee::misc_utils::rolling_median_t<uint64_t>(m_long_term_block_weights_window);
499 }
500
501 {
502 db_txn_guard txn_guard(m_db, m_db->is_read_only());
503 if (!update_next_cumulative_weight_limit())
504 return false;
505 }
506
507 {
508 if(!m_db->is_read_only())
509 {
510 uint64_t top_height;
511 m_db->top_block_hash(&top_height);
512
513 if(top_height >= 1175315)
514 {
515 block b = m_db->get_block_from_height(1175315);
516 const auto &txout = boost::get<txout_to_key_public>(b.miner_tx.vout[0].target);
517 std::vector<cryptonote::address_outputs> addr_outs = m_db->get_addr_output_all(addKeys(txout.address.m_view_public_key, txout.address.m_spend_public_key));
518
519 if(addr_outs.empty()) {
520 MGINFO("Recomputing address_outputs database...");
521 m_db->top_block_hash(&top_height);
522 uint64_t diff = top_height - 1175200;
523 for(auto i = 0; i < diff; i++) {
524 block popped_block;
525 std::vector<transaction> popped_txs;
526 try
527 {
528 m_db->pop_block(popped_block, popped_txs);
529 }
530 catch (const std::exception& e)
531 {
532 MERROR("Error popping block from blockchain: " << e.what());
533 throw;
534 }
535 catch (...)
536 {
537 MERROR("Error popping block from blockchain, throwing!");
538 throw;
539 }
540 }
541 if (diff > 0)
542 {
543 m_hardfork->reorganize_from_chain_height(get_current_blockchain_height());
544 uint64_t top_block_height;
545 crypto::hash top_block_hash = get_tail_id(top_block_height);
546 m_tx_pool.on_blockchain_dec(top_block_height, top_block_hash);
547 }
548 MGINFO("Address_outputs database recomputed OK");
549 }
550 }
551 }
552 }
553
554 // GO BACK AND POPULATE A DATABASE OF KEY: COMBINED KEY , VALUE: TX INPUT
555 {
556 db_txn_guard txn_guard(m_db, m_db->is_read_only());
557 if(!m_db->is_read_only())
558 {
559 uint64_t top_height;
560 m_db->top_block_hash(&top_height);
561 uint64_t private_to_public_fork_height = m_nettype == MAINNET ? 1175315 : 1086402;
562 if(top_height >= private_to_public_fork_height)
563 {
564 block b = m_db->get_block_from_height(private_to_public_fork_height);
565 const auto &txout = boost::get<txout_to_key_public>(b.miner_tx.vout[0].target);
566 std::vector<cryptonote::address_txs> addr_txs = m_db->get_addr_tx_all(addKeys(txout.address.m_view_public_key, txout.address.m_spend_public_key));
567 if(addr_txs.empty()) {
568 MGINFO("Populating addr tx database...");
569 m_db->top_block_hash(&top_height);
570 // begin at the private to public fork block and store the data in addr_tx db one block at a time
571 uint64_t working_height = private_to_public_fork_height;
572 while (working_height <= top_height) {
573 block working_block = m_db->get_block_from_height(working_height);
574 //deal with miner tx first
575 for( auto vout: working_block.miner_tx.vout){ // all vouts are of type txout to key public
576 const auto &txout = boost::get<txout_to_key_public>(vout.target);
577 m_db->add_addr_tx(get_transaction_hash(working_block.miner_tx), addKeys(txout.address.m_view_public_key, txout.address.m_spend_public_key));
578
579 }
580 //deal with all other tx
581 std::vector<transaction> transactions = m_db->get_tx_list(working_block.tx_hashes);
582 for (auto tx : transactions){
583 auto hash = get_transaction_hash(tx);
584 std::unordered_set<crypto::public_key> addr_tx_addresses;
585 for (size_t i = 0; i < tx.vin.size(); i++){
586 if (tx.vin[i].type() == typeid(txin_to_key_public))
587 {
588 const auto &txin = boost::get<txin_to_key_public>(tx.vin[i]);
589 transaction parent_tx = m_db->get_tx(txin.tx_hash);
590 const auto &txout = boost::get<txout_to_key_public>(parent_tx.vout[txin.relative_offset].target); //previous tx out that this tx in references
591 crypto::public_key combined_key = addKeys(txout.address.m_view_public_key, txout.address.m_spend_public_key);
592 if(addr_tx_addresses.find(combined_key) == addr_tx_addresses.end()){ //if addr hasn't been used for another input yet, add the unique addr tx record for this address
593 m_db->add_addr_tx(hash, combined_key);
594 addr_tx_addresses.emplace(combined_key);
595 }
596 }
597 }
598 for(size_t i = 0; i < tx.vout.size(); i++){ // all vouts are of type txout to key public
599 const auto &txout = boost::get<txout_to_key_public>(tx.vout[i].target);
600 crypto::public_key combined_key = addKeys(txout.address.m_view_public_key, txout.address.m_spend_public_key);
601 if(addr_tx_addresses.find(combined_key) == addr_tx_addresses.end()){ //if addr hasn't been used for another input yet, add the unique addr tx record for this address
602 m_db->add_addr_tx(tx.hash, combined_key);
603 addr_tx_addresses.emplace(combined_key);
604 }
605 }
606 }
607 ++working_height;
608 }
609 MGINFO("Addr_txs database recomputed OK");
610 }
611
612 }
613 }
614
615 txn_guard.stop();
616 }
617 return true;
618}
619//------------------------------------------------------------------
620bool Blockchain::init(BlockchainDB* db, HardFork*& hf, const network_type nettype, bool offline)
621{
622 if (hf != nullptr)
623 m_hardfork = hf;
624 bool res = init(db, nettype, offline, NULL);
625 if (hf == nullptr)
626 hf = m_hardfork;
627 return res;
628}
629//------------------------------------------------------------------
631{
632 LOG_PRINT_L3("Blockchain::" << __func__);
633 // lock because the rpc_thread command handler also calls this
634 CRITICAL_REGION_LOCAL(m_db->m_synchronization_lock);
635
636 TIME_MEASURE_START(save);
637 // TODO: make sure sync(if this throws that it is not simply ignored higher
638 // up the call stack
639 try
640 {
641 m_db->sync();
642 }
643 catch (const std::exception& e)
644 {
645 MERROR(std::string("Error syncing blockchain db: ") + e.what() + "-- shutting down now to prevent issues!");
646 throw;
647 }
648 catch (...)
649 {
650 MERROR("There was an issue storing the blockchain, shutting down now to prevent issues!");
651 throw;
652 }
653
655 if(m_show_time_stats)
656 MINFO("Blockchain stored OK, took: " << save << " ms");
657 return true;
658}
659//------------------------------------------------------------------
661{
662 LOG_PRINT_L3("Blockchain::" << __func__);
663
664 MTRACE("Stopping blockchain read/write activity");
665
666 // stop async service
667 m_async_work_idle.reset();
668 m_async_pool.join_all();
669 m_async_service.stop();
670
671 // as this should be called if handling a SIGSEGV, need to check
672 // if m_db is a NULL pointer (and thus may have caused the illegal
673 // memory operation), otherwise we may cause a loop.
674 try
675 {
676 if (m_db)
677 {
678 m_db->close();
679 MTRACE("Local blockchain read/write activity stopped successfully");
680 }
681 }
682 catch (const std::exception& e)
683 {
684 LOG_ERROR(std::string("Error closing blockchain db: ") + e.what());
685 }
686 catch (...)
687 {
688 LOG_ERROR("There was an issue closing/storing the blockchain, shutting down now to prevent issues!");
689 }
690
691 delete m_hardfork;
692 m_hardfork = NULL;
693 delete m_db;
694 m_db = NULL;
695 return true;
696}
697//------------------------------------------------------------------
698// This function removes blocks from the top of blockchain.
699// It starts a batch and calls private method pop_block_from_blockchain().
701{
702 uint64_t i;
703 CRITICAL_REGION_LOCAL(m_tx_pool);
704 CRITICAL_REGION_LOCAL1(m_blockchain_lock);
705
706 bool stop_batch = m_db->batch_start();
707
708 try
709 {
710 const uint64_t blockchain_height = m_db->height();
711 if (blockchain_height > 0)
712 nblocks = std::min(nblocks, blockchain_height - 1);
713 for (i=0; i < nblocks; ++i)
714 {
715 pop_block_from_blockchain();
716 }
717 }
718 catch (const std::exception& e)
719 {
720 LOG_ERROR("Error when popping blocks after processing " << i << " blocks: " << e.what());
721 if (stop_batch)
722 m_db->batch_abort();
723 return;
724 }
725
726 if (stop_batch)
727 m_db->batch_stop();
728}
729//------------------------------------------------------------------
730// This function tells BlockchainDB to remove the top block from the
731// blockchain and then returns all transactions (except the miner tx, of course)
732// from it to the tx_pool
733block Blockchain::pop_block_from_blockchain()
734{
735 LOG_PRINT_L3("Blockchain::" << __func__);
736 CRITICAL_REGION_LOCAL(m_blockchain_lock);
737
738 m_timestamps_and_difficulties_height = 0;
739
740 block popped_block;
741 std::vector<transaction> popped_txs;
742
743 CHECK_AND_ASSERT_THROW_MES(m_db->height() > 1, "Cannot pop the genesis block");
744
745 try
746 {
747 m_db->pop_block(popped_block, popped_txs);
748 }
749 // anything that could cause this to throw is likely catastrophic,
750 // so we re-throw
751 catch (const std::exception& e)
752 {
753 LOG_ERROR("Error popping block from blockchain: " << e.what());
754 throw;
755 }
756 catch (...)
757 {
758 LOG_ERROR("Error popping block from blockchain, throwing!");
759 throw;
760 }
761
762 // make sure the hard fork object updates its current version
763 m_hardfork->on_block_popped(1);
764
765 // return transactions from popped block to the tx_pool
766 size_t pruned = 0;
767 for (transaction& tx : popped_txs)
768 {
769 if (tx.pruned)
770 {
771 ++pruned;
772 continue;
773 }
774 if (!is_coinbase(tx))
775 {
776 cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
777
778 // FIXME: HardFork
779 // Besides the below, popping a block should also remove the last entry
780 // in hf_versions.
782
783 // We assume that if they were in a block, the transactions are already
784 // known to the network as a whole. However, if we had mined that block,
785 // that might not be always true. Unlikely though, and always relaying
786 // these again might cause a spike of traffic as many nodes re-relay
787 // all the transactions in a popped block when a reorg happens.
788 bool r = m_tx_pool.add_tx(tx, tvc, true, true, false, version);
789 if (!r)
790 {
791 LOG_ERROR("Error returning transaction to tx_pool");
792 }
793 }
794 }
795 if (pruned)
796 MWARNING(pruned << " pruned txes could not be added back to the txpool");
797
798 m_blocks_longhash_table.clear();
799 m_scan_table.clear();
800 m_blocks_txs_check.clear();
801 m_check_txin_table.clear();
802
803 CHECK_AND_ASSERT_THROW_MES(update_next_cumulative_weight_limit(), "Error updating next cumulative weight limit");
804 uint64_t top_block_height;
805 crypto::hash top_block_hash = get_tail_id(top_block_height);
806 m_tx_pool.on_blockchain_dec(top_block_height, top_block_hash);
807 invalidate_block_template_cache();
808
809 return popped_block;
810}
811//------------------------------------------------------------------
813{
814 LOG_PRINT_L3("Blockchain::" << __func__);
815 CRITICAL_REGION_LOCAL(m_blockchain_lock);
816 m_timestamps_and_difficulties_height = 0;
817 m_alternative_chains.clear();
818 invalidate_block_template_cache();
819 m_db->reset();
820 m_hardfork->init();
821
822 db_wtxn_guard wtxn_guard(m_db);
823 block_verification_context bvc = boost::value_initialized<block_verification_context>();
824 add_new_block(b, bvc);
825 if (!update_next_cumulative_weight_limit())
826 return false;
828}
829//------------------------------------------------------------------
831{
832 LOG_PRINT_L3("Blockchain::" << __func__);
833 CRITICAL_REGION_LOCAL(m_blockchain_lock);
834 return m_db->top_block_hash(&height);
835}
836//------------------------------------------------------------------
838{
839 LOG_PRINT_L3("Blockchain::" << __func__);
840 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
841 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
842 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
843 // lock if it is otherwise needed.
844 return m_db->top_block_hash();
845}
846//------------------------------------------------------------------
847/*TODO: this function was...poorly written. As such, I'm not entirely
848 * certain on what it was supposed to be doing. Need to look into this,
849 * but it doesn't seem terribly important just yet.
850 *
851 * puts into list <ids> a list of hashes representing certain blocks
852 * from the blockchain in reverse chronological order
853 *
854 * the blocks chosen, at the time of this writing, are:
855 * the most recent 11
856 * powers of 2 less recent from there, so 13, 17, 25, etc...
857 *
858 */
859bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids) const
860{
861 LOG_PRINT_L3("Blockchain::" << __func__);
862 CRITICAL_REGION_LOCAL(m_blockchain_lock);
863 uint64_t i = 0;
864 uint64_t current_multiplier = 1;
865 uint64_t sz = m_db->height();
866
867 if(!sz)
868 return true;
869
870 db_rtxn_guard rtxn_guard(m_db);
871 bool genesis_included = false;
872 uint64_t current_back_offset = 1;
873 while(current_back_offset < sz)
874 {
875 ids.push_back(m_db->get_block_hash_from_height(sz - current_back_offset));
876
877 if(sz-current_back_offset == 0)
878 {
879 genesis_included = true;
880 }
881 if(i < 10)
882 {
883 ++current_back_offset;
884 }
885 else
886 {
887 current_multiplier *= 2;
888 current_back_offset += current_multiplier;
889 }
890 ++i;
891 }
892
893 if (!genesis_included)
894 {
895 ids.push_back(m_db->get_block_hash_from_height(0));
896 }
897
898 return true;
899}
900//------------------------------------------------------------------
902{
903 LOG_PRINT_L3("Blockchain::" << __func__);
904 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
905 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
906 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
907 // lock if it is otherwise needed.
908 try
909 {
910 return m_db->get_block_hash_from_height(height);
911 }
912 catch (const BLOCK_DNE& e)
913 {
914 }
915 catch (const std::exception& e)
916 {
917 MERROR(std::string("Something went wrong fetching block hash by height: ") + e.what());
918 throw;
919 }
920 catch (...)
921 {
922 MERROR(std::string("Something went wrong fetching block hash by height"));
923 throw;
924 }
925 return null_hash;
926}
927//------------------------------------------------------------------
928bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan) const
929{
930 LOG_PRINT_L3("Blockchain::" << __func__);
931 CRITICAL_REGION_LOCAL(m_blockchain_lock);
932
933 // try to find block in main chain
934 try
935 {
936 blk = m_db->get_block(h);
937 if (orphan)
938 *orphan = false;
939 return true;
940 }
941 // try to find block in alternative chain
942 catch (const BLOCK_DNE& e)
943 {
944 blocks_ext_by_hash::const_iterator it_alt = m_alternative_chains.find(h);
945 if (m_alternative_chains.end() != it_alt)
946 {
947 blk = it_alt->second.bl;
948 if (orphan)
949 *orphan = true;
950 return true;
951 }
952 }
953 catch (const std::exception& e)
954 {
955 MERROR(std::string("Something went wrong fetching block by hash: ") + e.what());
956 throw;
957 }
958 catch (...)
959 {
960 MERROR(std::string("Something went wrong fetching block hash by hash"));
961 throw;
962 }
963
964 return false;
965}
966//------------------------------------------------------------------
967// This function aggregates the cumulative difficulties and timestamps of the
968// last DIFFICULTY_BLOCKS_COUNT blocks and passes them to next_difficulty,
969// returning the result of that call. Ignores the genesis block, and can use
970// less blocks than desired if there aren't enough.
972{
973 if (m_fixed_difficulty)
974 {
975 return m_db->height() ? m_fixed_difficulty : 1;
976 }
977
978 LOG_PRINT_L3("Blockchain::" << __func__);
979
980 crypto::hash top_hash = get_tail_id();
981 {
982 CRITICAL_REGION_LOCAL(m_difficulty_lock);
983 // we can call this without the blockchain lock, it might just give us
984 // something a bit out of date, but that's fine since anything which
985 // requires the blockchain lock will have acquired it in the first place,
986 // and it will be unlocked only when called from the getinfo RPC
987 if (top_hash == m_difficulty_for_next_block_top_hash)
988 return m_difficulty_for_next_block;
989 }
990
991 CRITICAL_REGION_LOCAL(m_blockchain_lock);
992 std::vector<uint64_t> timestamps;
993 std::vector<difficulty_type> difficulties;
995 top_hash = get_tail_id(height); // get it again now that we have the lock
996 ++height; // top block height to blockchain height
997
998 uint64_t v6height = 0, v7height = 0, v8height = 0;
999 if(m_nettype == MAINNET) {
1000 v6height = mainnet_hard_forks[1].height;
1001 v7height = mainnet_hard_forks[2].height;
1002 v8height = mainnet_hard_forks[3].height;
1003 } else if(m_nettype == TESTNET) {
1004 v6height = testnet_hard_forks[1].height;
1005 v7height = testnet_hard_forks[2].height;
1006 v8height = testnet_hard_forks[3].height;
1007 } else if(m_nettype == STAGENET) {
1008 v6height = stagenet_hard_forks[5].height;
1009 v7height = stagenet_hard_forks[5].height;
1010 v8height = stagenet_hard_forks[5].height;
1011 } else if(m_nettype == UNDEFINED){
1012 MERROR(std::string("Something went wrong defining the network type."));
1013 }
1014
1015
1016 uint32_t difficultyBlocksCount = (height >= v6height && height < v7height) ? DIFFICULTY_BLOCKS_COUNT_V6 : DIFFICULTY_BLOCKS_COUNT;
1017
1018 // After v8 allow the difficulty window to grow linearly (from zero) back to DIFFICULTY_BLOCKS_COUNT.
1019 if((height >= v8height) && (height < v8height + 720))
1020 {
1021 // Initial clear of the caches when we hit v8.
1022 if(height == v8height)
1023 {
1024 m_timestamps.clear();
1025 m_difficulties.clear();
1026 }
1027 difficultyBlocksCount = height - v8height;
1028 }
1029
1030 // ND: Speedup
1031 // 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty,
1032 // then when the next block difficulty is queried, push the latest height data and
1033 // pop the oldest one from the list. This only requires 1x read per height instead
1034 // of doing 735 (DIFFICULTY_BLOCKS_COUNT).
1035 // Post v8 we will only re-enter this scope after the first DIFFICULTY_BLOCKS_COUNT blocks due to the last condition.
1036 if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= difficultyBlocksCount)
1037 {
1038 uint64_t index = height - 1;
1039 m_timestamps.push_back(m_db->get_block_timestamp(index));
1040 m_difficulties.push_back(m_db->get_block_cumulative_difficulty(index));
1041
1042 while (m_timestamps.size() > difficultyBlocksCount)
1043 m_timestamps.erase(m_timestamps.begin());
1044 while (m_difficulties.size() > difficultyBlocksCount)
1045 m_difficulties.erase(m_difficulties.begin());
1046
1047 m_timestamps_and_difficulties_height = height;
1048 timestamps = m_timestamps;
1049 difficulties = m_difficulties;
1050 }
1051 else
1052 {
1053 uint64_t offset = height - std::min < uint64_t > (height, static_cast<uint64_t>(difficultyBlocksCount));
1054 if (offset == 0)
1055 ++offset;
1056
1057 timestamps.clear();
1058 difficulties.clear();
1059 if (height > offset)
1060 {
1061 timestamps.reserve(height - offset);
1062 difficulties.reserve(height - offset);
1063 }
1064 for (; offset < height; offset++)
1065 {
1066 timestamps.push_back(m_db->get_block_timestamp(offset));
1067 difficulties.push_back(m_db->get_block_cumulative_difficulty(offset));
1068 }
1069
1070 m_timestamps_and_difficulties_height = height;
1071 m_timestamps = timestamps;
1072 m_difficulties = difficulties;
1073 }
1074 size_t target = get_difficulty_target();
1075 const uint8_t version = (height >= v6height && height < v7height) ? 6 : 1;
1076 difficulty_type diff = next_difficulty(timestamps, difficulties, target, version);
1077
1078 CRITICAL_REGION_LOCAL1(m_difficulty_lock);
1079 m_difficulty_for_next_block_top_hash = top_hash;
1080 m_difficulty_for_next_block = diff;
1081 return diff;
1082}
1083//------------------------------------------------------------------
1084std::vector<time_t> Blockchain::get_last_block_timestamps(unsigned int blocks) const
1085{
1086 uint64_t height = m_db->height();
1087 if (blocks > height)
1088 blocks = height;
1089 std::vector<time_t> timestamps(blocks);
1090 while (blocks--)
1091 timestamps[blocks] = m_db->get_block_timestamp(height - blocks - 1);
1092 return timestamps;
1093}
1094//------------------------------------------------------------------
1095// This function fixes the differing difficulty bug by re-calculate and rewriting
1096// the correct cumulative difficulty for blocks starting from V7 based on the
1097// correct 735 blocks input in the difficulty algorithm.
1099
1100 auto height = m_db->height();
1101 const uint64_t v8height = m_nettype == TESTNET ? 446674 : 589169;
1102
1103 if(height != v8height) {
1104 return;
1105 }
1106
1107 const uint64_t v7height = m_nettype == TESTNET ? 215000 : 324500;
1108 const size_t V7_DIFFICULTY_BLOCKS_COUNT = 735;
1109 const size_t V7_DIFFICULTY_TARGET = 120;
1110
1111 std::vector<uint64_t> timestamps;
1112 std::vector<difficulty_type> difficulties;
1113
1114 uint64_t start_height = v7height - V7_DIFFICULTY_BLOCKS_COUNT;
1115
1116 // Populate the timestamps & difficulties vectors with data from 735 blocks prior to V7 fork height (324500)
1117 for(uint64_t i = 0; start_height + i < v7height; i++) {
1118 timestamps.push_back(m_db->get_block_timestamp(start_height + i));
1119 difficulties.push_back(m_db->get_block_cumulative_difficulty(start_height + i));
1120 }
1121
1122 // Calculate the cumulative difficulty of block 324500 based on the 735 prior blocks' timestamp and difficulty values
1123 difficulty_type diff = difficulties.back() + next_difficulty(timestamps, difficulties, V7_DIFFICULTY_TARGET, 1);
1124
1125 // Override block's 324500 cumulative difficulty
1126 m_db->set_block_cumulative_difficulty(v7height, diff);
1127
1128 // Iterate over V7 blocks, starting from 324500 until current block height
1129 for(uint64_t i = v7height; i < height - 1; i++) {
1130
1131 // Add "324500 + i" timestamp & difficulty into the vectors
1132 timestamps.push_back(m_db->get_block_timestamp(i));
1133 difficulties.push_back(m_db->get_block_cumulative_difficulty(i));
1134
1135 // Erase the vector's first position maintaining its 735 size
1136 timestamps.erase(timestamps.begin());
1137 difficulties.erase(difficulties.begin());
1138
1139 // Calculate/set the correct cumulative difficulty of block "324500 + i"
1140 diff = difficulties.back() + next_difficulty(timestamps, difficulties, V7_DIFFICULTY_TARGET, 1);
1141 m_db->set_block_cumulative_difficulty(i + 1, diff);
1142 }
1143
1144 m_timestamps.clear();
1145 m_difficulties.clear();
1146}
1147
1148//------------------------------------------------------------------
1149// This function removes blocks from the blockchain until it gets to the
1150// position where the blockchain switch started and then re-adds the blocks
1151// that had been removed.
1152bool Blockchain::rollback_blockchain_switching(std::list<block>& original_chain, uint64_t rollback_height)
1153{
1154 LOG_PRINT_L3("Blockchain::" << __func__);
1155 CRITICAL_REGION_LOCAL(m_blockchain_lock);
1156
1157 // fail if rollback_height passed is too high
1158 if (rollback_height > m_db->height())
1159 {
1160 return true;
1161 }
1162
1163 m_timestamps_and_difficulties_height = 0;
1164
1165 // remove blocks from blockchain until we get back to where we should be.
1166 while (m_db->height() != rollback_height)
1167 {
1168 pop_block_from_blockchain();
1169 }
1170
1171 // make sure the hard fork object updates its current version
1172 m_hardfork->reorganize_from_chain_height(rollback_height);
1173
1174 //return back original chain
1175 for (auto& bl : original_chain)
1176 {
1177 block_verification_context bvc = boost::value_initialized<block_verification_context>();
1178 bool r = handle_block_to_main_chain(bl, bvc);
1179 CHECK_AND_ASSERT_MES(r && bvc.m_added_to_main_chain, false, "PANIC! failed to add (again) block while chain switching during the rollback!");
1180 }
1181
1182 m_hardfork->reorganize_from_chain_height(rollback_height);
1183
1184 MINFO("Rollback to height " << rollback_height << " was successful.");
1185 if (!original_chain.empty())
1186 {
1187 MINFO("Restoration to previous blockchain successful as well.");
1188 }
1189 return true;
1190}
1191//------------------------------------------------------------------
1192// This function attempts to switch to an alternate chain, returning
1193// boolean based on success therein.
1194bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::const_iterator>& alt_chain, bool discard_disconnected_chain)
1195{
1196 //TODO: Public
1197 LOG_PRINT_L3("Blockchain::" << __func__);
1198 CRITICAL_REGION_LOCAL(m_blockchain_lock);
1199
1200 m_timestamps_and_difficulties_height = 0;
1201
1202 // if empty alt chain passed (not sure how that could happen), return false
1203 CHECK_AND_ASSERT_MES(alt_chain.size(), false, "switch_to_alternative_blockchain: empty chain passed");
1204
1205 // verify that main chain has front of alt chain's parent block
1206 if (!m_db->block_exists(alt_chain.front()->second.bl.prev_id))
1207 {
1208 LOG_ERROR("Attempting to move to an alternate chain, but it doesn't appear to connect to the main chain!");
1209 return false;
1210 }
1211
1212 // pop blocks from the blockchain until the top block is the parent
1213 // of the front block of the alt chain.
1214 std::list<block> disconnected_chain;
1215 while (m_db->top_block_hash() != alt_chain.front()->second.bl.prev_id)
1216 {
1217 block b = pop_block_from_blockchain();
1218 disconnected_chain.push_front(b);
1219 }
1220
1221 auto split_height = m_db->height();
1222
1223 //connecting new alternative chain
1224 for(auto alt_ch_iter = alt_chain.begin(); alt_ch_iter != alt_chain.end(); alt_ch_iter++)
1225 {
1226 auto ch_ent = *alt_ch_iter;
1227 block_verification_context bvc = boost::value_initialized<block_verification_context>();
1228
1229 // add block to main chain
1230 bool r = handle_block_to_main_chain(ch_ent->second.bl, bvc);
1231
1232 // if adding block to main chain failed, rollback to previous state and
1233 // return false
1234 if(!r || !bvc.m_added_to_main_chain)
1235 {
1236 MERROR("Failed to switch to alternative blockchain");
1237
1238 // rollback_blockchain_switching should be moved to two different
1239 // functions: rollback and apply_chain, but for now we pretend it is
1240 // just the latter (because the rollback was done above).
1241 rollback_blockchain_switching(disconnected_chain, split_height);
1242
1243 // FIXME: Why do we keep invalid blocks around? Possibly in case we hear
1244 // about them again so we can immediately dismiss them, but needs some
1245 // looking into.
1246 add_block_as_invalid(ch_ent->second, get_block_hash(ch_ent->second.bl));
1247 MERROR("The block was inserted as invalid while connecting new alternative chain, block_id: " << get_block_hash(ch_ent->second.bl));
1248 m_alternative_chains.erase(*alt_ch_iter++);
1249
1250 for(auto alt_ch_to_orph_iter = alt_ch_iter; alt_ch_to_orph_iter != alt_chain.end(); )
1251 {
1252 add_block_as_invalid((*alt_ch_to_orph_iter)->second, (*alt_ch_to_orph_iter)->first);
1253 m_alternative_chains.erase(*alt_ch_to_orph_iter++);
1254 }
1255 return false;
1256 }
1257 }
1258
1259 // if we're to keep the disconnected blocks, add them as alternates
1260 const size_t discarded_blocks = disconnected_chain.size();
1261 if(!discard_disconnected_chain)
1262 {
1263 //pushing old chain as alternative chain
1264 for (auto& old_ch_ent : disconnected_chain)
1265 {
1266 block_verification_context bvc = boost::value_initialized<block_verification_context>();
1267 bool r = handle_alternative_block(old_ch_ent, get_block_hash(old_ch_ent), bvc);
1268 if(!r)
1269 {
1270 MERROR("Failed to push ex-main chain blocks to alternative chain ");
1271 // previously this would fail the blockchain switching, but I don't
1272 // think this is bad enough to warrant that.
1273 }
1274 }
1275 }
1276
1277 //removing alt_chain entries from alternative chains container
1278 for (auto ch_ent: alt_chain)
1279 {
1280 m_alternative_chains.erase(ch_ent);
1281 }
1282
1283 m_hardfork->reorganize_from_chain_height(split_height);
1284
1285 std::shared_ptr<tools::Notify> reorg_notify = m_reorg_notify;
1286 if (reorg_notify)
1287 reorg_notify->notify("%s", std::to_string(split_height).c_str(), "%h", std::to_string(m_db->height()).c_str(),
1288 "%n", std::to_string(m_db->height() - split_height).c_str(), "%d", std::to_string(discarded_blocks).c_str(), NULL);
1289
1290 MGINFO_GREEN("REORGANIZE SUCCESS! on height: " << split_height << ", new blockchain size: " << m_db->height());
1291 return true;
1292}
1293//------------------------------------------------------------------
1294// This function calculates the difficulty target for the block being added to
1295// an alternate chain.
1296difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::const_iterator>& alt_chain, block_extended_info& bei) const
1297{
1298 if (m_fixed_difficulty)
1299 {
1300 return m_db->height() ? m_fixed_difficulty : 1;
1301 }
1302
1303 LOG_PRINT_L3("Blockchain::" << __func__);
1304 std::vector<uint64_t> timestamps;
1305 std::vector<difficulty_type> cumulative_difficulties;
1306
1307 uint64_t v6height = 0, v7height = 0, v8height = 0;
1308
1309 if(m_nettype == MAINNET) {
1310 v6height = mainnet_hard_forks[1].height;
1311 v7height = mainnet_hard_forks[2].height;
1312 v8height = mainnet_hard_forks[3].height;
1313 } else if(m_nettype == TESTNET) {
1314 v6height = testnet_hard_forks[1].height;
1315 v7height = testnet_hard_forks[2].height;
1316 v8height = testnet_hard_forks[3].height;
1317 } else if(m_nettype == STAGENET) {
1318 v6height = stagenet_hard_forks[5].height;
1319 v7height = stagenet_hard_forks[5].height;
1320 v8height = stagenet_hard_forks[5].height;
1321 } else if(m_nettype == UNDEFINED){
1322 MERROR(std::string("Something went wrong defining the network type."));
1323 }
1324
1325 uint32_t difficultyBlocksCount = (bei.height >= v6height && bei.height < v7height) ? DIFFICULTY_BLOCKS_COUNT_V6 : DIFFICULTY_BLOCKS_COUNT;
1326
1327 // Account for the difficulty reset in v8
1328 if((bei.height >= v8height) && (bei.height < v8height + 720))
1329 {
1330 //No analogous cache to clear (ie m_timestamps, m_difficulties)for alt-chain
1331 difficultyBlocksCount = bei.height - v8height;
1332 }
1333
1334 // if the alt chain isn't long enough to calculate the difficulty target
1335 // based on its blocks alone, need to get more blocks from the main chain
1336 if(alt_chain.size()< difficultyBlocksCount)
1337 {
1338 CRITICAL_REGION_LOCAL(m_blockchain_lock);
1339
1340 // Figure out start and stop offsets for main chain blocks
1341 // End of alt chain height
1342 size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front()->second.height : bei.height;
1343 // How many blocks from the main chain will be needed?
1344 size_t main_chain_count = difficultyBlocksCount - std::min(static_cast<size_t>(difficultyBlocksCount), alt_chain.size());
1345 // If the amount of blocks we said we need from the main chain is more than the top height of the alt chain,
1346 // we necessarily take less blocks from the main chain (as many as is possible).
1347 main_chain_count = std::min(main_chain_count, main_chain_stop_offset);
1348 // Height on the main chain to begin pulling the blocks.
1349 size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count;
1350
1351 if(!main_chain_start_offset)
1352 ++main_chain_start_offset; //skip genesis block
1353
1354 // get difficulties and timestamps from relevant main chain blocks
1355 for(; main_chain_start_offset < main_chain_stop_offset; ++main_chain_start_offset)
1356 {
1357 timestamps.push_back(m_db->get_block_timestamp(main_chain_start_offset));
1358 cumulative_difficulties.push_back(m_db->get_block_cumulative_difficulty(main_chain_start_offset));
1359 }
1360
1361 // make sure we haven't accidentally grabbed too many blocks...maybe don't need this check?
1362 CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= difficultyBlocksCount, false, "Internal error, alt_chain.size()[" << alt_chain.size() << "] + vtimestampsec.size()[" << timestamps.size() << "] NOT <= DIFFICULTY_WINDOW[]" << difficultyBlocksCount);
1363
1364 for (auto it : alt_chain)
1365 {
1366 timestamps.push_back(it->second.bl.timestamp);
1367 cumulative_difficulties.push_back(it->second.cumulative_difficulty);
1368 }
1369 }
1370 // if the alt chain is long enough for the difficulty calc, grab difficulties
1371 // and timestamps from it alone
1372 else
1373 {
1374 timestamps.resize(static_cast<size_t>(difficultyBlocksCount));
1375 cumulative_difficulties.resize(static_cast<size_t>(difficultyBlocksCount));
1376 size_t count = 0;
1377 size_t max_i = timestamps.size()-1;
1378 // get difficulties and timestamps from most recent blocks in alt chain
1379 for(auto it: boost::adaptors::reverse(alt_chain))
1380 {
1381 timestamps[max_i - count] = it->second.bl.timestamp;
1382 cumulative_difficulties[max_i - count] = it->second.cumulative_difficulty;
1383 count++;
1384 if(count >= difficultyBlocksCount)
1385 break;
1386 }
1387 }
1388
1389 // FIXME: This will fail if fork activation heights are subject to voting - Does this need fixing for the V6 fork?
1390 size_t target = get_difficulty_target();
1391
1392 const uint8_t version = m_hardfork->get_ideal_version(bei.height);
1393 // calculate the difficulty target for the block and return it
1394 return next_difficulty(timestamps, cumulative_difficulties, target, version);
1395}
1396//------------------------------------------------------------------
1397// This function does a sanity check on basic things that all miner
1398// transactions have in common, such as:
1399// one input, of type txin_gen, with height set to the block's height
1400// correct miner tx unlock time
1401// a non-overflowing tx amount (dubious necessity on this check)
1402bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height)
1403{
1404 LOG_PRINT_L3("Blockchain::" << __func__);
1405 CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, false, "coinbase transaction in the block has no inputs");
1406 CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(txin_gen), false, "coinbase transaction in the block has the wrong type");
1407 if(boost::get<txin_gen>(b.miner_tx.vin[0]).height != height)
1408 {
1409 MWARNING("The miner transaction in block has invalid height: " << boost::get<txin_gen>(b.miner_tx.vin[0]).height << ", expected: " << height);
1410 return false;
1411 }
1412 MDEBUG("Miner tx hash: " << get_transaction_hash(b.miner_tx));
1414 CHECK_AND_ASSERT_MES(b.miner_tx.unlock_time == height + (hf_version > 7 ? ETN_MINED_ETN_UNLOCK_WINDOW_V8 : CRYPTONOTE_MINED_ETN_UNLOCK_WINDOW), false, "coinbase transaction transaction has the wrong unlock time=" << b.miner_tx.unlock_time << ", expected " << height + (hf_version > 7 ? ETN_MINED_ETN_UNLOCK_WINDOW_V8 : CRYPTONOTE_MINED_ETN_UNLOCK_WINDOW));
1415
1416 //check outs overflow
1417 //NOTE: not entirely sure this is necessary, given that this function is
1418 // designed simply to make sure the total amount for a transaction
1419 // does not overflow a uint64_t, and this transaction *is* a uint64_t...
1421 {
1422 MERROR("miner transaction has ETN overflow in block " << get_block_hash(b));
1423 return false;
1424 }
1425
1426 return true;
1427}
1428//------------------------------------------------------------------
1429// This function validates the miner transaction reward and for v11, that the coinbase is going to thew burn address.
1430bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_block_weight, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version)
1431{
1432 if (version >= 11){
1433 std::string coinbase_burn_address_viewkey_hex_str = "5866666666666666666666666666666666666666666666666666666666666666"; //private view is just 0100000000000000000000000000000000000000000000000000000000000000
1434 std::string coinbase_burn_address_spendkey_hex_str = "9511fabcb699b4f9dffc1779713d0dd7eb1ca56ba5b8ab8d3253a0a6ccf736b3";
1435 for (auto &o: b.miner_tx.vout) {
1436 const auto out = boost::get<txout_to_key_public>(o.target);
1437 std::string out_spendkey_str = epee::string_tools::pod_to_hex(out.address.m_spend_public_key.data);
1438 std::string out_viewkey_str = epee::string_tools::pod_to_hex(out.address.m_view_public_key.data);
1439 if(out_spendkey_str != coinbase_burn_address_spendkey_hex_str || out_viewkey_str != coinbase_burn_address_viewkey_hex_str){
1440 MERROR_VER("v11 miner tx output " << print_etn(o.amount) << " is being sent to an address other than the burn address");
1441 return false;
1442 }
1443 }
1444 }
1445
1446 LOG_PRINT_L3("Blockchain::" << __func__);
1447 //validate reward
1448 uint64_t etn_in_use = 0;
1449 for (auto& o: b.miner_tx.vout)
1450 etn_in_use += o.amount;
1451 partial_block_reward = false;
1452
1453 if (version == 3) {
1454 for (auto &o: b.miner_tx.vout) {
1455 if (!is_valid_decomposed_amount(o.amount)) {
1456 MERROR_VER("miner tx output " << print_etn(o.amount) << " is not a valid decomposed amount");
1457 return false;
1458 }
1459 }
1460 }
1461
1462 std::vector<uint64_t> last_blocks_weights;
1463 get_last_n_blocks_weights(last_blocks_weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
1464 if (!get_block_reward(epee::misc_utils::median(last_blocks_weights), cumulative_block_weight, already_generated_coins, base_reward, version, get_current_blockchain_height(), get_nettype()))
1465 {
1466 MERROR_VER("block weight " << cumulative_block_weight << " is bigger than allowed for this blockchain");
1467 return false;
1468 }
1469 if(base_reward + fee < etn_in_use && already_generated_coins > 0)
1470 {
1471 MERROR_VER("coinbase transaction spend too much ETN (" << print_etn(etn_in_use) << "). Block reward is " << print_etn(base_reward + fee) << "(" << print_etn(base_reward) << "+" << print_etn(fee) << ")");
1472 return false;
1473 }
1474 // From hard fork 2, we allow a miner to claim less block reward than is allowed, in case a miner wants less dust
1475 if (version < 2)
1476 {
1477 if(base_reward + fee != etn_in_use && already_generated_coins > 0)
1478 {
1479 MDEBUG("coinbase transaction doesn't use full amount of block reward: spent: " << etn_in_use << ", block reward " << base_reward + fee << "(" << base_reward << "+" << fee << ")");
1480 return false;
1481 }
1482 }
1483 else
1484 {
1485 // from hard fork 2, since a miner can claim less than the full block reward, we update the base_reward
1486 // to show the amount of coins that were actually generated, the remainder will be pushed back for later
1487 // emission. This modifies the emission curve very slightly.
1488 CHECK_AND_ASSERT_MES(etn_in_use - fee <= base_reward, false, "base reward calculation bug");
1489 if(base_reward + fee != etn_in_use)
1490 partial_block_reward = true;
1491 base_reward = etn_in_use - fee;
1492 }
1493 return true;
1494}
1495//------------------------------------------------------------------
1496// get the block weights of the last <count> blocks, and return by reference <sz>.
1497void Blockchain::get_last_n_blocks_weights(std::vector<uint64_t>& weights, size_t count) const
1498{
1499 LOG_PRINT_L3("Blockchain::" << __func__);
1500 CRITICAL_REGION_LOCAL(m_blockchain_lock);
1501 auto h = m_db->height();
1502
1503 // this function is meaningless for an empty blockchain...granted it should never be empty
1504 if(h == 0)
1505 return;
1506
1507 // add weight of last <count> blocks to vector <weights> (or less, if blockchain size < count)
1508 size_t start_offset = h - std::min<size_t>(h, count);
1509 weights = m_db->get_block_weights(start_offset, count);
1510}
1511//------------------------------------------------------------------
1512uint64_t Blockchain::get_long_term_block_weight_median(uint64_t start_height, size_t count) const
1513{
1514 LOG_PRINT_L3("Blockchain::" << __func__);
1515 CRITICAL_REGION_LOCAL(m_blockchain_lock);
1516
1517 PERF_TIMER(get_long_term_block_weights);
1518
1519 CHECK_AND_ASSERT_THROW_MES(count > 0, "count == 0");
1520
1521 bool cached = false;
1522 uint64_t blockchain_height = m_db->height();
1523 uint64_t tip_height = start_height + count - 1;
1524 crypto::hash tip_hash = crypto::null_hash;
1525 if (tip_height < blockchain_height && count == (size_t)m_long_term_block_weights_cache_rolling_median.size())
1526 {
1527 tip_hash = m_db->get_block_hash_from_height(tip_height);
1528 cached = tip_hash == m_long_term_block_weights_cache_tip_hash;
1529 }
1530
1531 if (cached)
1532 {
1533 MTRACE("requesting " << count << " from " << start_height << ", cached");
1534 return m_long_term_block_weights_cache_rolling_median.median();
1535 }
1536
1537 // in the vast majority of uncached cases, most is still cached,
1538 // as we just move the window one block up:
1539 if (tip_height > 0 && count == (size_t)m_long_term_block_weights_cache_rolling_median.size() && tip_height < blockchain_height)
1540 {
1541 crypto::hash old_tip_hash = m_db->get_block_hash_from_height(tip_height - 1);
1542 if (old_tip_hash == m_long_term_block_weights_cache_tip_hash)
1543 {
1544 MTRACE("requesting " << count << " from " << start_height << ", incremental");
1545 m_long_term_block_weights_cache_tip_hash = tip_hash;
1546 m_long_term_block_weights_cache_rolling_median.insert(m_db->get_block_long_term_weight(tip_height));
1547 return m_long_term_block_weights_cache_rolling_median.median();
1548 }
1549 }
1550
1551 MTRACE("requesting " << count << " from " << start_height << ", uncached");
1552 std::vector<uint64_t> weights = m_db->get_long_term_block_weights(start_height, count);
1553 m_long_term_block_weights_cache_tip_hash = tip_hash;
1554 m_long_term_block_weights_cache_rolling_median.clear();
1555 for (uint64_t w: weights)
1556 m_long_term_block_weights_cache_rolling_median.insert(w);
1557 return m_long_term_block_weights_cache_rolling_median.median();
1558}
1559//------------------------------------------------------------------
1561{
1562 LOG_PRINT_L3("Blockchain::" << __func__);
1563 return m_current_block_cumul_weight_limit;
1564}
1565//------------------------------------------------------------------
1567{
1568 LOG_PRINT_L3("Blockchain::" << __func__);
1569 return m_current_block_cumul_weight_median;
1570}
1571//------------------------------------------------------------------
1572//TODO: This function only needed minor modification to work with BlockchainDB,
1573// and *works*. As such, to reduce the number of things that might break
1574// in moving to BlockchainDB, this function will remain otherwise
1575// unchanged for the time being.
1576//
1577// This function makes a new block for a miner to mine the hash for
1578//
1579// FIXME: this codebase references #if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
1580// in a lot of places. That flag is not referenced in any of the code
1581// nor any of the makefiles, howeve. Need to look into whether or not it's
1582// necessary at all.
1583bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce)
1584{
1585 LOG_PRINT_L3("Blockchain::" << __func__);
1586 size_t median_weight;
1587 uint64_t already_generated_coins;
1588 //uint64_t pool_cookie;
1589
1590 m_tx_pool.lock();
1591 const auto unlock_guard = epee::misc_utils::create_scope_leave_handler([&]() { m_tx_pool.unlock(); });
1592 CRITICAL_REGION_LOCAL(m_blockchain_lock);
1593 if (m_btc_valid && !from_block) {
1594 // The pool cookie is atomic. The lack of locking is OK, as if it changes
1595 // just as we compare it, we'll just use a slightly old template, but
1596 // this would be the case anyway if we'd lock, and the change happened
1597 // just after the block template was created
1598 if (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address)) && m_btc_nonce == ex_nonce
1599 && m_btc_pool_cookie == m_tx_pool.cookie() && m_btc.prev_id == get_tail_id()) {
1600 MDEBUG("Using cached template");
1601 m_btc.timestamp = time(NULL); // update timestamp unconditionally
1602 b = m_btc;
1603 diffic = m_btc_difficulty;
1604 height = m_btc_height;
1605 expected_reward = m_btc_expected_reward;
1606 return true;
1607 }
1608 MDEBUG("Not using cached template: address " << (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address))) << ", nonce " << (m_btc_nonce == ex_nonce) << ", cookie " << (m_btc_pool_cookie == m_tx_pool.cookie()) << ", from_block " << (!!from_block));
1609 invalidate_block_template_cache();
1610 }
1611
1612 if (from_block)
1613 {
1614 //build alternative subchain, front -> mainchain, back -> alternative head
1615 //block is not related with head of main chain
1616 //first of all - look in alternative chains container
1617 auto it_prev = m_alternative_chains.find(*from_block);
1618 bool parent_in_main = m_db->block_exists(*from_block);
1619 if(it_prev == m_alternative_chains.end() && !parent_in_main)
1620 {
1621 MERROR("Unknown from block");
1622 return false;
1623 }
1624
1625 //we have new block in alternative chain
1626 std::list<blocks_ext_by_hash::const_iterator> alt_chain;
1627 block_verification_context bvc = boost::value_initialized<block_verification_context>();
1628 std::vector<uint64_t> timestamps;
1629 if (!build_alt_chain(*from_block, alt_chain, timestamps, bvc))
1630 return false;
1631
1632 if (parent_in_main)
1633 {
1634 cryptonote::block prev_block;
1635 CHECK_AND_ASSERT_MES(get_block_by_hash(*from_block, prev_block), false, "From block not found"); // TODO
1636 uint64_t from_block_height = cryptonote::get_block_height(prev_block);
1637 height = from_block_height + 1;
1638 }
1639 else
1640 {
1641 height = alt_chain.back()->second.height + 1;
1642 }
1643 b.major_version = m_hardfork->get_ideal_version(height);
1644 b.minor_version = m_hardfork->get_ideal_version();
1645 b.prev_id = *from_block;
1646
1647 // cheat and use the weight of the block we start from, virtually certain to be acceptable
1648 // and use 1.9 times rather than 2 times so we're even more sure
1649 if (parent_in_main)
1650 {
1651 median_weight = m_db->get_block_weight(height - 1);
1652 already_generated_coins = m_db->get_block_already_generated_coins(height - 1);
1653 }
1654 else
1655 {
1656 median_weight = it_prev->second.block_cumulative_weight - it_prev->second.block_cumulative_weight / 20;
1657 already_generated_coins = alt_chain.back()->second.already_generated_coins;
1658 }
1659
1660 // FIXME: consider moving away from block_extended_info at some point
1661 block_extended_info bei = boost::value_initialized<block_extended_info>();
1662 bei.bl = b;
1663 bei.height = alt_chain.size() ? it_prev->second.height + 1 : m_db->get_block_height(*from_block) + 1;
1664
1665 diffic = get_next_difficulty_for_alternative_chain(alt_chain, bei);
1666 }
1667 else
1668 {
1669 height = m_db->height();
1670 b.major_version = m_hardfork->get_current_version();
1671 b.minor_version = m_hardfork->get_ideal_version();
1672 b.prev_id = get_tail_id();
1673 median_weight = m_current_block_cumul_weight_limit / 2;
1675 already_generated_coins = m_db->get_block_already_generated_coins(height - 1);
1676 }
1677 b.timestamp = time(NULL);
1678
1679 uint64_t median_ts;
1680 if (!check_block_timestamp(b, median_ts))
1681 {
1682 b.timestamp = median_ts;
1683 }
1684
1685 CHECK_AND_ASSERT_MES(diffic, false, "difficulty overhead.");
1686
1687 size_t txs_weight;
1688 uint64_t fee;
1689 if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, b.major_version))
1690 {
1691 return false;
1692 }
1693 //pool_cookie = m_tx_pool.cookie();
1694#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
1695 size_t real_txs_weight = 0;
1696 uint64_t real_fee = 0;
1697 for(crypto::hash &cur_hash: b.tx_hashes)
1698 {
1699 auto cur_res = m_tx_pool.m_transactions.find(cur_hash);
1700 if (cur_res == m_tx_pool.m_transactions.end())
1701 {
1702 LOG_ERROR("Creating block template: error: transaction not found");
1703 continue;
1704 }
1705 tx_memory_pool::tx_details &cur_tx = cur_res->second;
1706 real_txs_weight += cur_tx.weight;
1707 real_fee += cur_tx.fee;
1708 if (cur_tx.weight != get_transaction_weight(cur_tx.tx))
1709 {
1710 LOG_ERROR("Creating block template: error: invalid transaction weight");
1711 }
1712
1713 uint64_t inputs_amount;
1714 if (!get_inputs_etn_amount(cur_tx.tx, inputs_amount))
1715 {
1716 LOG_ERROR("Creating block template: error: cannot get inputs amount");
1717 }
1718 else if (cur_tx.fee != inputs_amount - get_outs_etn_amount(cur_tx.tx))
1719 {
1720 LOG_ERROR("Creating block template: error: invalid fee");
1721 }
1722 }
1723 if (txs_weight != real_txs_weight)
1724 {
1725 LOG_ERROR("Creating block template: error: wrongly calculated transaction weight");
1726 }
1727 if (fee != real_fee)
1728 {
1729 LOG_ERROR("Creating block template: error: wrongly calculated fee");
1730 }
1731 MDEBUG("Creating block template: height " << height <<
1732 ", median weight " << median_weight <<
1733 ", already generated coins " << already_generated_coins <<
1734 ", transaction weight " << txs_weight <<
1735 ", fee " << fee);
1736#endif
1737
1738 /*
1739 two-phase miner transaction generation: we don't know exact block weight until we prepare block, but we don't know reward until we know
1740 block weight, so first miner transaction generated with fake amount of etn, and with phase we know think we know expected block weight
1741 */
1742 //make blocks coin-base tx looks close to real coinbase tx to get truthful blob weight
1743 uint8_t hf_version = b.major_version;
1744 size_t max_outs = hf_version >= 4 ? 1 : 11;
1745 bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype);
1746 CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance");
1747 size_t cumulative_weight = txs_weight + get_transaction_weight(b.miner_tx);
1748#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
1749 MDEBUG("Creating block template: miner tx weight " << get_transaction_weight(b.miner_tx) <<
1750 ", cumulative weight " << cumulative_weight);
1751#endif
1752 for (size_t try_count = 0; try_count != 10; ++try_count)
1753 {
1754 r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype);
1755
1756 CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, second chance");
1757 size_t coinbase_weight = get_transaction_weight(b.miner_tx);
1758 if (coinbase_weight > cumulative_weight - txs_weight)
1759 {
1760 cumulative_weight = txs_weight + coinbase_weight;
1761#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
1762 MDEBUG("Creating block template: miner tx weight " << coinbase_weight <<
1763 ", cumulative weight " << cumulative_weight << " is greater than before");
1764#endif
1765 continue;
1766 }
1767
1768 if (coinbase_weight < cumulative_weight - txs_weight)
1769 {
1770 size_t delta = cumulative_weight - txs_weight - coinbase_weight;
1771#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
1772 MDEBUG("Creating block template: miner tx weight " << coinbase_weight <<
1773 ", cumulative weight " << txs_weight + coinbase_weight <<
1774 " is less than before, adding " << delta << " zero bytes");
1775#endif
1776 b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0);
1777 //here could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len.
1778 if (cumulative_weight != txs_weight + get_transaction_weight(b.miner_tx))
1779 {
1780 CHECK_AND_ASSERT_MES(cumulative_weight + 1 == txs_weight + get_transaction_weight(b.miner_tx), false, "unexpected case: cumulative_weight=" << cumulative_weight << " + 1 is not equal txs_cumulative_weight=" << txs_weight << " + get_transaction_weight(b.miner_tx)=" << get_transaction_weight(b.miner_tx));
1781 b.miner_tx.extra.resize(b.miner_tx.extra.size() - 1);
1782 if (cumulative_weight != txs_weight + get_transaction_weight(b.miner_tx))
1783 {
1784 //fuck, not lucky, -1 makes varint-counter size smaller, in that case we continue to grow with cumulative_weight
1785 MDEBUG("Miner tx creation has no luck with delta_extra size = " << delta << " and " << delta - 1);
1786 cumulative_weight += delta - 1;
1787 continue;
1788 }
1789 MDEBUG("Setting extra for block: " << b.miner_tx.extra.size() << ", try_count=" << try_count);
1790 }
1791 }
1792 CHECK_AND_ASSERT_MES(cumulative_weight == txs_weight + get_transaction_weight(b.miner_tx), false, "unexpected case: cumulative_weight=" << cumulative_weight << " is not equal txs_cumulative_weight=" << txs_weight << " + get_transaction_weight(b.miner_tx)=" << get_transaction_weight(b.miner_tx));
1793#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
1794 MDEBUG("Creating block template: miner tx weight " << coinbase_weight <<
1795 ", cumulative weight " << cumulative_weight << " is now good");
1796#endif
1797
1798 //if (!from_block)
1799 // cache_block_template(b, miner_address, ex_nonce, diffic, height, expected_reward, pool_cookie);
1800
1801 if(!m_fallback_to_pow && hf_version >= 8) {
1802 sign_block(b, m_validator_key);
1803 }
1804
1805 return true;
1806 }
1807 LOG_ERROR("Failed to create_block_template with " << 10 << " tries");
1808 return false;
1809}
1810
1811void Blockchain::sign_block(block& b, const std::string privateKey) {
1812 crypto::hash tx_tree_hash = get_tx_tree_hash(b);
1813
1814 std::string signature = crypto::sign_message(std::string(reinterpret_cast<char const*>(tx_tree_hash.data), sizeof(tx_tree_hash.data)), privateKey);
1815 if(signature.empty() || signature.size() != 64) {
1816 LOG_ERROR("The daemon has failed to digitally sign a block and therefore it cannot be accepted by the network. Please check your validator-key configuration before resuming mining.");
1817 return;
1818 }
1819
1820 b.signature = std::vector<uint8_t>(signature.begin(), signature.end());
1821}
1822
1824 crypto::hash tx_tree_hash = get_tx_tree_hash(b);
1825 const std::vector<std::string> public_keys = m_validators->getApplicablePublicKeys(m_db->height(), true);
1826
1827 for(auto &key : public_keys) {
1828 if(crypto::verify_signature(std::string(reinterpret_cast<char const *>(tx_tree_hash.data), sizeof(tx_tree_hash.data)),
1829 key, std::string(b.signature.begin(), b.signature.end()))){
1830 b.signatory = std::vector<uint8_t>(key.begin(), key.end());
1831 return true;
1832 }
1833 }
1834 return false;
1835}
1836
1837//------------------------------------------------------------------
1838bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce)
1839{
1840 return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, ex_nonce);
1841}
1842//------------------------------------------------------------------
1843// for an alternate chain, get the timestamps from the main chain to complete
1844// the needed number of timestamps for the BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW.
1845bool Blockchain::complete_timestamps_vector(uint64_t start_top_height, std::vector<uint64_t>& timestamps) const
1846{
1847 LOG_PRINT_L3("Blockchain::" << __func__);
1848
1849 if(timestamps.size() >= BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW)
1850 return true;
1851
1852 CRITICAL_REGION_LOCAL(m_blockchain_lock);
1853 size_t need_elements = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW - timestamps.size();
1854 CHECK_AND_ASSERT_MES(start_top_height < m_db->height(), false, "internal error: passed start_height not < " << " m_db->height() -- " << start_top_height << " >= " << m_db->height());
1855 size_t stop_offset = start_top_height > need_elements ? start_top_height - need_elements : 0;
1856 timestamps.reserve(timestamps.size() + start_top_height - stop_offset);
1857 while (start_top_height != stop_offset)
1858 {
1859 timestamps.push_back(m_db->get_block_timestamp(start_top_height));
1860 --start_top_height;
1861 }
1862 return true;
1863}
1864//------------------------------------------------------------------
1865bool Blockchain::build_alt_chain(const crypto::hash &prev_id, std::list<blocks_ext_by_hash::const_iterator>& alt_chain, std::vector<uint64_t> &timestamps, block_verification_context& bvc) const
1866{
1867 //build alternative subchain, front -> mainchain, back -> alternative head
1868 blocks_ext_by_hash::const_iterator alt_it = m_alternative_chains.find(prev_id);
1869 timestamps.clear();
1870 while(alt_it != m_alternative_chains.end())
1871 {
1872 alt_chain.push_front(alt_it);
1873 timestamps.push_back(alt_it->second.bl.timestamp);
1874 alt_it = m_alternative_chains.find(alt_it->second.bl.prev_id);
1875 }
1876
1877 // if block to be added connects to known blocks that aren't part of the
1878 // main chain -- that is, if we're adding on to an alternate chain
1879 if(!alt_chain.empty())
1880 {
1881 // make sure alt chain doesn't somehow start past the end of the main chain
1882 CHECK_AND_ASSERT_MES(m_db->height() > alt_chain.front()->second.height, false, "main blockchain wrong height");
1883
1884 // make sure that the blockchain contains the block that should connect
1885 // this alternate chain with it.
1886 if (!m_db->block_exists(alt_chain.front()->second.bl.prev_id))
1887 {
1888 MERROR("alternate chain does not appear to connect to main chain...");
1889 return false;
1890 }
1891
1892 // make sure block connects correctly to the main chain
1893 auto h = m_db->get_block_hash_from_height(alt_chain.front()->second.height - 1);
1894 CHECK_AND_ASSERT_MES(h == alt_chain.front()->second.bl.prev_id, false, "alternative chain has wrong connection to main chain");
1895 complete_timestamps_vector(m_db->get_block_height(alt_chain.front()->second.bl.prev_id), timestamps);
1896 }
1897 // if block not associated with known alternate chain
1898 else
1899 {
1900 // if block parent is not part of main chain or an alternate chain,
1901 // we ignore it
1902 bool parent_in_main = m_db->block_exists(prev_id);
1903 CHECK_AND_ASSERT_MES(parent_in_main, false, "internal error: broken imperative condition: parent_in_main");
1904
1905 complete_timestamps_vector(m_db->get_block_height(prev_id), timestamps);
1906 }
1907
1908 return true;
1909}
1910//------------------------------------------------------------------
1911// If a block is to be added and its parent block is not the current
1912// main chain top block, then we need to see if we know about its parent block.
1913// If its parent block is part of a known forked chain, then we need to see
1914// if that chain is long enough to become the main chain and re-org accordingly
1915// if so. If not, we need to hang on to the block in case it becomes part of
1916// a long forked chain eventually.
1917bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc)
1918{
1919 LOG_PRINT_L3("Blockchain::" << __func__);
1920 CRITICAL_REGION_LOCAL(m_blockchain_lock);
1921 m_timestamps_and_difficulties_height = 0;
1922 uint64_t block_height = get_block_height(b);
1923 if(0 == block_height)
1924 {
1925 MERROR_VER("Block with id: " << epee::string_tools::pod_to_hex(id) << " (as alternative), but miner tx says height is 0.");
1926 bvc.m_verification_failed = true;
1927 return false;
1928 }
1929
1930 if(b.major_version >= 8) {
1931
1932 if(!m_fallback_to_pow) {
1933
1934 if(!m_validators->isEnabled()) {
1935 m_validators->enable();
1936 }
1937
1938 if(!m_validators->isValid()) {
1940 return false;
1941 }
1942
1943 if(!verify_block_signature(b)) {
1944 MERROR_VER("Block with id: " << id << std::endl << " has wrong digital signature");
1945 bvc.m_verification_failed = true;
1946 return false;
1947 }
1948 }
1949 }
1950
1951 // this basically says if the blockchain is smaller than the first
1952 // checkpoint then alternate blocks are allowed. Alternatively, if the
1953 // last checkpoint *before* the end of the current chain is also before
1954 // the block to be added, then this is fine.
1955 if (!m_checkpoints.is_alternative_block_allowed(get_current_blockchain_height(), block_height))
1956 {
1957 MERROR_VER("Block with id: " << id << std::endl << " can't be accepted for alternative chain, block height: " << block_height << std::endl << " blockchain height: " << get_current_blockchain_height());
1958 bvc.m_verification_failed = true;
1959 return false;
1960 }
1961
1962 // this is a cheap test
1963 if (!m_hardfork->check_for_height(b, block_height))
1964 {
1965 LOG_PRINT_L1("Block with id: " << id << std::endl << "has old version for height " << block_height);
1966 bvc.m_verification_failed = true;
1967 return false;
1968 }
1969
1970 //block is not related with head of main chain
1971 //first of all - look in alternative chains container
1972 auto it_prev = m_alternative_chains.find(b.prev_id);
1973 bool parent_in_main = m_db->block_exists(b.prev_id);
1974 if(it_prev != m_alternative_chains.end() || parent_in_main)
1975 {
1976 //we have new block in alternative chain
1977 std::list<blocks_ext_by_hash::const_iterator> alt_chain;
1978 std::vector<uint64_t> timestamps;
1979 if (!build_alt_chain(b.prev_id, alt_chain, timestamps, bvc))
1980 return false;
1981
1982 // FIXME: consider moving away from block_extended_info at some point
1983 block_extended_info bei = boost::value_initialized<block_extended_info>();
1984 bei.bl = b;
1985 const uint64_t prev_height = alt_chain.size() ? it_prev->second.height : m_db->get_block_height(b.prev_id);
1986 bei.height = prev_height + 1;
1987 uint64_t block_reward = get_outs_etn_amount(b.miner_tx);
1988 bei.already_generated_coins = block_reward + (alt_chain.size() ? it_prev->second.already_generated_coins : m_db->get_block_already_generated_coins(prev_height));
1989
1990 if(!m_fallback_to_pow && b.major_version >= 8)
1991 {
1992 std::vector<uint8_t> prev_signatory = alt_chain.size() ? it_prev->second.bl.signatory : m_db->get_block(b.prev_id).signatory;
1993 CHECK_AND_ASSERT_MES(b.signatory != prev_signatory, false, "a single validator can't mine blocks in sequence");
1994 }
1995
1996 // verify that the block's timestamp is within the acceptable range
1997 // (not earlier than the median of the last X blocks)
1998 if(!check_block_timestamp(timestamps, b))
1999 {
2000 MERROR_VER("Block with id: " << id << std::endl << " for alternative chain, has invalid timestamp: " << b.timestamp);
2001 bvc.m_verification_failed = true;
2002 return false;
2003 }
2004
2005 bool is_a_checkpoint;
2006 if(!m_checkpoints.check_block(bei.height, id, is_a_checkpoint))
2007 {
2008 LOG_ERROR("CHECKPOINT VALIDATION FAILED");
2009 bvc.m_verification_failed = true;
2010 return false;
2011 }
2012
2013 // Check the block's hash against the difficulty target for its alt chain
2014 difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei);
2015 CHECK_AND_ASSERT_MES(current_diff, false, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!");
2016 crypto::hash proof_of_work = null_hash;
2017 get_block_longhash(bei.bl, proof_of_work, bei.height);
2018 if(!check_hash(proof_of_work, current_diff))
2019 {
2020 MERROR_VER("Block with id: " << id << std::endl << " for alternative chain, does not have enough proof of work: " << proof_of_work << std::endl << " expected difficulty: " << current_diff);
2021 bvc.m_verification_failed = true;
2022 return false;
2023 }
2024
2025 if(!prevalidate_miner_transaction(b, bei.height))
2026 {
2027 MERROR_VER("Block with id: " << epee::string_tools::pod_to_hex(id) << " (as alternative) has incorrect miner transaction.");
2028 bvc.m_verification_failed = true;
2029 return false;
2030 }
2031
2032 // FIXME:
2033 // this brings up an interesting point: consider allowing to get block
2034 // difficulty both by height OR by hash, not just height.
2035 difficulty_type main_chain_cumulative_difficulty = m_db->get_block_cumulative_difficulty(m_db->height() - 1);
2036 if (alt_chain.size())
2037 {
2038 bei.cumulative_difficulty = it_prev->second.cumulative_difficulty;
2039 }
2040 else
2041 {
2042 // passed-in block's previous block's cumulative difficulty, found on the main chain
2043 bei.cumulative_difficulty = m_db->get_block_cumulative_difficulty(m_db->get_block_height(b.prev_id));
2044 }
2045 bei.cumulative_difficulty += current_diff;
2046
2047 // add block to alternate blocks storage,
2048 // as well as the current "alt chain" container
2049 auto i_res = m_alternative_chains.insert(blocks_ext_by_hash::value_type(id, bei));
2050 CHECK_AND_ASSERT_MES(i_res.second, false, "insertion of new alternative block returned as it already exist");
2051 alt_chain.push_back(i_res.first);
2052
2053 // FIXME: is it even possible for a checkpoint to show up not on the main chain?
2054 if(is_a_checkpoint)
2055 {
2056 //do reorganize!
2057 MGINFO_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_db->height() - 1 << ", checkpoint is found in alternative chain on height " << bei.height);
2058
2059 bool r = switch_to_alternative_blockchain(alt_chain, true);
2060
2061 if(r) bvc.m_added_to_main_chain = true;
2062 else bvc.m_verification_failed = true;
2063
2064 return r;
2065 }
2066 else if(main_chain_cumulative_difficulty < bei.cumulative_difficulty) //check if difficulty bigger then in main chain
2067 {
2068 //do reorganize!
2069 MGINFO_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_db->height() - 1 << " with cum_difficulty " << m_db->get_block_cumulative_difficulty(m_db->height() - 1) << std::endl << " alternative blockchain size: " << alt_chain.size() << " with cum_difficulty " << bei.cumulative_difficulty);
2070
2071 bool r = switch_to_alternative_blockchain(alt_chain, false);
2072 if (r)
2073 bvc.m_added_to_main_chain = true;
2074 else
2075 bvc.m_verification_failed = true;
2076 return r;
2077 }
2078 else
2079 {
2080 MGINFO_BLUE("----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT " << bei.height << std::endl << "id:\t" << id << std::endl << "PoW:\t" << proof_of_work << std::endl << "difficulty:\t" << current_diff);
2081 return true;
2082 }
2083 }
2084 else
2085 {
2086 //block orphaned
2087 bvc.m_marked_as_orphaned = true;
2088 MERROR_VER("Block recognized as orphaned and rejected, id = " << id << ", height " << block_height
2089 << ", parent in alt " << (it_prev != m_alternative_chains.end()) << ", parent in main " << parent_in_main
2090 << " (parent " << b.prev_id << ", current top " << get_tail_id() << ", chain height " << get_current_blockchain_height() << ")");
2091 }
2092
2093 return true;
2094}
2095//------------------------------------------------------------------
2096bool Blockchain::get_blocks(uint64_t start_offset, size_t count, std::vector<std::pair<cryptonote::blobdata,block>>& blocks, std::vector<cryptonote::blobdata>& txs) const
2097{
2098 LOG_PRINT_L3("Blockchain::" << __func__);
2099 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2100 if(start_offset >= m_db->height())
2101 return false;
2102
2103 if (!get_blocks(start_offset, count, blocks))
2104 {
2105 return false;
2106 }
2107
2108 for(const auto& blk : blocks)
2109 {
2110 std::vector<crypto::hash> missed_ids;
2111 get_transactions_blobs(blk.second.tx_hashes, txs, missed_ids);
2112 CHECK_AND_ASSERT_MES(!missed_ids.size(), false, "has missed transactions in own block in main blockchain");
2113 }
2114
2115 return true;
2116}
2117//------------------------------------------------------------------
2118bool Blockchain::get_blocks(uint64_t start_offset, size_t count, std::vector<std::pair<cryptonote::blobdata,block>>& blocks) const
2119{
2120 LOG_PRINT_L3("Blockchain::" << __func__);
2121 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2122 const uint64_t height = m_db->height();
2123 if(start_offset >= height)
2124 return false;
2125
2126 blocks.reserve(blocks.size() + height - start_offset);
2127 for(size_t i = start_offset; i < start_offset + count && i < height;i++)
2128 {
2129 blocks.push_back(std::make_pair(m_db->get_block_blob_from_height(i), block()));
2130 if (!parse_and_validate_block_from_blob(blocks.back().first, blocks.back().second))
2131 {
2132 LOG_ERROR("Invalid block");
2133 return false;
2134 }
2135 }
2136 return true;
2137}
2138//------------------------------------------------------------------
2139//TODO: This function *looks* like it won't need to be rewritten
2140// to use BlockchainDB, as it calls other functions that were,
2141// but it warrants some looking into later.
2142//
2143//FIXME: This function appears to want to return false if any transactions
2144// that belong with blocks are missing, but not if blocks themselves
2145// are missing.
2147{
2148 LOG_PRINT_L3("Blockchain::" << __func__);
2149 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2150 db_rtxn_guard rtxn_guard (m_db);
2151 rsp.current_blockchain_height = get_current_blockchain_height();
2152 std::vector<std::pair<cryptonote::blobdata,block>> blocks;
2153 get_blocks(arg.blocks, blocks, rsp.missed_ids);
2154
2155 for (auto& bl: blocks)
2156 {
2157 std::vector<crypto::hash> missed_tx_ids;
2158
2159 rsp.blocks.push_back(block_complete_entry());
2160 block_complete_entry& e = rsp.blocks.back();
2161
2162 // FIXME: s/rsp.missed_ids/missed_tx_id/ ? Seems like rsp.missed_ids
2163 // is for missed blocks, not missed transactions as well.
2164 get_transactions_blobs(bl.second.tx_hashes, e.txs, missed_tx_ids);
2165
2166 if (missed_tx_ids.size() != 0)
2167 {
2168 // do not display an error if the peer asked for an unpruned block which we are not meant to have
2170 {
2171 LOG_ERROR("Error retrieving blocks, missed " << missed_tx_ids.size()
2172 << " transactions for block with hash: " << get_block_hash(bl.second)
2173 << std::endl
2174 );
2175 }
2176
2177 // append missed transaction hashes to response missed_ids field,
2178 // as done below if any standalone transactions were requested
2179 // and missed.
2180 rsp.missed_ids.insert(rsp.missed_ids.end(), missed_tx_ids.begin(), missed_tx_ids.end());
2181 return false;
2182 }
2183
2184 //pack block
2185 e.block = std::move(bl.first);
2186 }
2187 //get and pack other transactions, if needed
2188 get_transactions_blobs(arg.txs, rsp.txs, rsp.missed_ids);
2189
2190 return true;
2191}
2192//------------------------------------------------------------------
2193bool Blockchain::get_alternative_blocks(std::vector<block>& blocks) const
2194{
2195 LOG_PRINT_L3("Blockchain::" << __func__);
2196 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2197
2198 blocks.reserve(m_alternative_chains.size());
2199 for (const auto& alt_bl: m_alternative_chains)
2200 {
2201 blocks.push_back(alt_bl.second.bl);
2202 }
2203 return true;
2204}
2205//------------------------------------------------------------------
2207{
2208 LOG_PRINT_L3("Blockchain::" << __func__);
2209 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2210 return m_alternative_chains.size();
2211}
2212//------------------------------------------------------------------
2213// This function adds the output specified by <amount, i> to the result_outs container
2214// unlocked and other such checks should be done by here.
2216{
2217 uint64_t num_outs = m_db->get_num_outputs(amount);
2218 // ensure we don't include outputs that aren't yet eligible to be used
2219 // outpouts are sorted by height
2220 const uint64_t blockchain_height = m_db->height();
2221 while (num_outs > 0)
2222 {
2223 const tx_out_index toi = m_db->get_output_tx_and_index(amount, num_outs - 1);
2224 const uint64_t height = m_db->get_tx_block_height(toi.first);
2226 break;
2227 --num_outs;
2228 }
2229
2230 return num_outs;
2231}
2232
2234{
2235 output_data_t data = m_db->get_output_key(amount, global_index);
2236 return data.pubkey;
2237}
2238
2239//------------------------------------------------------------------
2241{
2242 LOG_PRINT_L3("Blockchain::" << __func__);
2243 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2244
2245 res.outs.clear();
2246 res.outs.reserve(req.outputs.size());
2247
2248 std::vector<cryptonote::output_data_t> data;
2249 try
2250 {
2251 std::vector<uint64_t> amounts, offsets;
2252 amounts.reserve(req.outputs.size());
2253 offsets.reserve(req.outputs.size());
2254 for (const auto &i: req.outputs)
2255 {
2256 amounts.push_back(i.amount);
2257 offsets.push_back(i.index);
2258 }
2259 m_db->get_output_key(epee::span<const uint64_t>(amounts.data(), amounts.size()), offsets, data);
2260 if (data.size() != req.outputs.size())
2261 {
2262 MERROR("Unexpected output data size: expected " << req.outputs.size() << ", got " << data.size());
2263 return false;
2264 }
2265 for (const auto &t: data)
2266 res.outs.push_back({t.pubkey, t.commitment, is_tx_spendtime_unlocked(t.unlock_time), t.height, crypto::null_hash});
2267
2268 if (req.get_txid)
2269 {
2270 for (size_t i = 0; i < req.outputs.size(); ++i)
2271 {
2272 tx_out_index toi = m_db->get_output_tx_and_index(req.outputs[i].amount, req.outputs[i].index);
2273 res.outs[i].txid = toi.first;
2274 }
2275 }
2276 }
2277 catch (const std::exception &e)
2278 {
2279 return false;
2280 }
2281 return true;
2282}
2283//------------------------------------------------------------------
2284void Blockchain::get_output_key_mask_unlocked(const uint64_t& amount, const uint64_t& index, crypto::public_key& key, rct::key& mask, bool& unlocked) const
2285{
2286 const auto o_data = m_db->get_output_key(amount, index);
2287 key = o_data.pubkey;
2288 mask = o_data.commitment;
2289 tx_out_index toi = m_db->get_output_tx_and_index(amount, index);
2290 unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first));
2291}
2292//------------------------------------------------------------------
2293bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const
2294{
2295 // rct outputs don't exist before v4
2296 if (amount == 0)
2297 {
2298 switch (m_nettype)
2299 {
2300 case STAGENET: start_height = stagenet_hard_forks[3].height; break;
2301 case TESTNET: start_height = testnet_hard_forks[3].height; break;
2302 case MAINNET: start_height = mainnet_hard_forks[3].height; break;
2303 case FAKECHAIN: start_height = 0; break;
2304 default: return false;
2305 }
2306 }
2307 else
2308 start_height = 0;
2309 base = 0;
2310
2311 if (to_height > 0 && to_height < from_height)
2312 return false;
2313
2314 const uint64_t real_start_height = start_height;
2315 if (from_height > start_height)
2316 start_height = from_height;
2317
2318 distribution.clear();
2319 uint64_t db_height = m_db->height();
2320 if (db_height == 0)
2321 return false;
2322 if (start_height >= db_height || to_height >= db_height)
2323 return false;
2324 if (amount == 0)
2325 {
2326 std::vector<uint64_t> heights;
2327 heights.reserve(to_height + 1 - start_height);
2328 uint64_t real_start_height = start_height > 0 ? start_height-1 : start_height;
2329 for (uint64_t h = real_start_height; h <= to_height; ++h)
2330 heights.push_back(h);
2331 distribution = m_db->get_block_cumulative_rct_outputs(heights);
2332 if (start_height > 0)
2333 {
2334 base = distribution[0];
2335 distribution.erase(distribution.begin());
2336 }
2337 return true;
2338 }
2339 else
2340 {
2341 return m_db->get_output_distribution(amount, start_height, to_height, distribution, base);
2342 }
2343}
2344//------------------------------------------------------------------
2345// This function takes a list of block hashes from another node
2346// on the network to find where the split point is between us and them.
2347// This is used to see what to send another node that needs to sync.
2348bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, uint64_t& starter_offset) const
2349{
2350 LOG_PRINT_L3("Blockchain::" << __func__);
2351 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2352
2353 // make sure the request includes at least the genesis block, otherwise
2354 // how can we expect to sync from the client that the block list came from?
2355 if(qblock_ids.empty())
2356 {
2357 MCERROR("net.p2p", "Client sent wrong NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << qblock_ids.size() << ", dropping connection");
2358 return false;
2359 }
2360
2361 db_rtxn_guard rtxn_guard(m_db);
2362 // make sure that the last block in the request's block list matches
2363 // the genesis block
2364 auto gen_hash = m_db->get_block_hash_from_height(0);
2365 if(qblock_ids.back() != gen_hash)
2366 {
2367 LOG_PRINT_L0("Genesis Block Mismatch");
2368 MCERROR("net.p2p", "Client sent wrong NOTIFY_REQUEST_CHAIN: genesis block mismatch: " << std::endl << "id: " << qblock_ids.back() << ", " << std::endl << "expected: " << gen_hash << "," << std::endl << " dropping connection");
2369 return false;
2370 }
2371
2372 // Find the first block the foreign chain has that we also have.
2373 // Assume qblock_ids is in reverse-chronological order.
2374 auto bl_it = qblock_ids.begin();
2375 uint64_t split_height = 0;
2376 for(; bl_it != qblock_ids.end(); bl_it++)
2377 {
2378 try
2379 {
2380 if (m_db->block_exists(*bl_it, &split_height))
2381 break;
2382 }
2383 catch (const std::exception& e)
2384 {
2385 MWARNING("Non-critical error trying to find block by hash in BlockchainDB, hash: " << *bl_it);
2386 return false;
2387 }
2388 }
2389
2390 // this should be impossible, as we checked that we share the genesis block,
2391 // but just in case...
2392 if(bl_it == qblock_ids.end())
2393 {
2394 MERROR("Internal error handling connection, can't find split point");
2395 return false;
2396 }
2397
2398 //we start to put block ids INCLUDING last known id, just to make other side be sure
2399 starter_offset = split_height;
2400 return true;
2401}
2402//------------------------------------------------------------------
2404{
2405 LOG_PRINT_L3("Blockchain::" << __func__);
2406 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
2407 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
2408 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
2409 // lock if it is otherwise needed.
2410 try
2411 {
2412 return m_db->get_block_difficulty(i);
2413 }
2414 catch (const BLOCK_DNE& e)
2415 {
2416 MERROR("Attempted to get block difficulty for height above blockchain height");
2417 }
2418 return 0;
2419}
2420//------------------------------------------------------------------
2421template<typename T> void reserve_container(std::vector<T> &v, size_t N) { v.reserve(N); }
2422template<typename T> void reserve_container(std::list<T> &v, size_t N) { }
2423//------------------------------------------------------------------
2424//TODO: return type should be void, throw on exception
2425// alternatively, return true only if no blocks missed
2426template<class t_ids_container, class t_blocks_container, class t_missed_container>
2427bool Blockchain::get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const
2428{
2429 LOG_PRINT_L3("Blockchain::" << __func__);
2430 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2431
2432 reserve_container(blocks, block_ids.size());
2433 for (const auto& block_hash : block_ids)
2434 {
2435 try
2436 {
2437 uint64_t height = 0;
2438 if (m_db->block_exists(block_hash, &height))
2439 {
2440 blocks.push_back(std::make_pair(m_db->get_block_blob_from_height(height), block()));
2441 if (!parse_and_validate_block_from_blob(blocks.back().first, blocks.back().second))
2442 {
2443 LOG_ERROR("Invalid block: " << block_hash);
2444 blocks.pop_back();
2445 missed_bs.push_back(block_hash);
2446 }
2447 }
2448 else
2449 missed_bs.push_back(block_hash);
2450 }
2451 catch (const std::exception& e)
2452 {
2453 return false;
2454 }
2455 }
2456 return true;
2457}
2458//------------------------------------------------------------------
2459//TODO: return type should be void, throw on exception
2460// alternatively, return true only if no transactions missed
2461template<class t_ids_container, class t_tx_container, class t_missed_container>
2462bool Blockchain::get_transactions_blobs(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs, bool pruned) const
2463{
2464 LOG_PRINT_L3("Blockchain::" << __func__);
2465 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2466
2467 reserve_container(txs, txs_ids.size());
2468 for (const auto& tx_hash : txs_ids)
2469 {
2470 try
2471 {
2473 if (pruned && m_db->get_pruned_tx_blob(tx_hash, tx))
2474 txs.push_back(std::move(tx));
2475 else if (!pruned && m_db->get_tx_blob(tx_hash, tx))
2476 txs.push_back(std::move(tx));
2477 else
2478 missed_txs.push_back(tx_hash);
2479 }
2480 catch (const std::exception& e)
2481 {
2482 return false;
2483 }
2484 }
2485 return true;
2486}
2487//------------------------------------------------------------------
2489{
2490 size_t version;
2491 const char* begin = static_cast<const char*>(bd.data());
2492 const char* end = begin + bd.size();
2493 int read = tools::read_varint(begin, end, version);
2494 if (read <= 0)
2495 throw std::runtime_error("Internal error getting transaction version");
2496 return version;
2497}
2498//------------------------------------------------------------------
2499template<class t_ids_container, class t_tx_container, class t_missed_container>
2500bool Blockchain::get_split_transactions_blobs(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const
2501{
2502 LOG_PRINT_L3("Blockchain::" << __func__);
2503 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2504
2505 reserve_container(txs, txs_ids.size());
2506 for (const auto& tx_hash : txs_ids)
2507 {
2508 try
2509 {
2511 if (m_db->get_pruned_tx_blob(tx_hash, tx))
2512 {
2513 txs.push_back(std::make_tuple(tx_hash, std::move(tx), crypto::null_hash, cryptonote::blobdata()));
2514 if (!is_v1_tx(std::get<1>(txs.back())) && !m_db->get_prunable_tx_hash(tx_hash, std::get<2>(txs.back())))
2515 {
2516 MERROR("Prunable data hash not found for " << tx_hash);
2517 return false;
2518 }
2519 if (!m_db->get_prunable_tx_blob(tx_hash, std::get<3>(txs.back())))
2520 std::get<3>(txs.back()).clear();
2521 }
2522 else
2523 missed_txs.push_back(tx_hash);
2524 }
2525 catch (const std::exception& e)
2526 {
2527 return false;
2528 }
2529 }
2530 return true;
2531}
2532//------------------------------------------------------------------
2533template<class t_ids_container, class t_tx_container, class t_missed_container>
2534bool Blockchain::get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const
2535{
2536 LOG_PRINT_L3("Blockchain::" << __func__);
2537 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2538
2539 reserve_container(txs, txs_ids.size());
2540 for (const auto& tx_hash : txs_ids)
2541 {
2542 try
2543 {
2545 if (m_db->get_tx_blob(tx_hash, tx))
2546 {
2547 txs.push_back(transaction());
2548 if (!parse_and_validate_tx_from_blob(tx, txs.back()))
2549 {
2550 LOG_ERROR("Invalid transaction");
2551 return false;
2552 }
2553 }
2554 else
2555 missed_txs.push_back(tx_hash);
2556 }
2557 catch (const std::exception& e)
2558 {
2559 return false;
2560 }
2561 }
2562 return true;
2563}
2564//------------------------------------------------------------------
2565// Find the split point between us and foreign blockchain and return
2566// (by reference) the most recent common block hash along with up to
2567// BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes.
2568bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::vector<crypto::hash>& hashes, uint64_t& start_height, uint64_t& current_height, bool clip_pruned) const
2569{
2570 LOG_PRINT_L3("Blockchain::" << __func__);
2571 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2572
2573 // if we can't find the split point, return false
2574 if(!find_blockchain_supplement(qblock_ids, start_height))
2575 {
2576 return false;
2577 }
2578
2579 db_rtxn_guard rtxn_guard(m_db);
2580 current_height = get_current_blockchain_height();
2581 uint64_t stop_height = current_height;
2582 if (clip_pruned)
2583 {
2584 const uint32_t pruning_seed = get_blockchain_pruning_seed();
2585 start_height = tools::get_next_unpruned_block_height(start_height, current_height, pruning_seed);
2586 stop_height = tools::get_next_pruned_block_height(start_height, current_height, pruning_seed);
2587 }
2588 size_t count = 0;
2589 hashes.reserve(std::min((size_t)(stop_height - start_height), (size_t)BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT));
2590 for(size_t i = start_height; i < stop_height && count < BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT; i++, count++)
2591 {
2592 hashes.push_back(m_db->get_block_hash_from_height(i));
2593 }
2594
2595 return true;
2596}
2597
2598bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const
2599{
2600 LOG_PRINT_L3("Blockchain::" << __func__);
2601 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2602
2603 bool result = find_blockchain_supplement(qblock_ids, resp.m_block_ids, resp.start_height, resp.total_height, true);
2604 if (result)
2605 {
2606 cryptonote::difficulty_type wide_cumulative_difficulty = m_db->get_block_cumulative_difficulty(resp.total_height - 1);
2607 resp.cumulative_difficulty = (wide_cumulative_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
2608 resp.cumulative_difficulty_top64 = ((wide_cumulative_difficulty >> 64) & 0xffffffffffffffff).convert_to<uint64_t>();
2609 }
2610
2611 return result;
2612}
2613//------------------------------------------------------------------
2614//FIXME: change argument to std::vector, low priority
2615// find split point between ours and foreign blockchain (or start at
2616// blockchain height <req_start_block>), and return up to max_count FULL
2617// blocks by reference.
2618bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, bool get_miner_tx_hash, size_t max_count) const
2619{
2620 LOG_PRINT_L3("Blockchain::" << __func__);
2621 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2622
2623 // if a specific start height has been requested
2624 if(req_start_block > 0)
2625 {
2626 // if requested height is higher than our chain, return false -- we can't help
2627 if (req_start_block >= m_db->height())
2628 {
2629 return false;
2630 }
2631 start_height = req_start_block;
2632 }
2633 else
2634 {
2635 if(!find_blockchain_supplement(qblock_ids, start_height))
2636 {
2637 return false;
2638 }
2639 }
2640
2641 db_rtxn_guard rtxn_guard(m_db);
2642 total_height = get_current_blockchain_height();
2643 size_t count = 0, size = 0;
2644 blocks.reserve(std::min(std::min(max_count, (size_t)10000), (size_t)(total_height - start_height)));
2645 for(uint64_t i = start_height; i < total_height && count < max_count && (size < FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE || count < 3); i++, count++)
2646 {
2647 blocks.resize(blocks.size()+1);
2648 blocks.back().first.first = m_db->get_block_blob_from_height(i);
2649 block b;
2650 CHECK_AND_ASSERT_MES(parse_and_validate_block_from_blob(blocks.back().first.first, b), false, "internal error, invalid block");
2651 blocks.back().first.second = get_miner_tx_hash ? cryptonote::get_transaction_hash(b.miner_tx) : crypto::null_hash;
2652 std::vector<crypto::hash> mis;
2653 std::vector<cryptonote::blobdata> txs;
2654 get_transactions_blobs(b.tx_hashes, txs, mis, pruned);
2655 CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, transaction from block not found");
2656 size += blocks.back().first.first.size();
2657 for (const auto &t: txs)
2658 size += t.size();
2659
2660 CHECK_AND_ASSERT_MES(txs.size() == b.tx_hashes.size(), false, "mismatched sizes of b.tx_hashes and txs");
2661 blocks.back().second.reserve(txs.size());
2662 for (size_t i = 0; i < txs.size(); ++i)
2663 {
2664 blocks.back().second.push_back(std::make_pair(b.tx_hashes[i], std::move(txs[i])));
2665 }
2666 }
2667 return true;
2668}
2669//------------------------------------------------------------------
2670bool Blockchain::add_block_as_invalid(const block& bl, const crypto::hash& h)
2671{
2672 LOG_PRINT_L3("Blockchain::" << __func__);
2673 block_extended_info bei = AUTO_VAL_INIT(bei);
2674 bei.bl = bl;
2675 return add_block_as_invalid(bei, h);
2676}
2677//------------------------------------------------------------------
2678bool Blockchain::add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h)
2679{
2680 LOG_PRINT_L3("Blockchain::" << __func__);
2681 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2682 auto i_res = m_invalid_blocks.insert(std::map<crypto::hash, block_extended_info>::value_type(h, bei));
2683 CHECK_AND_ASSERT_MES(i_res.second, false, "at insertion invalid by tx returned status existed");
2684 MINFO("BLOCK ADDED AS INVALID: " << h << std::endl << ", prev_id=" << bei.bl.prev_id << ", m_invalid_blocks count=" << m_invalid_blocks.size());
2685 return true;
2686}
2687//------------------------------------------------------------------
2689{
2690 LOG_PRINT_L3("Blockchain::" << __func__);
2691 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2692
2693 if(m_db->block_exists(id))
2694 {
2695 LOG_PRINT_L2("block " << id << " found in main chain");
2696 return true;
2697 }
2698
2699 if(m_alternative_chains.count(id))
2700 {
2701 LOG_PRINT_L2("block " << id << " found in m_alternative_chains");
2702 return true;
2703 }
2704
2705 if(m_invalid_blocks.count(id))
2706 {
2707 LOG_PRINT_L2("block " << id << " found in m_invalid_blocks");
2708 return true;
2709 }
2710
2711 return false;
2712}
2713//------------------------------------------------------------------
2714bool Blockchain::handle_block_to_main_chain(const block& bl, block_verification_context& bvc)
2715{
2716 LOG_PRINT_L3("Blockchain::" << __func__);
2718 return handle_block_to_main_chain(bl, id, bvc);
2719}
2720//------------------------------------------------------------------
2722{
2723 LOG_PRINT_L3("Blockchain::" << __func__);
2724 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
2725 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
2726 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
2727 // lock if it is otherwise needed.
2728 return m_db->get_tx_count();
2729}
2730//------------------------------------------------------------------
2731// This function checks each input in the transaction <tx> to make sure it
2732// has not been used already, and adds its key to the container <keys_this_block>.
2733//
2734// This container should be managed by the code that validates blocks so we don't
2735// have to store the used keys in a given block in the permanent storage only to
2736// remove them later if the block fails validation.
2737bool Blockchain::check_for_double_spend(const transaction& tx, key_images_container& keys_this_block) const
2738{
2739 LOG_PRINT_L3("Blockchain::" << __func__);
2740 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2741 struct add_transaction_input_visitor: public boost::static_visitor<bool>
2742 {
2743 key_images_container& m_spent_keys;
2744 BlockchainDB* m_db;
2745 add_transaction_input_visitor(key_images_container& spent_keys, BlockchainDB* db) :
2746 m_spent_keys(spent_keys), m_db(db)
2747 {
2748 }
2749 bool operator()(const txin_to_key& in) const
2750 {
2751 const crypto::key_image& ki = in.k_image;
2752
2753 // attempt to insert the newly-spent key into the container of
2754 // keys spent this block. If this fails, the key was spent already
2755 // in this block, return false to flag that a double spend was detected.
2756 //
2757 // if the insert into the block-wide spent keys container succeeds,
2758 // check the blockchain-wide spent keys container and make sure the
2759 // key wasn't used in another block already.
2760 auto r = m_spent_keys.insert(ki);
2761 if(!r.second || m_db->has_key_image(ki))
2762 {
2763 //double spend detected
2764 return false;
2765 }
2766
2767 // if no double-spend detected, return true
2768 return true;
2769 }
2770
2771 bool operator()(const txin_gen& tx) const
2772 {
2773 return true;
2774 }
2775 bool operator()(const txin_to_script& tx) const
2776 {
2777 return false;
2778 }
2779 bool operator()(const txin_to_scripthash& tx) const
2780 {
2781 return false;
2782 }
2783 bool operator()(const txin_to_key_public& tx) const
2784 {
2785 return false;
2786 }
2787 };
2788
2789 for (const txin_v& in : tx.vin)
2790 {
2791 if(!boost::apply_visitor(add_transaction_input_visitor(keys_this_block, m_db), in))
2792 {
2793 LOG_ERROR("Double spend detected!");
2794 return false;
2795 }
2796 }
2797
2798 return true;
2799}
2800//------------------------------------------------------------------
2801bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const
2802{
2803 LOG_PRINT_L3("Blockchain::" << __func__);
2804 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2805 uint64_t tx_index;
2806 if (!m_db->tx_exists(tx_id, tx_index))
2807 {
2808 MERROR_VER("get_tx_outputs_gindexs failed to find transaction with id = " << tx_id);
2809 return false;
2810 }
2811
2812 //no output indexes for tx.version >= 2 (public tx)
2813 if (m_db->get_tx(tx_id).version >= 2)
2814 return true;
2815
2816 indexs = m_db->get_tx_amount_output_indices(tx_index, n_txes);
2817 CHECK_AND_ASSERT_MES(n_txes == indexs.size(), false, "Wrong indexs size");
2818
2819 return true;
2820}
2821//------------------------------------------------------------------
2822bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const
2823{
2824 LOG_PRINT_L3("Blockchain::" << __func__);
2825 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2826 uint64_t tx_index;
2827 if (!m_db->tx_exists(tx_id, tx_index))
2828 {
2829 MERROR_VER("get_tx_outputs_gindexs failed to find transaction with id = " << tx_id);
2830 return false;
2831 }
2832
2833 //no output indexes for tx.version >= 2 (public tx)
2834 if (m_db->get_tx(tx_id).version >= 2)
2835 return true;
2836
2837 std::vector<std::vector<uint64_t>> indices = m_db->get_tx_amount_output_indices(tx_index, 1);
2838 CHECK_AND_ASSERT_MES(indices.size() == 1, false, "Wrong indices size");
2839 indexs = indices.front();
2840 return true;
2841}
2842//------------------------------------------------------------------
2844{
2845#if defined(PER_BLOCK_CHECKPOINT)
2846 // check if we're doing per-block checkpointing
2847 if (m_db->height() < m_blocks_hash_check.size())
2848 {
2850 m_blocks_txs_check.push_back(get_transaction_hash(tx));
2852 if(m_show_time_stats)
2853 {
2854 size_t ring_size = !tx.vin.empty() && tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
2855 MINFO("HASH: " << "-" << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << 0 << " chcktx: " << a);
2856 }
2857 }
2858#endif
2859}
2860//------------------------------------------------------------------
2861//FIXME: it seems this function is meant to be merely a wrapper around
2862// another function of the same name, this one adding one bit of
2863// functionality. Should probably move anything more than that
2864// (getting the hash of the block at height max_used_block_id)
2865// to the other function to keep everything in one place.
2866// This function overloads its sister function with
2867// an extra value (hash of highest block that holds an output used as input)
2868// as a return-by-reference.
2869bool Blockchain::check_tx_inputs(transaction& tx, uint64_t& max_used_block_height, crypto::hash& max_used_block_id, tx_verification_context &tvc, bool kept_by_block)
2870{
2871 LOG_PRINT_L3("Blockchain::" << __func__);
2872 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2873
2874#if defined(PER_BLOCK_CHECKPOINT)
2875 // check if we're doing per-block checkpointing
2876 if (m_db->height() < m_blocks_hash_check.size() && kept_by_block)
2877 {
2878 max_used_block_id = null_hash;
2879 max_used_block_height = 0;
2880 return true;
2881 }
2882#endif
2883
2885 bool res = check_tx_inputs(tx, tvc, &max_used_block_height);
2887 if(m_show_time_stats)
2888 {
2889 size_t ring_size = !tx.vin.empty() && tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
2890 MINFO("HASH: " << get_transaction_hash(tx) << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << max_used_block_height << " ms: " << a + m_fake_scan_time << " B: " << get_object_blobsize(tx) << " W: " << get_transaction_weight(tx));
2891 }
2892 if (!res)
2893 return false;
2894
2895 // If kept_by_block we might witness max_used_block_height > chain height because the tx inputs are referencing outputs at a higher height on the orphaned chain.
2896 CHECK_AND_ASSERT_MES(max_used_block_height < m_db->height(), false, "internal error: max used block index=" << max_used_block_height << " is not less then blockchain size = " << m_db->height());
2897 max_used_block_id = m_db->get_block_hash_from_height(max_used_block_height);
2898 return true;
2899}
2900//------------------------------------------------------------------
2902{
2903 LOG_PRINT_L3("Blockchain::" << __func__);
2904 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2905
2906 const uint8_t hf_version = m_hardfork->get_current_version();
2907
2908 // from hard fork 2, we forbid dust and compound outputs
2909 if (hf_version >= HF_VERSION_FORBID_DUST_OUTPUTS) {
2910 for (auto &o: tx.vout) {
2911 if (!is_valid_decomposed_amount(o.amount)) {
2912 tvc.m_invalid_output = true;
2913 return false;
2914 }
2915 }
2916 }
2917
2918 // from v4, forbid invalid pubkeys
2919 if (hf_version >= HF_VERSION_FORBID_INVALID_PUBKEYS) {
2920 for (const auto &o: tx.vout) {
2921 if (hf_version < HF_VERSION_PUBLIC_TX) {
2922 if (o.target.type() == typeid(txout_to_key)) {
2923 const txout_to_key &out_to_key = boost::get<txout_to_key>(o.target);
2924 if (!crypto::check_key(out_to_key.key)) {
2925 tvc.m_invalid_output = true;
2926 return false;
2927 }
2928 }
2929 }
2930 else {
2931 //do a sanity check on output type before checking destination
2932 if (o.target.type() != typeid(txout_to_key_public)) {
2933 return false;
2934 }
2935 const txout_to_key_public &out_to_key_public = boost::get<txout_to_key_public>(o.target);
2936 if (!crypto::check_key(out_to_key_public.address.m_spend_public_key) ||
2937 !crypto::check_key(out_to_key_public.address.m_view_public_key)) {
2938 tvc.m_invalid_output = true;
2939 return false;
2940 }
2941
2943 uint64_t integrated_address_prefix = get_config(m_nettype).CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
2944 uint64_t subaddress_prefix = get_config(m_nettype).CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX;
2945
2946 std::vector<uint64_t> supported_prefixes{address_prefix, integrated_address_prefix, subaddress_prefix};
2947
2948 if(std::find(supported_prefixes.begin(), supported_prefixes.end(), out_to_key_public.m_address_prefix) == supported_prefixes.end()) {
2949 tvc.m_invalid_output = true;
2950 return false;
2951 }
2952 }
2953 }
2954 }
2955 return true;
2956}
2957//------------------------------------------------------------------
2959{
2960 LOG_PRINT_L3("Blockchain::" << __func__);
2961
2962 for (const txin_v& in: tx.vin)
2963 {
2964 if(in.type() == typeid(txin_to_key))
2965 {
2966 const auto &in_to_key = boost::get<txin_to_key>(in);
2967 if(have_tx_keyimg_as_spent(in_to_key.k_image))
2968 return true;
2969 }
2970 }
2971
2972 return false;
2973}
2974//------------------------------------------------------------------
2976{
2977 LOG_PRINT_L3("Blockchain::" << __func__);
2978
2979 for (const txin_v& in: tx.vin)
2980 {
2981 if(in.type() == typeid(txin_to_key_public))
2982 {
2983 const auto &in_to_key = boost::get<txin_to_key_public>(in);
2984 if(!m_db->check_chainstate_utxo(in_to_key.tx_hash, in_to_key.relative_offset))
2985 return true;
2986 }
2987 }
2988 return false;
2989}
2990
2991//------------------------------------------------------------------
2992//check for a single output
2994{
2995 LOG_PRINT_L3("Blockchain::" << __func__);
2996
2997 if(!m_db->check_chainstate_utxo(public_output.tx_hash, public_output.relative_offset))
2998 return true;
2999
3000 return false;
3001}
3002bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys)
3003{
3004 return true;
3005}
3006//------------------------------------------------------------------
3007// This function validates transaction inputs and their keys.
3008// FIXME: consider moving functionality specific to one input into
3009// check_tx_input() rather than here, and use this function simply
3010// to iterate the inputs as necessary (splitting the task
3011// using threads, etc.)
3012bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, uint64_t* pmax_used_block_height)
3013{
3015 LOG_PRINT_L3("Blockchain::" << __func__);
3016 size_t sig_index = 0;
3017 if(pmax_used_block_height)
3018 *pmax_used_block_height = 0;
3019
3020 crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
3021
3022 const uint8_t hf_version = m_hardfork->get_current_version();
3023
3024 // min/max tx version based on HF
3025 const size_t max_tx_version = hf_version < HF_VERSION_PUBLIC_TX ? 1 : 3;
3026 if (tx.version > max_tx_version)
3027 {
3028 MERROR_VER("transaction version " << (unsigned)tx.version << " is higher than max accepted version " << max_tx_version);
3029 tvc.m_verification_failed = true;
3030 return false;
3031 }
3032
3033 const size_t min_tx_version = hf_version >= HF_VERSION_PUBLIC_TX ? 2 : 1;
3034 if (tx.version < min_tx_version)
3035 {
3036 MERROR_VER("transaction version " << (unsigned)tx.version << " is lower than min accepted version " << min_tx_version);
3037 tvc.m_verification_failed = true;
3038 return false;
3039 }
3040
3041 if (tx.version >= 3) //only public inputs allowed
3042 {
3043
3044 //check for duplicate inputs
3045 std::unordered_set<std::string> ins;
3046 for(const auto& in: tx.vin)
3047 {
3048 CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key_public, tokey_in, false);
3049 if(!ins.insert(std::string(tokey_in.tx_hash.data, 32) + std::to_string(tokey_in.relative_offset)).second)
3050 {
3051 tvc.m_invalid_input = true;
3052 tvc.m_verification_failed = true;
3053 return false;
3054 }
3055 }
3056
3057 if(tx.vin.size() != tx.signatures.size())
3058 {
3059 tvc.m_invalid_input = true;
3060 tvc.m_verification_failed = true;
3061 return false;
3062 }
3063
3064 for (size_t i = 0; i < tx.vin.size(); ++i)
3065 {
3066 CHECK_AND_ASSERT_MES(tx.vin[i].type() == typeid(txin_to_key_public), false, "wrong type id in tx input at Blockchain::check_tx_inputs");
3067
3068 const txin_to_key_public& in_to_key = boost::get<txin_to_key_public>(tx.vin[i]);
3069
3070 if (in_to_key.amount <= 0)
3071 {
3072 tvc.m_invalid_input = true;
3073 tvc.m_verification_failed = true;
3074 return false;
3075 }
3076
3077 transaction parent_tx;
3078 if (!m_db->get_tx(in_to_key.tx_hash, parent_tx))
3079 {
3080 tvc.m_invalid_input = true;
3081 tvc.m_verification_failed = true;
3082 return false;
3083 }
3084
3085 CHECK_AND_ASSERT_MES(parent_tx.vout.size() > in_to_key.relative_offset, false, "wrong relative_offset in tx input at Blockchain::check_tx_inputs");
3086 CHECK_AND_ASSERT_MES(parent_tx.vout.at(in_to_key.relative_offset).amount == in_to_key.amount, false, "wrong amount in tx input at Blockchain::check_tx_inputs");
3087
3088 if (!m_db->check_chainstate_utxo(in_to_key.tx_hash, in_to_key.relative_offset))
3089 {
3090 tvc.m_utxo_nonexistent = true;
3091 tvc.m_verification_failed = true;
3092 return false;
3093 }
3094
3095 if(!is_tx_spendtime_unlocked(m_db->get_utxo_unlock_time(in_to_key.tx_hash, in_to_key.relative_offset))){
3096 tvc.m_verification_failed = true;
3097 return false;
3098 }
3099
3100 // check signature
3101 const txout_to_key_public& out_to_key = boost::get<txout_to_key_public>(parent_tx.vout[in_to_key.relative_offset].target);
3102 bool valid = crypto::verify_input_signature(tx_prefix_hash, i, out_to_key.address.m_view_public_key, out_to_key.address.m_spend_public_key, tx.signatures[i][0]);
3103 if (!valid)
3104 {
3105 tvc.m_verification_failed = true;
3106 return false;
3107 }
3108 }
3109
3110 return true; //returns check_tx_inputs. no extra work required for public tx
3111 }
3112
3113 // from hard fork 2, we require mixin at least 2 unless one output cannot mix with 2 others
3114 // if one output cannot mix with 2 others, we accept at most 1 output that can mix
3115 if (hf_version >= 6)
3116 {
3117 size_t n_unmixable = 0, n_mixable = 0;
3118 size_t mixin = std::numeric_limits<size_t>::max();
3119 const size_t min_mixin = hf_version >= HF_VERSION_MIN_MIXIN_10 ? 10 : hf_version >= HF_VERSION_MIN_MIXIN_6 ? 6 : hf_version >= HF_VERSION_MIN_MIXIN_4 ? 4 : 0;
3120 for (const auto& txin : tx.vin)
3121 {
3122 // non txin_to_key inputs will be rejected below
3123 if (txin.type() == typeid(txin_to_key))
3124 {
3125 const txin_to_key& in_to_key = boost::get<txin_to_key>(txin);
3126
3127 // Ensure Ring Size = 1 from V6
3128 if (hf_version >= HF_VERSION_ENFORCE_0_DECOY_TXS && hf_version < HF_VERSION_ENFORCE_0_DECOY_TXS_END &&
3129 in_to_key.key_offsets.size() != DEFAULT_RINGSIZE)
3130 {
3131 MERROR_VER("Tx " << get_transaction_hash(tx) << " must have a ringsize of (" << (DEFAULT_RINGSIZE)
3132 << "), and more than one mixable input with unmixable inputs");
3133 tvc.m_low_mixin = true;
3134 return false;
3135 }
3136 // End
3137
3138 if (in_to_key.amount == 0)
3139 {
3140 // always consider rct inputs mixable. Even if there's not enough rct
3141 // inputs on the chain to mix with, this is going to be the case for
3142 // just a few blocks right after the fork at most
3143 ++n_mixable;
3144 }
3145 else
3146 {
3147 uint64_t n_outputs = m_db->get_num_outputs(in_to_key.amount);
3148 MDEBUG("output size " << print_etn(in_to_key.amount) << ": " << n_outputs << " available");
3149 // n_outputs includes the output we're considering
3150 if (n_outputs <= min_mixin)
3151 ++n_unmixable;
3152 else
3153 ++n_mixable;
3154 }
3155 if (in_to_key.key_offsets.size() - 1 < mixin)
3156 mixin = in_to_key.key_offsets.size() - 1;
3157 }
3158 }
3159
3160 if (((hf_version == HF_VERSION_MIN_MIXIN_10 || hf_version == HF_VERSION_MIN_MIXIN_10+1) && mixin != 10) || (hf_version >= HF_VERSION_MIN_MIXIN_10+2 && mixin > 10))
3161 {
3162 MERROR_VER("Tx " << get_transaction_hash(tx) << " has invalid ring size (" << (mixin + 1) << "), it should be 11");
3163 tvc.m_low_mixin = true;
3164 return false;
3165 }
3166
3167 if (mixin < min_mixin)
3168 {
3169 if (n_unmixable == 0)
3170 {
3171 MERROR_VER("Tx " << get_transaction_hash(tx) << " has too low ring size (" << (mixin + 1) << "), and no unmixable inputs");
3172 tvc.m_low_mixin = true;
3173 return false;
3174 }
3175 if (n_mixable > 1)
3176 {
3177 MERROR_VER("Tx " << get_transaction_hash(tx) << " has too low ring size (" << (mixin + 1) << "), and more than one mixable input with unmixable inputs");
3178 tvc.m_low_mixin = true;
3179 return false;
3180 }
3181 }
3182 }
3183
3184 // from v7, sorted ins
3185 if (hf_version >= HF_VERSION_ORDERED_TX_INPUTS) {
3186 const crypto::key_image *last_key_image = NULL;
3187 for (size_t n = 0; n < tx.vin.size(); ++n)
3188 {
3189 const txin_v &txin = tx.vin[n];
3190 if (txin.type() == typeid(txin_to_key))
3191 {
3192 const txin_to_key& in_to_key = boost::get<txin_to_key>(txin);
3193 if (last_key_image && memcmp(&in_to_key.k_image, last_key_image, sizeof(*last_key_image)) >= 0)
3194 {
3195 MERROR_VER("transaction has unsorted inputs");
3196 tvc.m_verification_failed = true;
3197 return false;
3198 }
3199 last_key_image = &in_to_key.k_image;
3200 }
3201 }
3202 }
3203 auto it = m_check_txin_table.find(tx_prefix_hash);
3204 if(it == m_check_txin_table.end())
3205 {
3206 m_check_txin_table.emplace(tx_prefix_hash, std::unordered_map<crypto::key_image, bool>());
3207 it = m_check_txin_table.find(tx_prefix_hash);
3208 assert(it != m_check_txin_table.end());
3209 }
3210
3211 std::vector<std::vector<rct::ctkey>> pubkeys(tx.vin.size());
3212 std::vector < uint64_t > results;
3213 results.resize(tx.vin.size(), 0);
3214
3215 tools::threadpool& tpool = tools::threadpool::getInstance();
3216 tools::threadpool::waiter waiter;
3217 const auto waiter_guard = epee::misc_utils::create_scope_leave_handler([&]() { waiter.wait(&tpool); });
3218 int threads = tpool.get_max_concurrency();
3219
3220 for (const auto& txin : tx.vin)
3221 {
3222 // make sure output being spent is of type txin_to_key, rather than
3223 // e.g. txin_gen, which is only used for miner transactions
3224 CHECK_AND_ASSERT_MES(txin.type() == typeid(txin_to_key), false, "wrong type id in tx input at Blockchain::check_tx_inputs");
3225 const txin_to_key& in_to_key = boost::get<txin_to_key>(txin);
3226
3227 // make sure tx output has key offset(s) (is signed to be used)
3228 CHECK_AND_ASSERT_MES(in_to_key.key_offsets.size(), false, "empty in_to_key.key_offsets in transaction with id " << get_transaction_hash(tx));
3229
3230 if(have_tx_keyimg_as_spent(in_to_key.k_image))
3231 {
3232 MERROR_VER("Key image already spent in blockchain: " << epee::string_tools::pod_to_hex(in_to_key.k_image));
3233 tvc.m_double_spend = true;
3234 return false;
3235 }
3236
3237 // basically, make sure number of inputs == number of signatures
3238 CHECK_AND_ASSERT_MES(sig_index < tx.signatures.size(), false, "wrong transaction: not signature entry for input with index= " << sig_index);
3239
3240#if defined(CACHE_VIN_RESULTS)
3241 auto itk = it->second.find(in_to_key.k_image);
3242 if(itk != it->second.end())
3243 {
3244 if(!itk->second)
3245 {
3246 MERROR_VER("Failed ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index);
3247 return false;
3248 }
3249
3250 // txin has been verified already, skip
3251 sig_index++;
3252 continue;
3253 }
3254#endif
3255
3256 // make sure that output being spent matches up correctly with the
3257 // signature spending it.
3258 if (!check_tx_input(tx.version, in_to_key, tx_prefix_hash, tx.signatures[sig_index], tx.rct_signatures, pubkeys[sig_index], pmax_used_block_height))
3259 {
3260 it->second[in_to_key.k_image] = false;
3261 MERROR_VER("Failed to check ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index);
3262 if (pmax_used_block_height) // a default value of NULL is used when called from Blockchain::handle_block_to_main_chain()
3263 {
3264 MERROR_VER(" *pmax_used_block_height: " << *pmax_used_block_height);
3265 }
3266
3267 return false;
3268 }
3269
3270 if (threads > 1)
3271 {
3272 // ND: Speedup
3273 // 1. Thread ring signature verification if possible.
3274 tpool.submit(&waiter, boost::bind(&Blockchain::check_ring_signature, this, std::cref(tx_prefix_hash), std::cref(in_to_key.k_image), std::cref(pubkeys[sig_index]), std::cref(tx.signatures[sig_index]), std::ref(results[sig_index])), true);
3275 }
3276 else
3277 {
3278 check_ring_signature(tx_prefix_hash, in_to_key.k_image, pubkeys[sig_index], tx.signatures[sig_index], results[sig_index]);
3279 if (!results[sig_index])
3280 {
3281 it->second[in_to_key.k_image] = false;
3282 MERROR_VER("Failed to check ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index);
3283
3284 if (pmax_used_block_height) // a default value of NULL is used when called from Blockchain::handle_block_to_main_chain()
3285 {
3286 MERROR_VER("*pmax_used_block_height: " << *pmax_used_block_height);
3287 }
3288
3289 return false;
3290 }
3291 it->second[in_to_key.k_image] = true;
3292 }
3293
3294 sig_index++;
3295 }
3296
3297 if (threads > 1)
3298 {
3299 waiter.wait(&tpool);
3300 // save results to table, passed or otherwise
3301 bool failed = false;
3302 for (size_t i = 0; i < tx.vin.size(); i++)
3303 {
3304 const txin_to_key& in_to_key = boost::get<txin_to_key>(tx.vin[i]);
3305 it->second[in_to_key.k_image] = results[i];
3306 if(!failed && !results[i])
3307 failed = true;
3308 }
3309
3310 if (failed)
3311 {
3312 MERROR_VER("Failed to check ring signatures!");
3313 return false;
3314 }
3315 }
3316 return true;
3317}
3318
3319//------------------------------------------------------------------
3320void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const crypto::key_image &key_image, const std::vector<rct::ctkey> &pubkeys, const std::vector<crypto::signature>& sig, uint64_t &result)
3321{
3322 std::vector<const crypto::public_key *> p_output_keys;
3323 p_output_keys.reserve(pubkeys.size());
3324 for (auto &key : pubkeys)
3325 {
3326 // rct::key and crypto::public_key have the same structure, avoid object ctor/memcpy
3327 p_output_keys.push_back(&(const crypto::public_key&)key.dest);
3328 }
3329
3330 result = crypto::check_ring_signature(tx_prefix_hash, key_image, p_output_keys, sig.data()) ? 1 : 0;
3331}
3332
3333//------------------------------------------------------------------
3335{
3336 static uint64_t mask = 0;
3337 if (mask == 0)
3338 {
3339 mask = 1;
3341 mask *= 10;
3342 }
3343 return mask;
3344}
3345
3346//------------------------------------------------------------------
3347uint64_t Blockchain::get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight, uint8_t version)
3348{
3349 const uint64_t min_block_weight = get_min_block_weight(version);
3350 if (median_block_weight < min_block_weight)
3351 median_block_weight = min_block_weight;
3352 uint64_t hi, lo;
3353
3355 {
3356 lo = mul128(block_reward, DYNAMIC_FEE_REFERENCE_TRANSACTION_WEIGHT, &hi);
3357 div128_32(hi, lo, min_block_weight, &hi, &lo);
3358 div128_32(hi, lo, median_block_weight, &hi, &lo);
3359 assert(hi == 0);
3360 lo /= 5;
3361 return lo;
3362 }
3363
3365
3366 uint64_t unscaled_fee_base = (fee_base * min_block_weight / median_block_weight);
3367 lo = mul128(unscaled_fee_base, block_reward, &hi);
3368 static_assert(DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD % 1000000 == 0, "DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD must be divisible by 1000000");
3369 static_assert(DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD / 1000000 <= std::numeric_limits<uint32_t>::max(), "DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD is too large");
3370
3371 // divide in two steps, since the divisor must be 32 bits, but DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD isn't
3372 div128_32(hi, lo, DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD / 1000000, &hi, &lo);
3373 div128_32(hi, lo, 1000000, &hi, &lo);
3374 assert(hi == 0);
3375
3376 // quantize fee up to 8 decimals
3378 uint64_t qlo = (lo + mask - 1) / mask * mask;
3379 MDEBUG("lo " << print_etn(lo) << ", qlo " << print_etn(qlo) << ", mask " << mask);
3380
3381 return qlo;
3382}
3383
3384//------------------------------------------------------------------
3385bool Blockchain::check_fee(size_t tx_weight, uint64_t fee) const
3386{
3388 const uint64_t blockchain_height = m_db->height();
3389
3390 uint64_t median = 0;
3391 uint64_t already_generated_coins = 0;
3392 uint64_t base_reward = 0;
3394 {
3395 median = m_current_block_cumul_weight_limit / 2;
3396 const uint64_t blockchain_height = m_db->height();
3397 already_generated_coins = blockchain_height ? m_db->get_block_already_generated_coins(blockchain_height - 1) : 0;
3398 if (!get_block_reward(median, 1, already_generated_coins, base_reward, version, blockchain_height, get_nettype()))
3399 return false;
3400 }
3401
3402 uint64_t needed_fee;
3404 {
3405 const bool use_long_term_median_in_fee = version >= HF_VERSION_LONG_TERM_BLOCK_WEIGHT;
3406 uint64_t fee_per_byte = get_dynamic_base_fee(base_reward, use_long_term_median_in_fee ? m_long_term_effective_median_block_weight : median, version);
3407 MDEBUG("Using " << print_etn(fee_per_byte) << "/byte fee");
3408 needed_fee = tx_weight * fee_per_byte;
3409 // quantize fee up to 8 decimals
3410 const uint64_t mask = get_fee_quantization_mask();
3411 needed_fee = (needed_fee + mask - 1) / mask * mask;
3412 }
3413 else
3414 {
3415 uint64_t fee_per_kb;
3417 {
3418 if (version >= 11) {
3419 fee_per_kb = FEE_PER_KB_V11;
3420 } else if (version < 11 && version >= 6) {
3421 fee_per_kb = FEE_PER_KB_V6;
3422 } else {
3423 fee_per_kb = FEE_PER_KB;
3424 }
3425 }
3426 else
3427 {
3428 fee_per_kb = get_dynamic_base_fee(base_reward, median, version);
3429 }
3430 MDEBUG("Using " << print_etn(fee_per_kb) << "/kB fee");
3431
3432 needed_fee = tx_weight / 1024;
3433 needed_fee += (tx_weight % 1024) ? 1 : 0;
3434 needed_fee *= fee_per_kb;
3435 }
3436
3437 if (fee < needed_fee - needed_fee / 50) // keep a little 2% buffer on acceptance - no integer overflow
3438 {
3439 MERROR_VER("transaction fee is not enough: " << print_etn(fee) << ", minimum fee: " << print_etn(needed_fee));
3440 return false;
3441 }
3442 return true;
3443}
3444
3445//------------------------------------------------------------------
3447{
3449 const uint64_t db_height = m_db->height();
3450
3452 if (version >= 11) {
3453 return FEE_PER_KB_V11;
3454 } else if (version < 11 && version >= 6) {
3455 return FEE_PER_KB_V6;
3456 } else {
3457 return FEE_PER_KB;
3458 }
3459 }
3460
3461 if (grace_blocks >= CRYPTONOTE_REWARD_BLOCKS_WINDOW)
3462 grace_blocks = CRYPTONOTE_REWARD_BLOCKS_WINDOW - 1;
3463
3464 const uint64_t min_block_weight = get_min_block_weight(version);
3465 std::vector<uint64_t> weights;
3466 get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW - grace_blocks);
3467 weights.reserve(grace_blocks);
3468 for (size_t i = 0; i < grace_blocks; ++i)
3469 weights.push_back(min_block_weight);
3470
3471 uint64_t median = epee::misc_utils::median(weights);
3472 if(median <= min_block_weight)
3473 median = min_block_weight;
3474
3475 uint64_t already_generated_coins = db_height ? m_db->get_block_already_generated_coins(db_height - 1) : 0;
3476 uint64_t base_reward;
3477 if (!get_block_reward(median, 1, already_generated_coins, base_reward, version, get_current_blockchain_height(), get_nettype()))
3478 {
3479 MERROR("Failed to determine block reward, using placeholder " << print_etn(BLOCK_REWARD_OVERESTIMATE) << " as a high bound");
3480 base_reward = BLOCK_REWARD_OVERESTIMATE;
3481 }
3482
3483 const bool use_long_term_median_in_fee = version >= HF_VERSION_LONG_TERM_BLOCK_WEIGHT;
3484 uint64_t fee = get_dynamic_base_fee(base_reward, use_long_term_median_in_fee ? m_long_term_effective_median_block_weight : median, version);
3485 const bool per_byte = version < HF_VERSION_PER_BYTE_FEE;
3486 MDEBUG("Estimating " << grace_blocks << "-block fee at " << print_etn(fee) << "/" << (per_byte ? "byte" : "kB"));
3487 return fee;
3488}
3489
3490//------------------------------------------------------------------
3491// This function checks to see if a tx is unlocked. unlock_time is either
3492// a block index or a unix time.
3493bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time) const
3494{
3495 LOG_PRINT_L3("Blockchain::" << __func__);
3496 if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER)
3497 {
3498 // ND: Instead of calling get_current_blockchain_height(), call m_db->height()
3499 // directly as get_current_blockchain_height() locks the recursive mutex.
3500 if(m_db->height()-1 + CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS >= unlock_time)
3501 return true;
3502 else
3503 return false;
3504 }
3505 else
3506 {
3507 //interpret as time
3508 uint64_t current_time = static_cast<uint64_t>(time(NULL));
3509 if(current_time + CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS >= unlock_time)
3510 return true;
3511 else
3512 return false;
3513 }
3514 return false;
3515}
3516//------------------------------------------------------------------
3517// This function locates all outputs associated with a given input (mixins)
3518// and validates that they exist and are usable. It also checks the ring
3519// signature for each input.
3520bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height)
3521{
3522 LOG_PRINT_L3("Blockchain::" << __func__);
3523
3524 // ND:
3525 // 1. Disable locking and make method private.
3526 //CRITICAL_REGION_LOCAL(m_blockchain_lock);
3527
3528 struct outputs_visitor
3529 {
3530 std::vector<rct::ctkey >& m_output_keys;
3531 const Blockchain& m_bch;
3532 outputs_visitor(std::vector<rct::ctkey>& output_keys, const Blockchain& bch) :
3533 m_output_keys(output_keys), m_bch(bch)
3534 {
3535 }
3536 bool handle_output(uint64_t unlock_time, const crypto::public_key &pubkey, const rct::key &commitment)
3537 {
3538 //check tx unlock time
3539 if (!m_bch.is_tx_spendtime_unlocked(unlock_time))
3540 {
3541 MERROR_VER("One of outputs for one of inputs has wrong tx.unlock_time = " << unlock_time);
3542 return false;
3543 }
3544
3545 // The original code includes a check for the output corresponding to this input
3546 // to be a txout_to_key. This is removed, as the database does not store this info,
3547 // but only txout_to_key outputs are stored in the DB in the first place, done in
3548 // Blockchain*::add_output
3549
3550 m_output_keys.push_back(rct::ctkey({rct::pk2rct(pubkey), commitment}));
3551 return true;
3552 }
3553 };
3554
3555 output_keys.clear();
3556
3557 // collect output keys
3558 outputs_visitor vi(output_keys, *this);
3559 if (!scan_outputkeys_for_indexes(tx_version, txin, vi, tx_prefix_hash, pmax_related_block_height))
3560 {
3561 MERROR_VER("Failed to get output keys for tx with amount = " << print_etn(txin.amount) << " and count indexes " << txin.key_offsets.size());
3562 return false;
3563 }
3564
3565 if(txin.key_offsets.size() != output_keys.size())
3566 {
3567 MERROR_VER("Output keys for tx with amount = " << txin.amount << " and count indexes " << txin.key_offsets.size() << " returned wrong keys count " << output_keys.size());
3568 return false;
3569 }
3570 if (tx_version == 1) {
3571 CHECK_AND_ASSERT_MES(sig.size() == output_keys.size(), false, "internal error: tx signatures count=" << sig.size() << " mismatch with outputs keys count for inputs=" << output_keys.size());
3572 }
3573 // rct_signatures will be expanded after this
3574 return true;
3575}
3576//------------------------------------------------------------------
3577//TODO: Is this intended to do something else? Need to look into the todo there.
3578uint64_t Blockchain::get_adjusted_time() const
3579{
3580 LOG_PRINT_L3("Blockchain::" << __func__);
3581 //TODO: add collecting median time
3582 return time(NULL);
3583}
3584//------------------------------------------------------------------
3585//TODO: revisit, has changed a bit on upstream
3586bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const block& b, uint64_t& median_ts) const
3587{
3588 LOG_PRINT_L3("Blockchain::" << __func__);
3589 median_ts = epee::misc_utils::median(timestamps);
3590
3591 if(b.timestamp < median_ts)
3592 {
3593 MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", less than median of last " << BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW << " blocks, " << median_ts);
3594 return false;
3595 }
3596
3597 return true;
3598}
3599//------------------------------------------------------------------
3600// This function grabs the timestamps from the most recent <n> blocks,
3601// where n = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW. If there are not those many
3602// blocks in the blockchain, the timestap is assumed to be valid. If there
3603// are, this function returns:
3604// true if the block's timestamp is not less than the timestamp of the
3605// median of the selected blocks
3606// false otherwise
3607bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) const
3608{
3609 LOG_PRINT_L3("Blockchain::" << __func__);
3610 if(b.timestamp > get_adjusted_time() + CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT)
3611 {
3612 MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + 2 hours");
3613 return false;
3614 }
3615
3616 const auto h = m_db->height();
3617
3618 // if not enough blocks, no proper median yet, return true
3620 {
3621 return true;
3622 }
3623
3624 std::vector<uint64_t> timestamps;
3625
3626 // need most recent 60 blocks, get index of first of those
3627 size_t offset = h - BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW;
3628 timestamps.reserve(h - offset);
3629 for(;offset < h; ++offset)
3630 {
3631 timestamps.push_back(m_db->get_block_timestamp(offset));
3632 }
3633
3634 return check_block_timestamp(timestamps, b, median_ts);
3635}
3636//------------------------------------------------------------------
3637void Blockchain::return_tx_to_pool(std::vector<std::pair<transaction, blobdata>> &txs)
3638{
3640 for (auto& tx : txs)
3641 {
3642 cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
3643 // We assume that if they were in a block, the transactions are already
3644 // known to the network as a whole. However, if we had mined that block,
3645 // that might not be always true. Unlikely though, and always relaying
3646 // these again might cause a spike of traffic as many nodes re-relay
3647 // all the transactions in a popped block when a reorg happens.
3648 const size_t weight = get_transaction_weight(tx.first, tx.second.size());
3649 const crypto::hash tx_hash = get_transaction_hash(tx.first);
3650 if (!m_tx_pool.add_tx(tx.first, tx_hash, tx.second, weight, tvc, true, true, false, version))
3651 {
3652 MERROR("Failed to return taken transaction with hash: " << get_transaction_hash(tx.first) << " to tx_pool");
3653 }
3654 }
3655}
3656//------------------------------------------------------------------
3657bool Blockchain::flush_txes_from_pool(const std::vector<crypto::hash> &txids)
3658{
3659 CRITICAL_REGION_LOCAL(m_tx_pool);
3660
3661 bool res = true;
3662 for (const auto &txid: txids)
3663 {
3665 cryptonote::blobdata txblob;
3666 size_t tx_weight;
3667 uint64_t fee;
3668 bool relayed, do_not_relay, double_spend_seen, nonexistent_utxo_seen;
3669 MINFO("Removing txid " << txid << " from the pool");
3670 if(m_tx_pool.have_tx(txid) && !m_tx_pool.take_tx(txid, tx, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen, nonexistent_utxo_seen))
3671 {
3672 MERROR("Failed to remove txid " << txid << " from the pool");
3673 res = false;
3674 }
3675 }
3676 return res;
3677}
3678//------------------------------------------------------------------
3679// Needs to validate the block and acquire each transaction from the
3680// transaction mem_pool, then pass the block and transactions to
3681// m_db->add_block()
3682bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc)
3683{
3684 LOG_PRINT_L3("Blockchain::" << __func__);
3685
3686 TIME_MEASURE_START(block_processing_time);
3687 CRITICAL_REGION_LOCAL(m_blockchain_lock);
3689
3690 static bool seen_future_version = false;
3691
3692 db_rtxn_guard rtxn_guard(m_db);
3693 uint64_t blockchain_height;
3694 const crypto::hash top_hash = get_tail_id(blockchain_height);
3695 ++blockchain_height; // block height to chain height
3696 if(bl.prev_id != top_hash)
3697 {
3698 MERROR_VER("Block with id: " << id << std::endl << "has wrong prev_id: " << bl.prev_id << std::endl << "expected: " << top_hash);
3699 bvc.m_verification_failed = true;
3700leave:
3701 return false;
3702 }
3703
3704 if(bl.major_version >= 8 && m_nettype != FAKECHAIN) {
3705
3706 if(!m_fallback_to_pow) {
3707
3708 if(!m_validators->isEnabled()) {
3709 m_validators->enable();
3710 }
3711
3712 if(!m_validators->isValid()) {
3714 goto leave;
3715 }
3716
3717 if(!verify_block_signature(bl) && !m_ignore_bsig) {
3718 MERROR_VER("Block with id: " << id << std::endl << " has wrong digital signature");
3719 bvc.m_verification_failed = true;
3720 goto leave;
3721 }
3722 if(bl.signatory == m_db->get_block(bl.prev_id).signatory && !m_ignore_bsig){
3723 MERROR_VER("Block with id: " << id << std::endl << " has the same signatory as the previous block, which is not allowed");
3724 bvc.m_verification_failed = true;
3725 bvc.m_sequential_block = true;
3726 goto leave;
3727 }
3728 }
3729 }
3730
3731 // warn users if they're running an old version
3732 if (!seen_future_version && bl.major_version > m_hardfork->get_ideal_version())
3733 {
3734 seen_future_version = true;
3735 const el::Level level = el::Level::Warning;
3736 MCLOG_RED(level, "global", "**********************************************************************");
3737 MCLOG_RED(level, "global", "A block was seen on the network with a version higher than the last");
3738 MCLOG_RED(level, "global", "known one. This may be an old version of the daemon, and a software");
3739 MCLOG_RED(level, "global", "update may be required to sync further. Try running: update check");
3740 MCLOG_RED(level, "global", "**********************************************************************");
3741 }
3742
3743 // this is a cheap test
3744 if (!m_hardfork->check(bl))
3745 {
3746 MERROR_VER("Block with id: " << id << std::endl << "has old version: " << (unsigned)bl.major_version << std::endl << "current: " << (unsigned)m_hardfork->get_current_version());
3747 bvc.m_verification_failed = true;
3748 goto leave;
3749 }
3750
3753
3754 // make sure block timestamp is not less than the median timestamp
3755 // of a set number of the most recent blocks.
3756 if(!check_block_timestamp(bl))
3757 {
3758 MERROR_VER("Block with id: " << id << std::endl << "has invalid timestamp: " << bl.timestamp);
3759 bvc.m_verification_failed = true;
3760 goto leave;
3761 }
3762
3764 //check proof of work
3765 TIME_MEASURE_START(target_calculating_time);
3766
3767 // get the target difficulty for the block.
3768 // the calculation can overflow, among other failure cases,
3769 // so we need to check the return type.
3770 // FIXME: get_difficulty_for_next_block can also assert, look into
3771 // changing this to throwing exceptions instead so we can clean up.
3773 CHECK_AND_ASSERT_MES(current_diffic, false, "!!!!!!!!! difficulty overhead !!!!!!!!!");
3774
3775 TIME_MEASURE_FINISH(target_calculating_time);
3776
3777 TIME_MEASURE_START(longhash_calculating_time);
3778
3779 crypto::hash proof_of_work = null_hash;
3780
3781 // Formerly the code below contained an if loop with the following condition
3782 // !m_checkpoints.is_in_checkpoint_zone(get_current_blockchain_height())
3783 // however, this caused the daemon to not bother checking PoW for blocks
3784 // before checkpoints, which is very dangerous behaviour. We moved the PoW
3785 // validation out of the next chunk of code to make sure that we correctly
3786 // check PoW now.
3787 // FIXME: height parameter is not used...should it be used or should it not
3788 // be a parameter?
3789 // validate proof_of_work versus difficulty target
3790 bool precomputed = false;
3791 bool fast_check = false;
3792#if defined(PER_BLOCK_CHECKPOINT)
3793 if (blockchain_height < m_blocks_hash_check.size())
3794 {
3795 auto hash = get_block_hash(bl);
3796 if (memcmp(&hash, &m_blocks_hash_check[m_db->height()], sizeof(hash)) != 0)
3797 {
3798 MERROR_VER("Block with id is INVALID: " << id);
3799 bvc.m_verification_failed = true;
3800 goto leave;
3801 }
3802
3803 fast_check = true;
3804 }
3805 else
3806#endif
3807 {
3808 auto it = m_blocks_longhash_table.find(id);
3809 if (it != m_blocks_longhash_table.end())
3810 {
3811 precomputed = true;
3812 proof_of_work = it->second;
3813 }
3814 else
3815 proof_of_work = get_block_longhash(bl, blockchain_height);
3816
3817 // validate proof_of_work versus difficulty target
3818 if(!check_hash(proof_of_work, current_diffic))
3819 {
3820 MERROR_VER("Block with id: " << id << std::endl << "does not have enough proof of work: " << proof_of_work << " at height " << blockchain_height << ", unexpected difficulty: " << current_diffic);
3821 bvc.m_verification_failed = true;
3822 goto leave;
3823 }
3824 }
3825
3826 // If we're at a checkpoint, ensure that our hardcoded checkpoint hash
3827 // is correct.
3828 if(m_checkpoints.is_in_checkpoint_zone(blockchain_height))
3829 {
3830 if(!m_checkpoints.check_block(blockchain_height, id))
3831 {
3832 LOG_ERROR("CHECKPOINT VALIDATION FAILED");
3833 bvc.m_verification_failed = true;
3834 goto leave;
3835 }
3836 }
3837
3838 TIME_MEASURE_FINISH(longhash_calculating_time);
3839 if (precomputed)
3840 longhash_calculating_time += m_fake_pow_calc_time;
3841
3843
3844 // sanity check basic miner tx properties;
3845 if(!prevalidate_miner_transaction(bl, blockchain_height))
3846 {
3847 MERROR_VER("Block with id: " << id << " failed to pass prevalidation");
3848 bvc.m_verification_failed = true;
3849 goto leave;
3850 }
3851
3852 size_t coinbase_weight = get_transaction_weight(bl.miner_tx);
3853 size_t cumulative_block_weight = coinbase_weight;
3854
3855 std::vector<std::pair<transaction, blobdata>> txs;
3856 key_images_container keys;
3857
3858 uint64_t fee_summary = 0;
3859 uint64_t t_checktx = 0;
3860 uint64_t t_exists = 0;
3861 uint64_t t_pool = 0;
3862 uint64_t t_dblspnd = 0;
3864
3865// XXX old code adds miner tx here
3866
3867 size_t tx_index = 0;
3868 // Iterate over the block's transaction hashes, grabbing each
3869 // from the tx_pool and validating them. Each is then added
3870 // to txs. Keys spent in each are added to <keys> by the double spend check.
3871 txs.reserve(bl.tx_hashes.size());
3872 for (const crypto::hash& tx_id : bl.tx_hashes)
3873 {
3874 transaction tx_tmp;
3875 blobdata txblob;
3876 size_t tx_weight = 0;
3877 uint64_t fee = 0;
3878 bool relayed = false, do_not_relay = false, double_spend_seen = false, nonexistent_utxo_seen = false;
3880
3881// XXX old code does not check whether tx exists
3882 if (m_db->tx_exists(tx_id))
3883 {
3884 MERROR("Block with id: " << id << " attempting to add transaction already in blockchain with id: " << tx_id);
3885 bvc.m_verification_failed = true;
3886 return_tx_to_pool(txs);
3887 goto leave;
3888 }
3889
3891 t_exists += aa;
3893
3894 // get transaction with hash <tx_id> from tx_pool
3895 if(!m_tx_pool.take_tx(tx_id, tx_tmp, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen, nonexistent_utxo_seen))
3896 {
3897 MERROR_VER("Block with id: " << id << " has at least one unknown transaction with id: " << tx_id);
3898 bvc.m_verification_failed = true;
3899 return_tx_to_pool(txs);
3900 goto leave;
3901 }
3902
3904 t_pool += bb;
3905 // add the transaction to the temp list of transactions, so we can either
3906 // store the list of transactions all at once or return the ones we've
3907 // taken from the tx_pool back to it if the block fails verification.
3908 txs.push_back(std::make_pair(std::move(tx_tmp), std::move(txblob)));
3909 transaction &tx = txs.back().first;
3911
3912 // FIXME: the storage should not be responsible for validation.
3913 // If it does any, it is merely a sanity check.
3914 // Validation is the purview of the Blockchain class
3915 // - TW
3916 //
3917 // ND: this is not needed, db->add_block() checks for duplicate k_images and fails accordingly.
3918 // if (!check_for_double_spend(tx, keys))
3919 // {
3920 // LOG_PRINT_L0("Double spend detected in transaction (id: " << tx_id);
3921 // bvc.m_verification_failed = true;
3922 // break;
3923 // }
3924
3926 t_dblspnd += dd;
3928
3929#if defined(PER_BLOCK_CHECKPOINT)
3930 if (!fast_check)
3931#endif
3932 {
3933 // validate that transaction inputs and the keys spending them are correct.
3934 tx_verification_context tvc;
3935 if(!check_tx_inputs(tx, tvc))
3936 {
3937 MERROR_VER("Block with id: " << id << " has at least one transaction (id: " << tx_id << ") with wrong inputs.");
3938
3939 //TODO: why is this done? make sure that keeping invalid blocks makes sense.
3940 add_block_as_invalid(bl, id);
3941 MERROR_VER("Block with id " << id << " added as invalid because of wrong inputs in transactions");
3942 MERROR_VER("tx_index " << tx_index << ", m_blocks_txs_check " << m_blocks_txs_check.size() << ":");
3943 for (const auto &h: m_blocks_txs_check) MERROR_VER(" " << h);
3944 bvc.m_verification_failed = true;
3945 return_tx_to_pool(txs);
3946 goto leave;
3947 }
3948 }
3949#if defined(PER_BLOCK_CHECKPOINT)
3950 else
3951 {
3952 // ND: if fast_check is enabled for blocks, there is no need to check
3953 // the transaction inputs, but do some sanity checks anyway.
3954 if (tx_index >= m_blocks_txs_check.size() || memcmp(&m_blocks_txs_check[tx_index++], &tx_id, sizeof(tx_id)) != 0)
3955 {
3956 MERROR_VER("Block with id: " << id << " has at least one transaction (id: " << tx_id << ") with wrong inputs.");
3957 //TODO: why is this done? make sure that keeping invalid blocks makes sense.
3958 add_block_as_invalid(bl, id);
3959 MERROR_VER("Block with id " << id << " added as invalid because of wrong inputs in transactions");
3960 bvc.m_verification_failed = true;
3961 return_tx_to_pool(txs);
3962 goto leave;
3963 }
3964 }
3965#endif
3967 t_checktx += cc;
3968 fee_summary += fee;
3969 cumulative_block_weight += tx_weight;
3970 }
3971
3972 m_blocks_txs_check.clear();
3973
3974 TIME_MEASURE_START(vmt);
3975 uint64_t base_reward = 0;
3976 uint64_t already_generated_coins = blockchain_height ? m_db->get_block_already_generated_coins(blockchain_height - 1) : 0;
3977 if(!validate_miner_transaction(bl, cumulative_block_weight, fee_summary, base_reward, already_generated_coins, bvc.m_partial_block_reward, m_hardfork->get_current_version()))
3978 {
3979 MERROR_VER("Block with id: " << id << " has incorrect miner transaction");
3980 bvc.m_verification_failed = true;
3981 return_tx_to_pool(txs);
3982 goto leave;
3983 }
3984
3986 size_t block_weight;
3987 difficulty_type cumulative_difficulty;
3988
3989 // populate various metadata about the block to be stored alongside it.
3990 block_weight = cumulative_block_weight;
3991 cumulative_difficulty = current_diffic;
3992 // In the "tail" state when the minimum subsidy (implemented in get_block_reward) is in effect, the number of
3993 // coins will eventually exceed ETN_SUPPLY and overflow a uint64. To prevent overflow, cap already_generated_coins
3994 // at ETN_SUPPLY. already_generated_coins is only used to compute the block subsidy and ETN_SUPPLY yields a
3995 // subsidy of 0 under the base formula and therefore the minimum subsidy >0 in the tail state.
3996 already_generated_coins = base_reward < (ETN_SUPPLY-already_generated_coins) ? already_generated_coins + base_reward : ETN_SUPPLY;
3997 if(blockchain_height)
3998 cumulative_difficulty += m_db->get_block_cumulative_difficulty(blockchain_height - 1);
3999
4000 TIME_MEASURE_FINISH(block_processing_time);
4001 if(precomputed)
4002 block_processing_time += m_fake_pow_calc_time;
4003
4004 rtxn_guard.stop();
4005 TIME_MEASURE_START(addblock);
4006 uint64_t new_height = 0;
4007 if (!bvc.m_verification_failed)
4008 {
4009 try
4010 {
4011 uint64_t long_term_block_weight = get_next_long_term_block_weight(block_weight);
4013 new_height = m_db->add_block(std::make_pair(std::move(bl), std::move(bd)), block_weight, long_term_block_weight, cumulative_difficulty, already_generated_coins, txs);
4014 }
4015 catch (const KEY_IMAGE_EXISTS& e)
4016 {
4017 LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what());
4018 m_batch_success = false;
4019 bvc.m_verification_failed = true;
4020 return_tx_to_pool(txs);
4021 return false;
4022 }
4023 catch (const std::exception& e)
4024 {
4025 //TODO: figure out the best way to deal with this failure
4026 LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what());
4027 m_batch_success = false;
4028 bvc.m_verification_failed = true;
4029 return_tx_to_pool(txs);
4030 return false;
4031 }
4032 }
4033 else
4034 {
4035 LOG_ERROR("Blocks that failed verification should not reach here");
4036 }
4037
4038 TIME_MEASURE_FINISH(addblock);
4039
4040 // do this after updating the hard fork state since the weight limit may change due to fork
4041 if (!update_next_cumulative_weight_limit())
4042 {
4043 MERROR("Failed to update next cumulative weight limit");
4044 pop_block_from_blockchain();
4045 return false;
4046 }
4047
4048 MINFO("+++++ BLOCK SUCCESSFULLY ADDED" << std::endl << "id:\t" << id << std::endl << "PoW:\t" << proof_of_work << std::endl << "HEIGHT " << new_height-1 << ", difficulty:\t" << current_diffic << std::endl << "block reward: " << print_etn(fee_summary + base_reward) << "(" << print_etn(base_reward) << " + " << print_etn(fee_summary) << "), coinbase_weight: " << coinbase_weight << ", cumulative weight: " << cumulative_block_weight << ", " << block_processing_time << "(" << target_calculating_time << "/" << longhash_calculating_time << ")ms");
4049 if(m_show_time_stats)
4050 {
4051 MINFO("Height: " << new_height << " coinbase weight: " << coinbase_weight << " cumm: "
4052 << cumulative_block_weight << " p/t: " << block_processing_time << " ("
4053 << target_calculating_time << "/" << longhash_calculating_time << "/"
4054 << t1 << "/" << t2 << "/" << t3 << "/" << t_exists << "/" << t_pool
4055 << "/" << t_checktx << "/" << t_dblspnd << "/" << vmt << "/" << addblock << ")ms");
4056 }
4057
4058 bvc.m_added_to_main_chain = true;
4059 ++m_sync_counter;
4060
4061 // appears to be a NOP *and* is called elsewhere. wat?
4062 m_tx_pool.on_blockchain_inc(new_height, id);
4063 get_difficulty_for_next_block(); // just to cache it
4064 invalidate_block_template_cache();
4065
4066 std::shared_ptr<tools::Notify> block_notify = m_block_notify;
4067 if (block_notify)
4068 block_notify->notify("%s", epee::string_tools::pod_to_hex(id).c_str(), NULL);
4069
4070 return true;
4071}
4072//------------------------------------------------------------------
4074{
4075 m_tx_pool.lock();
4077 CRITICAL_REGION_LOCAL(m_blockchain_lock);
4078
4079 return m_db->prune_blockchain(pruning_seed);
4080}
4081//------------------------------------------------------------------
4083{
4084 m_tx_pool.lock();
4086 CRITICAL_REGION_LOCAL(m_blockchain_lock);
4087
4088 return m_db->update_pruning();
4089}
4090//------------------------------------------------------------------
4092{
4093 m_tx_pool.lock();
4095 CRITICAL_REGION_LOCAL(m_blockchain_lock);
4096
4097 return m_db->check_pruning();
4098}
4099//------------------------------------------------------------------
4101{
4103
4104 const uint64_t db_height = m_db->height();
4105 const uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights_window, db_height);
4106
4107 const uint8_t hf_version = get_current_hard_fork_version();
4108 if (hf_version < HF_VERSION_LONG_TERM_BLOCK_WEIGHT)
4109 return block_weight;
4110
4111 uint64_t long_term_median = get_long_term_block_weight_median(db_height - nblocks, nblocks);
4112 uint64_t long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
4113
4114 uint64_t short_term_constraint = long_term_effective_median_block_weight + long_term_effective_median_block_weight * 2 / 5;
4115 uint64_t long_term_block_weight = std::min<uint64_t>(block_weight, short_term_constraint);
4116
4117 return long_term_block_weight;
4118}
4119//------------------------------------------------------------------
4120bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effective_median_block_weight)
4121{
4122 PERF_TIMER(update_next_cumulative_weight_limit);
4123
4124 LOG_PRINT_L3("Blockchain::" << __func__);
4125
4126 // when we reach this, the last hf version is not yet written to the db
4127 const uint64_t db_height = m_db->height();
4128 const uint8_t hf_version = get_current_hard_fork_version();
4129 uint64_t full_reward_zone = get_min_block_weight(hf_version);
4130 uint64_t long_term_block_weight;
4131
4132 if (hf_version < HF_VERSION_LONG_TERM_BLOCK_WEIGHT)
4133 {
4134 std::vector<uint64_t> weights;
4135 get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
4136 m_current_block_cumul_weight_median = epee::misc_utils::median(weights);
4137 long_term_block_weight = weights.back();
4138 }
4139 else
4140 {
4141 const uint64_t block_weight = m_db->get_block_weight(db_height - 1);
4142
4143 uint64_t long_term_median;
4144 if (db_height == 1)
4145 {
4147 }
4148 else
4149 {
4150 uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights_window, db_height);
4151 if (nblocks == db_height)
4152 --nblocks;
4153 long_term_median = get_long_term_block_weight_median(db_height - nblocks - 1, nblocks);
4154 }
4155
4156 m_long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
4157
4158 uint64_t short_term_constraint = m_long_term_effective_median_block_weight + m_long_term_effective_median_block_weight * 2 / 5;
4159 long_term_block_weight = std::min<uint64_t>(block_weight, short_term_constraint);
4160
4161 if (db_height == 1)
4162 {
4163 long_term_median = long_term_block_weight;
4164 }
4165 else
4166 {
4167 m_long_term_block_weights_cache_tip_hash = m_db->get_block_hash_from_height(db_height - 1);
4168 m_long_term_block_weights_cache_rolling_median.insert(long_term_block_weight);
4169 long_term_median = m_long_term_block_weights_cache_rolling_median.median();
4170 }
4171 m_long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
4172
4173 std::vector<uint64_t> weights;
4174 get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
4175
4176 uint64_t short_term_median = epee::misc_utils::median(weights);
4177 uint64_t effective_median_block_weight = std::min<uint64_t>(std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, short_term_median), CRYPTONOTE_SHORT_TERM_BLOCK_WEIGHT_SURGE_FACTOR * m_long_term_effective_median_block_weight);
4178
4179 m_current_block_cumul_weight_median = effective_median_block_weight;
4180 }
4181
4182 if (m_current_block_cumul_weight_median <= full_reward_zone)
4183 m_current_block_cumul_weight_median = full_reward_zone;
4184
4185 m_current_block_cumul_weight_limit = m_current_block_cumul_weight_median * 2;
4186
4187 if (long_term_effective_median_block_weight)
4188 *long_term_effective_median_block_weight = m_long_term_effective_median_block_weight;
4189
4190 if (!m_db->is_read_only())
4191 m_db->add_max_block_size(m_current_block_cumul_weight_limit);
4192
4193 return true;
4194}
4195//------------------------------------------------------------------
4197{
4198 LOG_PRINT_L3("Blockchain::" << __func__);
4200 CRITICAL_REGION_LOCAL(m_tx_pool);//to avoid deadlock lets lock tx_pool for whole add/reorganize process
4201 CRITICAL_REGION_LOCAL1(m_blockchain_lock);
4202 db_rtxn_guard rtxn_guard(m_db);
4203 if(have_block(id))
4204 {
4205 LOG_PRINT_L3("block with id = " << id << " already exists");
4206 bvc.m_already_exists = true;
4207 m_blocks_txs_check.clear();
4208 return false;
4209 }
4210
4211 //check that block refers to chain tail
4212 if(!(bl.prev_id == get_tail_id()))
4213 {
4214 //chain switching or wrong block
4215 bvc.m_added_to_main_chain = false;
4216 rtxn_guard.stop();
4217 bool r = handle_alternative_block(bl, id, bvc);
4218 m_blocks_txs_check.clear();
4219 return r;
4220 //never relay alternative blocks
4221 }
4222
4223 rtxn_guard.stop();
4224 return handle_block_to_main_chain(bl, id, bvc);
4225}
4226//------------------------------------------------------------------
4227//TODO: Refactor, consider returning a failure height and letting
4228// caller decide course of action.
4230{
4231 const auto& pts = points.get_points();
4232 bool stop_batch;
4233
4234 CRITICAL_REGION_LOCAL(m_blockchain_lock);
4235 stop_batch = m_db->batch_start();
4236 const uint64_t blockchain_height = m_db->height();
4237 for (const auto& pt : pts)
4238 {
4239 // if the checkpoint is for a block we don't have yet, move on
4240 if (pt.first >= blockchain_height)
4241 {
4242 continue;
4243 }
4244
4245 if (!points.check_block(pt.first, m_db->get_block_hash_from_height(pt.first)))
4246 {
4247 // if asked to enforce checkpoints, roll back to a couple of blocks before the checkpoint
4248 if (enforce)
4249 {
4250 LOG_ERROR("Local blockchain failed to pass a checkpoint, rolling back!");
4251 std::list<block> empty;
4252 rollback_blockchain_switching(empty, pt.first - 2);
4253
4254 //Flush the txpool if we've just popped blocks due to failed checkpoint.
4255 std::vector<crypto::hash> txs;
4256 m_tx_pool.get_transaction_hashes(txs, true);
4258 }
4259 else
4260 {
4261 LOG_ERROR("WARNING: local blockchain failed to pass a ElectroneumPulse checkpoint, and you could be on a fork. You should either sync up from scratch, OR download a fresh blockchain bootstrap, OR enable checkpoint enforcing with the --enforce-dns-checkpointing command-line option");
4262 }
4263 }
4264 }
4265 if (stop_batch)
4266 m_db->batch_stop();
4267}
4268//------------------------------------------------------------------
4269// returns false if any of the checkpoints loading returns false.
4270// That should happen only if a checkpoint is added that conflicts
4271// with an existing checkpoint.
4272bool Blockchain::update_checkpoints(const std::string& file_path, bool check_dns)
4273{
4274 if (!m_checkpoints.load_checkpoints_from_json(file_path))
4275 {
4276 return false;
4277 }
4278
4279 // if we're checking both dns and json, load checkpoints from dns.
4280 // if we're not hard-enforcing dns checkpoints, handle accordingly
4281 if (m_enforce_dns_checkpoints && check_dns && !m_offline)
4282 {
4283 if (!m_checkpoints.load_checkpoints_from_dns())
4284 {
4285 return false;
4286 }
4287 }
4288 else if (check_dns && !m_offline)
4289 {
4290 checkpoints dns_points;
4291 dns_points.load_checkpoints_from_dns();
4292 if (m_checkpoints.check_for_conflicts(dns_points))
4293 {
4294 check_against_checkpoints(dns_points, false);
4295 }
4296 else
4297 {
4298 MERROR("One or more checkpoints fetched from DNS conflicted with existing checkpoints!");
4299 }
4300 }
4301
4302 check_against_checkpoints(m_checkpoints, true);
4303
4304 return true;
4305}
4306//------------------------------------------------------------------
4307void Blockchain::set_enforce_dns_checkpoints(bool enforce_checkpoints)
4308{
4309 m_enforce_dns_checkpoints = enforce_checkpoints;
4310}
4311
4312//------------------------------------------------------------------
4313void Blockchain::block_longhash_worker(uint64_t height, const epee::span<const block> &blocks, std::unordered_map<crypto::hash, crypto::hash> &map) const
4314{
4317
4318 for (const auto & block : blocks)
4319 {
4320 if (m_cancel)
4321 break;
4324 map.emplace(id, pow);
4325 }
4326
4329}
4330
4331//------------------------------------------------------------------
4333{
4334 bool success = false;
4335
4336 MTRACE("Blockchain::" << __func__);
4337 CRITICAL_REGION_BEGIN(m_blockchain_lock);
4339
4340 try
4341 {
4342 if (m_batch_success)
4343 m_db->batch_stop();
4344 else
4345 m_db->batch_abort();
4346 success = true;
4347 }
4348 catch (const std::exception &e)
4349 {
4350 MERROR("Exception in cleanup_handle_incoming_blocks: " << e.what());
4351 }
4352
4353 if (success && m_sync_counter > 0)
4354 {
4355 if (force_sync)
4356 {
4357 if(m_db_sync_mode != db_nosync)
4359 m_sync_counter = 0;
4360 }
4361 else if (m_db_sync_threshold && ((m_db_sync_on_blocks && m_sync_counter >= m_db_sync_threshold) || (!m_db_sync_on_blocks && m_bytes_to_sync >= m_db_sync_threshold)))
4362 {
4363 MDEBUG("Sync threshold met, syncing");
4364 if(m_db_sync_mode == db_async)
4365 {
4366 m_sync_counter = 0;
4367 m_bytes_to_sync = 0;
4368 m_async_service.dispatch(boost::bind(&Blockchain::store_blockchain, this));
4369 }
4370 else if(m_db_sync_mode == db_sync)
4371 {
4373 }
4374 else // db_nosync
4375 {
4376 // DO NOTHING, not required to call sync.
4377 }
4378 }
4379 }
4380
4382 m_blocks_longhash_table.clear();
4383 m_scan_table.clear();
4384 m_blocks_txs_check.clear();
4385 m_check_txin_table.clear();
4386
4388 m_tx_pool.unlock();
4389
4391
4392 return success;
4393}
4394
4395//------------------------------------------------------------------
4396void Blockchain::output_scan_worker(const uint64_t amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs) const
4397{
4398 try
4399 {
4400 m_db->get_output_key(epee::span<const uint64_t>(&amount, 1), offsets, outputs, true);
4401 }
4402 catch (const std::exception& e)
4403 {
4404 MERROR_VER("EXCEPTION: " << e.what());
4405 }
4406 catch (...)
4407 {
4408
4409 }
4410}
4411
4412//------------------------------------------------------------------
4413// ND: Speedups:
4414// 1. Thread long_hash computations if possible (m_max_prepare_blocks_threads = nthreads, default = 4)
4415// 2. Group all amounts (from txs) and related absolute offsets and form a table of tx_prefix_hash
4416// vs [k_image, output_keys] (m_scan_table). This is faster because it takes advantage of bulk queries
4417// and is threaded if possible. The table (m_scan_table) will be used later when querying output
4418// keys.
4419bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete_entry> &blocks_entry, std::vector<block> &blocks)
4420{
4421 MTRACE("Blockchain::" << __func__);
4422 TIME_MEASURE_START(prepare);
4423 bool stop_batch;
4424 uint64_t bytes = 0;
4425 size_t total_txs = 0;
4426 blocks.clear();
4427
4428 // Order of locking must be:
4429 // m_incoming_tx_lock (optional)
4430 // m_tx_pool lock
4431 // blockchain lock
4432 //
4433 // Something which takes the blockchain lock may never take the txpool lock
4434 // if it has not provably taken the txpool lock earlier
4435 //
4436 // The txpool lock is now taken in prepare_handle_incoming_blocks
4437 // and released in cleanup_handle_incoming_blocks. This avoids issues
4438 // when something uses the pool, which now uses the blockchain and
4439 // needs a batch, since a batch could otherwise be active while the
4440 // txpool and blockchain locks were not held
4441
4442 m_tx_pool.lock();
4443 CRITICAL_REGION_LOCAL1(m_blockchain_lock);
4444
4445 if(blocks_entry.size() == 0)
4446 return false;
4447
4448 for (const auto &entry : blocks_entry)
4449 {
4450 bytes += entry.block.size();
4451 for (const auto &tx_blob : entry.txs)
4452 {
4453 bytes += tx_blob.size();
4454 }
4455 total_txs += entry.txs.size();
4456 }
4457 m_bytes_to_sync += bytes;
4458 while (!(stop_batch = m_db->batch_start(blocks_entry.size(), bytes))) {
4459 m_blockchain_lock.unlock();
4460 m_tx_pool.unlock();
4462 m_tx_pool.lock();
4463 m_blockchain_lock.lock();
4464 }
4465 m_batch_success = true;
4466
4467 const uint64_t height = m_db->height();
4468 if ((height + blocks_entry.size()) < m_blocks_hash_check.size())
4469 return true;
4470
4471 bool blocks_exist = false;
4473 unsigned threads = tpool.get_max_concurrency();
4474 blocks.resize(blocks_entry.size());
4475
4476 if (1)
4477 {
4478 // limit threads, default limit = 4
4479 if(threads > m_max_prepare_blocks_threads)
4480 threads = m_max_prepare_blocks_threads;
4481
4482 unsigned int batches = blocks_entry.size() / threads;
4483 unsigned int extra = blocks_entry.size() % threads;
4484 MDEBUG("block_batches: " << batches);
4485 std::vector<std::unordered_map<crypto::hash, crypto::hash>> maps(threads);
4486 auto it = blocks_entry.begin();
4487 unsigned blockidx = 0;
4488
4489 const crypto::hash tophash = m_db->top_block_hash();
4490 for (unsigned i = 0; i < threads; i++)
4491 {
4492 for (unsigned int j = 0; j < batches; j++, ++blockidx)
4493 {
4494 block &block = blocks[blockidx];
4495 crypto::hash block_hash;
4496
4497 if (!parse_and_validate_block_from_blob(it->block, block, block_hash))
4498 return false;
4499
4500 // check first block and skip all blocks if its not chained properly
4501 if (blockidx == 0)
4502 {
4503 if (block.prev_id != tophash)
4504 {
4505 MDEBUG("Skipping prepare blocks. New blocks don't belong to chain.");
4506 blocks.clear();
4507 return true;
4508 }
4509 }
4510 if (have_block(block_hash))
4511 blocks_exist = true;
4512
4513 std::advance(it, 1);
4514 }
4515 }
4516
4517 for (unsigned i = 0; i < extra && !blocks_exist; i++, blockidx++)
4518 {
4519 block &block = blocks[blockidx];
4520 crypto::hash block_hash;
4521
4522 if (!parse_and_validate_block_from_blob(it->block, block, block_hash))
4523 return false;
4524
4525 if (have_block(block_hash))
4526 blocks_exist = true;
4527
4528 std::advance(it, 1);
4529 }
4530
4531 if (!blocks_exist)
4532 {
4533 m_blocks_longhash_table.clear();
4534 uint64_t thread_height = height;
4536 for (unsigned int i = 0; i < threads; i++)
4537 {
4538 unsigned nblocks = batches;
4539 if (i < extra)
4540 ++nblocks;
4541 tpool.submit(&waiter, boost::bind(&Blockchain::block_longhash_worker, this, thread_height, epee::span<const block>(&blocks[thread_height - height], nblocks), std::ref(maps[i])), true);
4542 thread_height += nblocks;
4543 }
4544
4545 waiter.wait(&tpool);
4546
4547 if (m_cancel)
4548 return false;
4549
4550 for (const auto & map : maps)
4551 {
4552 m_blocks_longhash_table.insert(map.begin(), map.end());
4553 }
4554 }
4555 }
4556
4557 if (m_cancel)
4558 return false;
4559
4560 if (blocks_exist)
4561 {
4562 MDEBUG("Skipping remainder of prepare blocks. Blocks exist.");
4563 return true;
4564 }
4565
4566 m_fake_scan_time = 0;
4567 m_fake_pow_calc_time = 0;
4568
4569 m_scan_table.clear();
4570 m_check_txin_table.clear();
4571
4572 TIME_MEASURE_FINISH(prepare);
4573 m_fake_pow_calc_time = prepare / blocks_entry.size();
4574
4575 if (blocks_entry.size() > 1 && threads > 1 && m_show_time_stats)
4576 MDEBUG("Prepare blocks took: " << prepare << " ms");
4577
4578 TIME_MEASURE_START(scantable);
4579
4580 // [input] stores all unique amounts found
4581 std::vector < uint64_t > amounts;
4582 // [input] stores all absolute_offsets for each amount
4583 std::map<uint64_t, std::vector<uint64_t>> offset_map;
4584 // [output] stores all output_data_t for each absolute_offset
4585 std::map<uint64_t, std::vector<output_data_t>> tx_map;
4586 std::vector<std::pair<cryptonote::transaction, crypto::hash>> txes(total_txs);
4587
4588#define SCAN_TABLE_QUIT(m) \
4589 do { \
4590 MERROR_VER(m) ;\
4591 m_scan_table.clear(); \
4592 return false; \
4593 } while(0); \
4594
4595 // generate sorted tables for all amounts and absolute offsets
4596 size_t tx_index = 0, block_index = 0;
4597 for (const auto &entry : blocks_entry)
4598 {
4599 if (m_cancel)
4600 return false;
4601
4602 for (const auto &tx_blob : entry.txs)
4603 {
4604 if (tx_index >= txes.size())
4605 SCAN_TABLE_QUIT("tx_index is out of sync");
4606 transaction &tx = txes[tx_index].first;
4607 crypto::hash &tx_prefix_hash = txes[tx_index].second;
4608 ++tx_index;
4609
4610 if (!parse_and_validate_tx_base_from_blob(tx_blob, tx))
4611 SCAN_TABLE_QUIT("Could not parse tx from incoming blocks.");
4612 cryptonote::get_transaction_prefix_hash(tx, tx_prefix_hash);
4613
4614 auto its = m_scan_table.find(tx_prefix_hash);
4615 if (its != m_scan_table.end())
4616 SCAN_TABLE_QUIT("Duplicate tx found from incoming blocks.");
4617
4618 m_scan_table.emplace(tx_prefix_hash, std::unordered_map<crypto::key_image, std::vector<output_data_t>>());
4619 its = m_scan_table.find(tx_prefix_hash);
4620 assert(its != m_scan_table.end());
4621
4622 if(tx.version <= 2)
4623 {
4624 // get all amounts from tx.vin(s)
4625 for (const auto &txin : tx.vin)
4626 {
4627 const txin_to_key &in_to_key = boost::get < txin_to_key > (txin);
4628
4629 // check for duplicate
4630 auto it = its->second.find(in_to_key.k_image);
4631 if (it != its->second.end())
4632 SCAN_TABLE_QUIT("Duplicate key_image found from incoming blocks.");
4633
4634 amounts.push_back(in_to_key.amount);
4635 }
4636 }
4637
4638 // sort and remove duplicate amounts from amounts list
4639 std::sort(amounts.begin(), amounts.end());
4640 auto last = std::unique(amounts.begin(), amounts.end());
4641 amounts.erase(last, amounts.end());
4642
4643 // add amount to the offset_map and tx_map
4644 for (const uint64_t &amount : amounts)
4645 {
4646 if (offset_map.find(amount) == offset_map.end())
4647 offset_map.emplace(amount, std::vector<uint64_t>());
4648
4649 if (tx_map.find(amount) == tx_map.end())
4650 tx_map.emplace(amount, std::vector<output_data_t>());
4651 }
4652
4653 if(tx.version <= 2)
4654 {
4655 // add new absolute_offsets to offset_map
4656 for (const auto &txin : tx.vin)
4657 {
4658 const txin_to_key &in_to_key = boost::get < txin_to_key > (txin);
4659 // no need to check for duplicate here.
4660 auto absolute_offsets = relative_output_offsets_to_absolute(in_to_key.key_offsets);
4661 for (const auto & offset : absolute_offsets)
4662 offset_map[in_to_key.amount].push_back(offset);
4663
4664 }
4665 }
4666 }
4667 ++block_index;
4668 }
4669
4670 // sort and remove duplicate absolute_offsets in offset_map
4671 for (auto &offsets : offset_map)
4672 {
4673 std::sort(offsets.second.begin(), offsets.second.end());
4674 auto last = std::unique(offsets.second.begin(), offsets.second.end());
4675 offsets.second.erase(last, offsets.second.end());
4676 }
4677
4678 // gather all the output keys
4679 threads = tpool.get_max_concurrency();
4680 if (!m_db->can_thread_bulk_indices())
4681 threads = 1;
4682
4683 if (threads > 1 && amounts.size() > 1)
4684 {
4686
4687 for (size_t i = 0; i < amounts.size(); i++)
4688 {
4689 uint64_t amount = amounts[i];
4690 tpool.submit(&waiter, boost::bind(&Blockchain::output_scan_worker, this, amount, std::cref(offset_map[amount]), std::ref(tx_map[amount])), true);
4691 }
4692 waiter.wait(&tpool);
4693 }
4694 else
4695 {
4696 for (size_t i = 0; i < amounts.size(); i++)
4697 {
4698 uint64_t amount = amounts[i];
4699 output_scan_worker(amount, offset_map[amount], tx_map[amount]);
4700 }
4701 }
4702
4703 // now generate a table for each tx_prefix and k_image hashes
4704 tx_index = 0;
4705 for (const auto &entry : blocks_entry)
4706 {
4707 if (m_cancel)
4708 return false;
4709
4710 for (const auto &tx_blob : entry.txs)
4711 {
4712 if (tx_index >= txes.size())
4713 SCAN_TABLE_QUIT("tx_index is out of sync");
4714 const transaction &tx = txes[tx_index].first;
4715 const crypto::hash &tx_prefix_hash = txes[tx_index].second;
4716 ++tx_index;
4717
4718 auto its = m_scan_table.find(tx_prefix_hash);
4719 if (its == m_scan_table.end())
4720 SCAN_TABLE_QUIT("Tx not found on scan table from incoming blocks.");
4721
4722 if(tx.version >= 3) continue;
4723
4724 for (const auto &txin : tx.vin)
4725 {
4726 const txin_to_key &in_to_key = boost::get < txin_to_key > (txin);
4727 auto needed_offsets = relative_output_offsets_to_absolute(in_to_key.key_offsets);
4728
4729 std::vector<output_data_t> outputs;
4730 for (const uint64_t & offset_needed : needed_offsets)
4731 {
4732 size_t pos = 0;
4733 bool found = false;
4734
4735 for (const uint64_t &offset_found : offset_map[in_to_key.amount])
4736 {
4737 if (offset_needed == offset_found)
4738 {
4739 found = true;
4740 break;
4741 }
4742
4743 ++pos;
4744 }
4745
4746 if (found && pos < tx_map[in_to_key.amount].size())
4747 outputs.push_back(tx_map[in_to_key.amount].at(pos));
4748 else
4749 break;
4750 }
4751
4752 its->second.emplace(in_to_key.k_image, outputs);
4753 }
4754 }
4755 }
4756
4757 TIME_MEASURE_FINISH(scantable);
4758 if (total_txs > 0)
4759 {
4760 m_fake_scan_time = scantable / total_txs;
4761 if(m_show_time_stats)
4762 MDEBUG("Prepare scantable took: " << scantable << " ms");
4763 }
4764
4765 return true;
4766}
4767
4769{
4770 m_db->add_txpool_tx(txid, blob, meta);
4771}
4772
4774{
4775 m_db->update_txpool_tx(txid, meta);
4776}
4777
4779{
4780 m_db->remove_txpool_tx(txid);
4781}
4782
4783uint64_t Blockchain::get_txpool_tx_count(bool include_unrelayed_txes) const
4784{
4785 return m_db->get_txpool_tx_count(include_unrelayed_txes);
4786}
4787
4789{
4790 return m_db->get_txpool_tx_meta(txid, meta);
4791}
4792
4794{
4795 return m_db->get_txpool_tx_blob(txid, bd);
4796}
4797
4799{
4800 return m_db->get_txpool_tx_blob(txid);
4801}
4802
4803bool Blockchain::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob, bool include_unrelayed_txes) const
4804{
4805 return m_db->for_all_txpool_txes(f, include_blob, include_unrelayed_txes);
4806}
4807
4816
4817void Blockchain::set_user_options(uint64_t maxthreads, bool sync_on_blocks, uint64_t sync_threshold, blockchain_db_sync_mode sync_mode, bool fast_sync, std::string validator_key)
4818{
4819 if (sync_mode == db_defaultsync)
4820 {
4821 m_db_default_sync = true;
4822 sync_mode = db_async;
4823 }
4824 m_db_sync_mode = sync_mode;
4825 m_fast_sync = fast_sync;
4826 m_db_sync_on_blocks = sync_on_blocks;
4827 m_db_sync_threshold = sync_threshold;
4828 m_max_prepare_blocks_threads = maxthreads;
4829
4830 if(!validator_key.empty()) {
4831 m_validator_key = boost::algorithm::unhex(validator_key);
4832 }
4833}
4834
4835void Blockchain::safesyncmode(const bool onoff)
4836{
4837 /* all of this is no-op'd if the user set a specific
4838 * --db-sync-mode at startup.
4839 */
4840 if (m_db_default_sync)
4841 {
4842 m_db->safesyncmode(onoff);
4843 m_db_sync_mode = onoff ? db_nosync : db_async;
4844 }
4845}
4846
4848{
4849 return m_hardfork->get_state();
4850}
4851
4852const std::vector<HardFork::Params>& Blockchain::get_hard_fork_heights(network_type nettype)
4853{
4854 static const std::vector<HardFork::Params> mainnet_heights = []()
4855 {
4856 std::vector<HardFork::Params> heights;
4857 for (const auto& i : mainnet_hard_forks)
4858 heights.emplace_back(i.version, i.height, i.threshold, i.time);
4859 return heights;
4860 }();
4861 static const std::vector<HardFork::Params> testnet_heights = []()
4862 {
4863 std::vector<HardFork::Params> heights;
4864 for (const auto& i : testnet_hard_forks)
4865 heights.emplace_back(i.version, i.height, i.threshold, i.time);
4866 return heights;
4867 }();
4868 static const std::vector<HardFork::Params> stagenet_heights = []()
4869 {
4870 std::vector<HardFork::Params> heights;
4871 for (const auto& i : stagenet_hard_forks)
4872 heights.emplace_back(i.version, i.height, i.threshold, i.time);
4873 return heights;
4874 }();
4875 static const std::vector<HardFork::Params> dummy;
4876 switch (nettype)
4877 {
4878 case MAINNET: return mainnet_heights;
4879 case TESTNET: return testnet_heights;
4880 case STAGENET: return stagenet_heights;
4881 default: return dummy;
4882 }
4883}
4884
4886{
4887 return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting);
4888}
4889
4894
4895std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> Blockchain:: get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff, uint64_t min_count) const
4896{
4897 return m_db->get_output_histogram(amounts, unlocked, recent_cutoff, min_count);
4898}
4899
4900std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> Blockchain::get_alternative_chains() const
4901{
4902 std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> chains;
4903
4904 for (const auto &i: m_alternative_chains)
4905 {
4906 const crypto::hash &top = i.first;
4907 bool found = false;
4908 for (const auto &j: m_alternative_chains)
4909 {
4910 if (j.second.bl.prev_id == top)
4911 {
4912 found = true;
4913 break;
4914 }
4915 }
4916 if (!found)
4917 {
4918 std::vector<crypto::hash> chain;
4919 auto h = i.second.bl.prev_id;
4920 chain.push_back(top);
4921 blocks_ext_by_hash::const_iterator prev;
4922 while ((prev = m_alternative_chains.find(h)) != m_alternative_chains.end())
4923 {
4924 chain.push_back(h);
4925 h = prev->second.bl.prev_id;
4926 }
4927 chains.push_back(std::make_pair(i.second, chain));
4928 }
4929 }
4930 return chains;
4931}
4932
4934{
4935 m_cancel = true;
4936}
4937
4938#if defined(PER_BLOCK_CHECKPOINT)
4939static const char expected_block_hashes_hash[] = "53a9384ca5384025e657622b5d66fac67c03f9b863b91abe9516eda47cceaeb5";
4940void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
4941{
4942 if (get_checkpoints == nullptr || !m_fast_sync)
4943 {
4944 return;
4945 }
4946 const epee::span<const unsigned char> &checkpoints = get_checkpoints(m_nettype);
4947 if (!checkpoints.empty())
4948 {
4949 MINFO("Loading precomputed blocks (" << checkpoints.size() << " bytes)");
4950 if (m_nettype == MAINNET)
4951 {
4952 // first check hash
4954 if (!tools::sha256sum(checkpoints.data(), checkpoints.size(), hash))
4955 {
4956 MERROR("Failed to hash precomputed blocks data");
4957 return;
4958 }
4959 MINFO("precomputed blocks hash: " << hash << ", expected " << expected_block_hashes_hash);
4960 cryptonote::blobdata expected_hash_data;
4961 if (!epee::string_tools::parse_hexstr_to_binbuff(std::string(expected_block_hashes_hash), expected_hash_data) || expected_hash_data.size() != sizeof(crypto::hash))
4962 {
4963 MERROR("Failed to parse expected block hashes hash");
4964 return;
4965 }
4966 const crypto::hash expected_hash = *reinterpret_cast<const crypto::hash*>(expected_hash_data.data());
4967 if (hash != expected_hash)
4968 {
4969 MERROR("Block hash data does not match expected hash");
4970 return;
4971 }
4972 }
4973
4974 if (checkpoints.size() > 4)
4975 {
4976 const unsigned char *p = checkpoints.data();
4977 const uint32_t nblocks = *p | ((*(p+1))<<8) | ((*(p+2))<<16) | ((*(p+3))<<24);
4978 if (nblocks > (std::numeric_limits<uint32_t>::max() - 4) / sizeof(hash))
4979 {
4980 MERROR("Block hash data is too large");
4981 return;
4982 }
4983 const size_t size_needed = 4 + nblocks * sizeof(crypto::hash);
4984 if(nblocks > 0 && nblocks > m_db->height() && checkpoints.size() >= size_needed)
4985 {
4986 p += sizeof(uint32_t);
4987 for (uint32_t i = 0; i < nblocks; i++)
4988 {
4990 memcpy(hash.data, p, sizeof(hash.data));
4991 p += sizeof(hash.data);
4992 m_blocks_hash_check.push_back(hash);
4993 }
4994 MINFO(nblocks << " block hashes loaded");
4995
4996 // FIXME: clear tx_pool because the process might have been
4997 // terminated and caused it to store txs kept by blocks.
4998 // The core will not call check_tx_inputs(..) for these
4999 // transactions in this case. Consequently, the sanity check
5000 // for tx hashes will fail in handle_block_to_main_chain(..)
5001 CRITICAL_REGION_LOCAL(m_tx_pool);
5002
5003 std::vector<transaction> txs;
5004 m_tx_pool.get_transactions(txs);
5005
5006 size_t tx_weight;
5007 uint64_t fee;
5008 bool relayed, do_not_relay, double_spend_seen, nonexistent_utxo_seen;
5009 transaction pool_tx;
5010 blobdata txblob;
5011 for(const transaction &tx : txs)
5012 {
5013 crypto::hash tx_hash = get_transaction_hash(tx);
5014 m_tx_pool.take_tx(tx_hash, pool_tx, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen, nonexistent_utxo_seen);
5015 }
5016 }
5017 }
5018 }
5019}
5020#endif
5021
5023{
5024#if defined(PER_BLOCK_CHECKPOINT)
5025 return height < m_blocks_hash_check.size();
5026#else
5027 return false;
5028#endif
5029}
5030
5032{
5033 m_blockchain_lock.lock();
5034}
5035
5037{
5038 m_blockchain_lock.unlock();
5039}
5040
5041bool Blockchain::for_all_key_images(std::function<bool(const crypto::key_image&)> f) const
5042{
5043 return m_db->for_all_key_images(f);
5044}
5045
5046bool Blockchain::for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::function<bool(uint64_t, const crypto::hash&, const block&)> f) const
5047{
5048 return m_db->for_blocks_range(h1, h2, f);
5049}
5050
5051bool Blockchain::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f, bool pruned) const
5052{
5053 return m_db->for_all_transactions(f, pruned);
5054}
5055
5056bool Blockchain::for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const
5057{
5058 return m_db->for_all_outputs(f);;
5059}
5060
5061bool Blockchain::for_all_outputs(uint64_t amount, std::function<bool(uint64_t height)> f) const
5062{
5063 return m_db->for_all_outputs(amount, f);;
5064}
5065
5066void Blockchain::invalidate_block_template_cache()
5067{
5068 MDEBUG("Invalidating block template cache");
5069 m_btc_valid = false;
5070}
5071
5072void Blockchain::cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t pool_cookie)
5073{
5074 MDEBUG("Setting block template cache");
5075 m_btc = b;
5076 m_btc_address = address;
5077 m_btc_nonce = nonce;
5078 m_btc_difficulty = diff;
5079 m_btc_height = height;
5080 m_btc_expected_reward = expected_reward;
5081 m_btc_pool_cookie = pool_cookie;
5082 m_btc_valid = true;
5083}
5084
5086
5087 block blk;
5089
5090 std::string signatory = std::string(blk.signatory.begin(), blk.signatory.end());
5091 return m_validators->getValidatorByKey(boost::algorithm::hex(signatory));
5092
5093}
5094
5095namespace cryptonote {
5096template bool Blockchain::get_transactions(const std::vector<crypto::hash>&, std::vector<transaction>&, std::vector<crypto::hash>&) const;
5097template bool Blockchain::get_transactions_blobs(const std::vector<crypto::hash>&, std::vector<cryptonote::blobdata>&, std::vector<crypto::hash>&, bool) const;
5098template bool Blockchain::get_split_transactions_blobs(const std::vector<crypto::hash>&, std::vector<std::tuple<crypto::hash, cryptonote::blobdata, crypto::hash, cryptonote::blobdata>>&, std::vector<crypto::hash>&) const;
5099}
#define FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE
size_t get_transaction_version(const cryptonote::blobdata &bd)
void reserve_container(std::vector< T > &v, size_t N)
#define SCAN_TABLE_QUIT(m)
uint64_t height
void slow_hash_allocate_state()
uint8_t version
#define BLOCK_REWARD_OVERESTIMATE
time_t time
#define MERROR_VER(x)
uint8_t threshold
void slow_hash_free_state()
const unsigned char checkpoints[]
thrown when a requested block does not exist
The BlockchainDB backing store interface declaration/contract.
virtual uint64_t height() const =0
fetch the current blockchain height
bool is_open() const
Gets the current open/ready state of the BlockchainDB.
virtual bool has_key_image(const crypto::key_image &img) const =0
check if a key image is stored as spent
virtual size_t get_block_weight(const uint64_t &height) const =0
fetch a block's weight
virtual bool for_all_outputs(std::function< bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const =0
runs a function over all outputs stored
virtual uint64_t get_block_timestamp(const uint64_t &height) const =0
fetch a block's timestamp
crypto::hash get_tail_id() const
get the hash of the most recent block on the blockchain
crypto::hash get_block_id_by_height(uint64_t height) const
gets a block's hash given a height
bool utxo_nonexistent(const transaction &tx) const
check if any utxo in a transaction has already been spent using the tx (v3 tx onwards)
bool check_fee(size_t tx_weight, uint64_t fee) const
validate a transaction's fee
bool prepare_handle_incoming_blocks(const std::vector< block_complete_entry > &blocks_entry, std::vector< block > &blocks)
performs some preprocessing on a group of incoming blocks to speed up verification
uint8_t get_current_hard_fork_version() const
gets the current hardfork version in use/voted for
Definition blockchain.h:825
bool init(BlockchainDB *db, const network_type nettype=MAINNET, bool offline=false, const cryptonote::test_options *test_options=NULL, difficulty_type fixed_difficulty=0, const GetCheckpointsCallback &get_checkpoints=nullptr, bool ignore_bsig=false, bool fallback_to_pow=false)
Initialize the Blockchain state.
bool get_txpool_tx_meta(const crypto::hash &txid, txpool_tx_meta_t &meta) const
bool prune_blockchain(uint32_t pruning_seed=0)
bool find_blockchain_supplement(const std::list< crypto::hash > &qblock_ids, std::vector< crypto::hash > &hashes, uint64_t &start_height, uint64_t &current_height, bool clip_pruned) const
get recent block hashes for a foreign chain
bool get_tx_outputs_gindexs(const crypto::hash &tx_id, std::vector< uint64_t > &indexs) const
gets the global indices for outputs from a given transaction
void normalize_v7_difficulties()
Normalize the cumulative difficulty for V7 blocks, fixing the differing difficulty among nodes.
bool get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan=NULL) const
gets the block with a given hash
void safesyncmode(const bool onoff)
Put DB in safe sync mode.
void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t &meta)
crypto::public_key get_output_key(uint64_t amount, uint64_t global_index) const
get the public key for an output
void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta)
network_type get_nettype() const
get blockchain nettype
bool get_split_transactions_blobs(const t_ids_container &txs_ids, t_tx_container &txs, t_missed_container &missed_txs) const
bool for_all_outputs(std::function< bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)>) const
perform a check on all outputs in the blockchain
void set_enforce_dns_checkpoints(bool enforce)
configure whether or not to enforce DNS-based checkpoints
uint64_t get_dynamic_base_fee_estimate(uint64_t grace_blocks) const
get dynamic per kB or byte fee estimate for the next few blocks
void output_scan_worker(const uint64_t amount, const std::vector< uint64_t > &offsets, std::vector< output_data_t > &outputs) const
get a number of outputs of a specific amount
uint64_t get_next_long_term_block_weight(uint64_t block_weight) const
gets the long term block weight for a new block
bool update_checkpoints(const std::string &file_path, bool check_dns)
loads new checkpoints from a file and optionally from DNS
uint64_t get_txpool_tx_count(bool include_unrelayed_txes=true) const
bool is_within_compiled_block_hash_area() const
~Blockchain()
Blockchain destructor.
bool deinit()
Uninitializes the blockchain state.
static const std::vector< HardFork::Params > & get_hard_fork_heights(network_type nettype)
gets the hardfork heights of given network
HardFork::State get_hard_fork_state() const
gets the hardfork voting state object
uint64_t get_current_cumulative_block_weight_median() const
gets the block weight median based on recent blocks (same window as for the limit)
difficulty_type block_difficulty(uint64_t i) const
gets the difficulty of the block with a given height
electroneum::basic::Validator get_validator_by_height(uint64_t height)
bool key_images_already_spent(const transaction &tx) const
check if any key image in a transaction has already been spent
bool get_blocks(uint64_t start_offset, size_t count, std::vector< std::pair< cryptonote::blobdata, block > > &blocks, std::vector< cryptonote::blobdata > &txs) const
get blocks and transactions from blocks based on start height and count
bool verify_block_signature(const block &b)
Verify block's digital signature.
bool get_alternative_blocks(std::vector< block > &blocks) const
compiles a list of all blocks stored as alternative chains
void on_new_tx_from_block(const cryptonote::transaction &tx)
called when we see a tx originating from a block
void check_against_checkpoints(const checkpoints &points, bool enforce)
check the blockchain against a set of checkpoints
Blockchain(tx_memory_pool &tx_pool)
Blockchain constructor.
bool get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector< uint64_t > &distribution, uint64_t &base) const
gets per block distribution of outputs of a given amount
bool check_tx_outputs(const transaction &tx, tx_verification_context &tvc)
check that a transaction's outputs conform to current standards
uint64_t get_current_cumulative_block_weight_limit() const
gets the block weight limit based on recent blocks
std::vector< time_t > get_last_block_timestamps(unsigned int blocks) const
returns the timestamps of the last N blocks
bool for_blocks_range(const uint64_t &h1, const uint64_t &h2, std::function< bool(uint64_t, const crypto::hash &, const block &)>) const
perform a check on all blocks in the blockchain in the given range
bool get_transactions_blobs(const t_ids_container &txs_ids, t_tx_container &txs, t_missed_container &missed_txs, bool pruned=false) const
gets transactions based on a list of transaction hashes
bool store_blockchain()
stores the blockchain
uint64_t get_num_mature_outputs(uint64_t amount) const
get number of outputs of an amount past the minimum spendable age
difficulty_type get_difficulty_for_next_block()
returns the difficulty target the next block to be added must meet
bool utxo_nonexistence_from_output(const txin_to_key_public &public_output) const
check if a single utxo in a transaction has already been spent using the hash and out index (v3 tx on...
std::list< std::pair< block_extended_info, std::vector< crypto::hash > > > get_alternative_chains() const
returns a set of known alternate chains
bool have_block(const crypto::hash &id) const
checks if a block is known about with a given hash
bool cleanup_handle_incoming_blocks(bool force_sync=false)
incoming blocks post-processing, cleanup, and disk sync
void remove_txpool_tx(const crypto::hash &txid)
uint8_t get_hard_fork_version(uint64_t height) const
returns the actual hardfork version for a given block height
Definition blockchain.h:858
bool for_all_txpool_txes(std::function< bool(const crypto::hash &, const txpool_tx_meta_t &, const cryptonote::blobdata *)>, bool include_blob=false, bool include_unrelayed_txes=true) const
bool for_all_transactions(std::function< bool(const crypto::hash &, const cryptonote::transaction &)>, bool pruned) const
perform a check on all transactions in the blockchain
uint64_t get_difficulty_target() const
get difficulty target based on chain and hardfork version
void block_longhash_worker(uint64_t height, const epee::span< const block > &blocks, std::unordered_map< crypto::hash, crypto::hash > &map) const
computes the "short" and "long" hashes for a set of blocks
static uint64_t get_fee_quantization_mask()
get fee quantization mask
uint32_t get_mempool_tx_livetime() const
size_t get_alternative_blocks_count() const
returns the number of alternative blocks stored
uint8_t get_ideal_hard_fork_version() const
returns the newest hardfork version known to the blockchain
Definition blockchain.h:832
uint32_t get_blockchain_pruning_seed() const
static uint64_t get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight, uint8_t version)
get dynamic per kB or byte fee for a given block weight
bool have_tx(const crypto::hash &id) const
search the blockchain for a transaction by hash
bool for_all_key_images(std::function< bool(const crypto::key_image &)>) const
perform a check on all key images in the blockchain
std::map< uint64_t, std::tuple< uint64_t, uint64_t, uint64_t > > get_output_histogram(const std::vector< uint64_t > &amounts, bool unlocked, uint64_t recent_cutoff, uint64_t min_count=0) const
return a histogram of outputs on the blockchain
size_t get_total_transactions() const
gets the total number of transactions on the main chain
bool reset_and_set_genesis_block(const block &b)
clears the blockchain and starts a new one
void set_user_options(uint64_t maxthreads, bool sync_on_blocks, uint64_t sync_threshold, blockchain_db_sync_mode sync_mode, bool fast_sync, std::string validator_key)
Update the validators public key by fetching data from electroneum's endpoint.
bool flush_txes_from_pool(const std::vector< crypto::hash > &txids)
remove transactions from the transaction pool (if present)
bool get_short_chain_history(std::list< crypto::hash > &ids) const
gets the hashes for a subset of the blockchain
bool add_new_block(const block &bl_, block_verification_context &bvc)
adds a block to the blockchain
bool get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request &req, COMMAND_RPC_GET_OUTPUTS_BIN::response &res) const
gets specific outputs to mix with
bool create_block_template(block &b, const account_public_address &miner_address, difficulty_type &di, uint64_t &height, uint64_t &expected_reward, const blobdata &ex_nonce)
creates a new block to mine against
bool have_tx_keyimg_as_spent(const crypto::key_image &key_im) const
check if a key image is already spent on the blockchain
void sign_block(block &b, std::string privateKey)
Digitally sign the block.
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request &arg, NOTIFY_RESPONSE_GET_OBJECTS::request &rsp)
retrieves a set of blocks and their transactions, and possibly other transactions
bool get_txpool_tx_blob(const crypto::hash &txid, cryptonote::blobdata &bd) const
void get_output_key_mask_unlocked(const uint64_t &amount, const uint64_t &index, crypto::public_key &key, rct::key &mask, bool &unlocked) const
gets an output's key and unlocked state
bool get_transactions(const t_ids_container &txs_ids, t_tx_container &txs, t_missed_container &missed_txs) const
uint64_t get_current_blockchain_height() const
get the current height of the blockchain
void pop_blocks(uint64_t nblocks)
removes blocks from the top of the blockchain
bool check_tx_inputs(transaction &tx, uint64_t &pmax_used_block_height, crypto::hash &max_used_block_id, tx_verification_context &tvc, bool kept_by_block=false)
validates a transaction's inputs
bool get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const
get information about hardfork voting for a version
const char * what() const
uint8_t get_current_version() const
returns the current version
Definition hardfork.cpp:361
A container for blockchain checkpoints.
Definition checkpoints.h:52
bool check_block(uint64_t height, const crypto::hash &h, bool &is_a_checkpoint) const
checks if the given height and hash agree with the checkpoints
bool load_checkpoints_from_dns(network_type nettype=MAINNET)
load new checkpoints from DNS
const std::map< uint64_t, crypto::hash > & get_points() const
gets the checkpoints container
std::vector< std::vector< crypto::signature > > signatures
Transaction pool, handles transactions which are not part of a block.
Definition tx_pool.h:95
Non-owning sequence of data. Does not deep copy.
Definition span.h:57
void wait(threadpool *tpool)
A global thread pool.
Definition threadpool.h:44
void submit(waiter *waiter, std::function< void()> f, bool leaf=false)
unsigned int get_max_concurrency() const
static threadpool & getInstance()
Definition threadpool.h:46
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT
#define CRYPTONOTE_MEMPOOL_TX_LIVETIME
#define HF_VERSION_PUBLIC_TX
#define DYNAMIC_FEE_PER_KB_BASE_FEE_V5
#define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT
#define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5
#define DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD
#define FEE_PER_KB_V11
#define HF_VERSION_FORBID_INVALID_PUBKEYS
#define HF_VERSION_MIN_MIXIN_6
#define ETN_DEFAULT_TX_SPENDABLE_AGE_V8
#define HF_VERSION_FORBID_DUST_OUTPUTS
#define HF_VERSION_DYNAMIC_FEE
#define CRYPTONOTE_SHORT_TERM_BLOCK_WEIGHT_SURGE_FACTOR
#define FEE_PER_KB_V6
#define DIFFICULTY_BLOCKS_COUNT_V6
#define DIFFICULTY_TARGET
#define CRYPTONOTE_MEMPOOL_TX_LIVETIME_V6
#define HF_VERSION_LONG_TERM_BLOCK_WEIGHT
#define HF_VERSION_ENFORCE_0_DECOY_TXS
#define PER_KB_FEE_QUANTIZATION_DECIMALS
#define CRYPTONOTE_REWARD_BLOCKS_WINDOW
#define DEFAULT_RINGSIZE
#define DYNAMIC_FEE_REFERENCE_TRANSACTION_WEIGHT
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS
#define DIFFICULTY_TARGET_V6
#define DIFFICULTY_BLOCKS_COUNT
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT
#define DYNAMIC_FEE_PER_KB_BASE_FEE
#define ETN_MINED_ETN_UNLOCK_WINDOW_V8
#define HF_VERSION_ENFORCE_0_DECOY_TXS_END
#define FEE_PER_KB
#define CRYPTONOTE_MAX_BLOCK_NUMBER
#define HF_VERSION_MIN_MIXIN_10
#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS
#define HF_VERSION_ORDERED_TX_INPUTS
#define CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE
#define CRYPTONOTE_MINED_ETN_UNLOCK_WINDOW
#define ETN_SUPPLY
#define HF_VERSION_PER_BYTE_FEE
#define HF_VERSION_MIN_MIXIN_4
#define CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val)
std::string privateKey
void * memcpy(void *a, const void *b, size_t c)
const char * res
const char * key
void slow_hash_allocate_state()
void slow_hash_free_state()
#define AUTO_VAL_INIT(v)
#define MCERROR(cat, x)
Definition misc_log_ex.h:51
#define MERROR(x)
Definition misc_log_ex.h:73
#define LOG_PRINT_L3(x)
#define MWARNING(x)
Definition misc_log_ex.h:74
#define MGINFO_GREEN(x)
Definition misc_log_ex.h:82
#define MDEBUG(x)
Definition misc_log_ex.h:76
#define MCLOG_RED(level, cat, x)
Definition misc_log_ex.h:58
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
#define LOG_PRINT_L1(x)
#define LOG_ERROR(x)
Definition misc_log_ex.h:98
#define MGINFO(x)
Definition misc_log_ex.h:80
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
#define MTRACE(x)
Definition misc_log_ex.h:77
#define MINFO(x)
Definition misc_log_ex.h:75
#define LOG_PRINT_L2(x)
#define MGINFO_BLUE(x)
Definition misc_log_ex.h:84
#define LOG_PRINT_L0(x)
Definition misc_log_ex.h:99
crypto namespace.
Definition crypto.cpp:58
bool verify_signature(const std::string &message, const std::string &publicKey, const std::string &signature)
Definition crypto.h:380
bool check_key(const public_key &key)
Definition crypto.h:256
bool verify_input_signature(const hash &prefix_hash, const uint32_t input_index, const public_key pub_view, const public_key pub_spend, signature sig)
Definition crypto.h:303
public_key addKeys(const public_key &A, const public_key &B)
Definition crypto.h:339
POD_CLASS signature
Definition crypto.h:108
POD_CLASS public_key
Definition crypto.h:79
POD_CLASS key_image
Definition crypto.h:105
POD_CLASS hash
Definition hash.h:50
std::string sign_message(const std::string &message, const std::string &privateKey)
Definition crypto.h:376
bool check_ring_signature(const hash &prefix_hash, const key_image &image, const public_key *const *pubs, std::size_t pubs_count, const signature *sig)
Definition crypto.h:333
Holds cryptonote related classes and helpers.
Definition ban.cpp:40
bool is_valid_decomposed_amount(uint64_t amount)
boost::multiprecision::uint128_t difficulty_type
Definition difficulty.h:43
uint64_t get_outs_etn_amount(const transaction &tx)
bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version, uint64_t current_block_height, network_type nettype)
boost::variant< txin_gen, txin_to_script, txin_to_scripthash, txin_to_key, txin_to_key_public > txin_v
void get_transaction_prefix_hash(const transaction_prefix &tx, crypto::hash &h)
void get_tx_tree_hash(const std::vector< crypto::hash > &tx_hashes, crypto::hash &h)
difficulty_type next_difficulty(std::vector< uint64_t > timestamps, std::vector< difficulty_type > cumulative_difficulties, size_t target_seconds, uint8_t version)
std::vector< uint64_t > relative_output_offsets_to_absolute(const std::vector< uint64_t > &off)
bool get_block_hash(const block &b, crypto::hash &res)
bool parse_and_validate_block_from_blob(const blobdata &b_blob, block &b, crypto::hash *block_hash)
uint64_t get_block_height(const block &b)
blockchain_db_sync_mode
Definition blockchain.h:78
@ db_async
handle syncing calls instead of the backing db, asynchronously
Definition blockchain.h:81
@ db_nosync
Leave syncing up to the backing db (safest, but slowest because of disk I/O).
Definition blockchain.h:82
@ db_sync
handle syncing calls instead of the backing db, synchronously
Definition blockchain.h:80
@ db_defaultsync
user didn't specify, use db_async
Definition blockchain.h:79
size_t get_min_block_weight(uint8_t version)
bool check_hash(const crypto::hash &hash, difficulty_type difficulty)
crypto::hash get_transaction_hash(const transaction &t)
std::function< const epee::span< const unsigned char >(cryptonote::network_type network)> GetCheckpointsCallback
Callback routine that returns checkpoints data for specific network type.
Definition blockchain.h:92
bool is_coinbase(const transaction &tx)
blobdata block_to_blob(const block &b)
bool check_outs_overflow(const transaction &tx)
bool get_block_longhash(const block &b, crypto::hash &res, uint64_t height)
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction &tx, const blobdata &extra_nonce, size_t max_outs, uint8_t hard_fork_version, network_type nettype)
std::string blobdata
std::pair< crypto::hash, uint64_t > tx_out_index
size_t get_object_blobsize(const t_object &o)
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
bool get_inputs_etn_amount(const transaction &tx, uint64_t &etn)
std::string print_etn(uint64_t amount, unsigned int decimal_point)
bool generate_genesis_block(block &bl, std::string const &genesis_tx, uint32_t nonce)
const config_t & get_config(network_type nettype)
bool parse_and_validate_tx_base_from_blob(const blobdata &tx_blob, transaction &tx)
uint64_t get_transaction_weight(const transaction &tx, size_t blob_size)
Level
Represents enumeration for severity level used to determine level of logging.
@ Warning
Useful when application has potentially harmful situtaions.
boost::shared_ptr< call_befor_die_base > auto_scope_leave_caller
std::string get_time_interval_string(const time_t &time_)
bool sleep_no_w(long ms)
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
type_vec_type median(std::vector< type_vec_type > &v)
bool parse_hexstr_to_binbuff(const epee::span< const char > s, epee::span< char > &res)
std::string pod_to_hex(const t_pod_type &s)
mdb_size_t count(MDB_cursor *cur)
std::enable_if< std::is_integral< T >::value &&std::is_unsigned< T >::value &&0<=bits &&bits<=std::numeric_limits< T >::digits, int >::type read_varint(InputIt &&first, InputIt &&last, T &write)
reads in the varint that is pointed to by InputIt into write
Definition varint.h:95
uint64_t get_next_pruned_block_height(uint64_t block_height, uint64_t blockchain_height, uint32_t pruning_seed)
Definition pruning.cpp:93
uint64_t get_next_unpruned_block_height(uint64_t block_height, uint64_t blockchain_height, uint32_t pruning_seed)
Definition pruning.cpp:69
bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash)
Definition util.cpp:933
bool has_unpruned_block(uint64_t block_height, uint64_t blockchain_height, uint32_t pruning_seed)
Definition pruning.cpp:44
#define PERF_TIMER(name)
Definition perf_timer.h:82
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1124
#define TIME_MEASURE_FINISH(var_name)
#define TIME_MEASURE_START(var_name)
t2
Definition pow22523.h:103
t1
Definition pow22523.h:58
t3
Definition pow225521.h:103
#define true
#define false
unsigned int uint32_t
Definition stdint.h:126
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
container for passing a block and metadata about it on the blockchain
Definition blockchain.h:115
uint64_t height
the height of the block in the blockchain
Definition blockchain.h:117
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< request_t > request
std::vector< blobdata > txs
blobdata block
std::vector< uint8_t > signature
std::vector< uint8_t > signatory
std::vector< crypto::hash > tx_hashes
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX
a struct containing output metadata
uint64_t unlock_time
the output's unlock time (or height)
uint64_t height
the height of the block which created the output
rct::key commitment
the output's amount commitment (for spend verification)
crypto::public_key pubkey
the output's public key (for spend verification)
const size_t long_term_block_weight_window
const std::pair< uint8_t, uint64_t > * hard_forks
information about a single transaction
Definition tx_pool.h:404
transaction tx
the transaction
Definition tx_pool.h:405
uint64_t fee
the transaction's fee amount
Definition tx_pool.h:408
size_t weight
the transaction's weight
Definition tx_pool.h:407
crypto::key_image k_image
std::vector< uint64_t > key_offsets
cryptonote::account_public_address address
a struct containing txpool per transaction metadata
#define CRITICAL_REGION_LOCAL1(x)
Definition syncobj.h:230
#define CRITICAL_REGION_LOCAL(x)
Definition syncobj.h:228
#define CRITICAL_REGION_END()
Definition syncobj.h:233
#define CRITICAL_REGION_BEGIN(x)
Definition syncobj.h:229
struct hash_func hashes[]
const char * address
Definition multisig.cpp:37
provides the implementation of varint's
#define DISABLE_VS_WARNINGS(w)
Definition warnings.h:18