forked from lthn/blockchain
pos mining code is generalized and now can be used outside of wallet2
This commit is contained in:
parent
bb71c52d01
commit
078a7bf8b5
4 changed files with 158 additions and 100 deletions
103
src/currency_core/pos_mining.cpp
Normal file
103
src/currency_core/pos_mining.cpp
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (c) 2022 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
#include "currency_basic.h"
|
||||
#include "difficulty.h"
|
||||
#include "pos_mining.h"
|
||||
#include "wallet/wallet2.h"
|
||||
#include "crypto/zarcanum.h"
|
||||
#include "crypto_config.h"
|
||||
|
||||
namespace currency
|
||||
{
|
||||
void pos_mining_context::init(const wide_difficulty_type& pos_diff, const stake_modifier_type& sm, bool is_zarcanum)
|
||||
{
|
||||
this->basic_diff = pos_diff;
|
||||
this->sk.stake_modifier = sm;
|
||||
this->zarcanum = is_zarcanum;
|
||||
|
||||
if (is_zarcanum)
|
||||
{
|
||||
this->last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, this->sk.stake_modifier.last_pow_id);
|
||||
this->z_l_div_z_D = crypto::zarcanum_precalculate_z_l_div_z_D(this->basic_diff);
|
||||
}
|
||||
}
|
||||
|
||||
void pos_mining_context::prepare_entry(uint64_t stake_amount, const crypto::key_image& stake_out_ki, const crypto::public_key& stake_source_tx_pub_key, uint64_t stake_out_in_tx_index,
|
||||
const crypto::scalar_t& stake_out_blinding_mask, const crypto::secret_key& view_secret)
|
||||
{
|
||||
this->stake_amount = stake_amount;
|
||||
this->sk.kimage = stake_out_ki;
|
||||
|
||||
if (this->zarcanum)
|
||||
{
|
||||
crypto::scalar_t v = view_secret;
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
bool r = crypto::generate_key_derivation(stake_source_tx_pub_key, view_secret, derivation); // 8 * v * R
|
||||
CHECK_AND_ASSERT_MES_NO_RET(r, "generate_key_derivation failed");
|
||||
crypto::scalar_t h = AUTO_VAL_INIT(h);
|
||||
crypto::derivation_to_scalar(derivation, stake_out_in_tx_index, h.as_secret_key()); // h = Hs(8 * v * R, i)
|
||||
|
||||
// q = Hs(domain_sep, Hs(8 * v * R, i) ) * 8 * v
|
||||
this->secret_q = v * 8 * crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h);
|
||||
this->stake_out_blinding_mask = stake_out_blinding_mask;
|
||||
}
|
||||
}
|
||||
|
||||
bool pos_mining_context::do_iteration(uint64_t ts)
|
||||
{
|
||||
// update stake kernel and calculate it's hash
|
||||
this->sk.block_timestamp = ts;
|
||||
{
|
||||
PROFILE_FUNC("calc_hash");
|
||||
this->kernel_hash = crypto::cn_fast_hash(&this->sk, sizeof(this->sk));
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
if (this->zarcanum /* && td.is_zc() */)
|
||||
{
|
||||
crypto::mp::uint256_t lhs;
|
||||
crypto::mp::uint512_t rhs;
|
||||
{
|
||||
PROFILE_FUNC("check_zarcanum");
|
||||
found = crypto::zarcanum_check_main_pos_inequality(this->kernel_hash, this->stake_out_blinding_mask, this->secret_q, this->last_pow_block_id_hashed, this->z_l_div_z_D, this->stake_amount, lhs, rhs);
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
found = true;
|
||||
LOG_PRINT_GREEN("Found Zarcanum kernel: amount: " << currency::print_money_brief(this->stake_amount) << /* ", gindex: " << td.m_global_output_index << */ ENDL
|
||||
<< "difficulty: " << this->basic_diff << ENDL
|
||||
<< "kernel info: " << ENDL
|
||||
<< print_stake_kernel_info(this->sk)
|
||||
<< "kernel_hash: " << this->kernel_hash << ENDL
|
||||
<< "lhs: " << lhs << ENDL
|
||||
<< "rhs: " << rhs
|
||||
, LOG_LEVEL_0);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// old PoS with non-hidden amounts
|
||||
currency::wide_difficulty_type final_diff = this->basic_diff / this->stake_amount;
|
||||
{
|
||||
PROFILE_FUNC("check_hash");
|
||||
found = currency::check_hash(this->kernel_hash, final_diff);
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
LOG_PRINT_GREEN("Found kernel: amount: " << currency::print_money_brief(this->stake_amount)<< /* ", gindex: " << td.m_global_output_index << */ ENDL
|
||||
<< "difficulty: " << this->basic_diff << ", final_diff: " << final_diff << ENDL
|
||||
<< "kernel info: " << ENDL
|
||||
<< print_stake_kernel_info(this->sk)
|
||||
<< "kernel_hash(proof): " << this->kernel_hash,
|
||||
LOG_LEVEL_0);
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
}; // namespace currency
|
||||
33
src/currency_core/pos_mining.h
Normal file
33
src/currency_core/pos_mining.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) 2022 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
namespace currency
|
||||
{
|
||||
|
||||
struct pos_mining_context
|
||||
{
|
||||
wide_difficulty_type basic_diff;
|
||||
stake_kernel sk;
|
||||
|
||||
crypto::scalar_t last_pow_block_id_hashed; // Zarcanum notation: f'
|
||||
crypto::scalar_t secret_q; // Zarcanum notation: q
|
||||
boost::multiprecision::uint256_t z_l_div_z_D; // Zarcanum notation: z * floor( l / (z * D) ) (max possible value (assuming z=2^64) : z * 2^252 / (z * 1) ~= 2^252)
|
||||
crypto::hash kernel_hash; // Zarcanum notation: h
|
||||
crypto::scalar_t stake_out_blinding_mask; // Zarcanum notation: f
|
||||
|
||||
uint64_t stake_amount;
|
||||
|
||||
bool zarcanum;
|
||||
|
||||
void init(const wide_difficulty_type& pos_diff, const stake_modifier_type& sm, bool is_zarcanum);
|
||||
|
||||
void prepare_entry(uint64_t stake_amount, const crypto::key_image& stake_out_ki, const crypto::public_key& stake_source_tx_pub_key, uint64_t stake_out_in_tx_index,
|
||||
const crypto::scalar_t& stake_out_blinding_mask, const crypto::secret_key& view_secret);
|
||||
|
||||
bool do_iteration(uint64_t ts);
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -3567,8 +3567,11 @@ bool wallet2::get_transfer_address(const std::string& adr_str, currency::account
|
|||
return m_core_proxy->get_transfer_address(adr_str, addr, payment_id);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_transfer_okay_for_pos(const transfer_details& tr, uint64_t& stake_unlock_time) const
|
||||
bool wallet2::is_transfer_okay_for_pos(const transfer_details& tr, bool is_zarcanum_hf, uint64_t& stake_unlock_time) const
|
||||
{
|
||||
if (is_zarcanum_hf && !tr.is_zc())
|
||||
return false;
|
||||
|
||||
if (!tr.is_spendable())
|
||||
return false;
|
||||
|
||||
|
|
@ -3603,6 +3606,7 @@ void wallet2::get_mining_history(wallet_public::mining_history& hist, uint64_t t
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
size_t wallet2::get_pos_entries_count()
|
||||
{
|
||||
bool is_zarcanum_hf = is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM);
|
||||
size_t counter = 0;
|
||||
|
||||
for (size_t i = 0, size = m_transfers.size(); i < size; i++)
|
||||
|
|
@ -3610,7 +3614,7 @@ size_t wallet2::get_pos_entries_count()
|
|||
auto& tr = m_transfers[i];
|
||||
|
||||
uint64_t stake_unlock_time = 0;
|
||||
if (!is_transfer_okay_for_pos(tr, stake_unlock_time))
|
||||
if (!is_transfer_okay_for_pos(tr, is_zarcanum_hf, stake_unlock_time))
|
||||
continue;
|
||||
|
||||
++counter;
|
||||
|
|
@ -3621,12 +3625,13 @@ size_t wallet2::get_pos_entries_count()
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::get_pos_entries(std::vector<currency::pos_entry>& entries)
|
||||
{
|
||||
bool is_zarcanum_hf = is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM);
|
||||
for (size_t i = 0; i != m_transfers.size(); i++)
|
||||
{
|
||||
auto& tr = m_transfers[i];
|
||||
|
||||
uint64_t stake_unlock_time = 0;
|
||||
if (!is_transfer_okay_for_pos(tr, stake_unlock_time))
|
||||
if (!is_transfer_okay_for_pos(tr, is_zarcanum_hf, stake_unlock_time))
|
||||
continue;
|
||||
|
||||
pos_entry pe = AUTO_VAL_INIT(pe);
|
||||
|
|
@ -3819,26 +3824,17 @@ bool wallet2::fill_mining_context(mining_context& ctx)
|
|||
{
|
||||
currency::COMMAND_RPC_GET_POS_MINING_DETAILS::request pos_details_req = AUTO_VAL_INIT(pos_details_req);
|
||||
currency::COMMAND_RPC_GET_POS_MINING_DETAILS::response pos_details_resp = AUTO_VAL_INIT(pos_details_resp);
|
||||
ctx.status = API_RETURN_CODE_NOT_FOUND;
|
||||
m_core_proxy->call_COMMAND_RPC_GET_POS_MINING_DETAILS(pos_details_req, pos_details_resp);
|
||||
if (pos_details_resp.status != API_RETURN_CODE_OK)
|
||||
return false;
|
||||
ctx.basic_diff.assign(pos_details_resp.pos_basic_difficulty);
|
||||
ctx.sk = AUTO_VAL_INIT(ctx.sk);
|
||||
ctx.sk.stake_modifier = pos_details_resp.sm;
|
||||
|
||||
if (is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM))
|
||||
{
|
||||
// Zarcanum (PoS with hidden amounts)
|
||||
ctx.zarcanum = true;
|
||||
ctx.last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, ctx.sk.stake_modifier.last_pow_id);
|
||||
ctx.z_l_div_z_D = crypto::zarcanum_precalculate_z_l_div_z_D(ctx.basic_diff);
|
||||
}
|
||||
ctx = mining_context{};
|
||||
ctx.init(wide_difficulty_type(pos_details_resp.pos_basic_difficulty), pos_details_resp.sm, is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM));
|
||||
|
||||
ctx.last_block_hash = pos_details_resp.last_block_hash;
|
||||
ctx.is_pos_allowed = pos_details_resp.pos_mining_allowed;
|
||||
ctx.starter_timestamp = pos_details_resp.starter_timestamp;
|
||||
ctx.status = API_RETURN_CODE_OK;
|
||||
ctx.status = API_RETURN_CODE_NOT_FOUND;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
|
@ -3885,82 +3881,17 @@ void wallet2::do_pos_mining_prepare_entry(mining_context& context, size_t transf
|
|||
CHECK_AND_ASSERT_MES_NO_RET(transfer_index < m_transfers.size(), "transfer_index is out of bounds: " << transfer_index);
|
||||
const transfer_details& td = m_transfers[transfer_index];
|
||||
|
||||
// pre build kernel
|
||||
context.sk.kimage = td.m_key_image;
|
||||
crypto::scalar_t blinding_mask{};
|
||||
if (td.m_opt_blinding_mask)
|
||||
blinding_mask = *td.m_opt_blinding_mask;
|
||||
|
||||
if (context.zarcanum)
|
||||
{
|
||||
crypto::scalar_t v = m_account.get_keys().view_secret_key;
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
bool r = crypto::generate_key_derivation(get_tx_pub_key_from_extra(td.m_ptx_wallet_info->m_tx), m_account.get_keys().view_secret_key, derivation); // 8 * v * R
|
||||
CHECK_AND_ASSERT_MES_NO_RET(r, "generate_key_derivation failed");
|
||||
crypto::scalar_t h = AUTO_VAL_INIT(h);
|
||||
crypto::derivation_to_scalar(derivation, td.m_internal_output_index, h.as_secret_key()); // h = Hs(8 * v * R, i)
|
||||
|
||||
// q = Hs(domain_sep, Hs(8 * v * R, i) ) * 8 * v
|
||||
context.secret_q = v * 8 * crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h);
|
||||
}
|
||||
context.prepare_entry(td.amount(), td.m_key_image, get_tx_pub_key_from_extra(td.m_ptx_wallet_info->m_tx), td.m_internal_output_index,
|
||||
blinding_mask, m_account.get_keys().view_secret_key);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool wallet2::do_pos_mining_iteration(mining_context& context, size_t transfer_index, uint64_t ts)
|
||||
{
|
||||
CHECK_AND_NO_ASSERT_MES(transfer_index < m_transfers.size(), false, "transfer_index is out of bounds: " << transfer_index);
|
||||
const transfer_details& td = m_transfers[transfer_index];
|
||||
|
||||
// update stake kernel and calculate it's hash
|
||||
context.sk.block_timestamp = ts;
|
||||
{
|
||||
PROFILE_FUNC("calc_hash");
|
||||
context.kernel_hash = crypto::cn_fast_hash(&context.sk, sizeof(context.sk));
|
||||
}
|
||||
|
||||
const uint64_t stake_amount = td.amount();
|
||||
bool found = false;
|
||||
|
||||
if (context.zarcanum && td.is_zc())
|
||||
{
|
||||
crypto::mp::uint256_t lhs;
|
||||
crypto::mp::uint512_t rhs;
|
||||
{
|
||||
PROFILE_FUNC("check_zarcanum");
|
||||
found = crypto::zarcanum_check_main_pos_inequality(context.kernel_hash, *td.m_opt_blinding_mask, context.secret_q, context.last_pow_block_id_hashed, context.z_l_div_z_D, stake_amount, lhs, rhs);
|
||||
++context.iterations_processed;
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
found = true;
|
||||
LOG_PRINT_GREEN("Found Zarcanum kernel: amount: " << currency::print_money_brief(stake_amount) << ", gindex: " << td.m_global_output_index << ENDL
|
||||
<< "difficulty: " << context.basic_diff << ENDL
|
||||
<< "kernel info: " << ENDL
|
||||
<< print_stake_kernel_info(context.sk)
|
||||
<< "kernel_hash: " << context.kernel_hash << ENDL
|
||||
<< "lhs: " << lhs << ENDL
|
||||
<< "rhs: " << rhs
|
||||
, LOG_LEVEL_0);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// old PoS with non-hidden amounts
|
||||
currency::wide_difficulty_type final_diff = context.basic_diff / stake_amount;
|
||||
{
|
||||
PROFILE_FUNC("check_hash");
|
||||
found = currency::check_hash(context.kernel_hash, final_diff);
|
||||
++context.iterations_processed;
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
LOG_PRINT_GREEN("Found kernel: amount: " << currency::print_money_brief(stake_amount)<< ", gindex: " << td.m_global_output_index << ENDL
|
||||
<< "difficulty: " << context.basic_diff << ", final_diff: " << final_diff << ENDL
|
||||
<< "kernel info: " << ENDL
|
||||
<< print_stake_kernel_info(context.sk)
|
||||
<< "kernel_hash(proof): " << context.kernel_hash,
|
||||
LOG_LEVEL_0);
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
return context.do_iteration(ts);
|
||||
}
|
||||
//-------------------------------
|
||||
bool wallet2::reset_history()
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include "common/pod_array_file_container.h"
|
||||
#include "wallet_chain_shortener.h"
|
||||
#include "tor-connect/torlib/tor_lib_iface.h"
|
||||
#include "currency_core/pos_mining.h"
|
||||
|
||||
|
||||
#define WALLET_DEFAULT_TX_SPENDABLE_AGE 10
|
||||
|
|
@ -412,28 +413,18 @@ namespace tools
|
|||
uint64_t m_unlock_time = 0;
|
||||
};
|
||||
|
||||
struct mining_context
|
||||
struct mining_context : public currency::pos_mining_context
|
||||
{
|
||||
std::string status;
|
||||
|
||||
bool is_pos_allowed = false;;
|
||||
bool zarcanum = false;
|
||||
bool is_pos_allowed = false;
|
||||
|
||||
uint64_t index = 0; // index in m_transfers
|
||||
uint64_t stake_unlock_time = 0;
|
||||
//uint64_t block_timestamp;
|
||||
uint64_t height = 0;
|
||||
uint64_t starter_timestamp = 0;
|
||||
crypto::hash last_block_hash = currency::null_hash;
|
||||
|
||||
crypto::scalar_t last_pow_block_id_hashed; // Zarcanum notation: f'
|
||||
crypto::scalar_t secret_q; // Zarcanum notation: q
|
||||
boost::multiprecision::uint256_t z_l_div_z_D; // Zarcanum notation: z * floor( l / (z * D) ) (max possible value (assuming z=2^64) : z * 2^252 / (z * 1) ~= 2^252)
|
||||
crypto::hash kernel_hash; // Zarcanum notation: h
|
||||
|
||||
currency::wide_difficulty_type basic_diff;
|
||||
currency::stake_kernel sk;
|
||||
|
||||
uint64_t iterations_processed = 0;
|
||||
uint64_t total_items_checked = 0;
|
||||
uint64_t total_amount_checked = 0;
|
||||
|
|
@ -968,7 +959,7 @@ private:
|
|||
std::string get_alias_for_address(const std::string& addr);
|
||||
std::vector<std::string> get_aliases_for_address(const std::string& addr);
|
||||
bool is_connected_to_net();
|
||||
bool is_transfer_okay_for_pos(const transfer_details& tr, uint64_t& stake_unlock_time) const;
|
||||
bool is_transfer_okay_for_pos(const transfer_details& tr, bool is_zarcanum_hf, uint64_t& stake_unlock_time) const;
|
||||
bool scan_unconfirmed_outdate_tx();
|
||||
const currency::transaction& get_transaction_by_id(const crypto::hash& tx_hash);
|
||||
void rise_on_transfer2(const wallet_public::wallet_transfer_info& wti);
|
||||
|
|
@ -1342,7 +1333,7 @@ namespace tools
|
|||
auto& tr = m_transfers[transfer_index];
|
||||
|
||||
uint64_t stake_unlock_time = 0;
|
||||
if (!is_transfer_okay_for_pos(tr, stake_unlock_time))
|
||||
if (!is_transfer_okay_for_pos(tr, cxt.zarcanum, stake_unlock_time))
|
||||
continue;
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue