1
0
Fork 0
forked from lthn/blockchain

Merge branch 'zarcanum' into multiassets

This commit is contained in:
cryptozoidberg 2022-10-16 14:46:47 +02:00
commit 76aa0c71a2
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
22 changed files with 312 additions and 150 deletions

View file

@ -116,7 +116,7 @@ DISABLE_VS_WARNINGS(4100)
#define ENABLE_CHANNEL_BY_DEFAULT(ch_name) \
static bool COMBINE(init_channel, __LINE__) UNUSED_ATTRIBUTE = epee::misc_utils::static_initializer([](){ \
epee::log_space::log_singletone::enable_channel(ch_name); return true; \
epee::log_space::log_singletone::enable_channel(ch_name, false); return true; \
});
@ -1239,21 +1239,24 @@ namespace log_space
return genabled_channels.find(ch_name) != genabled_channels.end();
}
static void enable_channels(const std::string& channels_set)
static void enable_channels(const std::string& channels_set, bool verbose = true)
{
std::set<std::string>& genabled_channels = get_enabled_channels();
std::list<std::string> list_of_channels;
boost::split(list_of_channels, channels_set, boost::is_any_of(",;: "), boost::token_compress_on);
std::cout << "log channels: ";
if (verbose)
std::cout << "log channels: ";
for (const auto& ch : list_of_channels)
{
genabled_channels.insert(ch);
std::cout << ch << " ";
if (verbose)
std::cout << ch << " ";
}
std::cout << " enabled" << std::endl;
if (verbose)
std::cout << " enabled" << std::endl;
}
static void enable_channel(const std::string& ch_name)
static void enable_channel(const std::string& ch_name, bool verbose = true)
{
std::set<std::string>& genabled_channels = get_enabled_channels();
//lazy synchronization: just replace with modified copy of whole set
@ -1261,7 +1264,8 @@ namespace log_space
enabled_channels_local.insert(ch_name);
genabled_channels.swap(enabled_channels_local);
#ifndef ANDROID_BUILD
//std::cout << "log channel '" << ch_name << "' enabled" << std::endl;
if (verbose)
std::cout << "log channel '" << ch_name << "' enabled" << std::endl;
#endif
}

View file

@ -46,12 +46,15 @@ namespace crypto
if (!(cond)) { LOG_PRINT_RED("zarcanum_generate_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
bool zarcanum_generate_proof(const hash& kernel_hash, const public_key& commitment_1div8, const scalar_t& blinding_mask, const scalar_t& secret_q,
const scalar_t& last_pow_block_id_hashed, uint64_t stake_amount, zarcanum_proof& result, uint8_t* p_err)
bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment,
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, const scalar_t& pseudo_out_blinding_mask, uint64_t stake_amount, const scalar_t& stake_blinding_mask,
zarcanum_proof& result, uint8_t* p_err /* = nullptr */)
{
const scalar_t a = stake_amount;
const scalar_t h = scalar_t(kernel_hash);
const scalar_t f_plus_q = blinding_mask + secret_q;
const scalar_t f_plus_q = stake_blinding_mask + secret_q;
const scalar_t f_plus_q_plus_fp = f_plus_q + last_pow_block_id_hashed;
const scalar_t lhs = h * f_plus_q_plus_fp; // == h * (f + q + f') mod l
const mp::uint256_t d_mp = lhs.as_boost_mp_type<mp::uint256_t>() / (c_zarcanum_z_coeff_mp * stake_amount) + 1;
@ -71,9 +74,9 @@ namespace crypto
point_t C_prime = x1 * c_point_X + f_plus_q * c_point_H + a * c_point_G;
point_t E = bx * c_point_X + ba * c_point_H + bf * c_point_G;
result.C = C.to_public_key();
result.C_prime = C_prime.to_public_key();
result.E = E.to_public_key();
result.C = (c_scalar_1div8 * C).to_public_key();
result.C_prime = (c_scalar_1div8 * C_prime).to_public_key();
result.E = (c_scalar_1div8 * E).to_public_key();
// three proofs with a shared Fiat-Shamir challenge c
// 1) linear composition proof for the fact, that C + C' = lin(X, H + G) = (x + x') X + (a + f + q) (H + G)
@ -109,29 +112,26 @@ namespace crypto
result.y4 = r4 + result.c * x2; // y_4 = r_4 + c x''
// range proof for E
const scalar_vec_t values = { a }; // H component
const scalar_vec_t values = { ba }; // H component
const scalar_vec_t masks = { bf }; // G component
const scalar_vec_t masks2 = { bx }; // X component
const std::vector<const public_key*> commitments_1div8 = { &commitment_1div8 };
const std::vector<const public_key*> E_1div8_vec_ptr = { &result.E };
if (!bppe_gen<bpp_crypto_trait_zano<>>(values, masks, masks2, commitments_1div8, result.E_range_proof, p_err))
{
return false;
}
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_gen<bpp_crypto_trait_zano<>>(values, masks, masks2, E_1div8_vec_ptr, result.E_range_proof), 10);
// = four-layers ring signature data outline =
// (j in [0, ring_size-1])
// layer 0 ring
// se.outputs[j].stealth_address;
// A[j] ( = ring[j].stealth_address)
// layer 0 secret (with respect to G)
// in_contexts[i].in_ephemeral.sec;
// secret_x
// layer 0 linkability
// in.k_image;
// stake_ki
//
// layer 1 ring
// crypto::point_t(se.outputs[j].amount_commitment) - pseudo_out_amount_commitment;
// ring[j].amount_commitment - pseudo_out_amount_commitment
// layer 1 secret (with respect to G)
// se.real_out_amount_blinding_mask - blinding_mask;
// stake_blinding_mask - pseudo_out_blinding_mask
//
// additional layers for Zarcanum:
//
@ -144,8 +144,13 @@ namespace crypto
// Q[j]
// layer 3 secret (with respect to G)
// secret_q
TRY_ENTRY()
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(generate_CLSAG_GGXG(m, ring, pseudo_out_amount_commitment, C, stake_ki,
secret_x, stake_blinding_mask - pseudo_out_blinding_mask, x0, secret_q, secret_index,
result.clsag_ggxg), 20);
CATCH_ENTRY2(false);
return true;
return true;
}

View file

@ -27,9 +27,9 @@ namespace crypto
struct zarcanum_proof
{
scalar_t d = 0;
public_key C;
public_key C_prime;
public_key E;
public_key C; // premultiplied by 1/8
public_key C_prime; // premultiplied by 1/8
public_key E; // premultiplied by 1/8
scalar_t c; // shared Fiat-Shamir challenge for the following three proofs
scalar_t y0; // 1st linear composition proof
@ -39,14 +39,15 @@ namespace crypto
scalar_t y4; // Schnorr proof (F = lin(X))
bppe_signature E_range_proof;
CLSAG_GGXG_signature ring_sig;
crypto::public_key pseudo_out_amount_commitment; // premultiplied by 1/8
CLSAG_GGXG_signature clsag_ggxg;
};
bool zarcanum_generate_proof(const hash& kernel_hash, const public_key& stake_commitment_1div8, const scalar_t& last_pow_block_id_hashed,
const scalar_t& blinding_mask, const scalar_t& secret_q, uint64_t stake_amount,
uint64_t secret_index,
bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment,
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, const scalar_t& pseudo_out_blinding_mask, uint64_t stake_amount, const scalar_t& stake_blinding_mask,
zarcanum_proof& result, uint8_t* p_err = nullptr);
bool zarcanum_verify_proof(const hash& kernel_hash, const public_key& commitment_1div8, const scalar_t& last_pow_block_id_hashed, const zarcanum_proof& proof, uint8_t* p_err = nullptr);

View file

@ -4552,7 +4552,7 @@ struct outputs_visitor
//check tx unlock time
uint64_t source_out_unlock_time = get_tx_unlock_time(source_tx, out_i);
//let coinbase sources for PoS block to have locked inputs, the outputs supposed to be locked same way, except the reward
if (is_coinbase(validated_tx) && is_pos_block(validated_tx)) // @#@ consider changing to one call to is_pos_coinbase()
if (is_coinbase(validated_tx) && is_pos_miner_tx(validated_tx)) // @#@ consider changing to one call to is_pos_coinbase()
{
CHECK_AND_ASSERT_MES(should_unlock_value_be_treated_as_block_height(source_out_unlock_time), false, "source output #" << out_i << " is locked by time, not by height, which is not allowed for PoS coinbase");
if (source_out_unlock_time > m_source_max_unlock_time_for_pos_coinbase)
@ -5374,7 +5374,7 @@ bool blockchain_storage::validate_pos_block(const block& b,
wide_difficulty_type basic_diff,
uint64_t& amount,
wide_difficulty_type& final_diff,
crypto::hash& proof_hash,
crypto::hash& kernel_hash,
const crypto::hash& id,
bool for_altchain,
const alt_chain_type& alt_chain,
@ -5415,7 +5415,7 @@ bool blockchain_storage::validate_pos_block(const block& b,
CHECK_AND_ASSERT_MES(r, false, "failed to build_stake_modifier");
r = build_kernel(stake_key_image, sk, sm, b.timestamp);
CHECK_AND_ASSERT_MES(r, false, "failed to build kernel_stake");
proof_hash = crypto::cn_fast_hash(&sk, sizeof(sk));
kernel_hash = crypto::cn_fast_hash(&sk, sizeof(sk));
if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM))
{
@ -5424,6 +5424,7 @@ bool blockchain_storage::validate_pos_block(const block& b,
else
{
// old PoS non-hidden amount scheme
CHECK_AND_ASSERT_MES(b.miner_tx.version <= TRANSACTION_VERSION_PRE_HF4, false, "PoS miner tx has incorrect version: " << b.miner_tx.version);
CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "incorrect input 1 type: " << b.miner_tx.vin[1].type().name() << ", txin_to_key expected");
const txin_to_key& intk = boost::get<txin_to_key>(b.miner_tx.vin[1]);
amount = intk.amount;
@ -5435,16 +5436,16 @@ bool blockchain_storage::validate_pos_block(const block& b,
LOG_PRINT_L2("STAKE KERNEL for bl ID: " << get_block_hash(b) << ENDL
<< print_stake_kernel_info(sk)
<< "amount: " << print_money(amount) << ENDL
<< "kernel_hash: " << proof_hash);
<< "kernel_hash: " << kernel_hash);
final_diff = basic_diff / amount;
if (!check_hash(proof_hash, final_diff))
if (!check_hash(kernel_hash, final_diff))
{
LOG_ERROR("PoS difficulty check failed for block " << get_block_hash(b) << " @ HEIGHT " << get_block_height(b) << ":" << ENDL
<< " basic_diff: " << basic_diff << ENDL
<< " final_diff: " << final_diff << ENDL
<< " amount: " << print_money_brief(amount) << ENDL
<< " kernel_hash: " << proof_hash << ENDL
<< " kernel_hash: " << kernel_hash << ENDL
);
return false;
}

View file

@ -352,7 +352,7 @@ namespace currency
wide_difficulty_type basic_diff,
uint64_t& amount,
wide_difficulty_type& final_diff,
crypto::hash& proof_hash,
crypto::hash& kernel_hash,
const crypto::hash& id,
bool for_altchain,
const alt_chain_type& alt_chain = alt_chain_type(),

View file

@ -30,6 +30,7 @@
#define CURRENT_TRANSACTION_VERSION 2
#define TRANSACTION_VERSION_INITAL 0
#define TRANSACTION_VERSION_PRE_HF4 1
#define TRANSACTION_VERSION_POST_HF4 2
#define HF1_BLOCK_MAJOR_VERSION 1
#define HF3_BLOCK_MAJOR_VERSION 2
#define CURRENT_BLOCK_MAJOR_VERSION 3

View file

@ -189,7 +189,6 @@ namespace currency
const pos_entry& pe)
{
bool r = false;
CHECK_AND_ASSERT_THROW_MES(!pos || tx_version <= TRANSACTION_VERSION_PRE_HF4, "PoS miner tx is currently unsupported for HF4 -- sowle");
uint64_t block_reward = 0;
if (!get_block_reward(pos, median_size, current_block_size, already_generated_coins, block_reward, height))
@ -265,16 +264,22 @@ namespace currency
in.height = height;
tx.vin.push_back(in);
// input #1: stake (for PoS blocks only)
if (pos)
{
// input #1: stake (for PoS blocks only)
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
if (tx.version > TRANSACTION_VERSION_PRE_HF4 /* && stake is zarcanum */)
{
// TODO: add Zarcanum part
//txin_zc_input stake_input = AUTO_VAL_INIT(stake_input);
//stake_input.key_offsets.push_back(pe.g_index);
//stake_input.k_image = pe.keyimage;
tx.vin.emplace_back(std::move(txin_zc_input()));
//reserve place for ring signature
tx.signatures.emplace_back(std::move(zarcanum_sig()));
}
else
{
// old fashioned tx non-hidden amounts PoS scheme
// old fashioned non-hidden amount direct spend PoS scheme
txin_to_key stake_input;
stake_input.amount = pe.amount;
stake_input.key_offsets.push_back(pe.g_index);
@ -578,7 +583,7 @@ namespace currency
}
//---------------------------------------------------------------
bool get_tx_fee(const transaction& tx, uint64_t & fee)
bool get_tx_fee(const transaction& tx, uint64_t& fee)
{
fee = 0;
if (is_coinbase(tx))
@ -607,10 +612,8 @@ namespace currency
return true; // continue
};
bool r = process_type_in_variant_container<zarcanum_tx_data_v1>(tx.extra, cb, false);
if (!r)
{
fee = 0;
@ -3575,17 +3578,19 @@ namespace currency
{
if (!(b.flags & CURRENCY_BLOCK_FLAG_POS_BLOCK))
return false;
return is_pos_block(b.miner_tx);
return is_pos_miner_tx(b.miner_tx);
}
//---------------------------------------------------------------
bool is_pos_block(const transaction& tx)
bool is_pos_miner_tx(const transaction& tx)
{
if (tx.vin.size() == 2 &&
tx.vin[0].type() == typeid(txin_gen) &&
tx.vin[1].type() == typeid(txin_to_key))
(tx.vin[1].type() == typeid(txin_to_key) ||
tx.vin[1].type() == typeid(txin_zc_input)))
return true;
return false;
}
//---------------------------------------------------------------
size_t get_max_block_size()
{
return CURRENCY_MAX_BLOCK_SIZE;

View file

@ -385,7 +385,7 @@ namespace currency
//PoS
bool is_pos_block(const block& b);
bool is_pos_block(const transaction& tx);
bool is_pos_miner_tx(const transaction& tx);
wide_difficulty_type correct_difficulty_with_sequence_factor(size_t sequence_factor, wide_difficulty_type diff);
void print_currency_details();
std::string print_reward_change_first_blocks(size_t n_of_first_blocks);

View file

@ -218,7 +218,6 @@ namespace currency
catch(...)
{
// should never go here, just precaution
return false;
}
return false;

View file

@ -125,7 +125,7 @@ int main(int argc, char* argv[])
#endif
log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0);
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,wallet");
log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,wallet", false);
LOG_PRINT_L0("Starting...");
tools::signal_handler::install_fatal([](int sig_number, void* address) {

View file

@ -130,7 +130,7 @@ namespace plain_wallet
log_dir += "/" LOGS_FOLDER;
log_space::get_set_need_thread_id(true, true);
log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,p2p,wallet");
log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,p2p,wallet", false);
epee::log_space::get_set_log_detalisation_level(true, log_level);
#ifdef ANDROID_BUILD
epee::log_space::log_singletone::add_logger(new android_logger());

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2019 Zano Project
// Copyright (c) 2014-2022 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -3647,12 +3647,16 @@ bool wallet2::is_in_hardfork_zone(uint64_t hardfork_index) const
return m_core_runtime_config.is_hardfork_active_for_height(hardfork_index, get_blockchain_current_size());
}
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_and_sign_pos_block(currency::block& b, const pos_entry& pe) const
bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::block& b, const pos_entry& pe) const
{
bool r = false;
WLT_CHECK_AND_ASSERT_MES(pe.wallet_index < m_transfers.size(), false, "invalid pe.wallet_index: " << pe.wallet_index);
const transaction& source_tx = m_transfers[pe.wallet_index].m_ptx_wallet_info->m_tx;
if (!is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM))
const transfer_details& td = m_transfers[pe.wallet_index];
const transaction& source_tx = td.m_ptx_wallet_info->m_tx;
const crypto::public_key source_tx_pub_key = get_tx_pub_key_from_extra(source_tx);
WLT_CHECK_AND_ASSERT_MES(pe.tx_out_index < source_tx.vout.size(), false, "invalid pe.tx_out_index: " << pe.tx_out_index);
const currency::tx_out_v& stake_out_v = source_tx.vout[pe.tx_out_index];
if (!cxt.zarcanum)
{
// old PoS with non-hidden amounts
WLT_CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(currency::txin_gen), false, "Wrong input 0 type in transaction: " << b.miner_tx.vin[0].type().name());
@ -3667,13 +3671,11 @@ bool wallet2::prepare_and_sign_pos_block(currency::block& b, const pos_entry& pe
//derive secret key
crypto::key_derivation pos_coin_derivation = AUTO_VAL_INIT(pos_coin_derivation);
bool r = crypto::generate_key_derivation(get_tx_pub_key_from_extra(source_tx),
bool r = crypto::generate_key_derivation(source_tx_pub_key,
m_account.get_keys().view_secret_key,
pos_coin_derivation);
WLT_CHECK_AND_ASSERT_MES(r, false, "internal error: pos coin base generator: failed to generate_key_derivation("
<< pe.tx_id
<< ", view secret key: " << m_account.get_keys().view_secret_key << ")");
WLT_CHECK_AND_ASSERT_MES(r, false, "generate_key_derivation failed, pe.tx_id: " << pe.tx_id);
crypto::secret_key derived_secret_ephemeral_key = AUTO_VAL_INIT(derived_secret_ephemeral_key);
crypto::derive_secret_key(pos_coin_derivation,
@ -3687,7 +3689,6 @@ bool wallet2::prepare_and_sign_pos_block(currency::block& b, const pos_entry& pe
// get stake output pub key (stealth address) for ring signature generation
std::vector<const crypto::public_key*> keys_ptrs;
TRY_ENTRY()
const currency::tx_out_v& stake_out_v = source_tx.vout[pe.tx_out_index];
keys_ptrs.push_back(&boost::get<currency::txout_to_key>(boost::get<tx_out_bare>(stake_out_v).target).key);
CATCH_ENTRY_CUSTOM("wallet2::prepare_and_sign_pos_block", { LOG_PRINT_RED_L0("unable to get output's pub key because of the exception"); }, false);
@ -3707,8 +3708,113 @@ bool wallet2::prepare_and_sign_pos_block(currency::block& b, const pos_entry& pe
}
// Zarcanum
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(false, "ZRCANUM BLOCKS NOT IMPLEMENTED YET");
return false; // to get rid of warning
WLT_CHECK_AND_ASSERT_MES(td.is_zc(), false, "the transfer [" << pe.wallet_index << "] is not zc type, which is required for zarcanum");
WLT_CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(currency::txin_gen), false, "Wrong input 0 type in transaction: " << b.miner_tx.vin[0].type().name());
WLT_CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(currency::txin_zc_input), false, "Wrong input 1 type in transaction: " << b.miner_tx.vin[1].type().name());
WLT_CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1 && b.miner_tx.signatures[0].type() == typeid(zarcanum_sig), false, "wrong sig prepared in a PoS block");
WLT_CHECK_AND_ASSERT_MES(stake_out_v.type() == typeid(tx_out_zarcanum), false, "unexpected stake output type: " << stake_out_v.type().name() << ", expected: tx_out_zarcanum");
zarcanum_sig& sig = boost::get<zarcanum_sig>(b.miner_tx.signatures[0]);
txin_zc_input& stake_input = boost::get<txin_zc_input>(b.miner_tx.vin[1]);
const tx_out_zarcanum& stake_out = boost::get<tx_out_zarcanum>(stake_out_v);
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response decoys_resp = AUTO_VAL_INIT(decoys_resp);
std::vector<crypto::CLSAG_GGXG_input_ref_t> ring;
uint64_t secret_index = 0; // index of the real stake output
// get decoys outputs and construct miner tx
static size_t required_decoys_count = 8; // TODO @#@# set them somewhere else
static bool use_only_forced_to_mix = false; // TODO @#@# set them somewhere else
if (required_decoys_count > 0)
{
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request decoys_req = AUTO_VAL_INIT(decoys_req);
decoys_req.height_upper_limit = m_last_pow_block_h; // request decoys to be either older than, or the same age as stake output's height
decoys_req.use_forced_mix_outs = use_only_forced_to_mix;
decoys_req.decoys_count = required_decoys_count + 1; // one more to be able to skip a decoy in case it hits the real output
decoys_req.amounts.push_back(0); // request one batch of decoys for hidden amounts
r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(decoys_req, decoys_resp);
// TODO @#@# do we need these exceptions?
THROW_IF_FALSE_WALLET_EX(r, error::no_connection_to_daemon, "getrandom_outs.bin");
THROW_IF_FALSE_WALLET_EX(decoys_resp.status != API_RETURN_CODE_BUSY, error::daemon_busy, "getrandom_outs.bin");
THROW_IF_FALSE_WALLET_EX(decoys_resp.status == API_RETURN_CODE_OK, error::get_random_outs_error, decoys_resp.status);
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(decoys_resp.outs.size() == 1, "got wrong number of decoys batches: " << decoys_resp.outs.size());
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(decoys_resp.outs[0].outs.size() == required_decoys_count + 1, "for PoS stake tx got less decoys to mix than requested: " << decoys_resp.outs[0].outs.size() << " < " << required_decoys_count + 1);
auto& decoys = decoys_resp.outs[0].outs;
std::unordered_set<uint64_t> used_gindices{ td.m_global_output_index };
size_t good_decoys_count = 0;
for(auto it = decoys.begin(); it != decoys.end(); )
{
if (used_gindices.count(it->global_amount_index) != 0)
{
it = decoys.erase(it);
continue;
}
used_gindices.insert(it->global_amount_index);
if (++good_decoys_count == required_decoys_count)
{
decoys.erase(++it, decoys.end());
break;
}
++it;
}
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(decoys.size() == required_decoys_count, "for PoS stake got less good decoys than required: " << decoys.size() << " < " << required_decoys_count);
secret_index = crypto::rand<uint64_t>() % (decoys.size());
uint64_t i = 0;
for(auto& el : decoys)
{
if (i++ == secret_index)
{
ring.emplace_back(stake_out.stealth_address, stake_out.amount_commitment, stake_out.concealing_point);
stake_input.key_offsets.push_back(td.m_global_output_index);
}
ring.emplace_back(el.stealth_address, el.amount_commitment, el.concealing_point);
stake_input.key_offsets.push_back(el.global_amount_index);
}
if (i == secret_index)
{
ring.emplace_back(stake_out.stealth_address, stake_out.amount_commitment, stake_out.concealing_point);
stake_input.key_offsets.push_back(td.m_global_output_index);
}
stake_input.key_offsets = absolute_output_offsets_to_relative(stake_input.key_offsets);
}
else
{
// no decoys, the ring consist of one element -- the real stake output
ring.emplace_back(stake_out.stealth_address, stake_out.amount_commitment, stake_out.concealing_point);
stake_input.key_offsets.push_back(td.m_global_output_index);
}
stake_input.k_image = pe.keyimage;
#ifndef NDEBUG
{
crypto::point_t source_amount_commitment = crypto::c_scalar_1div8 * td.m_amount * crypto::c_point_H + crypto::c_scalar_1div8 * *td.m_opt_blinding_mask * crypto::c_point_G;
CHECK_AND_ASSERT_MES(stake_out.amount_commitment == source_amount_commitment.to_public_key(), false, "real output amount commitment check failed");
}
#endif
crypto::scalar_t pseudo_out_blinding_mask = crypto::scalar_t::random();
crypto::point_t pseudo_out_amount_commitment = td.m_amount * crypto::c_point_H + pseudo_out_blinding_mask * crypto::c_point_G;
sig.pseudo_out_amount_commitment = (crypto::c_scalar_1div8 * pseudo_out_amount_commitment).to_public_key();
crypto::hash tx_hash_for_sig = get_transaction_hash(b.miner_tx);
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
r = crypto::generate_key_derivation(source_tx_pub_key, m_account.get_keys().view_secret_key, derivation);
WLT_CHECK_AND_ASSERT_MES(r, false, "generate_key_derivation failed, tid: " << pe.wallet_index << ", pe.tx_id: " << pe.tx_id);
crypto::secret_key secret_x = AUTO_VAL_INIT(secret_x);
crypto::derive_secret_key(derivation, pe.tx_out_index, m_account.get_keys().spend_secret_key, secret_x);
uint8_t err = 0;
r = crypto::zarcanum_generate_proof(tx_hash_for_sig, cxt.kernel_hash, ring, pseudo_out_amount_commitment, cxt.last_pow_block_id_hashed,
pe.keyimage, secret_x, cxt.secret_q, secret_index, pseudo_out_blinding_mask, td.m_amount, *td.m_opt_blinding_mask,
static_cast<crypto::zarcanum_proof&>(sig), &err);
WLT_CHECK_AND_ASSERT_MES(r, false, "zarcanum_generate_proof failed, err: " << (int)err);
return true;
}
//------------------------------------------------------------------
bool wallet2::fill_mining_context(mining_context& ctx)
@ -3799,10 +3905,9 @@ bool wallet2::do_pos_mining_iteration(mining_context& context, size_t transfer_i
// update stake kernel and calculate it's hash
context.sk.block_timestamp = ts;
crypto::hash kernel_hash;
{
PROFILE_FUNC("calc_hash");
kernel_hash = crypto::cn_fast_hash(&context.sk, sizeof(context.sk));
context.kernel_hash = crypto::cn_fast_hash(&context.sk, sizeof(context.sk));
}
const uint64_t stake_amount = td.amount();
@ -3814,7 +3919,7 @@ bool wallet2::do_pos_mining_iteration(mining_context& context, size_t transfer_i
crypto::mp::uint512_t rhs;
{
PROFILE_FUNC("check_zarcanum");
found = crypto::zarcanum_check_main_pos_inequality(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);
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)
@ -3824,7 +3929,7 @@ bool wallet2::do_pos_mining_iteration(mining_context& context, size_t transfer_i
<< "difficulty: " << context.basic_diff << ENDL
<< "kernel info: " << ENDL
<< print_stake_kernel_info(context.sk)
<< "kernel_hash: " << kernel_hash << ENDL
<< "kernel_hash: " << context.kernel_hash << ENDL
<< "lhs: " << lhs << ENDL
<< "rhs: " << rhs
, LOG_LEVEL_0);
@ -3837,7 +3942,7 @@ bool wallet2::do_pos_mining_iteration(mining_context& context, size_t transfer_i
currency::wide_difficulty_type final_diff = context.basic_diff / stake_amount;
{
PROFILE_FUNC("check_hash");
found = currency::check_hash(kernel_hash, final_diff);
found = currency::check_hash(context.kernel_hash, final_diff);
++context.iterations_processed;
}
if (found)
@ -3846,7 +3951,7 @@ bool wallet2::do_pos_mining_iteration(mining_context& context, size_t transfer_i
<< "difficulty: " << context.basic_diff << ", final_diff: " << final_diff << ENDL
<< "kernel info: " << ENDL
<< print_stake_kernel_info(context.sk)
<< "kernel_hash(proof): " << kernel_hash,
<< "kernel_hash(proof): " << context.kernel_hash,
LOG_LEVEL_0);
}
}
@ -3884,6 +3989,7 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco
tmpl_req.wallet_address = get_account_address_as_str(miner_address);
tmpl_req.stakeholder_address = get_account_address_as_str(m_account.get_public_address());
tmpl_req.pos_block = true;
tmpl_req.extra_text = m_miner_text_info;
tmpl_req.pe = AUTO_VAL_INIT(tmpl_req.pe);
tmpl_req.pe.amount = td.amount();
@ -3895,18 +4001,6 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco
tmpl_req.pe.tx_out_index = td.m_internal_output_index;
tmpl_req.pe.wallet_index = cxt.index;
//pe.g_index = tmpl_req.pos_g_index = td.m_global_output_index;
//pe.amount = tmpl_req.pos_amount = td.amount();// pe.amount;
//pe.keyimage = td.m_key_image;
//pe.block_timestamp = td.m_ptx_wallet_info->m_block_timestamp;
//pe.stake_unlock_time = tmpl_req.stake_unlock_time = cxt.stake_unlock_time;
//pe.tx_id = tmpl_req.tx_id = td.tx_hash();
//pe.tx_out_index = tmpl_req.tx_out_index = td.m_internal_output_index;
//pe.wallet_index = cxt.index;
//tmpl_req.pos_index = pe.index; // gindex <--- this should be removed as soon as pos_entry::index is replaced with tx_id and tx_out_index
// TODO: also fill out tx_id and tx_out_index for mining tx creation
tmpl_req.extra_text = m_miner_text_info;
//generate packing tx
transaction pack_tx = AUTO_VAL_INIT(pack_tx);
if (generate_packing_transaction_if_needed(pack_tx, 0))
@ -3936,20 +4030,18 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco
set_block_datetime(current_timestamp, b);
WLT_LOG_MAGENTA("Applying actual timestamp: " << current_timestamp, LOG_LEVEL_0);
const currency::tx_out_v& stake_out_v = td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index];
if (cxt.zarcanum && td.is_zc())
{
// Zarcanum
WLT_CHECK_AND_ASSERT_MES(stake_out_v.type() == typeid(tx_out_zarcanum), false, "unexpected stake output type: " << stake_out_v.type().name() << ", expected: zarcanum");
return false;
}
else
{
//const currency::tx_out_v& stake_out_v = td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index];
//if (cxt.zarcanum && td.is_zc())
//{
// // Zarcanum
// return false;
//}
//else
//{
// old fashioned non-hidden amount PoS scheme
res = prepare_and_sign_pos_block(b, tmpl_req.pe);
res = prepare_and_sign_pos_block(cxt, b, tmpl_req.pe);
WLT_CHECK_AND_ASSERT_MES(res, false, "Failed to prepare_and_sign_pos_block");
}
//}
crypto::hash block_hash = get_block_hash(b);
WLT_LOG_GREEN("Block " << print16(block_hash) << " has been constructed, sending to core...", LOG_LEVEL_0);

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2020 Zano Project
// Copyright (c) 2014-2022 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -252,9 +252,6 @@ namespace tools
const currency::tx_destination_entry& change_dst, uint64_t dust_threshold,
std::vector<currency::tx_destination_entry>& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed)
{
//&&&&&
LOG_PRINT_MAGENTA("[--apply_split_strategy_by_id, split strtegy_id: " << id, LOG_LEVEL_0);
switch (id)
{
case ssi_digit:
@ -432,6 +429,7 @@ namespace tools
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;
@ -842,7 +840,7 @@ namespace tools
//next functions in public area only becausce of test_generator
//TODO: Need refactoring - remove it back to private zone
void set_genesis(const crypto::hash& genesis_hash);
bool prepare_and_sign_pos_block(currency::block& b, const currency::pos_entry& pe) const;
bool prepare_and_sign_pos_block(const mining_context& cxt, currency::block& b, const currency::pos_entry& pe) const;
void process_new_blockchain_entry(const currency::block& b,
const currency::block_direct_data_entry& bche,
const crypto::hash& bl_id,

View file

@ -221,7 +221,7 @@ bool gen_chain_switch_pow_pos::check_balance_1(currency::core& c, size_t ev_inde
test_generator::wallets_vector w;
bool r = generator.build_wallets(get_block_hash(plk_2), m_accounts, w);
CHECK_AND_ASSERT_MES(r && w.size() == 3 && w[0] != 0 && w[1] != 0 && w[2] != 0, false, "failed to build wallets");
CHECK_AND_ASSERT_MES(r && w.size() == 3 && w[0].wallet != 0 && w[1].wallet != 0 && w[2].wallet != 0, false, "failed to build wallets");
/*
uint64_t mined_amount = m_early_blocks_reward * 12 + TX_POOL_MINIMUM_FEE / 2 + m_enormous_fee / 2;
@ -229,7 +229,7 @@ bool gen_chain_switch_pow_pos::check_balance_1(currency::core& c, size_t ev_inde
return false;
*/
if (!check_balance_via_wallet(*w[1], "alice", MK_TEST_COINS(1), 0, 0, 0, 0))
if (!check_balance_via_wallet(*w[1].wallet, "alice", MK_TEST_COINS(1), 0, 0, 0, 0))
return false;
return true;

View file

@ -330,7 +330,7 @@ bool test_generator::construct_block(currency::block& blk,
else
{
//need to build pos block
r = sign_block(blk, pe, *wallets[won_walled_index], blocks, oi);
r = sign_block(blk, pe, *wallets[won_walled_index].wallet, wallets[won_walled_index].mining_context, blocks, oi);
CHECK_AND_ASSERT_MES(r, false, "Failed to find_kernel_and_sign()");
}
@ -347,32 +347,15 @@ bool test_generator::construct_block(currency::block& blk,
return true;
}
bool test_generator::sign_block(currency::block& b,
pos_entry& pe,
tools::wallet2& w,
bool test_generator::sign_block(currency::block& b,
pos_entry& pe,
tools::wallet2& w,
const tools::wallet2::mining_context& mining_context,
const std::vector<const block_info*>& blocks,
const outputs_index& oi)
{
/*uint64_t h = 0;
uint64_t out_i = 0;
const transaction * pts = nullptr;
crypto::public_key source_tx_pub_key = null_pkey;
crypto::public_key out_key = null_pkey;
bool r = get_output_details_by_global_index(blocks,
oi,
pe.amount,
pe.g_index,
h,
pts,
out_i,
source_tx_pub_key,
out_key);
CHECK_AND_ASSERT_THROW_MES(r, "Failed to get_output_details_by_global_index()");*/
bool r = w.prepare_and_sign_pos_block(b, pe);
CHECK_AND_ASSERT_THROW_MES(r,"Failed to prepare_and_sign_pos_block()");
bool r = w.prepare_and_sign_pos_block(mining_context, b, pe);
CHECK_AND_ASSERT_MES(r, false, "prepare_and_sign_pos_block failed");
return true;
}
@ -438,10 +421,11 @@ bool test_generator::build_wallets(const blockchain_vector& blockchain,
wallets.clear();
for (auto a : accs)
{
wallets.push_back(std::shared_ptr<tools::wallet2>(new tools::wallet2()));
wallets.back()->assign_account(a);
wallets.back()->get_account().set_createtime(0);
wallets.back()->set_core_proxy(tmp_proxy);
wallets.push_back(gen_wallet_info());
wallets.back().wallet = std::shared_ptr<tools::wallet2>(new tools::wallet2());
wallets.back().wallet->assign_account(a);
wallets.back().wallet->get_account().set_createtime(0);
wallets.back().wallet->set_core_proxy(tmp_proxy);
currency::core_runtime_config pc = cc;
pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE;
@ -449,7 +433,7 @@ bool test_generator::build_wallets(const blockchain_vector& blockchain,
pc.hard_forks = m_hardforks;
pc.get_core_time = test_core_time::get_time;
wallets.back()->set_core_runtime_config(pc);
wallets.back().wallet->set_core_runtime_config(pc);
}
for (auto& w : wallets)
@ -474,7 +458,7 @@ bool test_generator::build_wallets(const blockchain_vector& blockchain,
bdde.txs_ptr.push_back(tx_ptr);
}
w->process_new_blockchain_entry(b->b, bdde, currency::get_block_hash(b->b), height);
w.wallet->process_new_blockchain_entry(b->b, bdde, currency::get_block_hash(b->b), height);
}
}
return true;
@ -539,12 +523,13 @@ bool test_generator::find_kernel(const std::list<currency::account_base>& accs,
//lets try to find block
for (size_t wallet_index = 0, size = wallets.size(); wallet_index < size; ++wallet_index)
{
std::shared_ptr<tools::wallet2> w = wallets[wallet_index];
std::shared_ptr<tools::wallet2> w = wallets[wallet_index].wallet;
wallets[wallet_index].mining_context = AUTO_VAL_INIT_T(tools::wallet2::mining_context);
tools::wallet2::mining_context& context = wallets[wallet_index].mining_context;
//set m_last_pow_block_h to big value, to let wallet to use any available outputs, including the those which is not behind last pow block
if (m_ignore_last_pow_in_wallets)
w->m_last_pow_block_h = CURRENCY_MAX_BLOCK_NUMBER;
tools::wallet2::mining_context context = AUTO_VAL_INIT(context);
w->fill_mining_context(context);
std::atomic<bool> stop(false);

View file

@ -372,7 +372,13 @@ public:
typedef std::unordered_map<crypto::hash, std::vector<uint64_t> > tx_global_indexes;
typedef std::vector<const block_info*> blockchain_vector;
typedef std::vector<std::shared_ptr<tools::wallet2> > wallets_vector;
struct gen_wallet_info
{
tools::wallet2::mining_context mining_context;
std::shared_ptr<tools::wallet2> wallet;
};
typedef std::vector<gen_wallet_info> wallets_vector;
enum block_fields
@ -430,7 +436,8 @@ public:
bool sign_block(currency::block& b,
currency::pos_entry& pe,
tools::wallet2& w,
tools::wallet2& w,
const tools::wallet2::mining_context& mining_context,
const blockchain_vector& blocks,
const outputs_index& oi);

View file

@ -658,7 +658,7 @@ int main(int argc, char* argv[])
log_space::log_singletone::get_default_log_file().c_str(),
log_space::log_singletone::get_default_log_folder().c_str());
log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,p2p,wallet");
log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,p2p,wallet", false);
tools::signal_handler::install_fatal([](int sig_number, void* address) {
LOG_ERROR("\n\nFATAL ERROR\nsig: " << sig_number << ", address: " << address);
@ -1061,14 +1061,8 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(zarcanum_basic_test);
//stop_on_first_fail = true;
//for (size_t i = 0; i != 100; i++)
//{
multiassets_basic_test::ts_starter = 0;
GENERATE_AND_PLAY(multiassets_basic_test);
//}
GENERATE_AND_PLAY(multiassets_basic_test);
//GENERATE_AND_PLAY(zarcanum_test_n_inputs_validation);
// GENERATE_AND_PLAY(gen_block_reward);
// END OF TESTS */

View file

@ -47,9 +47,9 @@ bool wallet_test::check_balance_via_build_wallets(currency::core& c, size_t ev_i
std::list<account_base> accounts(1, acc);
test_generator::wallets_vector w;
r = generator.build_wallets(get_block_hash(*top_block), accounts, w, c.get_blockchain_storage().get_core_runtime_config());
CHECK_AND_ASSERT_MES(r && w.size() == 1 && w[0] != 0, false, "check_balance: failed to build wallets");
CHECK_AND_ASSERT_MES(r && w.size() == 1 && w[0].wallet != 0, false, "check_balance: failed to build wallets");
if (!check_balance_via_wallet(*w[0], epee::string_tools::num_to_string_fast(pcb.account_index).c_str(), pcb.total_balance, pcb.mined_balance, pcb.unlocked_balance, pcb.awaiting_in, pcb.awaiting_out))
if (!check_balance_via_wallet(*w[0].wallet, epee::string_tools::num_to_string_fast(pcb.account_index).c_str(), pcb.total_balance, pcb.mined_balance, pcb.unlocked_balance, pcb.awaiting_in, pcb.awaiting_out))
return false;
return true;

View file

@ -8,6 +8,8 @@
#include "wallet_test_core_proxy.h"
#include "random_helper.h"
#include "tx_builder.h"
#define AMOUNT_TO_TRANSFER_ZARCANUM_BASIC (TESTS_DEFAULT_FEE*10)
@ -52,6 +54,7 @@ bool zarcanum_basic_test::c1(currency::core& c, size_t ev_index, const std::vect
account_base alice_acc;
alice_acc.generate();
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, alice_acc);
//pass over hardfork
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 2);
@ -165,3 +168,62 @@ bool zarcanum_basic_test::c1(currency::core& c, size_t ev_index, const std::vect
return true;
}
zarcanum_test_n_inputs_validation::zarcanum_test_n_inputs_validation()
{
REGISTER_CALLBACK_METHOD(zarcanum_basic_test, configure_core);
m_hardforks.set_hardfork_height(1, 1);
m_hardforks.set_hardfork_height(2, 1);
m_hardforks.set_hardfork_height(3, 1);
m_hardforks.set_hardfork_height(4, 12);
}
bool zarcanum_test_n_inputs_validation::generate(std::vector<test_event_entry>& events) const
{
uint64_t ts_start = 1338224400;
GENERATE_ACCOUNT(miner_account);
MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
destinations.resize(1);
tx_builder builder;
builder.step1_init(TRANSACTION_VERSION_PRE_HF4);
builder.step2_fill_inputs(miner_account.get_keys(), sources);
builder.step3_fill_outputs(destinations);
builder.step4_calc_hash();
builder.step5_sign(sources);
// DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(builder.m_tx);
MAKE_NEXT_BLOCK_TX1(events, blk_11, blk_0r, miner_account, builder.m_tx);
REWIND_BLOCKS_N(events, blk_14, blk_11, miner_account, 4);
sources.clear();
destinations.clear();
fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
destinations.resize(1);
tx_builder builder2;
//TODO: implement configuring for zarcanum type outputs
builder2.step1_init(TRANSACTION_VERSION_POST_HF4);
builder2.step2_fill_inputs(miner_account.get_keys(), sources);
builder2.step3_fill_outputs(destinations);
builder2.step4_calc_hash();
builder2.step5_sign(sources);
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(builder2.m_tx);
REWIND_BLOCKS_N(events, blk_16, blk_14, miner_account, 2);
return true;
}

View file

@ -14,3 +14,11 @@ struct zarcanum_basic_test : public wallet_test
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};
struct zarcanum_test_n_inputs_validation : public wallet_test
{
zarcanum_test_n_inputs_validation();
bool generate(std::vector<test_event_entry>& events) const;
};

View file

@ -64,7 +64,7 @@ TEST(ml2s, hs)
x = 0;
crypto::hash h;
scalar_t r;
//scalar_t r;
sha3(0, 0, &h, sizeof h);
LOG_PRINT("SHA3() -> " << h, LOG_LEVEL_0);

View file

@ -986,7 +986,7 @@ namespace db_test
bool r = false;
epee::shared_recursive_mutex rw_lock;
epee::log_space::log_singletone::enable_channels("lmdb");
epee::log_space::log_singletone::enable_channels("lmdb", false);
static const uint64_t buffer_size = 64 * 1024; // 64 KB
static const uint64_t db_total_size = static_cast<uint64_t>(2.1 * 1024 * 1024 * 1024); // 2.1 GB -- a bit more than 2GB to test 2GB boundary