1
0
Fork 0
forked from lthn/blockchain

pos mining code is generalized and now can be used outside of wallet2

This commit is contained in:
sowle 2022-10-23 23:48:43 +02:00
parent bb71c52d01
commit 078a7bf8b5
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
4 changed files with 158 additions and 100 deletions

View 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

View 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);
};
};

View file

@ -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()

View file

@ -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;