danicoin/src/cryptonote_core/blockchain_storage.h

239 lines
11 KiB
C
Raw Normal View History

2014-03-03 22:07:58 +00:00
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
2014-06-20 15:56:33 +00:00
#include "SwappedVector.h"
#include "cryptonote_format_utils.h"
2014-03-03 22:07:58 +00:00
#include "tx_pool.h"
#include "common/util.h"
#include "rpc/core_rpc_server_commands_defs.h"
#include "checkpoints.h"
2014-06-20 15:56:33 +00:00
namespace cryptonote {
class blockchain_storage {
2014-03-03 22:07:58 +00:00
public:
2014-05-15 16:40:40 +00:00
blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), m_is_blockchain_storing(false)
2014-03-03 22:07:58 +00:00
{};
bool init() { return init(tools::get_default_data_dir()); }
bool init(const std::string& config_folder);
bool deinit();
void set_checkpoints(checkpoints&& chk_pts) { m_checkpoints = chk_pts; }
bool get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks, std::list<transaction>& txs);
bool get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks);
bool get_alternative_blocks(std::list<block>& blocks);
size_t get_alternative_blocks_count();
crypto::hash get_block_id_by_height(uint64_t height);
bool get_block_by_hash(const crypto::hash &h, block &blk);
2014-06-20 15:56:33 +00:00
template<class archive_t> void serialize(archive_t & ar, const unsigned int version);
2014-03-03 22:07:58 +00:00
bool have_tx(const crypto::hash &id);
bool have_tx_keyimges_as_spent(const transaction &tx);
uint64_t get_current_blockchain_height();
crypto::hash get_tail_id();
crypto::hash get_tail_id(uint64_t& height);
difficulty_type get_difficulty_for_next_block();
bool add_new_block(const block& bl_, block_verification_context& bvc);
bool reset_and_set_genesis_block(const block& b);
bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, const blobdata& ex_nonce);
bool have_block(const crypto::hash& id);
size_t get_total_transactions();
bool get_short_chain_history(std::list<crypto::hash>& ids);
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp);
2014-06-20 15:56:33 +00:00
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<std::pair<block, std::list<transaction>>>& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count);
2014-03-03 22:07:58 +00:00
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp);
bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res);
bool get_backward_blocks_sizes(size_t from_height, std::vector<size_t>& sz, size_t count);
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs);
bool store_blockchain();
bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id);
uint64_t get_current_comulative_blocksize_limit();
2014-03-20 11:46:11 +00:00
bool is_storing_blockchain(){return m_is_blockchain_storing;}
2014-04-07 15:02:15 +00:00
uint64_t block_difficulty(size_t i);
2014-03-03 22:07:58 +00:00
template<class t_ids_container, class t_blocks_container, class t_missed_container>
2014-06-20 15:56:33 +00:00
bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) {
2014-03-03 22:07:58 +00:00
CRITICAL_REGION_LOCAL(m_blockchain_lock);
2014-06-20 15:56:33 +00:00
for (const auto& bl_id : block_ids) {
auto it = m_blockMap.find(bl_id);
if (it == m_blockMap.end()) {
2014-03-03 22:07:58 +00:00
missed_bs.push_back(bl_id);
2014-06-20 15:56:33 +00:00
} else {
CHECK_AND_ASSERT_MES(it->second < m_blocks.size(), false, "Internal error: bl_id=" << epee::string_tools::pod_to_hex(bl_id)
2014-03-03 22:07:58 +00:00
<< " have index record with offset="<<it->second<< ", bigger then m_blocks.size()=" << m_blocks.size());
blocks.push_back(m_blocks[it->second].bl);
}
}
2014-06-20 15:56:33 +00:00
2014-03-03 22:07:58 +00:00
return true;
}
template<class t_ids_container, class t_tx_container, class t_missed_container>
2014-06-20 15:56:33 +00:00
bool get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) {
2014-03-03 22:07:58 +00:00
CRITICAL_REGION_LOCAL(m_blockchain_lock);
2014-06-20 15:56:33 +00:00
for (const auto& tx_id : txs_ids) {
auto it = m_transactionMap.find(tx_id);
if (it == m_transactionMap.end()) {
2014-03-03 22:07:58 +00:00
transaction tx;
2014-06-20 15:56:33 +00:00
if (!m_tx_pool.get_transaction(tx_id, tx)) {
2014-03-03 22:07:58 +00:00
missed_txs.push_back(tx_id);
2014-06-20 15:56:33 +00:00
} else {
2014-03-03 22:07:58 +00:00
txs.push_back(tx);
2014-06-20 15:56:33 +00:00
}
} else {
txs.push_back(transactionByIndex(it->second).tx);
2014-03-03 22:07:58 +00:00
}
}
2014-06-20 15:56:33 +00:00
2014-03-03 22:07:58 +00:00
return true;
}
2014-06-20 15:56:33 +00:00
2014-03-03 22:07:58 +00:00
//debug functions
void print_blockchain(uint64_t start_index, uint64_t end_index);
void print_blockchain_index();
void print_blockchain_outs(const std::string& file);
private:
2014-06-20 15:56:33 +00:00
struct Transaction {
transaction tx;
std::vector<uint32_t> m_global_output_indexes;
template<class archive_t> void serialize(archive_t & ar, unsigned int version);
BEGIN_SERIALIZE_OBJECT()
FIELD(tx)
FIELD(m_global_output_indexes)
END_SERIALIZE()
};
struct Block {
block bl;
uint32_t height;
uint64_t block_cumulative_size;
difficulty_type cumulative_difficulty;
uint64_t already_generated_coins;
std::vector<Transaction> transactions;
template<class Archive> void serialize(Archive& archive, unsigned int version);
BEGIN_SERIALIZE_OBJECT()
FIELD(bl)
VARINT_FIELD(height)
VARINT_FIELD(block_cumulative_size)
VARINT_FIELD(cumulative_difficulty)
VARINT_FIELD(already_generated_coins)
FIELD(transactions)
END_SERIALIZE()
};
struct TransactionIndex {
uint32_t block;
uint16_t transaction;
template<class Archive> void serialize(Archive& archive, unsigned int version);
};
2014-03-03 22:07:58 +00:00
typedef std::unordered_set<crypto::key_image> key_images_container;
2014-06-20 15:56:33 +00:00
typedef std::unordered_map<crypto::hash, Block> blocks_ext_by_hash;
typedef std::map<uint64_t, std::vector<std::pair<TransactionIndex, uint16_t>>> outputs_container; //crypto::hash - tx hash, size_t - index of out in transaction
2014-03-03 22:07:58 +00:00
tx_memory_pool& m_tx_pool;
epee::critical_section m_blockchain_lock; // TODO: add here reader/writer lock
2014-03-03 22:07:58 +00:00
key_images_container m_spent_keys;
2014-04-02 16:00:17 +00:00
size_t m_current_block_cumul_sz_limit;
2014-03-03 22:07:58 +00:00
blocks_ext_by_hash m_alternative_chains; // crypto::hash -> block_extended_info
outputs_container m_outputs;
std::string m_config_folder;
checkpoints m_checkpoints;
std::atomic<bool> m_is_in_checkpoint_zone;
2014-03-20 11:46:11 +00:00
std::atomic<bool> m_is_blockchain_storing;
2014-03-03 22:07:58 +00:00
2014-06-20 15:56:33 +00:00
typedef SwappedVector<Block> Blocks;
typedef std::unordered_map<crypto::hash, uint32_t> BlockMap;
typedef std::unordered_map<crypto::hash, TransactionIndex> TransactionMap;
Blocks m_blocks;
BlockMap m_blockMap;
TransactionMap m_transactionMap;
2014-03-03 22:07:58 +00:00
2014-06-20 15:56:33 +00:00
template<class visitor_t> bool scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height = NULL);
bool switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::iterator>& alt_chain, bool discard_disconnected_chain);
2014-03-03 22:07:58 +00:00
bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc);
2014-06-20 15:56:33 +00:00
difficulty_type get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::iterator>& alt_chain, Block& bei);
2014-03-03 22:07:58 +00:00
bool prevalidate_miner_transaction(const block& b, uint64_t height);
bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins);
bool validate_transaction(const block& b, uint64_t height, const transaction& tx);
bool rollback_blockchain_switching(std::list<block>& original_chain, size_t rollback_height);
bool get_last_n_blocks_sizes(std::vector<size_t>& sz, size_t count);
2014-06-20 15:56:33 +00:00
bool add_out_to_get_random_outs(std::vector<std::pair<TransactionIndex, uint16_t>>& amount_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i);
2014-03-03 22:07:58 +00:00
bool is_tx_spendtime_unlocked(uint64_t unlock_time);
2014-06-20 15:56:33 +00:00
size_t find_end_of_allowed_index(const std::vector<std::pair<TransactionIndex, uint16_t>>& amount_outs);
2014-03-03 22:07:58 +00:00
bool check_block_timestamp_main(const block& b);
bool check_block_timestamp(std::vector<uint64_t> timestamps, const block& b);
uint64_t get_adjusted_time();
bool complete_timestamps_vector(uint64_t start_height, std::vector<uint64_t>& timestamps);
bool update_next_comulative_size_limit();
2014-06-20 15:56:33 +00:00
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, uint64_t& starter_offset);
bool check_tx_input(const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t* pmax_related_block_height = NULL);
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t* pmax_used_block_height = NULL);
bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL);
bool have_tx_keyimg_as_spent(const crypto::key_image &key_im);
const Transaction& transactionByIndex(TransactionIndex index);
bool pushBlock(const block& blockData, block_verification_context& bvc);
bool pushBlock(Block& block);
void popBlock(const crypto::hash& blockHash);
bool pushTransaction(Block& block, const crypto::hash& transactionHash, TransactionIndex transactionIndex);
void popTransaction(const transaction& transaction, const crypto::hash& transactionHash);
void popTransactions(const Block& block, const crypto::hash& minerTransactionHash);
2014-03-03 22:07:58 +00:00
};
2014-06-20 15:56:33 +00:00
template<class visitor_t> bool blockchain_storage::scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height) {
2014-04-02 16:00:17 +00:00
CRITICAL_REGION_LOCAL(m_blockchain_lock);
2014-03-03 22:07:58 +00:00
auto it = m_outputs.find(tx_in_to_key.amount);
2014-06-20 15:56:33 +00:00
if (it == m_outputs.end() || !tx_in_to_key.key_offsets.size())
2014-03-03 22:07:58 +00:00
return false;
std::vector<uint64_t> absolute_offsets = relative_output_offsets_to_absolute(tx_in_to_key.key_offsets);
2014-06-20 15:56:33 +00:00
std::vector<std::pair<TransactionIndex, uint16_t>>& amount_outs_vec = it->second;
2014-03-03 22:07:58 +00:00
size_t count = 0;
2014-06-20 15:56:33 +00:00
for (uint64_t i : absolute_offsets) {
if(i >= amount_outs_vec.size() ) {
2014-03-03 22:07:58 +00:00
LOG_PRINT_L0("Wrong index in transaction inputs: " << i << ", expected maximum " << amount_outs_vec.size() - 1);
return false;
}
2014-06-20 15:56:33 +00:00
//auto tx_it = m_transactionMap.find(amount_outs_vec[i].first);
//CHECK_AND_ASSERT_MES(tx_it != m_transactionMap.end(), false, "Wrong transaction id in output indexes: " << epee::string_tools::pod_to_hex(amount_outs_vec[i].first));
const Transaction& tx = transactionByIndex(amount_outs_vec[i].first);
CHECK_AND_ASSERT_MES(amount_outs_vec[i].second < tx.tx.vout.size(), false,
"Wrong index in transaction outputs: " << amount_outs_vec[i].second << ", expected less then " << tx.tx.vout.size());
if (!vis.handle_output(tx.tx, tx.tx.vout[amount_outs_vec[i].second])) {
2014-03-03 22:07:58 +00:00
LOG_PRINT_L0("Failed to handle_output for output no = " << count << ", with absolute offset " << i);
return false;
}
2014-06-20 15:56:33 +00:00
if(count++ == absolute_offsets.size()-1 && pmax_related_block_height) {
if (*pmax_related_block_height < amount_outs_vec[i].first.block) {
*pmax_related_block_height = amount_outs_vec[i].first.block;
}
2014-03-03 22:07:58 +00:00
}
}
return true;
}
}
2014-06-20 15:56:33 +00:00
#include "cryptonote_boost_serialization.h"
#include "blockchain_storage_boost_serialization.h"