From 14463ca688885e1bc5b7f3916e2c8984f7bf4320 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Tue, 15 Oct 2019 10:04:16 +0800 Subject: [PATCH 01/34] fix Mac build issues. --- src/cryptonote_basic/difficulty.cpp | 2 -- src/cryptonote_basic/difficulty.h | 1 + tests/functional_tests/transactions_flow_test.cpp | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cryptonote_basic/difficulty.cpp b/src/cryptonote_basic/difficulty.cpp index b6cfdf2c97a..456b9cb4fe8 100644 --- a/src/cryptonote_basic/difficulty.cpp +++ b/src/cryptonote_basic/difficulty.cpp @@ -35,8 +35,6 @@ #include #include "int-util.h" -#include "crypto/hash.h" -#include "cryptonote_config.h" #include "difficulty.h" #undef MONERO_DEFAULT_LOG_CATEGORY diff --git a/src/cryptonote_basic/difficulty.h b/src/cryptonote_basic/difficulty.h index d554e4f343a..a48b86313ed 100644 --- a/src/cryptonote_basic/difficulty.h +++ b/src/cryptonote_basic/difficulty.h @@ -36,6 +36,7 @@ #include #include "crypto/hash.h" +#include "cryptonote_config.h" namespace cryptonote { diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index 32b601d7aed..5bbfda5474b 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -270,7 +270,7 @@ bool transactions_flow_test(std::string& working_folder, misc_utils::sleep_no_w(DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN*1000);//wait two blocks before sync on another wallet on another daemon } - uint64_t money_2 = w2.balance(0); + uint64_t money_2 = w2.balance(0).template convert_to(); if(money_2 == transfered_money) { MGINFO_GREEN("-----------------------FINISHING TRANSACTIONS FLOW TEST OK-----------------------"); From 6f70fa1b638b964487f7bbd3a54ca251a74a04c5 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Mon, 28 Oct 2019 15:18:28 +0800 Subject: [PATCH 02/34] debug: comment checkpoint for debug. --- src/checkpoints/checkpoints.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp index 9ce910893ce..1059cebef4d 100644 --- a/src/checkpoints/checkpoints.cpp +++ b/src/checkpoints/checkpoints.cpp @@ -177,6 +177,7 @@ namespace cryptonote ADD_CHECKPOINT(1866300, "d5ae24ba79fdedc484616fd317f59ba66eb6d526d723fc07f7092ebde2e576c9"); return true; } + /* ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148"); ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381"); ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d"); @@ -211,6 +212,7 @@ namespace cryptonote ADD_CHECKPOINT(1390000, "a8f5649dd4ded60eedab475f2bec8c934681c07e3cf640e9be0617554f13ff6c"); ADD_CHECKPOINT(1450000, "ac94e8860093bc7c83e4e91215cba1d663421ecf4067a0ae609c3a8b52bcfac2"); ADD_CHECKPOINT(1530000, "01759bce497ec38e63c78b1038892169203bb78f87e488172f6b854fcd63ba7e"); + */ // ADD_CHECKPOINT(1579000, "7d0d7a2346373afd41ed1e744a939fc5d474a7dbaa257be5c6fff4009e789241"); // ADD_CHECKPOINT(1668900, "ac2dcaf3d2f58ffcf8391639f0f1ebafcb8eac43c49479c7c37f611868d07568"); // ADD_CHECKPOINT(1775600, "1c6e01c661dc22cab939e79ec6a5272190624ce8356d2f7b958e4f9a57fdb05e"); From 07fe9c149fbee839d92ed0faa761f9f54bdfca47 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Mon, 28 Oct 2019 17:50:17 +0800 Subject: [PATCH 03/34] Add command line arg of pos settings. --- src/cryptonote_basic/miner.cpp | 54 ++++++++++++++++++++++++++++++++++ src/cryptonote_basic/miner.h | 9 ++++++ 2 files changed, 63 insertions(+) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index e594eb0494c..91829f64220 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -43,6 +43,8 @@ #include "string_tools.h" #include "storages/portable_storage_template_helper.h" #include "boost/logic/tribool.hpp" +#include "rapidjson/document.h" +#include "common/json_util.h" #ifdef __APPLE__ #include @@ -75,6 +77,7 @@ #define AUTODETECT_WINDOW 10 // seconds #define AUTODETECT_GAIN_THRESHOLD 1.02f // 2% +#define POS_MAX_TX_COUNT 5 using namespace epee; @@ -96,6 +99,7 @@ namespace cryptonote const command_line::arg_descriptor arg_bg_mining_min_idle_interval_seconds = {"bg-mining-min-idle-interval", "Specify min lookback interval in seconds for determining idle state", miner::BACKGROUND_MINING_DEFAULT_MIN_IDLE_INTERVAL_IN_SECONDS, true}; const command_line::arg_descriptor arg_bg_mining_idle_threshold_percentage = {"bg-mining-idle-threshold", "Specify minimum avg idle percentage over lookback interval", miner::BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE, true}; const command_line::arg_descriptor arg_bg_mining_miner_target_percentage = {"bg-mining-miner-target", "Specify maximum percentage cpu use by miner(s)", miner::BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE, true}; + const command_line::arg_descriptor arg_pos_settings = {"pos-settings-file", "Specify file for pos settings", "", true}; } @@ -285,10 +289,60 @@ namespace cryptonote command_line::add_arg(desc, arg_bg_mining_min_idle_interval_seconds); command_line::add_arg(desc, arg_bg_mining_idle_threshold_percentage); command_line::add_arg(desc, arg_bg_mining_miner_target_percentage); + command_line::add_arg(desc, arg_pos_settings); } //----------------------------------------------------------------------------------------------------- bool miner::init(const boost::program_options::variables_map& vm, network_type nettype) { + if(command_line::has_arg(vm, arg_pos_settings)) + { + std::string buf, filename = command_line::get_arg(vm, arg_pos_settings); + bool r = epee::file_io_utils::load_file_to_string(filename, buf); + CHECK_AND_ASSERT_MES(r, false, "Failed to load pos settings file " << filename); + + rapidjson::Document json; + r = json.Parse(buf.c_str()).HasParseError(); + CHECK_AND_ASSERT_MES(!r, false, "Failed to parse pos settings JSON file " << filename); + + // parse view_secret_key field + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, view_secret_key, std::string, String, false, std::string()); + CHECK_AND_ASSERT_MES(field_view_secret_key_found, false, "Failed to found view secret key"); + + cryptonote::blobdata viewkey_data; + r = epee::string_tools::parse_hexstr_to_binbuff(field_view_secret_key, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse view key secret key"); + + crypto::secret_key viewkey = *reinterpret_cast(viewkey_data.data()); + crypto::public_key pkey; + r = crypto::secret_key_to_public_key(viewkey, pkey); + CHECK_AND_ASSERT_MES(r, false, "Failed to verify view key secret key"); + + m_pos_settings = AUTO_VAL_INIT(m_pos_settings); + m_pos_settings.view_secret_key = viewkey; + + // parse tx_id field + r = json.HasMember("tx_id"); + CHECK_AND_ASSERT_MES(r, false, "Failed to found tx id"); + + const rapidjson::Value& array_txid = json["tx_id"]; + r = array_txid.IsArray(); + CHECK_AND_ASSERT_MES(r, false, "tx id must be array"); + + rapidjson::SizeType sz = array_txid.Size(); + CHECK_AND_ASSERT_MES(sz <= POS_MAX_TX_COUNT, false, "tx id should be less than 5"); + for (rapidjson::SizeType i = 0; i < sz; i++) { + std::string field_id = static_cast(array_txid[i].GetString()); + cryptonote::blobdata id_data; + r = epee::string_tools::parse_hexstr_to_binbuff(field_id, id_data) || id_data.size() != sizeof(crypto::hash); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse tx id"); + + crypto::hash id = *reinterpret_cast(id_data.data()); + m_pos_settings.tx_id.push_back(id); + } + + MINFO("POS: Loaded view key succeed, and with " << sz << " tx ids"); + } + if(command_line::has_arg(vm, arg_extra_messages)) { std::string buff; diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index ac7a0381c58..92d823e73a5 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -116,6 +116,11 @@ namespace cryptonote END_KV_SERIALIZE_MAP() }; + struct pos_config + { + crypto::secret_key view_secret_key; + std::vector tx_id; + }; volatile uint32_t m_stop; epee::critical_section m_template_lock; @@ -173,5 +178,9 @@ namespace cryptonote static uint8_t get_percent_of_total(uint64_t some_time, uint64_t total_time); static boost::logic::tribool on_battery_power(); std::atomic m_block_reward; + + // pos mining stuffs .. + + pos_config m_pos_settings; }; } From 00fe75af7e95eb0cfa478532f66b1d7389a3b4d5 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Mon, 28 Oct 2019 18:08:57 +0800 Subject: [PATCH 04/34] Add more check for pos_settings_file arg. --- src/cryptonote_basic/miner.cpp | 85 ++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 91829f64220..48a57498117 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -294,8 +294,51 @@ namespace cryptonote //----------------------------------------------------------------------------------------------------- bool miner::init(const boost::program_options::variables_map& vm, network_type nettype) { + 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 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); + const std::string filename = m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME; + CHECK_AND_ASSERT_MES(epee::serialization::load_t_from_json_file(m_config, filename), false, "Failed to load data from " << filename); + MINFO("Loaded " << m_extra_messages.size() << " extra messages, current index " << m_config.current_extra_message_index); + } + + if(command_line::has_arg(vm, arg_start_mining)) + { + address_parse_info info; + if(!cryptonote::get_account_address_from_str(info, nettype, command_line::get_arg(vm, arg_start_mining)) || info.is_subaddress) + { + LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled"); + return false; + } + m_mine_address = info.address; + 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); + } + } + if(command_line::has_arg(vm, arg_pos_settings)) { + CHECK_AND_ASSERT_MES(m_do_mining, false, "Must specify start-ming argument when using pos-settings-file"); + std::string buf, filename = command_line::get_arg(vm, arg_pos_settings); bool r = epee::file_io_utils::load_file_to_string(filename, buf); CHECK_AND_ASSERT_MES(r, false, "Failed to load pos settings file " << filename); @@ -316,6 +359,7 @@ namespace cryptonote crypto::public_key pkey; r = crypto::secret_key_to_public_key(viewkey, pkey); CHECK_AND_ASSERT_MES(r, false, "Failed to verify view key secret key"); + CHECK_AND_ASSERT_MES(pkey == m_mine_address.m_view_public_key, false, "view secret key does not match mine address"); m_pos_settings = AUTO_VAL_INIT(m_pos_settings); m_pos_settings.view_secret_key = viewkey; @@ -343,47 +387,6 @@ namespace cryptonote MINFO("POS: Loaded view key succeed, and with " << sz << " tx ids"); } - 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 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); - const std::string filename = m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME; - CHECK_AND_ASSERT_MES(epee::serialization::load_t_from_json_file(m_config, filename), false, "Failed to load data from " << filename); - MINFO("Loaded " << m_extra_messages.size() << " extra messages, current index " << m_config.current_extra_message_index); - } - - if(command_line::has_arg(vm, arg_start_mining)) - { - address_parse_info info; - if(!cryptonote::get_account_address_from_str(info, nettype, command_line::get_arg(vm, arg_start_mining)) || info.is_subaddress) - { - LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled"); - return false; - } - m_mine_address = info.address; - 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); - } - } - // Background mining parameters // Let init set all parameters even if background mining is not enabled, they can start later with params set if(command_line::has_arg(vm, arg_bg_mining_enable)) From 1c6998ec6e7d71f066564d2b4ab81aeeb864696a Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Mon, 28 Oct 2019 18:29:06 +0800 Subject: [PATCH 05/34] check duplicate tx id arg --- src/cryptonote_basic/miner.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 48a57498117..fca8ccd1c29 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -373,7 +373,7 @@ namespace cryptonote CHECK_AND_ASSERT_MES(r, false, "tx id must be array"); rapidjson::SizeType sz = array_txid.Size(); - CHECK_AND_ASSERT_MES(sz <= POS_MAX_TX_COUNT, false, "tx id should be less than 5"); + CHECK_AND_ASSERT_MES(sz <= POS_MAX_TX_COUNT, false, "tx id should be less than " << POS_MAX_TX_COUNT); for (rapidjson::SizeType i = 0; i < sz; i++) { std::string field_id = static_cast(array_txid[i].GetString()); cryptonote::blobdata id_data; @@ -381,10 +381,12 @@ namespace cryptonote CHECK_AND_ASSERT_MES(r, false, "Failed to parse tx id"); crypto::hash id = *reinterpret_cast(id_data.data()); + if (std::find(m_pos_settings.tx_id.begin(), m_pos_settings.tx_id.end(), id) != m_pos_settings.tx_id.end()) + continue; m_pos_settings.tx_id.push_back(id); } - MINFO("POS: Loaded view key succeed, and with " << sz << " tx ids"); + MINFO("POS: Loaded view key succeed, and with " << m_pos_settings.tx_id.size() << " tx ids"); } // Background mining parameters From b63703828740e977845a2ceeea326f45be6670dc Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Tue, 29 Oct 2019 14:49:17 +0800 Subject: [PATCH 06/34] Add tx extra stake --- .../cryptonote_format_utils.cpp | 35 +++++++++++++++++++ .../cryptonote_format_utils.h | 3 ++ src/cryptonote_basic/miner.cpp | 16 ++++++++- src/cryptonote_basic/miner.h | 2 +- src/cryptonote_basic/tx_extra.h | 17 ++++++++- src/cryptonote_core/blockchain.cpp | 10 +++--- src/cryptonote_core/blockchain.h | 4 +-- src/cryptonote_core/cryptonote_core.cpp | 8 ++--- src/cryptonote_core/cryptonote_core.h | 4 +-- src/cryptonote_core/cryptonote_tx_utils.cpp | 5 ++- src/cryptonote_core/cryptonote_tx_utils.h | 2 +- src/rpc/core_rpc_server.cpp | 3 +- 12 files changed, 90 insertions(+), 19 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index 5b68f56a26d..d37b9a91e57 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -592,6 +592,7 @@ namespace cryptonote if (!pick(nar, tx_extra_fields, TX_EXTRA_MERGE_MINING_TAG)) return false; if (!pick(nar, tx_extra_fields, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG)) return false; if (!pick(nar, tx_extra_fields, TX_EXTRA_TAG_PADDING)) return false; + if (!pick(nar, tx_extra_fields, TX_EXTRA_TAG_STAKE)) return false; // if not empty, someone added a new type and did not add a case above if (!tx_extra_fields.empty()) @@ -767,6 +768,40 @@ namespace cryptonote return true; } //--------------------------------------------------------------- + bool add_stake_to_extra(std::vector& tx_extra, const std::vector &extra_stake) + { + const size_t HASH_SIZE = sizeof(crypto::hash); + if (extra_stake.size() % HASH_SIZE != 0 || extra_stake.size() < HASH_SIZE * 2) + return false; + + // parse stake + tx_extra_stake stake; + std::copy(extra_stake.data(), extra_stake.data() + HASH_SIZE, stake.view_secret_key.data); + + size_t cnt = extra_stake.size() / sizeof(crypto::hash) - 1; + stake.count = static_cast(cnt); + for (size_t i = 0; i < cnt; ++i) + { + crypto::hash id; + std::copy(extra_stake.data() + HASH_SIZE * (1 + i), extra_stake.data() + HASH_SIZE * (2 + i), id.data); + stake.tx_id.push_back(id); + } + + // convert to variant + tx_extra_field field = stake; + // serialize + std::ostringstream oss; + binary_archive ar(oss); + bool r = ::do_serialize(ar, field); + CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra stake"); + // append + std::string tx_extra_str = oss.str(); + size_t pos = tx_extra.size(); + tx_extra.resize(tx_extra.size() + tx_extra_str.size()); + memcpy(&tx_extra[pos], tx_extra_str.data(), tx_extra_str.size()); + return true; + } + //--------------------------------------------------------------- bool get_inputs_money_amount(const transaction& tx, uint64_t& money) { money = 0; diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index f3cc62d99c1..3024394898b 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -85,6 +85,9 @@ namespace cryptonote void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id); bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id); bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id); + bool add_stake_to_extra(std::vector& tx_extra, const std::vector& extra_stake); + void get_stake_from_extra(); + bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, const std::vector& additional_tx_public_keys, size_t output_index); struct subaddress_receive_info { diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index fca8ccd1c29..623013c6bd8 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -169,7 +169,20 @@ namespace cryptonote extra_nonce = m_extra_messages[m_config.current_extra_message_index]; } - if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce)) + std::vector extra_stake; + if (m_pos_settings.tx_id.size()) + { + extra_stake.reserve((sizeof(crypto::secret_key) + sizeof(crypto::hash) * m_pos_settings.tx_id.size())); + // copy view secret key + std::copy(&m_pos_settings.view_secret_key.data[0], &m_pos_settings.view_secret_key.data[sizeof(crypto::secret_key)], std::back_inserter(extra_stake)); + // copy each tx id + for (const auto& id: m_pos_settings.tx_id) + { + std::copy(&id.data[0], &id.data[sizeof(crypto::hash)], std::back_inserter(extra_stake)); + } + } + + if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce, extra_stake)) { LOG_ERROR("Failed to get_block_template(), stopping mining"); return false; @@ -386,6 +399,7 @@ namespace cryptonote m_pos_settings.tx_id.push_back(id); } + CHECK_AND_ASSERT_MES(m_pos_settings.tx_id.size(), false, "tx id can not be empty"); MINFO("POS: Loaded view key succeed, and with " << m_pos_settings.tx_id.size() << " tx ids"); } diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index 92d823e73a5..fb6ce8e866d 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -47,7 +47,7 @@ namespace cryptonote struct i_miner_handler { virtual bool handle_block_found(block& b, block_verification_context &bvc) = 0; - virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce) = 0; + virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, const std::vector& ex_stake) = 0; protected: ~i_miner_handler(){}; }; diff --git a/src/cryptonote_basic/tx_extra.h b/src/cryptonote_basic/tx_extra.h index ecb4c604086..4aab2f3c004 100644 --- a/src/cryptonote_basic/tx_extra.h +++ b/src/cryptonote_basic/tx_extra.h @@ -40,6 +40,7 @@ #define TX_EXTRA_MERGE_MINING_TAG 0x03 #define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS 0x04 #define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE +#define TX_EXTRA_TAG_STAKE 0x58 #define TX_EXTRA_NONCE_PAYMENT_ID 0x00 #define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01 @@ -179,11 +180,24 @@ namespace cryptonote END_SERIALIZE() }; + struct tx_extra_stake + { + crypto::secret_key view_secret_key; + uint8_t count; + std::vector tx_id; + + BEGIN_SERIALIZE() + FIELD(view_secret_key) + FIELD(count) + FIELD(tx_id) + END_SERIALIZE() + }; + // tx_extra_field format, except tx_extra_padding and tx_extra_pub_key: // varint tag; // varint size; // varint data[]; - typedef boost::variant tx_extra_field; + typedef boost::variant tx_extra_field; } VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING); @@ -192,3 +206,4 @@ VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE); VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG); VARIANT_TAG(binary_archive, cryptonote::tx_extra_additional_pub_keys, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS); VARIANT_TAG(binary_archive, cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG); +VARIANT_TAG(binary_archive, cryptonote::tx_extra_stake, TX_EXTRA_TAG_STAKE); diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 5ee37f80d1e..0e9f5950804 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1418,7 +1418,7 @@ uint64_t Blockchain::get_current_cumulative_block_weight_median() const // in a lot of places. That flag is not referenced in any of the code // nor any of the makefiles, howeve. Need to look into whether or not it's // necessary at all. -bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce) +bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, const std::vector& ex_stake) { LOG_PRINT_L3("Blockchain::" << __func__); size_t median_weight; @@ -1590,7 +1590,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, uint8_t hf_version = b.major_version; size_t max_outs = hf_version >= 4 ? 1 : 11; // bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); - bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype); + bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake); CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance"); size_t cumulative_weight = txs_weight + get_transaction_weight(b.miner_tx); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) @@ -1600,7 +1600,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, for (size_t try_count = 0; try_count != 10; ++try_count) { // r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); - r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype); + r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake); CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, second chance"); size_t coinbase_weight = get_transaction_weight(b.miner_tx); @@ -1652,9 +1652,9 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, return false; } //------------------------------------------------------------------ -bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce) +bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, const std::vector& ex_stake) { - return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, ex_nonce); + return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, ex_nonce, ex_stake); } //------------------------------------------------------------------ // for an alternate chain, get the timestamps from the main chain to complete diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 6b5beb48e37..b875da263c2 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -346,8 +346,8 @@ namespace cryptonote * * @return true if block template filled in successfully, else false */ - bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce); - bool create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce); + bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, const std::vector& ex_stake); + bool create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, const std::vector& ex_stake); /** * @brief checks if a block is known about with a given hash diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index e8da9f08d4f..b566a8f9328 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -1278,14 +1278,14 @@ namespace cryptonote m_mempool.set_relayed(txs); } //----------------------------------------------------------------------------------------------- - bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce) + bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, const std::vector& ex_stake) { - return m_blockchain_storage.create_block_template(b, adr, diffic, height, expected_reward, ex_nonce); + return m_blockchain_storage.create_block_template(b, adr, diffic, height, expected_reward, ex_nonce, ex_stake); } //----------------------------------------------------------------------------------------------- - bool core::get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce) + bool core::get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, const std::vector& ex_stake) { - return m_blockchain_storage.create_block_template(b, prev_block, adr, diffic, height, expected_reward, ex_nonce); + return m_blockchain_storage.create_block_template(b, prev_block, adr, diffic, height, expected_reward, ex_nonce, ex_stake); } //----------------------------------------------------------------------------------------------- bool core::find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 71e8cd07dde..b8d75716d83 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -207,8 +207,8 @@ namespace cryptonote * * @note see Blockchain::create_block_template */ - virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce); - virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce); + virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, const std::vector& ex_stake); + virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, const std::vector& ex_stake); /** * @brief called when a transaction is relayed diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index cef59f0ae25..bce56661413 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -77,13 +77,16 @@ namespace cryptonote } //--------------------------------------------------------------- // bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) { - bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version, network_type nettype) { + bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version, network_type nettype, const std::vector &extra_stake) { tx.vin.clear(); tx.vout.clear(); tx.extra.clear(); keypair txkey = keypair::generate(hw::get_device("default")); add_tx_pub_key_to_extra(tx, txkey.pub); + if(!extra_stake.empty()) + if (!add_stake_to_extra(tx.extra, extra_stake)) + return false; if(!extra_nonce.empty()) if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) return false; diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index e02683ac6c9..b80da33b10b 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -38,7 +38,7 @@ namespace cryptonote { //--------------------------------------------------------------- // bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1); - bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1, network_type nettype = MAINNET); + bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1, network_type nettype = MAINNET, const std::vector& extra_stake = std::vector()); struct tx_source_entry { diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 76f23071dcf..ba2afbd2a51 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1248,6 +1248,7 @@ namespace cryptonote block b; cryptonote::blobdata blob_reserve; blob_reserve.resize(req.reserve_size, 0); + std::vector ex_stake(sizeof(crypto::secret_key) + sizeof(crypto::hash), 0); cryptonote::difficulty_type wdiff; crypto::hash prev_block; if (!req.prev_block.empty()) @@ -1259,7 +1260,7 @@ namespace cryptonote return false; } } - if(!m_core.get_block_template(b, req.prev_block.empty() ? NULL : &prev_block, info.address, wdiff, res.height, res.expected_reward, blob_reserve)) + if(!m_core.get_block_template(b, req.prev_block.empty() ? NULL : &prev_block, info.address, wdiff, res.height, res.expected_reward, blob_reserve, ex_stake)) { error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; error_resp.message = "Internal error: failed to create block template"; From 37983d2f1b328b88c95d32ff0d6b5e7ce0c13a0f Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Wed, 30 Oct 2019 16:27:11 +0800 Subject: [PATCH 07/34] progressing: Add check miner pos reward --- .../cryptonote_format_utils.cpp | 27 +++-- .../cryptonote_format_utils.h | 2 +- src/cryptonote_core/blockchain.cpp | 113 ++++++++++++++++-- src/cryptonote_core/blockchain.h | 9 ++ 4 files changed, 136 insertions(+), 15 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index d37b9a91e57..9d7060fbcec 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -768,24 +768,37 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool add_stake_to_extra(std::vector& tx_extra, const std::vector &extra_stake) + bool get_tx_stake_from_extra(crypto::secret_key& view_secret_key, std::vector& tx_id, const std::vector& extra_stake) { const size_t HASH_SIZE = sizeof(crypto::hash); if (extra_stake.size() % HASH_SIZE != 0 || extra_stake.size() < HASH_SIZE * 2) return false; - // parse stake - tx_extra_stake stake; - std::copy(extra_stake.data(), extra_stake.data() + HASH_SIZE, stake.view_secret_key.data); + std::copy(extra_stake.data(), extra_stake.data() + HASH_SIZE, view_secret_key.data); - size_t cnt = extra_stake.size() / sizeof(crypto::hash) - 1; - stake.count = static_cast(cnt); + size_t cnt = extra_stake.size() / HASH_SIZE - 1; for (size_t i = 0; i < cnt; ++i) { crypto::hash id; std::copy(extra_stake.data() + HASH_SIZE * (1 + i), extra_stake.data() + HASH_SIZE * (2 + i), id.data); - stake.tx_id.push_back(id); + tx_id.push_back(id); } + return true; + } + //--------------------------------------------------------------- + bool add_stake_to_extra(std::vector& tx_extra, const std::vector &extra_stake) + { + crypto::secret_key vsk = AUTO_VAL_INIT(vsk); + std::vector ti = AUTO_VAL_INIT(ti); + + if (!get_tx_stake_from_extra(vsk, ti, extra_stake)) + return false; + + // parse stake + tx_extra_stake stake; + stake.view_secret_key = vsk; + stake.tx_id = ti; + stake.count = static_cast(ti.size()); // convert to variant tx_extra_field field = stake; diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index 3024394898b..ed001872e1c 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -86,7 +86,7 @@ namespace cryptonote bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id); bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id); bool add_stake_to_extra(std::vector& tx_extra, const std::vector& extra_stake); - void get_stake_from_extra(); + bool get_tx_stake_from_extra(crypto::secret_key& view_secret_key, std::vector& tx_id, const std::vector& extra_stake); bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, const std::vector& additional_tx_public_keys, size_t output_index); struct subaddress_receive_info diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 0e9f5950804..364d000a7f2 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -94,24 +94,31 @@ static const struct { { 1, 1, 0, 1341378000 }, // version 2 starts from block 1009827, which is on or around the 20th of March, 2016. Fork time finalised on 2015-09-20. No fork voting occurs for the v2 fork. - { 2, 1009827, 0, 1442763710 }, + //{ 2, 1009827, 0, 1442763710 }, + { 2, 1025, 0, 1442763710 }, // version 3 starts from block 1141317, which is on or around the 24th of September, 2016. Fork time finalised on 2016-03-21. - { 3, 1141317, 0, 1458558528 }, + //{ 3, 1141317, 0, 1458558528 }, + { 3, 1026, 0, 1458558528 }, // version 4 starts from block 1220516, which is on or around the 5th of January, 2017. Fork time finalised on 2016-09-18. - { 4, 1220516, 0, 1483574400 }, + //{ 4, 1220516, 0, 1483574400 }, + { 4, 1027, 0, 1483574400 }, // version 5 starts from block 1288616, which is on or around the 15th of April, 2017. Fork time finalised on 2017-03-14. - { 5, 1288616, 0, 1489520158 }, + //{ 5, 1288616, 0, 1489520158 }, + { 5, 1028, 0, 1489520158 }, // version 6 starts from block 1400000, which is on or around the 16th of September, 2017. Fork time finalised on 2017-08-18. - { 6, 1400000, 0, 1503046577 }, + //{ 6, 1400000, 0, 1503046577 }, + { 6, 1029, 0, 1503046577 }, // version 60 starts from block 1907000 - { HF_VERSION_60, DIFFICULTY_ADJUST_HEIGHT, 0, 1565600181}, + //{ HF_VERSION_60, DIFFICULTY_ADJUST_HEIGHT, 0, 1565600181}, + { HF_VERSION_60, 1030, 0, 1565600181}, }; -static const uint64_t mainnet_hard_fork_version_1_till = 1009826; +//static const uint64_t mainnet_hard_fork_version_1_till = 1009826; +static const uint64_t mainnet_hard_fork_version_1_till = 1024; static const struct { uint8_t version; @@ -1522,6 +1529,9 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, CHECK_AND_ASSERT_MES(diffic, false, "difficulty overhead."); + uint64_t pos_reward = 0; + CHECK_AND_ASSERT_MES(check_miner_stakes(miner_address, ex_stake, pos_reward), false, "check miner's pos failed"); + size_t txs_weight; uint64_t fee; if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, b.major_version)) @@ -5080,6 +5090,95 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_ m_btc_valid = true; } +bool Blockchain::check_miner_stakes(const account_public_address& miner_address, const std::vector& ex_stake, uint64_t& stake_reward) +{ + stake_reward = 0; + + crypto::secret_key vsk = AUTO_VAL_INIT(vsk); + std::vector ti = AUTO_VAL_INIT(ti); + bool r = get_tx_stake_from_extra(vsk, ti, ex_stake); + CHECK_AND_ASSERT_MES(r, false, "failed to parse tx extra stake"); + + crypto::public_key pkey; + r = crypto::secret_key_to_public_key(vsk, pkey); + CHECK_AND_ASSERT_MES(r, false, "Failed to verify view key secret key"); + CHECK_AND_ASSERT_MES(pkey == miner_address.m_view_public_key, false, "view secret key does not match mine address"); + + std::vector mis; + std::vector txs; + get_transactions(ti, txs, mis); + CHECK_AND_ASSERT_MES(!mis.size() && txs.size(), false, "transaction provided by extra stake not found"); + + uint64_t weight = 0; + hw::device &hwd = hw::get_device("default"); + for(const auto& tx: txs) + { + uint64_t amount = 0; + // we only need locked tx, and since tx is locked, so it's unspent, thus we don't need check double spend. + if (is_tx_spendtime_unlocked(tx.unlock_time)) + continue; + + // we don't want coinbase tx + if (is_coinbase(tx)) + continue; + + const rct::rctSig& rv = tx.rct_signatures; + + const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); + crypto::key_derivation derivation; + r = hwd.generate_key_derivation(tx_pub_key, vsk, derivation); + CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation"); + + // scan all output, calculate amount + for(size_t i = 0; i < tx.vout.size(); ++i) + { + const cryptonote::tx_out& vo = tx.vout[i]; + + // we only need txout_to_key + if (vo.target.type() != typeid(txout_to_key)) + continue; + + // check if this is our address + crypto::public_key pk; + r = hwd.derive_public_key(derivation, i, miner_address.m_spend_public_key, pk); + CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key"); + if (pk != boost::get(vo.target).key) + continue; + + crypto::secret_key scalar1; + hwd.derivation_to_scalar(derivation, i, scalar1); + + // we decode the amount + rct::key mask; + uint8_t type = rv.type; + switch (type) + { + case rct::RCTTypeSimple: + case rct::RCTTypeBulletproof: + case rct::RCTTypeBulletproof2: + amount += rct::decodeRctSimple(rv, rct::sk2rct(scalar1), static_cast(i), mask, hwd); + break; + case rct::RCTTypeFull: + amount += rct::decodeRct(rv, rct::sk2rct(scalar1), static_cast(i), mask, hwd); + break; + // This should never happen + case rct::RCTTypeNull: + amount += vo.amount; + break; + default: + LOG_ERROR("Unsupported rct type: " << type); + break; + } + } + + // we calculate weight + //weight += amount * ( tx.unlock_time - m_db->height()); + } + // we use amount and lock time to calculate weight, and then for pos reward + + return true; +} + namespace cryptonote { template bool Blockchain::get_transactions(const std::vector&, std::vector&, std::vector&) const; template bool Blockchain::get_transactions_blobs(const std::vector&, std::vector&, std::vector&, bool) const; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index b875da263c2..ec021a2f919 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1488,5 +1488,14 @@ namespace cryptonote * At some point, may be used to push an update to miners */ void cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t pool_cookie); + + /** + * @brief check miner stake + * + * stake's view secret key must match miner's view public key + * stake's every tx must be miner's + * stake_reward is the reward of stake + */ + bool check_miner_stakes(const account_public_address& miner_address, const std::vector& ex_stake, uint64_t& stake_reward); }; } // namespace cryptonote From 5324c9208f6d7a6bb64b460346575dbeeb0058f3 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Thu, 31 Oct 2019 10:25:30 +0800 Subject: [PATCH 08/34] progressing: Add pos reward while miner tx --- src/cryptonote_core/blockchain.cpp | 9 +++++---- src/cryptonote_core/cryptonote_tx_utils.cpp | 4 +++- src/cryptonote_core/cryptonote_tx_utils.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 364d000a7f2..f0582faad1f 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1538,6 +1538,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, { return false; } + expected_reward += pos_reward; pool_cookie = m_tx_pool.cookie(); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) size_t real_txs_weight = 0; @@ -1600,7 +1601,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, uint8_t hf_version = b.major_version; size_t max_outs = hf_version >= 4 ? 1 : 11; // bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); - bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake); + bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake, pos_reward); CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance"); size_t cumulative_weight = txs_weight + get_transaction_weight(b.miner_tx); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) @@ -1610,7 +1611,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, for (size_t try_count = 0; try_count != 10; ++try_count) { // r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); - r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake); + r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake, pos_reward); CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, second chance"); size_t coinbase_weight = get_transaction_weight(b.miner_tx); @@ -5171,10 +5172,10 @@ bool Blockchain::check_miner_stakes(const account_public_address& miner_address, } } - // we calculate weight + // TODO: we calculate weight //weight += amount * ( tx.unlock_time - m_db->height()); } - // we use amount and lock time to calculate weight, and then for pos reward + // TODO: we use amount and lock time to calculate weight, and then for pos reward return true; } diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index bce56661413..be25a676ffa 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -77,7 +77,7 @@ namespace cryptonote } //--------------------------------------------------------------- // bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) { - bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version, network_type nettype, const std::vector &extra_stake) { + bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version, network_type nettype, const std::vector &extra_stake, uint64_t pos_reward) { tx.vin.clear(); tx.vout.clear(); tx.extra.clear(); @@ -134,6 +134,8 @@ namespace cryptonote MERROR("construct_miner_tx,block_reward=" << block_reward <<",fund_reward=" << fund_reward << ",height=" << height); } + block_reward += pos_reward; + std::vector out_amounts; decompose_amount_into_digits(block_reward, hard_fork_version >= 2 ? 0 : ::config::DEFAULT_DUST_THRESHOLD, [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index b80da33b10b..211c7824f6f 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -38,7 +38,7 @@ namespace cryptonote { //--------------------------------------------------------------- // bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1); - bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1, network_type nettype = MAINNET, const std::vector& extra_stake = std::vector()); + bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1, network_type nettype = MAINNET, const std::vector& extra_stake = std::vector(), uint64_t pos_reward = 0); struct tx_source_entry { From 2886afac4651500d46a43a8da9acbd7f8fbde925 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Thu, 31 Oct 2019 17:19:24 +0800 Subject: [PATCH 09/34] progressing: Add check pos in validate_miner_tx --- .../cryptonote_format_utils.cpp | 36 +++++++--- .../cryptonote_format_utils.h | 4 +- src/cryptonote_basic/miner.cpp | 16 +++-- src/cryptonote_basic/tx_extra.h | 2 + src/cryptonote_core/blockchain.cpp | 72 ++++++++++++++----- src/cryptonote_core/blockchain.h | 2 +- 6 files changed, 98 insertions(+), 34 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index 9d7060fbcec..11119654012 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -768,34 +768,54 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool get_tx_stake_from_extra(crypto::secret_key& view_secret_key, std::vector& tx_id, const std::vector& extra_stake) + bool get_tx_stake_from_extra(crypto::public_key& spend_pub_key, crypto::secret_key& view_secret_key, std::vector& tx_ids, const std::vector& extra_stake) { - const size_t HASH_SIZE = sizeof(crypto::hash); - if (extra_stake.size() % HASH_SIZE != 0 || extra_stake.size() < HASH_SIZE * 2) + const size_t HASH_SIZE = sizeof(crypto::hash); // public_key, secret_key, hash has same size + if (extra_stake.size() % HASH_SIZE != 0 || extra_stake.size() < HASH_SIZE * 3) return false; - std::copy(extra_stake.data(), extra_stake.data() + HASH_SIZE, view_secret_key.data); + std::copy(extra_stake.data(), extra_stake.data() + HASH_SIZE, spend_pub_key.data); - size_t cnt = extra_stake.size() / HASH_SIZE - 1; + std::copy(extra_stake.data() + HASH_SIZE, extra_stake.data() + 2 * HASH_SIZE, view_secret_key.data); + + size_t cnt = extra_stake.size() / HASH_SIZE - 2; for (size_t i = 0; i < cnt; ++i) { crypto::hash id; - std::copy(extra_stake.data() + HASH_SIZE * (1 + i), extra_stake.data() + HASH_SIZE * (2 + i), id.data); - tx_id.push_back(id); + std::copy(extra_stake.data() + HASH_SIZE * (2 + i), extra_stake.data() + HASH_SIZE * (3 + i), id.data); + tx_ids.push_back(id); } return true; } //--------------------------------------------------------------- + bool get_tx_stake_from_extra(crypto::public_key& spend_pub_key, crypto::secret_key& view_secret_key, std::vector& tx_ids, const std::vector &tx_extra, size_t stk_index) + { + std::vector tx_extra_fields; + parse_tx_extra(tx_extra, tx_extra_fields); + + tx_extra_stake stake_field; + if(!find_tx_extra_field_by_type(tx_extra_fields, stake_field, stk_index)) + return false; + + spend_pub_key = stake_field.spend_pub_key; + view_secret_key = stake_field.view_secret_key; + tx_ids = stake_field.tx_id; + + return true; + } + //--------------------------------------------------------------- bool add_stake_to_extra(std::vector& tx_extra, const std::vector &extra_stake) { + crypto::public_key spk = AUTO_VAL_INIT(spk); crypto::secret_key vsk = AUTO_VAL_INIT(vsk); std::vector ti = AUTO_VAL_INIT(ti); - if (!get_tx_stake_from_extra(vsk, ti, extra_stake)) + if (!get_tx_stake_from_extra(spk, vsk, ti, extra_stake)) return false; // parse stake tx_extra_stake stake; + stake.spend_pub_key = spk; stake.view_secret_key = vsk; stake.tx_id = ti; stake.count = static_cast(ti.size()); diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index ed001872e1c..fa3a77bab5e 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -86,8 +86,8 @@ namespace cryptonote bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id); bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id); bool add_stake_to_extra(std::vector& tx_extra, const std::vector& extra_stake); - bool get_tx_stake_from_extra(crypto::secret_key& view_secret_key, std::vector& tx_id, const std::vector& extra_stake); - + bool get_tx_stake_from_extra(crypto::public_key& spend_pub_key, crypto::secret_key& view_secret_key, std::vector& tx_ids, const std::vector& extra_stake); + bool get_tx_stake_from_extra(crypto::public_key& spend_pub_key, crypto::secret_key& view_secret_key, std::vector& tx_id, const std::vector& tx_extra, size_t stk_index); bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, const std::vector& additional_tx_public_keys, size_t output_index); struct subaddress_receive_info { diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 623013c6bd8..a5a67d9547c 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -172,14 +172,16 @@ namespace cryptonote std::vector extra_stake; if (m_pos_settings.tx_id.size()) { - extra_stake.reserve((sizeof(crypto::secret_key) + sizeof(crypto::hash) * m_pos_settings.tx_id.size())); - // copy view secret key - std::copy(&m_pos_settings.view_secret_key.data[0], &m_pos_settings.view_secret_key.data[sizeof(crypto::secret_key)], std::back_inserter(extra_stake)); - // copy each tx id - for (const auto& id: m_pos_settings.tx_id) - { + extra_stake.reserve( sizeof(crypto::public_key) + sizeof(crypto::secret_key) + sizeof(crypto::hash) * m_pos_settings.tx_id.size()); + // copy spend public key + std::copy(&m_mine_address.m_spend_public_key.data[0], &m_mine_address.m_spend_public_key.data[sizeof(crypto::public_key)], std::back_inserter(extra_stake)); + // copy view secret key + std::copy(&m_pos_settings.view_secret_key.data[0], &m_pos_settings.view_secret_key.data[sizeof(crypto::secret_key)], std::back_inserter(extra_stake)); + // copy each tx id + for (const auto& id: m_pos_settings.tx_id) + { std::copy(&id.data[0], &id.data[sizeof(crypto::hash)], std::back_inserter(extra_stake)); - } + } } if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce, extra_stake)) diff --git a/src/cryptonote_basic/tx_extra.h b/src/cryptonote_basic/tx_extra.h index 4aab2f3c004..1d0ce9a2c6e 100644 --- a/src/cryptonote_basic/tx_extra.h +++ b/src/cryptonote_basic/tx_extra.h @@ -182,11 +182,13 @@ namespace cryptonote struct tx_extra_stake { + crypto::public_key spend_pub_key; crypto::secret_key view_secret_key; uint8_t count; std::vector tx_id; BEGIN_SERIALIZE() + FIELD(spend_pub_key) FIELD(view_secret_key) FIELD(count) FIELD(tx_id) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index f0582faad1f..75b3722e48a 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1257,6 +1257,41 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height) bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_block_weight, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version) { LOG_PRINT_L3("Blockchain::" << __func__); + uint64_t height = boost::get(b.miner_tx.vin[0]).height; + uint64_t pos_reward = 0; + crypto::public_key spk = AUTO_VAL_INIT(spk); + crypto::secret_key vsk = AUTO_VAL_INIT(vsk); + std::vector ti = AUTO_VAL_INIT(ti); + bool r = get_tx_stake_from_extra(spk, vsk, ti, b.miner_tx.extra, 0); + if (r) + { + // miner us pos, we should make check + // 1. check if vout and spk, vsk match + crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx.extra); + + account_keys acc; + acc.m_view_secret_key = vsk; + acc.m_account_address.m_spend_public_key = spk; + + r = false; + for (size_t i = 0; i < b.miner_tx.vout.size(); ++i) + { + const tx_out& tax_out = b.miner_tx.vout[i]; + std::vector additional_derivations; + r = cryptonote::is_out_to_acc(acc, boost::get(tax_out.target), tx_pub_key, additional_derivations, i); + // there are should be two outputs, one is miner reward, another is funding reward, we need miner reward be true should ok + if (r) break; + } + CHECK_AND_ASSERT_MES(r, false, "failed to validate miner's stake extra"); + + // 2. check if amount match pos's stake + crypto::public_key vpk = AUTO_VAL_INIT(vpk); + r = crypto::secret_key_to_public_key(vsk, vpk); + CHECK_AND_ASSERT_MES(r, false, "illegal view secret key in stake extra"); + + r = check_miner_stakes(spk, vsk, ti, height, pos_reward); + } + //validate reward uint64_t money_in_use = 0; for (auto& o: b.miner_tx.vout) @@ -1277,7 +1312,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl } } - uint64_t height = boost::get(b.miner_tx.vin[0]).height; + uint64_t funding_amount = 0; uint64_t miner_reward_amount = 0; // cryptonote::BlockFunding fundctl; @@ -1529,8 +1564,23 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, CHECK_AND_ASSERT_MES(diffic, false, "difficulty overhead."); + // calculate pos reward uint64_t pos_reward = 0; - CHECK_AND_ASSERT_MES(check_miner_stakes(miner_address, ex_stake, pos_reward), false, "check miner's pos failed"); + if (!ex_stake.empty()) + { + crypto::public_key spk = AUTO_VAL_INIT(spk); + crypto::secret_key vsk = AUTO_VAL_INIT(vsk); + std::vector ti = AUTO_VAL_INIT(ti); + bool r = get_tx_stake_from_extra(spk, vsk, ti, ex_stake); + CHECK_AND_ASSERT_MES(r, false, "failed to parse tx extra stake"); + CHECK_AND_ASSERT_MES(spk == miner_address.m_spend_public_key, false, "failed to construct stake extra spend pub key"); + + crypto::public_key pkey; + r = crypto::secret_key_to_public_key(vsk, pkey); + CHECK_AND_ASSERT_MES(r, false, "failed to verify view key secret key"); + CHECK_AND_ASSERT_MES(pkey == miner_address.m_view_public_key, false, "view secret key does not match mine address"); + CHECK_AND_ASSERT_MES(check_miner_stakes(spk, vsk, ti, height, pos_reward), false, "check miner's pos failed"); + } size_t txs_weight; uint64_t fee; @@ -5091,20 +5141,10 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_ m_btc_valid = true; } -bool Blockchain::check_miner_stakes(const account_public_address& miner_address, const std::vector& ex_stake, uint64_t& stake_reward) +bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, std::vector &ti, size_t height, uint64_t& stake_reward) { stake_reward = 0; - crypto::secret_key vsk = AUTO_VAL_INIT(vsk); - std::vector ti = AUTO_VAL_INIT(ti); - bool r = get_tx_stake_from_extra(vsk, ti, ex_stake); - CHECK_AND_ASSERT_MES(r, false, "failed to parse tx extra stake"); - - crypto::public_key pkey; - r = crypto::secret_key_to_public_key(vsk, pkey); - CHECK_AND_ASSERT_MES(r, false, "Failed to verify view key secret key"); - CHECK_AND_ASSERT_MES(pkey == miner_address.m_view_public_key, false, "view secret key does not match mine address"); - std::vector mis; std::vector txs; get_transactions(ti, txs, mis); @@ -5127,7 +5167,7 @@ bool Blockchain::check_miner_stakes(const account_public_address& miner_address, const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); crypto::key_derivation derivation; - r = hwd.generate_key_derivation(tx_pub_key, vsk, derivation); + bool r = hwd.generate_key_derivation(tx_pub_key, view_seckey, derivation); CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation"); // scan all output, calculate amount @@ -5141,7 +5181,7 @@ bool Blockchain::check_miner_stakes(const account_public_address& miner_address, // check if this is our address crypto::public_key pk; - r = hwd.derive_public_key(derivation, i, miner_address.m_spend_public_key, pk); + r = hwd.derive_public_key(derivation, i, spend_pubkey, pk); CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key"); if (pk != boost::get(vo.target).key) continue; @@ -5173,7 +5213,7 @@ bool Blockchain::check_miner_stakes(const account_public_address& miner_address, } // TODO: we calculate weight - //weight += amount * ( tx.unlock_time - m_db->height()); + //weight += amount * ( tx.unlock_time - height); } // TODO: we use amount and lock time to calculate weight, and then for pos reward diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index ec021a2f919..f7fd69c4522 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1496,6 +1496,6 @@ namespace cryptonote * stake's every tx must be miner's * stake_reward is the reward of stake */ - bool check_miner_stakes(const account_public_address& miner_address, const std::vector& ex_stake, uint64_t& stake_reward); + bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, std::vector& ti, size_t height, uint64_t& stake_reward); }; } // namespace cryptonote From b6c4069ddd10530b35d30235aa36d91d1a23a315 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Fri, 1 Nov 2019 10:32:08 +0800 Subject: [PATCH 10/34] progressing: Add pos reward calculate(partial) --- .../cryptonote_basic_impl.cpp | 42 ++++++++++++++++++- src/cryptonote_basic/cryptonote_basic_impl.h | 1 + src/cryptonote_core/blockchain.cpp | 7 ++-- src/cryptonote_core/blockchain.h | 2 +- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index e7e971de892..0d5ddef9776 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -46,6 +46,10 @@ using namespace epee; #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "cn" +const static uint64_t MIN_STAKE_COIN = 1e12; // minimum stake coin, 1 XMC +const static size_t MIN_STAKE_HEIGHT = 21600; // minimum stake height, 3 month +const static uint64_t MIN_STAKE_TIMESTAMP = 3 * 30 * 24 * 60 * 60; // minimum stake time, 3 month + namespace cryptonote { struct integrated_address { @@ -318,8 +322,44 @@ namespace cryptonote { } bool operator ==(const cryptonote::block& a, const cryptonote::block& b) { - return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b); + return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b); + } + //-------------------------------------------------------------------------------- + uint64_t get_pos_block_reward(uint64_t unlock_time, uint64_t block_time, size_t block_height, uint64_t staked_coins) + { + uint64_t reward = 0; + + if (staked_coins < MIN_STAKE_COIN) + return reward; + + if (unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER) + { + // treat unlock_time as height + if (unlock_time < block_height) + return reward; + + uint64_t delta_height = unlock_time - block_height; + if (delta_height < MIN_STAKE_HEIGHT) + return reward; + } + else + { + // treat unlock_time as timestamp + if (unlock_time < block_time) + return reward; + + uint64_t delta_ts = unlock_time - block_time; + if (delta_ts < MIN_STAKE_TIMESTAMP) + return reward; + + } + + + // TODO: need more.. + + return reward; } + //-------------------------------------------------------------------------------- } //-------------------------------------------------------------------------------- diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h index c7198a16f3b..1d6f4367575 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/cryptonote_basic/cryptonote_basic_impl.h @@ -91,6 +91,7 @@ namespace cryptonote { bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version); uint8_t get_account_address_checksum(const public_address_outer_blob& bl); uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl); + uint64_t get_pos_block_reward(uint64_t unlock_time, uint64_t block_time, size_t block_height, uint64_t staked_coins); std::string get_account_address_as_str( network_type nettype diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 75b3722e48a..501e5315026 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1289,7 +1289,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl r = crypto::secret_key_to_public_key(vsk, vpk); CHECK_AND_ASSERT_MES(r, false, "illegal view secret key in stake extra"); - r = check_miner_stakes(spk, vsk, ti, height, pos_reward); + r = check_miner_stakes(spk, vsk, ti, height, b.timestamp, pos_reward); } //validate reward @@ -1579,7 +1579,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, r = crypto::secret_key_to_public_key(vsk, pkey); CHECK_AND_ASSERT_MES(r, false, "failed to verify view key secret key"); CHECK_AND_ASSERT_MES(pkey == miner_address.m_view_public_key, false, "view secret key does not match mine address"); - CHECK_AND_ASSERT_MES(check_miner_stakes(spk, vsk, ti, height, pos_reward), false, "check miner's pos failed"); + CHECK_AND_ASSERT_MES(check_miner_stakes(spk, vsk, ti, height, b.timestamp, pos_reward), false, "check miner's pos failed"); } size_t txs_weight; @@ -5141,7 +5141,7 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_ m_btc_valid = true; } -bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, std::vector &ti, size_t height, uint64_t& stake_reward) +bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, std::vector &ti, size_t height, uint64_t timestamp, uint64_t& stake_reward) { stake_reward = 0; @@ -5214,6 +5214,7 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto // TODO: we calculate weight //weight += amount * ( tx.unlock_time - height); + stake_reward += get_pos_block_reward(tx.unlock_time, timestamp, height, amount); } // TODO: we use amount and lock time to calculate weight, and then for pos reward diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index f7fd69c4522..9664e82ae7d 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1496,6 +1496,6 @@ namespace cryptonote * stake's every tx must be miner's * stake_reward is the reward of stake */ - bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, std::vector& ti, size_t height, uint64_t& stake_reward); + bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, std::vector& ti, size_t height, uint64_t timestamp, uint64_t& stake_reward); }; } // namespace cryptonote From 2502173bf44ffe9863d81d301c3968b4c00940d3 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Fri, 1 Nov 2019 14:59:09 +0800 Subject: [PATCH 11/34] progressing: check amount --- src/cryptonote_core/blockchain.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 501e5315026..252a8a7d7f4 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1265,7 +1265,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl bool r = get_tx_stake_from_extra(spk, vsk, ti, b.miner_tx.extra, 0); if (r) { - // miner us pos, we should make check + // miner use pos, we should make check // 1. check if vout and spk, vsk match crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx.extra); @@ -1312,7 +1312,6 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl } } - uint64_t funding_amount = 0; uint64_t miner_reward_amount = 0; // cryptonote::BlockFunding fundctl; @@ -1335,6 +1334,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl MERROR_VER("block weight " << cumulative_block_weight << " is bigger than allowed for this blockchain"); return false; } + base_reward += pos_reward; if(base_reward + fee < money_in_use) { MERROR_VER("coinbase transaction spend too much money (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + fee) << "(" << print_money(base_reward) << "+" << print_money(fee) << ")"); @@ -5150,7 +5150,6 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto get_transactions(ti, txs, mis); CHECK_AND_ASSERT_MES(!mis.size() && txs.size(), false, "transaction provided by extra stake not found"); - uint64_t weight = 0; hw::device &hwd = hw::get_device("default"); for(const auto& tx: txs) { @@ -5186,8 +5185,8 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto if (pk != boost::get(vo.target).key) continue; - crypto::secret_key scalar1; - hwd.derivation_to_scalar(derivation, i, scalar1); + crypto::secret_key sk; + hwd.derivation_to_scalar(derivation, i, sk); // we decode the amount rct::key mask; @@ -5197,10 +5196,10 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto case rct::RCTTypeSimple: case rct::RCTTypeBulletproof: case rct::RCTTypeBulletproof2: - amount += rct::decodeRctSimple(rv, rct::sk2rct(scalar1), static_cast(i), mask, hwd); + amount += rct::decodeRctSimple(rv, rct::sk2rct(sk), static_cast(i), mask, hwd); break; case rct::RCTTypeFull: - amount += rct::decodeRct(rv, rct::sk2rct(scalar1), static_cast(i), mask, hwd); + amount += rct::decodeRct(rv, rct::sk2rct(sk), static_cast(i), mask, hwd); break; // This should never happen case rct::RCTTypeNull: @@ -5216,7 +5215,6 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto //weight += amount * ( tx.unlock_time - height); stake_reward += get_pos_block_reward(tx.unlock_time, timestamp, height, amount); } - // TODO: we use amount and lock time to calculate weight, and then for pos reward return true; } From d1af4b7ab6dc41f7f8b512930bc6be2c1446006d Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Mon, 4 Nov 2019 15:27:47 +0800 Subject: [PATCH 12/34] progressing: Add sample code for stake time/coin --- .../cryptonote_basic_impl.cpp | 39 +++++++++++++------ src/cryptonote_basic/cryptonote_basic_impl.h | 2 +- src/cryptonote_basic/miner.cpp | 2 +- src/cryptonote_core/blockchain.cpp | 13 ++++++- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index 0d5ddef9776..84f01235d09 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -46,9 +46,15 @@ using namespace epee; #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "cn" -const static uint64_t MIN_STAKE_COIN = 1e12; // minimum stake coin, 1 XMC -const static size_t MIN_STAKE_HEIGHT = 21600; // minimum stake height, 3 month -const static uint64_t MIN_STAKE_TIMESTAMP = 3 * 30 * 24 * 60 * 60; // minimum stake time, 3 month +const static size_t MIN_STAKE_HEIGHT = 2160; // minimum stake height, 3 day +const static uint64_t MIN_STAKE_TIMESTAMP = 3 * 24 * 60 * 60; // minimum stake time, 3 day + +// for timestamp map, we can multiple 60 * 2 for STAKE_HEIGHT_PROFIT's first +const static std::map STAKE_HEIGHT_PROFIT = { + {3 * 24 * 60 / 2, 1}, // 3 day + {6 * 24 * 60 / 2, 3}, // 6 day + {12 * 24 * 60 / 2, 10}, // 12 day +}; namespace cryptonote { @@ -325,12 +331,20 @@ namespace cryptonote { return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b); } //-------------------------------------------------------------------------------- - uint64_t get_pos_block_reward(uint64_t unlock_time, uint64_t block_time, size_t block_height, uint64_t staked_coins) + uint64_t get_pos_block_reward(uint64_t unlock_time, size_t block_height, uint64_t block_time, uint64_t staked_coins) { - uint64_t reward = 0; - - if (staked_coins < MIN_STAKE_COIN) - return reward; + uint64_t reward = 0, time_proft = 0; + + auto cal_tp = [&](uint64_t t, bool is_height) { + uint64_t tp = 0; + for (auto i = STAKE_HEIGHT_PROFIT.rbegin(); i != STAKE_HEIGHT_PROFIT.rend(); ++i ) { + if (t / (i->first * (is_height ? 1 : 2 * 60))) { + tp = i->second; + break; + } + } + return tp; + }; if (unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER) { @@ -341,9 +355,9 @@ namespace cryptonote { uint64_t delta_height = unlock_time - block_height; if (delta_height < MIN_STAKE_HEIGHT) return reward; - } - else - { + + time_proft = cal_tp(delta_height, true); + } else { // treat unlock_time as timestamp if (unlock_time < block_time) return reward; @@ -352,10 +366,11 @@ namespace cryptonote { if (delta_ts < MIN_STAKE_TIMESTAMP) return reward; + time_proft = cal_tp(delta_ts, false); } - // TODO: need more.. + reward = staked_coins * time_proft / 100000; return reward; } diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h index 1d6f4367575..31ae3555485 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/cryptonote_basic/cryptonote_basic_impl.h @@ -91,7 +91,7 @@ namespace cryptonote { bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version); uint8_t get_account_address_checksum(const public_address_outer_blob& bl); uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl); - uint64_t get_pos_block_reward(uint64_t unlock_time, uint64_t block_time, size_t block_height, uint64_t staked_coins); + uint64_t get_pos_block_reward(uint64_t unlock_time, size_t block_height, uint64_t block_time, uint64_t staked_coins); std::string get_account_address_as_str( network_type nettype diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index a5a67d9547c..93aa9ea448f 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -77,7 +77,7 @@ #define AUTODETECT_WINDOW 10 // seconds #define AUTODETECT_GAIN_THRESHOLD 1.02f // 2% -#define POS_MAX_TX_COUNT 5 +#define POS_MAX_TX_COUNT 20 using namespace epee; diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 252a8a7d7f4..3526bd0ac80 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -161,6 +161,8 @@ static const struct { { 6, 36000, 0, 1521480000 }, }; +const static uint64_t MIN_STAKE_COIN = 10000e12; // 10'000 XMC + //------------------------------------------------------------------ Blockchain::Blockchain(tx_memory_pool& tx_pool) : m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_weight_limit(0), m_current_block_cumul_weight_median(0), @@ -5150,6 +5152,7 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto get_transactions(ti, txs, mis); CHECK_AND_ASSERT_MES(!mis.size() && txs.size(), false, "transaction provided by extra stake not found"); + uint64_t staked_coin = 0; hw::device &hwd = hw::get_device("default"); for(const auto& tx: txs) { @@ -5209,13 +5212,19 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto LOG_ERROR("Unsupported rct type: " << type); break; } + + staked_coin += amount; } // TODO: we calculate weight - //weight += amount * ( tx.unlock_time - height); - stake_reward += get_pos_block_reward(tx.unlock_time, timestamp, height, amount); + stake_reward += cryptonote::get_pos_block_reward(tx.unlock_time, height, timestamp, amount); } + stake_reward = stake_reward > 1e12 ? 1e12 : stake_reward; + + if (staked_coin < MIN_STAKE_COIN) + stake_reward = 0; + return true; } From f4cbd7c569f7aa8fa938f64f616b0d0aad582eee Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Tue, 5 Nov 2019 11:40:28 +0800 Subject: [PATCH 13/34] progressing: use staked_tx block height, instead of miner_tx block height --- .../cryptonote_basic_impl.cpp | 2 +- src/cryptonote_basic/cryptonote_basic_impl.h | 2 +- src/cryptonote_core/blockchain.cpp | 21 +++++++++++++------ src/cryptonote_core/blockchain.h | 2 +- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index 84f01235d09..f82ce7e598a 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -331,7 +331,7 @@ namespace cryptonote { return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b); } //-------------------------------------------------------------------------------- - uint64_t get_pos_block_reward(uint64_t unlock_time, size_t block_height, uint64_t block_time, uint64_t staked_coins) + uint64_t get_pos_block_reward(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins) { uint64_t reward = 0, time_proft = 0; diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h index 31ae3555485..d10633f3e0d 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/cryptonote_basic/cryptonote_basic_impl.h @@ -91,7 +91,7 @@ namespace cryptonote { bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version); uint8_t get_account_address_checksum(const public_address_outer_blob& bl); uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl); - uint64_t get_pos_block_reward(uint64_t unlock_time, size_t block_height, uint64_t block_time, uint64_t staked_coins); + uint64_t get_pos_block_reward(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins); std::string get_account_address_as_str( network_type nettype diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 3526bd0ac80..646a0793c87 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1259,7 +1259,7 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height) bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_block_weight, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version) { LOG_PRINT_L3("Blockchain::" << __func__); - uint64_t height = boost::get(b.miner_tx.vin[0]).height; + uint64_t pos_reward = 0; crypto::public_key spk = AUTO_VAL_INIT(spk); crypto::secret_key vsk = AUTO_VAL_INIT(vsk); @@ -1291,7 +1291,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl r = crypto::secret_key_to_public_key(vsk, vpk); CHECK_AND_ASSERT_MES(r, false, "illegal view secret key in stake extra"); - r = check_miner_stakes(spk, vsk, ti, height, b.timestamp, pos_reward); + r = check_miner_stakes(spk, vsk, ti, pos_reward); } //validate reward @@ -1316,6 +1316,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl uint64_t funding_amount = 0; uint64_t miner_reward_amount = 0; + uint64_t height = boost::get(b.miner_tx.vin[0]).height; // cryptonote::BlockFunding fundctl; // CHECK_AND_ASSERT_MES(fundctl.init(m_nettype), false, "init fundctl failed"); // if (fundctl.funding_enabled(height)) @@ -1581,7 +1582,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, r = crypto::secret_key_to_public_key(vsk, pkey); CHECK_AND_ASSERT_MES(r, false, "failed to verify view key secret key"); CHECK_AND_ASSERT_MES(pkey == miner_address.m_view_public_key, false, "view secret key does not match mine address"); - CHECK_AND_ASSERT_MES(check_miner_stakes(spk, vsk, ti, height, b.timestamp, pos_reward), false, "check miner's pos failed"); + CHECK_AND_ASSERT_MES(check_miner_stakes(spk, vsk, ti, pos_reward), false, "check miner's pos failed"); } size_t txs_weight; @@ -5143,7 +5144,7 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_ m_btc_valid = true; } -bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, std::vector &ti, size_t height, uint64_t timestamp, uint64_t& stake_reward) +bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, std::vector &ti, uint64_t& stake_reward) { stake_reward = 0; @@ -5156,7 +5157,7 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto hw::device &hwd = hw::get_device("default"); for(const auto& tx: txs) { - uint64_t amount = 0; + uint64_t amount = 0, tx_block_height = 0, tx_block_time = 0; // we only need locked tx, and since tx is locked, so it's unspent, thus we don't need check double spend. if (is_tx_spendtime_unlocked(tx.unlock_time)) continue; @@ -5165,6 +5166,14 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto if (is_coinbase(tx)) continue; + tx_block_height = m_db->get_tx_block_height(tx.hash); + if (!tx_block_height) + continue; + + tx_block_time = m_db->get_block_timestamp(tx_block_height); + if (!tx_block_time) + continue; + const rct::rctSig& rv = tx.rct_signatures; const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); @@ -5217,7 +5226,7 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto } // TODO: we calculate weight - stake_reward += cryptonote::get_pos_block_reward(tx.unlock_time, height, timestamp, amount); + stake_reward += cryptonote::get_pos_block_reward(tx.unlock_time, tx_block_height, tx_block_time, amount); } stake_reward = stake_reward > 1e12 ? 1e12 : stake_reward; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 9664e82ae7d..04510778482 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1496,6 +1496,6 @@ namespace cryptonote * stake's every tx must be miner's * stake_reward is the reward of stake */ - bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, std::vector& ti, size_t height, uint64_t timestamp, uint64_t& stake_reward); + bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, std::vector& ti, uint64_t& stake_reward); }; } // namespace cryptonote From e120ca3b4e7a4306a74ea82d337eb17c2814b4e2 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Tue, 5 Nov 2019 11:45:08 +0800 Subject: [PATCH 14/34] progressing: refactor comment --- src/cryptonote_core/blockchain.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 646a0793c87..5ff05826b9b 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -5158,6 +5158,7 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto for(const auto& tx: txs) { uint64_t amount = 0, tx_block_height = 0, tx_block_time = 0; + // we only need locked tx, and since tx is locked, so it's unspent, thus we don't need check double spend. if (is_tx_spendtime_unlocked(tx.unlock_time)) continue; @@ -5225,12 +5226,14 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto staked_coin += amount; } - // TODO: we calculate weight + // TODO: we calculate reward stake_reward += cryptonote::get_pos_block_reward(tx.unlock_time, tx_block_height, tx_block_time, amount); } + // reward has maximum limit stake_reward = stake_reward > 1e12 ? 1e12 : stake_reward; + // staked coin has minimum limit if (staked_coin < MIN_STAKE_COIN) stake_reward = 0; From 469aace9b6a10357338cdddd6570ece8890c73eb Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Tue, 5 Nov 2019 16:47:06 +0800 Subject: [PATCH 15/34] progressing: refactor code --- src/cryptonote_core/blockchain.cpp | 2 +- src/cryptonote_core/blockchain.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 5ff05826b9b..46dc077c59d 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -5144,7 +5144,7 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_ m_btc_valid = true; } -bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, std::vector &ti, uint64_t& stake_reward) +bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, const std::vector &ti, uint64_t& stake_reward) { stake_reward = 0; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 04510778482..83ff7a8bba2 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1492,10 +1492,11 @@ namespace cryptonote /** * @brief check miner stake * + * spend_pubkey is miner's public spend key * stake's view secret key must match miner's view public key * stake's every tx must be miner's * stake_reward is the reward of stake */ - bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, std::vector& ti, uint64_t& stake_reward); + bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, const std::vector& ti, uint64_t& stake_reward); }; } // namespace cryptonote From a0202ce9fbf8d5926b79f08ecbab6cb0a0e3f921 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Wed, 6 Nov 2019 10:36:12 +0800 Subject: [PATCH 16/34] progressing: fix bug --- src/cryptonote_core/blockchain.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 46dc077c59d..982ba1357a3 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -5147,16 +5147,19 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, const std::vector &ti, uint64_t& stake_reward) { stake_reward = 0; - - std::vector mis; - std::vector txs; - get_transactions(ti, txs, mis); - CHECK_AND_ASSERT_MES(!mis.size() && txs.size(), false, "transaction provided by extra stake not found"); - uint64_t staked_coin = 0; hw::device &hwd = hw::get_device("default"); - for(const auto& tx: txs) + + for(const auto& txid: ti) { + cryptonote::blobdata db; + if (!m_db->get_tx_blob(txid, db)) + continue; + + transaction tx; + if (!parse_and_validate_tx_from_blob(db, tx)) + continue; + uint64_t amount = 0, tx_block_height = 0, tx_block_time = 0; // we only need locked tx, and since tx is locked, so it's unspent, thus we don't need check double spend. @@ -5167,7 +5170,7 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto if (is_coinbase(tx)) continue; - tx_block_height = m_db->get_tx_block_height(tx.hash); + tx_block_height = m_db->get_tx_block_height(txid); if (!tx_block_height) continue; From e66232d3588aa6819e025be5e4f69a26aeb447b3 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Wed, 6 Nov 2019 10:37:41 +0800 Subject: [PATCH 17/34] progressing: update pos settings when file modified. --- src/cryptonote_basic/miner.cpp | 128 ++++++++++++++++++++------------- src/cryptonote_basic/miner.h | 3 + 2 files changed, 82 insertions(+), 49 deletions(-) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 93aa9ea448f..17abb1c7350 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -125,7 +125,8 @@ namespace cryptonote m_idle_threshold(BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE), m_mining_target(BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE), m_miner_extra_sleep(BACKGROUND_MINING_DEFAULT_MINER_EXTRA_SLEEP_MILLIS), - m_block_reward(0) + m_block_reward(0), + m_modify_time(0) { m_attrs.set_stack_size(THREAD_STACK_SIZE); } @@ -163,6 +164,17 @@ namespace cryptonote uint64_t height = AUTO_VAL_INIT(height); uint64_t expected_reward; //only used for RPC calls - could possibly be useful here too? + // TODO: check if pos settings file changed, if changed, we read new settings, if not, we leave it + time_t mt; + if (epee::file_io_utils::get_file_time(m_pos_settings_file, mt)) + { + if (m_modify_time != mt) + { + load_pos_settings(m_pos_settings_file); + m_modify_time = mt; + } + } + cryptonote::blobdata extra_nonce; if(m_extra_messages.size() && m_config.current_extra_message_index < m_extra_messages.size()) { @@ -354,55 +366,15 @@ namespace cryptonote { CHECK_AND_ASSERT_MES(m_do_mining, false, "Must specify start-ming argument when using pos-settings-file"); - std::string buf, filename = command_line::get_arg(vm, arg_pos_settings); - bool r = epee::file_io_utils::load_file_to_string(filename, buf); - CHECK_AND_ASSERT_MES(r, false, "Failed to load pos settings file " << filename); - - rapidjson::Document json; - r = json.Parse(buf.c_str()).HasParseError(); - CHECK_AND_ASSERT_MES(!r, false, "Failed to parse pos settings JSON file " << filename); - - // parse view_secret_key field - GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, view_secret_key, std::string, String, false, std::string()); - CHECK_AND_ASSERT_MES(field_view_secret_key_found, false, "Failed to found view secret key"); - - cryptonote::blobdata viewkey_data; - r = epee::string_tools::parse_hexstr_to_binbuff(field_view_secret_key, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key); - CHECK_AND_ASSERT_MES(r, false, "Failed to parse view key secret key"); - - crypto::secret_key viewkey = *reinterpret_cast(viewkey_data.data()); - crypto::public_key pkey; - r = crypto::secret_key_to_public_key(viewkey, pkey); - CHECK_AND_ASSERT_MES(r, false, "Failed to verify view key secret key"); - CHECK_AND_ASSERT_MES(pkey == m_mine_address.m_view_public_key, false, "view secret key does not match mine address"); - - m_pos_settings = AUTO_VAL_INIT(m_pos_settings); - m_pos_settings.view_secret_key = viewkey; - - // parse tx_id field - r = json.HasMember("tx_id"); - CHECK_AND_ASSERT_MES(r, false, "Failed to found tx id"); - - const rapidjson::Value& array_txid = json["tx_id"]; - r = array_txid.IsArray(); - CHECK_AND_ASSERT_MES(r, false, "tx id must be array"); - - rapidjson::SizeType sz = array_txid.Size(); - CHECK_AND_ASSERT_MES(sz <= POS_MAX_TX_COUNT, false, "tx id should be less than " << POS_MAX_TX_COUNT); - for (rapidjson::SizeType i = 0; i < sz; i++) { - std::string field_id = static_cast(array_txid[i].GetString()); - cryptonote::blobdata id_data; - r = epee::string_tools::parse_hexstr_to_binbuff(field_id, id_data) || id_data.size() != sizeof(crypto::hash); - CHECK_AND_ASSERT_MES(r, false, "Failed to parse tx id"); - - crypto::hash id = *reinterpret_cast(id_data.data()); - if (std::find(m_pos_settings.tx_id.begin(), m_pos_settings.tx_id.end(), id) != m_pos_settings.tx_id.end()) - continue; - m_pos_settings.tx_id.push_back(id); - } + std::string filename = command_line::get_arg(vm, arg_pos_settings); + load_pos_settings(filename); + m_pos_settings_file = filename; - CHECK_AND_ASSERT_MES(m_pos_settings.tx_id.size(), false, "tx id can not be empty"); - MINFO("POS: Loaded view key succeed, and with " << m_pos_settings.tx_id.size() << " tx ids"); + time_t mt; + if (epee::file_io_utils::get_file_time(filename, mt)) + { + m_modify_time = mt; + } } // Background mining parameters @@ -1204,4 +1176,62 @@ namespace cryptonote LOG_ERROR("couldn't query power status"); return boost::logic::tribool(boost::logic::indeterminate); } + + bool miner::load_pos_settings(const std::string& filename) + { + std::string buf; + bool r = epee::file_io_utils::is_file_exist(filename); + CHECK_AND_ASSERT_MES(r, false, "pos settings file not exist"); + + r = epee::file_io_utils::load_file_to_string(filename, buf); + CHECK_AND_ASSERT_MES(r, false, "Failed to load pos settings file " << filename); + + rapidjson::Document json; + r = json.Parse(buf.c_str()).HasParseError(); + CHECK_AND_ASSERT_MES(!r, false, "Failed to parse pos settings JSON file " << filename); + + // parse view_secret_key field + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, view_secret_key, std::string, String, false, std::string()); + CHECK_AND_ASSERT_MES(field_view_secret_key_found, false, "Failed to found view secret key"); + + cryptonote::blobdata viewkey_data; + r = epee::string_tools::parse_hexstr_to_binbuff(field_view_secret_key, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse view key secret key"); + + crypto::secret_key viewkey = *reinterpret_cast(viewkey_data.data()); + crypto::public_key pkey; + r = crypto::secret_key_to_public_key(viewkey, pkey); + CHECK_AND_ASSERT_MES(r, false, "Failed to verify view key secret key"); + CHECK_AND_ASSERT_MES(pkey == m_mine_address.m_view_public_key, false, "view secret key does not match mine address"); + + m_pos_settings = AUTO_VAL_INIT(m_pos_settings); + m_pos_settings.view_secret_key = viewkey; + + // parse tx_id field + r = json.HasMember("tx_id"); + CHECK_AND_ASSERT_MES(r, false, "Failed to found tx id"); + + const rapidjson::Value& array_txid = json["tx_id"]; + r = array_txid.IsArray(); + CHECK_AND_ASSERT_MES(r, false, "tx id must be array"); + + rapidjson::SizeType sz = array_txid.Size(); + CHECK_AND_ASSERT_MES(sz <= POS_MAX_TX_COUNT, false, "tx id should be less than " << POS_MAX_TX_COUNT); + for (rapidjson::SizeType i = 0; i < sz; i++) { + std::string field_id = static_cast(array_txid[i].GetString()); + cryptonote::blobdata id_data; + r = epee::string_tools::parse_hexstr_to_binbuff(field_id, id_data) || id_data.size() != sizeof(crypto::hash); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse tx id"); + + crypto::hash id = *reinterpret_cast(id_data.data()); + if (std::find(m_pos_settings.tx_id.begin(), m_pos_settings.tx_id.end(), id) != m_pos_settings.tx_id.end()) + continue; + m_pos_settings.tx_id.push_back(id); + } + + CHECK_AND_ASSERT_MES(m_pos_settings.tx_id.size(), false, "tx id can not be empty"); + MINFO("POS: Loaded view key succeed, and with " << m_pos_settings.tx_id.size() << " tx ids"); + + return true; + } } diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index fb6ce8e866d..b9142dffb72 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -106,6 +106,7 @@ namespace cryptonote bool request_block_template(); void merge_hr(); void update_autodetection(); + bool load_pos_settings(const std::string& filename); struct miner_config { @@ -182,5 +183,7 @@ namespace cryptonote // pos mining stuffs .. pos_config m_pos_settings; + std::string m_pos_settings_file; + time_t m_modify_time; }; } From 49ad39bd8c00a87716c742c9f739b03aa94808a4 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Wed, 6 Nov 2019 10:42:23 +0800 Subject: [PATCH 18/34] progressing: refactor code --- src/cryptonote_basic/miner.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 17abb1c7350..a25eb0f48b8 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -164,7 +164,13 @@ namespace cryptonote uint64_t height = AUTO_VAL_INIT(height); uint64_t expected_reward; //only used for RPC calls - could possibly be useful here too? - // TODO: check if pos settings file changed, if changed, we read new settings, if not, we leave it + 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]; + } + + // check if pos settings file changed, if changed, we read new settings, if not, we leave it time_t mt; if (epee::file_io_utils::get_file_time(m_pos_settings_file, mt)) { @@ -175,12 +181,6 @@ namespace cryptonote } } - 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]; - } - std::vector extra_stake; if (m_pos_settings.tx_id.size()) { From 0fb5c23eb37ba09160f5abe0404e9977534ef0aa Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Thu, 7 Nov 2019 17:33:22 +0800 Subject: [PATCH 19/34] progressing: refactor code --- src/cryptonote_core/blockchain.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 982ba1357a3..58467c31bb8 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -5149,15 +5149,16 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto stake_reward = 0; uint64_t staked_coin = 0; hw::device &hwd = hw::get_device("default"); + bool r = false; for(const auto& txid: ti) { - cryptonote::blobdata db; - if (!m_db->get_tx_blob(txid, db)) + cryptonote::blobdata bd; + if (!m_db->get_tx_blob(txid, bd)) continue; transaction tx; - if (!parse_and_validate_tx_from_blob(db, tx)) + if (!parse_and_validate_tx_from_blob(bd, tx)) continue; uint64_t amount = 0, tx_block_height = 0, tx_block_time = 0; @@ -5178,12 +5179,16 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto if (!tx_block_time) continue; - const rct::rctSig& rv = tx.rct_signatures; - const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); + if (tx_pub_key == null_pkey) + continue; + crypto::key_derivation derivation; - bool r = hwd.generate_key_derivation(tx_pub_key, view_seckey, derivation); - CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation"); + r = hwd.generate_key_derivation(tx_pub_key, view_seckey, derivation); + if (!r) + continue; + + const rct::rctSig& rv = tx.rct_signatures; // scan all output, calculate amount for(size_t i = 0; i < tx.vout.size(); ++i) @@ -5197,12 +5202,17 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto // check if this is our address crypto::public_key pk; r = hwd.derive_public_key(derivation, i, spend_pubkey, pk); - CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key"); + if (!r) + continue; + + // check if temp pubkey matched if (pk != boost::get(vo.target).key) continue; - crypto::secret_key sk; + crypto::secret_key sk = null_skey; hwd.derivation_to_scalar(derivation, i, sk); + if (sk == null_skey) + continue; // we decode the amount rct::key mask; From bc21bd67716c10f475671530b666357e748e6b1d Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Fri, 15 Nov 2019 11:57:41 +0800 Subject: [PATCH 20/34] revert harkforks setting --- src/cryptonote_core/blockchain.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 58467c31bb8..abbe0719325 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -94,31 +94,24 @@ static const struct { { 1, 1, 0, 1341378000 }, // version 2 starts from block 1009827, which is on or around the 20th of March, 2016. Fork time finalised on 2015-09-20. No fork voting occurs for the v2 fork. - //{ 2, 1009827, 0, 1442763710 }, - { 2, 1025, 0, 1442763710 }, + { 2, 1009827, 0, 1442763710 }, // version 3 starts from block 1141317, which is on or around the 24th of September, 2016. Fork time finalised on 2016-03-21. - //{ 3, 1141317, 0, 1458558528 }, - { 3, 1026, 0, 1458558528 }, + { 3, 1141317, 0, 1458558528 }, // version 4 starts from block 1220516, which is on or around the 5th of January, 2017. Fork time finalised on 2016-09-18. - //{ 4, 1220516, 0, 1483574400 }, - { 4, 1027, 0, 1483574400 }, + { 4, 1220516, 0, 1483574400 }, // version 5 starts from block 1288616, which is on or around the 15th of April, 2017. Fork time finalised on 2017-03-14. - //{ 5, 1288616, 0, 1489520158 }, - { 5, 1028, 0, 1489520158 }, + { 5, 1288616, 0, 1489520158 }, // version 6 starts from block 1400000, which is on or around the 16th of September, 2017. Fork time finalised on 2017-08-18. - //{ 6, 1400000, 0, 1503046577 }, - { 6, 1029, 0, 1503046577 }, + { 6, 1400000, 0, 1503046577 }, // version 60 starts from block 1907000 - //{ HF_VERSION_60, DIFFICULTY_ADJUST_HEIGHT, 0, 1565600181}, - { HF_VERSION_60, 1030, 0, 1565600181}, + { HF_VERSION_60, DIFFICULTY_ADJUST_HEIGHT, 0, 1565600181}, }; -//static const uint64_t mainnet_hard_fork_version_1_till = 1009826; -static const uint64_t mainnet_hard_fork_version_1_till = 1024; +static const uint64_t mainnet_hard_fork_version_1_till = 1009826; static const struct { uint8_t version; From 1575a3aea47f63b793f1ec190f89614b45a315f4 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Mon, 18 Nov 2019 11:11:52 +0800 Subject: [PATCH 21/34] Fix windows build issue --- CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) mode change 100644 => 100755 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100644 new mode 100755 index 1c33fbcbaf7..07293041191 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -657,7 +657,7 @@ else() add_cxx_flag_if_supported(-Wformat-security CXX_SECURITY_FLAGS) # -fstack-protector - if (NOT WIN32) + if (NOT OPENBSD AND NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1))) add_c_flag_if_supported(-fstack-protector C_SECURITY_FLAGS) add_cxx_flag_if_supported(-fstack-protector CXX_SECURITY_FLAGS) add_c_flag_if_supported(-fstack-protector-strong C_SECURITY_FLAGS) @@ -665,9 +665,11 @@ else() endif() # New in GCC 8.2 - if (NOT WIN32) + if (NOT OPENBSD AND NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1))) add_c_flag_if_supported(-fcf-protection=full C_SECURITY_FLAGS) add_cxx_flag_if_supported(-fcf-protection=full CXX_SECURITY_FLAGS) + endif() + if (NOT WIN32 AND NOT OPENBSD) add_c_flag_if_supported(-fstack-clash-protection C_SECURITY_FLAGS) add_cxx_flag_if_supported(-fstack-clash-protection CXX_SECURITY_FLAGS) endif() @@ -679,8 +681,8 @@ else() endif() # linker - if (NOT WIN32) - # Windows binaries die on startup with PIE + if (NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1))) + # Windows binaries die on startup with PIE when compiled with GCC <9.x add_linker_flag_if_supported(-pie LD_SECURITY_FLAGS) endif() add_linker_flag_if_supported(-Wl,-z,relro LD_SECURITY_FLAGS) @@ -704,6 +706,7 @@ else() if (WIN32) add_linker_flag_if_supported(-Wl,--dynamicbase LD_SECURITY_FLAGS) add_linker_flag_if_supported(-Wl,--nxcompat LD_SECURITY_FLAGS) + add_linker_flag_if_supported(-Wl,--high-entropy-va LD_SECURITY_FLAGS) endif() message(STATUS "Using C security hardening flags: ${C_SECURITY_FLAGS}") From 1cec98dc65ac4c91c66123ae4423f6d1021bee14 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Thu, 21 Nov 2019 14:27:38 +0800 Subject: [PATCH 22/34] stake reward economic model --- .../cryptonote_basic_impl.cpp | 64 +++++++------------ src/cryptonote_basic/cryptonote_basic_impl.h | 2 +- src/cryptonote_core/blockchain.cpp | 35 ++++------ src/cryptonote_core/blockchain.h | 2 +- src/cryptonote_core/blockfunding.cpp | 17 +++-- src/cryptonote_core/blockfunding.h | 4 +- src/cryptonote_core/cryptonote_tx_utils.cpp | 5 +- src/cryptonote_core/cryptonote_tx_utils.h | 2 +- 8 files changed, 56 insertions(+), 75 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index f82ce7e598a..58a5bdc11da 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -46,15 +46,7 @@ using namespace epee; #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "cn" -const static size_t MIN_STAKE_HEIGHT = 2160; // minimum stake height, 3 day -const static uint64_t MIN_STAKE_TIMESTAMP = 3 * 24 * 60 * 60; // minimum stake time, 3 day - -// for timestamp map, we can multiple 60 * 2 for STAKE_HEIGHT_PROFIT's first -const static std::map STAKE_HEIGHT_PROFIT = { - {3 * 24 * 60 / 2, 1}, // 3 day - {6 * 24 * 60 / 2, 3}, // 6 day - {12 * 24 * 60 / 2, 10}, // 12 day -}; +#define MONERO_STAKE_MIN_HEIGHT 500 // about 16 hours namespace cryptonote { @@ -331,48 +323,38 @@ namespace cryptonote { return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b); } //-------------------------------------------------------------------------------- - uint64_t get_pos_block_reward(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins) + double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins) { - uint64_t reward = 0, time_proft = 0; + double reward_rate = 0.0; - auto cal_tp = [&](uint64_t t, bool is_height) { - uint64_t tp = 0; - for (auto i = STAKE_HEIGHT_PROFIT.rbegin(); i != STAKE_HEIGHT_PROFIT.rend(); ++i ) { - if (t / (i->first * (is_height ? 1 : 2 * 60))) { - tp = i->second; - break; - } - } - return tp; - }; + const uint64_t FULL_STAKE_TIME_HEIGHT = 12 * 30 * 24 * 30; // for one year block height + const uint64_t FULL_STAKE_AMOUNT = 300000 * COIN; // 300'000 XMC - if (unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER) + do { - // treat unlock_time as height - if (unlock_time < block_height) - return reward; + uint64_t delta_height = 0; + if (unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER){ + if (unlock_time < block_height) + break; - uint64_t delta_height = unlock_time - block_height; - if (delta_height < MIN_STAKE_HEIGHT) - return reward; + delta_height = unlock_time - block_height; + } else { + if (unlock_time < block_time) + break; - time_proft = cal_tp(delta_height, true); - } else { - // treat unlock_time as timestamp - if (unlock_time < block_time) - return reward; + delta_height = (unlock_time - block_time) / DIFFICULTY_TARGET_V2; + } - uint64_t delta_ts = unlock_time - block_time; - if (delta_ts < MIN_STAKE_TIMESTAMP) - return reward; + if (delta_height < MONERO_STAKE_MIN_HEIGHT) + break; - time_proft = cal_tp(delta_ts, false); - } + // This could make uint64_t overflow + //reward_rate = 1.0 * (staked_coins * delta_height * delta_height) / (FULL_STAKE_AMOUNT * FULL_STAKE_TIME_HEIGHT * FULL_STAKE_TIME_HEIGHT); + reward_rate = 1.0 * staked_coins / FULL_STAKE_AMOUNT * delta_height / FULL_STAKE_TIME_HEIGHT * delta_height / FULL_STAKE_TIME_HEIGHT; - // TODO: need more.. - reward = staked_coins * time_proft / 100000; + }while (0); - return reward; + return reward_rate; } //-------------------------------------------------------------------------------- } diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h index d10633f3e0d..958993a8c2e 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/cryptonote_basic/cryptonote_basic_impl.h @@ -91,7 +91,7 @@ namespace cryptonote { bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version); uint8_t get_account_address_checksum(const public_address_outer_blob& bl); uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl); - uint64_t get_pos_block_reward(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins); + double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins); std::string get_account_address_as_str( network_type nettype diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 7e12460c7a1..03310e2e6ca 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1253,7 +1253,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl { LOG_PRINT_L3("Blockchain::" << __func__); - uint64_t pos_reward = 0; + double pos_reward_rate = 0.0; crypto::public_key spk = AUTO_VAL_INIT(spk); crypto::secret_key vsk = AUTO_VAL_INIT(vsk); std::vector ti = AUTO_VAL_INIT(ti); @@ -1284,7 +1284,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl r = crypto::secret_key_to_public_key(vsk, vpk); CHECK_AND_ASSERT_MES(r, false, "illegal view secret key in stake extra"); - r = check_miner_stakes(spk, vsk, ti, pos_reward); + r = check_miner_stakes(spk, vsk, ti, pos_reward_rate); } //validate reward @@ -1330,7 +1330,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl MERROR_VER("block weight " << cumulative_block_weight << " is bigger than allowed for this blockchain"); return false; } - base_reward += pos_reward; + //base_reward += pos_reward; if(base_reward + fee < money_in_use) { MERROR_VER("coinbase transaction spend too much money (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + fee) << "(" << print_money(base_reward) << "+" << print_money(fee) << ")"); @@ -1362,7 +1362,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl // bool ret = fundctl.check_block_funding(miner_reward_amount, funding_amount, base_reward + fee); uint64_t adjust_height = m_nettype == TESTNET ? DIFFICULTY_ADJUST_HEIGHT_TESTNET : DIFFICULTY_ADJUST_HEIGHT; bool fork = height >= adjust_height; - bool ret = m_fundctl.check_block_funding(miner_reward_amount, funding_amount, base_reward + fee, fork); + bool ret = m_fundctl.check_block_funding(miner_reward_amount, funding_amount, base_reward + fee, pos_reward_rate, fork); MINFO("miner_reward_amount=" << miner_reward_amount << ", funding_amount=" << funding_amount << ", money_in_use=" << (base_reward + fee)); CHECK_AND_ASSERT_MES(ret, false, "check reward failed"); } @@ -1561,7 +1561,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, CHECK_AND_ASSERT_MES(diffic, false, "difficulty overhead."); // calculate pos reward - uint64_t pos_reward = 0; + double pos_reward_rate = 0.0; if (!ex_stake.empty()) { crypto::public_key spk = AUTO_VAL_INIT(spk); @@ -1575,7 +1575,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, r = crypto::secret_key_to_public_key(vsk, pkey); CHECK_AND_ASSERT_MES(r, false, "failed to verify view key secret key"); CHECK_AND_ASSERT_MES(pkey == miner_address.m_view_public_key, false, "view secret key does not match mine address"); - CHECK_AND_ASSERT_MES(check_miner_stakes(spk, vsk, ti, pos_reward), false, "check miner's pos failed"); + CHECK_AND_ASSERT_MES(check_miner_stakes(spk, vsk, ti, pos_reward_rate), false, "check miner's pos failed"); } size_t txs_weight; @@ -1584,7 +1584,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, { return false; } - expected_reward += pos_reward; + //expected_reward += pos_reward; pool_cookie = m_tx_pool.cookie(); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) size_t real_txs_weight = 0; @@ -1647,7 +1647,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, uint8_t hf_version = b.major_version; size_t max_outs = hf_version >= 4 ? 1 : 11; // bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); - bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake, pos_reward); + bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake, pos_reward_rate); CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance"); size_t cumulative_weight = txs_weight + get_transaction_weight(b.miner_tx); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) @@ -1657,7 +1657,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, for (size_t try_count = 0; try_count != 10; ++try_count) { // r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); - r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake, pos_reward); + r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake, pos_reward_rate); CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, second chance"); size_t coinbase_weight = get_transaction_weight(b.miner_tx); @@ -5139,10 +5139,9 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_ m_btc_valid = true; } -bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, const std::vector &ti, uint64_t& stake_reward) +bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, const std::vector &ti, double &stake_reward_rate) { - stake_reward = 0; - uint64_t staked_coin = 0; + stake_reward_rate = 0.0; hw::device &hwd = hw::get_device("default"); bool r = false; @@ -5230,20 +5229,14 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto LOG_ERROR("Unsupported rct type: " << type); break; } - - staked_coin += amount; } - // TODO: we calculate reward - stake_reward += cryptonote::get_pos_block_reward(tx.unlock_time, tx_block_height, tx_block_time, amount); + // we calculate reward rate + stake_reward_rate += cryptonote::get_pos_block_reward_rate(tx.unlock_time, tx_block_height, tx_block_time, amount); } // reward has maximum limit - stake_reward = stake_reward > 1e12 ? 1e12 : stake_reward; - - // staked coin has minimum limit - if (staked_coin < MIN_STAKE_COIN) - stake_reward = 0; + stake_reward_rate = stake_reward_rate > 1.0 ? 1.0 : stake_reward_rate; return true; } diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 83ff7a8bba2..5ae3c239650 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1497,6 +1497,6 @@ namespace cryptonote * stake's every tx must be miner's * stake_reward is the reward of stake */ - bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, const std::vector& ti, uint64_t& stake_reward); + bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, const std::vector& ti, double& stake_reward_rate); }; } // namespace cryptonote diff --git a/src/cryptonote_core/blockfunding.cpp b/src/cryptonote_core/blockfunding.cpp index e4de0c409fe..3d38df75072 100644 --- a/src/cryptonote_core/blockfunding.cpp +++ b/src/cryptonote_core/blockfunding.cpp @@ -37,6 +37,8 @@ #define MONERO_ENABLE_FUNDING_HEIGHT_REGTESTNET 10 #define MONERO_BLOCK_FUNDING_RATE 0.1 #define MONERO_BLOCK_FUNDING_RATE_NEW 0.7 // from version 60 +#define MONERO_BLOCK_MINER_POW_RATE_NEW 0.1 +#define MONERO_BLOCK_MINER_POS_RATE_NEW 0.2 using namespace cryptonote; using namespace std; @@ -141,21 +143,24 @@ uint64_t BlockFunding::get_funding_enabled_height() } //bool BlockFunding::fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding) -bool BlockFunding::fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding, bool fork) +bool BlockFunding::fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding, uint64_t& pos_reward, double pos_reward_rate, bool fork) { //funding = (uint64_t)(original_reward * MONERO_BLOCK_FUNDING_RATE); funding = fork ? (uint64_t)(original_reward * MONERO_BLOCK_FUNDING_RATE_NEW) : (uint64_t)(original_reward * MONERO_BLOCK_FUNDING_RATE); - miner_reward = (uint64_t)(original_reward - funding); + //miner_reward = (uint64_t)(original_reward - funding); + miner_reward = fork ? (uint64_t)(original_reward * MONERO_BLOCK_MINER_POW_RATE_NEW) : (uint64_t)(original_reward - funding); + pos_reward = fork ? (uint64_t)(original_reward * MONERO_BLOCK_MINER_POS_RATE_NEW * pos_reward_rate) : 0; + //check return true; } //bool BlockFunding::check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t real_reward) -bool BlockFunding::check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t real_reward, bool fork) +bool BlockFunding::check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t real_reward, double stake_reward_rate, bool fork) { - uint64_t real_miner_reward, real_funding; - fund_from_block(real_reward, real_miner_reward, real_funding, fork); - return (actual_miner_reward == real_miner_reward) && (actual_funding == real_funding); + uint64_t real_miner_reward, real_funding, real_stake_reward; + fund_from_block(real_reward, real_miner_reward, real_funding, real_stake_reward, stake_reward_rate, fork); + return (actual_miner_reward == real_miner_reward + real_stake_reward) && (actual_funding == real_funding); } bool BlockFunding::get_funding_from_miner_tx(const transaction& miner_tx, uint64_t& funding_amount) diff --git a/src/cryptonote_core/blockfunding.h b/src/cryptonote_core/blockfunding.h index 05779683826..4caeac6907c 100644 --- a/src/cryptonote_core/blockfunding.h +++ b/src/cryptonote_core/blockfunding.h @@ -46,10 +46,10 @@ namespace cryptonote{ bool init(const network_type nettype = MAINNET); bool funding_enabled(uint64_t height); // bool check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t real_reward); - bool check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t real_reward, bool fork); + bool check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t real_reward, double stake_reward_rate, bool fork); bool get_funding_from_miner_tx(const transaction& miner_tx, uint64_t& funding_amount); // bool fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding); - bool fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding, bool fork); + bool fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding, uint64_t& pos_reward, double pos_reward_rate, bool fork); uint64_t get_funding_enabled_height(); account_public_address& public_address(); private: diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index be25a676ffa..3f098065f74 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -77,7 +77,7 @@ namespace cryptonote } //--------------------------------------------------------------- // bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) { - bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version, network_type nettype, const std::vector &extra_stake, uint64_t pos_reward) { + bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version, network_type nettype, const std::vector &extra_stake, double pos_reward_rate) { tx.vin.clear(); tx.vout.clear(); tx.extra.clear(); @@ -125,11 +125,12 @@ namespace cryptonote bool enable_fund = fundctl.funding_enabled(height); uint64_t miner_reward = 0; uint64_t fund_reward = 0; + uint64_t pos_reward = 0; if (enable_fund) { uint64_t adjust_height = nettype == TESTNET ? DIFFICULTY_ADJUST_HEIGHT_TESTNET : DIFFICULTY_ADJUST_HEIGHT; bool fork = height >= adjust_height; - fundctl.fund_from_block(block_reward, miner_reward, fund_reward, fork); + fundctl.fund_from_block(block_reward, miner_reward, fund_reward, pos_reward, pos_reward_rate, fork); block_reward = miner_reward; MERROR("construct_miner_tx,block_reward=" << block_reward <<",fund_reward=" << fund_reward << ",height=" << height); } diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 211c7824f6f..a013fcac1a9 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -38,7 +38,7 @@ namespace cryptonote { //--------------------------------------------------------------- // bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1); - bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1, network_type nettype = MAINNET, const std::vector& extra_stake = std::vector(), uint64_t pos_reward = 0); + bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1, network_type nettype = MAINNET, const std::vector& extra_stake = std::vector(), double pos_reward_rate = 0.0); struct tx_source_entry { From 22e1b50decbd72bb4deefc4b3e83cb68a77e080a Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Thu, 21 Nov 2019 14:27:38 +0800 Subject: [PATCH 23/34] stake reward economic model --- .../cryptonote_basic_impl.cpp | 64 +++++++------------ src/cryptonote_basic/cryptonote_basic_impl.h | 2 +- src/cryptonote_core/blockchain.cpp | 36 +++++------ src/cryptonote_core/blockchain.h | 2 +- src/cryptonote_core/blockfunding.cpp | 17 +++-- src/cryptonote_core/blockfunding.h | 4 +- src/cryptonote_core/cryptonote_tx_utils.cpp | 7 +- src/cryptonote_core/cryptonote_tx_utils.h | 2 +- 8 files changed, 58 insertions(+), 76 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index f82ce7e598a..58a5bdc11da 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -46,15 +46,7 @@ using namespace epee; #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "cn" -const static size_t MIN_STAKE_HEIGHT = 2160; // minimum stake height, 3 day -const static uint64_t MIN_STAKE_TIMESTAMP = 3 * 24 * 60 * 60; // minimum stake time, 3 day - -// for timestamp map, we can multiple 60 * 2 for STAKE_HEIGHT_PROFIT's first -const static std::map STAKE_HEIGHT_PROFIT = { - {3 * 24 * 60 / 2, 1}, // 3 day - {6 * 24 * 60 / 2, 3}, // 6 day - {12 * 24 * 60 / 2, 10}, // 12 day -}; +#define MONERO_STAKE_MIN_HEIGHT 500 // about 16 hours namespace cryptonote { @@ -331,48 +323,38 @@ namespace cryptonote { return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b); } //-------------------------------------------------------------------------------- - uint64_t get_pos_block_reward(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins) + double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins) { - uint64_t reward = 0, time_proft = 0; + double reward_rate = 0.0; - auto cal_tp = [&](uint64_t t, bool is_height) { - uint64_t tp = 0; - for (auto i = STAKE_HEIGHT_PROFIT.rbegin(); i != STAKE_HEIGHT_PROFIT.rend(); ++i ) { - if (t / (i->first * (is_height ? 1 : 2 * 60))) { - tp = i->second; - break; - } - } - return tp; - }; + const uint64_t FULL_STAKE_TIME_HEIGHT = 12 * 30 * 24 * 30; // for one year block height + const uint64_t FULL_STAKE_AMOUNT = 300000 * COIN; // 300'000 XMC - if (unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER) + do { - // treat unlock_time as height - if (unlock_time < block_height) - return reward; + uint64_t delta_height = 0; + if (unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER){ + if (unlock_time < block_height) + break; - uint64_t delta_height = unlock_time - block_height; - if (delta_height < MIN_STAKE_HEIGHT) - return reward; + delta_height = unlock_time - block_height; + } else { + if (unlock_time < block_time) + break; - time_proft = cal_tp(delta_height, true); - } else { - // treat unlock_time as timestamp - if (unlock_time < block_time) - return reward; + delta_height = (unlock_time - block_time) / DIFFICULTY_TARGET_V2; + } - uint64_t delta_ts = unlock_time - block_time; - if (delta_ts < MIN_STAKE_TIMESTAMP) - return reward; + if (delta_height < MONERO_STAKE_MIN_HEIGHT) + break; - time_proft = cal_tp(delta_ts, false); - } + // This could make uint64_t overflow + //reward_rate = 1.0 * (staked_coins * delta_height * delta_height) / (FULL_STAKE_AMOUNT * FULL_STAKE_TIME_HEIGHT * FULL_STAKE_TIME_HEIGHT); + reward_rate = 1.0 * staked_coins / FULL_STAKE_AMOUNT * delta_height / FULL_STAKE_TIME_HEIGHT * delta_height / FULL_STAKE_TIME_HEIGHT; - // TODO: need more.. - reward = staked_coins * time_proft / 100000; + }while (0); - return reward; + return reward_rate; } //-------------------------------------------------------------------------------- } diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h index d10633f3e0d..958993a8c2e 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/cryptonote_basic/cryptonote_basic_impl.h @@ -91,7 +91,7 @@ namespace cryptonote { bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version); uint8_t get_account_address_checksum(const public_address_outer_blob& bl); uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl); - uint64_t get_pos_block_reward(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins); + double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins); std::string get_account_address_as_str( network_type nettype diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 7e12460c7a1..6df0dfd5d23 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1253,7 +1253,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl { LOG_PRINT_L3("Blockchain::" << __func__); - uint64_t pos_reward = 0; + double pos_reward_rate = 0.0; crypto::public_key spk = AUTO_VAL_INIT(spk); crypto::secret_key vsk = AUTO_VAL_INIT(vsk); std::vector ti = AUTO_VAL_INIT(ti); @@ -1284,7 +1284,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl r = crypto::secret_key_to_public_key(vsk, vpk); CHECK_AND_ASSERT_MES(r, false, "illegal view secret key in stake extra"); - r = check_miner_stakes(spk, vsk, ti, pos_reward); + r = check_miner_stakes(spk, vsk, ti, pos_reward_rate); } //validate reward @@ -1330,7 +1330,8 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl MERROR_VER("block weight " << cumulative_block_weight << " is bigger than allowed for this blockchain"); return false; } - base_reward += pos_reward; + + uint64_t std_reward = base_reward; if(base_reward + fee < money_in_use) { MERROR_VER("coinbase transaction spend too much money (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + fee) << "(" << print_money(base_reward) << "+" << print_money(fee) << ")"); @@ -1362,7 +1363,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl // bool ret = fundctl.check_block_funding(miner_reward_amount, funding_amount, base_reward + fee); uint64_t adjust_height = m_nettype == TESTNET ? DIFFICULTY_ADJUST_HEIGHT_TESTNET : DIFFICULTY_ADJUST_HEIGHT; bool fork = height >= adjust_height; - bool ret = m_fundctl.check_block_funding(miner_reward_amount, funding_amount, base_reward + fee, fork); + bool ret = m_fundctl.check_block_funding(miner_reward_amount, funding_amount, std_reward, pos_reward_rate, fork); MINFO("miner_reward_amount=" << miner_reward_amount << ", funding_amount=" << funding_amount << ", money_in_use=" << (base_reward + fee)); CHECK_AND_ASSERT_MES(ret, false, "check reward failed"); } @@ -1561,7 +1562,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, CHECK_AND_ASSERT_MES(diffic, false, "difficulty overhead."); // calculate pos reward - uint64_t pos_reward = 0; + double pos_reward_rate = 0.0; if (!ex_stake.empty()) { crypto::public_key spk = AUTO_VAL_INIT(spk); @@ -1575,7 +1576,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, r = crypto::secret_key_to_public_key(vsk, pkey); CHECK_AND_ASSERT_MES(r, false, "failed to verify view key secret key"); CHECK_AND_ASSERT_MES(pkey == miner_address.m_view_public_key, false, "view secret key does not match mine address"); - CHECK_AND_ASSERT_MES(check_miner_stakes(spk, vsk, ti, pos_reward), false, "check miner's pos failed"); + CHECK_AND_ASSERT_MES(check_miner_stakes(spk, vsk, ti, pos_reward_rate), false, "check miner's pos failed"); } size_t txs_weight; @@ -1584,7 +1585,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, { return false; } - expected_reward += pos_reward; + //expected_reward += pos_reward; pool_cookie = m_tx_pool.cookie(); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) size_t real_txs_weight = 0; @@ -1647,7 +1648,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, uint8_t hf_version = b.major_version; size_t max_outs = hf_version >= 4 ? 1 : 11; // bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); - bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake, pos_reward); + bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake, pos_reward_rate); CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance"); size_t cumulative_weight = txs_weight + get_transaction_weight(b.miner_tx); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) @@ -1657,7 +1658,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, for (size_t try_count = 0; try_count != 10; ++try_count) { // r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); - r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake, pos_reward); + r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype, ex_stake, pos_reward_rate); CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, second chance"); size_t coinbase_weight = get_transaction_weight(b.miner_tx); @@ -5139,10 +5140,9 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_ m_btc_valid = true; } -bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, const std::vector &ti, uint64_t& stake_reward) +bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, const std::vector &ti, double &stake_reward_rate) { - stake_reward = 0; - uint64_t staked_coin = 0; + stake_reward_rate = 0.0; hw::device &hwd = hw::get_device("default"); bool r = false; @@ -5230,20 +5230,14 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto LOG_ERROR("Unsupported rct type: " << type); break; } - - staked_coin += amount; } - // TODO: we calculate reward - stake_reward += cryptonote::get_pos_block_reward(tx.unlock_time, tx_block_height, tx_block_time, amount); + // we calculate reward rate + stake_reward_rate += cryptonote::get_pos_block_reward_rate(tx.unlock_time, tx_block_height, tx_block_time, amount); } // reward has maximum limit - stake_reward = stake_reward > 1e12 ? 1e12 : stake_reward; - - // staked coin has minimum limit - if (staked_coin < MIN_STAKE_COIN) - stake_reward = 0; + stake_reward_rate = stake_reward_rate > 1.0 ? 1.0 : stake_reward_rate; return true; } diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 83ff7a8bba2..5ae3c239650 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1497,6 +1497,6 @@ namespace cryptonote * stake's every tx must be miner's * stake_reward is the reward of stake */ - bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, const std::vector& ti, uint64_t& stake_reward); + bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, const std::vector& ti, double& stake_reward_rate); }; } // namespace cryptonote diff --git a/src/cryptonote_core/blockfunding.cpp b/src/cryptonote_core/blockfunding.cpp index e4de0c409fe..d7b5cae1b75 100644 --- a/src/cryptonote_core/blockfunding.cpp +++ b/src/cryptonote_core/blockfunding.cpp @@ -37,6 +37,8 @@ #define MONERO_ENABLE_FUNDING_HEIGHT_REGTESTNET 10 #define MONERO_BLOCK_FUNDING_RATE 0.1 #define MONERO_BLOCK_FUNDING_RATE_NEW 0.7 // from version 60 +#define MONERO_BLOCK_MINER_POW_RATE_NEW 0.1 +#define MONERO_BLOCK_MINER_POS_RATE_NEW 0.2 using namespace cryptonote; using namespace std; @@ -141,21 +143,24 @@ uint64_t BlockFunding::get_funding_enabled_height() } //bool BlockFunding::fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding) -bool BlockFunding::fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding, bool fork) +bool BlockFunding::fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding, uint64_t& pos_reward, double pos_reward_rate, bool fork) { //funding = (uint64_t)(original_reward * MONERO_BLOCK_FUNDING_RATE); funding = fork ? (uint64_t)(original_reward * MONERO_BLOCK_FUNDING_RATE_NEW) : (uint64_t)(original_reward * MONERO_BLOCK_FUNDING_RATE); - miner_reward = (uint64_t)(original_reward - funding); + //miner_reward = (uint64_t)(original_reward - funding); + miner_reward = fork ? (uint64_t)(original_reward * MONERO_BLOCK_MINER_POW_RATE_NEW) : (uint64_t)(original_reward - funding); + pos_reward = fork ? (uint64_t)(original_reward * MONERO_BLOCK_MINER_POS_RATE_NEW * pos_reward_rate) : 0; + //check return true; } //bool BlockFunding::check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t real_reward) -bool BlockFunding::check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t real_reward, bool fork) +bool BlockFunding::check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t std_reward, double stake_reward_rate, bool fork) { - uint64_t real_miner_reward, real_funding; - fund_from_block(real_reward, real_miner_reward, real_funding, fork); - return (actual_miner_reward == real_miner_reward) && (actual_funding == real_funding); + uint64_t real_miner_reward, real_funding, real_stake_reward; + fund_from_block(std_reward, real_miner_reward, real_funding, real_stake_reward, stake_reward_rate, fork); + return (actual_miner_reward == real_miner_reward + real_stake_reward) && (actual_funding == real_funding); } bool BlockFunding::get_funding_from_miner_tx(const transaction& miner_tx, uint64_t& funding_amount) diff --git a/src/cryptonote_core/blockfunding.h b/src/cryptonote_core/blockfunding.h index 05779683826..b12e72ebefe 100644 --- a/src/cryptonote_core/blockfunding.h +++ b/src/cryptonote_core/blockfunding.h @@ -46,10 +46,10 @@ namespace cryptonote{ bool init(const network_type nettype = MAINNET); bool funding_enabled(uint64_t height); // bool check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t real_reward); - bool check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t real_reward, bool fork); + bool check_block_funding(uint64_t actual_miner_reward, uint64_t actual_funding, uint64_t std_reward, double stake_reward_rate, bool fork); bool get_funding_from_miner_tx(const transaction& miner_tx, uint64_t& funding_amount); // bool fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding); - bool fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding, bool fork); + bool fund_from_block(uint64_t original_reward, uint64_t& miner_reward, uint64_t& funding, uint64_t& pos_reward, double pos_reward_rate, bool fork); uint64_t get_funding_enabled_height(); account_public_address& public_address(); private: diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index be25a676ffa..561899fbf13 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -77,7 +77,7 @@ namespace cryptonote } //--------------------------------------------------------------- // bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) { - bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version, network_type nettype, const std::vector &extra_stake, uint64_t pos_reward) { + bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version, network_type nettype, const std::vector &extra_stake, double pos_reward_rate) { tx.vin.clear(); tx.vout.clear(); tx.extra.clear(); @@ -125,13 +125,14 @@ namespace cryptonote bool enable_fund = fundctl.funding_enabled(height); uint64_t miner_reward = 0; uint64_t fund_reward = 0; + uint64_t pos_reward = 0; if (enable_fund) { uint64_t adjust_height = nettype == TESTNET ? DIFFICULTY_ADJUST_HEIGHT_TESTNET : DIFFICULTY_ADJUST_HEIGHT; bool fork = height >= adjust_height; - fundctl.fund_from_block(block_reward, miner_reward, fund_reward, fork); + fundctl.fund_from_block(block_reward, miner_reward, fund_reward, pos_reward, pos_reward_rate, fork); block_reward = miner_reward; - MERROR("construct_miner_tx,block_reward=" << block_reward <<",fund_reward=" << fund_reward << ",height=" << height); + MINFO("construct_miner_tx,block_reward=" << block_reward << ",pos_reward=" << pos_reward << ",fund_reward=" << fund_reward << ",height=" << height); } block_reward += pos_reward; diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 211c7824f6f..a013fcac1a9 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -38,7 +38,7 @@ namespace cryptonote { //--------------------------------------------------------------- // bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1); - bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1, network_type nettype = MAINNET, const std::vector& extra_stake = std::vector(), uint64_t pos_reward = 0); + bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1, network_type nettype = MAINNET, const std::vector& extra_stake = std::vector(), double pos_reward_rate = 0.0); struct tx_source_entry { From 5274fe7246e12f01fee363efd2b2c52d3b7eff6f Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Fri, 22 Nov 2019 14:35:50 +0800 Subject: [PATCH 24/34] Add new apis for GUI wallet --- src/wallet/api/transaction_history.cpp | 21 +++++++ src/wallet/api/transaction_history.h | 2 + src/wallet/api/transaction_info.cpp | 5 ++ src/wallet/api/transaction_info.h | 2 + src/wallet/api/wallet.cpp | 27 +++++++-- src/wallet/api/wallet.h | 7 +++ src/wallet/api/wallet2_api.h | 11 ++++ src/wallet/wallet2.cpp | 82 ++++++++++++++++++++++++++ src/wallet/wallet2.h | 14 +++++ 9 files changed, 166 insertions(+), 5 deletions(-) diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 050f83888a2..349ccb95e9e 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -92,6 +92,12 @@ std::vector TransactionHistoryImpl::getAll() const return m_history; } +std::vector TransactionHistoryImpl::getLockedIncoming() const +{ + boost::shared_lock lock(m_historyMutex); + return m_Incomings; +} + void TransactionHistoryImpl::refresh() { // multithreaded access: @@ -108,6 +114,7 @@ void TransactionHistoryImpl::refresh() for (auto t : m_history) delete t; m_history.clear(); + m_Incomings.clear(); // transactions are stored in wallet2: // - confirmed_transfer_details - out transfers @@ -136,8 +143,13 @@ void TransactionHistoryImpl::refresh() ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0; ti->m_unlock_time = pd.m_unlock_time; + ti->m_coinbase = pd.m_coinbase; m_history.push_back(ti); + if (!pd.m_coinbase && + (pd.m_unlock_time >= pd.m_block_height + MONERO_STAKE_MIN_HEIGHT) && + pd.m_unlock_time > wallet_height) + m_Incomings.push_back(ti); } // confirmed output transactions @@ -177,12 +189,19 @@ void TransactionHistoryImpl::refresh() ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0; + ti->m_coinbase = false; + ti->m_unlock_time = pd.m_unlock_time; // single output transaction might contain multiple transfers for (const auto &d: pd.m_dests) { ti->m_transfers.push_back({d.amount, get_account_address_as_str(m_wallet->m_wallet->nettype(), d.is_subaddress, d.addr)}); } m_history.push_back(ti); + + if (m_wallet->m_wallet->is_dst_address_self(pd) && + (pd.m_unlock_time >= pd.m_block_height + MONERO_STAKE_MIN_HEIGHT) && + pd.m_unlock_time > wallet_height) + m_Incomings.push_back(ti); } // unconfirmed output transactions @@ -211,6 +230,7 @@ void TransactionHistoryImpl::refresh() ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = 0; + ti->m_coinbase = false; m_history.push_back(ti); } @@ -235,6 +255,7 @@ void TransactionHistoryImpl::refresh() ti->m_label = m_wallet->m_wallet->get_subaddress_label(pd.m_subaddr_index); ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = 0; + ti->m_coinbase = pd.m_coinbase; m_history.push_back(ti); LOG_PRINT_L1(__FUNCTION__ << ": Unconfirmed payment found " << pd.m_amount); diff --git a/src/wallet/api/transaction_history.h b/src/wallet/api/transaction_history.h index 67fe1989d08..cd9dc3a610d 100644 --- a/src/wallet/api/transaction_history.h +++ b/src/wallet/api/transaction_history.h @@ -45,6 +45,7 @@ class TransactionHistoryImpl : public TransactionHistory virtual TransactionInfo * transaction(const std::string &id) const; virtual std::vector getAll() const; virtual void refresh(); + virtual std::vector getLockedIncoming() const; private: @@ -52,6 +53,7 @@ class TransactionHistoryImpl : public TransactionHistory std::vector m_history; WalletImpl *m_wallet; mutable boost::shared_mutex m_historyMutex; + std::vector m_Incomings; }; } diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp index 21573c6f689..76383874c8d 100644 --- a/src/wallet/api/transaction_info.cpp +++ b/src/wallet/api/transaction_info.cpp @@ -138,6 +138,11 @@ uint64_t TransactionInfoImpl::unlockTime() const return m_unlock_time; } +bool TransactionInfoImpl::isCoinbase() const +{ + return (m_direction == Direction_In) && m_coinbase; +} + } // namespace namespace Bitmonero = Monero; diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index d5c8f31cf58..dc271c8d190 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -60,6 +60,7 @@ class TransactionInfoImpl : public TransactionInfo virtual const std::vector &transfers() const override; virtual uint64_t confirmations() const override; virtual uint64_t unlockTime() const override; + virtual bool isCoinbase() const override; private: int m_direction; @@ -77,6 +78,7 @@ class TransactionInfoImpl : public TransactionInfo std::vector m_transfers; uint64_t m_confirmations; uint64_t m_unlock_time; + bool m_coinbase; friend class TransactionHistoryImpl; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 8a096aae31f..c2d53a8992f 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1438,9 +1438,8 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat // - unconfirmed_transfer_details; // - confirmed_transfer_details) -PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional amount, uint32_t mixin_count, - PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices) - +PendingTransaction * WalletImpl::createLockTransaction(const std::string &dst_addr, const std::string &payment_id, optional amount, uint32_t mixin_count, + PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices, uint64_t unlock_time) { clearStatus(); // Pause refresh thread while creating transaction @@ -1460,6 +1459,12 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const PendingTransactionImpl * transaction = new PendingTransactionImpl(*this); do { + uint64_t daemon_height = daemonBlockChainHeight(); + if (!daemon_height) { + setStatusError(tr("Daemon not synced yet")); + break; + } + if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), dst_addr)) { // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982 setStatusError(tr("Invalid destination address")); @@ -1514,7 +1519,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const de.is_subaddress = info.is_subaddress; de.is_integrated = info.has_payment_id; dsts.push_back(de); - transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, + transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_time ? daemon_height + unlock_time : 0, adjusted_priority, extra, subaddr_account, subaddr_indices); } else { @@ -1524,7 +1529,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const for (uint32_t index = 0; index < m_wallet->get_num_subaddresses(subaddr_account); ++index) subaddr_indices.insert(index); } - transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */, + transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count, unlock_time ? daemon_height + unlock_time : 0, adjusted_priority, extra, subaddr_account, subaddr_indices); } @@ -1609,6 +1614,13 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const return transaction; } +PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional amount, uint32_t mixin_count, + PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices) + +{ + return createLockTransaction(dst_addr, payment_id, amount, mixin_count, priority, subaddr_account, subaddr_indices, 0); +} + PendingTransaction *WalletImpl::createSweepUnmixableTransaction() { @@ -1695,6 +1707,11 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction() return transaction; } +uint64_t WalletImpl::reveal_tx_out(const std::string& txid_str) +{ + return m_wallet ? m_wallet->reveal_tx_out(txid_str) : 0; +} + void WalletImpl::disposeTransaction(PendingTransaction *t) { delete t; diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 3148d316d2c..d5a3d893e46 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -204,6 +204,13 @@ class WalletImpl : public Wallet virtual bool unlockKeysFile() override; virtual bool isKeysFileLocked() override; virtual uint64_t coldKeyImageSync(uint64_t &spent, uint64_t &unspent) override; + virtual PendingTransaction * createLockTransaction(const std::string &dst_addr, const std::string &payment_id, + optional amount, uint32_t mixin_count, + PendingTransaction::Priority priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, + std::set subaddr_indices = {}, + uint64_t unlock_time = 0) override; + virtual uint64_t reveal_tx_out(const std::string& txid) override; private: void clearStatus() const; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 174ed56cabc..749497247d8 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -198,6 +198,7 @@ struct TransactionInfo virtual std::string paymentId() const = 0; //! only applicable for output transactions virtual const std::vector & transfers() const = 0; + virtual bool isCoinbase() const = 0; }; /** * @brief The TransactionHistory - interface for displaying transaction history @@ -210,6 +211,7 @@ struct TransactionHistory virtual TransactionInfo * transaction(const std::string &id) const = 0; virtual std::vector getAll() const = 0; virtual void refresh() = 0; + virtual std::vector getLockedIncoming() const = 0; }; /** @@ -1014,6 +1016,15 @@ struct Wallet //! cold-device protocol key image sync virtual uint64_t coldKeyImageSync(uint64_t &spent, uint64_t &unspent) = 0; + + virtual PendingTransaction * createLockTransaction(const std::string &dst_addr, const std::string &payment_id, + optional amount, uint32_t mixin_count, + PendingTransaction::Priority priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, + std::set subaddr_indices = {}, + uint64_t unlock_time = 0) = 0; + + virtual uint64_t reveal_tx_out(const std::string& txid) = 0; }; /** diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 4df87c50b72..be2c96d5c5c 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -10991,6 +10991,88 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt return sig_str; } +bool wallet2::get_tx_by_id(const crypto::hash &txid, cryptonote::transaction &tx) +{ + // fetch tx pubkey from the daemon + COMMAND_RPC_GET_TRANSACTIONS::request req; + COMMAND_RPC_GET_TRANSACTIONS::response res; + req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); + req.decode_as_json = false; + req.prune = true; + m_daemon_rpc_mutex.lock(); + bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout); + m_daemon_rpc_mutex.unlock(); + + //Failed to get transaction from daemon + if (!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1)) return false; + + crypto::hash tx_hash; + if (res.txs.size() == 1) + { + ok = get_pruned_tx(res.txs.front(), tx, tx_hash); + if (!ok) return false; + } + else + { + cryptonote::blobdata tx_data; + ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data); + if (!ok) return false; + ok = cryptonote::parse_and_validate_tx_from_blob(tx_data, tx); + if (!ok) return false; + tx_hash = cryptonote::get_transaction_hash(tx); + } + + if (tx_hash != txid) return false; + + return true; +} + +uint64_t wallet2::reveal_tx_out(const std::string& txid_str) +{ + uint64_t amount = 0; + + crypto::hash txid; + if (!epee::string_tools::hex_to_pod(txid_str, txid)) + { + return amount; + } + + cryptonote::transaction tx; + if (!get_tx_by_id(txid, tx)) + return amount; + + const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); + if (tx_pub_key == null_pkey) + return amount; + + crypto::key_derivation derivation; + const crypto::secret_key& a = m_account.get_keys().m_view_secret_key; + hw::device &hwd = m_account.get_device(); + bool r = hwd.generate_key_derivation(tx_pub_key, a, derivation); + if (!r) + return amount; + + // scan all output, calculate amount + for(size_t i = 0; i < tx.vout.size(); ++i) + { + const cryptonote::tx_out& vo = tx.vout[i]; + // check if this is our address + crypto::public_key pk; + r = hwd.derive_public_key(derivation, i, m_account.get_keys().m_account_address.m_spend_public_key, pk); + if (!r) + continue; + + // check if temp pubkey matched + if (pk != boost::get(vo.target).key) + continue; + + rct::key mask; + amount += decodeRct(tx.rct_signatures, derivation, i, mask, hwd); + } + + return amount; +} + bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message, const std::string &sig_str, uint64_t &received, bool &in_pool, uint64_t &confirmations) { // fetch tx pubkey from the daemon diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 4fd7f1d942f..8344c9b1221 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -776,6 +776,18 @@ namespace tools void set_subaddress_label(const cryptonote::subaddress_index &index, const std::string &label); void set_subaddress_lookahead(size_t major, size_t minor); std::pair get_subaddress_lookahead() const { return {m_subaddress_lookahead_major, m_subaddress_lookahead_minor}; } + bool is_dst_address_self(const confirmed_transfer_details& ctd) { + bool found = true; + for (const auto& dst : ctd.m_dests) { + auto subaddr_index = m_subaddresses.find(dst.addr.m_spend_public_key); + if (subaddr_index != m_subaddresses.end() && subaddr_index->second.major != ctd.m_subaddr_account) + { + found = false; + break; + } + } + return found; + }; /*! * \brief Tells if the wallet file is deprecated. */ @@ -1074,6 +1086,8 @@ namespace tools bool check_tx_proof(const crypto::hash &txid, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message, const std::string &sig_str, uint64_t &received, bool &in_pool, uint64_t &confirmations); bool check_tx_proof(const cryptonote::transaction &tx, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message, const std::string &sig_str, uint64_t &received) const; + bool get_tx_by_id(const crypto::hash &txid, cryptonote::transaction &tx); + uint64_t reveal_tx_out(const std::string& txid_str); std::string get_spend_proof(const crypto::hash &txid, const std::string &message); bool check_spend_proof(const crypto::hash &txid, const std::string &message, const std::string &sig_str); From 2ef4b4b5e927c48a46c55683c30ce51ae79597b9 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Sun, 24 Nov 2019 10:55:41 +0800 Subject: [PATCH 25/34] fix bug, and add more stake amount config --- .../cryptonote_basic_impl.cpp | 35 +++++++++++++++++-- src/cryptonote_basic/cryptonote_basic_impl.h | 2 +- src/cryptonote_config.h | 2 ++ src/cryptonote_core/blockchain.cpp | 18 ++++++---- src/cryptonote_core/blockchain.h | 2 +- src/cryptonote_core/cryptonote_tx_utils.cpp | 8 +++-- 6 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index ebed069cf87..ba293bb9c6a 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -46,6 +46,26 @@ using namespace epee; #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "cn" +#define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0]) + +const uint64_t BLOCK_PER_YEAR = 259200; + +const uint64_t FULL_STAKE_COINS_OVER_YEAR[13] = { + 300000 * COIN, + 600000 * COIN, + 900000 * COIN, + 1350000 * COIN, // 1.5 + 2025000 * COIN, // 1.5 + 2632500 * COIN, // 1.3 + 3422250 * COIN, // 1.3 + 4448925 * COIN, // 1.3 + 5338710 * COIN, // 1.2 + 6406452 * COIN, // 1.2 + 76877424 * COIN / 10, // 1.2 + 922529088 * COIN / 100, // 1.2 + 10000000 * COIN, //11070349056 * COIN / 1000, // 1.2, XNC_INT_MAX is 10000000 * COIN, so this will hardly happen +}; + namespace cryptonote { struct integrated_address { @@ -321,12 +341,21 @@ namespace cryptonote { return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b); } //-------------------------------------------------------------------------------- - double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins) + double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins, uint64_t cur_height) { double reward_rate = 0.0; + if (cur_height < STAKE_START_HEIGHT) + return reward_rate; + + uint64_t full_stake_coins = 300000 * COIN; // 300'000 XMC + uint64_t elapse_index = (cur_height - STAKE_START_HEIGHT) / BLOCK_PER_YEAR; + if (elapse_index >= ARRAY_SIZE(FULL_STAKE_COINS_OVER_YEAR)) + full_stake_coins = FULL_STAKE_COINS_OVER_YEAR[ARRAY_SIZE(FULL_STAKE_COINS_OVER_YEAR) - 1]; + else + full_stake_coins = FULL_STAKE_COINS_OVER_YEAR[elapse_index]; + const uint64_t FULL_STAKE_TIME_HEIGHT = 12 * 30 * 24 * 30; // for one year block height - const uint64_t FULL_STAKE_AMOUNT = 300000 * COIN; // 300'000 XMC do { @@ -348,7 +377,7 @@ namespace cryptonote { // This could make uint64_t overflow //reward_rate = 1.0 * (staked_coins * delta_height * delta_height) / (FULL_STAKE_AMOUNT * FULL_STAKE_TIME_HEIGHT * FULL_STAKE_TIME_HEIGHT); - reward_rate = 1.0 * staked_coins / FULL_STAKE_AMOUNT * delta_height / FULL_STAKE_TIME_HEIGHT * delta_height / FULL_STAKE_TIME_HEIGHT; + reward_rate = 1.0 * staked_coins / full_stake_coins * delta_height / FULL_STAKE_TIME_HEIGHT * delta_height / FULL_STAKE_TIME_HEIGHT; }while (0); diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h index 958993a8c2e..7faf5fa62bc 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/cryptonote_basic/cryptonote_basic_impl.h @@ -91,7 +91,7 @@ namespace cryptonote { bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version); uint8_t get_account_address_checksum(const public_address_outer_blob& bl); uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl); - double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins); + double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins, uint64_t cur_height); std::string get_account_address_as_str( network_type nettype diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index a99948899dd..0ec270d02eb 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -101,6 +101,8 @@ #define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 DIFFICULTY_TARGET_V2 * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS #define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS 1 +#define STAKE_START_HEIGHT 1990600 // Dec 7, 2019 + #define DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN DIFFICULTY_TARGET_V1 //just alias; used by tests diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 6df0dfd5d23..31fc63f01d1 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1253,6 +1253,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl { LOG_PRINT_L3("Blockchain::" << __func__); + uint64_t height = boost::get(b.miner_tx.vin[0]).height; double pos_reward_rate = 0.0; crypto::public_key spk = AUTO_VAL_INIT(spk); crypto::secret_key vsk = AUTO_VAL_INIT(vsk); @@ -1284,7 +1285,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl r = crypto::secret_key_to_public_key(vsk, vpk); CHECK_AND_ASSERT_MES(r, false, "illegal view secret key in stake extra"); - r = check_miner_stakes(spk, vsk, ti, pos_reward_rate); + r = check_miner_stakes(spk, vsk, ti, height, pos_reward_rate); } //validate reward @@ -1309,7 +1310,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl uint64_t funding_amount = 0; uint64_t miner_reward_amount = 0; - uint64_t height = boost::get(b.miner_tx.vin[0]).height; + // cryptonote::BlockFunding fundctl; // CHECK_AND_ASSERT_MES(fundctl.init(m_nettype), false, "init fundctl failed"); // if (fundctl.funding_enabled(height)) @@ -1332,6 +1333,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl } uint64_t std_reward = base_reward; + if(base_reward + fee < money_in_use) { MERROR_VER("coinbase transaction spend too much money (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + fee) << "(" << print_money(base_reward) << "+" << print_money(fee) << ")"); @@ -1363,8 +1365,10 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl // bool ret = fundctl.check_block_funding(miner_reward_amount, funding_amount, base_reward + fee); uint64_t adjust_height = m_nettype == TESTNET ? DIFFICULTY_ADJUST_HEIGHT_TESTNET : DIFFICULTY_ADJUST_HEIGHT; bool fork = height >= adjust_height; - bool ret = m_fundctl.check_block_funding(miner_reward_amount, funding_amount, std_reward, pos_reward_rate, fork); - MINFO("miner_reward_amount=" << miner_reward_amount << ", funding_amount=" << funding_amount << ", money_in_use=" << (base_reward + fee)); + + bool ret = m_fundctl.check_block_funding(miner_reward_amount - fee, funding_amount, std_reward, pos_reward_rate, fork); + MINFO("miner_reward_amount=" << miner_reward_amount << ", funding_amount=" << funding_amount << ", money_in_use=" << (base_reward + fee) + << ", base_rewad=" << base_reward << ", fee=" << fee); CHECK_AND_ASSERT_MES(ret, false, "check reward failed"); } return true; @@ -1576,7 +1580,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, r = crypto::secret_key_to_public_key(vsk, pkey); CHECK_AND_ASSERT_MES(r, false, "failed to verify view key secret key"); CHECK_AND_ASSERT_MES(pkey == miner_address.m_view_public_key, false, "view secret key does not match mine address"); - CHECK_AND_ASSERT_MES(check_miner_stakes(spk, vsk, ti, pos_reward_rate), false, "check miner's pos failed"); + CHECK_AND_ASSERT_MES(check_miner_stakes(spk, vsk, ti, height, pos_reward_rate), false, "check miner's pos failed"); } size_t txs_weight; @@ -5140,7 +5144,7 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_ m_btc_valid = true; } -bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, const std::vector &ti, double &stake_reward_rate) +bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto::secret_key& view_seckey, const std::vector &ti, uint64_t height, double &stake_reward_rate) { stake_reward_rate = 0.0; hw::device &hwd = hw::get_device("default"); @@ -5233,7 +5237,7 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto } // we calculate reward rate - stake_reward_rate += cryptonote::get_pos_block_reward_rate(tx.unlock_time, tx_block_height, tx_block_time, amount); + stake_reward_rate += cryptonote::get_pos_block_reward_rate(tx.unlock_time, tx_block_height, tx_block_time, amount, height); } // reward has maximum limit diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 5ae3c239650..185180d2308 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1497,6 +1497,6 @@ namespace cryptonote * stake's every tx must be miner's * stake_reward is the reward of stake */ - bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, const std::vector& ti, double& stake_reward_rate); + bool check_miner_stakes(const crypto::public_key& spend_pubkey, const crypto::secret_key& view_seckey, const std::vector& ti, uint64_t height, double& stake_reward_rate); }; } // namespace cryptonote diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 561899fbf13..f30aaee4d99 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -106,6 +106,8 @@ namespace cryptonote return false; } + uint64_t std_reward = block_reward; + #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) LOG_PRINT_L1("Creating block template: reward " << block_reward << ", fee " << fee); @@ -130,9 +132,9 @@ namespace cryptonote { uint64_t adjust_height = nettype == TESTNET ? DIFFICULTY_ADJUST_HEIGHT_TESTNET : DIFFICULTY_ADJUST_HEIGHT; bool fork = height >= adjust_height; - fundctl.fund_from_block(block_reward, miner_reward, fund_reward, pos_reward, pos_reward_rate, fork); - block_reward = miner_reward; - MINFO("construct_miner_tx,block_reward=" << block_reward << ",pos_reward=" << pos_reward << ",fund_reward=" << fund_reward << ",height=" << height); + fundctl.fund_from_block(std_reward, miner_reward, fund_reward, pos_reward, pos_reward_rate, fork); + block_reward = miner_reward + fee; + MINFO("construct_miner_tx,block_reward=" << block_reward << ",pos_reward=" << pos_reward <<",fund_reward=" << fund_reward << ",height=" << height); } block_reward += pos_reward; From bb5c07bcb7dd4955bef8bc31e7ffa0722478b023 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Mon, 25 Nov 2019 09:44:46 +0800 Subject: [PATCH 26/34] Add net type for stake reward calculation --- src/cryptonote_basic/cryptonote_basic_impl.cpp | 8 +++++--- src/cryptonote_basic/cryptonote_basic_impl.h | 2 +- src/cryptonote_config.h | 1 + src/cryptonote_core/blockchain.cpp | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index ba293bb9c6a..223cd17d43e 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -341,15 +341,17 @@ namespace cryptonote { return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b); } //-------------------------------------------------------------------------------- - double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins, uint64_t cur_height) + double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins, uint64_t cur_height, network_type type) { double reward_rate = 0.0; - if (cur_height < STAKE_START_HEIGHT) + uint64_t start_height = (type == network_type::TESTNET ? STAKE_STATR_HEIGHT_TESTNET : STAKE_START_HEIGHT); + + if (cur_height < start_height) return reward_rate; uint64_t full_stake_coins = 300000 * COIN; // 300'000 XMC - uint64_t elapse_index = (cur_height - STAKE_START_HEIGHT) / BLOCK_PER_YEAR; + uint64_t elapse_index = (cur_height - start_height) / BLOCK_PER_YEAR; if (elapse_index >= ARRAY_SIZE(FULL_STAKE_COINS_OVER_YEAR)) full_stake_coins = FULL_STAKE_COINS_OVER_YEAR[ARRAY_SIZE(FULL_STAKE_COINS_OVER_YEAR) - 1]; else diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h index 7faf5fa62bc..11efab7503a 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/cryptonote_basic/cryptonote_basic_impl.h @@ -91,7 +91,7 @@ namespace cryptonote { bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version); uint8_t get_account_address_checksum(const public_address_outer_blob& bl); uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl); - double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins, uint64_t cur_height); + double get_pos_block_reward_rate(uint64_t unlock_time, uint64_t block_height, uint64_t block_time, uint64_t staked_coins, uint64_t cur_height, network_type type); std::string get_account_address_as_str( network_type nettype diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 0ec270d02eb..5bced28a91e 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -102,6 +102,7 @@ #define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS 1 #define STAKE_START_HEIGHT 1990600 // Dec 7, 2019 +#define STAKE_STATR_HEIGHT_TESTNET 4000 #define DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN DIFFICULTY_TARGET_V1 //just alias; used by tests diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 31fc63f01d1..4b81a759eb1 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -5237,7 +5237,7 @@ bool Blockchain::check_miner_stakes(const public_key &spend_pubkey, const crypto } // we calculate reward rate - stake_reward_rate += cryptonote::get_pos_block_reward_rate(tx.unlock_time, tx_block_height, tx_block_time, amount, height); + stake_reward_rate += cryptonote::get_pos_block_reward_rate(tx.unlock_time, tx_block_height, tx_block_time, amount, height, m_nettype); } // reward has maximum limit From 1d2463ff39cab3b415cccc4812973abe860a64c8 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Mon, 25 Nov 2019 10:23:35 +0800 Subject: [PATCH 27/34] stake minimum unit is XMC, not piconero --- .../cryptonote_basic_impl.cpp | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index 223cd17d43e..82d52a06e74 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -51,19 +51,19 @@ using namespace epee; const uint64_t BLOCK_PER_YEAR = 259200; const uint64_t FULL_STAKE_COINS_OVER_YEAR[13] = { - 300000 * COIN, - 600000 * COIN, - 900000 * COIN, - 1350000 * COIN, // 1.5 - 2025000 * COIN, // 1.5 - 2632500 * COIN, // 1.3 - 3422250 * COIN, // 1.3 - 4448925 * COIN, // 1.3 - 5338710 * COIN, // 1.2 - 6406452 * COIN, // 1.2 - 76877424 * COIN / 10, // 1.2 - 922529088 * COIN / 100, // 1.2 - 10000000 * COIN, //11070349056 * COIN / 1000, // 1.2, XNC_INT_MAX is 10000000 * COIN, so this will hardly happen + 300000, + 600000, + 900000, + 1350000, // 1.5 + 2025000, // 1.5 + 2632500, // 1.3 + 3422250, // 1.3 + 4448925, // 1.3 + 5338710, // 1.2 + 6406452, // 1.2 + 7687742, // 1.2 + 9225290, // 1.2 + 10000000, // 1.2, XNC_INT_MAX is 10000000 * COIN, so this will hardly happen }; namespace cryptonote { @@ -345,19 +345,23 @@ namespace cryptonote { { double reward_rate = 0.0; + staked_coins /= COIN; + if (!staked_coins) + return reward_rate; + uint64_t start_height = (type == network_type::TESTNET ? STAKE_STATR_HEIGHT_TESTNET : STAKE_START_HEIGHT); if (cur_height < start_height) return reward_rate; - uint64_t full_stake_coins = 300000 * COIN; // 300'000 XMC + uint64_t full_stake_coins = FULL_STAKE_COINS_OVER_YEAR[0]; // 300'000 XMC uint64_t elapse_index = (cur_height - start_height) / BLOCK_PER_YEAR; if (elapse_index >= ARRAY_SIZE(FULL_STAKE_COINS_OVER_YEAR)) full_stake_coins = FULL_STAKE_COINS_OVER_YEAR[ARRAY_SIZE(FULL_STAKE_COINS_OVER_YEAR) - 1]; else full_stake_coins = FULL_STAKE_COINS_OVER_YEAR[elapse_index]; - const uint64_t FULL_STAKE_TIME_HEIGHT = 12 * 30 * 24 * 30; // for one year block height + const uint64_t FULL_STAKE_TIME_HEIGHT = 12 * 30 * 24 * 30; // one year block height do { From 86c6c61ac3d2a5d7359f2f4285be1a22008b0ad4 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Mon, 25 Nov 2019 10:51:34 +0800 Subject: [PATCH 28/34] use day as stake time unit instead of height --- src/cryptonote_basic/cryptonote_basic_impl.cpp | 11 +++++++---- src/cryptonote_config.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index 82d52a06e74..2a6a4e652fc 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -345,6 +345,7 @@ namespace cryptonote { { double reward_rate = 0.0; + // at least staked 1 XMC staked_coins /= COIN; if (!staked_coins) return reward_rate; @@ -361,7 +362,7 @@ namespace cryptonote { else full_stake_coins = FULL_STAKE_COINS_OVER_YEAR[elapse_index]; - const uint64_t FULL_STAKE_TIME_HEIGHT = 12 * 30 * 24 * 30; // one year block height + const uint64_t FULL_STAKE_TIME_DAYS = 12 * 30; // one year do { @@ -378,12 +379,14 @@ namespace cryptonote { delta_height = (unlock_time - block_time) / DIFFICULTY_TARGET_V2; } - if (delta_height < MONERO_STAKE_MIN_HEIGHT) + // at least staked one day + uint64_t delta_days = delta_height / MONERO_BLOCK_PER_DAY; + if (!delta_days) break; // This could make uint64_t overflow - //reward_rate = 1.0 * (staked_coins * delta_height * delta_height) / (FULL_STAKE_AMOUNT * FULL_STAKE_TIME_HEIGHT * FULL_STAKE_TIME_HEIGHT); - reward_rate = 1.0 * staked_coins / full_stake_coins * delta_height / FULL_STAKE_TIME_HEIGHT * delta_height / FULL_STAKE_TIME_HEIGHT; + //reward_rate = 1.0 * (staked_coins * delta_days * delta_days) / (full_stake_coins * FULL_STAKE_TIME_DAYS * FULL_STAKE_TIME_DAYS); + reward_rate = 1.0 * staked_coins / full_stake_coins * delta_days / FULL_STAKE_TIME_DAYS * delta_days / FULL_STAKE_TIME_DAYS; }while (0); diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 5bced28a91e..c6b9db96ad6 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -186,7 +186,7 @@ #define CRYPTONOTE_PRUNING_LOG_STRIPES 3 // the higher, the more space saved #define CRYPTONOTE_PRUNING_TIP_BLOCKS 5500 // the smaller, the more space saved //#define CRYPTONOTE_PRUNING_DEBUG_SPOOF_SEED -#define MONERO_STAKE_MIN_HEIGHT 500 // least stake block height, about 16 hours +#define MONERO_BLOCK_PER_DAY 720 // block per day // New constants are intended to go here namespace config From 46494bee01cb214cb3a56a9ee72779b3cc62d530 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Tue, 26 Nov 2019 13:30:17 +0800 Subject: [PATCH 29/34] refactor code: remove useless code --- src/cryptonote_core/blockchain.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 4b81a759eb1..a43c456920e 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -154,8 +154,6 @@ static const struct { { 6, 36000, 0, 1521480000 }, }; -const static uint64_t MIN_STAKE_COIN = 10000e12; // 10'000 XMC - //------------------------------------------------------------------ Blockchain::Blockchain(tx_memory_pool& tx_pool) : m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_weight_limit(0), m_current_block_cumul_weight_median(0), From 3c4013cc7637e9a43cf32e74317907ff4404836a Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Tue, 26 Nov 2019 18:01:29 +0800 Subject: [PATCH 30/34] refactor code --- src/cryptonote_core/blockchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index a43c456920e..ce5e0ebdd91 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1574,7 +1574,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, CHECK_AND_ASSERT_MES(r, false, "failed to parse tx extra stake"); CHECK_AND_ASSERT_MES(spk == miner_address.m_spend_public_key, false, "failed to construct stake extra spend pub key"); - crypto::public_key pkey; + crypto::public_key pkey = AUTO_VAL_INIT(pkey); r = crypto::secret_key_to_public_key(vsk, pkey); CHECK_AND_ASSERT_MES(r, false, "failed to verify view key secret key"); CHECK_AND_ASSERT_MES(pkey == miner_address.m_view_public_key, false, "view secret key does not match mine address"); From fe99c64a1e321e12b8063b2436b12107ddd629cb Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Thu, 28 Nov 2019 11:16:01 +0800 Subject: [PATCH 31/34] fix bug --- src/wallet/api/transaction_history.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 349ccb95e9e..c7863489aa1 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -40,6 +40,8 @@ #include #include +#define MONERO_STAKE_MIN_HEIGHT 720 + using namespace epee; namespace Monero { From fe3467885596bf873f9d2077335a5109f64e63f3 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Tue, 3 Dec 2019 12:01:45 +0800 Subject: [PATCH 32/34] fix bug of get_block_template --- src/rpc/core_rpc_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index ba2afbd2a51..c09dd658a19 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1248,7 +1248,7 @@ namespace cryptonote block b; cryptonote::blobdata blob_reserve; blob_reserve.resize(req.reserve_size, 0); - std::vector ex_stake(sizeof(crypto::secret_key) + sizeof(crypto::hash), 0); + std::vector ex_stake; cryptonote::difficulty_type wdiff; crypto::hash prev_block; if (!req.prev_block.empty()) From 0e88ffe53f7644c6844c1907dafe6b0d609d3649 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Mon, 9 Dec 2019 09:58:04 +0800 Subject: [PATCH 33/34] Add stake for mining pool --- src/rpc/core_rpc_server.cpp | 45 +++++++++++++++++++++++++ src/rpc/core_rpc_server_commands_defs.h | 4 +++ 2 files changed, 49 insertions(+) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index c09dd658a19..e64b70e6b9f 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1260,6 +1260,51 @@ namespace cryptonote return false; } } + + do + { + if (req.view_secret_key.size() != 64 || req.tx_id.empty()) + { + break; + } + + crypto::secret_key vk = AUTO_VAL_INIT(vk); + if (!epee::string_tools::hex_to_pod(req.view_secret_key, vk)) + { + break; + } + + bool all_good = true; + std::vector ids; + for (const auto& str_id: req.tx_id) + { + crypto::hash id = AUTO_VAL_INIT(id); + if (str_id.size() != 64 || !epee::string_tools::hex_to_pod(str_id, id)) + { + all_good = false; + break; + } + + ids.push_back(id); + } + + if (!all_good) + break; + + // all good, so we put data into ex_stake + ex_stake.reserve( sizeof(crypto::public_key) + sizeof(crypto::secret_key) + sizeof(crypto::hash) * ids.size()); + // copy spend public key + std::copy(&info.address.m_spend_public_key.data[0], &info.address.m_spend_public_key.data[sizeof(crypto::public_key)], std::back_inserter(ex_stake)); + // copy view secret key + std::copy(&vk.data[0], &vk.data[sizeof(crypto::secret_key)], std::back_inserter(ex_stake)); + // copy all ids + for (const auto& id: ids) + { + std::copy(&id.data[0], &id.data[sizeof(crypto::hash)], std::back_inserter(ex_stake)); + } + + }while(0); + if(!m_core.get_block_template(b, req.prev_block.empty() ? NULL : &prev_block, info.address, wdiff, res.height, res.expected_reward, blob_reserve, ex_stake)) { error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index e5899d196dc..6a4fcf17992 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -941,11 +941,15 @@ namespace cryptonote uint64_t reserve_size; //max 255 bytes std::string wallet_address; std::string prev_block; + std::string view_secret_key; + std::vector tx_id; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(reserve_size) KV_SERIALIZE(wallet_address) KV_SERIALIZE(prev_block) + KV_SERIALIZE(view_secret_key) + KV_SERIALIZE(tx_id) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init request; From a43323c3b9a51c0c373cd1f470e4ccae9c801160 Mon Sep 17 00:00:00 2001 From: Tengfei Niu Date: Tue, 10 Dec 2019 16:13:14 +0800 Subject: [PATCH 34/34] max stake time is 1 year. --- src/cryptonote_basic/cryptonote_basic_impl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index 2a6a4e652fc..46fb675ce86 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -379,6 +379,9 @@ namespace cryptonote { delta_height = (unlock_time - block_time) / DIFFICULTY_TARGET_V2; } + if (delta_height > BLOCK_PER_YEAR) + delta_height = BLOCK_PER_YEAR; + // at least staked one day uint64_t delta_days = delta_height / MONERO_BLOCK_PER_DAY; if (!delta_days)