mirror of
https://github.com/monero-project/monero.git
synced 2025-07-23 13:10:46 -04:00
moved all stuff to github
This commit is contained in:
parent
095fbeeb67
commit
296ae46ed8
388 changed files with 95937 additions and 469 deletions
50
src/cryptonote_core/account.cpp
Normal file
50
src/cryptonote_core/account.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
// 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.
|
||||
|
||||
#include <boost/archive/binary_oarchive.hpp>
|
||||
#include <boost/archive/binary_iarchive.hpp>
|
||||
#include <fstream>
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "account.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "cryptonote_core/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
using namespace std;
|
||||
|
||||
DISABLE_VS_WARNINGS(4244 4345)
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
//-----------------------------------------------------------------
|
||||
account_base::account_base()
|
||||
{
|
||||
set_null();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::set_null()
|
||||
{
|
||||
m_keys = account_keys();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::generate()
|
||||
{
|
||||
generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key);
|
||||
generate_keys(m_keys.m_account_address.m_view_public_key, m_keys.m_view_secret_key);
|
||||
m_creation_timestamp = time(NULL);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
const account_keys& account_base::get_keys() const
|
||||
{
|
||||
return m_keys;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
std::string account_base::get_public_address_str()
|
||||
{
|
||||
//TODO: change this code into base 58
|
||||
return get_account_address_as_str(m_keys.m_account_address);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
}
|
61
src/cryptonote_core/account.h
Normal file
61
src/cryptonote_core/account.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
// 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
|
||||
|
||||
#include "cryptonote_core/cryptonote_basic.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
struct account_keys
|
||||
{
|
||||
account_public_address m_account_address;
|
||||
crypto::secret_key m_spend_secret_key;
|
||||
crypto::secret_key m_view_secret_key;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_account_address)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_secret_key)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_secret_key)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class account_base
|
||||
{
|
||||
public:
|
||||
account_base();
|
||||
void generate();
|
||||
const account_keys& get_keys() const;
|
||||
std::string get_public_address_str();
|
||||
|
||||
uint64_t get_createtime() const { return m_creation_timestamp; }
|
||||
void set_createtime(uint64_t val) { m_creation_timestamp = val; }
|
||||
|
||||
bool load(const std::string& file_path);
|
||||
bool store(const std::string& file_path);
|
||||
|
||||
template <class t_archive>
|
||||
inline void serialize(t_archive &a, const unsigned int /*ver*/)
|
||||
{
|
||||
a & m_keys;
|
||||
a & m_creation_timestamp;
|
||||
}
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_keys)
|
||||
KV_SERIALIZE(m_creation_timestamp)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
private:
|
||||
void set_null();
|
||||
account_keys m_keys;
|
||||
uint64_t m_creation_timestamp;
|
||||
};
|
||||
}
|
31
src/cryptonote_core/account_boost_serialization.h
Normal file
31
src/cryptonote_core/account_boost_serialization.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
// 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
|
||||
|
||||
#include "account.h"
|
||||
#include "cryptonote_core/cryptonote_boost_serialization.h"
|
||||
|
||||
//namespace cryptonote {
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::account_keys &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.m_account_address;
|
||||
a & x.m_spend_secret_key;
|
||||
a & x.m_view_secret_key;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::account_public_address &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.m_spend_public_key;
|
||||
a & x.m_view_public_key;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
1633
src/cryptonote_core/blockchain_storage.cpp
Normal file
1633
src/cryptonote_core/blockchain_storage.cpp
Normal file
File diff suppressed because it is too large
Load diff
297
src/cryptonote_core/blockchain_storage.h
Normal file
297
src/cryptonote_core/blockchain_storage.h
Normal file
|
@ -0,0 +1,297 @@
|
|||
// 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
|
||||
#include <boost/serialization/serialization.hpp>
|
||||
#include <boost/serialization/version.hpp>
|
||||
#include <boost/serialization/list.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/global_fun.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <atomic>
|
||||
|
||||
#include "tx_pool.h"
|
||||
#include "cryptonote_basic.h"
|
||||
#include "common/util.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||
#include "rpc/core_rpc_server_commands_defs.h"
|
||||
#include "difficulty.h"
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
#include "verification_context.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "checkpoints.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class blockchain_storage
|
||||
{
|
||||
public:
|
||||
struct transaction_chain_entry
|
||||
{
|
||||
transaction tx;
|
||||
uint64_t m_keeper_block_height;
|
||||
size_t m_blob_size;
|
||||
std::vector<uint64_t> m_global_output_indexes;
|
||||
};
|
||||
|
||||
struct block_extended_info
|
||||
{
|
||||
block bl;
|
||||
uint64_t height;
|
||||
size_t block_cumulative_size;
|
||||
difficulty_type cumulative_difficulty;
|
||||
uint64_t already_generated_coins;
|
||||
};
|
||||
|
||||
blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_comul_sz_limit(0), m_is_in_checkpoint_zone(false)
|
||||
{};
|
||||
|
||||
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 push_new_block();
|
||||
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);
|
||||
//bool get_orphaned_blocks(std::list<block>& orphaned_by_prev_id, std::list<block>& orphaned_by_tx);
|
||||
//size_t get_orphaned_by_prev_blocks_count();
|
||||
//size_t get_orphaned_by_tx_blocks_count();
|
||||
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);
|
||||
void get_all_known_block_ids(std::list<crypto::hash> &main, std::list<crypto::hash> &alt, std::list<crypto::hash> &invalid);
|
||||
|
||||
template<class archive_t>
|
||||
void serialize(archive_t & ar, const unsigned int version);
|
||||
|
||||
bool have_tx(const crypto::hash &id);
|
||||
bool have_tx_keyimges_as_spent(const transaction &tx);
|
||||
bool have_tx_keyimg_as_spent(const crypto::key_image &key_im);
|
||||
transaction *get_tx(const crypto::hash &id);
|
||||
|
||||
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);
|
||||
|
||||
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_outs(uint64_t amount, std::list<crypto::public_key>& pkeys);
|
||||
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);
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, uint64_t& starter_offset);
|
||||
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);
|
||||
//bool get_chain_entry(const NOTIFY_REQUEST_CHAIN_ENTRY::request& req, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp);
|
||||
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp);
|
||||
bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res);
|
||||
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_outs_for_amounts(uint64_t amount, std::vector<std::pair<crypto::hash, size_t> >& keys, std::map<crypto::hash, transaction>& txs);
|
||||
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_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 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();
|
||||
|
||||
template<class t_ids_container, class t_blocks_container, class t_missed_container>
|
||||
bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
||||
BOOST_FOREACH(const auto& bl_id, block_ids)
|
||||
{
|
||||
auto it = m_blocks_index.find(bl_id);
|
||||
if(it == m_blocks_index.end())
|
||||
missed_bs.push_back(bl_id);
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(it->second < m_blocks.size(), false, "Internal error: bl_id=" << string_tools::pod_to_hex(bl_id)
|
||||
<< " have index record with offset="<<it->second<< ", bigger then m_blocks.size()=" << m_blocks.size());
|
||||
blocks.push_back(m_blocks[it->second].bl);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class t_ids_container, class t_tx_container, class t_missed_container>
|
||||
bool get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
||||
BOOST_FOREACH(const auto& tx_id, txs_ids)
|
||||
{
|
||||
auto it = m_transactions.find(tx_id);
|
||||
if(it == m_transactions.end())
|
||||
{
|
||||
transaction tx;
|
||||
if(!m_tx_pool.get_transaction(tx_id, tx))
|
||||
missed_txs.push_back(tx_id);
|
||||
else
|
||||
txs.push_back(tx);
|
||||
}
|
||||
else
|
||||
txs.push_back(it->second.tx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//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:
|
||||
typedef std::unordered_map<crypto::hash, size_t> blocks_by_id_index;
|
||||
typedef std::unordered_map<crypto::hash, transaction_chain_entry> transactions_container;
|
||||
typedef std::unordered_set<crypto::key_image> key_images_container;
|
||||
typedef std::vector<block_extended_info> blocks_container;
|
||||
typedef std::unordered_map<crypto::hash, block_extended_info> blocks_ext_by_hash;
|
||||
typedef std::unordered_map<crypto::hash, block> blocks_by_hash;
|
||||
typedef std::map<uint64_t, std::vector<std::pair<crypto::hash, size_t>>> outputs_container; //crypto::hash - tx hash, size_t - index of out in transaction
|
||||
|
||||
tx_memory_pool& m_tx_pool;
|
||||
critical_section m_blockchain_lock; // TODO: add here reader/writer lock
|
||||
|
||||
// main chain
|
||||
blocks_container m_blocks; // height -> block_extended_info
|
||||
blocks_by_id_index m_blocks_index; // crypto::hash -> height
|
||||
transactions_container m_transactions;
|
||||
key_images_container m_spent_keys;
|
||||
size_t m_current_block_comul_sz_limit;
|
||||
|
||||
|
||||
// all alternative chains
|
||||
blocks_ext_by_hash m_alternative_chains; // crypto::hash -> block_extended_info
|
||||
|
||||
// some invalid blocks
|
||||
blocks_ext_by_hash m_invalid_blocks; // 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;
|
||||
|
||||
|
||||
|
||||
|
||||
bool switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::iterator>& alt_chain);
|
||||
bool pop_block_from_blockchain();
|
||||
bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count);
|
||||
bool purge_transaction_from_blockchain(const crypto::hash& tx_id);
|
||||
bool purge_transaction_keyimages_from_blockchain(const transaction& tx, bool strict_check);
|
||||
|
||||
bool handle_block_to_main_chain(const block& bl, block_verification_context& bvc);
|
||||
bool handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc);
|
||||
bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc);
|
||||
//bool handle_block_as_orphaned(const block& b, const crypto::hash& id, block_verification_context& bvc);
|
||||
difficulty_type get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::iterator>& alt_chain, block_extended_info& bei);
|
||||
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 add_block_to_orphaned_by_tx(const block& bl, const crypto::hash& h);
|
||||
//bool finish_forward_orphaned_chain(std::list< orphans_indexed_container::index<by_id>::type::iterator >& orph_chain);
|
||||
bool rollback_blockchain_switching(std::list<block>& original_chain, size_t rollback_height);
|
||||
bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height);
|
||||
bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector<uint64_t>& global_indexes);
|
||||
bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id);
|
||||
//bool review_orphaned_blocks_with_new_block_id(const crypto::hash& id, bool main_chain);
|
||||
//void review_orphaned_blocks_finisher();
|
||||
bool get_last_n_blocks_sizes(std::vector<size_t>& sz, size_t count);
|
||||
bool add_out_to_get_random_outs(std::vector<std::pair<crypto::hash, size_t> >& amount_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i);
|
||||
bool is_tx_spendtime_unlocked(uint64_t unlock_time);
|
||||
bool add_block_as_invalid(const block& bl, const crypto::hash& h);
|
||||
bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h);
|
||||
size_t find_end_of_allowed_index(const std::vector<std::pair<crypto::hash, size_t> >& amount_outs);
|
||||
uint64_t block_difficulty(size_t i);
|
||||
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();
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
#define CURRENT_BLOCKCHAIN_STORAGE_ARCHIVE_VER 11
|
||||
|
||||
template<class archive_t>
|
||||
void blockchain_storage::serialize(archive_t & ar, const unsigned int version)
|
||||
{
|
||||
if(version < CURRENT_BLOCKCHAIN_STORAGE_ARCHIVE_VER)
|
||||
return;
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
ar & m_blocks;
|
||||
ar & m_blocks_index;
|
||||
ar & m_transactions;
|
||||
ar & m_spent_keys;
|
||||
ar & m_alternative_chains;
|
||||
ar & m_outputs;
|
||||
ar & m_invalid_blocks;
|
||||
ar & m_current_block_comul_sz_limit;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
|
||||
auto it = m_outputs.find(tx_in_to_key.amount);
|
||||
if(it == m_outputs.end() || !tx_in_to_key.key_offsets.size())
|
||||
return false;
|
||||
|
||||
std::vector<uint64_t> absolute_offsets = relative_output_offsets_to_absolute(tx_in_to_key.key_offsets);
|
||||
|
||||
|
||||
std::vector<std::pair<crypto::hash, size_t> >& amount_outs_vec = it->second;
|
||||
size_t count = 0;
|
||||
BOOST_FOREACH(uint64_t i, absolute_offsets)
|
||||
{
|
||||
if(i >= amount_outs_vec.size() )
|
||||
{
|
||||
LOG_PRINT_L0("Wrong index in transaction inputs: " << i << ", expected maximum " << amount_outs_vec.size() - 1);
|
||||
return false;
|
||||
}
|
||||
transactions_container::iterator tx_it = m_transactions.find(amount_outs_vec[i].first);
|
||||
CHECK_AND_ASSERT_MES(tx_it != m_transactions.end(), false, "Wrong transaction id in output indexes: " <<string_tools::pod_to_hex(amount_outs_vec[i].first));
|
||||
CHECK_AND_ASSERT_MES(amount_outs_vec[i].second < tx_it->second.tx.vout.size(), false,
|
||||
"Wrong index in transaction outputs: " << amount_outs_vec[i].second << ", expected less then " << tx_it->second.tx.vout.size());
|
||||
if(!vis.handle_output(tx_it->second.tx, tx_it->second.tx.vout[amount_outs_vec[i].second]))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to handle_output for output no = " << count << ", with absolute offset " << i);
|
||||
return false;
|
||||
}
|
||||
if(count++ == absolute_offsets.size()-1 && pmax_related_block_height)
|
||||
{
|
||||
if(*pmax_related_block_height < tx_it->second.m_keeper_block_height)
|
||||
*pmax_related_block_height = tx_it->second.m_keeper_block_height;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_CLASS_VERSION(cryptonote::blockchain_storage, CURRENT_BLOCKCHAIN_STORAGE_ARCHIVE_VER)
|
33
src/cryptonote_core/blockchain_storage_boost_serialization.h
Normal file
33
src/cryptonote_core/blockchain_storage_boost_serialization.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
// 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
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
|
||||
|
||||
template<class archive_t>
|
||||
void serialize(archive_t & ar, cryptonote::blockchain_storage::transaction_chain_entry& te, const unsigned int version)
|
||||
{
|
||||
ar & te.tx;
|
||||
ar & te.m_keeper_block_height;
|
||||
ar & te.m_blob_size;
|
||||
ar & te.m_global_output_indexes;
|
||||
}
|
||||
|
||||
template<class archive_t>
|
||||
void serialize(archive_t & ar, cryptonote::blockchain_storage::block_extended_info& ei, const unsigned int version)
|
||||
{
|
||||
ar & ei.bl;
|
||||
ar & ei.height;
|
||||
ar & ei.cumulative_difficulty;
|
||||
ar & ei.block_cumulative_size;
|
||||
ar & ei.already_generated_coins;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
48
src/cryptonote_core/checkpoints.cpp
Normal file
48
src/cryptonote_core/checkpoints.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
// 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.
|
||||
|
||||
#include "include_base_utils.h"
|
||||
using namespace epee;
|
||||
|
||||
#include "checkpoints.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
//---------------------------------------------------------------------------
|
||||
checkpoints::checkpoints()
|
||||
{
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
bool r = epee::string_tools::parse_tpod_from_hex_string(hash_str, h);
|
||||
CHECK_AND_ASSERT_MES(r, false, "WRONG HASH IN CHECKPOINTS!!!");
|
||||
CHECK_AND_ASSERT_MES(0 == m_points.count(height), false, "WRONG HASH IN CHECKPOINTS!!!");
|
||||
m_points[height] = h;
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool checkpoints::is_in_checkpoint_zone(uint64_t height) const
|
||||
{
|
||||
return !m_points.empty() && (height <= (--m_points.end())->first);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool checkpoints::check_block(uint64_t height, const crypto::hash& h) const
|
||||
{
|
||||
auto it = m_points.find(height);
|
||||
if(it == m_points.end())
|
||||
return true;
|
||||
|
||||
if(it->second == h)
|
||||
{
|
||||
LOG_PRINT_GREEN("CHECKPOINT PASSED FOR HEIGHT " << height << " " << h, LOG_LEVEL_0);
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
LOG_ERROR("CHECKPOINT FAILED FOR HEIGHT " << height << ". EXPECTED HASH: " << it->second << ", FETCHED HASH: " << h);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
22
src/cryptonote_core/checkpoints.h
Normal file
22
src/cryptonote_core/checkpoints.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
// 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
|
||||
#include <map>
|
||||
#include "cryptonote_basic_impl.h"
|
||||
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
class checkpoints
|
||||
{
|
||||
public:
|
||||
checkpoints();
|
||||
bool add_checkpoint(uint64_t height, const std::string& hash_str);
|
||||
bool is_in_checkpoint_zone(uint64_t height) const;
|
||||
bool check_block(uint64_t height, const crypto::hash& h) const;
|
||||
private:
|
||||
std::map<uint64_t, crypto::hash> m_points;
|
||||
};
|
||||
}
|
27
src/cryptonote_core/checkpoints_create.h
Normal file
27
src/cryptonote_core/checkpoints_create.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
// 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
|
||||
|
||||
#include "checkpoints.h"
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(checkpoints.add_checkpoint(h, hash), false);
|
||||
|
||||
namespace cryptonote {
|
||||
inline bool create_checkpoints(cryptonote::checkpoints& checkpoints)
|
||||
{
|
||||
ADD_CHECKPOINT(79000, "cae33204e624faeb64938d80073bb7bbacc27017dc63f36c5c0f313cad455a02");
|
||||
ADD_CHECKPOINT(140000, "993059fb6ab92db7d80d406c67a52d9c02d873ca34b6290a12b744c970208772");
|
||||
ADD_CHECKPOINT(200000, "a5f74c7542077df6859f48b5b1f9c3741f29df38f91a47e14c94b5696e6c3073");
|
||||
ADD_CHECKPOINT(230580, "32bd7cb6c68a599cf2861941f29002a5e203522b9af54f08dfced316f6459103");
|
||||
ADD_CHECKPOINT(260000, "f68e70b360ca194f48084da7a7fd8e0251bbb4b5587f787ca65a6f5baf3f5947");
|
||||
ADD_CHECKPOINT(300000, "8e80861713f68354760dc10ea6ea79f5f3ff28f39b3f0835a8637463b09d70ff");
|
||||
ADD_CHECKPOINT(390285, "e00bdc9bf407aeace2f3109de11889ed25894bf194231d075eddaec838097eb7");
|
||||
ADD_CHECKPOINT(417000, "2dc96f8fc4d4a4d76b3ed06722829a7ab09d310584b8ecedc9b578b2c458a69f");
|
||||
ADD_CHECKPOINT(427193, "00feabb08f2d5759ed04fd6b799a7513187478696bba2db2af10d4347134e311");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
54
src/cryptonote_core/connection_context.h
Normal file
54
src/cryptonote_core/connection_context.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
// 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
|
||||
#include <unordered_set>
|
||||
#include <atomic>
|
||||
#include "net/net_utils_base.h"
|
||||
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
class my_atomic: public std::atomic<uint32_t>
|
||||
{
|
||||
public:
|
||||
my_atomic()
|
||||
{};
|
||||
my_atomic(const my_atomic& a):std::atomic<uint32_t>(a.load())
|
||||
{}
|
||||
my_atomic& operator= (const my_atomic& a)
|
||||
{
|
||||
store(a.load());
|
||||
return *this;
|
||||
}
|
||||
uint32_t operator++()
|
||||
{
|
||||
return std::atomic<uint32_t>::operator++();
|
||||
}
|
||||
uint32_t operator++(int fake)
|
||||
{
|
||||
return std::atomic<uint32_t>::operator++(fake);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct cryptonote_connection_context: public epee::net_utils::connection_context_base
|
||||
{
|
||||
|
||||
enum state
|
||||
{
|
||||
state_befor_handshake = 0, //default state
|
||||
state_synchronizing,
|
||||
state_normal
|
||||
};
|
||||
|
||||
state m_state;
|
||||
std::list<crypto::hash> m_needed_objects;
|
||||
std::unordered_set<crypto::hash> m_requested_objects;
|
||||
uint64_t m_remote_blockchain_height;
|
||||
uint64_t m_last_response_height;
|
||||
my_atomic m_callback_request_count; //in debug purpose: problem with double callback rise
|
||||
//size_t m_score; TODO: add score calculations
|
||||
};
|
||||
}
|
347
src/cryptonote_core/cryptonote_basic.h
Normal file
347
src/cryptonote_core/cryptonote_basic.h
Normal file
|
@ -0,0 +1,347 @@
|
|||
// 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
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/functional/hash/hash.hpp>
|
||||
#include <vector>
|
||||
#include <cstring> // memcmp
|
||||
#include <sstream>
|
||||
#include "serialization/serialization.h"
|
||||
#include "serialization/variant.h"
|
||||
#include "serialization/vector.h"
|
||||
#include "serialization/binary_archive.h"
|
||||
#include "serialization/json_archive.h"
|
||||
#include "serialization/debug_archive.h"
|
||||
#include "serialization/crypto.h"
|
||||
#include "serialization/keyvalue_serialization.h" // eepe named serialization
|
||||
#include "string_tools.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "misc_language.h"
|
||||
#include "tx_extra.h"
|
||||
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash);
|
||||
const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey);
|
||||
|
||||
typedef std::vector<crypto::signature> ring_signature;
|
||||
|
||||
|
||||
/* outputs */
|
||||
|
||||
struct txout_to_script
|
||||
{
|
||||
std::vector<crypto::public_key> keys;
|
||||
std::vector<uint8_t> script;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(keys)
|
||||
FIELD(script)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txout_to_scripthash
|
||||
{
|
||||
crypto::hash hash;
|
||||
};
|
||||
|
||||
struct txout_to_key
|
||||
{
|
||||
txout_to_key() { }
|
||||
txout_to_key(const crypto::public_key &_key) : key(_key) { }
|
||||
crypto::public_key key;
|
||||
};
|
||||
|
||||
|
||||
/* inputs */
|
||||
|
||||
struct txin_gen
|
||||
{
|
||||
size_t height;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(height)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_to_script
|
||||
{
|
||||
crypto::hash prev;
|
||||
size_t prevout;
|
||||
std::vector<uint8_t> sigset;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(prev)
|
||||
VARINT_FIELD(prevout)
|
||||
FIELD(sigset)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_to_scripthash
|
||||
{
|
||||
crypto::hash prev;
|
||||
size_t prevout;
|
||||
txout_to_script script;
|
||||
std::vector<uint8_t> sigset;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(prev)
|
||||
VARINT_FIELD(prevout)
|
||||
FIELD(script)
|
||||
FIELD(sigset)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_to_key
|
||||
{
|
||||
uint64_t amount;
|
||||
std::vector<uint64_t> key_offsets;
|
||||
crypto::key_image k_image; // double spending protection
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(key_offsets)
|
||||
FIELD(k_image)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
||||
typedef boost::variant<txin_gen, txin_to_script, txin_to_scripthash, txin_to_key> txin_v;
|
||||
|
||||
typedef boost::variant<txout_to_script, txout_to_scripthash, txout_to_key> txout_target_v;
|
||||
|
||||
//typedef std::pair<uint64_t, txout> out_t;
|
||||
struct tx_out
|
||||
{
|
||||
uint64_t amount;
|
||||
txout_target_v target;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(target)
|
||||
END_SERIALIZE()
|
||||
|
||||
|
||||
};
|
||||
|
||||
class transaction_prefix
|
||||
{
|
||||
|
||||
public:
|
||||
// tx information
|
||||
size_t version;
|
||||
uint64_t unlock_time; //number of block (or time), used as a limitation like: spend this tx not early then block/time
|
||||
|
||||
std::vector<txin_v> vin;
|
||||
std::vector<tx_out> vout;
|
||||
//extra
|
||||
std::vector<uint8_t> extra;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(version)
|
||||
if(CURRENT_TRANSACTION_VERSION < version) return false;
|
||||
VARINT_FIELD(unlock_time)
|
||||
FIELD(vin)
|
||||
FIELD(vout)
|
||||
FIELD(extra)
|
||||
END_SERIALIZE()
|
||||
|
||||
|
||||
protected:
|
||||
transaction_prefix(){}
|
||||
};
|
||||
|
||||
class transaction: public transaction_prefix
|
||||
{
|
||||
public:
|
||||
std::vector<std::vector<crypto::signature> > signatures; //count signatures always the same as inputs count
|
||||
|
||||
transaction();
|
||||
virtual ~transaction();
|
||||
void set_null();
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELDS(*static_cast<transaction_prefix *>(this))
|
||||
|
||||
ar.tag("signatures");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures);
|
||||
bool signatures_not_expected = signatures.empty();
|
||||
if (!signatures_not_expected && vin.size() != signatures.size())
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < vin.size(); ++i)
|
||||
{
|
||||
size_t signature_size = get_signature_size(vin[i]);
|
||||
if (signatures_not_expected)
|
||||
{
|
||||
if (0 == signature_size)
|
||||
continue;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]);
|
||||
if (signature_size != signatures[i].size())
|
||||
return false;
|
||||
|
||||
FIELDS(signatures[i]);
|
||||
|
||||
if (vin.size() - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
END_SERIALIZE()
|
||||
|
||||
private:
|
||||
static size_t get_signature_size(const txin_v& tx_in);
|
||||
};
|
||||
|
||||
|
||||
inline
|
||||
transaction::transaction()
|
||||
{
|
||||
set_null();
|
||||
}
|
||||
|
||||
inline
|
||||
transaction::~transaction()
|
||||
{
|
||||
//set_null();
|
||||
}
|
||||
|
||||
inline
|
||||
void transaction::set_null()
|
||||
{
|
||||
version = 0;
|
||||
unlock_time = 0;
|
||||
vin.clear();
|
||||
vout.clear();
|
||||
extra.clear();
|
||||
signatures.clear();
|
||||
}
|
||||
|
||||
inline
|
||||
size_t transaction::get_signature_size(const txin_v& tx_in)
|
||||
{
|
||||
struct txin_signature_size_visitor : public boost::static_visitor<size_t>
|
||||
{
|
||||
size_t operator()(const txin_gen& txin) const{return 0;}
|
||||
size_t operator()(const txin_to_script& txin) const{return 0;}
|
||||
size_t operator()(const txin_to_scripthash& txin) const{return 0;}
|
||||
size_t operator()(const txin_to_key& txin) const {return txin.key_offsets.size();}
|
||||
};
|
||||
|
||||
return boost::apply_visitor(txin_signature_size_visitor(), tx_in);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct block_header
|
||||
{
|
||||
uint8_t major_version;
|
||||
uint8_t minor_version;
|
||||
uint64_t timestamp;
|
||||
crypto::hash prev_id;
|
||||
uint32_t nonce;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(major_version)
|
||||
if(major_version > CURRENT_BLOCK_MAJOR_VERSION) return false;
|
||||
VARINT_FIELD(minor_version)
|
||||
VARINT_FIELD(timestamp)
|
||||
FIELD(prev_id)
|
||||
FIELD(nonce)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct block: public block_header
|
||||
{
|
||||
transaction miner_tx;
|
||||
std::vector<crypto::hash> tx_hashes;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELDS(*static_cast<block_header *>(this))
|
||||
FIELD(miner_tx)
|
||||
FIELD(tx_hashes)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct account_public_address
|
||||
{
|
||||
crypto::public_key m_spend_public_key;
|
||||
crypto::public_key m_view_public_key;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(m_spend_public_key)
|
||||
FIELD(m_view_public_key)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_public_key)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_public_key)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct keypair
|
||||
{
|
||||
crypto::public_key pub;
|
||||
crypto::secret_key sec;
|
||||
|
||||
static inline keypair generate()
|
||||
{
|
||||
keypair k;
|
||||
generate_keys(k.pub, k.sec);
|
||||
return k;
|
||||
}
|
||||
};
|
||||
//---------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
BLOB_SERIALIZER(cryptonote::txout_to_key);
|
||||
BLOB_SERIALIZER(cryptonote::txout_to_scripthash);
|
||||
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_gen, 0xff);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_to_script, 0x0);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_to_scripthash, 0x1);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_to_key, 0x2);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_script, 0x0);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2);
|
||||
VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc);
|
||||
VARIANT_TAG(binary_archive, cryptonote::block, 0xbb);
|
||||
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_gen, "gen");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_to_script, "script");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_to_key, "key");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_script, "script");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_key, "key");
|
||||
VARIANT_TAG(json_archive, cryptonote::transaction, "tx");
|
||||
VARIANT_TAG(json_archive, cryptonote::block, "block");
|
||||
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_gen, "gen");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_to_script, "script");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_to_key, "key");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_script, "script");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_key, "key");
|
||||
VARIANT_TAG(debug_archive, cryptonote::transaction, "tx");
|
||||
VARIANT_TAG(debug_archive, cryptonote::block, "block");
|
193
src/cryptonote_core/cryptonote_basic_impl.cpp
Normal file
193
src/cryptonote_core/cryptonote_basic_impl.cpp
Normal file
|
@ -0,0 +1,193 @@
|
|||
// 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.
|
||||
|
||||
|
||||
#include "include_base_utils.h"
|
||||
using namespace epee;
|
||||
|
||||
#include "cryptonote_basic_impl.h"
|
||||
#include "string_tools.h"
|
||||
#include "serialization/binary_utils.h"
|
||||
#include "serialization/vector.h"
|
||||
#include "cryptonote_format_utils.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "misc_language.h"
|
||||
#include "common/base58.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "common/int-util.h"
|
||||
|
||||
namespace cryptonote {
|
||||
|
||||
/************************************************************************/
|
||||
/* Cryptonote helper functions */
|
||||
/************************************************************************/
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
size_t get_max_block_size()
|
||||
{
|
||||
return CRYPTONOTE_MAX_BLOCK_SIZE;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
size_t get_max_tx_size()
|
||||
{
|
||||
return CRYPTONOTE_MAX_TX_SIZE;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
uint64_t get_block_reward(std::vector<size_t>& last_blocks_sizes, size_t current_block_size, bool& block_too_big, uint64_t already_generated_coins)
|
||||
{
|
||||
block_too_big = false;
|
||||
|
||||
uint64_t base_reward = (MONEY_SUPPLY - already_generated_coins) >> 18;
|
||||
|
||||
if(current_block_size < CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE)
|
||||
return base_reward;
|
||||
|
||||
size_t med_sz = misc_utils::median(last_blocks_sizes);
|
||||
|
||||
//make it soft
|
||||
if(med_sz < CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE)
|
||||
med_sz = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE;
|
||||
|
||||
if(current_block_size > med_sz)
|
||||
{
|
||||
if(current_block_size > med_sz*2)
|
||||
{
|
||||
LOG_PRINT_L0("Block cumulative size is too big: " << current_block_size << ", expected less than " << med_sz*2);
|
||||
block_too_big = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(med_sz < std::numeric_limits<uint32_t>::max());
|
||||
assert(current_block_size < std::numeric_limits<uint32_t>::max());
|
||||
|
||||
uint64_t product_hi;
|
||||
uint64_t product_lo = mul128(base_reward, current_block_size * (2 * med_sz - current_block_size), &product_hi);
|
||||
|
||||
uint64_t reward_hi;
|
||||
uint64_t reward_lo;
|
||||
div128_32(product_hi, product_lo, static_cast<uint32_t>(med_sz), &reward_hi, &reward_lo);
|
||||
div128_32(reward_hi, reward_lo, static_cast<uint32_t>(med_sz), &reward_hi, &reward_lo);
|
||||
assert(0 == reward_hi);
|
||||
assert(reward_lo < base_reward);
|
||||
|
||||
return reward_lo;
|
||||
}else
|
||||
return base_reward;
|
||||
}
|
||||
//------------------------------------------------------------------------------------
|
||||
uint8_t get_account_address_checksum(const public_address_outer_blob& bl)
|
||||
{
|
||||
const unsigned char* pbuf = reinterpret_cast<const unsigned char*>(&bl);
|
||||
uint8_t summ = 0;
|
||||
for(size_t i = 0; i!= sizeof(public_address_outer_blob)-1; i++)
|
||||
summ += pbuf[i];
|
||||
|
||||
return summ;
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
std::string get_account_address_as_str(const account_public_address& adr)
|
||||
{
|
||||
return tools::base58::encode_addr(CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(adr));
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
bool is_coinbase(const transaction& tx)
|
||||
{
|
||||
if(tx.vin.size() != 1)
|
||||
return false;
|
||||
|
||||
if(tx.vin[0].type() != typeid(txin_gen))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
bool get_account_address_from_str(account_public_address& adr, const std::string& str)
|
||||
{
|
||||
if (2 * sizeof(public_address_outer_blob) != str.size())
|
||||
{
|
||||
blobdata data;
|
||||
uint64_t prefix;
|
||||
if (!tools::base58::decode_addr(str, prefix, data))
|
||||
{
|
||||
LOG_PRINT_L0("Invalid address format");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX != prefix)
|
||||
{
|
||||
LOG_PRINT_L0("Wrong address prefix: " << prefix << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!::serialization::parse_binary(data, adr))
|
||||
{
|
||||
LOG_PRINT_L0("Account public address keys can't be parsed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!crypto::check_key(adr.m_spend_public_key) || !crypto::check_key(adr.m_view_public_key))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to validate address keys");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Old address format
|
||||
std::string buff;
|
||||
if(!string_tools::parse_hexstr_to_binbuff(str, buff))
|
||||
return false;
|
||||
|
||||
if(buff.size()!=sizeof(public_address_outer_blob))
|
||||
{
|
||||
LOG_PRINT_L0("Wrong public address size: " << buff.size() << ", expected size: " << sizeof(public_address_outer_blob));
|
||||
return false;
|
||||
}
|
||||
|
||||
public_address_outer_blob blob = *reinterpret_cast<const public_address_outer_blob*>(buff.data());
|
||||
|
||||
|
||||
if(blob.m_ver > CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER)
|
||||
{
|
||||
LOG_PRINT_L0("Unknown version of public address: " << blob.m_ver << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(blob.check_sum != get_account_address_checksum(blob))
|
||||
{
|
||||
LOG_PRINT_L0("Wrong public address checksum");
|
||||
return false;
|
||||
}
|
||||
|
||||
//we success
|
||||
adr = blob.m_address;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) {
|
||||
return cryptonote::get_transaction_hash(a) == cryptonote::get_transaction_hash(b);
|
||||
}
|
||||
|
||||
bool operator ==(const cryptonote::block& a, const cryptonote::block& b) {
|
||||
return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool parse_hash256(const std::string str_hash, crypto::hash& hash)
|
||||
{
|
||||
std::string buf;
|
||||
bool res = epee::string_tools::parse_hexstr_to_binbuff(str_hash, buf);
|
||||
if (!res || buf.size() != sizeof(crypto::hash))
|
||||
{
|
||||
std::cout << "invalid hash format: <" << str_hash << '>' << std::endl;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.copy(reinterpret_cast<char *>(&hash), sizeof(crypto::hash));
|
||||
return true;
|
||||
}
|
||||
}
|
65
src/cryptonote_core/cryptonote_basic_impl.h
Normal file
65
src/cryptonote_core/cryptonote_basic_impl.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
// 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
|
||||
|
||||
#include "cryptonote_basic.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
|
||||
namespace cryptonote {
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
template<class t_array>
|
||||
struct array_hasher: std::unary_function<t_array&, std::size_t>
|
||||
{
|
||||
std::size_t operator()(const t_array& val) const
|
||||
{
|
||||
return boost::hash_range(&val.data[0], &val.data[sizeof(val.data)]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct public_address_outer_blob
|
||||
{
|
||||
uint8_t m_ver;
|
||||
account_public_address m_address;
|
||||
uint8_t check_sum;
|
||||
};
|
||||
#pragma pack (pop)
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Cryptonote helper functions */
|
||||
/************************************************************************/
|
||||
size_t get_max_block_size();
|
||||
size_t get_max_tx_size();
|
||||
uint64_t get_block_reward(std::vector<size_t>& last_blocks_sizes, size_t current_block_size, bool& block_too_big, uint64_t already_generated_coins);
|
||||
uint8_t get_account_address_checksum(const public_address_outer_blob& bl);
|
||||
std::string get_account_address_as_str(const account_public_address& adr);
|
||||
bool get_account_address_from_str(account_public_address& adr, const std::string& str);
|
||||
bool is_coinbase(const transaction& tx);
|
||||
|
||||
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b);
|
||||
bool operator ==(const cryptonote::block& a, const cryptonote::block& b);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::ostream &print256(std::ostream &o, const T &v) {
|
||||
return o << "<" << epee::string_tools::pod_to_hex(v) << ">";
|
||||
}
|
||||
|
||||
bool parse_hash256(const std::string str_hash, crypto::hash& hash);
|
||||
|
||||
namespace crypto {
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return print256(o, v); }
|
||||
}
|
143
src/cryptonote_core/cryptonote_boost_serialization.h
Normal file
143
src/cryptonote_core/cryptonote_boost_serialization.h
Normal file
|
@ -0,0 +1,143 @@
|
|||
// 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
|
||||
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/utility.hpp>
|
||||
#include <boost/serialization/variant.hpp>
|
||||
#include <boost/serialization/set.hpp>
|
||||
#include <boost/serialization/map.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/serialization/is_bitwise_serializable.hpp>
|
||||
#include "cryptonote_basic.h"
|
||||
#include "common/unordered_containers_boost_serialization.h"
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
//namespace cryptonote {
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
|
||||
//---------------------------------------------------
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::public_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::public_key)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::secret_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::secret_key)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::key_derivation &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_derivation)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::key_image &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_image)]>(x);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::signature &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::signature)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::hash &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::hash)]>(x);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txout_to_script &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.keys;
|
||||
a & x.script;
|
||||
}
|
||||
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txout_to_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.key;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txout_to_scripthash &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.hash;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txin_gen &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.height;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txin_to_script &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.prev;
|
||||
a & x.prevout;
|
||||
a & x.sigset;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txin_to_scripthash &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.prev;
|
||||
a & x.prevout;
|
||||
a & x.script;
|
||||
a & x.sigset;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txin_to_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.amount;
|
||||
a & x.key_offsets;
|
||||
a & x.k_image;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::tx_out &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.amount;
|
||||
a & x.target;
|
||||
}
|
||||
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::transaction &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.version;
|
||||
a & x.unlock_time;
|
||||
a & x.vin;
|
||||
a & x.vout;
|
||||
a & x.extra;
|
||||
a & x.signatures;
|
||||
}
|
||||
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::block &b, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & b.major_version;
|
||||
a & b.minor_version;
|
||||
a & b.timestamp;
|
||||
a & b.prev_id;
|
||||
a & b.nonce;
|
||||
//------------------
|
||||
a & b.miner_tx;
|
||||
a & b.tx_hashes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//}
|
519
src/cryptonote_core/cryptonote_core.cpp
Normal file
519
src/cryptonote_core/cryptonote_core.cpp
Normal file
|
@ -0,0 +1,519 @@
|
|||
// 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.
|
||||
|
||||
|
||||
#include "include_base_utils.h"
|
||||
using namespace epee;
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <unordered_set>
|
||||
#include "cryptonote_core.h"
|
||||
#include "common/command_line.h"
|
||||
#include "common/util.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "cryptonote_format_utils.h"
|
||||
#include "misc_language.h"
|
||||
|
||||
DISABLE_VS_WARNINGS(4355)
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
core::core(i_cryptonote_protocol* pprotocol):
|
||||
m_mempool(m_blockchain_storage),
|
||||
m_blockchain_storage(m_mempool),
|
||||
m_miner(this),
|
||||
m_miner_address(boost::value_initialized<account_public_address>()),
|
||||
m_starter_message_showed(false)
|
||||
{
|
||||
set_cryptonote_protocol(pprotocol);
|
||||
}
|
||||
void core::set_cryptonote_protocol(i_cryptonote_protocol* pprotocol)
|
||||
{
|
||||
if(pprotocol)
|
||||
m_pprotocol = pprotocol;
|
||||
else
|
||||
m_pprotocol = &m_protocol_stub;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
void core::set_checkpoints(checkpoints&& chk_pts)
|
||||
{
|
||||
m_blockchain_storage.set_checkpoints(std::move(chk_pts));
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
void core::init_options(boost::program_options::options_description& /*desc*/)
|
||||
{
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_command_line(const boost::program_options::variables_map& vm)
|
||||
{
|
||||
m_config_folder = command_line::get_arg(vm, command_line::arg_data_dir);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
uint64_t core::get_current_blockchain_height()
|
||||
{
|
||||
return m_blockchain_storage.get_current_blockchain_height();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_blockchain_top(uint64_t& height, crypto::hash& top_id)
|
||||
{
|
||||
top_id = m_blockchain_storage.get_tail_id(height);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks, std::list<transaction>& txs)
|
||||
{
|
||||
return m_blockchain_storage.get_blocks(start_offset, count, blocks, txs);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks)
|
||||
{
|
||||
return m_blockchain_storage.get_blocks(start_offset, count, blocks);
|
||||
} //-----------------------------------------------------------------------------------------------
|
||||
bool core::get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<transaction>& txs, std::list<crypto::hash>& missed_txs)
|
||||
{
|
||||
return m_blockchain_storage.get_transactions(txs_ids, txs, missed_txs);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_transaction(const crypto::hash &h, transaction &tx)
|
||||
{
|
||||
std::vector<crypto::hash> ids;
|
||||
ids.push_back(h);
|
||||
std::list<transaction> ltx;
|
||||
std::list<crypto::hash> missing;
|
||||
if (m_blockchain_storage.get_transactions(ids, ltx, missing))
|
||||
{
|
||||
if (ltx.size() > 0)
|
||||
{
|
||||
tx = *ltx.begin();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_alternative_blocks(std::list<block>& blocks)
|
||||
{
|
||||
return m_blockchain_storage.get_alternative_blocks(blocks);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
size_t core::get_alternative_blocks_count()
|
||||
{
|
||||
return m_blockchain_storage.get_alternative_blocks_count();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::init(const boost::program_options::variables_map& vm)
|
||||
{
|
||||
bool r = handle_command_line(vm);
|
||||
|
||||
r = m_mempool.init(m_config_folder);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");
|
||||
|
||||
r = m_blockchain_storage.init(m_config_folder);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
|
||||
|
||||
r = m_miner.init(vm);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
|
||||
|
||||
return load_state_data();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::set_genesis_block(const block& b)
|
||||
{
|
||||
return m_blockchain_storage.reset_and_set_genesis_block(b);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::load_state_data()
|
||||
{
|
||||
// may be some code later
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::deinit()
|
||||
{
|
||||
m_miner.stop();
|
||||
m_mempool.deinit();
|
||||
m_blockchain_storage.deinit();
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block)
|
||||
{
|
||||
tvc = boost::value_initialized<tx_verification_context>();
|
||||
//want to process all transactions sequentially
|
||||
CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
|
||||
|
||||
if(tx_blob.size() > get_max_tx_size())
|
||||
{
|
||||
LOG_PRINT_L0("WRONG TRANSACTION BLOB, too big size " << tx_blob.size() << ", rejected");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::hash tx_hash = null_hash;
|
||||
crypto::hash tx_prefixt_hash = null_hash;
|
||||
transaction tx;
|
||||
|
||||
if(!parse_tx_from_blob(tx, tx_hash, tx_prefixt_hash, tx_blob))
|
||||
{
|
||||
LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to parse, rejected");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
//std::cout << "!"<< tx.vin.size() << std::endl;
|
||||
|
||||
if(!check_tx_syntax(tx))
|
||||
{
|
||||
LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " syntax, rejected");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_tx_semantic(tx, keeped_by_block))
|
||||
{
|
||||
LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool r = add_new_tx(tx, tx_hash, tx_prefixt_hash, tx_blob.size(), tvc, keeped_by_block);
|
||||
if(tvc.m_verifivation_failed)
|
||||
{LOG_PRINT_RED_L0("Transaction verification failed: " << tx_hash);}
|
||||
else if(tvc.m_verifivation_impossible)
|
||||
{LOG_PRINT_RED_L0("Transaction verification impossible: " << tx_hash);}
|
||||
|
||||
if(tvc.m_added_to_pool)
|
||||
LOG_PRINT_L1("tx added: " << tx_hash);
|
||||
return r;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_stat_info(core_stat_info& st_inf)
|
||||
{
|
||||
st_inf.mining_speed = m_miner.get_speed();
|
||||
st_inf.alternative_blocks = m_blockchain_storage.get_alternative_blocks_count();
|
||||
st_inf.blockchain_height = m_blockchain_storage.get_current_blockchain_height();
|
||||
st_inf.tx_pool_size = m_mempool.get_transactions_count();
|
||||
st_inf.top_block_id_str = epee::string_tools::pod_to_hex(m_blockchain_storage.get_tail_id());
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_semantic(const transaction& tx, bool keeped_by_block)
|
||||
{
|
||||
if(!tx.vin.size())
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx with empty inputs, rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_inputs_types_supported(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("unsupported input types for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_outs_valid(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx with invalid outputs, rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_money_overflow(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx have money overflow, rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::uint64_t amount_in = 0;
|
||||
get_inputs_money_amount(tx, amount_in);
|
||||
boost::uint64_t amount_out = get_outs_money_amount(tx);
|
||||
|
||||
if(amount_in <= amount_out)
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!keeped_by_block && get_object_blobsize(tx) >= m_blockchain_storage.get_current_comulative_blocksize_limit() - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE)
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx have to big size " << get_object_blobsize(tx) << ", expected not bigger than " << m_blockchain_storage.get_current_comulative_blocksize_limit() - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE);
|
||||
return false;
|
||||
}
|
||||
|
||||
//check if tx use different key images
|
||||
if(!check_tx_inputs_keyimages_diff(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx have to big size " << get_object_blobsize(tx) << ", expected not bigger than " << m_blockchain_storage.get_current_comulative_blocksize_limit() - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_inputs_keyimages_diff(const transaction& tx)
|
||||
{
|
||||
std::unordered_set<crypto::key_image> ki;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
|
||||
if(!ki.insert(tokey_in.k_image).second)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block)
|
||||
{
|
||||
crypto::hash tx_hash = get_transaction_hash(tx);
|
||||
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
|
||||
blobdata bl;
|
||||
t_serializable_object_to_blob(tx, bl);
|
||||
return add_new_tx(tx, tx_hash, tx_prefix_hash, bl.size(), tvc, keeped_by_block);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
size_t core::get_blockchain_total_transactions()
|
||||
{
|
||||
return m_blockchain_storage.get_total_transactions();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_outs(uint64_t amount, std::list<crypto::public_key>& pkeys)
|
||||
{
|
||||
return m_blockchain_storage.get_outs(amount, pkeys);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block)
|
||||
{
|
||||
if(m_mempool.have_tx(tx_hash))
|
||||
{
|
||||
LOG_PRINT_L2("tx " << tx_hash << "already have transaction in tx_pool");
|
||||
return true;
|
||||
}
|
||||
|
||||
if(m_blockchain_storage.have_tx(tx_hash))
|
||||
{
|
||||
LOG_PRINT_L2("tx " << tx_hash << " already have transaction in blockchain");
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_mempool.add_tx(tx, tx_hash, blob_size, tvc, keeped_by_block);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce)
|
||||
{
|
||||
return m_blockchain_storage.create_block_template(b, adr, diffic, height, ex_nonce);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp)
|
||||
{
|
||||
return m_blockchain_storage.find_blockchain_supplement(qblock_ids, resp);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::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)
|
||||
{
|
||||
return m_blockchain_storage.find_blockchain_supplement(qblock_ids, blocks, total_height, start_height, max_count);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::print_blockchain(uint64_t start_index, uint64_t end_index)
|
||||
{
|
||||
m_blockchain_storage.print_blockchain(start_index, end_index);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::print_blockchain_index()
|
||||
{
|
||||
m_blockchain_storage.print_blockchain_index();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::print_blockchain_outs(const std::string& file)
|
||||
{
|
||||
m_blockchain_storage.print_blockchain_outs(file);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)
|
||||
{
|
||||
return m_blockchain_storage.get_random_outs_for_amounts(req, res);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs)
|
||||
{
|
||||
return m_blockchain_storage.get_tx_outputs_gindexs(tx_id, indexs);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::pause_mine()
|
||||
{
|
||||
m_miner.pause();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::resume_mine()
|
||||
{
|
||||
m_miner.resume();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_block_found(block& b)
|
||||
{
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
m_miner.pause();
|
||||
m_blockchain_storage.add_new_block(b, bvc);
|
||||
//anyway - update miner template
|
||||
update_miner_block_template();
|
||||
m_miner.resume();
|
||||
|
||||
|
||||
CHECK_AND_ASSERT_MES(!bvc.m_verifivation_failed, false, "mined block failed verification");
|
||||
if(bvc.m_added_to_main_chain)
|
||||
{
|
||||
cryptonote_connection_context exclude_context = boost::value_initialized<cryptonote_connection_context>();
|
||||
NOTIFY_NEW_BLOCK::request arg = AUTO_VAL_INIT(arg);
|
||||
arg.hop = 0;
|
||||
arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_height();
|
||||
std::list<crypto::hash> missed_txs;
|
||||
std::list<transaction> txs;
|
||||
m_blockchain_storage.get_transactions(b.tx_hashes, txs, missed_txs);
|
||||
if(missed_txs.size() && m_blockchain_storage.get_block_id_by_height(get_block_height(b)) != get_block_hash(b))
|
||||
{
|
||||
LOG_PRINT_L0("Block found but, seems that reorganize just happened after that, do not relay this block");
|
||||
return true;
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(txs.size() == b.tx_hashes.size() && !missed_txs.size(), false, "cant find some transactions in found block:" << get_block_hash(b) << " txs.size()=" << txs.size()
|
||||
<< ", b.tx_hashes.size()=" << b.tx_hashes.size() << ", missed_txs.size()" << missed_txs.size());
|
||||
|
||||
block_to_blob(b, arg.b.block);
|
||||
//pack transactions
|
||||
BOOST_FOREACH(auto& tx, txs)
|
||||
arg.b.txs.push_back(t_serializable_object_to_blob(tx));
|
||||
|
||||
m_pprotocol->relay_block(arg, exclude_context);
|
||||
}
|
||||
return bvc.m_added_to_main_chain;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::on_synchronized()
|
||||
{
|
||||
m_miner.on_synchronized();
|
||||
}
|
||||
bool core::get_backward_blocks_sizes(uint64_t from_height, std::vector<size_t>& sizes, size_t count)
|
||||
{
|
||||
return m_blockchain_storage.get_backward_blocks_sizes(from_height, sizes, count);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::add_new_block(const block& b, block_verification_context& bvc)
|
||||
{
|
||||
return m_blockchain_storage.add_new_block(b, bvc);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate)
|
||||
{
|
||||
bvc = boost::value_initialized<block_verification_context>();
|
||||
if(block_blob.size() > get_max_block_size())
|
||||
{
|
||||
LOG_PRINT_L0("WRONG BLOCK BLOB, too big size " << block_blob.size() << ", rejected");
|
||||
bvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
if(!parse_and_validate_block_from_blob(block_blob, b))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to parse and validate new block");
|
||||
bvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
add_new_block(b, bvc);
|
||||
if(update_miner_blocktemplate && bvc.m_added_to_main_chain)
|
||||
update_miner_block_template();
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
crypto::hash core::get_tail_id()
|
||||
{
|
||||
return m_blockchain_storage.get_tail_id();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
size_t core::get_pool_transactions_count()
|
||||
{
|
||||
return m_mempool.get_transactions_count();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::have_block(const crypto::hash& id)
|
||||
{
|
||||
return m_blockchain_storage.have_block(id);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob)
|
||||
{
|
||||
return parse_and_validate_tx_from_blob(blob, tx, tx_hash, tx_prefix_hash);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_syntax(const transaction& tx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_pool_transactions(std::list<transaction>& txs)
|
||||
{
|
||||
return m_mempool.get_transactions(txs);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_short_chain_history(std::list<crypto::hash>& ids)
|
||||
{
|
||||
return m_blockchain_storage.get_short_chain_history(ids);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote_connection_context& context)
|
||||
{
|
||||
return m_blockchain_storage.handle_get_objects(arg, rsp);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
crypto::hash core::get_block_id_by_height(uint64_t height)
|
||||
{
|
||||
return m_blockchain_storage.get_block_id_by_height(height);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_by_hash(const crypto::hash &h, block &blk) {
|
||||
return m_blockchain_storage.get_block_by_hash(h, blk);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::get_all_known_block_ids(std::list<crypto::hash> &main, std::list<crypto::hash> &alt, std::list<crypto::hash> &invalid) {
|
||||
m_blockchain_storage.get_all_known_block_ids(main, alt, invalid);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
std::string core::print_pool(bool short_format)
|
||||
{
|
||||
return m_mempool.print_pool(short_format);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::update_miner_block_template()
|
||||
{
|
||||
m_miner.on_block_chain_update();
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::on_idle()
|
||||
{
|
||||
if(!m_starter_message_showed)
|
||||
{
|
||||
LOG_PRINT_L0(ENDL << "**********************************************************************" << ENDL
|
||||
<< "The daemon will start synchronizing with the network. It may take up to several hours." << ENDL
|
||||
<< ENDL
|
||||
<< "You can set the level of process detailization by using command \"set_log <level>\", where <level> is either 0 (no details), 1 (current block height synchronized), or 2 (all details)." << ENDL
|
||||
<< ENDL
|
||||
<< "Use \"help\" command to see the list of available commands." << ENDL
|
||||
<< ENDL
|
||||
<< "Note: in case you need to interrupt the process, use \"exit\" command. Otherwise, the current progress won't be saved." << ENDL
|
||||
<< "**********************************************************************");
|
||||
m_starter_message_showed = true;
|
||||
}
|
||||
|
||||
m_store_blockchain_interval.do_call(boost::bind(&blockchain_storage::store_blockchain, &m_blockchain_storage));
|
||||
m_miner.on_idle();
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
}
|
130
src/cryptonote_core/cryptonote_core.h
Normal file
130
src/cryptonote_core/cryptonote_core.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
// 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
|
||||
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
|
||||
#include "p2p/net_node_common.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler_common.h"
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
#include "tx_pool.h"
|
||||
#include "blockchain_storage.h"
|
||||
#include "miner.h"
|
||||
#include "connection_context.h"
|
||||
#include "cryptonote_core/cryptonote_stat_info.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
PUSH_WARNINGS
|
||||
DISABLE_VS_WARNINGS(4355)
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class core: public i_miner_handler
|
||||
{
|
||||
public:
|
||||
core(i_cryptonote_protocol* pprotocol);
|
||||
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote_connection_context& context);
|
||||
bool on_idle();
|
||||
bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate = true);
|
||||
i_cryptonote_protocol* get_protocol(){return m_pprotocol;}
|
||||
|
||||
//-------------------- i_miner_handler -----------------------
|
||||
virtual bool handle_block_found( block& b);
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce);
|
||||
|
||||
|
||||
miner& get_miner(){return m_miner;}
|
||||
static void init_options(boost::program_options::options_description& desc);
|
||||
bool init(const boost::program_options::variables_map& vm);
|
||||
bool set_genesis_block(const block& b);
|
||||
bool deinit();
|
||||
uint64_t get_current_blockchain_height();
|
||||
bool get_blockchain_top(uint64_t& heeight, crypto::hash& top_id);
|
||||
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);
|
||||
template<class t_ids_container, class t_blocks_container, class t_missed_container>
|
||||
bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs)
|
||||
{
|
||||
return m_blockchain_storage.get_blocks(block_ids, blocks, missed_bs);
|
||||
}
|
||||
crypto::hash get_block_id_by_height(uint64_t height);
|
||||
bool get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<transaction>& txs, std::list<crypto::hash>& missed_txs);
|
||||
bool get_transaction(const crypto::hash &h, transaction &tx);
|
||||
bool get_block_by_hash(const crypto::hash &h, block &blk);
|
||||
void get_all_known_block_ids(std::list<crypto::hash> &main, std::list<crypto::hash> &alt, std::list<crypto::hash> &invalid);
|
||||
|
||||
bool get_alternative_blocks(std::list<block>& blocks);
|
||||
size_t get_alternative_blocks_count();
|
||||
|
||||
void set_cryptonote_protocol(i_cryptonote_protocol* pprotocol);
|
||||
void set_checkpoints(checkpoints&& chk_pts);
|
||||
|
||||
bool get_pool_transactions(std::list<transaction>& txs);
|
||||
size_t get_pool_transactions_count();
|
||||
size_t get_blockchain_total_transactions();
|
||||
bool get_outs(uint64_t amount, std::list<crypto::public_key>& pkeys);
|
||||
bool have_block(const crypto::hash& id);
|
||||
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);
|
||||
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);
|
||||
bool get_stat_info(core_stat_info& st_inf);
|
||||
bool get_backward_blocks_sizes(uint64_t from_height, std::vector<size_t>& sizes, size_t count);
|
||||
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs);
|
||||
crypto::hash get_tail_id();
|
||||
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);
|
||||
void pause_mine();
|
||||
void resume_mine();
|
||||
blockchain_storage& get_blockchain_storage(){return m_blockchain_storage;}
|
||||
//debug functions
|
||||
void print_blockchain(uint64_t start_index, uint64_t end_index);
|
||||
void print_blockchain_index();
|
||||
std::string print_pool(bool short_format);
|
||||
void print_blockchain_outs(const std::string& file);
|
||||
void on_synchronized();
|
||||
|
||||
private:
|
||||
bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool add_new_block(const block& b, block_verification_context& bvc);
|
||||
bool load_state_data();
|
||||
bool parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob);
|
||||
|
||||
bool check_tx_syntax(const transaction& tx);
|
||||
//check correct values, amounts and all lightweight checks not related with database
|
||||
bool check_tx_semantic(const transaction& tx, bool keeped_by_block);
|
||||
//check if tx already in memory pool or in main blockchain
|
||||
|
||||
bool is_key_image_spent(const crypto::key_image& key_im);
|
||||
|
||||
bool check_tx_ring_signature(const txin_to_key& tx, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig);
|
||||
bool is_tx_spendtime_unlocked(uint64_t unlock_time);
|
||||
bool update_miner_block_template();
|
||||
bool handle_command_line(const boost::program_options::variables_map& vm);
|
||||
bool on_update_blocktemplate_interval();
|
||||
bool check_tx_inputs_keyimages_diff(const transaction& tx);
|
||||
|
||||
|
||||
tx_memory_pool m_mempool;
|
||||
blockchain_storage m_blockchain_storage;
|
||||
i_cryptonote_protocol* m_pprotocol;
|
||||
critical_section m_incoming_tx_lock;
|
||||
//m_miner and m_miner_addres are probably temporary here
|
||||
miner m_miner;
|
||||
account_public_address m_miner_address;
|
||||
std::string m_config_folder;
|
||||
cryptonote_protocol_stub m_protocol_stub;
|
||||
math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval;
|
||||
friend class tx_validate_inputs;
|
||||
std::atomic<bool> m_starter_message_showed;
|
||||
};
|
||||
}
|
||||
|
||||
POP_WARNINGS
|
710
src/cryptonote_core/cryptonote_format_utils.cpp
Normal file
710
src/cryptonote_core/cryptonote_format_utils.cpp
Normal file
|
@ -0,0 +1,710 @@
|
|||
// 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.
|
||||
|
||||
#include "include_base_utils.h"
|
||||
using namespace epee;
|
||||
|
||||
#include "cryptonote_format_utils.h"
|
||||
#include <boost/foreach.hpp>
|
||||
#include "cryptonote_config.h"
|
||||
#include "miner.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h)
|
||||
{
|
||||
std::ostringstream s;
|
||||
binary_archive<true> a(s);
|
||||
::serialization::serialize(a, const_cast<transaction_prefix&>(tx));
|
||||
crypto::cn_fast_hash(s.str().data(), s.str().size(), h);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
get_transaction_prefix_hash(tx, h);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << tx_blob;
|
||||
binary_archive<false> ba(ss);
|
||||
bool r = ::serialization::serialize(ba, tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << tx_blob;
|
||||
binary_archive<false> ba(ss);
|
||||
bool r = ::serialization::serialize(ba, tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
|
||||
//TODO: validate tx
|
||||
|
||||
crypto::cn_fast_hash(tx_blob.data(), tx_blob.size(), tx_hash);
|
||||
get_transaction_prefix_hash(tx, tx_prefix_hash);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector<size_t>& blocks_sizes, size_t current_block_size, size_t max_outs)
|
||||
{
|
||||
return construct_miner_tx(height, already_generated_coins, miner_address, tx, fee, blocks_sizes, current_block_size, blobdata(), max_outs);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector<size_t>& blocks_sizes, size_t current_block_size, const blobdata& extra_nonce, size_t max_outs)
|
||||
{
|
||||
tx.vin.clear();
|
||||
tx.vout.clear();
|
||||
tx.extra.clear();
|
||||
|
||||
keypair txkey = keypair::generate();
|
||||
add_tx_pub_key_to_extra(tx, txkey.pub);
|
||||
if(extra_nonce.size())
|
||||
if(!add_tx_extra_nonce(tx, extra_nonce))
|
||||
return false;
|
||||
|
||||
txin_gen in;
|
||||
in.height = height;
|
||||
|
||||
bool block_too_big = false;
|
||||
uint64_t block_reward = get_block_reward(blocks_sizes, current_block_size, block_too_big, already_generated_coins) + fee;
|
||||
if(block_too_big)
|
||||
{
|
||||
LOG_PRINT_L0("Block is too big");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<size_t> out_amounts;
|
||||
decompose_amount_into_digits(block_reward, DEFAULT_FEE,
|
||||
[&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); },
|
||||
[&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); });
|
||||
|
||||
CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero");
|
||||
while (max_outs < out_amounts.size())
|
||||
{
|
||||
out_amounts[out_amounts.size() - 2] += out_amounts.back();
|
||||
out_amounts.resize(out_amounts.size() - 1);
|
||||
}
|
||||
|
||||
size_t summary_amounts = 0;
|
||||
for (size_t no = 0; no < out_amounts.size(); no++)
|
||||
{
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);;
|
||||
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
|
||||
bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")");
|
||||
|
||||
r = crypto::derive_public_key(derivation, no, miner_address.m_spend_public_key, out_eph_public_key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< miner_address.m_spend_public_key << ")");
|
||||
|
||||
txout_to_key tk;
|
||||
tk.key = out_eph_public_key;
|
||||
|
||||
tx_out out;
|
||||
summary_amounts += out.amount = out_amounts[no];
|
||||
out.target = tk;
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(summary_amounts == block_reward, false, "Failed to construct miner tx, summary_amounts = " << summary_amounts << " not equal block_reward = " << block_reward);
|
||||
|
||||
tx.version = CURRENT_TRANSACTION_VERSION;
|
||||
//lock
|
||||
tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
|
||||
tx.vin.push_back(in);
|
||||
//LOG_PRINT("MINER_TX generated ok, block_reward=" << print_money(block_reward) << "(" << print_money(block_reward - fee) << "+" << print_money(fee)
|
||||
// << "), current_block_size=" << current_block_size << ", already_generated_coins=" << already_generated_coins << ", tx_id=" << get_transaction_hash(tx), LOG_LEVEL_2);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki)
|
||||
{
|
||||
crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
|
||||
bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
|
||||
|
||||
r = crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub);
|
||||
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to derive_public_key(" << recv_derivation << ", " << real_output_index << ", " << ack.m_account_address.m_spend_public_key << ")");
|
||||
|
||||
crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, in_ephemeral.sec);
|
||||
|
||||
crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t power_integral(uint64_t a, uint64_t b)
|
||||
{
|
||||
if(b == 0)
|
||||
return 1;
|
||||
uint64_t total = a;
|
||||
for(uint64_t i = 1; i != b; i++)
|
||||
total *= a;
|
||||
return total;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_amount(uint64_t& amount, const std::string& str_amount_)
|
||||
{
|
||||
std::vector<std::string> pars;
|
||||
std::string str_amount = str_amount_;
|
||||
boost::algorithm::trim(str_amount);
|
||||
if(!str_amount.size())
|
||||
return false;
|
||||
if(str_amount[0] == '-')
|
||||
return false;
|
||||
|
||||
boost::split(pars, str_amount, boost::is_any_of("."), boost::token_compress_on );
|
||||
if(pars.size() > 2 || pars.size() < 1)
|
||||
return false;
|
||||
uint64_t left = 0;
|
||||
if(!string_tools::get_xtype_from_string(left, pars[0]))
|
||||
return false;
|
||||
amount = left * power_integral(10, CRYPTONOTE_DISPLAY_DECIMAL_POINT);
|
||||
if(pars.size() == 2)
|
||||
{
|
||||
uint64_t right = 0;
|
||||
if(pars[1].size() > 8 )
|
||||
return false;
|
||||
if(pars[1].size() < 8 )
|
||||
pars[1].append(8 - pars[1].size(), '0');
|
||||
if(!string_tools::get_xtype_from_string(right, pars[1]))
|
||||
return false;
|
||||
amount += right;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_tx_fee(const transaction& tx, uint64_t & fee)
|
||||
{
|
||||
uint64_t amount_in = 0;
|
||||
uint64_t amount_out = 0;
|
||||
BOOST_FOREACH(auto& in, tx.vin)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), 0, "unexpected type id in transaction");
|
||||
amount_in += boost::get<txin_to_key>(in).amount;
|
||||
}
|
||||
BOOST_FOREACH(auto& o, tx.vout)
|
||||
amount_out += o.amount;
|
||||
|
||||
CHECK_AND_ASSERT_MES(amount_in >= amount_out, false, "transaction spend (" <<amount_in << ") more than it has (" << amount_out << ")");
|
||||
fee = amount_in - amount_out;
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_tx_fee(const transaction& tx)
|
||||
{
|
||||
uint64_t r = 0;
|
||||
if(!get_tx_fee(tx, r))
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx)
|
||||
{
|
||||
crypto::public_key pk = null_pkey;
|
||||
parse_and_validate_tx_extra(tx, pk);
|
||||
return pk;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key)
|
||||
{
|
||||
tx_pub_key = null_pkey;
|
||||
bool padding_started = false; //let the padding goes only at the end
|
||||
bool tx_extra_tag_pubkey_found = false;
|
||||
bool tx_extra_extra_nonce_found = false;
|
||||
for(size_t i = 0; i != tx.extra.size();)
|
||||
{
|
||||
if(padding_started)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!tx.extra[i], false, "Failed to parse transaction extra (not 0 after padding) in tx " << get_transaction_hash(tx));
|
||||
}
|
||||
else if(tx.extra[i] == TX_EXTRA_TAG_PUBKEY)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(sizeof(crypto::public_key) <= tx.extra.size()-1-i, false, "Failed to parse transaction extra (TX_EXTRA_TAG_PUBKEY have not enough bytes) in tx " << get_transaction_hash(tx));
|
||||
CHECK_AND_ASSERT_MES(!tx_extra_tag_pubkey_found, false, "Failed to parse transaction extra (duplicate TX_EXTRA_TAG_PUBKEY entry) in tx " << get_transaction_hash(tx));
|
||||
tx_pub_key = *reinterpret_cast<const crypto::public_key*>(&tx.extra[i+1]);
|
||||
i += 1 + sizeof(crypto::public_key);
|
||||
tx_extra_tag_pubkey_found = true;
|
||||
continue;
|
||||
}else if(tx.extra[i] == TX_EXTRA_NONCE)
|
||||
{
|
||||
//CHECK_AND_ASSERT_MES(is_coinbase(tx), false, "Failed to parse transaction extra (TX_EXTRA_NONCE can be only in coinbase) in tx " << get_transaction_hash(tx));
|
||||
CHECK_AND_ASSERT_MES(!tx_extra_extra_nonce_found, false, "Failed to parse transaction extra (duplicate TX_EXTRA_NONCE entry) in tx " << get_transaction_hash(tx));
|
||||
CHECK_AND_ASSERT_MES(tx.extra.size()-1-i >= 1, false, "Failed to parse transaction extra (TX_EXTRA_NONCE have not enough bytes) in tx " << get_transaction_hash(tx));
|
||||
++i;
|
||||
CHECK_AND_ASSERT_MES(tx.extra.size()-1-i >= tx.extra[i], false, "Failed to parse transaction extra (TX_EXTRA_NONCE have wrong bytes counter) in tx " << get_transaction_hash(tx));
|
||||
tx_extra_extra_nonce_found = true;
|
||||
i += tx.extra[i];//actually don't need to extract it now, just skip
|
||||
}
|
||||
else if(!tx.extra[i])
|
||||
{
|
||||
padding_started = true;
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key)
|
||||
{
|
||||
tx.extra.resize(tx.extra.size() + 1 + sizeof(crypto::public_key));
|
||||
tx.extra[tx.extra.size() - 1 - sizeof(crypto::public_key)] = TX_EXTRA_TAG_PUBKEY;
|
||||
*reinterpret_cast<crypto::public_key*>(&tx.extra[tx.extra.size() - sizeof(crypto::public_key)]) = tx_pub_key;
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool add_tx_extra_nonce(transaction& tx, const blobdata& extra_nonce)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(extra_nonce.size() <=255, false, "extra nonce could be 255 bytes max");
|
||||
size_t start_pos = tx.extra.size();
|
||||
tx.extra.resize(tx.extra.size() + 2 + extra_nonce.size());
|
||||
//write tag
|
||||
tx.extra[start_pos] = TX_EXTRA_NONCE;
|
||||
//write len
|
||||
++start_pos;
|
||||
tx.extra[start_pos] = static_cast<uint8_t>(extra_nonce.size());
|
||||
//write data
|
||||
++start_pos;
|
||||
memcpy(&tx.extra[start_pos], extra_nonce.data(), extra_nonce.size());
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, transaction& tx, uint64_t unlock_time)
|
||||
{
|
||||
tx.vin.clear();
|
||||
tx.vout.clear();
|
||||
tx.signatures.clear();
|
||||
tx.extra.clear();
|
||||
|
||||
tx.version = CURRENT_TRANSACTION_VERSION;
|
||||
tx.unlock_time = unlock_time;
|
||||
|
||||
keypair txkey = keypair::generate();
|
||||
add_tx_pub_key_to_extra(tx, txkey.pub);
|
||||
|
||||
struct input_generation_context_data
|
||||
{
|
||||
keypair in_ephemeral;
|
||||
};
|
||||
std::vector<input_generation_context_data> in_contexts;
|
||||
|
||||
|
||||
uint64_t summary_inputs_money = 0;
|
||||
//fill inputs
|
||||
BOOST_FOREACH(const tx_source_entry& src_entr, sources)
|
||||
{
|
||||
if(src_entr.real_output >= src_entr.outputs.size())
|
||||
{
|
||||
LOG_ERROR("real_output index (" << src_entr.real_output << ")bigger than output_keys.size()=" << src_entr.outputs.size());
|
||||
return false;
|
||||
}
|
||||
summary_inputs_money += src_entr.amount;
|
||||
|
||||
//key_derivation recv_derivation;
|
||||
in_contexts.push_back(input_generation_context_data());
|
||||
keypair& in_ephemeral = in_contexts.back().in_ephemeral;
|
||||
crypto::key_image img;
|
||||
if(!generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_ephemeral, img))
|
||||
return false;
|
||||
|
||||
//check that derivated key is equal with real output key
|
||||
if( !(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second) )
|
||||
{
|
||||
LOG_ERROR("derived public key missmatch with output public key! "<< ENDL << "derived_key:"
|
||||
<< string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:"
|
||||
<< string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second) );
|
||||
return false;
|
||||
}
|
||||
|
||||
//put key image into tx input
|
||||
txin_to_key input_to_key;
|
||||
input_to_key.amount = src_entr.amount;
|
||||
input_to_key.k_image = img;
|
||||
|
||||
//fill outputs array and use relative offsets
|
||||
BOOST_FOREACH(const tx_source_entry::output_entry& out_entry, src_entr.outputs)
|
||||
input_to_key.key_offsets.push_back(out_entry.first);
|
||||
|
||||
input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets);
|
||||
tx.vin.push_back(input_to_key);
|
||||
}
|
||||
|
||||
// "Shuffle" outs
|
||||
std::vector<tx_destination_entry> shuffled_dsts(destinations);
|
||||
std::sort(shuffled_dsts.begin(), shuffled_dsts.end(), [](const tx_destination_entry& de1, const tx_destination_entry& de2) { return de1.amount < de2.amount; } );
|
||||
|
||||
uint64_t summary_outs_money = 0;
|
||||
//fill outputs
|
||||
size_t output_index = 0;
|
||||
BOOST_FOREACH(const tx_destination_entry& dst_entr, shuffled_dsts)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(dst_entr.amount > 0, false, "Destination with wrong amount: " << dst_entr.amount);
|
||||
crypto::key_derivation derivation;
|
||||
crypto::public_key out_eph_public_key;
|
||||
bool r = crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, txkey.sec, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_view_public_key << ", " << txkey.sec << ")");
|
||||
|
||||
r = crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to derive_public_key(" << derivation << ", " << output_index << ", "<< dst_entr.addr.m_spend_public_key << ")");
|
||||
|
||||
tx_out out;
|
||||
out.amount = dst_entr.amount;
|
||||
txout_to_key tk;
|
||||
tk.key = out_eph_public_key;
|
||||
out.target = tk;
|
||||
tx.vout.push_back(out);
|
||||
output_index++;
|
||||
summary_outs_money += dst_entr.amount;
|
||||
}
|
||||
|
||||
//check money
|
||||
if(summary_outs_money > summary_inputs_money )
|
||||
{
|
||||
LOG_ERROR("Transaction inputs money ("<< summary_inputs_money << ") less than outputs money (" << summary_outs_money << ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//generate ring signatures
|
||||
crypto::hash tx_prefix_hash;
|
||||
get_transaction_prefix_hash(tx, tx_prefix_hash);
|
||||
|
||||
std::stringstream ss_ring_s;
|
||||
size_t i = 0;
|
||||
BOOST_FOREACH(const tx_source_entry& src_entr, sources)
|
||||
{
|
||||
ss_ring_s << "pub_keys:" << ENDL;
|
||||
std::vector<const crypto::public_key*> keys_ptrs;
|
||||
BOOST_FOREACH(const tx_source_entry::output_entry& o, src_entr.outputs)
|
||||
{
|
||||
keys_ptrs.push_back(&o.second);
|
||||
ss_ring_s << o.second << ENDL;
|
||||
}
|
||||
|
||||
tx.signatures.push_back(std::vector<crypto::signature>());
|
||||
std::vector<crypto::signature>& sigs = tx.signatures.back();
|
||||
sigs.resize(src_entr.outputs.size());
|
||||
crypto::generate_ring_signature(tx_prefix_hash, boost::get<txin_to_key>(tx.vin[i]).k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||
ss_ring_s << "signatures:" << ENDL;
|
||||
std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL;});
|
||||
ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output;
|
||||
i++;
|
||||
}
|
||||
|
||||
LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL << ss_ring_s.str() , LOG_LEVEL_3);
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_inputs_money_amount(const transaction& tx, uint64_t& money)
|
||||
{
|
||||
money = 0;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
|
||||
money += tokey_in.amount;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_block_height(const block& b)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, 0, "wrong miner tx in block: " << get_block_hash(b) << ", b.miner_tx.vin.size() != 1");
|
||||
CHECKED_GET_SPECIFIC_VARIANT(b.miner_tx.vin[0], const txin_gen, coinbase_in, 0);
|
||||
return coinbase_in.height;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool check_inputs_types_supported(const transaction& tx)
|
||||
{
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), false, "wrong variant type: "
|
||||
<< in.type().name() << ", expected " << typeid(txin_to_key).name()
|
||||
<< ", in transaction id=" << get_transaction_hash(tx));
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool check_outs_valid(const transaction& tx)
|
||||
{
|
||||
BOOST_FOREACH(const tx_out& out, tx.vout)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key), false, "wrong variant type: "
|
||||
<< out.target.type().name() << ", expected " << typeid(txout_to_key).name()
|
||||
<< ", in transaction id=" << get_transaction_hash(tx));
|
||||
|
||||
CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount ouput in transaction id=" << get_transaction_hash(tx));
|
||||
|
||||
if(!check_key(boost::get<txout_to_key>(out.target).key))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool check_money_overflow(const transaction& tx)
|
||||
{
|
||||
return check_inputs_overflow(tx) && check_outs_overflow(tx);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool check_inputs_overflow(const transaction& tx)
|
||||
{
|
||||
uint64_t money = 0;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
|
||||
if(money > tokey_in.amount + money)
|
||||
return false;
|
||||
money += tokey_in.amount;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool check_outs_overflow(const transaction& tx)
|
||||
{
|
||||
uint64_t money = 0;
|
||||
BOOST_FOREACH(const auto& o, tx.vout)
|
||||
{
|
||||
if(money > o.amount + money)
|
||||
return false;
|
||||
money += o.amount;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_outs_money_amount(const transaction& tx)
|
||||
{
|
||||
uint64_t outputs_amount = 0;
|
||||
BOOST_FOREACH(const auto& o, tx.vout)
|
||||
outputs_amount += o.amount;
|
||||
return outputs_amount;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
std::string short_hash_str(const crypto::hash& h)
|
||||
{
|
||||
std::string res = string_tools::pod_to_hex(h);
|
||||
CHECK_AND_ASSERT_MES(res.size() == 64, res, "wrong hash256 with string_tools::pod_to_hex conversion");
|
||||
auto erased_pos = res.erase(8, 48);
|
||||
res.insert(8, "....");
|
||||
return res;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index)
|
||||
{
|
||||
crypto::key_derivation derivation;
|
||||
generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation);
|
||||
crypto::public_key pk;
|
||||
derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk);
|
||||
return pk == out_key.key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered)
|
||||
{
|
||||
return lookup_acc_outs(acc, tx, get_tx_pub_key_from_extra(tx), outs, money_transfered);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered)
|
||||
{
|
||||
money_transfered = 0;
|
||||
size_t i = 0;
|
||||
BOOST_FOREACH(const tx_out& o, tx.vout)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong type id in transaction out" );
|
||||
if(is_out_to_acc(acc, boost::get<txout_to_key>(o.target), tx_pub_key, i))
|
||||
{
|
||||
outs.push_back(i);
|
||||
money_transfered += o.amount;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
void get_blob_hash(const blobdata& blob, crypto::hash& res)
|
||||
{
|
||||
cn_fast_hash(blob.data(), blob.size(), res);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
std::string print_money(uint64_t amount)
|
||||
{
|
||||
std::string s = std::to_string(amount);
|
||||
if(s.size() < CRYPTONOTE_DISPLAY_DECIMAL_POINT+1)
|
||||
{
|
||||
s.insert(0, CRYPTONOTE_DISPLAY_DECIMAL_POINT+1 - s.size(), '0');
|
||||
}
|
||||
s.insert(s.size() - CRYPTONOTE_DISPLAY_DECIMAL_POINT, ".");
|
||||
return s;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_blob_hash(const blobdata& blob)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
get_blob_hash(blob, h);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_transaction_hash(const transaction& t)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
size_t blob_size = 0;
|
||||
get_object_hash(t, h, blob_size);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res)
|
||||
{
|
||||
size_t blob_size = 0;
|
||||
return get_object_hash(t, res, blob_size);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size)
|
||||
{
|
||||
return get_object_hash(t, res, blob_size);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata get_block_hashing_blob(const block& b)
|
||||
{
|
||||
blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
|
||||
crypto::hash tree_root_hash = get_tx_tree_hash(b);
|
||||
blob.append((const char*)&tree_root_hash, sizeof(tree_root_hash ));
|
||||
blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
|
||||
return blob;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_block_hash(const block& b, crypto::hash& res)
|
||||
{
|
||||
return get_object_hash(get_block_hashing_blob(b), res);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_block_hash(const block& b)
|
||||
{
|
||||
crypto::hash p = null_hash;
|
||||
get_block_hash(b, p);
|
||||
return p;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool generate_genesis_block(block& bl)
|
||||
{
|
||||
//genesis block
|
||||
bl = boost::value_initialized<block>();
|
||||
|
||||
|
||||
account_public_address ac = boost::value_initialized<account_public_address>();
|
||||
std::vector<size_t> sz;
|
||||
construct_miner_tx(0, 0, ac, bl.miner_tx, 0, sz, 0, 1); // zero fee in genesis
|
||||
blobdata txb = tx_to_blob(bl.miner_tx);
|
||||
std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb);
|
||||
|
||||
//hard code coinbase tx in genesis block, because "tru" generating tx use random, but genesis should be always the same
|
||||
std::string genesis_coinbase_tx_hex = "010a01ff0001ffffffffffff0f029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121013c086a48c15fb637a96991bc6d53caf77068b5ba6eeb3c82357228c49790584a";
|
||||
|
||||
blobdata tx_bl;
|
||||
string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl);
|
||||
bool r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
|
||||
bl.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
bl.minor_version = CURRENT_BLOCK_MINOR_VERSION;
|
||||
bl.timestamp = 0;
|
||||
bl.nonce = 70;
|
||||
miner::find_nonce_for_given_block(bl, 1, 0);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height)
|
||||
{
|
||||
block b_local = b; //workaround to avoid const errors with do_serialize
|
||||
blobdata bd = get_block_hashing_blob(b);
|
||||
crypto::cn_slow_hash(bd.data(), bd.size(), res);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
std::vector<uint64_t> relative_output_offsets_to_absolute(const std::vector<uint64_t>& off)
|
||||
{
|
||||
std::vector<uint64_t> res = off;
|
||||
for(size_t i = 1; i < res.size(); i++)
|
||||
res[i] += res[i-1];
|
||||
return res;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
std::vector<uint64_t> absolute_output_offsets_to_relative(const std::vector<uint64_t>& off)
|
||||
{
|
||||
std::vector<uint64_t> res = off;
|
||||
if(!off.size())
|
||||
return res;
|
||||
std::sort(res.begin(), res.end());//just to be sure, actually it is already should be sorted
|
||||
for(size_t i = res.size()-1; i != 0; i--)
|
||||
res[i] -= res[i-1];
|
||||
|
||||
return res;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_block_longhash(const block& b, uint64_t height)
|
||||
{
|
||||
crypto::hash p = null_hash;
|
||||
get_block_longhash(b, p, height);
|
||||
return p;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << b_blob;
|
||||
binary_archive<false> ba(ss);
|
||||
bool r = ::serialization::serialize(ba, b);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob");
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata block_to_blob(const block& b)
|
||||
{
|
||||
return t_serializable_object_to_blob(b);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool block_to_blob(const block& b, blobdata& b_blob)
|
||||
{
|
||||
return t_serializable_object_to_blob(b, b_blob);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata tx_to_blob(const transaction& tx)
|
||||
{
|
||||
return t_serializable_object_to_blob(tx);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool tx_to_blob(const transaction& tx, blobdata& b_blob)
|
||||
{
|
||||
return t_serializable_object_to_blob(tx, b_blob);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h)
|
||||
{
|
||||
tree_hash(tx_hashes.data(), tx_hashes.size(), h);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
get_tx_tree_hash(tx_hashes, h);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_tx_tree_hash(const block& b)
|
||||
{
|
||||
std::vector<crypto::hash> txs_ids;
|
||||
crypto::hash h = null_hash;
|
||||
size_t bl_sz = 0;
|
||||
get_transaction_hash(b.miner_tx, h, bl_sz);
|
||||
txs_ids.push_back(h);
|
||||
BOOST_FOREACH(auto& th, b.tx_hashes)
|
||||
txs_ids.push_back(th);
|
||||
return get_tx_tree_hash(txs_ids);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
}
|
191
src/cryptonote_core/cryptonote_format_utils.h
Normal file
191
src/cryptonote_core/cryptonote_format_utils.h
Normal file
|
@ -0,0 +1,191 @@
|
|||
// 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
|
||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||
#include "cryptonote_core/cryptonote_basic_impl.h"
|
||||
#include "account.h"
|
||||
#include "include_base_utils.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h);
|
||||
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx);
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash);
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx);
|
||||
bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector<size_t>& blocks_sizes, size_t current_block_size, const blobdata& extra_nonce, size_t max_outs = 1);
|
||||
bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector<size_t>& blocks_sizes, size_t current_block_size, size_t max_outs = 1);
|
||||
|
||||
struct tx_source_entry
|
||||
{
|
||||
typedef std::pair<uint64_t, crypto::public_key> output_entry;
|
||||
|
||||
std::vector<output_entry> outputs; //index + key
|
||||
uint64_t real_output; //index in outputs vector of real output_entry
|
||||
crypto::public_key real_out_tx_key; //incoming real tx public key
|
||||
size_t real_output_in_tx_index; //index in transaction outputs vector
|
||||
uint64_t amount; //money
|
||||
};
|
||||
|
||||
struct tx_destination_entry
|
||||
{
|
||||
uint64_t amount; //money
|
||||
account_public_address addr; //destination address
|
||||
|
||||
tx_destination_entry() { }
|
||||
tx_destination_entry(uint64_t a, const account_public_address &ad) : amount(a), addr(ad) { }
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------
|
||||
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, transaction& tx, uint64_t unlock_time);
|
||||
bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key);
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx);
|
||||
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key);
|
||||
bool add_tx_extra_nonce(transaction& tx, const blobdata& extra_nonce);
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool get_tx_fee(const transaction& tx, uint64_t & fee);
|
||||
uint64_t get_tx_fee(const transaction& tx);
|
||||
bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki);
|
||||
void get_blob_hash(const blobdata& blob, crypto::hash& res);
|
||||
crypto::hash get_blob_hash(const blobdata& blob);
|
||||
std::string short_hash_str(const crypto::hash& h);
|
||||
|
||||
crypto::hash get_transaction_hash(const transaction& t);
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res);
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size);
|
||||
blobdata get_block_hashing_blob(const block& b);
|
||||
bool get_block_hash(const block& b, crypto::hash& res);
|
||||
crypto::hash get_block_hash(const block& b);
|
||||
bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height);
|
||||
crypto::hash get_block_longhash(const block& b, uint64_t height);
|
||||
bool generate_genesis_block(block& bl);
|
||||
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b);
|
||||
bool get_inputs_money_amount(const transaction& tx, uint64_t& money);
|
||||
uint64_t get_outs_money_amount(const transaction& tx);
|
||||
bool check_inputs_types_supported(const transaction& tx);
|
||||
bool check_outs_valid(const transaction& tx);
|
||||
blobdata get_block_hashing_blob(const block& b);
|
||||
bool parse_amount(uint64_t& amount, const std::string& str_amount);
|
||||
|
||||
bool check_money_overflow(const transaction& tx);
|
||||
bool check_outs_overflow(const transaction& tx);
|
||||
bool check_inputs_overflow(const transaction& tx);
|
||||
uint64_t get_block_height(const block& b);
|
||||
std::vector<uint64_t> relative_output_offsets_to_absolute(const std::vector<uint64_t>& off);
|
||||
std::vector<uint64_t> absolute_output_offsets_to_relative(const std::vector<uint64_t>& off);
|
||||
std::string print_money(uint64_t amount);
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
bool t_serializable_object_to_blob(const t_object& to, blobdata& b_blob)
|
||||
{
|
||||
std::stringstream ss;
|
||||
binary_archive<true> ba(ss);
|
||||
bool r = ::serialization::serialize(ba, const_cast<t_object&>(to));
|
||||
b_blob = ss.str();
|
||||
return r;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
blobdata t_serializable_object_to_blob(const t_object& to)
|
||||
{
|
||||
blobdata b;
|
||||
t_serializable_object_to_blob(to, b);
|
||||
return b;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
bool get_object_hash(const t_object& o, crypto::hash& res)
|
||||
{
|
||||
get_blob_hash(t_serializable_object_to_blob(o), res);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
size_t get_object_blobsize(const t_object& o)
|
||||
{
|
||||
blobdata b = t_serializable_object_to_blob(o);
|
||||
return b.size();
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
bool get_object_hash(const t_object& o, crypto::hash& res, size_t& blob_size)
|
||||
{
|
||||
blobdata bl = t_serializable_object_to_blob(o);
|
||||
blob_size = bl.size();
|
||||
get_blob_hash(bl, res);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template <typename T>
|
||||
std::string obj_to_json_str(T& obj)
|
||||
{
|
||||
std::stringstream ss;
|
||||
json_archive<true> ar(ss, true);
|
||||
bool r = ::serialization::serialize(ar, obj);
|
||||
CHECK_AND_ASSERT_MES(r, "", "obj_to_json_str failed: serialization::serialize returned false");
|
||||
return ss.str();
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// 62387455827 -> 455827 + 7000000 + 80000000 + 300000000 + 2000000000 + 60000000000, where 455827 <= dust_threshold
|
||||
template<typename chunk_handler_t, typename dust_handler_t>
|
||||
void decompose_amount_into_digits(uint64_t amount, uint64_t dust_threshold, const chunk_handler_t& chunk_handler, const dust_handler_t& dust_handler)
|
||||
{
|
||||
if (0 == amount)
|
||||
{
|
||||
chunk_handler(0);
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_dust_handled = false;
|
||||
uint64_t dust = 0;
|
||||
uint64_t order = 1;
|
||||
while (0 != amount)
|
||||
{
|
||||
uint64_t chunk = (amount % 10) * order;
|
||||
amount /= 10;
|
||||
order *= 10;
|
||||
|
||||
if (dust + chunk <= dust_threshold)
|
||||
{
|
||||
dust += chunk;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_dust_handled && 0 != dust)
|
||||
{
|
||||
dust_handler(dust);
|
||||
is_dust_handled = true;
|
||||
}
|
||||
if (0 != chunk)
|
||||
{
|
||||
chunk_handler(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_dust_handled && 0 != dust)
|
||||
{
|
||||
dust_handler(dust);
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata block_to_blob(const block& b);
|
||||
bool block_to_blob(const block& b, blobdata& b_blob);
|
||||
blobdata tx_to_blob(const transaction& b);
|
||||
bool tx_to_blob(const transaction& b, blobdata& b_blob);
|
||||
void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h);
|
||||
crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes);
|
||||
crypto::hash get_tx_tree_hash(const block& b);
|
||||
|
||||
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \
|
||||
CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \
|
||||
specific_type& variable_name = boost::get<specific_type>(variant_var);
|
||||
|
||||
}
|
27
src/cryptonote_core/cryptonote_stat_info.h
Normal file
27
src/cryptonote_core/cryptonote_stat_info.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
// 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
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
struct core_stat_info
|
||||
{
|
||||
uint64_t tx_pool_size;
|
||||
uint64_t blockchain_height;
|
||||
uint64_t mining_speed;
|
||||
uint64_t alternative_blocks;
|
||||
std::string top_block_id_str;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tx_pool_size)
|
||||
KV_SERIALIZE(blockchain_height)
|
||||
KV_SERIALIZE(mining_speed)
|
||||
KV_SERIALIZE(alternative_blocks)
|
||||
KV_SERIALIZE(top_block_id_str)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
}
|
111
src/cryptonote_core/difficulty.cpp
Normal file
111
src/cryptonote_core/difficulty.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
// 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.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "common/int-util.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "difficulty.h"
|
||||
|
||||
namespace cryptonote {
|
||||
|
||||
using std::size_t;
|
||||
using std::uint64_t;
|
||||
using std::vector;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <windows.h>
|
||||
#include <winnt.h>
|
||||
|
||||
static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) {
|
||||
low = UnsignedMultiply128(a, b, &high);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) {
|
||||
typedef unsigned __int128 uint128_t;
|
||||
uint128_t res = (uint128_t) a * (uint128_t) b;
|
||||
low = (uint64_t) res;
|
||||
high = (uint64_t) (res >> 64);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline bool cadd(uint64_t a, uint64_t b) {
|
||||
return a + b < a;
|
||||
}
|
||||
|
||||
static inline bool cadc(uint64_t a, uint64_t b, bool c) {
|
||||
return a + b < a || (c && a + b == (uint64_t) -1);
|
||||
}
|
||||
|
||||
bool check_hash(const crypto::hash &hash, difficulty_type difficulty) {
|
||||
uint64_t low, high, top, cur;
|
||||
// First check the highest word, this will most likely fail for a random hash.
|
||||
mul(swap64le(((const uint64_t *) &hash)[3]), difficulty, top, high);
|
||||
if (high != 0) {
|
||||
return false;
|
||||
}
|
||||
mul(swap64le(((const uint64_t *) &hash)[0]), difficulty, low, cur);
|
||||
mul(swap64le(((const uint64_t *) &hash)[1]), difficulty, low, high);
|
||||
bool carry = cadd(cur, low);
|
||||
cur = high;
|
||||
mul(swap64le(((const uint64_t *) &hash)[2]), difficulty, low, high);
|
||||
carry = cadc(cur, low, carry);
|
||||
carry = cadc(high, top, carry);
|
||||
return !carry;
|
||||
}
|
||||
|
||||
difficulty_type next_difficulty(vector<uint64_t> timestamps, vector<difficulty_type> cumulative_difficulties, size_t target_seconds) {
|
||||
//cutoff DIFFICULTY_LAG
|
||||
if(timestamps.size() > DIFFICULTY_WINDOW)
|
||||
{
|
||||
timestamps.resize(DIFFICULTY_WINDOW);
|
||||
cumulative_difficulties.resize(DIFFICULTY_WINDOW);
|
||||
}
|
||||
|
||||
|
||||
size_t length = timestamps.size();
|
||||
assert(length == cumulative_difficulties.size());
|
||||
if (length <= 1) {
|
||||
return 1;
|
||||
}
|
||||
static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small");
|
||||
assert(length <= DIFFICULTY_WINDOW);
|
||||
sort(timestamps.begin(), timestamps.end());
|
||||
size_t cut_begin, cut_end;
|
||||
static_assert(2 * DIFFICULTY_CUT <= DIFFICULTY_WINDOW - 2, "Cut length is too large");
|
||||
if (length <= DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) {
|
||||
cut_begin = 0;
|
||||
cut_end = length;
|
||||
} else {
|
||||
cut_begin = (length - (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) + 1) / 2;
|
||||
cut_end = cut_begin + (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT);
|
||||
}
|
||||
assert(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length);
|
||||
uint64_t time_span = timestamps[cut_end - 1] - timestamps[cut_begin];
|
||||
if (time_span == 0) {
|
||||
time_span = 1;
|
||||
}
|
||||
difficulty_type total_work = cumulative_difficulties[cut_end - 1] - cumulative_difficulties[cut_begin];
|
||||
assert(total_work > 0);
|
||||
uint64_t low, high;
|
||||
mul(total_work, target_seconds, low, high);
|
||||
if (high != 0 || low + time_span - 1 < low) {
|
||||
return 0;
|
||||
}
|
||||
return (low + time_span - 1) / time_span;
|
||||
}
|
||||
|
||||
difficulty_type next_difficulty(vector<uint64_t> timestamps, vector<difficulty_type> cumulative_difficulties)
|
||||
{
|
||||
return next_difficulty(std::move(timestamps), std::move(cumulative_difficulties), DIFFICULTY_TARGET);
|
||||
}
|
||||
}
|
19
src/cryptonote_core/difficulty.h
Normal file
19
src/cryptonote_core/difficulty.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
// 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
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "crypto/hash.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
typedef std::uint64_t difficulty_type;
|
||||
|
||||
bool check_hash(const crypto::hash &hash, difficulty_type difficulty);
|
||||
difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties);
|
||||
difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
|
||||
}
|
356
src/cryptonote_core/miner.cpp
Normal file
356
src/cryptonote_core/miner.cpp
Normal file
|
@ -0,0 +1,356 @@
|
|||
// 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.
|
||||
|
||||
|
||||
#include <sstream>
|
||||
#include <numeric>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include "misc_language.h"
|
||||
#include "include_base_utils.h"
|
||||
#include "cryptonote_basic_impl.h"
|
||||
#include "cryptonote_format_utils.h"
|
||||
#include "file_io_utils.h"
|
||||
#include "common/command_line.h"
|
||||
#include "string_coding.h"
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
|
||||
using namespace epee;
|
||||
|
||||
#include "miner.h"
|
||||
|
||||
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
const command_line::arg_descriptor<std::string> arg_extra_messages = {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true};
|
||||
const command_line::arg_descriptor<std::string> arg_start_mining = {"start-mining", "Specify wallet address to mining for", "", true};
|
||||
const command_line::arg_descriptor<uint32_t> arg_mining_threads = {"mining-threads", "Specify mining threads count", 0, true};
|
||||
}
|
||||
|
||||
|
||||
miner::miner(i_miner_handler* phandler):m_stop(1),
|
||||
m_template(boost::value_initialized<block>()),
|
||||
m_template_no(0),
|
||||
m_diffic(0),
|
||||
m_thread_index(0),
|
||||
m_phandler(phandler),
|
||||
m_height(0),
|
||||
m_pausers_count(0),
|
||||
m_threads_total(0),
|
||||
m_starter_nonce(0),
|
||||
m_last_hr_merge_time(0),
|
||||
m_hashes(0),
|
||||
m_do_print_hashrate(false),
|
||||
m_do_mining(false)
|
||||
{
|
||||
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
miner::~miner()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::set_block_template(const block& bl, const difficulty_type& di, uint64_t height)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_template_lock);
|
||||
m_template = bl;
|
||||
m_diffic = di;
|
||||
m_height = height;
|
||||
++m_template_no;
|
||||
m_starter_nonce = crypto::rand<uint32_t>();
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::on_block_chain_update()
|
||||
{
|
||||
if(!is_mining())
|
||||
return true;
|
||||
|
||||
return request_block_template();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::request_block_template()
|
||||
{
|
||||
block bl = AUTO_VAL_INIT(bl);
|
||||
difficulty_type di = AUTO_VAL_INIT(di);
|
||||
uint64_t height = AUTO_VAL_INIT(height);
|
||||
cryptonote::blobdata extra_nonce;
|
||||
if(m_extra_messages.size() && m_config.current_extra_message_index < m_extra_messages.size())
|
||||
{
|
||||
extra_nonce = m_extra_messages[m_config.current_extra_message_index];
|
||||
}
|
||||
|
||||
if(!m_phandler->get_block_template(bl, m_mine_address, di, height, extra_nonce))
|
||||
{
|
||||
LOG_ERROR("Failed to get_block_template(), stopping mining");
|
||||
return false;
|
||||
}
|
||||
set_block_template(bl, di, height);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::on_idle()
|
||||
{
|
||||
m_update_block_template_interval.do_call([&](){
|
||||
if(is_mining())request_block_template();
|
||||
return true;
|
||||
});
|
||||
|
||||
m_update_merge_hr_interval.do_call([&](){
|
||||
merge_hr();
|
||||
return true;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void miner::do_print_hashrate(bool do_hr)
|
||||
{
|
||||
m_do_print_hashrate = do_hr;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void miner::merge_hr()
|
||||
{
|
||||
if(m_last_hr_merge_time && is_mining())
|
||||
{
|
||||
m_current_hash_rate = m_hashes * 1000 / ((misc_utils::get_tick_count() - m_last_hr_merge_time + 1));
|
||||
CRITICAL_REGION_LOCAL(m_last_hash_rates_lock);
|
||||
m_last_hash_rates.push_back(m_current_hash_rate);
|
||||
if(m_last_hash_rates.size() > 19)
|
||||
m_last_hash_rates.pop_front();
|
||||
if(m_do_print_hashrate)
|
||||
{
|
||||
uint64_t total_hr = std::accumulate(m_last_hash_rates.begin(), m_last_hash_rates.end(), 0);
|
||||
float hr = static_cast<float>(total_hr)/static_cast<float>(m_last_hash_rates.size());
|
||||
std::cout << "hashrate: " << std::setprecision(4) << std::fixed << hr << ENDL;
|
||||
}
|
||||
}
|
||||
m_last_hr_merge_time = misc_utils::get_tick_count();
|
||||
m_hashes = 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void miner::init_options(boost::program_options::options_description& desc)
|
||||
{
|
||||
command_line::add_arg(desc, arg_extra_messages);
|
||||
command_line::add_arg(desc, arg_start_mining);
|
||||
command_line::add_arg(desc, arg_mining_threads);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::init(const boost::program_options::variables_map& vm)
|
||||
{
|
||||
if(command_line::has_arg(vm, arg_extra_messages))
|
||||
{
|
||||
std::string buff;
|
||||
bool r = file_io_utils::load_file_to_string(command_line::get_arg(vm, arg_extra_messages), buff);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to load file with extra messages: " << command_line::get_arg(vm, arg_extra_messages));
|
||||
std::vector<std::string> extra_vec;
|
||||
boost::split(extra_vec, buff, boost::is_any_of("\n"), boost::token_compress_on );
|
||||
m_extra_messages.resize(extra_vec.size());
|
||||
for(size_t i = 0; i != extra_vec.size(); i++)
|
||||
{
|
||||
string_tools::trim(extra_vec[i]);
|
||||
if(!extra_vec[i].size())
|
||||
continue;
|
||||
std::string buff = string_encoding::base64_decode(extra_vec[i]);
|
||||
if(buff != "0")
|
||||
m_extra_messages[i] = buff;
|
||||
}
|
||||
m_config_folder_path = boost::filesystem::path(command_line::get_arg(vm, arg_extra_messages)).parent_path().string();
|
||||
m_config = AUTO_VAL_INIT(m_config);
|
||||
epee::serialization::load_t_from_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
|
||||
LOG_PRINT_L0("Loaded " << m_extra_messages.size() << " extra messages, current index " << m_config.current_extra_message_index);
|
||||
}
|
||||
|
||||
if(command_line::has_arg(vm, arg_start_mining))
|
||||
{
|
||||
if(!cryptonote::get_account_address_from_str(m_mine_address, command_line::get_arg(vm, arg_start_mining)))
|
||||
{
|
||||
LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled");
|
||||
return false;
|
||||
}
|
||||
m_threads_total = 1;
|
||||
m_do_mining = true;
|
||||
if(command_line::has_arg(vm, arg_mining_threads))
|
||||
{
|
||||
m_threads_total = command_line::get_arg(vm, arg_mining_threads);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::is_mining()
|
||||
{
|
||||
return !m_stop;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::start(const account_public_address& adr, size_t threads_count)
|
||||
{
|
||||
m_mine_address = adr;
|
||||
m_threads_total = static_cast<uint32_t>(threads_count);
|
||||
m_starter_nonce = crypto::rand<uint32_t>();
|
||||
CRITICAL_REGION_LOCAL(m_threads_lock);
|
||||
if(is_mining())
|
||||
{
|
||||
LOG_ERROR("Starting miner but it's already started");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_threads.empty())
|
||||
{
|
||||
LOG_ERROR("Unable to start miner because there are active mining threads");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_template_no)
|
||||
request_block_template();//lets update block template
|
||||
|
||||
boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0);
|
||||
boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0);
|
||||
|
||||
for(size_t i = 0; i != threads_count; i++)
|
||||
m_threads.push_back(boost::thread(boost::bind(&miner::worker_thread, this)));
|
||||
|
||||
LOG_PRINT_L0("Mining has started with " << threads_count << " threads, good luck!" )
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
uint64_t miner::get_speed()
|
||||
{
|
||||
return m_current_hash_rate;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void miner::send_stop_signal()
|
||||
{
|
||||
boost::interprocess::ipcdetail::atomic_write32(&m_stop, 1);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::stop()
|
||||
{
|
||||
send_stop_signal();
|
||||
CRITICAL_REGION_LOCAL(m_threads_lock);
|
||||
|
||||
BOOST_FOREACH(boost::thread& th, m_threads)
|
||||
th.join();
|
||||
|
||||
m_threads.clear();
|
||||
LOG_PRINT_L0("Mining has been stopped, " << m_threads.size() << " finished" );
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height)
|
||||
{
|
||||
for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++)
|
||||
{
|
||||
crypto::hash h;
|
||||
get_block_longhash(bl, h, height);
|
||||
|
||||
if(check_hash(h, diffic))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void miner::on_synchronized()
|
||||
{
|
||||
if(m_do_mining)
|
||||
{
|
||||
start(m_mine_address, m_threads_total);
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void miner::pause()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_miners_count_lock);
|
||||
++m_pausers_count;
|
||||
if(m_pausers_count == 1 && is_mining())
|
||||
LOG_PRINT_L2("MINING PAUSED");
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void miner::resume()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_miners_count_lock);
|
||||
--m_pausers_count;
|
||||
if(m_pausers_count < 0)
|
||||
{
|
||||
m_pausers_count = 0;
|
||||
LOG_PRINT_RED_L0("Unexpected miner::resume() called");
|
||||
}
|
||||
if(!m_pausers_count && is_mining())
|
||||
LOG_PRINT_L2("MINING RESUMED");
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::worker_thread()
|
||||
{
|
||||
uint32_t th_local_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index);
|
||||
LOG_PRINT_L0("Miner thread was started ["<< th_local_index << "]");
|
||||
log_space::log_singletone::set_thread_log_prefix(std::string("[miner ") + std::to_string(th_local_index) + "]");
|
||||
uint32_t nonce = m_starter_nonce + th_local_index;
|
||||
uint64_t height = 0;
|
||||
difficulty_type local_diff = 0;
|
||||
uint32_t local_template_ver = 0;
|
||||
block b;
|
||||
while(!m_stop)
|
||||
{
|
||||
if(m_pausers_count)//anti split workaround
|
||||
{
|
||||
misc_utils::sleep_no_w(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(local_template_ver != m_template_no)
|
||||
{
|
||||
|
||||
CRITICAL_REGION_BEGIN(m_template_lock);
|
||||
b = m_template;
|
||||
local_diff = m_diffic;
|
||||
height = m_height;
|
||||
CRITICAL_REGION_END();
|
||||
local_template_ver = m_template_no;
|
||||
nonce = m_starter_nonce + th_local_index;
|
||||
}
|
||||
|
||||
if(!local_template_ver)//no any set_block_template call
|
||||
{
|
||||
LOG_PRINT_L2("Block template not set yet");
|
||||
epee::misc_utils::sleep_no_w(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
b.nonce = nonce;
|
||||
crypto::hash h;
|
||||
get_block_longhash(b, h, height);
|
||||
|
||||
if(check_hash(h, local_diff))
|
||||
{
|
||||
//we lucky!
|
||||
++m_config.current_extra_message_index;
|
||||
LOG_PRINT_GREEN("Found block for difficulty: " << local_diff, LOG_LEVEL_0);
|
||||
if(!m_phandler->handle_block_found(b))
|
||||
{
|
||||
--m_config.current_extra_message_index;
|
||||
}else
|
||||
{
|
||||
//success update, lets update config
|
||||
epee::serialization::store_t_to_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
|
||||
}
|
||||
}
|
||||
nonce+=m_threads_total;
|
||||
++m_hashes;
|
||||
}
|
||||
LOG_PRINT_L0("Miner thread stopped ["<< th_local_index << "]");
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
}
|
||||
|
99
src/cryptonote_core/miner.h
Normal file
99
src/cryptonote_core/miner.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
// 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
|
||||
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <atomic>
|
||||
#include "cryptonote_basic.h"
|
||||
#include "difficulty.h"
|
||||
#include "math_helper.h"
|
||||
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
struct i_miner_handler
|
||||
{
|
||||
virtual bool handle_block_found(block& b) = 0;
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce) = 0;
|
||||
protected:
|
||||
~i_miner_handler(){};
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class miner
|
||||
{
|
||||
public:
|
||||
miner(i_miner_handler* phandler);
|
||||
~miner();
|
||||
bool init(const boost::program_options::variables_map& vm);
|
||||
static void init_options(boost::program_options::options_description& desc);
|
||||
bool set_block_template(const block& bl, const difficulty_type& diffic, uint64_t height);
|
||||
bool on_block_chain_update();
|
||||
bool start(const account_public_address& adr, size_t threads_count);
|
||||
uint64_t get_speed();
|
||||
void send_stop_signal();
|
||||
bool stop();
|
||||
bool is_mining();
|
||||
bool on_idle();
|
||||
void on_synchronized();
|
||||
//synchronous analog (for fast calls)
|
||||
static bool find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height);
|
||||
void pause();
|
||||
void resume();
|
||||
void do_print_hashrate(bool do_hr);
|
||||
|
||||
private:
|
||||
bool worker_thread();
|
||||
bool request_block_template();
|
||||
void merge_hr();
|
||||
|
||||
struct miner_config
|
||||
{
|
||||
uint64_t current_extra_message_index;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(current_extra_message_index)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
||||
volatile uint32_t m_stop;
|
||||
::critical_section m_template_lock;
|
||||
block m_template;
|
||||
std::atomic<uint32_t> m_template_no;
|
||||
std::atomic<uint32_t> m_starter_nonce;
|
||||
difficulty_type m_diffic;
|
||||
uint64_t m_height;
|
||||
volatile uint32_t m_thread_index;
|
||||
volatile uint32_t m_threads_total;
|
||||
std::atomic<int32_t> m_pausers_count;
|
||||
::critical_section m_miners_count_lock;
|
||||
|
||||
std::list<boost::thread> m_threads;
|
||||
::critical_section m_threads_lock;
|
||||
i_miner_handler* m_phandler;
|
||||
account_public_address m_mine_address;
|
||||
math_helper::once_a_time_seconds<5> m_update_block_template_interval;
|
||||
math_helper::once_a_time_seconds<2> m_update_merge_hr_interval;
|
||||
std::vector<blobdata> m_extra_messages;
|
||||
miner_config m_config;
|
||||
std::string m_config_folder_path;
|
||||
std::atomic<uint64_t> m_last_hr_merge_time;
|
||||
std::atomic<uint64_t> m_hashes;
|
||||
std::atomic<uint64_t> m_current_hash_rate;
|
||||
critical_section m_last_hash_rates_lock;
|
||||
std::list<uint64_t> m_last_hash_rates;
|
||||
bool m_do_print_hashrate;
|
||||
bool m_do_mining;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
11
src/cryptonote_core/tx_extra.h
Normal file
11
src/cryptonote_core/tx_extra.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
// 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
|
||||
|
||||
|
||||
|
||||
#define TX_EXTRA_PADDING_MAX_COUNT 40
|
||||
#define TX_EXTRA_TAG_PUBKEY 0x01
|
||||
#define TX_EXTRA_NONCE 0x02
|
410
src/cryptonote_core/tx_pool.cpp
Normal file
410
src/cryptonote_core/tx_pool.cpp
Normal file
|
@ -0,0 +1,410 @@
|
|||
// 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.
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "tx_pool.h"
|
||||
#include "cryptonote_format_utils.h"
|
||||
#include "cryptonote_boost_serialization.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "blockchain_storage.h"
|
||||
#include "common/boost_serialization_helper.h"
|
||||
#include "misc_language.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated name length exceeded, name was truncated
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
//---------------------------------------------------------------------------------
|
||||
tx_memory_pool::tx_memory_pool(blockchain_storage& bchs): m_blockchain(bchs)
|
||||
{
|
||||
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::add_tx(const transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block)
|
||||
{
|
||||
|
||||
|
||||
if(!check_inputs_types_supported(tx))
|
||||
{
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t inputs_amount = 0;
|
||||
if(!get_inputs_money_amount(tx, inputs_amount))
|
||||
{
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t outputs_amount = get_outs_money_amount(tx);
|
||||
|
||||
if(outputs_amount >= inputs_amount)
|
||||
{
|
||||
LOG_PRINT_L0("transaction use more money then it has: use " << outputs_amount << ", have " << inputs_amount);
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//check key images for transaction if it is not kept by block
|
||||
if(!kept_by_block)
|
||||
{
|
||||
if(have_tx_keyimges_as_spent(tx))
|
||||
{
|
||||
LOG_ERROR("Transaction with id= "<< id << " used already spent key images");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
crypto::hash max_used_block_id = null_hash;
|
||||
uint64_t max_used_block_height = 0;
|
||||
bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id);
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
if(!ch_inp_res)
|
||||
{
|
||||
if(kept_by_block)
|
||||
{
|
||||
//anyway add this transaction to pool, because it related to block
|
||||
auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details()));
|
||||
CHECK_AND_ASSERT_MES(txd_p.second, false, "transaction already exists at inserting in memory pool");
|
||||
txd_p.first->second.blob_size = blob_size;
|
||||
txd_p.first->second.tx = tx;
|
||||
txd_p.first->second.fee = inputs_amount - outputs_amount;
|
||||
txd_p.first->second.max_used_block_id = null_hash;
|
||||
txd_p.first->second.max_used_block_height = 0;
|
||||
txd_p.first->second.kept_by_block = kept_by_block;
|
||||
tvc.m_verifivation_impossible = true;
|
||||
tvc.m_added_to_pool = true;
|
||||
}else
|
||||
{
|
||||
LOG_PRINT_L0("tx used wrong inputs, rejected");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
}else
|
||||
{
|
||||
//update transactions container
|
||||
auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details()));
|
||||
CHECK_AND_ASSERT_MES(txd_p.second, false, "intrnal error: transaction already exists at inserting in memorypool");
|
||||
txd_p.first->second.blob_size = blob_size;
|
||||
txd_p.first->second.tx = tx;
|
||||
txd_p.first->second.kept_by_block = kept_by_block;
|
||||
txd_p.first->second.fee = inputs_amount - outputs_amount;
|
||||
txd_p.first->second.max_used_block_id = max_used_block_id;
|
||||
txd_p.first->second.max_used_block_height = max_used_block_height;
|
||||
txd_p.first->second.last_failed_height = 0;
|
||||
txd_p.first->second.last_failed_id = null_hash;
|
||||
tvc.m_added_to_pool = true;
|
||||
|
||||
if(txd_p.first->second.fee > 0)
|
||||
tvc.m_should_be_relayed = true;
|
||||
}
|
||||
|
||||
tvc.m_verifivation_failed = true;
|
||||
//update image_keys container, here should everything goes ok.
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false);
|
||||
std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image];
|
||||
CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: keeped_by_block=" << kept_by_block
|
||||
<< ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
|
||||
<< "tx_id=" << id );
|
||||
auto ins_res = kei_image_set.insert(id);
|
||||
CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set");
|
||||
}
|
||||
|
||||
tvc.m_verifivation_failed = false;
|
||||
//succeed
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::add_tx(const transaction &tx, tx_verification_context& tvc, bool keeped_by_block)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
size_t blob_size = 0;
|
||||
get_transaction_hash(tx, h, blob_size);
|
||||
return add_tx(tx, h, blob_size, tvc, keeped_by_block);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::remove_transaction_keyimages(const transaction& tx)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
BOOST_FOREACH(const txin_v& vi, tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(vi, const txin_to_key, txin, false);
|
||||
auto it = m_spent_key_images.find(txin.k_image);
|
||||
CHECK_AND_ASSERT_MES(it != m_spent_key_images.end(), false, "failed to find transaction input in key images. img=" << txin.k_image << ENDL
|
||||
<< "transaction id = " << get_transaction_hash(tx));
|
||||
std::unordered_set<crypto::hash>& key_image_set = it->second;
|
||||
CHECK_AND_ASSERT_MES(key_image_set.size(), false, "empty key_image set, img=" << txin.k_image << ENDL
|
||||
<< "transaction id = " << get_transaction_hash(tx));
|
||||
|
||||
auto it_in_set = key_image_set.find(get_transaction_hash(tx));
|
||||
CHECK_AND_ASSERT_MES(key_image_set.size(), false, "transaction id not found in key_image set, img=" << txin.k_image << ENDL
|
||||
<< "transaction id = " << get_transaction_hash(tx));
|
||||
key_image_set.erase(it_in_set);
|
||||
if(!key_image_set.size())
|
||||
{
|
||||
//it is now empty hash container for this key_image
|
||||
m_spent_key_images.erase(it);
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
auto it = m_transactions.find(id);
|
||||
if(it == m_transactions.end())
|
||||
return false;
|
||||
|
||||
tx = it->second.tx;
|
||||
blob_size = it->second.blob_size;
|
||||
fee = it->second.fee;
|
||||
remove_transaction_keyimages(it->second.tx);
|
||||
m_transactions.erase(it);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
size_t tx_memory_pool::get_transactions_count()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
return m_transactions.size();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::get_transactions(std::list<transaction>& txs)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
BOOST_FOREACH(const auto& tx_vt, m_transactions)
|
||||
txs.push_back(tx_vt.second.tx);
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::get_transaction(const crypto::hash& id, transaction& tx)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
auto it = m_transactions.find(id);
|
||||
if(it == m_transactions.end())
|
||||
return false;
|
||||
tx = it->second.tx;
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::on_blockchain_dec(uint64_t new_block_height, const crypto::hash& top_block_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx(const crypto::hash &id)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
if(m_transactions.count(id))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx_keyimges_as_spent(const transaction& tx)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, true);//should never fail
|
||||
if(have_tx_keyimg_as_spent(tokey_in.k_image))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
return m_spent_key_images.end() != m_spent_key_images.find(key_im);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::lock()
|
||||
{
|
||||
m_transactions_lock.lock();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::unlock()
|
||||
{
|
||||
m_transactions_lock.unlock();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::is_transaction_ready_to_go(tx_details& txd)
|
||||
{
|
||||
//not the best implementation at this time, sorry :(
|
||||
//check is ring_signature already checked ?
|
||||
if(txd.max_used_block_id == null_hash)
|
||||
{//not checked, lets try to check
|
||||
|
||||
if(txd.last_failed_id != null_hash && m_blockchain.get_current_blockchain_height() > txd.last_failed_height && txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height))
|
||||
return false;//we already sure that this tx is broken for this height
|
||||
|
||||
if(!m_blockchain.check_tx_inputs(txd.tx, txd.max_used_block_height, txd.max_used_block_id))
|
||||
{
|
||||
txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
|
||||
txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
|
||||
return false;
|
||||
}
|
||||
}else
|
||||
{
|
||||
if(txd.max_used_block_height >= m_blockchain.get_current_blockchain_height())
|
||||
return false;
|
||||
if(m_blockchain.get_block_id_by_height(txd.max_used_block_height) != txd.max_used_block_id)
|
||||
{
|
||||
//if we already failed on this height and id, skip actual ring signature check
|
||||
if(txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height))
|
||||
return false;
|
||||
//check ring signature again, it is possible (with very small chance) that this transaction become again valid
|
||||
if(!m_blockchain.check_tx_inputs(txd.tx, txd.max_used_block_height, txd.max_used_block_id))
|
||||
{
|
||||
txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
|
||||
txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//if we here, transaction seems valid, but, anyway, check for key_images collisions with blockchain, just to be sure
|
||||
if(m_blockchain.have_tx_keyimges_as_spent(txd.tx))
|
||||
return false;
|
||||
|
||||
//transaction is ok.
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_key_images(const std::unordered_set<crypto::key_image>& k_images, const transaction& tx)
|
||||
{
|
||||
for(size_t i = 0; i!= tx.vin.size(); i++)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, false);
|
||||
if(k_images.count(itk.k_image))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::append_key_images(std::unordered_set<crypto::key_image>& k_images, const transaction& tx)
|
||||
{
|
||||
for(size_t i = 0; i!= tx.vin.size(); i++)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, false);
|
||||
auto i_res = k_images.insert(itk.k_image);
|
||||
CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: key images pool cache - inserted duplicate image in set: " << itk.k_image);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
std::string tx_memory_pool::print_pool(bool short_format)
|
||||
{
|
||||
std::stringstream ss;
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
BOOST_FOREACH(transactions_container::value_type& txe, m_transactions)
|
||||
{
|
||||
if(short_format)
|
||||
{
|
||||
tx_details& txd = txe.second;
|
||||
ss << "id: " << txe.first << ENDL
|
||||
<< "blob_size: " << txd.blob_size << ENDL
|
||||
<< "fee: " << txd.fee << ENDL
|
||||
<< "kept_by_block: " << txd.kept_by_block << ENDL
|
||||
<< "max_used_block_height: " << txd.max_used_block_height << ENDL
|
||||
<< "max_used_block_id: " << txd.max_used_block_id << ENDL
|
||||
<< "last_failed_height: " << txd.last_failed_height << ENDL
|
||||
<< "last_failed_id: " << txd.last_failed_id << ENDL;
|
||||
}else
|
||||
{
|
||||
tx_details& txd = txe.second;
|
||||
ss << "id: " << txe.first << ENDL
|
||||
<< obj_to_json_str(txd.tx) << ENDL
|
||||
<< "blob_size: " << txd.blob_size << ENDL
|
||||
<< "fee: " << txd.fee << ENDL
|
||||
<< "kept_by_block: " << txd.kept_by_block << ENDL
|
||||
<< "max_used_block_height: " << txd.max_used_block_height << ENDL
|
||||
<< "max_used_block_id: " << txd.max_used_block_id << ENDL
|
||||
<< "last_failed_height: " << txd.last_failed_height << ENDL
|
||||
<< "last_failed_id: " << txd.last_failed_id << ENDL;
|
||||
}
|
||||
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::fill_block_template(block& bl, size_t& cumulative_sizes, size_t max_comulative_sz, uint64_t& fee)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
|
||||
fee = 0;
|
||||
std::unordered_set<crypto::key_image> k_images;
|
||||
|
||||
BOOST_FOREACH(transactions_container::value_type& tx, m_transactions)
|
||||
{
|
||||
if(cumulative_sizes + tx.second.blob_size > max_comulative_sz)
|
||||
continue;
|
||||
|
||||
if(!is_transaction_ready_to_go(tx.second))
|
||||
continue;
|
||||
|
||||
if(have_key_images(k_images, tx.second.tx))
|
||||
continue;
|
||||
|
||||
bl.tx_hashes.push_back(tx.first);
|
||||
cumulative_sizes += tx.second.blob_size;
|
||||
fee += tx.second.fee;
|
||||
append_key_images(k_images, tx.second.tx);
|
||||
|
||||
if(cumulative_sizes >= max_comulative_sz)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::init(const std::string& config_folder)
|
||||
{
|
||||
m_config_folder = config_folder;
|
||||
std::string state_file_path = config_folder + "/" + CRYPTONOTE_POOLDATA_FILENAME;
|
||||
boost::system::error_code ec;
|
||||
if(!boost::filesystem::exists(state_file_path, ec))
|
||||
return true;
|
||||
bool res = tools::unserialize_obj_from_file(*this, state_file_path);
|
||||
if(!res)
|
||||
{
|
||||
LOG_PRINT_L0("Failed to load memory pool from file " << state_file_path);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::deinit()
|
||||
{
|
||||
if (!tools::create_directories_if_necessary(m_config_folder))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to create data directory: " << m_config_folder);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string state_file_path = m_config_folder + "/" + CRYPTONOTE_POOLDATA_FILENAME;
|
||||
bool res = tools::serialize_obj_to_file(*this, state_file_path);
|
||||
if(!res)
|
||||
{
|
||||
LOG_PRINT_L0("Failed to serialize memory pool to file " << state_file_path);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
168
src/cryptonote_core/tx_pool.h
Normal file
168
src/cryptonote_core/tx_pool.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
// 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
|
||||
#include "include_base_utils.h"
|
||||
using namespace epee;
|
||||
|
||||
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <boost/serialization/version.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include "string_tools.h"
|
||||
#include "syncobj.h"
|
||||
#include "cryptonote_basic_impl.h"
|
||||
#include "verification_context.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
class blockchain_storage;
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
class tx_memory_pool: boost::noncopyable
|
||||
{
|
||||
public:
|
||||
tx_memory_pool(blockchain_storage& bchs);
|
||||
bool add_tx(const transaction &tx, const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool add_tx(const transaction &tx, tx_verification_context& tvc, bool keeped_by_block);
|
||||
//gets tx and remove it from pool
|
||||
bool take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee);
|
||||
|
||||
bool have_tx(const crypto::hash &id);
|
||||
bool have_tx_keyimg_as_spent(const crypto::key_image& key_im);
|
||||
bool have_tx_keyimges_as_spent(const transaction& tx);
|
||||
|
||||
bool on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id);
|
||||
bool on_blockchain_dec(uint64_t new_block_height, const crypto::hash& top_block_id);
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
// load/store operations
|
||||
bool init(const std::string& config_folder);
|
||||
bool deinit();
|
||||
bool fill_block_template(block& bl, size_t& cumulative_sizes, size_t max_comulative_sz, uint64_t& fee);
|
||||
bool get_transactions(std::list<transaction>& txs);
|
||||
bool get_transaction(const crypto::hash& h, transaction& tx);
|
||||
size_t get_transactions_count();
|
||||
bool remove_transaction_keyimages(const transaction& tx);
|
||||
bool have_key_images(const std::unordered_set<crypto::key_image>& kic, const transaction& tx);
|
||||
bool append_key_images(std::unordered_set<crypto::key_image>& kic, const transaction& tx);
|
||||
std::string print_pool(bool short_format);
|
||||
|
||||
/*bool flush_pool(const std::strig& folder);
|
||||
bool inflate_pool(const std::strig& folder);*/
|
||||
|
||||
#define CURRENT_MEMPOOL_ARCHIVE_VER 7
|
||||
|
||||
template<class archive_t>
|
||||
void serialize(archive_t & a, const unsigned int version)
|
||||
{
|
||||
if(version < CURRENT_MEMPOOL_ARCHIVE_VER )
|
||||
return;
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
a & m_transactions;
|
||||
a & m_spent_key_images;
|
||||
}
|
||||
|
||||
struct tx_details
|
||||
{
|
||||
transaction tx;
|
||||
size_t blob_size;
|
||||
uint64_t fee;
|
||||
crypto::hash max_used_block_id;
|
||||
uint64_t max_used_block_height;
|
||||
bool kept_by_block;
|
||||
//
|
||||
uint64_t last_failed_height;
|
||||
crypto::hash last_failed_id;
|
||||
};
|
||||
|
||||
private:
|
||||
bool is_transaction_ready_to_go(tx_details& txd);
|
||||
typedef std::unordered_map<crypto::hash, tx_details > transactions_container;
|
||||
typedef std::unordered_map<crypto::key_image, std::unordered_set<crypto::hash> > key_images_container;
|
||||
|
||||
epee::critical_section m_transactions_lock;
|
||||
transactions_container m_transactions;
|
||||
key_images_container m_spent_key_images;
|
||||
|
||||
//transactions_container m_alternative_transactions;
|
||||
|
||||
std::string m_config_folder;
|
||||
blockchain_storage& m_blockchain;
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
/*class inputs_visitor: public boost::static_visitor<bool>
|
||||
{
|
||||
key_images_container& m_spent_keys;
|
||||
public:
|
||||
inputs_visitor(key_images_container& spent_keys): m_spent_keys(spent_keys)
|
||||
{}
|
||||
bool operator()(const txin_to_key& tx) const
|
||||
{
|
||||
auto pr = m_spent_keys.insert(tx.k_image);
|
||||
CHECK_AND_ASSERT_MES(pr.second, false, "Tried to insert transaction with input seems already spent, input: " << epee::string_tools::pod_to_hex(tx.k_image));
|
||||
return true;
|
||||
}
|
||||
bool operator()(const txin_gen& tx) const
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(false, false, "coinbase transaction in memory pool");
|
||||
return false;
|
||||
}
|
||||
bool operator()(const txin_to_script& tx) const {return false;}
|
||||
bool operator()(const txin_to_scripthash& tx) const {return false;}
|
||||
}; */
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class amount_visitor: public boost::static_visitor<uint64_t>
|
||||
{
|
||||
public:
|
||||
uint64_t operator()(const txin_to_key& tx) const
|
||||
{
|
||||
return tx.amount;
|
||||
}
|
||||
uint64_t operator()(const txin_gen& tx) const
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(false, false, "coinbase transaction in memory pool");
|
||||
return 0;
|
||||
}
|
||||
uint64_t operator()(const txin_to_script& tx) const {return 0;}
|
||||
uint64_t operator()(const txin_to_scripthash& tx) const {return 0;}
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
template<class archive_t>
|
||||
void serialize(archive_t & ar, cryptonote::tx_memory_pool::tx_details& td, const unsigned int version)
|
||||
{
|
||||
ar & td.blob_size;
|
||||
ar & td.fee;
|
||||
ar & td.tx;
|
||||
ar & td.max_used_block_height;
|
||||
ar & td.max_used_block_id;
|
||||
ar & td.last_failed_height;
|
||||
ar & td.last_failed_id;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_CLASS_VERSION(cryptonote::tx_memory_pool, CURRENT_MEMPOOL_ARCHIVE_VER)
|
||||
|
||||
|
||||
|
27
src/cryptonote_core/verification_context.h
Normal file
27
src/cryptonote_core/verification_context.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
// 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
|
||||
namespace cryptonote
|
||||
{
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct tx_verification_context
|
||||
{
|
||||
bool m_should_be_relayed;
|
||||
bool m_verifivation_failed; //bad tx, should drop connection
|
||||
bool m_verifivation_impossible; //the transaction is related with an alternative blockchain
|
||||
bool m_added_to_pool;
|
||||
};
|
||||
|
||||
struct block_verification_context
|
||||
{
|
||||
bool m_added_to_main_chain;
|
||||
bool m_verifivation_failed; //bad block, should drop connection
|
||||
bool m_marked_as_orphaned;
|
||||
bool m_already_exists;
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue