34 #include <boost/filesystem.hpp> 35 #include <boost/range/adaptor/reversed.hpp> 60 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY 61 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "blockchain" 63 #define FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE (100*1024*1024) // 100 MB 65 #define FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE (100*1024*1024) // 100 MB 84 #define MERROR_VER(x) MCERROR("verify", x) 87 #define BLOCK_REWARD_OVERESTIMATE (10 * 1000000000000) 94 } mainnet_hard_forks[] = {
96 { 1, 1, 0, 1341378000 },
97 { 6, 307500, 0, 1538815057 },
98 { 7, 324500, 0, 1538985600 },
99 { 8, 589169, 0, 1562547600 },
100 { 9, 862866, 0, 1595615809 },
101 { 10, 1175315, 0, 1632999041 },
102 { 11, 1811310, 0, 1709652642 },
104 static const uint64_t mainnet_hard_fork_version_1_till = 307499;
106 static const struct {
111 } testnet_hard_forks[] = {
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 },
119 { 11, 1455270, 0, 1693256672 }
121 static const uint64_t testnet_hard_fork_version_1_till = 190059;
123 static const struct {
128 } stagenet_hard_forks[] = {
130 { 1, 1, 0, 1341378000 },
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 },
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),
150 m_long_term_effective_median_block_weight(0),
151 m_long_term_block_weights_cache_tip_hash(
crypto::null_hash),
153 m_difficulty_for_next_block_top_hash(
crypto::null_hash),
154 m_difficulty_for_next_block(1),
156 m_batch_success(
true)
164 catch (
const std::exception &e) { }
190 template <
class visitor_t>
191 bool 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 207 std::vector<output_data_t> outputs;
210 auto it = m_scan_table.find(tx_prefix_hash);
211 if (it != m_scan_table.end())
213 auto its = it->second.find(tx_in_to_key.
k_image);
214 if (its != it->second.end())
216 outputs = its->second;
226 if (absolute_offsets.size() != outputs.size())
241 if (outputs.size() < absolute_offsets.size() && outputs.size() > 0)
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]);
252 if (add_offsets.size() != add_outputs.size())
263 outputs.insert(outputs.end(), add_outputs.begin(), add_outputs.end());
268 for (
const uint64_t& i : absolute_offsets)
276 if (
count < outputs.size())
284 MERROR_VER(
"Failed to handle_output for output no = " <<
count <<
", with absolute offset " << i);
290 MERROR_VER(
"Output does not exist! amount = " << tx_in_to_key.
amount <<
", absolute_offset = " << i);
295 if(++
count == absolute_offsets.size() && pmax_related_block_height)
299 if(*pmax_related_block_height < h)
301 *pmax_related_block_height = h;
345 LOG_ERROR(
"Attempted to init Blockchain with null DB");
350 LOG_ERROR(
"Attempted to init Blockchain with unopened DB");
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)
365 m_hardfork =
new HardFork(*db, 1, 0);
367 m_hardfork =
new HardFork(*db, 1, testnet_hard_fork_version_1_till);
369 m_hardfork =
new HardFork(*db, 1, mainnet_hard_fork_version_1_till);
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);
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);
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);
401 MINFO(
"Blockchain not loaded, generating genesis block.");
424 uint64_t timestamp_diff =
time(NULL) - top_block_timestamp;
427 if(!top_block_timestamp)
428 timestamp_diff =
time(NULL) - 1397818133;
432 m_async_work_idle = std::unique_ptr < boost::asio::io_service::work > (
new boost::asio::io_service::work(m_async_service));
434 m_async_pool.create_thread(boost::bind(&boost::asio::io_service::run, &m_async_service));
436 #if defined(PER_BLOCK_CHECKPOINT) 438 load_compiled_in_block_hashes(get_checkpoints);
452 if (ideal_hf_version <= 1 || ideal_hf_version == top_block.
major_version)
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);
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);
466 std::vector<transaction> popped_txs;
469 m_db->pop_block(popped_block, popped_txs);
473 catch (
const std::exception& e)
475 MERROR(
"Error popping block from blockchain: " << e.what());
480 MERROR(
"Error popping block from blockchain, throwing!");
486 if (num_popped_blocks > 0)
488 m_timestamps_and_difficulties_height = 0;
503 if (!update_next_cumulative_weight_limit())
513 if(top_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));
519 if(addr_outs.empty()) {
520 MGINFO(
"Recomputing address_outputs database...");
522 uint64_t diff = top_height - 1175200;
523 for(
auto i = 0; i < diff; i++) {
525 std::vector<transaction> popped_txs;
528 m_db->pop_block(popped_block, popped_txs);
530 catch (
const std::exception& e)
532 MERROR(
"Error popping block from blockchain: " << e.what());
537 MERROR(
"Error popping block from blockchain, throwing!");
548 MGINFO(
"Address_outputs database recomputed OK");
561 uint64_t private_to_public_fork_height = m_nettype ==
MAINNET ? 1175315 : 1086402;
562 if(top_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...");
571 uint64_t working_height = private_to_public_fork_height;
572 while (working_height <= top_height) {
576 const auto &txout = boost::get<txout_to_key_public>(vout.target);
582 for (
auto tx : transactions){
584 std::unordered_set<crypto::public_key> addr_tx_addresses;
585 for (
size_t i = 0; i < tx.vin.size(); i++){
588 const auto &txin = boost::get<txin_to_key_public>(tx.vin[i]);
590 const auto &txout = boost::get<txout_to_key_public>(parent_tx.vout[txin.relative_offset].target);
592 if(addr_tx_addresses.find(combined_key) == addr_tx_addresses.end()){
594 addr_tx_addresses.emplace(combined_key);
598 for(
size_t i = 0; i < tx.vout.size(); i++){
599 const auto &txout = boost::get<txout_to_key_public>(tx.vout[i].target);
601 if(addr_tx_addresses.find(combined_key) == addr_tx_addresses.end()){
603 addr_tx_addresses.emplace(combined_key);
609 MGINFO(
"Addr_txs database recomputed OK");
624 bool res =
init(db, nettype, offline, NULL);
643 catch (
const std::exception& e)
645 MERROR(
std::string(
"Error syncing blockchain db: ") + e.what() +
"-- shutting down now to prevent issues!");
650 MERROR(
"There was an issue storing the blockchain, shutting down now to prevent issues!");
655 if(m_show_time_stats)
656 MINFO(
"Blockchain stored OK, took: " <<
save <<
" ms");
664 MTRACE(
"Stopping blockchain read/write activity");
667 m_async_work_idle.reset();
668 m_async_pool.join_all();
669 m_async_service.stop();
679 MTRACE(
"Local blockchain read/write activity stopped successfully");
682 catch (
const std::exception& e)
688 LOG_ERROR(
"There was an issue closing/storing the blockchain, shutting down now to prevent issues!");
711 if (blockchain_height > 0)
712 nblocks = std::min(nblocks, blockchain_height - 1);
713 for (i=0; i < nblocks; ++i)
715 pop_block_from_blockchain();
718 catch (
const std::exception& e)
720 LOG_ERROR(
"Error when popping blocks after processing " << i <<
" blocks: " << e.what());
733 block Blockchain::pop_block_from_blockchain()
738 m_timestamps_and_difficulties_height = 0;
741 std::vector<transaction> popped_txs;
747 m_db->pop_block(popped_block, popped_txs);
751 catch (
const std::exception& e)
753 LOG_ERROR(
"Error popping block from blockchain: " << e.what());
758 LOG_ERROR(
"Error popping block from blockchain, throwing!");
788 bool r = m_tx_pool.
add_tx(tx, tvc,
true,
true,
false,
version);
791 LOG_ERROR(
"Error returning transaction to tx_pool");
796 MWARNING(pruned <<
" pruned txes could not be added back to the txpool");
798 m_blocks_longhash_table.clear();
799 m_scan_table.clear();
800 m_blocks_txs_check.clear();
801 m_check_txin_table.clear();
807 invalidate_block_template_cache();
816 m_timestamps_and_difficulties_height = 0;
817 m_alternative_chains.clear();
818 invalidate_block_template_cache();
825 if (!update_next_cumulative_weight_limit())
871 bool genesis_included =
false;
873 while(current_back_offset < sz)
877 if(sz-current_back_offset == 0)
879 genesis_included =
true;
883 ++current_back_offset;
887 current_multiplier *= 2;
888 current_back_offset += current_multiplier;
893 if (!genesis_included)
915 catch (
const std::exception& e)
917 MERROR(
std::string(
"Something went wrong fetching block hash by height: ") + e.what());
944 blocks_ext_by_hash::const_iterator it_alt = m_alternative_chains.find(h);
945 if (m_alternative_chains.end() != it_alt)
947 blk = it_alt->second.bl;
953 catch (
const std::exception& e)
973 if (m_fixed_difficulty)
975 return m_db->
height() ? m_fixed_difficulty : 1;
987 if (top_hash == m_difficulty_for_next_block_top_hash)
988 return m_difficulty_for_next_block;
992 std::vector<uint64_t> timestamps;
993 std::vector<difficulty_type> difficulties;
998 uint64_t v6height = 0, v7height = 0, v8height = 0;
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;
1008 v6height = stagenet_hard_forks[5].height;
1009 v7height = stagenet_hard_forks[5].height;
1010 v8height = stagenet_hard_forks[5].height;
1024 m_timestamps.clear();
1025 m_difficulties.clear();
1027 difficultyBlocksCount =
height - v8height;
1036 if (m_timestamps_and_difficulties_height != 0 && ((
height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= difficultyBlocksCount)
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());
1047 m_timestamps_and_difficulties_height =
height;
1048 timestamps = m_timestamps;
1049 difficulties = m_difficulties;
1058 difficulties.clear();
1061 timestamps.reserve(
height - offset);
1062 difficulties.reserve(
height - offset);
1064 for (; offset <
height; offset++)
1070 m_timestamps_and_difficulties_height =
height;
1071 m_timestamps = timestamps;
1072 m_difficulties = difficulties;
1079 m_difficulty_for_next_block_top_hash = top_hash;
1080 m_difficulty_for_next_block = diff;
1089 std::vector<time_t> timestamps(
blocks);
1108 const size_t V7_DIFFICULTY_BLOCKS_COUNT = 735;
1109 const size_t V7_DIFFICULTY_TARGET = 120;
1111 std::vector<uint64_t> timestamps;
1112 std::vector<difficulty_type> difficulties;
1114 uint64_t start_height = v7height - V7_DIFFICULTY_BLOCKS_COUNT;
1117 for(
uint64_t i = 0; start_height + i < v7height; i++) {
1136 timestamps.erase(timestamps.begin());
1137 difficulties.erase(difficulties.begin());
1140 diff = difficulties.back() +
next_difficulty(timestamps, difficulties, V7_DIFFICULTY_TARGET, 1);
1144 m_timestamps.clear();
1145 m_difficulties.clear();
1152 bool Blockchain::rollback_blockchain_switching(std::list<block>& original_chain,
uint64_t rollback_height)
1158 if (rollback_height > m_db->
height())
1163 m_timestamps_and_difficulties_height = 0;
1166 while (m_db->
height() != rollback_height)
1168 pop_block_from_blockchain();
1175 for (
auto& bl : original_chain)
1178 bool r = handle_block_to_main_chain(bl, bvc);
1184 MINFO(
"Rollback to height " << rollback_height <<
" was successful.");
1185 if (!original_chain.empty())
1187 MINFO(
"Restoration to previous blockchain successful as well.");
1194 bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::const_iterator>& alt_chain,
bool discard_disconnected_chain)
1200 m_timestamps_and_difficulties_height = 0;
1203 CHECK_AND_ASSERT_MES(alt_chain.size(),
false,
"switch_to_alternative_blockchain: empty chain passed");
1206 if (!m_db->
block_exists(alt_chain.front()->second.bl.prev_id))
1208 LOG_ERROR(
"Attempting to move to an alternate chain, but it doesn't appear to connect to the main chain!");
1214 std::list<block> disconnected_chain;
1215 while (m_db->
top_block_hash() != alt_chain.front()->second.bl.prev_id)
1217 block b = pop_block_from_blockchain();
1218 disconnected_chain.push_front(b);
1221 auto split_height = m_db->
height();
1224 for(
auto alt_ch_iter = alt_chain.begin(); alt_ch_iter != alt_chain.end(); alt_ch_iter++)
1226 auto ch_ent = *alt_ch_iter;
1230 bool r = handle_block_to_main_chain(ch_ent->second.bl, bvc);
1236 MERROR(
"Failed to switch to alternative blockchain");
1241 rollback_blockchain_switching(disconnected_chain, split_height);
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++);
1250 for(
auto alt_ch_to_orph_iter = alt_ch_iter; alt_ch_to_orph_iter != alt_chain.end(); )
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++);
1260 const size_t discarded_blocks = disconnected_chain.size();
1261 if(!discard_disconnected_chain)
1264 for (
auto& old_ch_ent : disconnected_chain)
1267 bool r = handle_alternative_block(old_ch_ent,
get_block_hash(old_ch_ent), bvc);
1270 MERROR(
"Failed to push ex-main chain blocks to alternative chain ");
1278 for (
auto ch_ent: alt_chain)
1280 m_alternative_chains.erase(ch_ent);
1285 std::shared_ptr<tools::Notify> reorg_notify = m_reorg_notify;
1290 MGINFO_GREEN(
"REORGANIZE SUCCESS! on height: " << split_height <<
", new blockchain size: " << m_db->
height());
1296 difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(
const std::list<blocks_ext_by_hash::const_iterator>& alt_chain, block_extended_info& bei)
const 1298 if (m_fixed_difficulty)
1300 return m_db->
height() ? m_fixed_difficulty : 1;
1304 std::vector<uint64_t> timestamps;
1305 std::vector<difficulty_type> cumulative_difficulties;
1307 uint64_t v6height = 0, v7height = 0, v8height = 0;
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;
1318 v6height = stagenet_hard_forks[5].height;
1319 v7height = stagenet_hard_forks[5].height;
1320 v8height = stagenet_hard_forks[5].height;
1328 if((bei.height >= v8height) && (bei.height < v8height + 720))
1331 difficultyBlocksCount = bei.height - v8height;
1336 if(alt_chain.size()< difficultyBlocksCount)
1342 size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front()->second.height : bei.height;
1344 size_t main_chain_count = difficultyBlocksCount - std::min(static_cast<size_t>(difficultyBlocksCount), alt_chain.size());
1347 main_chain_count = std::min(main_chain_count, main_chain_stop_offset);
1349 size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count;
1351 if(!main_chain_start_offset)
1352 ++main_chain_start_offset;
1355 for(; main_chain_start_offset < main_chain_stop_offset; ++main_chain_start_offset)
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);
1364 for (
auto it : alt_chain)
1366 timestamps.push_back(it->second.bl.timestamp);
1367 cumulative_difficulties.push_back(it->second.cumulative_difficulty);
1374 timestamps.resize(static_cast<size_t>(difficultyBlocksCount));
1375 cumulative_difficulties.resize(static_cast<size_t>(difficultyBlocksCount));
1377 size_t max_i = timestamps.size()-1;
1379 for(
auto it: boost::adaptors::reverse(alt_chain))
1381 timestamps[max_i -
count] = it->second.bl.timestamp;
1382 cumulative_difficulties[max_i -
count] = it->second.cumulative_difficulty;
1384 if(
count >= difficultyBlocksCount)
1409 MWARNING(
"The miner transaction in block has invalid height: " << boost::get<txin_gen>(b.
miner_tx.
vin[0]).height <<
", expected: " <<
height);
1433 std::string coinbase_burn_address_viewkey_hex_str =
"5866666666666666666666666666666666666666666666666666666666666666";
1434 std::string coinbase_burn_address_spendkey_hex_str =
"9511fabcb699b4f9dffc1779713d0dd7eb1ca56ba5b8ab8d3253a0a6ccf736b3";
1436 const auto out = boost::get<txout_to_key_public>(o.target);
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");
1450 etn_in_use += o.amount;
1451 partial_block_reward =
false;
1456 MERROR_VER(
"miner tx output " <<
print_etn(o.amount) <<
" is not a valid decomposed amount");
1462 std::vector<uint64_t> last_blocks_weights;
1466 MERROR_VER(
"block weight " << cumulative_block_weight <<
" is bigger than allowed for this blockchain");
1469 if(base_reward + fee < etn_in_use && already_generated_coins > 0)
1477 if(base_reward + fee != etn_in_use && already_generated_coins > 0)
1479 MDEBUG(
"coinbase transaction doesn't use full amount of block reward: spent: " << etn_in_use <<
", block reward " << base_reward + fee <<
"(" << base_reward <<
"+" << fee <<
")");
1489 if(base_reward + fee != etn_in_use)
1490 partial_block_reward =
true;
1491 base_reward = etn_in_use - fee;
1497 void Blockchain::get_last_n_blocks_weights(std::vector<uint64_t>& weights,
size_t count)
const 1508 size_t start_offset = h - std::min<size_t>(h,
count);
1521 bool cached =
false;
1525 if (tip_height < blockchain_height &&
count == (
size_t)m_long_term_block_weights_cache_rolling_median.
size())
1528 cached = tip_hash == m_long_term_block_weights_cache_tip_hash;
1533 MTRACE(
"requesting " <<
count <<
" from " << start_height <<
", cached");
1534 return m_long_term_block_weights_cache_rolling_median.
median();
1539 if (tip_height > 0 &&
count == (
size_t)m_long_term_block_weights_cache_rolling_median.
size() && tip_height < blockchain_height)
1542 if (old_tip_hash == m_long_term_block_weights_cache_tip_hash)
1544 MTRACE(
"requesting " <<
count <<
" from " << start_height <<
", incremental");
1545 m_long_term_block_weights_cache_tip_hash = tip_hash;
1547 return m_long_term_block_weights_cache_rolling_median.
median();
1551 MTRACE(
"requesting " <<
count <<
" from " << start_height <<
", uncached");
1553 m_long_term_block_weights_cache_tip_hash = tip_hash;
1554 m_long_term_block_weights_cache_rolling_median.
clear();
1556 m_long_term_block_weights_cache_rolling_median.
insert(w);
1557 return m_long_term_block_weights_cache_rolling_median.
median();
1563 return m_current_block_cumul_weight_limit;
1569 return m_current_block_cumul_weight_median;
1586 size_t median_weight;
1593 if (m_btc_valid && !from_block) {
1600 MDEBUG(
"Using cached template");
1603 diffic = m_btc_difficulty;
1605 expected_reward = m_btc_expected_reward;
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();
1617 auto it_prev = m_alternative_chains.find(*from_block);
1619 if(it_prev == m_alternative_chains.end() && !parent_in_main)
1621 MERROR(
"Unknown from block");
1626 std::list<blocks_ext_by_hash::const_iterator> alt_chain;
1628 std::vector<uint64_t> timestamps;
1629 if (!build_alt_chain(*from_block, alt_chain, timestamps, bvc))
1637 height = from_block_height + 1;
1641 height = alt_chain.back()->second.height + 1;
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;
1665 diffic = get_next_difficulty_for_alternative_chain(alt_chain, bei);
1673 median_weight = m_current_block_cumul_weight_limit / 2;
1680 if (!check_block_timestamp(b, median_ts))
1694 #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) 1695 size_t real_txs_weight = 0;
1699 auto cur_res = m_tx_pool.m_transactions.find(cur_hash);
1700 if (cur_res == m_tx_pool.m_transactions.end())
1702 LOG_ERROR(
"Creating block template: error: transaction not found");
1706 real_txs_weight += cur_tx.
weight;
1707 real_fee += cur_tx.
fee;
1710 LOG_ERROR(
"Creating block template: error: invalid transaction weight");
1716 LOG_ERROR(
"Creating block template: error: cannot get inputs amount");
1720 LOG_ERROR(
"Creating block template: error: invalid fee");
1723 if (txs_weight != real_txs_weight)
1725 LOG_ERROR(
"Creating block template: error: wrongly calculated transaction weight");
1727 if (fee != real_fee)
1729 LOG_ERROR(
"Creating block template: error: wrongly calculated fee");
1732 ", median weight " << median_weight <<
1733 ", already generated coins " << already_generated_coins <<
1734 ", transaction weight " << txs_weight <<
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);
1748 #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) 1750 ", cumulative weight " << cumulative_weight);
1752 for (
size_t try_count = 0; try_count != 10; ++try_count)
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);
1758 if (coinbase_weight > cumulative_weight - txs_weight)
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");
1768 if (coinbase_weight < cumulative_weight - txs_weight)
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");
1785 MDEBUG(
"Miner tx creation has no luck with delta_extra size = " << delta <<
" and " << delta - 1);
1786 cumulative_weight += delta - 1;
1789 MDEBUG(
"Setting extra for block: " << b.
miner_tx.
extra.size() <<
", try_count=" << try_count);
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");
1801 if(!m_fallback_to_pow && hf_version >= 8) {
1807 LOG_ERROR(
"Failed to create_block_template with " << 10 <<
" tries");
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.");
1827 for(
auto &
key : public_keys) {
1845 bool Blockchain::complete_timestamps_vector(
uint64_t start_top_height, std::vector<uint64_t>& timestamps)
const 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)
1865 bool Blockchain::build_alt_chain(
const crypto::hash &prev_id, std::list<blocks_ext_by_hash::const_iterator>& alt_chain, std::vector<uint64_t> ×tamps,
block_verification_context& bvc)
const 1868 blocks_ext_by_hash::const_iterator alt_it = m_alternative_chains.find(prev_id);
1870 while(alt_it != m_alternative_chains.end())
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);
1879 if(!alt_chain.empty())
1886 if (!m_db->
block_exists(alt_chain.front()->second.bl.prev_id))
1888 MERROR(
"alternate chain does not appear to connect to main chain...");
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);
1903 CHECK_AND_ASSERT_MES(parent_in_main,
false,
"internal error: broken imperative condition: parent_in_main");
1921 m_timestamps_and_difficulties_height = 0;
1923 if(0 == block_height)
1932 if(!m_fallback_to_pow) {
1938 if(!m_validators->
isValid()) {
1944 MERROR_VER(
"Block with id: " <<
id << std::endl <<
" has wrong digital signature");
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());
1965 LOG_PRINT_L1(
"Block with id: " <<
id << std::endl <<
"has old version for height " << block_height);
1972 auto it_prev = m_alternative_chains.find(b.
prev_id);
1974 if(it_prev != m_alternative_chains.end() || parent_in_main)
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))
1983 block_extended_info bei = boost::value_initialized<block_extended_info>();
1986 bei.height = prev_height + 1;
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));
1992 std::vector<uint8_t> prev_signatory = alt_chain.size() ? it_prev->second.bl.signatory : m_db->
get_block(b.
prev_id).
signatory;
1998 if(!check_block_timestamp(timestamps, b))
2000 MERROR_VER(
"Block with id: " <<
id << std::endl <<
" for alternative chain, has invalid timestamp: " << b.
timestamp);
2005 bool is_a_checkpoint;
2006 if(!m_checkpoints.
check_block(bei.height,
id, is_a_checkpoint))
2008 LOG_ERROR(
"CHECKPOINT VALIDATION FAILED");
2014 difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei);
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);
2025 if(!prevalidate_miner_transaction(b, bei.height))
2036 if (alt_chain.size())
2038 bei.cumulative_difficulty = it_prev->second.cumulative_difficulty;
2045 bei.cumulative_difficulty += current_diff;
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);
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);
2059 bool r = switch_to_alternative_blockchain(alt_chain,
true);
2066 else if(main_chain_cumulative_difficulty < bei.cumulative_difficulty)
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);
2071 bool r = switch_to_alternative_blockchain(alt_chain,
false);
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);
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
2100 if(start_offset >= m_db->
height())
2108 for(
const auto& blk :
blocks)
2110 std::vector<crypto::hash> missed_ids;
2112 CHECK_AND_ASSERT_MES(!missed_ids.size(),
false,
"has missed transactions in own block in main blockchain");
2123 if(start_offset >=
height)
2127 for(
size_t i = start_offset; i < start_offset +
count && i <
height;i++)
2152 std::vector<std::pair<cryptonote::blobdata,block>>
blocks;
2157 std::vector<crypto::hash> missed_tx_ids;
2166 if (missed_tx_ids.size() != 0)
2171 LOG_ERROR(
"Error retrieving blocks, missed " << missed_tx_ids.size()
2172 <<
" transactions for block with hash: " <<
get_block_hash(bl.second)
2180 rsp.missed_ids.insert(rsp.missed_ids.end(), missed_tx_ids.begin(), missed_tx_ids.end());
2198 blocks.reserve(m_alternative_chains.size());
2199 for (
const auto& alt_bl: m_alternative_chains)
2201 blocks.push_back(alt_bl.second.bl);
2210 return m_alternative_chains.size();
2221 while (num_outs > 0)
2246 res.outs.reserve(req.outputs.size());
2248 std::vector<cryptonote::output_data_t> data;
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)
2256 amounts.push_back(i.amount);
2257 offsets.push_back(i.index);
2260 if (data.size() != req.outputs.size())
2262 MERROR(
"Unexpected output data size: expected " << req.outputs.size() <<
", got " << data.size());
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});
2270 for (
size_t i = 0; i < req.outputs.size(); ++i)
2273 res.outs[i].txid = toi.first;
2277 catch (
const std::exception &e)
2287 key = o_data.pubkey;
2288 mask = o_data.commitment;
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;
2311 if (to_height > 0 && to_height < from_height)
2314 const uint64_t real_start_height = start_height;
2315 if (from_height > start_height)
2316 start_height = from_height;
2318 distribution.clear();
2322 if (start_height >= db_height || to_height >= db_height)
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);
2332 if (start_height > 0)
2334 base = distribution[0];
2335 distribution.erase(distribution.begin());
2355 if(qblock_ids.empty())
2357 MCERROR(
"net.p2p",
"Client sent wrong NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << qblock_ids.size() <<
", dropping connection");
2365 if(qblock_ids.back() != gen_hash)
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");
2374 auto bl_it = qblock_ids.begin();
2376 for(; bl_it != qblock_ids.end(); bl_it++)
2383 catch (
const std::exception& e)
2385 MWARNING(
"Non-critical error trying to find block by hash in BlockchainDB, hash: " << *bl_it);
2392 if(bl_it == qblock_ids.end())
2394 MERROR(
"Internal error handling connection, can't find split point");
2399 starter_offset = split_height;
2416 MERROR(
"Attempted to get block difficulty for height above blockchain height");
2426 template<
class t_
ids_container,
class t_blocks_container,
class t_missed_container>
2433 for (
const auto& block_hash : block_ids)
2443 LOG_ERROR(
"Invalid block: " << block_hash);
2445 missed_bs.push_back(block_hash);
2449 missed_bs.push_back(block_hash);
2451 catch (
const std::exception& e)
2461 template<
class t_
ids_container,
class t_tx_container,
class t_missed_container>
2468 for (
const auto& tx_hash : txs_ids)
2475 else if (!pruned && m_db->
get_tx_blob(tx_hash, tx))
2478 missed_txs.push_back(tx_hash);
2480 catch (
const std::exception& e)
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);
2495 throw std::runtime_error(
"Internal error getting transaction version");
2499 template<
class t_
ids_container,
class t_tx_container,
class t_missed_container>
2506 for (
const auto& tx_hash : txs_ids)
2516 MERROR(
"Prunable data hash not found for " << tx_hash);
2520 std::get<3>(txs.back()).clear();
2523 missed_txs.push_back(tx_hash);
2525 catch (
const std::exception& e)
2533 template<
class t_
ids_container,
class t_tx_container,
class t_missed_container>
2540 for (
const auto& tx_hash : txs_ids)
2555 missed_txs.push_back(tx_hash);
2557 catch (
const std::exception& e)
2581 uint64_t stop_height = current_height;
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>();
2618 bool 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 2624 if(req_start_block > 0)
2627 if (req_start_block >= m_db->
height())
2631 start_height = req_start_block;
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)));
2652 std::vector<crypto::hash> mis;
2653 std::vector<cryptonote::blobdata> txs;
2656 size +=
blocks.back().first.first.size();
2657 for (
const auto &t: txs)
2661 blocks.back().second.reserve(txs.size());
2662 for (
size_t i = 0; i < txs.size(); ++i)
2675 return add_block_as_invalid(bei, h);
2678 bool Blockchain::add_block_as_invalid(
const block_extended_info& bei,
const crypto::hash& h)
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());
2695 LOG_PRINT_L2(
"block " <<
id <<
" found in main chain");
2699 if(m_alternative_chains.count(
id))
2701 LOG_PRINT_L2(
"block " <<
id <<
" found in m_alternative_chains");
2705 if(m_invalid_blocks.count(
id))
2707 LOG_PRINT_L2(
"block " <<
id <<
" found in m_invalid_blocks");
2718 return handle_block_to_main_chain(bl,
id, bvc);
2737 bool Blockchain::check_for_double_spend(
const transaction& tx, key_images_container& keys_this_block)
const 2741 struct add_transaction_input_visitor:
public boost::static_visitor<bool>
2743 key_images_container& m_spent_keys;
2745 add_transaction_input_visitor(key_images_container& spent_keys,
BlockchainDB* db) :
2746 m_spent_keys(spent_keys), m_db(db)
2760 auto r = m_spent_keys.insert(ki);
2771 bool operator()(
const txin_gen& tx)
const 2791 if(!boost::apply_visitor(add_transaction_input_visitor(keys_this_block, m_db), in))
2808 MERROR_VER(
"get_tx_outputs_gindexs failed to find transaction with id = " << tx_id);
2829 MERROR_VER(
"get_tx_outputs_gindexs failed to find transaction with id = " << tx_id);
2839 indexs = indices.front();
2845 #if defined(PER_BLOCK_CHECKPOINT) 2847 if (m_db->
height() < m_blocks_hash_check.size())
2852 if(m_show_time_stats)
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);
2874 #if defined(PER_BLOCK_CHECKPOINT) 2876 if (m_db->
height() < m_blocks_hash_check.size() && kept_by_block)
2878 max_used_block_id = null_hash;
2879 max_used_block_height = 0;
2887 if(m_show_time_stats)
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;
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());
2910 for (
auto &o: tx.
vout) {
2920 for (
const auto &o: tx.
vout) {
2923 const txout_to_key &out_to_key = boost::get<txout_to_key>(o.target);
2946 std::vector<uint64_t> supported_prefixes{address_prefix, integrated_address_prefix, subaddress_prefix};
2948 if(std::find(supported_prefixes.begin(), supported_prefixes.end(), out_to_key_public.
m_address_prefix) == supported_prefixes.end()) {
2966 const auto &in_to_key = boost::get<txin_to_key>(in);
2983 const auto &in_to_key = boost::get<txin_to_key_public>(in);
3002 bool Blockchain::expand_transaction_2(
transaction &tx,
const crypto::hash &tx_prefix_hash,
const std::vector<std::vector<rct::ctkey>> &pubkeys)
3016 size_t sig_index = 0;
3017 if(pmax_used_block_height)
3018 *pmax_used_block_height = 0;
3026 if (tx.
version > max_tx_version)
3028 MERROR_VER(
"transaction version " << (
unsigned)tx.
version <<
" is higher than max accepted version " << max_tx_version);
3034 if (tx.
version < min_tx_version)
3036 MERROR_VER(
"transaction version " << (
unsigned)tx.
version <<
" is lower than min accepted version " << min_tx_version);
3045 std::unordered_set<std::string> ins;
3046 for(
const auto& in: tx.
vin)
3064 for (
size_t i = 0; i < tx.
vin.size(); ++i)
3070 if (in_to_key.
amount <= 0)
3115 if (hf_version >= 6)
3117 size_t n_unmixable = 0, n_mixable = 0;
3118 size_t mixin = std::numeric_limits<size_t>::max();
3120 for (
const auto& txin : tx.
vin)
3125 const txin_to_key& in_to_key = boost::get<txin_to_key>(txin);
3132 <<
"), and more than one mixable input with unmixable inputs");
3138 if (in_to_key.
amount == 0)
3150 if (n_outputs <= min_mixin)
3167 if (mixin < min_mixin)
3169 if (n_unmixable == 0)
3177 MERROR_VER(
"Tx " <<
get_transaction_hash(tx) <<
" has too low ring size (" << (mixin + 1) <<
"), and more than one mixable input with unmixable inputs");
3187 for (
size_t n = 0; n < tx.
vin.size(); ++n)
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)
3195 MERROR_VER(
"transaction has unsorted inputs");
3199 last_key_image = &in_to_key.
k_image;
3203 auto it = m_check_txin_table.find(tx_prefix_hash);
3204 if(it == m_check_txin_table.end())
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());
3211 std::vector<std::vector<rct::ctkey>> pubkeys(tx.
vin.size());
3212 std::vector < uint64_t > results;
3213 results.resize(tx.
vin.size(), 0);
3220 for (
const auto& txin : tx.
vin)
3225 const txin_to_key& in_to_key = boost::get<txin_to_key>(txin);
3240 #if defined(CACHE_VIN_RESULTS) 3241 auto itk = it->second.find(in_to_key.
k_image);
3242 if(itk != it->second.end())
3260 it->second[in_to_key.
k_image] =
false;
3262 if (pmax_used_block_height)
3264 MERROR_VER(
" *pmax_used_block_height: " << *pmax_used_block_height);
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);
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])
3281 it->second[in_to_key.
k_image] =
false;
3284 if (pmax_used_block_height)
3286 MERROR_VER(
"*pmax_used_block_height: " << *pmax_used_block_height);
3291 it->second[in_to_key.
k_image] =
true;
3299 waiter.
wait(&tpool);
3301 bool failed =
false;
3302 for (
size_t i = 0; i < tx.
vin.size(); i++)
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])
3312 MERROR_VER(
"Failed to check ring signatures!");
3322 std::vector<const crypto::public_key *> p_output_keys;
3323 p_output_keys.reserve(pubkeys.size());
3324 for (
auto &
key : pubkeys)
3350 if (median_block_weight < min_block_weight)
3351 median_block_weight = min_block_weight;
3357 div128_32(hi, lo, min_block_weight, &hi, &lo);
3358 div128_32(hi, lo, median_block_weight, &hi, &lo);
3366 uint64_t unscaled_fee_base = (fee_base * min_block_weight / median_block_weight);
3367 lo = mul128(unscaled_fee_base, block_reward, &hi);
3373 div128_32(hi, lo, 1000000, &hi, &lo);
3378 uint64_t qlo = (lo + mask - 1) / mask * mask;
3391 uint64_t already_generated_coins = 0;
3395 median = m_current_block_cumul_weight_limit / 2;
3408 needed_fee = tx_weight * fee_per_byte;
3411 needed_fee = (needed_fee + mask - 1) / mask * mask;
3420 }
else if (version < 11 && version >= 6) {
3432 needed_fee = tx_weight / 1024;
3433 needed_fee += (tx_weight % 1024) ? 1 : 0;
3434 needed_fee *= fee_per_kb;
3437 if (fee < needed_fee - needed_fee / 50)
3454 }
else if (version < 11 && version >= 6) {
3465 std::vector<uint64_t> weights;
3467 weights.reserve(grace_blocks);
3468 for (
size_t i = 0; i < grace_blocks; ++i)
3469 weights.push_back(min_block_weight);
3472 if(
median <= min_block_weight)
3473 median = min_block_weight;
3486 MDEBUG(
"Estimating " << grace_blocks <<
"-block fee at " <<
print_etn(fee) <<
"/" << (per_byte ?
"byte" :
"kB"));
3493 bool Blockchain::is_tx_spendtime_unlocked(
uint64_t unlock_time)
const 3520 bool 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)
3528 struct outputs_visitor
3530 std::vector<rct::ctkey >& m_output_keys;
3532 outputs_visitor(std::vector<rct::ctkey>& output_keys,
const Blockchain& bch) :
3533 m_output_keys(output_keys), m_bch(bch)
3539 if (!m_bch.is_tx_spendtime_unlocked(unlock_time))
3541 MERROR_VER(
"One of outputs for one of inputs has wrong tx.unlock_time = " << unlock_time);
3550 m_output_keys.push_back(
rct::ctkey({rct::pk2rct(pubkey), commitment}));
3555 output_keys.clear();
3558 outputs_visitor vi(output_keys, *
this);
3559 if (!scan_outputkeys_for_indexes(tx_version, txin, vi, tx_prefix_hash, pmax_related_block_height))
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());
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());
3578 uint64_t Blockchain::get_adjusted_time()
const 3586 bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps,
const block& b,
uint64_t& median_ts)
const 3607 bool Blockchain::check_block_timestamp(
const block& b,
uint64_t& median_ts)
const 3616 const auto h = m_db->
height();
3624 std::vector<uint64_t> timestamps;
3628 timestamps.reserve(h - offset);
3629 for(;offset < h; ++offset)
3634 return check_block_timestamp(timestamps, b, median_ts);
3637 void Blockchain::return_tx_to_pool(std::vector<std::pair<transaction, blobdata>> &txs)
3640 for (
auto& tx : txs)
3650 if (!m_tx_pool.
add_tx(tx.first, tx_hash, tx.second, weight, tvc,
true,
true,
false,
version))
3662 for (
const auto &txid: txids)
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))
3672 MERROR(
"Failed to remove txid " << txid <<
" from the pool");
3690 static bool seen_future_version =
false;
3695 ++blockchain_height;
3698 MERROR_VER(
"Block with id: " <<
id << std::endl <<
"has wrong prev_id: " << bl.
prev_id << std::endl <<
"expected: " << top_hash);
3706 if(!m_fallback_to_pow) {
3712 if(!m_validators->
isValid()) {
3718 MERROR_VER(
"Block with id: " <<
id << std::endl <<
" has wrong digital signature");
3723 MERROR_VER(
"Block with id: " <<
id << std::endl <<
" has the same signatory as the previous block, which is not allowed");
3734 seen_future_version =
true;
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",
"**********************************************************************");
3744 if (!m_hardfork->
check(bl))
3756 if(!check_block_timestamp(bl))
3758 MERROR_VER(
"Block with id: " <<
id << std::endl <<
"has invalid timestamp: " << bl.
timestamp);
3790 bool precomputed =
false;
3791 bool fast_check =
false;
3792 #if defined(PER_BLOCK_CHECKPOINT) 3793 if (blockchain_height < m_blocks_hash_check.size())
3796 if (memcmp(&
hash, &m_blocks_hash_check[m_db->
height()],
sizeof(
hash)) != 0)
3798 MERROR_VER(
"Block with id is INVALID: " <<
id);
3808 auto it = m_blocks_longhash_table.find(
id);
3809 if (it != m_blocks_longhash_table.end())
3812 proof_of_work = it->second;
3818 if(!
check_hash(proof_of_work, current_diffic))
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);
3830 if(!m_checkpoints.
check_block(blockchain_height,
id))
3832 LOG_ERROR(
"CHECKPOINT VALIDATION FAILED");
3840 longhash_calculating_time += m_fake_pow_calc_time;
3845 if(!prevalidate_miner_transaction(bl, blockchain_height))
3847 MERROR_VER(
"Block with id: " <<
id <<
" failed to pass prevalidation");
3853 size_t cumulative_block_weight = coinbase_weight;
3855 std::vector<std::pair<transaction, blobdata>> txs;
3856 key_images_container keys;
3867 size_t tx_index = 0;
3876 size_t tx_weight = 0;
3878 bool relayed =
false, do_not_relay =
false, double_spend_seen =
false, nonexistent_utxo_seen =
false;
3884 MERROR(
"Block with id: " <<
id <<
" attempting to add transaction already in blockchain with id: " << tx_id);
3886 return_tx_to_pool(txs);
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))
3897 MERROR_VER(
"Block with id: " <<
id <<
" has at least one unknown transaction with id: " << tx_id);
3899 return_tx_to_pool(txs);
3929 #if defined(PER_BLOCK_CHECKPOINT) 3937 MERROR_VER(
"Block with id: " <<
id <<
" has at least one transaction (id: " << tx_id <<
") with wrong inputs.");
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);
3945 return_tx_to_pool(txs);
3949 #if defined(PER_BLOCK_CHECKPOINT) 3954 if (tx_index >= m_blocks_txs_check.size() || memcmp(&m_blocks_txs_check[tx_index++], &tx_id,
sizeof(tx_id)) != 0)
3956 MERROR_VER(
"Block with id: " <<
id <<
" has at least one transaction (id: " << tx_id <<
") with wrong inputs.");
3958 add_block_as_invalid(bl,
id);
3959 MERROR_VER(
"Block with id " <<
id <<
" added as invalid because of wrong inputs in transactions");
3961 return_tx_to_pool(txs);
3969 cumulative_block_weight += tx_weight;
3972 m_blocks_txs_check.clear();
3979 MERROR_VER(
"Block with id: " <<
id <<
" has incorrect miner transaction");
3981 return_tx_to_pool(txs);
3986 size_t block_weight;
3990 block_weight = cumulative_block_weight;
3991 cumulative_difficulty = current_diffic;
3996 already_generated_coins = base_reward < (
ETN_SUPPLY-already_generated_coins) ? already_generated_coins + base_reward :
ETN_SUPPLY;
3997 if(blockchain_height)
4002 block_processing_time += m_fake_pow_calc_time;
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);
4017 LOG_ERROR(
"Error adding block with hash: " <<
id <<
" to blockchain, what = " << e.
what());
4018 m_batch_success =
false;
4020 return_tx_to_pool(txs);
4023 catch (
const std::exception& e)
4026 LOG_ERROR(
"Error adding block with hash: " <<
id <<
" to blockchain, what = " << e.what());
4027 m_batch_success =
false;
4029 return_tx_to_pool(txs);
4035 LOG_ERROR(
"Blocks that failed verification should not reach here");
4041 if (!update_next_cumulative_weight_limit())
4043 MERROR(
"Failed to update next cumulative weight limit");
4044 pop_block_from_blockchain();
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)
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");
4064 invalidate_block_template_cache();
4066 std::shared_ptr<tools::Notify> block_notify = m_block_notify;
4105 const uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights_window, db_height);
4109 return block_weight;
4111 uint64_t long_term_median = get_long_term_block_weight_median(db_height - nblocks, nblocks);
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);
4117 return long_term_block_weight;
4120 bool Blockchain::update_next_cumulative_weight_limit(
uint64_t *long_term_effective_median_block_weight)
4122 PERF_TIMER(update_next_cumulative_weight_limit);
4134 std::vector<uint64_t> weights;
4137 long_term_block_weight = weights.back();
4150 uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights_window, db_height);
4151 if (nblocks == db_height)
4153 long_term_median = get_long_term_block_weight_median(db_height - nblocks - 1, nblocks);
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);
4163 long_term_median = long_term_block_weight;
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();
4173 std::vector<uint64_t> weights;
4179 m_current_block_cumul_weight_median = effective_median_block_weight;
4182 if (m_current_block_cumul_weight_median <= full_reward_zone)
4183 m_current_block_cumul_weight_median = full_reward_zone;
4185 m_current_block_cumul_weight_limit = m_current_block_cumul_weight_median * 2;
4187 if (long_term_effective_median_block_weight)
4188 *long_term_effective_median_block_weight = m_long_term_effective_median_block_weight;
4205 LOG_PRINT_L3(
"block with id = " <<
id <<
" already exists");
4207 m_blocks_txs_check.clear();
4217 bool r = handle_alternative_block(bl,
id, bvc);
4218 m_blocks_txs_check.clear();
4224 return handle_block_to_main_chain(bl,
id, bvc);
4237 for (
const auto& pt : pts)
4240 if (pt.first >= blockchain_height)
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);
4255 std::vector<crypto::hash> txs;
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");
4281 if (m_enforce_dns_checkpoints && check_dns && !m_offline)
4288 else if (check_dns && !m_offline)
4298 MERROR(
"One or more checkpoints fetched from DNS conflicted with existing checkpoints!");
4309 m_enforce_dns_checkpoints = enforce_checkpoints;
4324 map.emplace(
id, pow);
4336 MTRACE(
"Blockchain::" << __func__);
4342 if (m_batch_success)
4348 catch (
const std::exception &e)
4350 MERROR(
"Exception in cleanup_handle_incoming_blocks: " << e.what());
4353 if (
success && m_sync_counter > 0)
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)))
4363 MDEBUG(
"Sync threshold met, syncing");
4367 m_bytes_to_sync = 0;
4370 else if(m_db_sync_mode ==
db_sync)
4382 m_blocks_longhash_table.clear();
4383 m_scan_table.clear();
4384 m_blocks_txs_check.clear();
4385 m_check_txin_table.clear();
4402 catch (
const std::exception& e)
4421 MTRACE(
"Blockchain::" << __func__);
4425 size_t total_txs = 0;
4445 if(blocks_entry.size() == 0)
4448 for (
const auto &entry : blocks_entry)
4450 bytes += entry.block.size();
4451 for (
const auto &tx_blob : entry.txs)
4453 bytes += tx_blob.size();
4455 total_txs += entry.txs.size();
4457 m_bytes_to_sync += bytes;
4458 while (!(stop_batch = m_db->
batch_start(blocks_entry.size(), bytes))) {
4459 m_blockchain_lock.
unlock();
4463 m_blockchain_lock.
lock();
4465 m_batch_success =
true;
4468 if ((
height + blocks_entry.size()) < m_blocks_hash_check.size())
4471 bool blocks_exist =
false;
4474 blocks.resize(blocks_entry.size());
4479 if(threads > m_max_prepare_blocks_threads)
4480 threads = m_max_prepare_blocks_threads;
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;
4490 for (
unsigned i = 0; i < threads; i++)
4492 for (
unsigned int j = 0; j < batches; j++, ++blockidx)
4505 MDEBUG(
"Skipping prepare blocks. New blocks don't belong to chain.");
4511 blocks_exist =
true;
4513 std::advance(it, 1);
4517 for (
unsigned i = 0; i < extra && !blocks_exist; i++, blockidx++)
4526 blocks_exist =
true;
4528 std::advance(it, 1);
4533 m_blocks_longhash_table.clear();
4536 for (
unsigned int i = 0; i < threads; i++)
4538 unsigned nblocks = batches;
4542 thread_height += nblocks;
4545 waiter.
wait(&tpool);
4550 for (
const auto & map : maps)
4552 m_blocks_longhash_table.insert(map.begin(), map.end());
4562 MDEBUG(
"Skipping remainder of prepare blocks. Blocks exist.");
4566 m_fake_scan_time = 0;
4567 m_fake_pow_calc_time = 0;
4569 m_scan_table.clear();
4570 m_check_txin_table.clear();
4573 m_fake_pow_calc_time = prepare / blocks_entry.size();
4575 if (blocks_entry.size() > 1 && threads > 1 && m_show_time_stats)
4576 MDEBUG(
"Prepare blocks took: " << prepare <<
" ms");
4581 std::vector < uint64_t > amounts;
4583 std::map<uint64_t, std::vector<uint64_t>> offset_map;
4585 std::map<uint64_t, std::vector<output_data_t>> tx_map;
4586 std::vector<std::pair<cryptonote::transaction, crypto::hash>> txes(total_txs);
4588 #define SCAN_TABLE_QUIT(m) \ 4591 m_scan_table.clear(); \ 4596 size_t tx_index = 0, block_index = 0;
4597 for (
const auto &entry : blocks_entry)
4602 for (
const auto &tx_blob : entry.txs)
4604 if (tx_index >= txes.size())
4614 auto its = m_scan_table.find(tx_prefix_hash);
4615 if (its != m_scan_table.end())
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());
4625 for (
const auto &txin : tx.
vin)
4627 const txin_to_key &in_to_key = boost::get < txin_to_key > (txin);
4630 auto it = its->second.find(in_to_key.
k_image);
4631 if (it != its->second.end())
4634 amounts.push_back(in_to_key.
amount);
4639 std::sort(amounts.begin(), amounts.end());
4640 auto last = std::unique(amounts.begin(), amounts.end());
4641 amounts.erase(last, amounts.end());
4644 for (
const uint64_t &amount : amounts)
4646 if (offset_map.find(amount) == offset_map.end())
4647 offset_map.emplace(amount, std::vector<uint64_t>());
4649 if (tx_map.find(amount) == tx_map.end())
4650 tx_map.emplace(amount, std::vector<output_data_t>());
4656 for (
const auto &txin : tx.
vin)
4658 const txin_to_key &in_to_key = boost::get < txin_to_key > (txin);
4661 for (
const auto & offset : absolute_offsets)
4662 offset_map[in_to_key.
amount].push_back(offset);
4671 for (
auto &offsets : offset_map)
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());
4683 if (threads > 1 && amounts.size() > 1)
4687 for (
size_t i = 0; i < amounts.size(); i++)
4692 waiter.
wait(&tpool);
4696 for (
size_t i = 0; i < amounts.size(); i++)
4705 for (
const auto &entry : blocks_entry)
4710 for (
const auto &tx_blob : entry.txs)
4712 if (tx_index >= txes.size())
4715 const crypto::hash &tx_prefix_hash = txes[tx_index].second;
4718 auto its = m_scan_table.find(tx_prefix_hash);
4719 if (its == m_scan_table.end())
4724 for (
const auto &txin : tx.
vin)
4726 const txin_to_key &in_to_key = boost::get < txin_to_key > (txin);
4729 std::vector<output_data_t> outputs;
4730 for (
const uint64_t & offset_needed : needed_offsets)
4735 for (
const uint64_t &offset_found : offset_map[in_to_key.
amount])
4737 if (offset_needed == offset_found)
4746 if (found && pos < tx_map[in_to_key.
amount].size())
4747 outputs.push_back(tx_map[in_to_key.
amount].at(pos));
4752 its->second.emplace(in_to_key.
k_image, outputs);
4760 m_fake_scan_time = scantable / total_txs;
4761 if(m_show_time_stats)
4762 MDEBUG(
"Prepare scantable took: " << scantable <<
" ms");
4821 m_db_default_sync =
true;
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;
4830 if(!validator_key.empty()) {
4831 m_validator_key = boost::algorithm::unhex(validator_key);
4840 if (m_db_default_sync)
4854 static const std::vector<HardFork::Params> mainnet_heights = []()
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);
4861 static const std::vector<HardFork::Params> testnet_heights = []()
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);
4868 static const std::vector<HardFork::Params> stagenet_heights = []()
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);
4875 static const std::vector<HardFork::Params> dummy;
4878 case MAINNET:
return mainnet_heights;
4879 case TESTNET:
return testnet_heights;
4880 case STAGENET:
return stagenet_heights;
4881 default:
return dummy;
4902 std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> chains;
4904 for (
const auto &i: m_alternative_chains)
4908 for (
const auto &j: m_alternative_chains)
4910 if (j.second.bl.prev_id == top)
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())
4925 h = prev->second.bl.prev_id;
4927 chains.push_back(std::make_pair(i.second, chain));
4938 #if defined(PER_BLOCK_CHECKPOINT) 4939 static const char expected_block_hashes_hash[] =
"53a9384ca5384025e657622b5d66fac67c03f9b863b91abe9516eda47cceaeb5";
4942 if (get_checkpoints ==
nullptr || !m_fast_sync)
4956 MERROR(
"Failed to hash precomputed blocks data");
4959 MINFO(
"precomputed blocks hash: " <<
hash <<
", expected " << expected_block_hashes_hash);
4963 MERROR(
"Failed to parse expected block hashes hash");
4967 if (
hash != expected_hash)
4969 MERROR(
"Block hash data does not match expected hash");
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))
4980 MERROR(
"Block hash data is too large");
4983 const size_t size_needed = 4 + nblocks *
sizeof(
crypto::hash);
4984 if(nblocks > 0 && nblocks > m_db->
height() &&
checkpoints.size() >= size_needed)
4987 for (
uint32_t i = 0; i < nblocks; i++)
4991 p +=
sizeof(
hash.data);
4992 m_blocks_hash_check.push_back(
hash);
4994 MINFO(nblocks <<
" block hashes loaded");
5003 std::vector<transaction> txs;
5008 bool relayed, do_not_relay, double_spend_seen, nonexistent_utxo_seen;
5014 m_tx_pool.
take_tx(tx_hash, pool_tx, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen, nonexistent_utxo_seen);
5024 #if defined(PER_BLOCK_CHECKPOINT) 5025 return height < m_blocks_hash_check.size();
5033 m_blockchain_lock.
lock();
5038 m_blockchain_lock.
unlock();
5066 void Blockchain::invalidate_block_template_cache()
5068 MDEBUG(
"Invalidating block template cache");
5069 m_btc_valid =
false;
5074 MDEBUG(
"Setting block template cache");
5077 m_btc_nonce = nonce;
5078 m_btc_difficulty = diff;
5080 m_btc_expected_reward = expected_reward;
5081 m_btc_pool_cookie = pool_cookie;
5096 template bool Blockchain::get_transactions(
const std::vector<crypto::hash>&, std::vector<transaction>&, std::vector<crypto::hash>&)
const;
5098 template 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;
#define CRITICAL_REGION_LOCAL1(x)
bool verify_block_signature(const block &b)
Verify block's digital signature.
bool is_within_compiled_block_hash_area() const
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
#define CRYPTONOTE_MINED_ETN_UNLOCK_WINDOW
const config_t & get_config(network_type nettype)
virtual bool update_pruning()=0
prunes recent blockchain changes as needed, iff pruning is enabled
uint64_t get_current_cumulative_block_weight_limit() const
gets the block weight limit based on recent blocks
vector< string > getApplicablePublicKeys(uint64_t height, bool convert_to_byte=false)
bool check_outs_overflow(const transaction &tx)
uint64_t cookie() const
return the cookie
bool is_coinbase(const transaction &tx)
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
#define CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE
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
virtual bool get_tx_blob(const crypto::hash &h, cryptonote::blobdata &tx) const =0
fetches the transaction blob with the given hash
void slow_hash_allocate_state()
virtual uint64_t get_tx_block_height(const crypto::hash &h) const =0
fetches the height of a transaction's block
std::vector< crypto::hash > tx_hashes
void slow_hash_free_state()
bool check_blockchain_pruning()
uint64_t height
the height of the block in the blockchain
bool get_split_transactions_blobs(const t_ids_container &txs_ids, t_tx_container &txs, t_missed_container &missed_txs) const
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.
void pop_blocks(uint64_t nblocks)
removes blocks from the top of the blockchain
bool reorganize_from_chain_height(uint64_t height)
handle syncing calls instead of the backing db, asynchronously
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
virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t &height) const =0
fetch a block blob by height
bool add_tx(transaction &tx, const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context &tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version)
uint8_t get_current_version() const
returns the current version
bool get_txpool_tx_meta(const crypto::hash &txid, txpool_tx_meta_t &meta) const
void save(Archive &a, const std::unordered_map< h_key, hval > &x, const boost::serialization::version_type ver)
void normalize_v7_difficulties()
Normalize the cumulative difficulty for V7 blocks, fixing the differing difficulty among nodes...
virtual void batch_abort()=0
aborts a batch transaction
virtual bool has_key_image(const crypto::key_image &img) const =0
check if a key image is stored as spent
virtual bool get_txpool_tx_blob(const crypto::hash &txid, cryptonote::blobdata &bd) const =0
get a txpool transaction's blob
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...
#define HF_VERSION_FORBID_INVALID_PUBKEYS
difficulty_type next_difficulty(std::vector< uint64_t > timestamps, std::vector< difficulty_type > cumulative_difficulties, size_t target_seconds, uint8_t version)
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 ...
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT
virtual uint64_t get_block_timestamp(const uint64_t &height) const =0
fetch a block's timestamp
uint64_t get_outs_etn_amount(const transaction &tx)
bool utxo_nonexistent(const transaction &tx) const
check if any utxo in a transaction has already been spent using the tx (v3 tx onwards) ...
#define HF_VERSION_ENFORCE_0_DECOY_TXS
bool m_verification_failed
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
std::string print_etn(uint64_t amount, unsigned int decimal_point)
std::vector< uint8_t > signatory
void get_transactions(std::vector< transaction > &txs, bool include_unrelayed_txes=true) const
get a list of all transactions in the pool
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
virtual crypto::hash get_block_hash_from_height(const uint64_t &height) const =0
fetch a block's hash
bool find_blockchain_supplement(const std::list< crypto::hash > &qblock_ids, std::vector< crypto::hash > &hashes, uint64_t &start_height, uint64_t ¤t_height, bool clip_pruned) const
get recent block hashes for a foreign chain
#define CRYPTONOTE_MAX_BLOCK_NUMBER
size_t get_object_blobsize(const t_object &o)
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
Validator getValidatorByKey(string key)
bool check(const cryptonote::block &block) const
check whether a new block would be accepted
#define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT
user didn't specify, use db_async
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
bool store_blockchain()
stores the blockchain
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 ...
void get_transaction_hashes(std::vector< crypto::hash > &txs, bool include_unrelayed_txes=true) const
get a list of all transaction hashes in the pool
boost::variant< txin_gen, txin_to_script, txin_to_scripthash, txin_to_key, txin_to_key_public > txin_v
virtual void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t &details)=0
add a txpool transaction
std::vector< blobdata > txs
#define ETN_DEFAULT_TX_SPENDABLE_AGE_V8
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)
#define SCAN_TABLE_QUIT(m)
#define CRYPTONOTE_MEMPOOL_TX_LIVETIME_V6
virtual uint64_t get_block_height(const crypto::hash &h) const =0
gets the height of the block with a given hash
provides the implementation of varint's
size_t get_min_block_weight(uint8_t version)
epee::critical_section m_synchronization_lock
A lock, currently for when BlockchainLMDB needs to resize the backing db file.
#define MCLOG_RED(level, cat, x)
void init()
initialize the object
handle syncing calls instead of the backing db, synchronously
std::function< const epee::span< const unsigned char >cryptonote::network_type network)> GetCheckpointsCallback
Callback routine that returns checkpoints data for specific network type.
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
virtual tx_out_index get_output_tx_and_index(const uint64_t &amount, const uint64_t &index) const =0
gets an output's tx hash and index
void remove_txpool_tx(const crypto::hash &txid)
virtual std::vector< address_txs > get_addr_tx_all(const crypto::public_key &combined_key)=0
#define DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD
static const std::vector< HardFork::Params > & get_hard_fork_heights(network_type nettype)
gets the hardfork heights of given network
transaction tx
the transaction
virtual bool tx_exists(const crypto::hash &h) const =0
check if a transaction with a given hash exists
cryptonote::account_public_address address
void set_enforce_dns_checkpoints(bool enforce)
configure whether or not to enforce DNS-based checkpoints
std::vector< uint64_t > key_offsets
Non-owning sequence of data. Does not deep copy.
public_key addKeys(const public_key &A, const public_key &B)
std::vector< uint64_t > relative_output_offsets_to_absolute(const std::vector< uint64_t > &off)
uint64_t get_current_blockchain_height() const
get the current height of the blockchain
bool key_images_already_spent(const transaction &tx) const
check if any key image in a transaction has already been spent
virtual difficulty_type get_block_cumulative_difficulty(const uint64_t &height) const =0
fetch a block's cumulative difficulty
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
void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta)
#define HF_VERSION_ENFORCE_0_DECOY_TXS_END
#define HF_VERSION_MIN_MIXIN_4
virtual 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 =0
runs a function over all txpool transactions
uint64_t get_transaction_weight(const transaction &tx, size_t blob_size)
virtual void safesyncmode(const bool onoff)=0
toggle safe syncs for the DB
Level
Represents enumeration for severity level used to determine level of logging.
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
struct hash_func hashes[]
virtual void set_batch_transactions(bool)=0
sets whether or not to batch transactions
bool add_new_block(const block &bl_, block_verification_context &bvc)
adds a block to the blockchain
virtual bool for_all_transactions(std::function< bool(const crypto::hash &, const cryptonote::transaction &)>, bool pruned) const =0
runs a function over all transactions stored
void safesyncmode(const bool onoff)
Put DB in safe sync mode.
void on_block_popped(uint64_t new_chain_height)
called when one or more blocks are popped from the blockchain
#define CRITICAL_REGION_END()
virtual uint64_t get_num_outputs(const uint64_t &amount) const =0
fetches the number of outputs of a given amount
bool take_tx(const crypto::hash &id, transaction &tx, cryptonote::blobdata &txblob, size_t &tx_weight, uint64_t &fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen, bool &nonexistent_utxo_seen)
takes a transaction with the given hash from the pool
bool m_validator_list_update_failed
virtual void add_max_block_size(uint64_t sz)=0
add a new max block size
std::vector< uint8_t > extra
bool is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const
checks if alternate chain blocks should be kept for a given height
uint64_t get_current_cumulative_block_weight_median() const
gets the block weight median based on recent blocks (same window as for the limit) ...
virtual bool get_pruned_tx_blob(const crypto::hash &h, cryptonote::blobdata &tx) const =0
fetches the pruned transaction blob with the given hash
#define FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE
bool get_short_chain_history(std::list< crypto::hash > &ids) const
gets the hashes for a subset of the blockchain
virtual bool get_prunable_tx_blob(const crypto::hash &h, cryptonote::blobdata &tx) const =0
fetches the prunable transaction blob with the given hash
bool m_partial_block_reward
#define DYNAMIC_FEE_REFERENCE_TRANSACTION_WEIGHT
virtual void close()=0
close the BlockchainDB
bool m_marked_as_orphaned
virtual std::vector< address_outputs > get_addr_output_all(const crypto::public_key &combined_key)=0
virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes=true) const =0
get the number of transactions in the txpool
#define ETN_MINED_ETN_UNLOCK_WINDOW_V8
bool update_checkpoints(const std::string &file_path, bool check_dns)
loads new checkpoints from a file and optionally from DNS
thrown when a requested transaction does not exist
std::vector< tx_out > vout
thrown when a spent key image exists, but shouldn't, namely when adding a block
std::list< std::pair< block_extended_info, std::vector< crypto::hash > > > get_alternative_chains() const
returns a set of known alternate chains
uint8_t get_current_hard_fork_version() const
gets the current hardfork version in use/voted for
Holds cryptonote related classes and helpers.
size_t get_total_transactions() const
gets the total number of transactions on the main chain
virtual bool check_chainstate_utxo(const crypto::hash tx_hash, const uint32_t relative_out_index)=0
#define BLOCK_REWARD_OVERESTIMATE
#define HF_VERSION_FORBID_DUST_OUTPUTS
#define HF_VERSION_LONG_TERM_BLOCK_WEIGHT
bool on_blockchain_inc(uint64_t new_block_height, const crypto::hash &top_block_id)
action to take when notified of a block added to the blockchain
virtual void set_block_cumulative_difficulty(uint64_t height, difficulty_type diff)=0
sets a block's cumulative difficulty
virtual size_t get_block_weight(const uint64_t &height) const =0
fetch a block's weight
size_t get_transaction_version(const cryptonote::blobdata &bd)
bool get_block_longhash(const block &b, crypto::hash &res, uint64_t height)
std::vector< txin_v > vin
bool flush_txes_from_pool(const std::vector< crypto::hash > &txids)
remove transactions from the transaction pool (if present)
virtual std::vector< uint64_t > get_block_weights(uint64_t start_height, size_t count) const =0
fetch the last N blocks' weights
mdb_size_t count(MDB_cursor *cur)
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
crypto::public_key m_spend_public_key
#define PER_KB_FEE_QUANTIZATION_DECIMALS
bool is_valid_decomposed_amount(uint64_t amount)
bool for_all_key_images(std::function< bool(const crypto::key_image &)>) const
perform a check on all key images in the blockchain
virtual output_data_t get_output_key(const uint64_t &amount, const uint64_t &index, bool include_commitmemt=true) const =0
get some of an output's data
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
crypto::hash get_tail_id() const
get the hash of the most recent block on 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
#define HF_VERSION_MIN_MIXIN_6
bool generate_genesis_block(block &bl, std::string const &genesis_tx, uint32_t nonce)
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
crypto::public_key m_view_public_key
virtual block get_block_from_height(const uint64_t &height) const
fetch a block by height
#define DIFFICULTY_TARGET_V6
bool verify_signature(const std::string &message, const std::string &publicKey, const std::string &signature)
uint64_t get_num_mature_outputs(uint64_t amount) const
get number of outputs of an amount past the minimum spendable age
#define CRITICAL_REGION_BEGIN(x)
rct::rctSig rct_signatures
uint64_t get_txpool_tx_count(bool include_unrelayed_txes=true) const
#define HF_VERSION_DYNAMIC_FEE
virtual bool get_prunable_tx_hash(const crypto::hash &tx_hash, crypto::hash &prunable_hash) const =0
fetches the prunable transaction hash
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
bool get_block_hash(const block &b, crypto::hash &res)
virtual std::vector< std::vector< uint64_t > > get_tx_amount_output_indices(const uint64_t tx_id, size_t n_txes=1) const =0
gets output indices (amount-specific) for a transaction's outputs
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
crypto::public_key get_output_key(uint64_t amount, uint64_t global_index) const
get the public key for an output
virtual bool is_read_only() const =0
is BlockchainDB in read-only mode?
void sign_block(block &b, std::string privateKey)
Digitally sign the block.
virtual bool can_thread_bulk_indices() const =0
boost::shared_ptr< call_befor_die_base > auto_scope_leave_caller
HardFork::State get_hard_fork_state() const
gets the hardfork voting state object
std::string const GENESIS_TX
static uint64_t get_fee_quantization_mask()
get fee quantization mask
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS
crypto::public_key pubkey
the output's public key (for spend verification)
#define DYNAMIC_FEE_PER_KB_BASE_FEE_V5
virtual transaction get_tx(const crypto::hash &h) const
fetches the transaction with the given hash
bool check_hash(const crypto::hash &hash, difficulty_type difficulty)
bool prune_blockchain(uint32_t pruning_seed=0)
#define DYNAMIC_FEE_PER_KB_BASE_FEE
virtual 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) const =0
return a histogram of outputs on the blockchain
unsigned __int64 uint64_t
#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW
std::string get_time_interval_string(const time_t &time_)
bool reset_and_set_genesis_block(const block &b)
clears the blockchain and starts a new one
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT
#define CRITICAL_REGION_LOCAL(x)
difficulty_type get_difficulty_for_next_block()
returns the difficulty target the next block to be added must meet
#define DIFFICULTY_BLOCKS_COUNT
void check_against_checkpoints(const checkpoints &points, bool enforce)
check the blockchain against a set of checkpoints
bool check_for_height(const cryptonote::block &block, uint64_t height) const
same as check, but for a particular height, rather than the top
virtual void sync()=0
sync the BlockchainDB with disk
virtual block get_top_block() const =0
fetch the top block
virtual uint64_t height() const =0
fetch the current blockchain height
Leave syncing up to the backing db (safest, but slowest because of disk I/O)
virtual void batch_stop()=0
ends a batch transaction
virtual uint64_t get_tx_unlock_time(const crypto::hash &h) const =0
fetch a transaction's unlock time/height
virtual std::vector< uint64_t > get_long_term_block_weights(uint64_t start_height, size_t count) const =0
fetch the last N blocks' long term weights
virtual bool block_exists(const crypto::hash &h, uint64_t *height=NULL) const =0
checks if a block exists
bool load_checkpoints_from_json(const std::string &json_hashfile_fullpath)
load new checkpoints from json
uint64_t fee
the transaction's fee amount
virtual bool for_all_key_images(std::function< bool(const crypto::key_image &)>) const =0
runs a function over all key images stored
void on_new_tx_from_block(const cryptonote::transaction &tx)
called when we see a tx originating from a block
virtual void add_addr_tx(const crypto::hash tx_hash, const crypto::public_key &combined_key)=0
thrown when a requested block does not exist
virtual void remove_txpool_tx(const crypto::hash &txid)=0
remove a txpool transaction
bool parse_and_validate_tx_base_from_blob(const blobdata &tx_blob, transaction &tx)
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
Useful when application has potentially harmful situtaions.
bool update_blockchain_pruning()
virtual bool get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, std::vector< uint64_t > &distribution, uint64_t &base) const =0
#define CRYPTONOTE_SHORT_TERM_BLOCK_WEIGHT_SURGE_FACTOR
bool get_transactions(const t_ids_container &txs_ids, t_tx_container &txs, t_missed_container &missed_txs) const
bool check_fee(size_t tx_weight, uint64_t fee) const
validate a transaction's fee
bool is_open() const
Gets the current open/ready state of the BlockchainDB.
size_t weight
the transaction's weight
uint8_t get_ideal_version() const
returns the latest "ideal" version
bool have_tx_keyimg_as_spent(const crypto::key_image &key_im) const
check if a key image is already spent on the blockchain
bool get_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const
returns information about current voting state
std::vector< std::vector< crypto::signature > > signatures
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
virtual void set_hard_fork(HardFork *hf)
virtual difficulty_type get_block_difficulty(const uint64_t &height) const =0
fetch a block's difficulty
Transaction pool, handles transactions which are not part of a block.
~Blockchain()
Blockchain destructor.
type_vec_type median(std::vector< type_vec_type > &v)
crypto::hash get_block_id_by_height(uint64_t height) const
gets a block's hash given a height
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
expect< void > success() noexcept
#define CRYPTONOTE_MEMPOOL_TX_LIVETIME
#define CRYPTONOTE_REWARD_BLOCKS_WINDOW
uint32_t get_mempool_tx_livetime() const
uint32_t get_blockchain_pruning_seed() const
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 unlock() const
unlocks the transaction pool
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
void get_transaction_prefix_hash(const transaction_prefix &tx, crypto::hash &h)
The BlockchainDB backing store interface declaration/contract.
std::vector< uint8_t > signature
virtual uint64_t get_utxo_unlock_time(const crypto::hash tx_hash, const uint32_t relative_out_index)=0
const T & move(const T &t)
bool have_tx(const crypto::hash &id) const
search the blockchain for a transaction by hash
virtual bool prune_blockchain(uint32_t pruning_seed=0)=0
prunes the blockchain
boost::multiprecision::uint128_t difficulty_type
virtual crypto::hash top_block_hash(uint64_t *block_height=NULL) const =0
fetch the top block's hash
information about a single transaction
bool have_block(const crypto::hash &id) const
checks if a block is known about with a given hash
bool get_alternative_blocks(std::vector< block > &blocks) const
compiles a list of all blocks stored as alternative chains
void * memcpy(void *a, const void *b, size_t c)
#define CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE
uint8_t get_ideal_hard_fork_version() const
returns the newest hardfork version known to the blockchain
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX
#define HF_VERSION_PUBLIC_TX
crypto::key_image k_image
uint8_t get_hard_fork_version(uint64_t height) const
returns the actual hardfork version for a given block height
uint64_t get_next_long_term_block_weight(uint64_t block_weight) const
gets the long term block weight for a new block
crypto::hash get_transaction_hash(const transaction &t)
uint64_t get_difficulty_target() const
get difficulty target based on chain and hardfork version
bool have_tx(const crypto::hash &id) const
checks if the pool has a transaction with the given hash
difficulty_type block_difficulty(uint64_t i) const
gets the difficulty of the block with a given height
bool check_key(const public_key &key)
uint64_t m_address_prefix
virtual bool for_blocks_range(const uint64_t &h1, const uint64_t &h2, std::function< bool(uint64_t, const crypto::hash &, const cryptonote::block &)>) const =0
runs a function over a range of blocks
#define HF_VERSION_ORDERED_TX_INPUTS
virtual uint64_t get_tx_count() const =0
fetches the total number of transactions ever
uint32_t const GENESIS_NONCE
bool m_added_to_main_chain
bool fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version)
Chooses transactions for a block to include.
network_type get_nettype() const
get blockchain nettype
virtual bool check_pruning()=0
checks pruning was done correctly, iff enabled
bool get_inputs_etn_amount(const transaction &tx, uint64_t &etn)
virtual std::vector< transaction > get_tx_list(const std::vector< crypto::hash > &hlist) const =0
fetches a list of transactions based on their hashes
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_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
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)
#define DIFFICULTY_TARGET
thrown when a requested output does not exist
State get_state(time_t t) const
returns current state at the given time
void reserve_container(std::vector< T > &v, size_t N)
DISABLE_VS_WARNINGS(4244 4345 4503) using namespace crypto
bool add_fork(uint8_t version, uint64_t height, uint8_t threshold, time_t time)
add a new hardfork height
bool load_checkpoints_from_dns(network_type nettype=MAINNET)
load new checkpoints from DNS
void get_tx_tree_hash(const std::vector< crypto::hash > &tx_hashes, crypto::hash &h)
bool on_blockchain_dec(uint64_t new_block_height, const crypto::hash &top_block_id)
action to take when notified of a block removed from the blockchain
#define HF_VERSION_MIN_MIXIN_10
std::pair< crypto::hash, uint64_t > tx_out_index
size_t get_alternative_blocks_count() const
returns the number of alternative blocks stored
A container for blockchain checkpoints.
bool get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan=NULL) const
gets the block with a given hash
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)
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 to_string(t_connection_type type)
std::string sign_message(const std::string &message, const std::string &privateKey)
const std::map< uint64_t, crypto::hash > & get_points() const
gets the checkpoints container
virtual uint64_t get_block_already_generated_coins(const uint64_t &height) const =0
fetch a block's already generated coins
bool check_tx_outputs(const transaction &tx, tx_verification_context &tvc)
check that a transaction's outputs conform to current standards
blobdata block_to_blob(const block &b)
virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &details)=0
update a txpool transaction's metadata
void lock() const
locks the transaction pool
virtual bool get_txpool_tx_meta(const crypto::hash &txid, txpool_tx_meta_t &meta) const =0
get a txpool transaction's metadata
container for passing a block and metadata about it on the blockchain
virtual void reset()=0
Remove everything from the BlockchainDB.
#define HF_VERSION_PER_BYTE_FEE
const std::pair< uint8_t, uint64_t > * hard_forks
electroneum::basic::Validator get_validator_by_height(uint64_t height)
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS
bool is_v1_tx(const blobdata_ref &tx_blob)
virtual block get_block(const crypto::hash &h) const
fetches the block with the given hash
virtual uint64_t get_top_block_timestamp() const =0
fetch the top block's timestamp
a struct containing output metadata
#define DIFFICULTY_BLOCKS_COUNT_V6
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX
virtual uint64_t get_block_long_term_weight(const uint64_t &height) const =0
fetch a block's long term weight
#define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5
bool m_verification_failed
const char * what() const
void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t &meta)
const size_t long_term_block_weight_window
bool get_txpool_tx_blob(const crypto::hash &txid, cryptonote::blobdata &bd) const
bool deinit()
Uninitializes the blockchain state.
uint64_t get_block_height(const block &b)
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 check_for_conflicts(const checkpoints &other) const
checks if our checkpoints container conflicts with another
bool parse_and_validate_block_from_blob(const blobdata &b_blob, block &b, crypto::hash *block_hash)
virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0)=0
tells the BlockchainDB to start a new "batch" of blocks
bool is_in_checkpoint_zone(uint64_t height) const
checks if there is a checkpoint in the future
virtual std::vector< uint64_t > get_block_cumulative_rct_outputs(const std::vector< uint64_t > &heights) const =0
fetch a block's cumulative number of rct outputs
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 cleanup_handle_incoming_blocks(bool force_sync=false)
incoming blocks post-processing, cleanup, and disk sync
rct::key commitment() const