forked from lthn/blockchain
merge from zarcanum
This commit is contained in:
commit
c9255c33b8
47 changed files with 1888 additions and 899 deletions
|
|
@ -94,6 +94,27 @@ namespace crypto
|
|||
END_BOOST_SERIALIZATION()
|
||||
};
|
||||
|
||||
struct CLSAG_GGXG_signature_serialized : public CLSAG_GGXG_signature
|
||||
{
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(c)
|
||||
FIELD((std::vector<scalar_t>&)(r_g))
|
||||
FIELD((std::vector<scalar_t>&)(r_x))
|
||||
FIELD(K1)
|
||||
FIELD(K2)
|
||||
FIELD(K3)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_BOOST_SERIALIZATION()
|
||||
BOOST_SERIALIZE(c)
|
||||
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_g))
|
||||
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_x))
|
||||
BOOST_SERIALIZE(K1)
|
||||
BOOST_SERIALIZE(K2)
|
||||
BOOST_SERIALIZE(K3)
|
||||
END_BOOST_SERIALIZATION()
|
||||
};
|
||||
|
||||
} // namespace crypto
|
||||
|
||||
BLOB_SERIALIZER(crypto::chacha8_iv);
|
||||
|
|
|
|||
|
|
@ -9,12 +9,15 @@
|
|||
//#include "misc_log_ex.h"
|
||||
#include "../currency_core/crypto_config.h"
|
||||
|
||||
DISABLE_GCC_AND_CLANG_WARNING(unused-function)
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
#define DBG_VAL_PRINT(x) (void(0)) // std::cout << #x ": " << x << std::endl
|
||||
#define DBG_PRINT(x) (void(0)) // std::cout << x << std::endl
|
||||
|
||||
//static std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return o << pod_to_hex(v); }
|
||||
static std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return o << pod_to_hex(v); }
|
||||
static std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return o << pod_to_hex(v); }
|
||||
|
||||
bool generate_CLSAG_GG(const hash& m, const std::vector<CLSAG_GG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const key_image& ki,
|
||||
const scalar_t& secret_x, const scalar_t& secret_f, uint64_t secret_index, CLSAG_GG_signature& sig)
|
||||
|
|
@ -183,7 +186,14 @@ namespace crypto
|
|||
// calculate key images
|
||||
point_t ki_base = hash_helper_t::hp(ring[secret_index].stealth_address);
|
||||
point_t key_image = secret_0_xp * ki_base;
|
||||
|
||||
#ifndef NDEBUG
|
||||
CRYPTO_CHECK_AND_THROW_MES(key_image == point_t(ki), "key image 0 mismatch");
|
||||
CRYPTO_CHECK_AND_THROW_MES((secret_0_xp * c_point_G).to_public_key() == ring[secret_index].stealth_address, "secret_0_xp mismatch");
|
||||
CRYPTO_CHECK_AND_THROW_MES(secret_1_f * c_point_G == 8 * point_t(ring[secret_index].amount_commitment) - pseudo_out_amount_commitment, "secret_1_f mismatch");
|
||||
CRYPTO_CHECK_AND_THROW_MES(secret_3_q * c_point_G == 8 * point_t(ring[secret_index].concealing_point), "secret_3_q mismatch");
|
||||
CRYPTO_CHECK_AND_THROW_MES(secret_2_x * c_point_X == extended_amount_commitment - 8 * point_t(ring[secret_index].amount_commitment) - 8 * point_t(ring[secret_index].concealing_point), "secret_3_q mismatch");
|
||||
#endif
|
||||
|
||||
point_t K1_div8 = (c_scalar_1div8 * secret_1_f) * ki_base;
|
||||
K1_div8.to_public_key(sig.K1);
|
||||
|
|
@ -208,6 +218,7 @@ namespace crypto
|
|||
hsc.add_pub_key(ring[i].stealth_address);
|
||||
hsc.add_pub_key(ring[i].amount_commitment);
|
||||
hsc.add_pub_key(ring[i].concealing_point);
|
||||
DBG_PRINT("ring[" << i << "]: sa:" << ring[i].stealth_address << ", ac:" << ring[i].amount_commitment << ", cp:" << ring[i].concealing_point);
|
||||
}
|
||||
hsc.add_point(c_scalar_1div8 * pseudo_out_amount_commitment);
|
||||
hsc.add_point(c_scalar_1div8 * extended_amount_commitment);
|
||||
|
|
@ -282,21 +293,33 @@ namespace crypto
|
|||
|
||||
// calculate aggregate key image (layers 0, 1, 3; G component)
|
||||
point_t W_key_image_g = agg_coeff_0 * key_image + agg_coeff_1 * K1 + /*agg_coeff_2 * K2 +*/ agg_coeff_3 * K3;
|
||||
DBG_VAL_PRINT(key_image);
|
||||
DBG_VAL_PRINT(K1);
|
||||
DBG_VAL_PRINT(K3);
|
||||
DBG_VAL_PRINT(W_key_image_g);
|
||||
|
||||
// calculate aggregate key image (layer 2; X component)
|
||||
point_t W_key_image_x = agg_coeff_2 * K2;
|
||||
DBG_VAL_PRINT(K2);
|
||||
DBG_VAL_PRINT(W_key_image_x);
|
||||
|
||||
#ifndef NDEBUG
|
||||
CRYPTO_CHECK_AND_THROW_MES(w_sec_key_g * c_point_G == W_pub_keys_g[secret_index], "aggregated secret G and pub key mismatch");
|
||||
CRYPTO_CHECK_AND_THROW_MES(w_sec_key_g * hash_helper_t::hp(ring[secret_index].stealth_address) == W_key_image_g, "aggregated secret G and key image mismatch");
|
||||
CRYPTO_CHECK_AND_THROW_MES(w_sec_key_x * c_point_X == W_pub_keys_x[secret_index], "aggregated secret X and pub key mismatch");
|
||||
CRYPTO_CHECK_AND_THROW_MES(w_sec_key_x * hash_helper_t::hp(ring[secret_index].stealth_address) == W_key_image_x, "aggregated secret X and key image mismatch");
|
||||
#endif
|
||||
|
||||
// initial commitment
|
||||
scalar_t alpha_g = scalar_t::random(); // randomness for layers 0,1,3
|
||||
scalar_t alpha_x = scalar_t::random(); // randomness for layer 2
|
||||
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_CHALLENGE);
|
||||
hsc.add_hash(input_hash);
|
||||
hsc.add_point(alpha_g * c_point_G); DBG_VAL_PRINT(alpha_g * c_point_G);
|
||||
hsc.add_point(alpha_g * ki_base); DBG_VAL_PRINT(alpha_g * ki_base);
|
||||
hsc.add_point(alpha_x * c_point_X); DBG_VAL_PRINT(alpha_x * c_point_X);
|
||||
hsc.add_point(alpha_x * ki_base); DBG_VAL_PRINT(alpha_x * ki_base);
|
||||
hsc.add_point(alpha_g * c_point_G);
|
||||
hsc.add_point(alpha_g * ki_base);
|
||||
hsc.add_point(alpha_x * c_point_X);
|
||||
hsc.add_point(alpha_x * ki_base);
|
||||
//DBG_PRINT("c[" << secret_index << "] = Hs(ih, " << alpha_g * c_point_G << ", " << alpha_g * ki_base << ", " << alpha_x * c_point_X << ", " << alpha_x * ki_base << ")");
|
||||
scalar_t c_prev = hsc.calc_hash(); // c_{secret_index + 1}
|
||||
|
||||
sig.r_g.clear();
|
||||
|
|
@ -334,8 +357,8 @@ namespace crypto
|
|||
}
|
||||
|
||||
|
||||
bool verify_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment, const public_key& extended_amount_commitment, const key_image& ki,
|
||||
const CLSAG_GGXG_signature& sig)
|
||||
bool verify_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment, const public_key& extended_amount_commitment,
|
||||
const key_image& ki, const CLSAG_GGXG_signature& sig)
|
||||
{
|
||||
DBG_PRINT("== verify_CLSAG_GGXG ==");
|
||||
size_t ring_size = ring.size();
|
||||
|
|
@ -360,6 +383,7 @@ namespace crypto
|
|||
hsc.add_pub_key(ring[i].stealth_address);
|
||||
hsc.add_pub_key(ring[i].amount_commitment);
|
||||
hsc.add_pub_key(ring[i].concealing_point);
|
||||
DBG_PRINT("ring[" << i << "]: sa:" << ring[i].stealth_address << ", ac:" << ring[i].amount_commitment << ", cp:" << ring[i].concealing_point);
|
||||
}
|
||||
hsc.add_pub_key(pseudo_out_amount_commitment);
|
||||
hsc.add_pub_key(extended_amount_commitment);
|
||||
|
|
@ -429,11 +453,14 @@ namespace crypto
|
|||
agg_coeff_0 * key_image +
|
||||
agg_coeff_1 * point_t(sig.K1).modify_mul8() +
|
||||
agg_coeff_3 * point_t(sig.K3).modify_mul8();
|
||||
DBG_VAL_PRINT(point_t(sig.K1).modify_mul8());
|
||||
DBG_VAL_PRINT(point_t(sig.K3).modify_mul8());
|
||||
DBG_VAL_PRINT(W_key_image_g);
|
||||
|
||||
// calculate aggregate key image (layer 2; X component)
|
||||
point_t W_key_image_x =
|
||||
agg_coeff_2 * point_t(sig.K2).modify_mul8();
|
||||
DBG_VAL_PRINT(point_t(sig.K2).modify_mul8());
|
||||
DBG_VAL_PRINT(W_key_image_x);
|
||||
|
||||
|
||||
|
|
@ -449,6 +476,7 @@ namespace crypto
|
|||
hsc.add_point(sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x);
|
||||
c_prev = hsc.calc_hash(); // c_{i + 1}
|
||||
DBG_PRINT("c[" << i + 1 << "] = " << c_prev);
|
||||
//DBG_PRINT("c[" << i + 1 << "] = Hs(ih, " << sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i] << ", " << sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g << ", " << sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i] << ", " << sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x << ")");
|
||||
}
|
||||
|
||||
return c_prev == sig.c;
|
||||
|
|
|
|||
|
|
@ -32,15 +32,18 @@ namespace crypto
|
|||
struct CLSAG_GG_input_ref_t
|
||||
{
|
||||
CLSAG_GG_input_ref_t(const public_key& stealth_address, const public_key& amount_commitment)
|
||||
: stealth_address(stealth_address), amount_commitment(amount_commitment) {}
|
||||
: stealth_address(stealth_address), amount_commitment(amount_commitment)
|
||||
{}
|
||||
|
||||
const public_key& stealth_address; // not premultiplied by 1/8, TODO @#@#: make sure it's okay
|
||||
const public_key& amount_commitment; // multiplied by 1/8
|
||||
const public_key& stealth_address; // P, not premultiplied by 1/8, TODO @#@#: make sure it's okay
|
||||
const public_key& amount_commitment; // A, premultiplied by 1/8
|
||||
};
|
||||
|
||||
// pseudo_out_amount_commitment -- not premultiplied by 1/8
|
||||
bool generate_CLSAG_GG(const hash& m, const std::vector<CLSAG_GG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const key_image& ki,
|
||||
const scalar_t& secret_x, const scalar_t& secret_f, uint64_t secret_index, CLSAG_GG_signature& sig);
|
||||
|
||||
// pseudo_out_amount_commitment -- premultiplied by 1/8
|
||||
bool verify_CLSAG_GG(const hash& m, const std::vector<CLSAG_GG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment, const key_image& ki,
|
||||
const CLSAG_GG_signature& sig);
|
||||
|
||||
|
|
@ -71,10 +74,15 @@ namespace crypto
|
|||
const public_key& concealing_point; // Q, premultiplied by 1/8
|
||||
};
|
||||
|
||||
// pseudo_out_amount_commitment -- not premultiplied by 1/8
|
||||
// extended_amount_commitment -- not premultiplied by 1/8
|
||||
bool generate_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const point_t& extended_amount_commitment, const key_image& ki,
|
||||
const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_x, const scalar_t& secret_3_q, uint64_t secret_index, CLSAG_GGXG_signature& sig);
|
||||
|
||||
bool verify_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment, const public_key& extended_amount_commitment, const key_image& ki,
|
||||
const CLSAG_GGXG_signature& sig);
|
||||
// pseudo_out_amount_commitment -- premultiplied by 1/8
|
||||
// extended_amount_commitment -- premultiplied by 1/8
|
||||
// may throw an exception TODO @#@# make sure it's okay
|
||||
bool verify_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment,
|
||||
const public_key& extended_amount_commitment, const key_image& ki, const CLSAG_GGXG_signature& sig);
|
||||
|
||||
} // namespace crypto
|
||||
|
|
|
|||
|
|
@ -137,15 +137,15 @@ namespace crypto
|
|||
const point_t& bpp_crypto_trait_zano<N, values_max>::bpp_H = c_point_G;
|
||||
|
||||
template<size_t N, size_t values_max>
|
||||
const point_t& bpp_crypto_trait_zano<N, values_max>::bpp_H2 = c_point_H2;
|
||||
const point_t& bpp_crypto_trait_zano<N, values_max>::bpp_H2 = c_point_X;
|
||||
|
||||
|
||||
// efficient multiexponentiation (naive stub implementation atm, TODO)
|
||||
template<typename CT>
|
||||
bool multiexp_and_check_being_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(g_scalars.size() < CT::c_bpp_mn_max, false, "g_scalars oversized");
|
||||
CHECK_AND_ASSERT_MES(h_scalars.size() < CT::c_bpp_mn_max, false, "h_scalars oversized");
|
||||
CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized");
|
||||
CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized");
|
||||
|
||||
point_t result = summand;
|
||||
|
||||
|
|
|
|||
|
|
@ -45,9 +45,8 @@ namespace crypto
|
|||
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
|
||||
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& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment,
|
||||
bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector<CLSAG_GGXG_input_ref_t>& ring,
|
||||
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 */)
|
||||
|
|
@ -117,7 +116,7 @@ namespace crypto
|
|||
const scalar_vec_t masks2 = { bx }; // X component
|
||||
const std::vector<const public_key*> E_1div8_vec_ptr = { &result.E };
|
||||
|
||||
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);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_gen<bpp_crypto_trait_zano<128>>(values, masks, masks2, E_1div8_vec_ptr, result.E_range_proof), 10);
|
||||
|
||||
// = four-layers ring signature data outline =
|
||||
// (j in [0, ring_size-1])
|
||||
|
|
@ -144,6 +143,10 @@ namespace crypto
|
|||
// Q[j]
|
||||
// layer 3 secret (with respect to G)
|
||||
// secret_q
|
||||
|
||||
point_t pseudo_out_amount_commitment = a * crypto::c_point_H + pseudo_out_blinding_mask * crypto::c_point_G;
|
||||
result.pseudo_out_amount_commitment = (crypto::c_scalar_1div8 * pseudo_out_amount_commitment).to_public_key();
|
||||
|
||||
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,
|
||||
|
|
@ -152,11 +155,29 @@ namespace crypto
|
|||
|
||||
return true;
|
||||
}
|
||||
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
|
||||
|
||||
|
||||
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 */)
|
||||
|
||||
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
|
||||
if (!(cond)) { LOG_PRINT_RED("zarcanum_verify_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_verify_proof(const hash& m, const hash& kernel_hash, const std::vector<CLSAG_GGXG_input_ref_t>& ring,
|
||||
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
|
||||
const zarcanum_proof& sig, uint8_t* p_err /* = nullptr */)
|
||||
{
|
||||
return false;
|
||||
bool r = false;
|
||||
|
||||
// TODO @#@#
|
||||
|
||||
std::vector<point_t> E_for_range_proof = { point_t(sig.E) };
|
||||
std::vector<bppe_sig_commit_ref_t> range_proofs = { bppe_sig_commit_ref_t(sig.E_range_proof, E_for_range_proof) };
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_verify<bpp_crypto_trait_zano<128>>(range_proofs), 10);
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(verify_CLSAG_GGXG(m, ring, sig.pseudo_out_amount_commitment, sig.C, stake_ki, sig.clsag_ggxg), 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -44,12 +44,14 @@ namespace crypto
|
|||
CLSAG_GGXG_signature clsag_ggxg;
|
||||
};
|
||||
|
||||
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,
|
||||
bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXG_input_ref_t>& ring,
|
||||
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);
|
||||
bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector<crypto::CLSAG_GGXG_input_ref_t>& ring,
|
||||
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
|
||||
const zarcanum_proof& sig, uint8_t* p_err = nullptr);
|
||||
|
||||
} // namespace crypto
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "tx_semantic_validation.h"
|
||||
#include "crypto/RIPEMD160_helper.h"
|
||||
#include "crypto/bitcoin/sha256_helper.h"
|
||||
#include "crypto_config.h"
|
||||
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
|
|
@ -1280,7 +1281,10 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t
|
|||
}
|
||||
if (pos)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "coinstake transaction in the block has the wrong type");
|
||||
if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) // TODO @#@# consider moving to validate_tx_for_hardfork_specific_terms
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_zc_input), false, "coinstake tx has incorrect type of input #1: " << b.miner_tx.vin[1].type().name());
|
||||
else
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "coinstake tx has incorrect type of input #1: " << b.miner_tx.vin[1].type().name());
|
||||
}
|
||||
|
||||
if (m_core_runtime_config.is_hardfork_active_for_height(1, height))
|
||||
|
|
@ -1315,11 +1319,19 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t
|
|||
return false;
|
||||
}
|
||||
|
||||
if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM))
|
||||
if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) // TODO @#@# consider moving to validate_tx_for_hardfork_specific_terms
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.attachment.size() == 2, false, "coinbase transaction has incorrect number of attachments (" << b.miner_tx.attachment.size() << "), expected 2");
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.attachment[0].type() == typeid(zc_outs_range_proof), false, "coinbase transaction wrong attachment #0 type (expected: zc_outs_range_proof)");
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.attachment[1].type() == typeid(zc_balance_proof), false, "coinbase transaction wrong attachmenttype #1 (expected: zc_balance_proof)");
|
||||
if (pos)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.attachment.size() == 1, false, "coinbase transaction has incorrect number of attachments (" << b.miner_tx.attachment.size() << "), expected 2");
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.attachment[0].type() == typeid(zc_outs_range_proof), false, "coinbase transaction wrong attachment #0 type (expected: zc_outs_range_proof)");
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.attachment.size() == 2, false, "coinbase transaction has incorrect number of attachments (" << b.miner_tx.attachment.size() << "), expected 2");
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.attachment[0].type() == typeid(zc_outs_range_proof), false, "coinbase transaction wrong attachment #0 type (expected: zc_outs_range_proof)");
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.attachment[1].type() == typeid(zc_balance_proof), false, "coinbase transaction wrong attachmenttype #1 (expected: zc_balance_proof)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1394,24 +1406,25 @@ uint64_t blockchain_storage::get_current_comulative_blocksize_limit() const
|
|||
return m_db_current_block_cumul_sz_limit;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::create_block_template(block& b,
|
||||
const account_public_address& miner_address,
|
||||
bool blockchain_storage::create_block_template(const account_public_address& miner_address,
|
||||
const blobdata& ex_nonce,
|
||||
block& b,
|
||||
wide_difficulty_type& diffic,
|
||||
uint64_t& height,
|
||||
const blobdata& ex_nonce) const
|
||||
uint64_t& height) const
|
||||
{
|
||||
return create_block_template(b, miner_address, miner_address, diffic, height, ex_nonce, false, pos_entry());
|
||||
return create_block_template(miner_address, miner_address, ex_nonce, false, pos_entry(), nullptr, b, diffic, height);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::create_block_template(block& b,
|
||||
const account_public_address& miner_address,
|
||||
bool blockchain_storage::create_block_template(const account_public_address& miner_address,
|
||||
const account_public_address& stakeholder_address,
|
||||
wide_difficulty_type& diffic,
|
||||
uint64_t& height,
|
||||
const blobdata& ex_nonce,
|
||||
bool pos,
|
||||
const blobdata& ex_nonce,
|
||||
bool pos,
|
||||
const pos_entry& pe,
|
||||
fill_block_template_func_t custom_fill_block_template_func /* = nullptr */) const
|
||||
fill_block_template_func_t custom_fill_block_template_func,
|
||||
block& b,
|
||||
wide_difficulty_type& diffic,
|
||||
uint64_t& height,
|
||||
crypto::scalar_t* blinding_mask_sum_ptr /* = nullptr */) const
|
||||
{
|
||||
create_block_template_params params = AUTO_VAL_INIT(params);
|
||||
params.miner_address = miner_address;
|
||||
|
|
@ -1422,9 +1435,12 @@ bool blockchain_storage::create_block_template(block& b,
|
|||
params.pcustom_fill_block_template_func = custom_fill_block_template_func;
|
||||
create_block_template_response resp = AUTO_VAL_INIT(resp);
|
||||
bool r = create_block_template(params, resp);
|
||||
|
||||
b = resp.b;
|
||||
diffic = resp.diffic;
|
||||
height = resp.height;
|
||||
height = resp.height;
|
||||
if (blinding_mask_sum_ptr)
|
||||
*blinding_mask_sum_ptr = resp.blinding_mask_sum;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -1508,7 +1524,8 @@ bool blockchain_storage::create_block_template(const create_block_template_param
|
|||
ex_nonce,
|
||||
CURRENCY_MINER_TX_MAX_OUTS,
|
||||
pos,
|
||||
pe);
|
||||
pe,
|
||||
&resp.blinding_mask_sum);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance");
|
||||
uint64_t coinbase_size = get_object_blobsize(b.miner_tx);
|
||||
// "- 100" - to reserve room for PoS additions into miner tx
|
||||
|
|
@ -5419,7 +5436,36 @@ bool blockchain_storage::validate_pos_block(const block& b,
|
|||
|
||||
if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM))
|
||||
{
|
||||
return false; // not implemented yet, TODO @#@#
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.version > TRANSACTION_VERSION_PRE_HF4, false, "Zarcanum PoS: miner tx with version " << b.miner_tx.version << " is not allowed");
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_zc_input), false, "incorrect input 1 type: " << b.miner_tx.vin[1].type().name() << ", txin_zc_input expected");
|
||||
const txin_zc_input& stake_input = boost::get<txin_zc_input>(b.miner_tx.vin[1]);
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1, false, "incorrect number of stake input signatures: " << b.miner_tx.signatures.size());
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.signatures[0].type() == typeid(zarcanum_sig), false, "incorrect sig 0 type: " << b.miner_tx.signatures[0].type().name());
|
||||
const zarcanum_sig& sig = boost::get<zarcanum_sig>(b.miner_tx.signatures[0]);
|
||||
const crypto::hash miner_tx_hash = get_transaction_hash(b.miner_tx);
|
||||
|
||||
// TODO @#@# do general input check for main chain blocks only?
|
||||
uint64_t max_related_block_height = 0;
|
||||
std::vector<crypto::public_key> dummy_output_keys; // won't be used
|
||||
uint64_t dummy_source_max_unlock_time_for_pos_coinbase_dummy = 0; // won't be used
|
||||
scan_for_keys_context scan_contex = AUTO_VAL_INIT(scan_contex);
|
||||
r = get_output_keys_for_input_with_checks(b.miner_tx, stake_input, dummy_output_keys, max_related_block_height, dummy_source_max_unlock_time_for_pos_coinbase_dummy, scan_contex);
|
||||
CHECK_AND_ASSERT_MES(r, false, "get_output_keys_for_input_with_checks failed for stake input");
|
||||
CHECK_AND_ASSERT_MES(scan_contex.zc_outs.size() == stake_input.key_offsets.size(), false, "incorrect number of referenced outputs found: " << scan_contex.zc_outs.size() << ", while " << stake_input.key_offsets.size() << " is expected.");
|
||||
// build a ring of references
|
||||
vector<crypto::CLSAG_GGXG_input_ref_t> ring;
|
||||
ring.reserve(scan_contex.zc_outs.size());
|
||||
for(auto& zc_out : scan_contex.zc_outs)
|
||||
ring.emplace_back(zc_out.stealth_address, zc_out.amount_commitment, zc_out.concealing_point);
|
||||
|
||||
crypto::scalar_t last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, sm.last_pow_id);
|
||||
|
||||
uint8_t err = 0;
|
||||
r = crypto::zarcanum_verify_proof(miner_tx_hash, kernel_hash, ring, last_pow_block_id_hashed, stake_input.k_image, sig, &err);
|
||||
CHECK_AND_ASSERT_MES(r, false, "zarcanum_verify_proof failed with code " << err);
|
||||
|
||||
final_diff = basic_diff; // just for logs
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -5703,17 +5749,24 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
m_is_in_checkpoint_zone = false;
|
||||
|
||||
crypto::hash proof_hash = null_hash;
|
||||
uint64_t pos_coinstake_amount = 0;
|
||||
uint64_t pos_coinstake_amount = UINT64_MAX;
|
||||
wide_difficulty_type this_coin_diff = 0;
|
||||
bool is_pos_bl = is_pos_block(bl);
|
||||
//check if PoS allowed in this height
|
||||
CHECK_AND_ASSERT_MES_CUSTOM(!(is_pos_bl && m_db_blocks.size() < m_core_runtime_config.pos_minimum_heigh), false, bvc.m_verification_failed = true, "PoS block not allowed on height " << m_db_blocks.size());
|
||||
|
||||
if (!prevalidate_miner_transaction(bl, m_db_blocks.size(), is_pos_bl))
|
||||
{
|
||||
LOG_PRINT_L0("Block with id: " << id << " @ " << height << " failed to pass miner tx prevalidation");
|
||||
bvc.m_verification_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//check proof of work
|
||||
TIME_MEASURE_START_PD(target_calculating_time_2);
|
||||
wide_difficulty_type current_diffic = get_next_diff_conditional(is_pos_bl);
|
||||
CHECK_AND_ASSERT_MES_CUSTOM(current_diffic, false, bvc.m_verification_failed = true, "!!!!!!!!! difficulty overhead !!!!!!!!!");
|
||||
TIME_MEASURE_FINISH_PD(target_calculating_time_2);
|
||||
TIME_MEASURE_FINISH_PD(target_calculating_time_2);
|
||||
|
||||
TIME_MEASURE_START_PD(longhash_calculating_time_3);
|
||||
if (is_pos_bl)
|
||||
|
|
@ -5737,16 +5790,10 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
return false;
|
||||
}
|
||||
}
|
||||
TIME_MEASURE_FINISH_PD(longhash_calculating_time_3);
|
||||
TIME_MEASURE_FINISH_PD(longhash_calculating_time_3);
|
||||
|
||||
size_t aliases_count_befor_block = m_db_aliases.size();
|
||||
|
||||
if (!prevalidate_miner_transaction(bl, m_db_blocks.size(), is_pos_bl))
|
||||
{
|
||||
LOG_PRINT_L0("Block with id: " << id << " @ " << height << " failed to pass miner tx prevalidation");
|
||||
bvc.m_verification_failed = true;
|
||||
return false;
|
||||
}
|
||||
size_t cumulative_block_size = 0;
|
||||
size_t coinbase_blob_size = get_object_blobsize(bl.miner_tx);
|
||||
|
||||
|
|
@ -6049,7 +6096,12 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
{ // PoS
|
||||
int64_t actual_ts = get_block_datetime(bei.bl); // signed int is intentionally used here
|
||||
int64_t ts_diff = actual_ts - m_core_runtime_config.get_core_time();
|
||||
powpos_str_entry << "PoS:\t" << proof_hash << ", stake amount: " << print_money_brief(pos_coinstake_amount) << ", final_difficulty: " << this_coin_diff;
|
||||
powpos_str_entry << "PoS:\t" << proof_hash << ", stake amount: ";
|
||||
if (pos_coinstake_amount != UINT64_MAX)
|
||||
powpos_str_entry << print_money_brief(pos_coinstake_amount);
|
||||
else
|
||||
powpos_str_entry << "hidden";
|
||||
powpos_str_entry << ", final_difficulty: " << this_coin_diff;
|
||||
timestamp_str_entry << ", actual ts: " << actual_ts << " (diff: " << std::showpos << ts_diff << "s) block ts: " << std::noshowpos << bei.bl.timestamp << " (shift: " << std::showpos << static_cast<int64_t>(bei.bl.timestamp) - actual_ts << ")";
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -260,8 +260,8 @@ namespace currency
|
|||
wide_difficulty_type get_cached_next_difficulty(bool pos) const;
|
||||
|
||||
|
||||
bool create_block_template(block& b, const account_public_address& miner_address, const account_public_address& stakeholder_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe, fill_block_template_func_t custom_fill_block_template_func = nullptr) const;
|
||||
bool create_block_template(block& b, const account_public_address& miner_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce) const;
|
||||
bool create_block_template(const account_public_address& miner_address, const blobdata& ex_nonce, block& b, wide_difficulty_type& di, uint64_t& height) const;
|
||||
bool create_block_template(const account_public_address& miner_address, const account_public_address& stakeholder_address, const blobdata& ex_nonce, bool pos, const pos_entry& pe, fill_block_template_func_t custom_fill_block_template_func, block& b, wide_difficulty_type& di, uint64_t& height, crypto::scalar_t* blinding_mask_sum_ptr = nullptr) const;
|
||||
bool create_block_template(const create_block_template_params& params, create_block_template_response& resp) const;
|
||||
|
||||
bool have_block(const crypto::hash& id) const;
|
||||
|
|
@ -332,6 +332,9 @@ namespace currency
|
|||
bool is_tx_expired(const transaction& tx) const;
|
||||
std::shared_ptr<const transaction_chain_entry> find_key_image_and_related_tx(const crypto::key_image& ki, crypto::hash& id_result) const;
|
||||
|
||||
// returns true as soon as the hardfork is active for the NEXT upcoming block (not for the top block in the blockchain storage)
|
||||
bool is_hardfork_active(size_t hardfork_id) const;
|
||||
|
||||
wide_difficulty_type block_difficulty(size_t i)const;
|
||||
bool forecast_difficulty(std::vector<std::pair<uint64_t, wide_difficulty_type>> &out_height_2_diff_vector, bool pos) const;
|
||||
bool prune_aged_alt_blocks();
|
||||
|
|
@ -676,10 +679,6 @@ namespace currency
|
|||
bool is_output_allowed_for_input(const txout_htlc& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const;
|
||||
bool is_output_allowed_for_input(const tx_out_zarcanum& out, const txin_v& in_v) const;
|
||||
|
||||
// returns true as soon as the hardfork is active for the NEXT upcoming block (not for the top block in the blockchain storage)
|
||||
bool is_hardfork_active(size_t hardfork_id) const;
|
||||
|
||||
|
||||
|
||||
|
||||
//POS
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ namespace currency
|
|||
block b;
|
||||
wide_difficulty_type diffic;
|
||||
uint64_t height;
|
||||
crypto::scalar_t blinding_mask_sum; // sum of all the outputs' blinding masks
|
||||
};
|
||||
|
||||
typedef std::unordered_map<crypto::hash, transaction> transactions_map;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,13 @@ namespace currency
|
|||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(hardfork_id < m_total_count, "invalid hardfork id: " << hardfork_id);
|
||||
m_height_the_hardfork_n_active_after[hardfork_id] = height_the_hardfork_is_active_after;
|
||||
|
||||
// set all unset previous hardforks to this height
|
||||
for(size_t hid = hardfork_id - 1; hid + 1 != 0; --hid)
|
||||
{
|
||||
if (m_height_the_hardfork_n_active_after[hid] == CURRENCY_MAX_BLOCK_NUMBER)
|
||||
m_height_the_hardfork_n_active_after[hid] = height_the_hardfork_is_active_after;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_hardfork_active_for_height(size_t hardfork_id, uint64_t height) const
|
||||
|
|
@ -57,7 +64,7 @@ namespace currency
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint8_t get_block_major_version_by_height(uint64_t height)
|
||||
uint8_t get_block_major_version_by_height(uint64_t height) const
|
||||
{
|
||||
if (!this->is_hardfork_active_for_height(1, height))
|
||||
return BLOCK_MAJOR_VERSION_INITIAL;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#define CRYPTO_HDS_CLSAG_GGXG_CHALLENGE "ZANO_HDS_CLSAG_GGXG_CHALLENGE__"
|
||||
|
||||
#define CRYPTO_HDS_ZARCANUM_LAST_POW_HASH "ZANO_HDS_ZARCANUM_LAST_POW_HASH"
|
||||
#define CRYPTO_HDS_ZARCANUM_SECRET_Q "ZANO_HDS_ZARCANUM_SECRET_Q_____"
|
||||
#define CRYPTO_HDS_ZARCANUM_PROOF_HASH "ZANO_HDS_ZARCANUM_PROOF_HASH___"
|
||||
|
||||
#define CRYPTO_HDS_ASSET_CONTROL_KEY "ZANO_HDS_ASSET_CONTROL_KEY_____"
|
||||
|
|
|
|||
|
|
@ -493,13 +493,33 @@ namespace currency
|
|||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(d)
|
||||
FIELD(C)
|
||||
// TODO
|
||||
FIELD(C_prime);
|
||||
FIELD(E);
|
||||
FIELD(c);
|
||||
FIELD(y0);
|
||||
FIELD(y1);
|
||||
FIELD(y2);
|
||||
FIELD(y3);
|
||||
FIELD(y4);
|
||||
FIELD((crypto::bppe_signature_serialized&)E_range_proof);
|
||||
FIELD(pseudo_out_amount_commitment);
|
||||
FIELD((crypto::CLSAG_GGXG_signature_serialized&)clsag_ggxg);
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_BOOST_SERIALIZATION()
|
||||
BOOST_SERIALIZE(d)
|
||||
BOOST_SERIALIZE(C)
|
||||
// TODO
|
||||
BOOST_SERIALIZE(C_prime);
|
||||
BOOST_SERIALIZE(E);
|
||||
BOOST_SERIALIZE(c);
|
||||
BOOST_SERIALIZE(y0);
|
||||
BOOST_SERIALIZE(y1);
|
||||
BOOST_SERIALIZE(y2);
|
||||
BOOST_SERIALIZE(y3);
|
||||
BOOST_SERIALIZE(y4);
|
||||
BOOST_SERIALIZE((crypto::bppe_signature_serialized&)E_range_proof);
|
||||
BOOST_SERIALIZE(pseudo_out_amount_commitment);
|
||||
BOOST_SERIALIZE((crypto::CLSAG_GGXG_signature_serialized&)clsag_ggxg);
|
||||
END_BOOST_SERIALIZATION()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ namespace currency
|
|||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe)
|
||||
{
|
||||
return m_blockchain_storage.create_block_template(b, adr, stakeholder_address, diffic, height, ex_nonce, pos, pe);
|
||||
return m_blockchain_storage.create_block_template(adr, stakeholder_address, ex_nonce, pos, pe, nullptr, b, diffic, height);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_template(const create_block_template_params& params, create_block_template_response& resp)
|
||||
|
|
@ -511,11 +511,11 @@ namespace currency
|
|||
if (h > 0)
|
||||
{
|
||||
auto& crc = m_blockchain_storage.get_core_runtime_config();
|
||||
size_t hardfork_id_for_prev_block = crc.hard_forks.get_the_most_recent_hardfork_id_for_height(h - 1);
|
||||
size_t hardfork_id_for_curr_block = crc.hard_forks.get_the_most_recent_hardfork_id_for_height(h);
|
||||
size_t hardfork_id_for_prev_block = crc.hard_forks.get_the_most_recent_hardfork_id_for_height(h);
|
||||
size_t hardfork_id_for_curr_block = crc.hard_forks.get_the_most_recent_hardfork_id_for_height(h + 1);
|
||||
if (hardfork_id_for_prev_block != hardfork_id_for_curr_block)
|
||||
{
|
||||
LOG_PRINT_GREEN("Hardfork " << hardfork_id_for_curr_block << " activated at height " << h, LOG_LEVEL_0);
|
||||
LOG_PRINT_GREEN("Hardfork " << hardfork_id_for_curr_block << " has been activated after the block at height " << h, LOG_LEVEL_0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -183,10 +183,13 @@ namespace currency
|
|||
const account_public_address &stakeholder_address,
|
||||
transaction& tx,
|
||||
uint64_t tx_version,
|
||||
const blobdata& extra_nonce,
|
||||
size_t max_outs,
|
||||
bool pos,
|
||||
const pos_entry& pe)
|
||||
const blobdata& extra_nonce /* = blobdata() */,
|
||||
size_t max_outs /* = CURRENCY_MINER_TX_MAX_OUTS */,
|
||||
bool pos /* = false */,
|
||||
const pos_entry& pe /* = pos_entry() */, // only pe.stake_unlock_time and pe.stake_amount are used now, TODO: consider refactoring -- sowle
|
||||
crypto::scalar_t* blinding_masks_sum_ptr /* = nullptr */,
|
||||
const keypair* tx_one_time_key_to_use /* = nullptr */
|
||||
)
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
|
|
@ -248,7 +251,10 @@ namespace currency
|
|||
tx = AUTO_VAL_INIT_T(transaction);
|
||||
tx.version = tx_version;
|
||||
|
||||
keypair txkey = keypair::generate();
|
||||
keypair txkey_local{};
|
||||
if (!tx_one_time_key_to_use)
|
||||
txkey_local = keypair::generate();
|
||||
const keypair& txkey = tx_one_time_key_to_use ? *tx_one_time_key_to_use : txkey_local;
|
||||
add_tx_pub_key_to_extra(tx, txkey.pub);
|
||||
if (extra_nonce.size())
|
||||
if (!add_tx_extra_userdata(tx, extra_nonce))
|
||||
|
|
@ -269,26 +275,16 @@ namespace currency
|
|||
{
|
||||
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;
|
||||
// just placeholders, they will be filled in wallet2::prepare_and_sign_pos_block()
|
||||
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 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);
|
||||
stake_input.k_image = pe.keyimage;
|
||||
tx.vin.push_back(stake_input);
|
||||
//reserve place for ring signature
|
||||
NLSAG_sig nlsag;
|
||||
nlsag.s.resize(stake_input.key_offsets.size());
|
||||
tx.signatures.push_back(nlsag); // consider using emplace_back and avoid copying
|
||||
// just placeholders, they will be filled in wallet2::prepare_and_sign_pos_block()
|
||||
tx.vin.emplace_back(std::move(txin_to_key()));
|
||||
tx.signatures.emplace_back(std::move(NLSAG_sig()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -333,6 +329,9 @@ namespace currency
|
|||
set_tx_unlock_time(tx, height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
}
|
||||
|
||||
if (blinding_masks_sum_ptr)
|
||||
*blinding_masks_sum_ptr = blinding_masks_sum;
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
|
@ -387,6 +386,9 @@ namespace currency
|
|||
VARIANT_CASE_CONST(ZC_sig, zc_sig);
|
||||
sum_of_pseudo_out_amount_commitments += crypto::point_t(zc_sig.pseudo_out_amount_commitment); // *1/8
|
||||
++zc_sigs_count;
|
||||
VARIANT_CASE_CONST(zarcanum_sig, sig);
|
||||
sum_of_pseudo_out_amount_commitments += crypto::point_t(sig.pseudo_out_amount_commitment); // *1/8
|
||||
++zc_sigs_count;
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
sum_of_pseudo_out_amount_commitments.modify_mul8();
|
||||
|
|
@ -927,12 +929,12 @@ namespace currency
|
|||
crypto::derivation_to_scalar((const crypto::key_derivation&)derivation, output_index, h.as_secret_key()); // h = Hs(8 * r * V, i)
|
||||
|
||||
out.stealth_address = (h * crypto::c_point_G + crypto::point_t(apa.spend_public_key)).to_public_key();
|
||||
out.concealing_point = (crypto::c_scalar_1div8 * crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h) * crypto::point_t(apa.view_public_key)).to_public_key(); // Q = 1/8 * Hs(domain_sep, h) * V
|
||||
out.concealing_point = (crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h) * crypto::point_t(apa.view_public_key)).to_public_key(); // Q = 1/8 * Hs(domain_sep, Hs(8 * r * V, i) ) * 8 * V
|
||||
|
||||
crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h);
|
||||
out.encrypted_amount = de.amount ^ amount_mask.m_u64[0];
|
||||
|
||||
out_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
|
||||
out_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_BLINDING_MASK, h); // f = Hs(domain_sep, Hs(8 * r * V, i) )
|
||||
out.amount_commitment = (crypto::c_scalar_1div8 * de.amount * crypto::c_point_H + crypto::c_scalar_1div8 * out_blinding_mask * crypto::c_point_G).to_public_key(); // A = 1/8 * a * H + 1/8 * f * G
|
||||
|
||||
if (de.addr.front().is_auditable())
|
||||
|
|
@ -1594,8 +1596,9 @@ namespace currency
|
|||
// prepare inputs
|
||||
struct input_generation_context_data
|
||||
{
|
||||
keypair in_ephemeral;
|
||||
//std::vector<keypair> participants_derived_keys;
|
||||
keypair in_ephemeral {}; // ephemeral output key (stealth_address and secret_x)
|
||||
size_t real_out_index = SIZE_MAX; // index of real output in local outputs vector
|
||||
std::vector<tx_source_entry::output_entry> outputs{}; // sorted by gindex
|
||||
};
|
||||
//--------------------------------------------------------------------------------
|
||||
bool generate_ZC_sig(const crypto::hash& tx_hash_for_signature, size_t input_index, const tx_source_entry& se, const input_generation_context_data& in_context,
|
||||
|
|
@ -1616,7 +1619,7 @@ namespace currency
|
|||
#ifndef NDEBUG
|
||||
{
|
||||
crypto::point_t source_amount_commitment = crypto::c_scalar_1div8 * se.amount * crypto::c_point_H + crypto::c_scalar_1div8 * se.real_out_amount_blinding_mask * crypto::c_point_G;
|
||||
CHECK_AND_ASSERT_MES(se.outputs[se.real_output].amount_commitment == source_amount_commitment.to_public_key(), false, "real output amount commitment check failed");
|
||||
CHECK_AND_ASSERT_MES(in_context.outputs[in_context.real_out_index].amount_commitment == source_amount_commitment.to_public_key(), false, "real output amount commitment check failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -1651,10 +1654,10 @@ namespace currency
|
|||
// se.real_out_amount_blinding_mask - blinding_mask;
|
||||
|
||||
std::vector<crypto::CLSAG_GG_input_ref_t> ring;
|
||||
for(size_t j = 0; j < se.outputs.size(); ++j)
|
||||
ring.emplace_back(se.outputs[j].stealth_address, se.outputs[j].amount_commitment);
|
||||
for(size_t j = 0; j < in_context.outputs.size(); ++j)
|
||||
ring.emplace_back(in_context.outputs[j].stealth_address, in_context.outputs[j].amount_commitment);
|
||||
|
||||
return crypto::generate_CLSAG_GG(tx_hash_for_signature, ring, pseudo_out_amount_commitment, in.k_image, in_context.in_ephemeral.sec, se.real_out_amount_blinding_mask - blinding_mask, se.real_output, sig.clsags_gg);
|
||||
return crypto::generate_CLSAG_GG(tx_hash_for_signature, ring, pseudo_out_amount_commitment, in.k_image, in_context.in_ephemeral.sec, se.real_out_amount_blinding_mask - blinding_mask, in_context.real_out_index, sig.clsags_gg);
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool generate_NLSAG_sig(const crypto::hash& tx_hash_for_signature, const crypto::hash& tx_prefix_hash, size_t input_index, const tx_source_entry& src_entr,
|
||||
|
|
@ -1679,22 +1682,22 @@ namespace currency
|
|||
*pss_ring_s << "input #" << input_index << ", pub_keys:" << ENDL;
|
||||
|
||||
std::vector<const crypto::public_key*> keys_ptrs;
|
||||
for(const tx_source_entry::output_entry& o : src_entr.outputs)
|
||||
for(const tx_source_entry::output_entry& o : in_context.outputs)
|
||||
{
|
||||
keys_ptrs.push_back(&o.stealth_address);
|
||||
if (pss_ring_s)
|
||||
*pss_ring_s << o.stealth_address << ENDL;
|
||||
}
|
||||
sigs.resize(src_entr.outputs.size());
|
||||
sigs.resize(in_context.outputs.size());
|
||||
|
||||
if (!watch_only_mode)
|
||||
crypto::generate_ring_signature(tx_hash_for_signature, get_key_image_from_txin_v(tx.vin[input_index]), keys_ptrs, in_context.in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||
crypto::generate_ring_signature(tx_hash_for_signature, get_key_image_from_txin_v(tx.vin[input_index]), keys_ptrs, in_context.in_ephemeral.sec, in_context.real_out_index, sigs.data());
|
||||
|
||||
if (pss_ring_s)
|
||||
{
|
||||
*pss_ring_s << "signatures:" << ENDL;
|
||||
std::for_each(sigs.begin(), sigs.end(), [&pss_ring_s](const crypto::signature& s) { *pss_ring_s << s << ENDL; });
|
||||
*pss_ring_s << "prefix_hash: " << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_context.in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL;
|
||||
*pss_ring_s << "prefix_hash: " << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_context.in_ephemeral.sec << ENDL << "real_output: " << in_context.real_out_index << ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1832,7 +1835,11 @@ namespace currency
|
|||
{
|
||||
inputs_mapping[current_index] = current_index;
|
||||
current_index++;
|
||||
in_contexts.push_back(input_generation_context_data());
|
||||
in_contexts.push_back(input_generation_context_data{});
|
||||
input_generation_context_data& in_context = in_contexts.back();
|
||||
|
||||
in_context.outputs = prepare_outputs_entries_for_key_offsets(src_entr.outputs, src_entr.real_output, in_context.real_out_index);
|
||||
|
||||
if(src_entr.is_multisig())
|
||||
{//multisig input
|
||||
txin_multisig input_multisig = AUTO_VAL_INIT(input_multisig);
|
||||
|
|
@ -1844,7 +1851,7 @@ namespace currency
|
|||
else if (src_entr.htlc_origin.size())
|
||||
{
|
||||
//htlc redeem
|
||||
keypair& in_ephemeral = in_contexts.back().in_ephemeral;
|
||||
keypair& in_ephemeral = in_context.in_ephemeral;
|
||||
//txin_to_key
|
||||
if(src_entr.outputs.size() != 1)
|
||||
{
|
||||
|
|
@ -1859,11 +1866,11 @@ namespace currency
|
|||
return false;
|
||||
|
||||
//check that derivated key is equal with real output key
|
||||
if (!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].stealth_address))
|
||||
if (!(in_ephemeral.pub == src_entr.outputs.front().stealth_address))
|
||||
{
|
||||
LOG_ERROR("derived public key missmatch with output public key! " << ENDL << "derived_key:"
|
||||
<< string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:"
|
||||
<< string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].stealth_address));
|
||||
<< string_tools::pod_to_hex(src_entr.outputs.front().stealth_address));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1872,47 +1879,37 @@ namespace currency
|
|||
input_to_key.amount = src_entr.amount;
|
||||
input_to_key.k_image = img;
|
||||
input_to_key.hltc_origin = src_entr.htlc_origin;
|
||||
input_to_key.key_offsets.push_back(src_entr.outputs.front().out_reference);
|
||||
|
||||
//fill outputs array and use relative offsets
|
||||
for(const tx_source_entry::output_entry& out_entry : src_entr.outputs)
|
||||
input_to_key.key_offsets.push_back(out_entry.out_reference);
|
||||
|
||||
input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets);
|
||||
tx.vin.push_back(input_to_key);
|
||||
}
|
||||
else
|
||||
{
|
||||
//regular to key out
|
||||
keypair& in_ephemeral = in_contexts.back().in_ephemeral;
|
||||
//txin_to_key
|
||||
if (src_entr.real_output >= src_entr.outputs.size())
|
||||
{
|
||||
LOG_ERROR("real_output index (" << src_entr.real_output << ") greater than or equal to output_keys.size()=" << src_entr.outputs.size());
|
||||
return false;
|
||||
}
|
||||
// txin_to_key or txin_zc_input
|
||||
CHECK_AND_ASSERT_MES(in_context.real_out_index < in_context.outputs.size(), false,
|
||||
"real_output index (" << in_context.real_out_index << ") greater than or equal to in_context.outputs.size()=" << in_context.outputs.size());
|
||||
|
||||
summary_inputs_money += src_entr.amount;
|
||||
|
||||
//key_derivation recv_derivation;
|
||||
crypto::key_image img;
|
||||
if (!generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_ephemeral, img))
|
||||
if (!generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_context.in_ephemeral, img))
|
||||
return false;
|
||||
|
||||
//check that derivated key is equal with real output key
|
||||
if (!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].stealth_address))
|
||||
if (!(in_context.in_ephemeral.pub == in_context.outputs[in_context.real_out_index].stealth_address))
|
||||
{
|
||||
LOG_ERROR("derived public key missmatch with output public key! " << ENDL << "derived_key:"
|
||||
<< string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:"
|
||||
<< string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].stealth_address));
|
||||
<< string_tools::pod_to_hex(in_context.in_ephemeral.pub) << ENDL << "real output_public_key:"
|
||||
<< string_tools::pod_to_hex(in_context.outputs[in_context.real_out_index].stealth_address));
|
||||
return false;
|
||||
}
|
||||
|
||||
//fill key_offsets array with relative offsets
|
||||
std::vector<txout_ref_v> key_offsets;
|
||||
for(const tx_source_entry::output_entry& out_entry : src_entr.outputs)
|
||||
for(const tx_source_entry::output_entry& out_entry : in_context.outputs)
|
||||
key_offsets.push_back(out_entry.out_reference);
|
||||
|
||||
key_offsets = absolute_output_offsets_to_relative(key_offsets);
|
||||
|
||||
//TODO: Might need some refactoring since this scheme is not the clearest one(did it this way for now to keep less changes to not broke anything)
|
||||
//potentially this approach might help to support htlc and multisig without making to complicated code
|
||||
if (src_entr.is_zarcanum())
|
||||
|
|
@ -1936,15 +1933,10 @@ namespace currency
|
|||
input_to_key.k_image = img;
|
||||
input_to_key.key_offsets = std::move(key_offsets);
|
||||
tx.vin.push_back(input_to_key);
|
||||
//NLSAG_sources.push_back(&src_entr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*if (ins_zc.elements.size())
|
||||
{
|
||||
tx.vin.push_back(ins_zc);
|
||||
}*/
|
||||
uint64_t amount_of_assets = 0;
|
||||
std::vector<tx_destination_entry> shuffled_dsts(destinations);
|
||||
if (asset_id_for_destinations != currency::null_hash)
|
||||
|
|
@ -2106,45 +2098,21 @@ namespace currency
|
|||
}
|
||||
|
||||
LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL << ss_ring_s.str(), LOG_LEVEL_3);
|
||||
|
||||
//input_index++;
|
||||
//in_context_index++;
|
||||
}
|
||||
/*
|
||||
for(const tx_source_entry& source_entry : sources)
|
||||
{
|
||||
crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, input_index, tx_prefix_hash);
|
||||
CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "prepare_prefix_hash_for_sign failed");
|
||||
std::stringstream ss_ring_s;
|
||||
|
||||
if (source_entry.is_zarcanum())
|
||||
{
|
||||
// ZC
|
||||
// blinding_masks_sum is supposed to be sum(mask of all tx output) - sum(masks of all pseudo out commitments)
|
||||
r = generate_ZC_sig(tx_hash_for_signature, input_index, source_entry, in_contexts[in_context_index], sender_account_keys, blinding_masks_sum, flags, local_blinding_masks_sum, tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_ZC_sigs failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
// NLSAG
|
||||
r = generate_NLSAG_sig(tx_hash_for_signature, tx_prefix_hash, input_index, source_entry, sender_account_keys, in_contexts[in_context_index], txkey, flags, tx, &ss_ring_s);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_NLSAG_sig failed");
|
||||
}
|
||||
//size_t prefix_size = get_object_blobsize(static_cast<const transaction_prefix&>(tx));
|
||||
//size_t full_blob_size = t_serializable_object_to_blob(tx).size();
|
||||
//size_t estimated_blob_size = get_object_blobsize(tx);
|
||||
//CHECK_AND_ASSERT_MES(full_blob_size == estimated_blob_size, false, "!");
|
||||
|
||||
LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL << ss_ring_s.str(), LOG_LEVEL_3);
|
||||
|
||||
input_index++;
|
||||
in_context_index++;
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_tx_version(uint64_t h, const hard_forks_descriptor& hfd)
|
||||
uint64_t get_tx_version(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd)
|
||||
{
|
||||
if (!hfd.is_hardfork_active_for_height(4, h))
|
||||
if (!hfd.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, tx_expected_block_height))
|
||||
{
|
||||
return TRANSACTION_VERSION_PRE_HF4;
|
||||
}
|
||||
|
|
@ -2503,18 +2471,18 @@ namespace currency
|
|||
return res;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index)
|
||||
bool is_out_to_acc(const account_public_address& addr, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index)
|
||||
{
|
||||
crypto::public_key pk;
|
||||
if (!derive_public_key(derivation, output_index, acc.account_address.spend_public_key, pk))
|
||||
if (!derive_public_key(derivation, output_index, addr.spend_public_key, pk))
|
||||
return false;
|
||||
return pk == out_key.key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index)
|
||||
bool is_out_to_acc(const account_public_address& addr, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index)
|
||||
{
|
||||
crypto::public_key pk;
|
||||
if (!derive_public_key(derivation, output_index, acc.account_address.spend_public_key, pk))
|
||||
if (!derive_public_key(derivation, output_index, addr.spend_public_key, pk))
|
||||
return false;
|
||||
auto it = std::find(out_multisig.keys.begin(), out_multisig.keys.end(), pk);
|
||||
if (out_multisig.keys.end() == it)
|
||||
|
|
@ -2522,16 +2490,16 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
|
||||
bool is_out_to_acc(const account_keys& acc, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount, crypto::scalar_t& blinding_mask)
|
||||
bool is_out_to_acc(const account_public_address& addr, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount, crypto::scalar_t& blinding_mask)
|
||||
{
|
||||
crypto::scalar_t h; // = crypto::hash_helper_t::hs(reinterpret_cast<const crypto::public_key&>(derivation), output_index); // h = Hs(8 * r * V, i)
|
||||
crypto::derivation_to_scalar(derivation, output_index, h.as_secret_key()); // h = Hs(8 * r * V, i)
|
||||
|
||||
crypto::point_t P_prime = h * crypto::c_point_G + crypto::point_t(acc.account_address.spend_public_key); // P =? Hs(8rV, i) * G + S
|
||||
crypto::point_t P_prime = h * crypto::c_point_G + crypto::point_t(addr.spend_public_key); // P =? Hs(8rV, i) * G + S
|
||||
if (P_prime.to_public_key() != zo.stealth_address)
|
||||
return false;
|
||||
|
||||
crypto::point_t Q_prime = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h) * crypto::point_t(acc.account_address.view_public_key); // Q' * 8 =? Hs(domain_sep, h) * V
|
||||
crypto::point_t Q_prime = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h) * 8 * crypto::point_t(addr.view_public_key); // Q' * 8 =? Hs(domain_sep, Hs(8 * r * V, i) ) * 8 * V
|
||||
if (Q_prime != crypto::point_t(zo.concealing_point).modify_mul8())
|
||||
return false;
|
||||
|
||||
|
|
@ -2595,7 +2563,7 @@ namespace currency
|
|||
const tx_out_bare& o = boost::get<tx_out_bare>(ov);
|
||||
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "condition failed: o.target.type() == typeid(txout_to_key)");
|
||||
if (is_out_to_acc(acc, boost::get<txout_to_key>(o.target), derivation, offset))
|
||||
if (is_out_to_acc(acc.account_address, boost::get<txout_to_key>(o.target), derivation, offset))
|
||||
{
|
||||
outs.emplace_back(offset, o.amount);
|
||||
money_transfered += o.amount;
|
||||
|
|
@ -2632,25 +2600,25 @@ namespace currency
|
|||
{
|
||||
VARIANT_SWITCH_BEGIN(o.target);
|
||||
VARIANT_CASE_CONST(txout_to_key, t)
|
||||
if (is_out_to_acc(acc, t, derivation, output_index))
|
||||
if (is_out_to_acc(acc.account_address, t, derivation, output_index))
|
||||
{
|
||||
outs.emplace_back(output_index, o.amount);
|
||||
money_transfered += o.amount;
|
||||
}
|
||||
VARIANT_CASE_CONST(txout_multisig, t)
|
||||
if (is_out_to_acc(acc, t, derivation, output_index))
|
||||
if (is_out_to_acc(acc.account_address, t, derivation, output_index))
|
||||
{
|
||||
outs.emplace_back(output_index, o.amount); // TODO: @#@# consider this
|
||||
//don't cout this money
|
||||
}
|
||||
VARIANT_CASE_CONST(txout_htlc, htlc)
|
||||
htlc_info hi = AUTO_VAL_INIT(hi);
|
||||
if (is_out_to_acc(acc, htlc.pkey_redeem, derivation, output_index))
|
||||
if (is_out_to_acc(acc.account_address, htlc.pkey_redeem, derivation, output_index))
|
||||
{
|
||||
hi.hltc_our_out_is_before_expiration = true;
|
||||
htlc_info_list.push_back(hi);
|
||||
}
|
||||
else if (is_out_to_acc(acc, htlc.pkey_refund, derivation, output_index))
|
||||
else if (is_out_to_acc(acc.account_address, htlc.pkey_refund, derivation, output_index))
|
||||
{
|
||||
hi.hltc_our_out_is_before_expiration = false;
|
||||
htlc_info_list.push_back(hi);
|
||||
|
|
@ -2664,7 +2632,7 @@ namespace currency
|
|||
VARIANT_CASE_CONST(tx_out_zarcanum, zo)
|
||||
uint64_t amount = 0;
|
||||
crypto::scalar_t blinding_mask = 0;
|
||||
if (is_out_to_acc(acc, zo, derivation, output_index, amount, blinding_mask))
|
||||
if (is_out_to_acc(acc.account_address, zo, derivation, output_index, amount, blinding_mask))
|
||||
{
|
||||
outs.emplace_back(output_index, amount, blinding_mask);
|
||||
open_asset_id v = AUTO_VAL_INIT(v);
|
||||
|
|
@ -3063,6 +3031,7 @@ namespace currency
|
|||
return res;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// DEPRECATED: consider using prepare_outputs_entries_for_key_offsets and absolute_sorted_output_offsets_to_relative_in_place instead
|
||||
std::vector<txout_ref_v> absolute_output_offsets_to_relative(const std::vector<txout_ref_v>& off)
|
||||
{
|
||||
std::vector<txout_ref_v> res = off;
|
||||
|
|
@ -3106,6 +3075,34 @@ namespace currency
|
|||
return res;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool absolute_sorted_output_offsets_to_relative_in_place(std::vector<txout_ref_v>& offsets) noexcept
|
||||
{
|
||||
if (offsets.size() < 2)
|
||||
return true;
|
||||
|
||||
size_t i = offsets.size() - 1;
|
||||
while (i != 0 && offsets[i].type() == typeid(ref_by_id))
|
||||
--i;
|
||||
|
||||
try
|
||||
{
|
||||
for (; i != 0; i--)
|
||||
{
|
||||
uint64_t& offset_i = boost::get<uint64_t>(offsets[i]);
|
||||
uint64_t& offset_im1 = boost::get<uint64_t>(offsets[i - 1]);
|
||||
if (offset_i <= offset_im1)
|
||||
return false; // input was not properly sorted
|
||||
offset_i -= offset_im1;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false; // unexpected type in boost::get (all ref_by_id's must be at the end of 'offsets')
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b)
|
||||
{
|
||||
return parse_and_validate_object_from_blob(b_blob, b);
|
||||
|
|
@ -3978,6 +3975,11 @@ namespace currency
|
|||
return false;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool operator ==(const currency::ref_by_id& a, const currency::ref_by_id& b)
|
||||
{
|
||||
return a.n == b.n && a.tx_id == b.tx_id;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool verify_multiple_zc_outs_range_proofs(const std::vector<zc_outs_range_proofs_with_commitments>& range_proofs)
|
||||
{
|
||||
if (range_proofs.empty())
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ namespace currency
|
|||
bool operator ==(const currency::void_sig& a, const currency::void_sig& b);
|
||||
bool operator ==(const currency::ZC_sig& a, const currency::ZC_sig& b);
|
||||
bool operator ==(const currency::zarcanum_sig& a, const currency::zarcanum_sig& b);
|
||||
bool operator ==(const currency::ref_by_id& a, const currency::ref_by_id& b);
|
||||
|
||||
typedef boost::multiprecision::uint128_t uint128_tl;
|
||||
|
||||
|
|
@ -243,7 +244,9 @@ namespace currency
|
|||
const blobdata& extra_nonce = blobdata(),
|
||||
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,
|
||||
bool pos = false,
|
||||
const pos_entry& pe = pos_entry());
|
||||
const pos_entry& pe = pos_entry(),
|
||||
crypto::scalar_t* blinding_masks_sum_ptr = nullptr,
|
||||
const keypair* tx_one_time_key_to_use = nullptr);
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_string_uint64_hash(const std::string& str);
|
||||
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, crypto::scalar_t& out_blinding_mask, finalized_tx& result, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
|
||||
|
|
@ -288,7 +291,7 @@ namespace currency
|
|||
bool shuffle = true,
|
||||
uint64_t flags = 0);
|
||||
|
||||
uint64_t get_tx_version(uint64_t h, const hard_forks_descriptor& hfd);
|
||||
uint64_t get_tx_version(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd); // returns tx version based on the height of the block where the transaction is expected to be
|
||||
bool construct_tx(const account_keys& sender_account_keys, const finalize_tx_param& param, finalized_tx& result);
|
||||
crypto::hash get_asset_id_from_descriptor(const asset_descriptor_base& adb);
|
||||
|
||||
|
|
@ -306,9 +309,9 @@ namespace currency
|
|||
bool add_tx_extra_userdata(transaction& tx, const blobdata& extra_nonce);
|
||||
|
||||
crypto::hash get_multisig_out_id(const transaction& tx, size_t n);
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index);
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index);
|
||||
bool is_out_to_acc(const account_keys& acc, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount);
|
||||
bool is_out_to_acc(const account_public_address& addr, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index);
|
||||
bool is_out_to_acc(const account_public_address& addr, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index);
|
||||
bool is_out_to_acc(const account_public_address& addr, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount, crypto::scalar_t& blinding_mask);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation, std::list<htlc_info>& htlc_info_list);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation);
|
||||
|
|
@ -363,7 +366,11 @@ namespace currency
|
|||
uint64_t get_block_height(const transaction& coinbase);
|
||||
uint64_t get_block_height(const block& b);
|
||||
std::vector<txout_ref_v> relative_output_offsets_to_absolute(const std::vector<txout_ref_v>& off);
|
||||
// DEPRECATED: consider using prepare_outputs_entries_for_key_offsets and absolute_sorted_output_offsets_to_relative_in_place instead
|
||||
std::vector<txout_ref_v> absolute_output_offsets_to_relative(const std::vector<txout_ref_v>& off);
|
||||
bool absolute_sorted_output_offsets_to_relative_in_place(std::vector<txout_ref_v>& offsets) noexcept;
|
||||
|
||||
|
||||
|
||||
// prints amount in format "3.14", "0.0"
|
||||
std::string print_money_brief(uint64_t amount);
|
||||
|
|
@ -813,6 +820,17 @@ namespace currency
|
|||
return boost::apply_visitor(input_amount_getter(), v);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
struct output_amount_getter : public boost::static_visitor<uint64_t>
|
||||
{
|
||||
template<class out_t>
|
||||
uint64_t operator()(const out_t&) const { return 0; }
|
||||
uint64_t operator()(const tx_out_bare& ob) const { return ob.amount; }
|
||||
};
|
||||
inline uint64_t get_amount_from_variant(const tx_out_v& out_v)
|
||||
{
|
||||
return boost::apply_visitor(output_amount_getter(), out_v);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
inline const tx_out_bare& get_tx_out_bare_from_out_v(const tx_out_v& o)
|
||||
{
|
||||
//this function will throw if type is not matching
|
||||
|
|
|
|||
|
|
@ -129,8 +129,9 @@ namespace currency
|
|||
return boost::get<specific_type_t>(ai);
|
||||
}
|
||||
}
|
||||
ASSERT_MES_AND_THROW("Objec not found");
|
||||
ASSERT_MES_AND_THROW("Object with type " << typeid(specific_type_t).name() << " was not found in a container");
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// if cb returns true, it means "continue", false -- means "stop"
|
||||
template<typename specific_type_t, typename variant_container_t, typename callback_t>
|
||||
bool process_type_in_variant_container(const variant_container_t& av, callback_t& cb, bool return_value_if_none_found = true)
|
||||
|
|
|
|||
|
|
@ -215,12 +215,35 @@ namespace currency
|
|||
return total;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
inline size_t get_input_expected_signature_size_local(const txin_v& tx_in, bool last_input_in_separately_signed_tx)
|
||||
{
|
||||
struct txin_signature_size_visitor : public boost::static_visitor<size_t>
|
||||
{
|
||||
txin_signature_size_visitor(size_t add) : a(add) {}
|
||||
size_t a;
|
||||
size_t operator()(const txin_gen& /*txin*/) const { return 0; }
|
||||
size_t operator()(const txin_to_key& txin) const { return tools::get_varint_packed_size(txin.key_offsets.size() + a) + sizeof(crypto::signature) * (txin.key_offsets.size() + a); }
|
||||
size_t operator()(const txin_multisig& txin) const { return tools::get_varint_packed_size(txin.sigs_count + a) + sizeof(crypto::signature) * (txin.sigs_count + a); }
|
||||
size_t operator()(const txin_htlc& txin) const { return tools::get_varint_packed_size(1 + a) + sizeof(crypto::signature) * (1 + a); }
|
||||
size_t operator()(const txin_zc_input& txin) const { return 96 + tools::get_varint_packed_size(txin.key_offsets.size()) + txin.key_offsets.size() * 32; }
|
||||
};
|
||||
|
||||
return boost::apply_visitor(txin_signature_size_visitor(last_input_in_separately_signed_tx ? 1 : 0), tx_in);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size)
|
||||
{
|
||||
size_t tx_blob_size = prefix_blob_size;
|
||||
|
||||
if (is_coinbase(t))
|
||||
{
|
||||
if (is_pos_miner_tx(t) && t.version > TRANSACTION_VERSION_PRE_HF4)
|
||||
{
|
||||
// Zarcanum
|
||||
return tx_blob_size;
|
||||
}
|
||||
return tx_blob_size;
|
||||
}
|
||||
|
||||
// for purged tx, with empty signatures and attachments, this function should return the blob size
|
||||
// which the tx would have if the signatures and attachments were correctly filled with actual data
|
||||
|
|
@ -229,10 +252,12 @@ namespace currency
|
|||
bool separately_signed_tx = get_tx_flags(t) & TX_FLAG_SIGNATURE_MODE_SEPARATE;
|
||||
|
||||
tx_blob_size += tools::get_varint_packed_size(t.vin.size()); // size of transaction::signatures (equals to total inputs count)
|
||||
if (t.version > TRANSACTION_VERSION_PRE_HF4)
|
||||
tx_blob_size += t.vin.size(); // for HF4 txs 'signatures' is a verctor of variants, so it's +1 byte per signature (assuming sigs count equals to inputs count)
|
||||
|
||||
for (size_t i = 0; i != t.vin.size(); i++)
|
||||
{
|
||||
size_t sig_size = get_input_expected_signature_size(t.vin[i], separately_signed_tx && i == t.vin.size() - 1);
|
||||
size_t sig_size = get_input_expected_signature_size_local(t.vin[i], separately_signed_tx && i == t.vin.size() - 1);
|
||||
tx_blob_size += sig_size;
|
||||
}
|
||||
|
||||
|
|
@ -298,4 +323,65 @@ namespace currency
|
|||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// Prepapres vector of output_entry to be used in key_offsets in a transaction input:
|
||||
// 1) sort all entries by gindex (while moving all ref_by_id to the end, keeping they relative order)
|
||||
// 2) convert absolute global indices to relative key_offsets
|
||||
std::vector<tx_source_entry::output_entry> prepare_outputs_entries_for_key_offsets(const std::vector<tx_source_entry::output_entry>& outputs, size_t old_real_index, size_t& new_real_index) noexcept
|
||||
{
|
||||
TRY_ENTRY()
|
||||
|
||||
std::vector<tx_source_entry::output_entry> result = outputs;
|
||||
if (outputs.size() < 2)
|
||||
{
|
||||
new_real_index = old_real_index;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::sort(result.begin(), result.end(), [](const tx_source_entry::output_entry& lhs, const tx_source_entry::output_entry& rhs)
|
||||
{
|
||||
if (lhs.out_reference.type() == typeid(uint64_t))
|
||||
{
|
||||
if (rhs.out_reference.type() == typeid(uint64_t))
|
||||
return boost::get<uint64_t>(lhs.out_reference) < boost::get<uint64_t>(rhs.out_reference);
|
||||
if (rhs.out_reference.type() == typeid(ref_by_id))
|
||||
return true;
|
||||
CHECK_AND_ASSERT_THROW_MES(false, "unexpected type in out_reference 1: " << rhs.out_reference.type().name());
|
||||
}
|
||||
else if (lhs.out_reference.type() == typeid(ref_by_id))
|
||||
{
|
||||
if (rhs.out_reference.type() == typeid(uint64_t))
|
||||
return false;
|
||||
if (rhs.out_reference.type() == typeid(ref_by_id))
|
||||
return false; // don't change the order of ref_by_id elements
|
||||
CHECK_AND_ASSERT_THROW_MES(false, "unexpected type in out_reference 2: " << rhs.out_reference.type().name());
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// restore index of the selected element, if needed
|
||||
if (old_real_index != SIZE_MAX)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(old_real_index < outputs.size(), "old_real_index is OOB");
|
||||
auto it = std::find(result.begin(), result.end(), outputs[old_real_index]);
|
||||
CHECK_AND_ASSERT_THROW_MES(it != result.end(), "internal error: cannot find old_real_index");
|
||||
new_real_index = it - result.begin();
|
||||
}
|
||||
|
||||
// find the last uint64_t entry - skip ref_by_id entries goint from the end to the beginnning
|
||||
size_t i = result.size() - 1;
|
||||
while (i != 0 && result[i].out_reference.type() == typeid(ref_by_id))
|
||||
--i;
|
||||
|
||||
for (; i != 0; i--)
|
||||
{
|
||||
boost::get<uint64_t>(result[i].out_reference) -= boost::get<uint64_t>(result[i - 1].out_reference);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
CATCH_ENTRY2(std::vector<tx_source_entry::output_entry>{});
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
|
@ -22,14 +22,16 @@ namespace currency
|
|||
output_entry(const output_entry &) = default;
|
||||
output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address)
|
||||
: out_reference(out_reference), stealth_address(stealth_address), concealing_point(null_pkey), amount_commitment(null_pkey) {}
|
||||
//output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address, const crypto::public_key& concealing_point, const crypto::public_key& amount_commitment)
|
||||
// : out_reference(out_reference), stealth_address(stealth_address), concealing_point(concealing_point), amount_commitment(amount_commitment) {}
|
||||
output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address, const crypto::public_key& concealing_point, const crypto::public_key& amount_commitment)
|
||||
: out_reference(out_reference), stealth_address(stealth_address), concealing_point(concealing_point), amount_commitment(amount_commitment) {}
|
||||
|
||||
txout_ref_v out_reference; // either global output index or ref_by_id
|
||||
crypto::public_key stealth_address; // a.k.a output's one-time public key
|
||||
crypto::public_key concealing_point; // only for zarcaum outputs
|
||||
crypto::public_key amount_commitment; // only for zarcaum outputs
|
||||
|
||||
bool operator==(const output_entry& rhs) const { return out_reference == rhs.out_reference; } // used in prepare_outputs_entries_for_key_offsets, it's okay to do partially comparison
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(out_reference)
|
||||
FIELD(stealth_address)
|
||||
|
|
@ -161,5 +163,5 @@ namespace currency
|
|||
bool read_keyimages_from_tx(const transaction& tx, std::list<crypto::key_image>& kil);
|
||||
bool validate_inputs_sorting(const transaction& tx);
|
||||
|
||||
|
||||
std::vector<tx_source_entry::output_entry> prepare_outputs_entries_for_key_offsets(const std::vector<tx_source_entry::output_entry>& outputs, size_t old_real_index, size_t& new_real_index) noexcept;
|
||||
}
|
||||
|
|
|
|||
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
|
||||
32
src/currency_core/pos_mining.h
Normal file
32
src/currency_core/pos_mining.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// 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
|
||||
{
|
||||
// Zarcanum notation:
|
||||
wide_difficulty_type basic_diff; // D
|
||||
stake_kernel sk;
|
||||
crypto::scalar_t last_pow_block_id_hashed; // f'
|
||||
crypto::scalar_t secret_q; // q
|
||||
boost::multiprecision::uint256_t z_l_div_z_D; // z * floor( l / (z * D) ) (max possible value (assuming z=2^64) : z * 2^252 / (z * 1) ~= 2^252)
|
||||
crypto::hash kernel_hash; // h
|
||||
crypto::scalar_t stake_out_blinding_mask; // f
|
||||
uint64_t stake_amount; // a
|
||||
|
||||
bool zarcanum; // false for pre-HF4 classic PoS with explicit amounts
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -863,6 +863,7 @@ namespace currency
|
|||
blobdata block_blob = t_serializable_object_to_blob(resp.b);
|
||||
res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob);
|
||||
res.prev_hash = string_tools::pod_to_hex(resp.b.prev_id);
|
||||
res.blinding_masks_sum = resp.blinding_mask_sum;
|
||||
res.height = resp.height;
|
||||
//calculate epoch seed
|
||||
res.seed = currency::ethash_epoch_to_seed(currency::ethash_height_to_epoch(res.height));
|
||||
|
|
|
|||
|
|
@ -332,6 +332,10 @@ namespace currency
|
|||
#pragma pack (push, 1)
|
||||
struct out_entry
|
||||
{
|
||||
out_entry() = default;
|
||||
out_entry(uint64_t global_amount_index, const crypto::public_key& stealth_address, const crypto::public_key& amount_commitment, const crypto::public_key& concealing_point)
|
||||
: global_amount_index(global_amount_index), stealth_address(stealth_address), amount_commitment(amount_commitment), concealing_point(concealing_point)
|
||||
{}
|
||||
uint64_t global_amount_index;
|
||||
crypto::public_key stealth_address;
|
||||
crypto::public_key concealing_point;
|
||||
|
|
@ -805,28 +809,17 @@ namespace currency
|
|||
blobdata explicit_transaction;
|
||||
std::string extra_text;
|
||||
std::string wallet_address;
|
||||
std::string stakeholder_address;
|
||||
bool pos_block; //is pos block
|
||||
//uint64_t pos_amount; //do we still need it?
|
||||
//uint64_t pos_g_index; //
|
||||
//crypto::hash tx_id;
|
||||
//uint64_t tx_out_index;
|
||||
//uint64_t stake_unlock_time;
|
||||
|
||||
pos_entry pe; // for making PoS blocks
|
||||
std::string stakeholder_address; // address for stake return (PoS blocks)
|
||||
pos_entry pe; // for PoS blocks
|
||||
bool pos_block; // is pos block
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_BLOB_AS_HEX_STRING(explicit_transaction)
|
||||
KV_SERIALIZE(extra_text)
|
||||
KV_SERIALIZE(wallet_address)
|
||||
KV_SERIALIZE(stakeholder_address);
|
||||
KV_SERIALIZE(pos_block)
|
||||
//KV_SERIALIZE(pos_amount)
|
||||
//KV_SERIALIZE(pos_g_index)
|
||||
//KV_SERIALIZE_POD_AS_HEX_STRING(tx_id)
|
||||
//KV_SERIALIZE(tx_out_index)
|
||||
//KV_SERIALIZE(stake_unlock_time)
|
||||
KV_SERIALIZE(pe)
|
||||
KV_SERIALIZE(pos_block)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
@ -837,6 +830,7 @@ namespace currency
|
|||
crypto::hash seed;
|
||||
blobdata blocktemplate_blob;
|
||||
std::string prev_hash;
|
||||
crypto::scalar_t blinding_masks_sum; // sum of outputs' blinding masks (for zc outs)
|
||||
std::string status;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
|
|
@ -845,6 +839,7 @@ namespace currency
|
|||
KV_SERIALIZE_POD_AS_HEX_STRING(seed)
|
||||
KV_SERIALIZE(blocktemplate_blob)
|
||||
KV_SERIALIZE(prev_hash)
|
||||
KV_SERIALIZE(blinding_masks_sum)
|
||||
KV_SERIALIZE(status)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3168,7 +3168,7 @@ bool wallet2::generate_packing_transaction_if_needed(currency::transaction& tx,
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool include_unspent /*= true*/) const
|
||||
{
|
||||
static const char* header = "index amount g_index flags block tx out# key image";
|
||||
static const char* header = "index amount g_index flags block tx out# key image";
|
||||
std::stringstream ss;
|
||||
ss << header << ENDL;
|
||||
size_t count = 0;
|
||||
|
|
@ -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);
|
||||
|
|
@ -3647,7 +3652,7 @@ 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(const mining_context& cxt, 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 crypto::scalar_t& blinding_masks_sum) const
|
||||
{
|
||||
bool r = false;
|
||||
WLT_CHECK_AND_ASSERT_MES(pe.wallet_index < m_transfers.size(), false, "invalid pe.wallet_index: " << pe.wallet_index);
|
||||
|
|
@ -3656,53 +3661,53 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl
|
|||
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];
|
||||
|
||||
// calculate stake_out_derivation and secret_x (derived ephemeral secret key)
|
||||
crypto::key_derivation stake_out_derivation = AUTO_VAL_INIT(stake_out_derivation);
|
||||
r = crypto::generate_key_derivation(source_tx_pub_key, m_account.get_keys().view_secret_key, stake_out_derivation); // d = 8 * v * R
|
||||
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(stake_out_derivation, pe.tx_out_index, m_account.get_keys().spend_secret_key, secret_x); // x = Hs(8 * v * R, i) + s
|
||||
|
||||
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());
|
||||
WLT_CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(currency::txin_to_key), false, "Wrong input 1 type in transaction: " << b.miner_tx.vin[1].type().name());
|
||||
auto& txin = boost::get<currency::txin_to_key>(b.miner_tx.vin[1]);
|
||||
txin.k_image = pe.keyimage;
|
||||
|
||||
WLT_CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1 &&
|
||||
b.miner_tx.signatures[0].type() == typeid(NLSAG_sig) &&
|
||||
boost::get<NLSAG_sig>(b.miner_tx.signatures[0]).s.size() == txin.key_offsets.size(),
|
||||
false, "Wrong signatures amount in coinbase transacton");
|
||||
|
||||
//derive secret key
|
||||
crypto::key_derivation pos_coin_derivation = AUTO_VAL_INIT(pos_coin_derivation);
|
||||
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, "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,
|
||||
pe.tx_out_index,
|
||||
m_account.get_keys().spend_secret_key,
|
||||
derived_secret_ephemeral_key);
|
||||
WLT_CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1 && b.miner_tx.signatures[0].type() == typeid(NLSAG_sig), false, "wrong sig prepared in a PoS block");
|
||||
WLT_CHECK_AND_ASSERT_MES(stake_out_v.type() == typeid(tx_out_bare), false, "unexpected stake output type: " << stake_out_v.type().name() << ", expected: tx_out_bare");
|
||||
const tx_out_bare& stake_out = boost::get<tx_out_bare>(stake_out_v);
|
||||
WLT_CHECK_AND_ASSERT_MES(stake_out.target.type() == typeid(txout_to_key), false, "unexpected stake output target type: " << stake_out.target.type().name() << ", expected: txout_to_key");
|
||||
|
||||
NLSAG_sig& sig = boost::get<NLSAG_sig>(b.miner_tx.signatures[0]);
|
||||
txin_to_key& stake_input = boost::get<txin_to_key>(b.miner_tx.vin[1]);
|
||||
const txout_to_key& stake_out_target = boost::get<txout_to_key>(stake_out.target);
|
||||
|
||||
// fill stake input
|
||||
stake_input.k_image = pe.keyimage;
|
||||
stake_input.amount = pe.amount;
|
||||
stake_input.key_offsets.push_back(pe.g_index);
|
||||
|
||||
// sign block actually in coinbase transaction
|
||||
crypto::hash block_hash = currency::get_block_hash(b);
|
||||
|
||||
// get stake output pub key (stealth address) for ring signature generation
|
||||
std::vector<const crypto::public_key*> keys_ptrs;
|
||||
TRY_ENTRY()
|
||||
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);
|
||||
keys_ptrs.push_back(&stake_out_target.key);
|
||||
|
||||
// generate sring signature
|
||||
sig.s.resize(1);
|
||||
crypto::generate_ring_signature(block_hash,
|
||||
txin.k_image,
|
||||
stake_input.k_image,
|
||||
keys_ptrs,
|
||||
derived_secret_ephemeral_key,
|
||||
secret_x,
|
||||
0,
|
||||
&boost::get<NLSAG_sig>(b.miner_tx.signatures[0]).s[0]);
|
||||
&sig.s[0]);
|
||||
|
||||
WLT_LOG_L4("GENERATED RING SIGNATURE: block_id " << block_hash
|
||||
<< "txin.k_image" << txin.k_image
|
||||
WLT_LOG_L4("GENERATED RING SIGNATURE for PoS block coinbase: block_id " << block_hash
|
||||
<< "txin.k_image" << stake_input.k_image
|
||||
<< "key_ptr:" << *keys_ptrs[0]
|
||||
<< "signature:" << boost::get<NLSAG_sig>(b.miner_tx.signatures[0]).s);
|
||||
<< "signature:" << sig.s);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3724,7 +3729,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl
|
|||
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 size_t required_decoys_count = 4; // TODO @#@# set them somewhere else
|
||||
static bool use_only_forced_to_mix = false; // TODO @#@# set them somewhere else
|
||||
if (required_decoys_count > 0)
|
||||
{
|
||||
|
|
@ -3743,8 +3748,10 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl
|
|||
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;
|
||||
decoys.emplace_front(td.m_global_output_index, stake_out.stealth_address, stake_out.amount_commitment, stake_out.concealing_point);
|
||||
|
||||
std::unordered_set<uint64_t> used_gindices;
|
||||
size_t good_outs_count = 0;
|
||||
for(auto it = decoys.begin(); it != decoys.end(); )
|
||||
{
|
||||
if (used_gindices.count(it->global_amount_index) != 0)
|
||||
|
|
@ -3753,33 +3760,29 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl
|
|||
continue;
|
||||
}
|
||||
used_gindices.insert(it->global_amount_index);
|
||||
if (++good_decoys_count == required_decoys_count)
|
||||
if (++good_outs_count == required_decoys_count + 1)
|
||||
{
|
||||
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);
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(decoys.size() == required_decoys_count + 1, "for PoS stake got less good decoys than required: " << decoys.size() << " < " << required_decoys_count);
|
||||
|
||||
decoys.sort([](auto& l, auto& r){ return l.global_amount_index < r.global_amount_index; }); // sort them now (note absolute_sorted_output_offsets_to_relative_in_place() below)
|
||||
|
||||
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);
|
||||
}
|
||||
uint64_t gindex = el.global_amount_index;
|
||||
if (gindex == td.m_global_output_index)
|
||||
secret_index = i;
|
||||
++i;
|
||||
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);
|
||||
r = absolute_sorted_output_offsets_to_relative_in_place(stake_input.key_offsets);
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "absolute_sorted_output_offsets_to_relative_in_place failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3793,24 +3796,15 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl
|
|||
{
|
||||
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");
|
||||
CHECK_AND_ASSERT_MES(ring[secret_index].amount_commitment == stake_out.amount_commitment, false, "ring secret member doesn't match with the stake output");
|
||||
}
|
||||
#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);
|
||||
crypto::hash tx_hash_for_sig = get_transaction_hash(b.miner_tx); // TODO @#@# change to block hash after the corresponding test is made
|
||||
|
||||
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,
|
||||
r = crypto::zarcanum_generate_proof(tx_hash_for_sig, cxt.kernel_hash, ring, cxt.last_pow_block_id_hashed, cxt.sk.kimage,
|
||||
secret_x, cxt.secret_q, secret_index, blinding_masks_sum, cxt.stake_amount, cxt.stake_out_blinding_mask,
|
||||
static_cast<crypto::zarcanum_proof&>(sig), &err);
|
||||
WLT_CHECK_AND_ASSERT_MES(r, false, "zarcanum_generate_proof failed, err: " << (int)err);
|
||||
|
||||
|
|
@ -3821,26 +3815,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;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
|
@ -3887,76 +3872,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::point_t R(get_tx_pub_key_from_extra(td.m_ptx_wallet_info->m_tx));
|
||||
crypto::scalar_t v = m_account.get_keys().view_secret_key;
|
||||
context.secret_q = v * crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_SECRET_Q, v * R);
|
||||
}
|
||||
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()
|
||||
|
|
@ -4039,7 +3965,7 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco
|
|||
//else
|
||||
//{
|
||||
// old fashioned non-hidden amount PoS scheme
|
||||
res = prepare_and_sign_pos_block(cxt, b, tmpl_req.pe);
|
||||
res = prepare_and_sign_pos_block(cxt, b, tmpl_req.pe, tmpl_rsp.blinding_masks_sum);
|
||||
WLT_CHECK_AND_ASSERT_MES(res, false, "Failed to prepare_and_sign_pos_block");
|
||||
//}
|
||||
|
||||
|
|
@ -4375,7 +4301,7 @@ void wallet2::dump_trunsfers(std::stringstream& ss, bool verbose) const
|
|||
else
|
||||
{
|
||||
boost::io::ios_flags_saver ifs(ss);
|
||||
ss << "index amount spent_h g_index block block_ts flg tx out# key image" << ENDL;
|
||||
ss << "index amount spent_h g_index block block_ts flg tx out# key image" << ENDL;
|
||||
for (size_t i = 0; i != m_transfers.size(); i++)
|
||||
{
|
||||
const transfer_details& td = m_transfers[i];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -699,7 +690,7 @@ namespace tools
|
|||
bool fill_mining_context(mining_context& ctx);
|
||||
|
||||
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
|
||||
std::string get_transfers_str(bool include_spent /*= true*/, bool include_unspent /*= true*/) const;
|
||||
std::string get_transfers_str(bool include_spent = true, bool include_unspent = true) const;
|
||||
|
||||
// Returns all payments by given id in unspecified order
|
||||
void get_payments(const std::string& payment_id, std::list<payment_details>& payments, uint64_t min_height = 0) const;
|
||||
|
|
@ -840,7 +831,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(const mining_context& cxt, 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 crypto::scalar_t& blinding_masks_sum) const;
|
||||
void process_new_blockchain_entry(const currency::block& b,
|
||||
const currency::block_direct_data_entry& bche,
|
||||
const crypto::hash& bl_id,
|
||||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ bool block_template_against_txs_size::c1(currency::core& c, size_t ev_index, con
|
|||
wide_difficulty_type diff = 0;
|
||||
uint64_t height = 0;
|
||||
g_block_txs_total_size = txs_total_size; // passing an argument to custom_fill_block_template_func via global variable (not perfect but works well)
|
||||
r = bcs.create_block_template(b, miner_addr, miner_addr, diff, height, ex_nonce, is_pos != 0, pe, &custom_fill_block_template_func);
|
||||
r = bcs.create_block_template(miner_addr, miner_addr, ex_nonce, is_pos != 0, pe, &custom_fill_block_template_func, b, diff, height);
|
||||
CHECK_AND_ASSERT_MES(r, false, "create_block_template failed, txs_total_size = " << txs_total_size);
|
||||
CHECK_AND_ASSERT_MES(height == top_block_height + 1, false, "Incorrect height: " << height << ", expected: " << top_block_height + 1 << ", txs_total_size = " << txs_total_size);
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ bool gen_chain_switch_pow_pos::generate(std::vector<test_event_entry>& events) c
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), alice.get_public_address());
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 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
|
||||
|
|
@ -25,8 +25,6 @@
|
|||
#include "wallet_test_core_proxy.h"
|
||||
#include "pos_block_builder.h"
|
||||
|
||||
//using namespace std;
|
||||
|
||||
using namespace epee;
|
||||
using namespace currency;
|
||||
|
||||
|
|
@ -34,7 +32,7 @@ using namespace currency;
|
|||
#define POS_DIFF_UP_TIMESTAMP_DELTA (DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN*2/3)
|
||||
|
||||
std::atomic<int64_t> test_core_time::m_time_shift;
|
||||
test_gentime_settings test_generator::m_test_gentime_settings_default = test_gentime_settings(tests_digits_split_strategy, CURRENCY_MINER_TX_MAX_OUTS, WALLET_MAX_ALLOWED_OUTPUT_AMOUNT, DEFAULT_DUST_THRESHOLD);
|
||||
const test_gentime_settings test_generator::m_test_gentime_settings_default{};
|
||||
test_gentime_settings test_generator::m_test_gentime_settings = test_generator::m_test_gentime_settings_default;
|
||||
|
||||
crypto::signature create_invalid_signature()
|
||||
|
|
@ -276,6 +274,7 @@ bool test_generator::construct_block(currency::block& blk,
|
|||
|
||||
blk.miner_tx = AUTO_VAL_INIT(blk.miner_tx);
|
||||
size_t target_block_size = txs_size + 0; // zero means no cost for ordinary coinbase
|
||||
crypto::scalar_t blinding_masks_sum = 0;
|
||||
while (true)
|
||||
{
|
||||
r = construct_miner_tx(height, misc_utils::median(block_sizes),
|
||||
|
|
@ -289,7 +288,8 @@ bool test_generator::construct_block(currency::block& blk,
|
|||
blobdata(),
|
||||
test_generator::get_test_gentime_settings().miner_tx_max_outs,
|
||||
static_cast<bool>(coin_stake_sources.size()),
|
||||
pe);
|
||||
pe,
|
||||
&blinding_masks_sum);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_miner_tx failed");
|
||||
|
||||
size_t coinbase_size = get_object_blobsize(blk.miner_tx);
|
||||
|
|
@ -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].wallet, wallets[won_walled_index].mining_context, blocks, oi);
|
||||
r = sign_block(wallets[won_walled_index].mining_context, pe, *wallets[won_walled_index].wallet, blinding_masks_sum, blk);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to find_kernel_and_sign()");
|
||||
}
|
||||
|
||||
|
|
@ -347,14 +347,13 @@ bool test_generator::construct_block(currency::block& blk,
|
|||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
bool test_generator::sign_block(const tools::wallet2::mining_context& mining_context,
|
||||
const pos_entry& pe,
|
||||
const tools::wallet2& w,
|
||||
const crypto::scalar_t& blinding_masks_sum,
|
||||
currency::block& b)
|
||||
{
|
||||
bool r = w.prepare_and_sign_pos_block(mining_context, b, pe);
|
||||
bool r = w.prepare_and_sign_pos_block(mining_context, b, pe, blinding_masks_sum);
|
||||
CHECK_AND_ASSERT_MES(r, false, "prepare_and_sign_pos_block failed");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -576,8 +575,9 @@ bool test_generator::build_outputs_indext_for_chain(const blockchain_vector& blo
|
|||
std::vector<uint64_t>& coinbase_outs = txs_outs[currency::get_transaction_hash(blocks[h]->b.miner_tx)];
|
||||
for (size_t out_i = 0; out_i != blocks[h]->b.miner_tx.vout.size(); out_i++)
|
||||
{
|
||||
coinbase_outs.push_back(index[boost::get<currency::tx_out_bare>(blocks[h]->b.miner_tx.vout[out_i]).amount].size());
|
||||
index[boost::get<currency::tx_out_bare>(blocks[h]->b.miner_tx.vout[out_i]).amount].push_back(std::tuple<size_t, size_t, size_t>(h, 0, out_i));
|
||||
uint64_t amount = get_amount_from_variant(blocks[h]->b.miner_tx.vout[out_i]);
|
||||
coinbase_outs.push_back(index[amount].size());
|
||||
index[amount].push_back(std::tuple<size_t, size_t, size_t>(h, 0, out_i));
|
||||
}
|
||||
|
||||
for (size_t tx_index = 0; tx_index != blocks[h]->m_transactions.size(); tx_index++)
|
||||
|
|
@ -585,14 +585,16 @@ bool test_generator::build_outputs_indext_for_chain(const blockchain_vector& blo
|
|||
std::vector<uint64_t>& tx_outs_indx = txs_outs[currency::get_transaction_hash(blocks[h]->m_transactions[tx_index])];
|
||||
for (size_t out_i = 0; out_i != blocks[h]->m_transactions[tx_index].vout.size(); out_i++)
|
||||
{
|
||||
tx_outs_indx.push_back(index[boost::get<currency::tx_out_bare>(blocks[h]->m_transactions[tx_index].vout[out_i]).amount].size());
|
||||
index[boost::get<currency::tx_out_bare>(blocks[h]->m_transactions[tx_index].vout[out_i]).amount].push_back(std::tuple<size_t, size_t, size_t>(h, tx_index + 1, out_i));
|
||||
uint64_t amount = get_amount_from_variant(blocks[h]->m_transactions[tx_index].vout[out_i]);
|
||||
tx_outs_indx.push_back(index[amount].size());
|
||||
index[amount].push_back(std::tuple<size_t, size_t, size_t>(h, tx_index + 1, out_i));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
/* not used, consider removing
|
||||
bool test_generator::get_output_details_by_global_index(const test_generator::blockchain_vector& blck_chain,
|
||||
const test_generator::outputs_index& indexes,
|
||||
uint64_t amount,
|
||||
|
|
@ -628,6 +630,7 @@ bool test_generator::get_output_details_by_global_index(const test_generator::bl
|
|||
output_key = boost::get<currency::txout_to_key>(boost::get<tx_out_bare>(tx->vout[tx_out_index]).target).key;
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
//------------------------------------------------------------------
|
||||
|
||||
bool test_generator::build_stake_modifier(stake_modifier_type& sm, const test_generator::blockchain_vector& blck_chain)
|
||||
|
|
@ -926,42 +929,44 @@ bool test_generator::construct_pow_block_with_alias_info_in_coinbase(const accou
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
struct output_index {
|
||||
const currency::txout_target_v out;
|
||||
uint64_t amount;
|
||||
size_t blk_height; // block height
|
||||
size_t tx_no; // index of transaction in block
|
||||
size_t out_no; // index of out in transaction
|
||||
size_t idx;
|
||||
bool spent;
|
||||
const currency::block *p_blk;
|
||||
const currency::transaction *p_tx;
|
||||
struct output_index
|
||||
{
|
||||
const currency::tx_out_v out_v;
|
||||
uint64_t amount;
|
||||
size_t tx_no; // index of transaction in block
|
||||
size_t out_no; // index of out in transaction
|
||||
size_t idx; // global index
|
||||
bool spent; // was it spent?
|
||||
bool zc_out; // is it a ZC output?
|
||||
const currency::block *p_blk;
|
||||
const currency::transaction *p_tx;
|
||||
crypto::scalar_t blinding_mask; // zc outs only
|
||||
|
||||
output_index(const currency::txout_target_v &_out, uint64_t _a, size_t _h, size_t tno, size_t ono, const currency::block *_pb, const currency::transaction *_pt)
|
||||
: out(_out), amount(_a), blk_height(_h), tx_no(tno), out_no(ono), idx(0), spent(false), p_blk(_pb), p_tx(_pt) { }
|
||||
output_index(const currency::tx_out_v &_out_v, uint64_t _a, size_t tno, size_t ono, const currency::block *_pb, const currency::transaction *_pt)
|
||||
: out_v(_out_v), amount(_a), tx_no(tno), out_no(ono), idx(0), spent(false), zc_out(false), p_blk(_pb), p_tx(_pt), blinding_mask(0)
|
||||
{}
|
||||
|
||||
output_index(const output_index &other)
|
||||
: out(other.out), amount(other.amount), blk_height(other.blk_height), tx_no(other.tx_no), out_no(other.out_no), idx(other.idx), spent(other.spent), p_blk(other.p_blk), p_tx(other.p_tx) { }
|
||||
output_index(const output_index &other) = default;
|
||||
|
||||
const std::string toString() const {
|
||||
std::stringstream ss;
|
||||
const std::string to_string() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "output_index{"
|
||||
<< " tx_no=" << tx_no
|
||||
<< " out_no=" << out_no
|
||||
<< " amount=" << amount
|
||||
<< " idx=" << idx
|
||||
<< " spent=" << spent
|
||||
<< " zc_out=" << zc_out
|
||||
<< "}";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
ss << "output_index{blk_height=" << blk_height
|
||||
<< " tx_no=" << tx_no
|
||||
<< " out_no=" << out_no
|
||||
<< " amount=" << amount
|
||||
<< " idx=" << idx
|
||||
<< " spent=" << spent
|
||||
<< "}";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
output_index& operator=(const output_index& other)
|
||||
{
|
||||
new(this) output_index(other);
|
||||
return *this;
|
||||
}
|
||||
output_index& operator=(const output_index& other) = default;
|
||||
/*{
|
||||
new(this) output_index(other);
|
||||
return *this;
|
||||
}*/
|
||||
};
|
||||
|
||||
typedef std::map<uint64_t, std::vector<size_t> > map_output_t; // amount -> [N -> global out index]
|
||||
|
|
@ -984,16 +989,18 @@ namespace
|
|||
|
||||
bool init_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, const currency::account_keys& acc_keys)
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
for (const block& blk : blockchain)
|
||||
{
|
||||
|
||||
uint64_t height = get_block_height(blk);
|
||||
std::vector<const transaction*> vtx;
|
||||
vtx.push_back(&blk.miner_tx);
|
||||
|
||||
for (const crypto::hash &h : blk.tx_hashes)
|
||||
{
|
||||
const map_hash2tx_t::const_iterator cit = mtx.find(h);
|
||||
CHECK_AND_ASSERT_MES(cit != mtx.end(), false, "block at height " << get_block_height(blk) << " contains a reference to unknown tx " << h);
|
||||
CHECK_AND_ASSERT_MES(cit != mtx.end(), false, "block at height " << height << " contains a reference to unknown tx " << h);
|
||||
vtx.push_back(cit->second);
|
||||
}
|
||||
|
||||
|
|
@ -1006,18 +1013,37 @@ bool init_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const
|
|||
|
||||
for (size_t j = 0; j < tx.vout.size(); ++j)
|
||||
{
|
||||
const tx_out_bare &out = boost::get<tx_out_bare>(tx.vout[j]);
|
||||
output_index oi(out.target, out.amount, boost::get<txin_gen>(*blk.miner_tx.vin.begin()).height, i, j, &blk, vtx[i]);
|
||||
VARIANT_SWITCH_BEGIN(tx.vout[j])
|
||||
VARIANT_CASE_CONST(tx_out_bare, out)
|
||||
if (out.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
std::vector<output_index>& outs_vec = outs[out.amount];
|
||||
size_t out_global_idx = outs_vec.size();
|
||||
output_index oi(out, out.amount, i, j, &blk, vtx[i]);
|
||||
oi.idx = out_global_idx;
|
||||
outs_vec.emplace_back(std::move(oi));
|
||||
// Is out to me?
|
||||
if (is_out_to_acc(acc_keys.account_address, boost::get<txout_to_key>(out.target), derivation, j))
|
||||
outs_mine[out.amount].push_back(out_global_idx);
|
||||
}
|
||||
VARIANT_CASE_CONST(tx_out_zarcanum, out)
|
||||
std::vector<output_index>& outs_vec = outs[0]; // amount = 0 for ZC outs
|
||||
size_t out_global_idx = outs_vec.size();
|
||||
|
||||
if (out.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
outs[out.amount].push_back(oi);
|
||||
size_t tx_global_idx = outs[out.amount].size() - 1;
|
||||
outs[out.amount][tx_global_idx].idx = tx_global_idx;
|
||||
// Is out to me?
|
||||
if (is_out_to_acc(acc_keys, boost::get<txout_to_key>(out.target), derivation, j))
|
||||
outs_mine[out.amount].push_back(tx_global_idx);
|
||||
}
|
||||
output_index oi(out, 0 /* amount */, i, j, &blk, vtx[i]);
|
||||
oi.zc_out = true;
|
||||
oi.idx = out_global_idx;
|
||||
outs_vec.emplace_back(std::move(oi));
|
||||
|
||||
uint64_t decoded_amount = 0;
|
||||
crypto::scalar_t decoded_blinding_mask{};
|
||||
if (is_out_to_acc(acc_keys.account_address, out, derivation, j, decoded_amount, decoded_blinding_mask))
|
||||
{
|
||||
outs_vec.back().amount = decoded_amount;
|
||||
outs_vec.back().blinding_mask = decoded_blinding_mask;
|
||||
outs_mine[0].push_back(out_global_idx);
|
||||
}
|
||||
VARIANT_SWITCH_END()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1027,59 +1053,56 @@ bool init_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const
|
|||
|
||||
bool init_spent_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, const currency::account_keys& from)
|
||||
{
|
||||
for(const map_output_t::value_type &o : outs_mine)
|
||||
// 1. make a hashset of spend key images
|
||||
std::unordered_set<crypto::key_image> spent_key_images;
|
||||
auto add_key_images_from_tx = [&](const transaction& tx) -> bool {
|
||||
for(const txin_v& in: tx.vin)
|
||||
{
|
||||
for (size_t i = 0; i < o.second.size(); ++i)
|
||||
{
|
||||
output_index &oi = outs[o.first][o.second[i]];
|
||||
|
||||
// construct key image for this output
|
||||
crypto::key_image out_ki;
|
||||
keypair in_ephemeral;
|
||||
generate_key_image_helper(from, get_tx_pub_key_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, out_ki);
|
||||
|
||||
// lookup for this key image in the events std::vector
|
||||
for(auto& tx_pair : mtx)
|
||||
{
|
||||
const transaction& tx = *tx_pair.second;
|
||||
for(const txin_v &in : tx.vin)
|
||||
{
|
||||
if (typeid(txin_to_key) == in.type())
|
||||
{
|
||||
const txin_to_key &itk = boost::get<txin_to_key>(in);
|
||||
if (itk.k_image == out_ki)
|
||||
oi.spent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check whether this key image has been spent in miner tx of a PoS block
|
||||
// TODO change this check to simply adding PoS miner tx to mtx map
|
||||
for (auto& b : blockchain)
|
||||
{
|
||||
if (!is_pos_block(b))
|
||||
continue;
|
||||
for (const txin_v &in : b.miner_tx.vin)
|
||||
{
|
||||
if (in.type() == typeid(txin_to_key))
|
||||
{
|
||||
const txin_to_key &itk = boost::get<txin_to_key>(in);
|
||||
if (itk.k_image == out_ki)
|
||||
oi.spent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
crypto::key_image ki{};
|
||||
if (get_key_image_from_txin_v(in, ki))
|
||||
if (!spent_key_images.insert(ki).second)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
for(auto& tx_pair : mtx)
|
||||
add_key_images_from_tx(*tx_pair.second); // some key images may be added more than once (because invalid txs can't be detected here), ignore that
|
||||
|
||||
for (auto& b : blockchain)
|
||||
{
|
||||
if (is_pos_block(b))
|
||||
CHECK_AND_ASSERT_MES(add_key_images_from_tx(b.miner_tx), false, "insertion of spent key image failed for miner tx " << get_transaction_hash(b.miner_tx));
|
||||
}
|
||||
|
||||
// 2. check outputs from outs_mine against spent key images
|
||||
if (spent_key_images.empty())
|
||||
return true;
|
||||
|
||||
for(const map_output_t::value_type &o : outs_mine)
|
||||
{
|
||||
for (size_t i = 0; i < o.second.size(); ++i)
|
||||
{
|
||||
output_index &oi = outs[o.first][o.second[i]];
|
||||
|
||||
// construct key image for this output
|
||||
crypto::key_image out_ki;
|
||||
keypair in_ephemeral;
|
||||
generate_key_image_helper(from, get_tx_pub_key_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, out_ki); // TODO: store ki and secret ephemeral for further use
|
||||
|
||||
if (spent_key_images.count(out_ki) != 0)
|
||||
oi.spent = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fill_output_entries(std::vector<output_index>& out_indices,
|
||||
size_t sender_out, size_t nmix, uint64_t& real_entry_idx,
|
||||
std::vector<tx_source_entry::output_entry>& output_entries,
|
||||
bool use_ref_by_id)
|
||||
bool fill_output_entries(const std::vector<output_index>& out_indices, size_t real_out_index, size_t nmix, bool check_for_unlocktime, bool use_ref_by_id,
|
||||
uint64_t next_block_height, uint64_t head_block_ts, uint64_t& real_entry_idx, std::vector<tx_source_entry::output_entry>& output_entries)
|
||||
{
|
||||
// use_ref_by_id = true; // <-- HINT: this could be used to enforce using ref_by_id across all the tests if needed
|
||||
|
||||
if (out_indices.size() <= nmix)
|
||||
return false;
|
||||
|
||||
|
|
@ -1092,7 +1115,7 @@ bool fill_output_entries(std::vector<output_index>& out_indices,
|
|||
continue;
|
||||
|
||||
bool append = false;
|
||||
if (i == sender_out)
|
||||
if (i == real_out_index)
|
||||
{
|
||||
append = true;
|
||||
sender_out_found = true;
|
||||
|
|
@ -1100,8 +1123,30 @@ bool fill_output_entries(std::vector<output_index>& out_indices,
|
|||
}
|
||||
else if (0 < rest)
|
||||
{
|
||||
if(boost::get<txout_to_key>(oi.out).mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX || boost::get<txout_to_key>(oi.out).mix_attr > nmix+1)
|
||||
continue;
|
||||
uint8_t mix_attr = 0;
|
||||
if (get_mix_attr_from_tx_out_v(oi.out_v, mix_attr))
|
||||
{
|
||||
if (mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX || mix_attr > nmix + 1)
|
||||
continue;
|
||||
|
||||
if (check_for_unlocktime)
|
||||
{
|
||||
uint64_t unlock_time = get_tx_max_unlock_time(*oi.p_tx);
|
||||
if (unlock_time < CURRENCY_MAX_BLOCK_NUMBER)
|
||||
{
|
||||
//interpret as block index
|
||||
if (unlock_time > next_block_height)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
//interpret as time
|
||||
if (unlock_time > head_block_ts + DIFFICULTY_TOTAL_TARGET)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
--rest;
|
||||
append = true;
|
||||
|
|
@ -1109,20 +1154,28 @@ bool fill_output_entries(std::vector<output_index>& out_indices,
|
|||
|
||||
if (append)
|
||||
{
|
||||
tx_source_entry::output_entry oe = AUTO_VAL_INIT(oe);
|
||||
const txout_to_key& otk = boost::get<txout_to_key>(oi.out);
|
||||
if (use_ref_by_id) // <-- HINT: this could be replaced by 'true' to enforce using ref_by_id across all the tests if needed
|
||||
txout_ref_v out_ref_v{};
|
||||
if (use_ref_by_id)
|
||||
{
|
||||
ref_by_id rbi = AUTO_VAL_INIT(rbi);
|
||||
rbi.n = oi.out_no;
|
||||
rbi.tx_id = get_transaction_hash(*oi.p_tx);
|
||||
oe = tx_source_entry::output_entry(rbi, otk.key);
|
||||
out_ref_v = rbi;
|
||||
}
|
||||
else
|
||||
{
|
||||
oe = tx_source_entry::output_entry(oi.idx, otk.key);
|
||||
out_ref_v = oi.idx;
|
||||
}
|
||||
output_entries.push_back(oe);
|
||||
|
||||
VARIANT_SWITCH_BEGIN(oi.out_v)
|
||||
VARIANT_CASE_CONST(tx_out_bare, ob)
|
||||
VARIANT_SWITCH_BEGIN(ob.target)
|
||||
VARIANT_CASE_CONST(txout_to_key, otk)
|
||||
output_entries.emplace_back(out_ref_v, otk.key);
|
||||
VARIANT_SWITCH_END()
|
||||
VARIANT_CASE_CONST(tx_out_zarcanum, ozc)
|
||||
output_entries.emplace_back(out_ref_v, ozc.stealth_address, ozc.concealing_point, ozc.amount_commitment);
|
||||
VARIANT_SWITCH_END()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1141,110 +1194,117 @@ bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std:
|
|||
const currency::block& blk_head, const currency::account_keys& from, uint64_t amount, size_t nmix, const std::vector<currency::tx_source_entry>& sources_to_avoid,
|
||||
bool check_for_spends, bool check_for_unlocktime, bool use_ref_by_id, uint64_t* p_sources_amount_found /* = nullptr */)
|
||||
{
|
||||
map_output_idx_t outs;
|
||||
map_output_t outs_mine;
|
||||
map_output_idx_t outs;
|
||||
map_output_t outs_mine;
|
||||
|
||||
std::vector<currency::block> blockchain;
|
||||
map_hash2tx_t mtx;
|
||||
if (!find_block_chain(events, blockchain, mtx, get_block_hash(blk_head)))
|
||||
return false;
|
||||
std::vector<currency::block> blockchain;
|
||||
map_hash2tx_t mtx;
|
||||
if (!find_block_chain(events, blockchain, mtx, get_block_hash(blk_head)))
|
||||
return false;
|
||||
|
||||
if (!init_output_indices(outs, outs_mine, blockchain, mtx, from))
|
||||
return false;
|
||||
if (!init_output_indices(outs, outs_mine, blockchain, mtx, from))
|
||||
return false;
|
||||
|
||||
if(check_for_spends)
|
||||
if(check_for_spends)
|
||||
{
|
||||
if (!init_spent_output_indices(outs, outs_mine, blockchain, mtx, from))
|
||||
return false;
|
||||
}
|
||||
|
||||
// mark some outputs as spent to avoid their using
|
||||
for (const auto& s : sources_to_avoid)
|
||||
{
|
||||
for (const auto& s_outputs_el : s.outputs) // avoid all outputs, including fake mix-ins
|
||||
{
|
||||
if (!init_spent_output_indices(outs, outs_mine, blockchain, mtx, from))
|
||||
return false;
|
||||
}
|
||||
|
||||
// mark some outputs as spent to avoid their using
|
||||
for (const auto& s : sources_to_avoid)
|
||||
{
|
||||
for (const auto& s_outputs_el : s.outputs) // avoid all outputs, including fake mix-ins
|
||||
txout_ref_v sout = s_outputs_el.out_reference;
|
||||
if (sout.type().hash_code() == typeid(uint64_t).hash_code()) // output by global index
|
||||
{
|
||||
txout_ref_v sout = s_outputs_el.out_reference;
|
||||
if (sout.type().hash_code() == typeid(uint64_t).hash_code()) // output by global index
|
||||
uint64_t gindex = boost::get<uint64_t>(sout);
|
||||
auto& outs_by_amount = outs[s.amount];
|
||||
if (gindex >= outs_by_amount.size())
|
||||
return false;
|
||||
outs_by_amount[gindex].spent = true;
|
||||
}
|
||||
else if (sout.type().hash_code() == typeid(ref_by_id).hash_code()) // output by ref_by_id
|
||||
{
|
||||
ref_by_id out_ref_by_id = boost::get<ref_by_id>(sout);
|
||||
const auto it = mtx.find(out_ref_by_id.tx_id);
|
||||
if (it == mtx.end())
|
||||
return false;
|
||||
const transaction* p_tx = it->second;
|
||||
for (auto& e : outs[s.amount]) // linear search by transaction among all outputs with such amount
|
||||
{
|
||||
uint64_t gindex = boost::get<uint64_t>(sout);
|
||||
auto& outs_by_amount = outs[s.amount];
|
||||
if (gindex >= outs_by_amount.size())
|
||||
return false;
|
||||
outs_by_amount[gindex].spent = true;
|
||||
}
|
||||
else if (sout.type().hash_code() == typeid(ref_by_id).hash_code()) // output by ref_by_id
|
||||
{
|
||||
ref_by_id out_ref_by_id = boost::get<ref_by_id>(sout);
|
||||
const auto it = mtx.find(out_ref_by_id.tx_id);
|
||||
if (it == mtx.end())
|
||||
return false;
|
||||
const transaction* p_tx = it->second;
|
||||
for (auto& e : outs[s.amount]) // linear search by transaction among all outputs with such amount
|
||||
if (e.p_tx == p_tx)
|
||||
{
|
||||
if (e.p_tx == p_tx)
|
||||
{
|
||||
e.spent = true;
|
||||
p_tx = nullptr; // means 'found'
|
||||
break;
|
||||
}
|
||||
e.spent = true;
|
||||
p_tx = nullptr; // means 'found'
|
||||
break;
|
||||
}
|
||||
if (p_tx != nullptr)
|
||||
return false; // output, referring by ref_by_id was not found
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // unknown output type
|
||||
}
|
||||
if (p_tx != nullptr)
|
||||
return false; // output, referring by ref_by_id was not found
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // unknown output type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate in reverse is more efficiency
|
||||
uint64_t sources_amount = 0;
|
||||
bool sources_found = false;
|
||||
BOOST_REVERSE_FOREACH(const map_output_t::value_type o, outs_mine)
|
||||
uint64_t head_block_ts = get_actual_timestamp(blk_head);
|
||||
uint64_t next_block_height = blockchain.size();
|
||||
|
||||
// Iterate in reverse is more efficiency
|
||||
uint64_t sources_amount = 0;
|
||||
bool sources_found = false;
|
||||
BOOST_REVERSE_FOREACH(const map_output_t::value_type o, outs_mine)
|
||||
{
|
||||
for (size_t i = 0; i < o.second.size() && !sources_found; ++i)
|
||||
{
|
||||
for (size_t i = 0; i < o.second.size() && !sources_found; ++i)
|
||||
size_t sender_out = o.second[i];
|
||||
const output_index& oi = outs[o.first][sender_out];
|
||||
if (oi.spent)
|
||||
continue;
|
||||
if (check_for_unlocktime)
|
||||
{
|
||||
uint64_t unlock_time = currency::get_tx_max_unlock_time(*oi.p_tx);
|
||||
if (unlock_time < CURRENCY_MAX_BLOCK_NUMBER)
|
||||
{
|
||||
size_t sender_out = o.second[i];
|
||||
const output_index& oi = outs[o.first][sender_out];
|
||||
if (oi.spent)
|
||||
continue;
|
||||
if (check_for_unlocktime)
|
||||
{
|
||||
if (currency::get_tx_max_unlock_time(*oi.p_tx) < CURRENCY_MAX_BLOCK_NUMBER)
|
||||
{
|
||||
//interpret as block index
|
||||
if (currency::get_tx_max_unlock_time(*oi.p_tx) > blockchain.size())
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
//interpret as time
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
currency::tx_source_entry ts = AUTO_VAL_INIT(ts);
|
||||
ts.amount = oi.amount;
|
||||
ts.real_output_in_tx_index = oi.out_no;
|
||||
ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // incoming tx public key
|
||||
if (!fill_output_entries(outs[o.first], sender_out, nmix, ts.real_output, ts.outputs, use_ref_by_id))
|
||||
continue;
|
||||
|
||||
sources.push_back(ts);
|
||||
|
||||
sources_amount += ts.amount;
|
||||
sources_found = amount <= sources_amount;
|
||||
//interpret as block index
|
||||
if (unlock_time > next_block_height)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
//interpret as time
|
||||
if (unlock_time > head_block_ts + DIFFICULTY_TOTAL_TARGET)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (sources_found)
|
||||
break;
|
||||
|
||||
currency::tx_source_entry ts = AUTO_VAL_INIT(ts);
|
||||
ts.amount = oi.amount;
|
||||
ts.real_out_amount_blinding_mask = oi.blinding_mask;
|
||||
ts.real_output_in_tx_index = oi.out_no;
|
||||
ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // source tx public key
|
||||
if (!fill_output_entries(outs[o.first], sender_out, nmix, check_for_unlocktime, use_ref_by_id, next_block_height, head_block_ts, ts.real_output, ts.outputs))
|
||||
continue;
|
||||
|
||||
sources.push_back(ts);
|
||||
|
||||
sources_amount += ts.amount;
|
||||
sources_found = amount <= sources_amount;
|
||||
}
|
||||
|
||||
if (p_sources_amount_found != nullptr)
|
||||
*p_sources_amount_found = sources_amount;
|
||||
if (sources_found)
|
||||
break;
|
||||
}
|
||||
|
||||
return sources_found;
|
||||
if (p_sources_amount_found != nullptr)
|
||||
*p_sources_amount_found = sources_amount;
|
||||
|
||||
return sources_found;
|
||||
}
|
||||
|
||||
bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& events, const block& blk_head,
|
||||
|
|
@ -1264,9 +1324,9 @@ bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
|
|||
|
||||
uint64_t source_amount_found = 0;
|
||||
bool r = fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix, std::vector<currency::tx_source_entry>(), check_for_spends, check_for_unlocktime, use_ref_by_id, &source_amount_found);
|
||||
CHECK_AND_ASSERT_MES(r, false, "couldn't fill transaction sources: " << ENDL <<
|
||||
CHECK_AND_ASSERT_MES(r, false, "couldn't fill transaction sources (nmix = " << nmix << "): " << ENDL <<
|
||||
" required: " << print_money(amount + fee) << " = " << std::fixed << std::setprecision(1) << ceil(1.0 * (amount + fee) / TESTS_DEFAULT_FEE) << " x TESTS_DEFAULT_FEE" << ENDL <<
|
||||
" unspent coins: " << print_money(source_amount_found) << " = " << std::fixed << std::setprecision(1) << ceil(1.0 * source_amount_found / TESTS_DEFAULT_FEE) << " x TESTS_DEFAULT_FEE" << ENDL <<
|
||||
" found coins: " << print_money(source_amount_found) << " = " << std::fixed << std::setprecision(1) << ceil(1.0 * source_amount_found / TESTS_DEFAULT_FEE) << " x TESTS_DEFAULT_FEE" << ENDL <<
|
||||
" lack of coins: " << print_money(amount + fee - source_amount_found) << " = " << std::fixed << std::setprecision(1) << ceil(1.0 * (amount + fee - source_amount_found) / TESTS_DEFAULT_FEE) << " x TESTS_DEFAULT_FEE"
|
||||
);
|
||||
|
||||
|
|
@ -1301,6 +1361,18 @@ bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
|
|||
case tests_digits_split_strategy:
|
||||
tools::detail::digit_split_strategy(dsts, change_dst, tgs.dust_threshold, destinations, dust, tgs.tx_max_out_amount);
|
||||
break;
|
||||
case tests_random_split_strategy:
|
||||
{
|
||||
size_t outs_count = cache_back > 0 ? 2 : 1;
|
||||
if (outs_count < tgs.rss_min_number_of_outputs)
|
||||
{
|
||||
// decompose both target and cache back amounts
|
||||
// TODO: support tgs.tx_max_out_amount
|
||||
decompose_amount_randomly(amount, [&](uint64_t a){ destinations.emplace_back(a, to.back()); }, tgs.rss_min_number_of_outputs, tgs.rss_num_digits_to_keep);
|
||||
decompose_amount_randomly(cache_back, [&](uint64_t a){ destinations.emplace_back(a, from.account_address); }, tgs.rss_min_number_of_outputs, tgs.rss_num_digits_to_keep);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CHECK_AND_ASSERT_MES(false, false, "Invalid split strategy set in gentime settings");
|
||||
}
|
||||
|
|
@ -1436,7 +1508,7 @@ bool construct_tx_to_key(const currency::hard_forks_descriptor& hf,
|
|||
std::vector<tx_destination_entry> destinations;
|
||||
if (!fill_tx_sources_and_destinations(events, blk_head, from.get_keys(), to.get_public_address(), amount, fee, nmix, sources, destinations, check_for_spends, check_for_unlocktime))
|
||||
return false;
|
||||
uint64_t tx_version = currency::get_tx_version(get_block_height(blk_head), hf);
|
||||
uint64_t tx_version = currency::get_tx_version(get_block_height(blk_head) + 1, hf); // assuming the tx will be in the next block (blk_head + 1)
|
||||
return construct_tx(from.get_keys(), sources, destinations, extr, att, tx, tx_version, sk, 0, mix_attr);
|
||||
}
|
||||
|
||||
|
|
@ -1506,33 +1578,36 @@ bool construct_tx_with_many_outputs(const currency::hard_forks_descriptor& hf, s
|
|||
return construct_tx(keys_from, sources, destinations, empty_attachment, tx, tx_version, 0);
|
||||
}
|
||||
|
||||
uint64_t get_balance(const currency::account_keys& addr, const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, bool dbg_log) {
|
||||
uint64_t res = 0;
|
||||
std::map<uint64_t, std::vector<output_index> > outs;
|
||||
std::map<uint64_t, std::vector<size_t> > outs_mine;
|
||||
uint64_t get_balance(const currency::account_keys& addr, const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, bool dbg_log)
|
||||
{
|
||||
uint64_t res = 0;
|
||||
std::map<uint64_t, std::vector<output_index> > outs;
|
||||
std::map<uint64_t, std::vector<size_t> > outs_mine;
|
||||
|
||||
map_hash2tx_t confirmed_txs;
|
||||
get_confirmed_txs(blockchain, mtx, confirmed_txs);
|
||||
map_hash2tx_t confirmed_txs;
|
||||
get_confirmed_txs(blockchain, mtx, confirmed_txs);
|
||||
|
||||
if (!init_output_indices(outs, outs_mine, blockchain, confirmed_txs, addr))
|
||||
return false;
|
||||
if (!init_output_indices(outs, outs_mine, blockchain, confirmed_txs, addr))
|
||||
return false;
|
||||
|
||||
if (!init_spent_output_indices(outs, outs_mine, blockchain, confirmed_txs, addr))
|
||||
return false;
|
||||
if (!init_spent_output_indices(outs, outs_mine, blockchain, confirmed_txs, addr))
|
||||
return false;
|
||||
|
||||
BOOST_FOREACH (const map_output_t::value_type &o, outs_mine) {
|
||||
for (size_t i = 0; i < o.second.size(); ++i) {
|
||||
if (outs[o.first][o.second[i]].spent)
|
||||
continue;
|
||||
for (const map_output_t::value_type &o : outs_mine)
|
||||
{
|
||||
for (size_t i = 0; i < o.second.size(); ++i)
|
||||
{
|
||||
if (outs[o.first][o.second[i]].spent)
|
||||
continue;
|
||||
|
||||
output_index& oiv = outs[o.first][o.second[i]];
|
||||
res += oiv.amount;
|
||||
if (dbg_log)
|
||||
LOG_PRINT_L0(oiv.toString());
|
||||
}
|
||||
output_index& oiv = outs[o.first][o.second[i]];
|
||||
res += oiv.amount;
|
||||
if (dbg_log)
|
||||
LOG_PRINT_L0(oiv.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
uint64_t get_balance(const currency::account_base& addr, const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, bool dbg_log)
|
||||
|
|
@ -1562,9 +1637,14 @@ void get_confirmed_txs(const std::vector<currency::block>& blockchain, const map
|
|||
|
||||
bool find_block_chain(const std::vector<test_event_entry>& events, std::vector<currency::block>& blockchain, map_hash2tx_t& mtx, const crypto::hash& head)
|
||||
{
|
||||
size_t invalid_tx_index = UINT64_MAX;
|
||||
size_t invalid_block_index = UINT64_MAX;
|
||||
std::unordered_map<crypto::hash, const block*> block_index;
|
||||
for(size_t i = 0, sz = events.size(); i < sz; ++i)
|
||||
{
|
||||
if (invalid_tx_index == i || invalid_block_index == i)
|
||||
continue;
|
||||
|
||||
const test_event_entry& ev = events[i];
|
||||
if (typeid(currency::block) == ev.type())
|
||||
{
|
||||
|
|
@ -1584,6 +1664,14 @@ bool find_block_chain(const std::vector<test_event_entry>& events, std::vector<c
|
|||
const transaction& tx = boost::get<transaction>(ev);
|
||||
mtx[get_transaction_hash(tx)] = &tx;
|
||||
}
|
||||
else if (test_chain_unit_enchanced::is_event_mark_invalid_block(ev))
|
||||
{
|
||||
invalid_block_index = i + 1;
|
||||
}
|
||||
else if (test_chain_unit_enchanced::is_event_mark_invalid_tx(ev))
|
||||
{
|
||||
invalid_tx_index = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool b_success = false;
|
||||
|
|
@ -1626,7 +1714,7 @@ bool check_balance_via_wallet(const tools::wallet2& w, const char* account_name,
|
|||
uint64_t total, unlocked, awaiting_in, awaiting_out, mined;
|
||||
balance_via_wallet(w, &total, &unlocked, &awaiting_in, &awaiting_out, &mined);
|
||||
|
||||
LOG_PRINT_CYAN("Balance for wallet " << account_name << ":" << ENDL <<
|
||||
LOG_PRINT_CYAN("Balance for wallet " << account_name << " @ height " << w.get_top_block_height() << ":" << ENDL <<
|
||||
"unlocked: " << print_money(unlocked) << ENDL <<
|
||||
"awaiting in: " << print_money(awaiting_in) << ENDL <<
|
||||
"awaiting out: " << print_money(awaiting_out) << ENDL <<
|
||||
|
|
@ -1925,7 +2013,7 @@ bool generate_pos_block_with_given_coinstake(test_generator& generator, const st
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake_tx.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner.get_public_address());
|
||||
|
|
@ -1992,16 +2080,36 @@ bool check_mixin_value_for_each_input(size_t mixin, const crypto::hash& tx_id, c
|
|||
for (size_t i = 0; i < ptce->tx.vin.size(); ++i)
|
||||
{
|
||||
auto& input = ptce->tx.vin[i];
|
||||
if (input.type() == typeid(txin_to_key))
|
||||
{
|
||||
auto& intk = boost::get<txin_to_key>(input);
|
||||
CHECK_AND_ASSERT_MES(intk.key_offsets.size() == mixin + 1, false, "for input #" << i << " mixin count is " << intk.key_offsets.size() - 1 << ", expected is " << mixin);
|
||||
}
|
||||
const std::vector<currency::txout_ref_v>& key_offsets = get_key_offsets_from_txin_v(input);
|
||||
CHECK_AND_ASSERT_MES(key_offsets.size() == mixin + 1, false, "for input #" << i << " mixin count is " << key_offsets.size() - 1 << ", expected is " << mixin);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// randomly shuffles tx_source_entry, restores the correct real_output afterwards
|
||||
bool shuffle_source_entry(tx_source_entry& se)
|
||||
{
|
||||
if (se.outputs.size() < 2)
|
||||
return true;
|
||||
tx_source_entry::output_entry real_out_entry = se.outputs[se.real_output]; // store the real one
|
||||
std::shuffle(se.outputs.begin(), se.outputs.end(), crypto::uniform_random_bit_generator{}); // shuffle
|
||||
auto it = std::find(se.outputs.begin(), se.outputs.end(), real_out_entry); // where is the real one now?
|
||||
CHECK_AND_ASSERT_MES(it != se.outputs.end(), false, "cannot find the real one output entry");
|
||||
se.real_output = it - se.outputs.begin(); // restore the real output index
|
||||
return true;
|
||||
}
|
||||
|
||||
// randomly shuffles std::vector<tx_source_entry>, restores the correct real_output afterwards
|
||||
bool shuffle_source_entries(std::vector<tx_source_entry>& sources)
|
||||
{
|
||||
for(auto& se : sources)
|
||||
if (!shuffle_source_entry(se))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void test_chain_unit_base::register_callback(const std::string& cb_name, verify_callback cb)
|
||||
|
|
@ -2033,6 +2141,11 @@ bool test_chain_unit_base::verify(const std::string& cb_name, currency::core& c,
|
|||
return cb_it->second(c, ev_index, events);
|
||||
}
|
||||
|
||||
void test_chain_unit_base::on_test_generator_created(test_generator& gen) const
|
||||
{
|
||||
gen.set_hardforks(m_hardforks);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
test_chain_unit_enchanced::test_chain_unit_enchanced()
|
||||
|
|
@ -2055,6 +2168,7 @@ test_chain_unit_enchanced::test_chain_unit_enchanced()
|
|||
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, remove_stuck_txs);
|
||||
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, check_offers_count);
|
||||
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, check_hardfork_active);
|
||||
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, check_hardfork_inactive);
|
||||
}
|
||||
|
||||
bool test_chain_unit_enchanced::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
|
|
@ -2191,12 +2305,51 @@ bool test_chain_unit_enchanced::check_hardfork_active(currency::core& c, size_t
|
|||
const std::string& params = boost::get<callback_entry>(events[ev_index]).callback_params;
|
||||
CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(params, hardfork_id_to_check), false, "hex_to_pod failed, params = " << params);
|
||||
|
||||
uint64_t top_block_height = c.get_top_block_height();
|
||||
if (!c.get_blockchain_storage().get_core_runtime_config().is_hardfork_active_for_height(hardfork_id_to_check, top_block_height))
|
||||
if (!c.get_blockchain_storage().is_hardfork_active(hardfork_id_to_check))
|
||||
{
|
||||
LOG_ERROR("Hardfork #" << hardfork_id_to_check << " is not active yet (top block height is " << top_block_height << ")");
|
||||
LOG_ERROR("Hardfork #" << hardfork_id_to_check << " is not active yet (top block height is " << c.get_top_block_height() << ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_chain_unit_enchanced::check_hardfork_inactive(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
size_t hardfork_id_to_check = 0;
|
||||
const std::string& params = boost::get<callback_entry>(events[ev_index]).callback_params;
|
||||
CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(params, hardfork_id_to_check), false, "hex_to_pod failed, params = " << params);
|
||||
|
||||
if (c.get_blockchain_storage().is_hardfork_active(hardfork_id_to_check))
|
||||
{
|
||||
LOG_ERROR("Hardfork #" << hardfork_id_to_check << " is active, which is not expected (top block height is " << c.get_top_block_height() << ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*static*/ bool test_chain_unit_enchanced::is_event_mark_invalid_block(const test_event_entry& ev, bool use_global_gentime_settings /* = true */)
|
||||
{
|
||||
if (use_global_gentime_settings && !test_generator::get_test_gentime_settings().ignore_invalid_blocks)
|
||||
return false;
|
||||
|
||||
if (typeid(callback_entry) != ev.type())
|
||||
return false;
|
||||
|
||||
const callback_entry& ce = boost::get<callback_entry>(ev);
|
||||
return ce.callback_name == "mark_invalid_block";
|
||||
}
|
||||
|
||||
/*static*/ bool test_chain_unit_enchanced::is_event_mark_invalid_tx(const test_event_entry& ev, bool use_global_gentime_settings /* = true */)
|
||||
{
|
||||
if (use_global_gentime_settings && !test_generator::get_test_gentime_settings().ignore_invalid_txs)
|
||||
return false;
|
||||
|
||||
if (typeid(callback_entry) != ev.type())
|
||||
return false;
|
||||
|
||||
const callback_entry& ce = boost::get<callback_entry>(ev);
|
||||
return ce.callback_name == "mark_invalid_tx";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 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
|
||||
|
|
@ -212,17 +212,21 @@ VARIANT_TAG(binary_archive, event_core_time, 0xd1);
|
|||
typedef boost::variant<currency::block, currency::transaction, currency::account_base, callback_entry, serialized_block, serialized_transaction, event_visitor_settings, event_special_block, event_core_time> test_event_entry;
|
||||
typedef std::unordered_map<crypto::hash, const currency::transaction*> map_hash2tx_t;
|
||||
|
||||
enum test_tx_split_strategy { tests_void_split_strategy, tests_null_split_strategy, tests_digits_split_strategy };
|
||||
enum test_tx_split_strategy { tests_void_split_strategy, tests_null_split_strategy, tests_digits_split_strategy, tests_random_split_strategy };
|
||||
struct test_gentime_settings
|
||||
{
|
||||
test_gentime_settings(test_tx_split_strategy split_strategy, size_t miner_tx_max_outs, uint64_t tx_max_out_amount, uint64_t dust_threshold)
|
||||
: split_strategy(split_strategy), miner_tx_max_outs(miner_tx_max_outs), tx_max_out_amount(tx_max_out_amount), dust_threshold(dust_threshold) {}
|
||||
test_tx_split_strategy split_strategy;
|
||||
size_t miner_tx_max_outs;
|
||||
uint64_t tx_max_out_amount;
|
||||
uint64_t dust_threshold;
|
||||
test_tx_split_strategy split_strategy = tests_digits_split_strategy;
|
||||
size_t miner_tx_max_outs = CURRENCY_MINER_TX_MAX_OUTS;
|
||||
uint64_t tx_max_out_amount = WALLET_MAX_ALLOWED_OUTPUT_AMOUNT;
|
||||
uint64_t dust_threshold = DEFAULT_DUST_THRESHOLD;
|
||||
size_t rss_min_number_of_outputs = CURRENCY_TX_MIN_ALLOWED_OUTS; // for random split strategy: min (target) number of tx outputs, one output will be split into this many parts
|
||||
size_t rss_num_digits_to_keep = CURRENCY_TX_OUTS_RND_SPLIT_DIGITS_TO_KEEP; // for random split strategy: number of digits to keep
|
||||
bool ignore_invalid_blocks = true; // gen-time blockchain building: don't take into account blocks marked as invalid ("mark_invalid_block")
|
||||
bool ignore_invalid_txs = true; // gen-time blockchain building: don't take into account txs marked as invalid ("mark_invalid_txs")
|
||||
};
|
||||
|
||||
class test_generator;
|
||||
|
||||
class test_chain_unit_base
|
||||
{
|
||||
public:
|
||||
|
|
@ -236,6 +240,8 @@ public:
|
|||
void set_core_proxy(std::shared_ptr<tools::i_core_proxy>) { /* do nothing */ }
|
||||
uint64_t get_tx_version_from_events(const std::vector<test_event_entry> &events) const;
|
||||
|
||||
void on_test_generator_created(test_generator& generator) const; // tests can override this for special initialization
|
||||
|
||||
private:
|
||||
callbacks_map m_callbacks;
|
||||
|
||||
|
|
@ -313,8 +319,10 @@ public:
|
|||
bool remove_stuck_txs(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool check_offers_count(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool check_hardfork_active(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool check_hardfork_inactive(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
|
||||
static bool is_event_mark_invalid_block(const test_event_entry& ev, bool use_global_gentime_settings = true);
|
||||
static bool is_event_mark_invalid_tx(const test_event_entry& ev, bool use_global_gentime_settings = true);
|
||||
|
||||
protected:
|
||||
struct params_top_block
|
||||
|
|
@ -434,14 +442,13 @@ public:
|
|||
bool init_test_wallet(const currency::account_base& account, const crypto::hash& genesis_hash, std::shared_ptr<tools::wallet2> &result);
|
||||
bool refresh_test_wallet(const std::vector<test_event_entry>& events, tools::wallet2* w, const crypto::hash& top_block_hash, size_t expected_blocks_to_be_fetched = std::numeric_limits<size_t>::max());
|
||||
|
||||
bool sign_block(currency::block& b,
|
||||
currency::pos_entry& pe,
|
||||
tools::wallet2& w,
|
||||
const tools::wallet2::mining_context& mining_context,
|
||||
const blockchain_vector& blocks,
|
||||
const outputs_index& oi);
|
||||
bool sign_block(const tools::wallet2::mining_context& mining_context,
|
||||
const currency::pos_entry& pe,
|
||||
const tools::wallet2& w,
|
||||
const crypto::scalar_t& blinding_masks_sum,
|
||||
currency::block& b);
|
||||
|
||||
bool get_output_details_by_global_index(const test_generator::blockchain_vector& blck_chain,
|
||||
/*bool get_output_details_by_global_index(const test_generator::blockchain_vector& blck_chain,
|
||||
const test_generator::outputs_index& indexes,
|
||||
uint64_t amount,
|
||||
uint64_t global_index,
|
||||
|
|
@ -449,7 +456,7 @@ public:
|
|||
const currency::transaction* tx,
|
||||
uint64_t& tx_out_index,
|
||||
crypto::public_key& tx_pub_key,
|
||||
crypto::public_key& output_key);
|
||||
crypto::public_key& output_key);*/
|
||||
|
||||
|
||||
|
||||
|
|
@ -538,9 +545,16 @@ private:
|
|||
|
||||
std::unordered_map<crypto::hash, block_info> m_blocks_info;
|
||||
static test_gentime_settings m_test_gentime_settings;
|
||||
static test_gentime_settings m_test_gentime_settings_default;
|
||||
static const test_gentime_settings m_test_gentime_settings_default;
|
||||
}; // class class test_generator
|
||||
|
||||
struct test_gentime_settings_restorer
|
||||
{
|
||||
test_gentime_settings_restorer() : m_settings(test_generator::get_test_gentime_settings()) {}
|
||||
~test_gentime_settings_restorer() { test_generator::set_test_gentime_settings(m_settings); }
|
||||
test_gentime_settings m_settings;
|
||||
};
|
||||
|
||||
extern const crypto::signature invalid_signature; // invalid non-null signature for test purpose
|
||||
static const std::vector<currency::extra_v> empty_extra;
|
||||
static const std::vector<currency::attachment_v> empty_attachment;
|
||||
|
|
@ -680,6 +694,9 @@ bool check_ring_signature_at_gen_time(const std::vector<test_event_entry>& event
|
|||
|
||||
bool check_mixin_value_for_each_input(size_t mixin, const crypto::hash& tx_id, currency::core& c);
|
||||
|
||||
bool shuffle_source_entry(currency::tx_source_entry& se);
|
||||
bool shuffle_source_entries(std::vector<currency::tx_source_entry>& sources);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
template<class t_test_class>
|
||||
auto do_check_tx_verification_context(const currency::tx_verification_context& tvc, bool tx_added, size_t event_index, const currency::transaction& tx, t_test_class& validator, int)
|
||||
|
|
@ -790,7 +807,7 @@ bool construct_broken_tx(const currency::account_keys& sender_account_keys, cons
|
|||
BOOST_FOREACH(const currency::tx_source_entry::output_entry& out_entry, src_entr.outputs)
|
||||
input_to_key.key_offsets.push_back(out_entry.out_reference);
|
||||
|
||||
input_to_key.key_offsets = currency::absolute_output_offsets_to_relative(input_to_key.key_offsets);
|
||||
input_to_key.key_offsets = currency::absolute_output_offsets_to_relative(input_to_key.key_offsets); // TODO @#@#
|
||||
tx.vin.push_back(input_to_key);
|
||||
}
|
||||
|
||||
|
|
@ -1006,6 +1023,7 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
#define MAKE_GENESIS_BLOCK(VEC_EVENTS, BLK_NAME, MINER_ACC, TS) \
|
||||
PRINT_EVENT_N_TEXT(VEC_EVENTS, "MAKE_GENESIS_BLOCK(" << #BLK_NAME << ")"); \
|
||||
test_generator generator; \
|
||||
this->on_test_generator_created(generator); \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
generator.construct_genesis_block(BLK_NAME, MINER_ACC, TS); \
|
||||
VEC_EVENTS.push_back(BLK_NAME)
|
||||
|
|
@ -1019,19 +1037,19 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
|
||||
|
||||
#define MAKE_NEXT_BLOCK_TIMESTAMP_ADJUSTMENT(ADJ, VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC) \
|
||||
PRINT_EVENT_N(VEC_EVENTS); \
|
||||
PRINT_EVENT_N_TEXT(VEC_EVENTS, "MAKE_NEXT_BLOCK_TIMESTAMP_ADJUSTMENT(" << #BLK_NAME << ")"); \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
generator.construct_block(ADJ, VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC); \
|
||||
VEC_EVENTS.push_back(BLK_NAME)
|
||||
|
||||
#define MAKE_NEXT_POS_BLOCK(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, MINERS_ACC_LIST) \
|
||||
PRINT_EVENT_N(VEC_EVENTS); \
|
||||
PRINT_EVENT_N_TEXT(VEC_EVENTS, "MAKE_NEXT_POS_BLOCK(" << #BLK_NAME << ")"); \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
generator.construct_block(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, std::list<currency::transaction>(), MINERS_ACC_LIST); \
|
||||
VEC_EVENTS.push_back(BLK_NAME)
|
||||
|
||||
#define MAKE_NEXT_POS_BLOCK_TX1(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, MINERS_ACC_LIST, TX_1) \
|
||||
PRINT_EVENT_N(VEC_EVENTS); \
|
||||
PRINT_EVENT_N_TEXT(VEC_EVENTS, "MAKE_NEXT_POS_BLOCK_TX1(" << #BLK_NAME << ")"); \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
{ \
|
||||
std::list<currency::transaction>tx_list; \
|
||||
|
|
@ -1041,7 +1059,7 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
VEC_EVENTS.push_back(BLK_NAME)
|
||||
|
||||
#define MAKE_NEXT_BLOCK_NO_ADD(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC) \
|
||||
PRINT_EVENT_N(VEC_EVENTS); \
|
||||
PRINT_EVENT_N_TEXT(VEC_EVENTS, "MAKE_NEXT_BLOCK_NO_ADD(" << #BLK_NAME << ")"); \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
generator.construct_block(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC); \
|
||||
VEC_EVENTS.push_back(event_special_block(BLK_NAME, event_special_block::flag_skip))
|
||||
|
|
@ -1051,7 +1069,7 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
VEC_EVENTS.push_back(BLK_NAME)
|
||||
|
||||
#define MAKE_NEXT_BLOCK_TX1(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TX1) \
|
||||
PRINT_EVENT_N_TEXT(VEC_EVENTS, "MAKE_NEXT_BLOCK_TX1(" << #BLK_NAME << ")"); \
|
||||
PRINT_EVENT_N_TEXT(VEC_EVENTS, "MAKE_NEXT_BLOCK_TX1(" << #BLK_NAME << ", " << #TX1 << ")"); \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
{ \
|
||||
std::list<currency::transaction> tx_list; \
|
||||
|
|
@ -1062,7 +1080,7 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
|
||||
|
||||
#define MAKE_NEXT_BLOCK_TX_LIST(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TXLIST) \
|
||||
PRINT_EVENT_N(VEC_EVENTS); \
|
||||
PRINT_EVENT_N_TEXT(VEC_EVENTS, "MAKE_NEXT_BLOCK_TX_LIST(" << #BLK_NAME << ", " << #TXLIST << ")"); \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
generator.construct_block(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TXLIST); \
|
||||
VEC_EVENTS.push_back(BLK_NAME)
|
||||
|
|
@ -1095,7 +1113,7 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
|
||||
|
||||
#define MAKE_TX_MIX_ATTR_EXTRA(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, NMIX, HEAD, MIX_ATTR, EXTRA, CHECK_SPENDS) \
|
||||
PRINT_EVENT_N(VEC_EVENTS); \
|
||||
PRINT_EVENT_N_TEXT(VEC_EVENTS, "transaction " << #TX_NAME); \
|
||||
currency::transaction TX_NAME; \
|
||||
{ \
|
||||
bool txr = construct_tx_to_key(generator.get_hardforks(), VEC_EVENTS, TX_NAME, HEAD, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, NMIX, generator.last_tx_generated_secret_key, MIX_ATTR, EXTRA, std::vector<currency::attachment_v>(), CHECK_SPENDS); \
|
||||
|
|
@ -1104,7 +1122,7 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
VEC_EVENTS.push_back(TX_NAME)
|
||||
|
||||
#define MAKE_TX_FEE_MIX_ATTR_EXTRA(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, FEE, NMIX, HEAD, MIX_ATTR, EXTRA, CHECK_SPENDS) \
|
||||
PRINT_EVENT_N(VEC_EVENTS); \
|
||||
PRINT_EVENT_N_TEXT(VEC_EVENTS, "transaction " << #TX_NAME); \
|
||||
currency::transaction TX_NAME; \
|
||||
{ \
|
||||
bool txr = construct_tx_to_key(generator.get_hardforks(), VEC_EVENTS, TX_NAME, HEAD, FROM, TO, AMOUNT, FEE, NMIX, generator.last_tx_generated_secret_key, MIX_ATTR, EXTRA, std::vector<currency::attachment_v>(), CHECK_SPENDS); \
|
||||
|
|
@ -1129,7 +1147,7 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
|
||||
#define MAKE_TX_MIX_LIST_EXTRA_MIX_ATTR(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD, MIX_ATTR, EXTRA, ATTACH) \
|
||||
{ \
|
||||
PRINT_EVENT_N(VEC_EVENTS); \
|
||||
PRINT_EVENT_N_TEXT(VEC_EVENTS, "transaction list " << #SET_NAME); \
|
||||
currency::transaction t; \
|
||||
bool r = construct_tx_to_key(generator.get_hardforks(), VEC_EVENTS, t, HEAD, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, NMIX, generator.last_tx_generated_secret_key, MIX_ATTR, EXTRA, ATTACH); \
|
||||
if (!r) { LOG_PRINT_YELLOW("ERROR in tx @ EVENT #" << VEC_EVENTS.size(), LOG_LEVEL_0); } \
|
||||
|
|
@ -1185,10 +1203,14 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
|
||||
// Adjust gentime and playtime "time" at once
|
||||
#define ADJUST_TEST_CORE_TIME(desired_time) \
|
||||
PRINT_EVENT_N(events); \
|
||||
PRINT_EVENT_N_TEXT(events, "ADJUST_TEST_CORE_TIME(" << desired_time << ")"); \
|
||||
test_core_time::adjust(desired_time); \
|
||||
events.push_back(event_core_time(desired_time))
|
||||
|
||||
#define ADD_CUSTOM_EVENT_CODE(VEC_EVENTS, CODE) PRINT_EVENT_N_TEXT(VEC_EVENTS, #CODE); CODE
|
||||
|
||||
#define ADD_CUSTOM_EVENT(VEC_EVENTS, EVENT_OBJ) PRINT_EVENT_N_TEXT(VEC_EVENTS, #EVENT_OBJ); VEC_EVENTS.push_back(EVENT_OBJ)
|
||||
|
||||
// --- gentime wallet helpers -----------------------------------------------------------------------
|
||||
|
||||
#define CREATE_TEST_WALLET(WLT_VAR, ACCOUNT, GENESIS_BLOCK) \
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ inline bool mine_next_pow_block_in_playtime_with_given_txs(const currency::accou
|
|||
{
|
||||
CRITICAL_REGION_LOCAL(s_locker);
|
||||
loc_helper::txs_accessor() = &txs;
|
||||
r = c.get_blockchain_storage().create_block_template(b, miner_addr, miner_addr, diff, height_from_template, extra, false, pe, loc_helper::fill_block_template_func);
|
||||
r = c.get_blockchain_storage().create_block_template(miner_addr, miner_addr, extra, false, pe, loc_helper::fill_block_template_func, b, diff, height_from_template);
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(r, false, "get_block_template failed");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 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
|
||||
|
|
@ -106,8 +106,9 @@ bool generate_and_play(const char* const genclass_name)
|
|||
{
|
||||
std::vector<test_event_entry> events;
|
||||
bool generated = false;
|
||||
bool result = true;
|
||||
std::cout << ENDL << concolor::bright_white << "#TEST# " << genclass_name << concolor::normal << ENDL << ENDL;
|
||||
bool result = false;
|
||||
std::cout << ENDL << concolor::bright_white << "#TEST# >>>> " << genclass_name << " <<<<" << ENDL << ENDL;
|
||||
|
||||
LOG_PRINT2("get_object_blobsize.log", "#TEST# " << genclass_name, LOG_LEVEL_3);
|
||||
|
||||
if (!clean_data_directory())
|
||||
|
|
@ -118,29 +119,36 @@ bool generate_and_play(const char* const genclass_name)
|
|||
genclass g;
|
||||
try
|
||||
{
|
||||
generated = g.generate(events);;
|
||||
generated = g.generate(events);
|
||||
if (generated)
|
||||
{
|
||||
std::cout << concolor::bright_white << std::string(100, '=') << std::endl <<
|
||||
"#TEST# >>>> " << genclass_name << " <<<< start replaying events" << std::endl <<
|
||||
std::string(100, '=') << concolor::normal << std::endl;
|
||||
|
||||
result = do_replay_events(events, g);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
LOG_ERROR(genclass_name << " generation failed: what=" << ex.what());
|
||||
LOG_ERROR("got an exception during " << genclass_name << (generated ? " replaying: " : " generation: ") << ex.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_ERROR(genclass_name << " generation failed: generic exception");
|
||||
LOG_ERROR("got an unknown exception during " << genclass_name << (generated ? " replaying" : " generation"));
|
||||
}
|
||||
|
||||
std::cout << concolor::bright_white << std::string(100, '=') << std::endl <<
|
||||
"#TEST# >>>> " << genclass_name << " <<<< start replaying events" << std::endl <<
|
||||
std::string(100, '=') << concolor::normal << std::endl;
|
||||
|
||||
if (generated && do_replay_events(events, g))
|
||||
if (result)
|
||||
{
|
||||
std::cout << concolor::green << "#TEST# Succeeded " << genclass_name << concolor::normal << std::endl;
|
||||
std::cout << concolor::green << std::string(100, '=') << std::endl <<
|
||||
"#TEST# >>>> " << genclass_name << " <<<< Succeeded" << std::endl <<
|
||||
std::string(100, '=') << concolor::normal << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << concolor::magenta << "#TEST# Failed " << genclass_name << concolor::normal << std::endl;
|
||||
LOG_PRINT_RED_L0("#TEST# Failed " << genclass_name);
|
||||
std::cout << concolor::red << std::string(100, '=') << std::endl <<
|
||||
"#TEST# >>>> " << genclass_name << " <<<< FAILED" << std::endl <<
|
||||
std::string(100, '=') << concolor::normal << std::endl;
|
||||
result = false;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
|
@ -667,6 +675,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
po::options_description desc_options("Allowed options");
|
||||
command_line::add_arg(desc_options, command_line::arg_help);
|
||||
command_line::add_arg(desc_options, command_line::arg_log_level);
|
||||
command_line::add_arg(desc_options, arg_test_data_path);
|
||||
command_line::add_arg(desc_options, arg_generate_test_data);
|
||||
command_line::add_arg(desc_options, arg_play_test_data);
|
||||
|
|
@ -697,6 +706,16 @@ int main(int argc, char* argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (command_line::has_arg(g_vm, command_line::arg_log_level))
|
||||
{
|
||||
int new_log_level = command_line::get_arg(g_vm, command_line::arg_log_level);
|
||||
if (new_log_level >= LOG_LEVEL_MIN && new_log_level <= LOG_LEVEL_MAX && log_space::get_set_log_detalisation_level(false) != new_log_level)
|
||||
{
|
||||
log_space::get_set_log_detalisation_level(true, new_log_level);
|
||||
LOG_PRINT_L0("LOG_LEVEL set to " << new_log_level);
|
||||
}
|
||||
}
|
||||
|
||||
if (command_line::has_arg(g_vm, arg_stop_on_fail))
|
||||
{
|
||||
stop_on_first_fail = command_line::get_arg(g_vm, arg_stop_on_fail);
|
||||
|
|
@ -761,8 +780,6 @@ int main(int argc, char* argv[])
|
|||
MARK_TEST_AS_POSTPONED(before_hard_fork_1_cumulative_difficulty);
|
||||
MARK_TEST_AS_POSTPONED(inthe_middle_hard_fork_1_cumulative_difficulty);
|
||||
|
||||
MARK_TEST_AS_POSTPONED(zarcanum_basic_test);
|
||||
|
||||
#undef MARK_TEST_AS_POSTPONED
|
||||
|
||||
|
||||
|
|
@ -1063,6 +1080,8 @@ int main(int argc, char* argv[])
|
|||
|
||||
GENERATE_AND_PLAY(multiassets_basic_test);
|
||||
GENERATE_AND_PLAY(zarcanum_test_n_inputs_validation);
|
||||
GENERATE_AND_PLAY(zarcanum_gen_time_balance);
|
||||
GENERATE_AND_PLAY(zarcanum_txs_with_big_shuffled_decoy_set_shuffled);
|
||||
|
||||
// GENERATE_AND_PLAY(gen_block_reward);
|
||||
// END OF TESTS */
|
||||
|
|
|
|||
|
|
@ -559,7 +559,7 @@ bool gen_checkpoints_pos_validation_on_altchain::generate(std::vector<test_event
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, blk_0r.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(blk_0r), miner_acc.get_public_address());
|
||||
|
|
@ -588,7 +588,7 @@ bool gen_checkpoints_pos_validation_on_altchain::generate(std::vector<test_event
|
|||
//crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, blk_0r.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(blk_0r), miner_acc.get_public_address());
|
||||
|
|
@ -654,7 +654,7 @@ bool gen_no_attchments_in_coinbase::init_config_set_cp(currency::core& c, size_t
|
|||
crc.pos_minimum_heigh = 1;
|
||||
c.get_blockchain_storage().set_core_runtime_config(crc);
|
||||
|
||||
m_checkpoints.add_checkpoint(12, "8cce274f3ade893fa407a5215b90c595d2ecb036e76ad934b3410da4e8bc7c2c");
|
||||
m_checkpoints.add_checkpoint(12, "ac57db2582acdd076f92aa8dfcb88d216f60e35b805c16b6256ca26e023bfc3c");
|
||||
c.set_checkpoints(currency::checkpoints(m_checkpoints));
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ bool emission_test::c1(currency::core& c, size_t ev_index, const std::vector<tes
|
|||
crypto::hash prev_id = get_block_hash(b);
|
||||
crypto::hash stake_tx_hash = stake_tx_outs.front().first;
|
||||
size_t stake_output_idx = stake_tx_outs.front().second;
|
||||
auto tce_ptr = c.get_blockchain_storage().get_tx_chain_entry(stake_tx_hash);
|
||||
auto tce_ptr = bcs.get_tx_chain_entry(stake_tx_hash);
|
||||
CHECK_AND_ASSERT_MES(tce_ptr, false, "");
|
||||
CHECK_AND_ASSERT_MES(stake_output_idx < tce_ptr->m_global_output_indexes.size(), false, "");
|
||||
|
||||
|
|
@ -105,11 +105,11 @@ bool emission_test::c1(currency::core& c, size_t ev_index, const std::vector<tes
|
|||
generate_key_image_helper(m_miner_acc.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
|
||||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
difficulty = c.get_blockchain_storage().get_next_diff_conditional(true);
|
||||
difficulty = bcs.get_next_diff_conditional(true);
|
||||
//size_t median_size = 0; // little hack: we're using small blocks (only coinbase tx), so we're in CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE - don't need to calc median size
|
||||
|
||||
pb.clear();
|
||||
pb.step1_init_header(get_block_height(b) + 1, prev_id);
|
||||
pb.step1_init_header(bcs.get_core_runtime_config().hard_forks, get_block_height(b) + 1, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, difficulty, prev_id, null_hash, timestamp);
|
||||
pb.step4_generate_coinbase_tx(0, already_generated_coins, m_miner_acc.get_public_address());
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ bool hard_fork_1_checkpoint_basic_test::generate(std::vector<test_event_entry>&
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.m_block.major_version = HF1_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
|
|
@ -573,7 +573,7 @@ bool hard_fork_1_pos_and_locked_coins::generate(std::vector<test_event_entry>& e
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address());
|
||||
|
|
@ -612,7 +612,7 @@ bool hard_fork_1_pos_and_locked_coins::generate(std::vector<test_event_entry>& e
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.m_block.major_version = HF1_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
|
|
@ -660,7 +660,7 @@ bool hard_fork_1_pos_and_locked_coins::generate(std::vector<test_event_entry>& e
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.m_block.major_version = HF1_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
|
|
@ -757,7 +757,7 @@ bool hard_fork_1_pos_locked_height_vs_time::generate(std::vector<test_event_entr
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.m_block.major_version = HF1_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
|
|
@ -802,7 +802,7 @@ bool hard_fork_1_pos_locked_height_vs_time::generate(std::vector<test_event_entr
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.m_block.major_version = HF1_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
|
|
@ -846,7 +846,7 @@ bool hard_fork_1_pos_locked_height_vs_time::generate(std::vector<test_event_entr
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.m_block.major_version = HF1_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ bool hard_fork_2_tx_payer_in_wallet::generate(std::vector<test_event_entry>& eve
|
|||
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(true); // Bob has auditable address
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
set_hard_fork_heights_to_generator(generator);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
|
|
@ -307,7 +306,6 @@ bool hard_fork_2_tx_receiver_in_wallet::generate(std::vector<test_event_entry>&
|
|||
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(true); // Bob has auditable address
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
set_hard_fork_heights_to_generator(generator);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
|
||||
|
||||
|
|
@ -448,7 +446,6 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::generate(std::vector<test_event
|
|||
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(true); // auditable address
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
set_hard_fork_heights_to_generator(generator);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
|
|
@ -640,7 +637,6 @@ bool hard_fork_2_auditable_addresses_basics::generate(std::vector<test_event_ent
|
|||
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(true); // Bob has auditable address
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
set_hard_fork_heights_to_generator(generator);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
|
|
@ -740,13 +736,16 @@ hard_fork_2_no_new_structures_before_hf::hard_fork_2_no_new_structures_before_hf
|
|||
|
||||
bool hard_fork_2_no_new_structures_before_hf::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
test_gentime_settings tgs = test_generator::get_test_gentime_settings();
|
||||
tgs.ignore_invalid_txs = false; // this test pushes originally invalid tx_0, tx_1 and tx_2 which are good after HF2, so we'd like to avoid mess with the sources among txs
|
||||
test_generator::set_test_gentime_settings(tgs);
|
||||
|
||||
bool r = false;
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
|
||||
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate();
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
set_hard_fork_heights_to_generator(generator);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
|
|
@ -830,9 +829,9 @@ bool hard_fork_2_no_new_structures_before_hf::generate(std::vector<test_event_en
|
|||
MAKE_NEXT_BLOCK(events, blk_6, blk_5, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_7, blk_6, miner_acc);
|
||||
|
||||
events.push_back(tx_0);
|
||||
events.push_back(tx_1);
|
||||
events.push_back(tx_2);
|
||||
ADD_CUSTOM_EVENT(events, tx_0);
|
||||
ADD_CUSTOM_EVENT(events, tx_1);
|
||||
ADD_CUSTOM_EVENT(events, tx_2);
|
||||
|
||||
|
||||
// tx_0 with tx_payer should be accepted after HF2
|
||||
|
|
@ -884,7 +883,6 @@ bool hard_fork_2_awo_wallets_basic_test<before_hf_2>::generate(std::vector<test_
|
|||
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(true); // Bob has auditable address
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
set_hard_fork_heights_to_generator(generator);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
|
|
@ -1158,7 +1156,6 @@ bool hard_fork_2_alias_update_using_old_tx<before_hf_2>::generate(std::vector<te
|
|||
alice_acc.set_createtime(ts);
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
|
||||
set_hard_fork_heights_to_generator(generator);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
events.push_back(event_core_time(ts));
|
||||
|
||||
|
|
@ -1276,7 +1273,6 @@ bool hard_fork_2_incorrect_alias_update<before_hf_2>::generate(std::vector<test_
|
|||
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(true); // Bob has auditable address
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
set_hard_fork_heights_to_generator(generator);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
|
|
|
|||
|
|
@ -1194,7 +1194,7 @@ bool multisig_and_unlock_time::generate(std::vector<test_event_entry>& events) c
|
|||
// noramal input -> multisig output with unlock time
|
||||
std::vector<tx_source_entry> sources;
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
r = fill_tx_sources_and_destinations(events, blk_0r, miner_acc.get_keys(), ms_addr_list, amount, TESTS_DEFAULT_FEE, 1, sources, destinations, true, true, 1);
|
||||
r = fill_tx_sources_and_destinations(events, blk_0r, miner_acc.get_keys(), ms_addr_list, amount, TESTS_DEFAULT_FEE, 1 /*nmix*/, sources, destinations, true, true, 1 /* minimum sigs */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed");
|
||||
|
||||
uint64_t unlock_time = blk_0r.timestamp + DIFFICULTY_TOTAL_TARGET * 3 + CURRENCY_LOCKED_TX_ALLOWED_DELTA_SECONDS;
|
||||
|
|
@ -1251,10 +1251,17 @@ bool multisig_and_unlock_time::generate(std::vector<test_event_entry>& events) c
|
|||
ADJUST_TEST_CORE_TIME(unlock_time_2 - CURRENCY_LOCKED_TX_ALLOWED_DELTA_SECONDS - 1);
|
||||
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
MAKE_TX(events, tx_3, alice_acc, bob_acc, amount - TESTS_DEFAULT_FEE * 2, blk_2);
|
||||
// instead of MAKE_TX use manual construction to set check_for_unlocktime = false, old: MAKE_TX(events, tx_3, alice_acc, bob_acc, amount - TESTS_DEFAULT_FEE * 2, blk_2);
|
||||
r = fill_tx_sources_and_destinations(events, blk_2, alice_acc, bob_acc, amount - TESTS_DEFAULT_FEE * 2, TESTS_DEFAULT_FEE, 0 /*nmix*/, sources, destinations, true, false /* check_for_unlocktime */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed");
|
||||
transaction tx_3{};
|
||||
r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_3, get_tx_version_from_events(events), 0);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
ADD_CUSTOM_EVENT(events, tx_3);
|
||||
|
||||
|
||||
ADJUST_TEST_CORE_TIME(unlock_time_2 - CURRENCY_LOCKED_TX_ALLOWED_DELTA_SECONDS + 1);
|
||||
events.push_back(tx_3);
|
||||
ADD_CUSTOM_EVENT(events, tx_3);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_acc, tx_3);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(BOB_ACC_IDX, amount - TESTS_DEFAULT_FEE * 2));
|
||||
|
|
@ -1362,11 +1369,11 @@ bool multisig_and_coinbase::generate(std::vector<test_event_entry>& events) cons
|
|||
keypair tx_key = keypair::generate();
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address(),
|
||||
blobdata(), CURRENCY_MINER_TX_MAX_OUTS, extra_alias_entry(), tx_key);
|
||||
blobdata(), CURRENCY_MINER_TX_MAX_OUTS, &tx_key);
|
||||
|
||||
// The builder creates PoS miner tx with normal outputs.
|
||||
// Replace all miner_tx outputs with one multisig output and re-sign it.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2022 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
|
@ -9,23 +9,17 @@
|
|||
using namespace epee;
|
||||
using namespace currency;
|
||||
|
||||
pos_block_builder::pos_block_builder()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void pos_block_builder::clear()
|
||||
{
|
||||
m_block = AUTO_VAL_INIT(m_block);
|
||||
m_stake_kernel = AUTO_VAL_INIT(m_stake_kernel);
|
||||
m_step = 0;
|
||||
*this = pos_block_builder{};
|
||||
}
|
||||
|
||||
void pos_block_builder::step1_init_header(size_t block_height, crypto::hash& prev_block_hash)
|
||||
|
||||
void pos_block_builder::step1_init_header(const hard_forks_descriptor& hardforks, size_t block_height, crypto::hash& prev_block_hash)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(m_step == 0, "pos_block_builder: incorrect step sequence");
|
||||
m_block.minor_version = CURRENT_BLOCK_MINOR_VERSION;
|
||||
m_block.major_version = BLOCK_MAJOR_VERSION_INITIAL;
|
||||
m_block.major_version = hardforks.get_block_major_version_by_height(block_height);
|
||||
m_block.timestamp = 0; // to be set at step 3
|
||||
m_block.prev_id = prev_block_hash;
|
||||
m_block.flags = CURRENCY_BLOCK_FLAG_POS_BLOCK;
|
||||
|
|
@ -33,9 +27,12 @@ void pos_block_builder::step1_init_header(size_t block_height, crypto::hash& pre
|
|||
|
||||
m_height = block_height;
|
||||
|
||||
m_context.zarcanum = hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, m_height);
|
||||
|
||||
m_step = 1;
|
||||
}
|
||||
|
||||
|
||||
void pos_block_builder::step2_set_txs(const std::vector<currency::transaction>& txs)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(m_step == 1, "pos_block_builder: incorrect step sequence");
|
||||
|
|
@ -57,6 +54,7 @@ void pos_block_builder::step2_set_txs(const std::vector<currency::transaction>&
|
|||
m_step = 2;
|
||||
}
|
||||
|
||||
|
||||
void pos_block_builder::step3_build_stake_kernel(
|
||||
uint64_t stake_output_amount,
|
||||
size_t stake_output_gindex,
|
||||
|
|
@ -68,78 +66,119 @@ void pos_block_builder::step3_build_stake_kernel(
|
|||
uint64_t timestamp_window,
|
||||
uint64_t timestamp_step)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(m_step == 2, "pos_block_builder: incorrect step sequence");
|
||||
m_pos_stake_amount = stake_output_amount;
|
||||
m_pos_stake_output_gindex = stake_output_gindex;
|
||||
step3a(difficulty, last_pow_block_hash, last_pos_block_kernel_hash);
|
||||
|
||||
m_stake_kernel.kimage = stake_output_key_image;
|
||||
m_stake_kernel.block_timestamp = m_block.timestamp;
|
||||
m_stake_kernel.stake_modifier.last_pow_id = last_pow_block_hash;
|
||||
m_stake_kernel.stake_modifier.last_pos_kernel_id = last_pos_block_kernel_hash;
|
||||
crypto::public_key stake_source_tx_pub_key {};
|
||||
uint64_t stake_out_in_tx_index = UINT64_MAX;
|
||||
crypto::scalar_t stake_out_blinding_mask {};
|
||||
crypto::secret_key view_secret {};
|
||||
|
||||
step3b(stake_output_amount, stake_output_key_image, stake_source_tx_pub_key, stake_out_in_tx_index, stake_out_blinding_mask, view_secret, stake_output_gindex,
|
||||
timestamp_lower_bound, timestamp_window, timestamp_step);
|
||||
}
|
||||
|
||||
|
||||
void pos_block_builder::step3a(
|
||||
currency::wide_difficulty_type difficulty,
|
||||
const crypto::hash& last_pow_block_hash,
|
||||
const crypto::hash& last_pos_block_kernel_hash
|
||||
)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(m_step == 2, "pos_block_builder: incorrect step sequence");
|
||||
|
||||
stake_modifier_type sm{};
|
||||
sm.last_pow_id = last_pow_block_hash;
|
||||
sm.last_pos_kernel_id = last_pos_block_kernel_hash;
|
||||
if (last_pos_block_kernel_hash == null_hash)
|
||||
{
|
||||
bool r = string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, m_stake_kernel.stake_modifier.last_pos_kernel_id);
|
||||
bool r = string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, sm.last_pos_kernel_id);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to parse POS_STARTER_KERNEL_HASH");
|
||||
}
|
||||
|
||||
wide_difficulty_type stake_difficulty = difficulty / stake_output_amount;
|
||||
m_context.init(difficulty, sm, m_context.zarcanum);
|
||||
m_step = 31;
|
||||
}
|
||||
|
||||
|
||||
void pos_block_builder::step3b(
|
||||
uint64_t stake_output_amount,
|
||||
const crypto::key_image& stake_output_key_image,
|
||||
const crypto::public_key& stake_source_tx_pub_key, // zarcanum only
|
||||
uint64_t stake_out_in_tx_index, // zarcanum only
|
||||
const crypto::scalar_t& stake_out_blinding_mask, // zarcanum only
|
||||
const crypto::secret_key& view_secret, // zarcanum only
|
||||
size_t stake_output_gindex,
|
||||
uint64_t timestamp_lower_bound,
|
||||
uint64_t timestamp_window,
|
||||
uint64_t timestamp_step)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(m_step == 31, "pos_block_builder: incorrect step sequence");
|
||||
|
||||
m_pos_stake_output_gindex = stake_output_gindex;
|
||||
|
||||
m_context.prepare_entry(stake_output_amount, stake_output_key_image, stake_source_tx_pub_key, stake_out_in_tx_index, stake_out_blinding_mask, view_secret);
|
||||
|
||||
// align timestamp_lower_bound up to timestamp_step boundary if needed
|
||||
if (timestamp_lower_bound % timestamp_step != 0)
|
||||
timestamp_lower_bound = timestamp_lower_bound - (timestamp_lower_bound % timestamp_step) + timestamp_step;
|
||||
bool sk_found = false;
|
||||
for (uint64_t ts = timestamp_lower_bound; !sk_found && ts < timestamp_lower_bound + timestamp_window; ts += timestamp_step)
|
||||
{
|
||||
m_stake_kernel.block_timestamp = ts;
|
||||
crypto::hash sk_hash = crypto::cn_fast_hash(&m_stake_kernel, sizeof(m_stake_kernel));
|
||||
if (check_hash(sk_hash, stake_difficulty))
|
||||
{
|
||||
if (m_context.do_iteration(ts))
|
||||
sk_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sk_found)
|
||||
ASSERT_MES_AND_THROW("Could't build stake kernel");
|
||||
|
||||
// update block header with found timestamp
|
||||
m_block.timestamp = m_stake_kernel.block_timestamp;
|
||||
m_block.timestamp = m_context.sk.block_timestamp;
|
||||
|
||||
m_step = 3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
|
||||
const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
const account_public_address &reward_and_stake_receiver_address,
|
||||
const blobdata& extra_nonce,
|
||||
size_t max_outs,
|
||||
const extra_alias_entry& alias,
|
||||
keypair tx_one_time_key)
|
||||
const keypair* tx_one_time_key_to_use)
|
||||
{
|
||||
step4_generate_coinbase_tx(median_size, already_generated_coins, reward_and_stake_receiver_address, reward_and_stake_receiver_address, extra_nonce, max_outs, alias, tx_one_time_key);
|
||||
step4_generate_coinbase_tx(median_size, already_generated_coins, reward_and_stake_receiver_address, reward_and_stake_receiver_address, extra_nonce, max_outs, tx_one_time_key_to_use);
|
||||
}
|
||||
|
||||
|
||||
void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
|
||||
const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
const account_public_address &reward_receiver_address,
|
||||
const account_public_address &stakeholder_address,
|
||||
const blobdata& extra_nonce,
|
||||
size_t max_outs,
|
||||
const extra_alias_entry& alias,
|
||||
keypair tx_one_time_key)
|
||||
const keypair* tx_one_time_key_to_use)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(m_step == 3, "pos_block_builder: incorrect step sequence");
|
||||
|
||||
uint64_t tx_version = m_context.zarcanum ? TRANSACTION_VERSION_POST_HF4 : TRANSACTION_VERSION_PRE_HF4;
|
||||
pos_entry pe{};
|
||||
pe.stake_unlock_time = 0; // TODO
|
||||
pe.amount = m_context.stake_amount;
|
||||
|
||||
// generate miner tx using incorrect current_block_size only for size estimation
|
||||
size_t estimated_block_size = m_txs_total_size;
|
||||
bool r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_pos_stake_amount, m_stake_kernel.kimage,
|
||||
m_pos_stake_output_gindex, reward_receiver_address, stakeholder_address, m_block.miner_tx, extra_nonce, max_outs, tx_one_time_key);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed");
|
||||
bool r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee,
|
||||
reward_receiver_address, stakeholder_address, m_block.miner_tx, tx_version, extra_nonce, max_outs, true, pe, &m_blinding_masks_sum, tx_one_time_key_to_use);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "construct_miner_tx failed");
|
||||
|
||||
estimated_block_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx);
|
||||
size_t cumulative_size = 0;
|
||||
for (size_t try_count = 0; try_count != 10; ++try_count)
|
||||
{
|
||||
r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_pos_stake_amount, m_stake_kernel.kimage,
|
||||
m_pos_stake_output_gindex, reward_receiver_address, stakeholder_address, m_block.miner_tx, extra_nonce, max_outs, tx_one_time_key);
|
||||
r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee,
|
||||
reward_receiver_address, stakeholder_address, m_block.miner_tx, tx_version, extra_nonce, max_outs, true, pe, &m_blinding_masks_sum, tx_one_time_key_to_use);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed");
|
||||
|
||||
cumulative_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx);
|
||||
|
|
@ -159,138 +198,94 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
|
|||
m_step = 4;
|
||||
}
|
||||
|
||||
void pos_block_builder::step5_sign(const crypto::public_key& stake_tx_pub_key, size_t stake_tx_out_index, const crypto::public_key& stake_tx_out_pub_key, const currency::account_base& stakeholder_account)
|
||||
// supports Zarcanum and mixins
|
||||
void pos_block_builder::step5_sign(const currency::tx_source_entry& se, const currency::account_keys& stakeholder_keys)
|
||||
{
|
||||
bool r = false;
|
||||
CHECK_AND_ASSERT_THROW_MES(m_step == 4, "pos_block_builder: incorrect step sequence");
|
||||
|
||||
crypto::key_derivation pos_coin_derivation = AUTO_VAL_INIT(pos_coin_derivation);
|
||||
bool r = crypto::generate_key_derivation(stake_tx_pub_key, stakeholder_account.get_keys().view_secret_key, pos_coin_derivation); // derivation(tx_pub; view_sec)
|
||||
// calculate stake_out_derivation and secret_x (derived ephemeral secret key)
|
||||
crypto::key_derivation stake_out_derivation = AUTO_VAL_INIT(stake_out_derivation);
|
||||
r = crypto::generate_key_derivation(se.real_out_tx_key, stakeholder_keys.view_secret_key, stake_out_derivation); // d = 8 * v * R
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "generate_key_derivation failed");
|
||||
crypto::secret_key secret_x = AUTO_VAL_INIT(secret_x);
|
||||
crypto::derive_secret_key(stake_out_derivation, se.real_output_in_tx_index, stakeholder_keys.spend_secret_key, secret_x); // x = Hs(8 * v * R, i) + s
|
||||
|
||||
crypto::secret_key derived_secret_ephemeral_key = AUTO_VAL_INIT(derived_secret_ephemeral_key);
|
||||
crypto::derive_secret_key(pos_coin_derivation, stake_tx_out_index, stakeholder_account.get_keys().spend_secret_key, derived_secret_ephemeral_key); // derivation.derive(spend_sec, out_idx) => input ephemeral secret key
|
||||
if (m_context.zarcanum)
|
||||
{
|
||||
// Zarcanum
|
||||
zarcanum_sig& sig = boost::get<zarcanum_sig>(m_block.miner_tx.signatures[0]);
|
||||
txin_zc_input& stake_input = boost::get<txin_zc_input>(m_block.miner_tx.vin[1]);
|
||||
|
||||
// sign block actually in coinbase transaction
|
||||
crypto::hash block_hash = currency::get_block_hash(m_block);
|
||||
std::vector<const crypto::public_key*> keys_ptrs(1, &stake_tx_out_pub_key);
|
||||
crypto::generate_ring_signature(block_hash, m_stake_kernel.kimage, keys_ptrs, derived_secret_ephemeral_key, 0, &boost::get<currency::NLSAG_sig>(m_block.miner_tx.signatures[0]).s[0]);
|
||||
stake_input.k_image = m_context.sk.kimage;
|
||||
|
||||
std::vector<crypto::CLSAG_GGXG_input_ref_t> ring;
|
||||
for(const auto& el : se.outputs)
|
||||
{
|
||||
stake_input.key_offsets.push_back(el.out_reference);
|
||||
ring.emplace_back(el.stealth_address, el.amount_commitment, el.concealing_point);
|
||||
}
|
||||
r = absolute_sorted_output_offsets_to_relative_in_place(stake_input.key_offsets);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "absolute_sorted_output_offsets_to_relative_in_place failed");
|
||||
|
||||
crypto::hash tx_hash_for_sig = get_transaction_hash(m_block.miner_tx); // TODO @#@# change to block hash after the corresponding test is made
|
||||
|
||||
uint8_t err = 0;
|
||||
r = crypto::zarcanum_generate_proof(tx_hash_for_sig, m_context.kernel_hash, ring, m_context.last_pow_block_id_hashed, m_context.sk.kimage,
|
||||
secret_x, m_context.secret_q, se.real_output, m_blinding_masks_sum, m_context.stake_amount, m_context.stake_out_blinding_mask,
|
||||
static_cast<crypto::zarcanum_proof&>(sig), &err);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "zarcanum_generate_proof failed, err: " << (int)err);
|
||||
}
|
||||
else
|
||||
{
|
||||
// old PoS with non-hidden amounts
|
||||
NLSAG_sig& sig = boost::get<NLSAG_sig>(m_block.miner_tx.signatures[0]);
|
||||
txin_to_key& stake_input = boost::get<txin_to_key>(m_block.miner_tx.vin[1]);
|
||||
|
||||
stake_input.k_image = m_context.sk.kimage;
|
||||
stake_input.amount = m_context.stake_amount;
|
||||
stake_input.key_offsets.push_back(m_pos_stake_output_gindex);
|
||||
|
||||
crypto::hash block_hash = currency::get_block_hash(m_block);
|
||||
std::vector<const crypto::public_key*> keys_ptrs(1, &se.outputs.front().stealth_address);
|
||||
sig.s.resize(1);
|
||||
crypto::generate_ring_signature(block_hash, m_context.sk.kimage, keys_ptrs, secret_x, 0, sig.s.data());
|
||||
}
|
||||
|
||||
m_step = 5;
|
||||
}
|
||||
|
||||
bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
size_t current_block_size,
|
||||
uint64_t fee,
|
||||
uint64_t pos_stake_amount,
|
||||
crypto::key_image pos_stake_keyimage,
|
||||
size_t pos_stake_gindex,
|
||||
const account_public_address &reward_receiving_address,
|
||||
const account_public_address &stakeholder_address,
|
||||
transaction& tx,
|
||||
const blobdata& extra_nonce /*= blobdata()*/,
|
||||
size_t max_outs /*= CURRENCY_MINER_TX_MAX_OUTS*/,
|
||||
keypair tx_one_time_key /*= keypair::generate()*/)
|
||||
|
||||
void pos_block_builder::step5_sign(const crypto::public_key& stake_tx_pub_key, size_t stake_tx_out_index, const crypto::public_key& stake_tx_out_pub_key,
|
||||
const currency::account_base& stakeholder_account)
|
||||
{
|
||||
boost::value_initialized<transaction> new_tx;
|
||||
tx = new_tx;
|
||||
CHECK_AND_ASSERT_THROW_MES(!m_context.zarcanum, "for zarcanum use another overloading");
|
||||
|
||||
tx.version = TRANSACTION_VERSION_PRE_HF4;
|
||||
set_tx_unlock_time(tx, height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
tx_source_entry se{};
|
||||
|
||||
// calculate block reward
|
||||
uint64_t block_reward;
|
||||
bool r = get_block_reward(true, median_size, current_block_size, already_generated_coins, block_reward, height);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Block is too big");
|
||||
block_reward += fee;
|
||||
se.real_out_tx_key = stake_tx_pub_key;
|
||||
se.real_output_in_tx_index = stake_tx_out_index;
|
||||
se.outputs.emplace_back(m_pos_stake_output_gindex, stake_tx_out_pub_key);
|
||||
|
||||
// decompose reward into outputs and populate tx.vout
|
||||
std::vector<size_t> out_amounts;
|
||||
decompose_amount_into_digits(block_reward, DEFAULT_DUST_THRESHOLD,
|
||||
[&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); },
|
||||
[&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); });
|
||||
|
||||
CHECK_AND_ASSERT_MES(2 <= max_outs, false, "max_out must be greather than 1");
|
||||
while (out_amounts.size() + 1 > max_outs)
|
||||
{
|
||||
out_amounts[out_amounts.size() - 2] += out_amounts.back();
|
||||
out_amounts.resize(out_amounts.size() - 1);
|
||||
}
|
||||
|
||||
// reward
|
||||
bool burn_money = reward_receiving_address.spend_public_key == null_pkey && reward_receiving_address.view_public_key == null_pkey; // if true, burn reward, so no one on Earth can spend them
|
||||
for (size_t output_index = 0; output_index < out_amounts.size(); ++output_index)
|
||||
{
|
||||
txout_to_key tk;
|
||||
tk.key = null_pkey; // null means burn money
|
||||
tk.mix_attr = 0;
|
||||
|
||||
if (!burn_money)
|
||||
{
|
||||
r = currency::derive_public_key_from_target_address(reward_receiving_address, tx_one_time_key.sec, output_index, tk.key); // derivation(view_pub; tx_sec).derive(output_index, spend_pub) => output pub key
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address");
|
||||
}
|
||||
|
||||
tx_out_bare out;
|
||||
out.amount = out_amounts[output_index];
|
||||
out.target = tk;
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
|
||||
// stake
|
||||
burn_money = stakeholder_address.spend_public_key == null_pkey && stakeholder_address.view_public_key == null_pkey; // if true, burn stake
|
||||
{
|
||||
txout_to_key tk;
|
||||
tk.key = null_pkey; // null means burn money
|
||||
tk.mix_attr = 0;
|
||||
|
||||
if (!burn_money)
|
||||
{
|
||||
r = currency::derive_public_key_from_target_address(stakeholder_address, tx_one_time_key.sec, tx.vout.size(), tk.key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address");
|
||||
}
|
||||
|
||||
tx_out_bare out;
|
||||
out.amount = pos_stake_amount;
|
||||
out.target = tk;
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
|
||||
// take care about extra
|
||||
add_tx_pub_key_to_extra(tx, tx_one_time_key.pub);
|
||||
if (extra_nonce.size())
|
||||
if (!add_tx_extra_userdata(tx, extra_nonce))
|
||||
return false;
|
||||
|
||||
// populate ins with 1) money-generating and 2) PoS
|
||||
txin_gen in;
|
||||
in.height = height;
|
||||
tx.vin.push_back(in);
|
||||
|
||||
txin_to_key posin;
|
||||
posin.amount = pos_stake_amount;
|
||||
posin.key_offsets.push_back(pos_stake_gindex);
|
||||
posin.k_image = pos_stake_keyimage;
|
||||
tx.vin.push_back(posin);
|
||||
//reserve place for ring signature
|
||||
tx.signatures.resize(1);
|
||||
boost::get<currency::NLSAG_sig>(tx.signatures[0]).s.resize(posin.key_offsets.size());
|
||||
|
||||
return true;
|
||||
step5_sign(se, stakeholder_account.get_keys());
|
||||
}
|
||||
|
||||
|
||||
bool mine_next_pos_block_in_playtime_sign_cb(currency::core& c, const currency::block& prev_block, const currency::block& coinstake_scr_block, const currency::account_base& acc,
|
||||
std::function<bool(currency::block&)> before_sign_cb, currency::block& output)
|
||||
{
|
||||
blockchain_storage& bcs = c.get_blockchain_storage();
|
||||
|
||||
// these values (median and diff) are correct only for the next main chain block, it's incorrect for altblocks, especially for old altblocks
|
||||
// but for now we assume they will work fine
|
||||
uint64_t block_size_median = c.get_blockchain_storage().get_current_comulative_blocksize_limit() / 2;
|
||||
currency::wide_difficulty_type difficulty = c.get_blockchain_storage().get_next_diff_conditional(true);
|
||||
uint64_t block_size_median = bcs.get_current_comulative_blocksize_limit() / 2;
|
||||
currency::wide_difficulty_type difficulty = bcs.get_next_diff_conditional(true);
|
||||
|
||||
crypto::hash prev_id = get_block_hash(prev_block);
|
||||
size_t height = get_block_height(prev_block) + 1;
|
||||
|
||||
block_extended_info bei = AUTO_VAL_INIT(bei);
|
||||
bool r = c.get_blockchain_storage().get_block_extended_info_by_hash(prev_id, bei);
|
||||
bool r = bcs.get_block_extended_info_by_hash(prev_id, bei);
|
||||
CHECK_AND_ASSERT_MES(r, false, "get_block_extended_info_by_hash failed for hash = " << prev_id);
|
||||
|
||||
|
||||
|
|
@ -305,7 +300,7 @@ bool mine_next_pos_block_in_playtime_sign_cb(currency::core& c, const currency::
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(bcs.get_core_runtime_config().hard_forks, height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, difficulty, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(block_size_median, bei.already_generated_coins, acc.get_public_address());
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2022 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#pragma once
|
||||
|
||||
#pragma once
|
||||
namespace currency
|
||||
{
|
||||
struct hard_forks_descriptor;
|
||||
}
|
||||
|
||||
struct pos_block_builder
|
||||
{
|
||||
pos_block_builder();
|
||||
pos_block_builder() = default;
|
||||
void clear();
|
||||
|
||||
void step1_init_header(size_t block_height, crypto::hash& prev_block_hash);
|
||||
void step1_init_header(const currency::hard_forks_descriptor& hardforks, size_t block_height, crypto::hash& prev_block_hash);
|
||||
|
||||
void step2_set_txs(const std::vector<currency::transaction>& txs);
|
||||
|
||||
|
|
@ -23,6 +27,26 @@ struct pos_block_builder
|
|||
uint64_t timestamp_lower_bound,
|
||||
uint64_t timestamp_window = POS_SCAN_WINDOW,
|
||||
uint64_t timestamp_step = POS_SCAN_STEP);
|
||||
|
||||
|
||||
void step3a(
|
||||
currency::wide_difficulty_type difficulty,
|
||||
const crypto::hash& last_pow_block_hash,
|
||||
const crypto::hash& last_pos_block_kernel_hash
|
||||
);
|
||||
|
||||
void step3b(
|
||||
uint64_t stake_output_amount,
|
||||
const crypto::key_image& stake_output_key_image,
|
||||
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,
|
||||
size_t stake_output_gindex,
|
||||
uint64_t timestamp_lower_bound,
|
||||
uint64_t timestamp_window,
|
||||
uint64_t timestamp_step);
|
||||
|
||||
|
||||
void step4_generate_coinbase_tx(size_t median_size,
|
||||
const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
|
|
@ -30,30 +54,38 @@ struct pos_block_builder
|
|||
const currency::account_public_address &stakeholder_address,
|
||||
const currency::blobdata& extra_nonce = currency::blobdata(),
|
||||
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,
|
||||
const currency::extra_alias_entry& alias = currency::extra_alias_entry(),
|
||||
currency::keypair tx_one_time_key = currency::keypair::generate());
|
||||
const currency::keypair* tx_one_time_key_to_use = nullptr
|
||||
);
|
||||
|
||||
void step4_generate_coinbase_tx(size_t median_size,
|
||||
const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
const currency::account_public_address &reward_and_stake_receiver_address,
|
||||
const currency::blobdata& extra_nonce = currency::blobdata(),
|
||||
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,
|
||||
const currency::extra_alias_entry& alias = currency::extra_alias_entry(),
|
||||
currency::keypair tx_one_time_key = currency::keypair::generate());
|
||||
const currency::keypair* tx_one_time_key_to_use = nullptr
|
||||
);
|
||||
|
||||
void step5_sign(const currency::tx_source_entry& se, const currency::account_keys& stakeholder_keys);
|
||||
|
||||
void step5_sign(const crypto::public_key& stake_tx_pub_key, size_t stake_tx_out_index, const crypto::public_key& stake_tx_out_pub_key, const currency::account_base& stakeholder_account);
|
||||
|
||||
currency::block m_block;
|
||||
size_t m_step;
|
||||
size_t m_txs_total_size;
|
||||
uint64_t m_total_fee;
|
||||
currency::stake_kernel m_stake_kernel;
|
||||
size_t m_height;
|
||||
size_t m_pos_stake_output_gindex;
|
||||
uint64_t m_pos_stake_amount;
|
||||
//void step5_sign_zarcanum(const crypto::public_key& stake_tx_pub_key, size_t stake_tx_out_index, const currency::account_base& stakeholder_account);
|
||||
|
||||
|
||||
currency::block m_block {};
|
||||
size_t m_step = 0;
|
||||
size_t m_txs_total_size = 0;
|
||||
uint64_t m_total_fee = 0;
|
||||
//currency::stake_kernel m_stake_kernel {};
|
||||
size_t m_height = 0;
|
||||
size_t m_pos_stake_output_gindex = 0;
|
||||
//uint64_t m_pos_stake_amount = 0;
|
||||
crypto::scalar_t m_blinding_masks_sum {}; // bliding masks of zc outputs of miner tx
|
||||
|
||||
currency::pos_mining_context m_context {};
|
||||
};
|
||||
|
||||
bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
/* bool construct_homemade_pos_miner_tx(bool zarcanum, size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
size_t current_block_size,
|
||||
uint64_t fee,
|
||||
uint64_t pos_stake_amount,
|
||||
|
|
@ -64,7 +96,7 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo
|
|||
currency::transaction& tx,
|
||||
const currency::blobdata& extra_nonce = currency::blobdata(),
|
||||
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,
|
||||
currency::keypair tx_one_time_key = currency::keypair::generate());
|
||||
currency::keypair tx_one_time_key = currency::keypair::generate()); */
|
||||
|
||||
bool mine_next_pos_block_in_playtime_sign_cb(currency::core& c, const currency::block& prev_block, const currency::block& coinstake_scr_block, const currency::account_base& acc,
|
||||
std::function<bool(currency::block&)> before_sign_cb, currency::block& output);
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ bool gen_pos_coinstake_already_spent::generate(std::vector<test_event_entry>& ev
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), alice.get_public_address());
|
||||
|
|
@ -130,7 +130,7 @@ bool gen_pos_incorrect_timestamp::generate(std::vector<test_event_entry>& events
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
// use incorrect timestamp_step
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, blk_0r.timestamp - 1, POS_SCAN_WINDOW, POS_SCAN_STEP - 1);
|
||||
|
|
@ -148,7 +148,7 @@ bool gen_pos_incorrect_timestamp::generate(std::vector<test_event_entry>& events
|
|||
|
||||
// Now try PoS timestamp window boundaries.
|
||||
pb.clear();
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
// move timestamp to the future
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, ts + CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT + 1, POS_SCAN_WINDOW, POS_SCAN_STEP);
|
||||
|
|
@ -162,7 +162,7 @@ bool gen_pos_incorrect_timestamp::generate(std::vector<test_event_entry>& events
|
|||
|
||||
// lower limit
|
||||
pb.clear();
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
// move timestamp to the future
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, genesis_ts - POS_SCAN_WINDOW, POS_SCAN_WINDOW, POS_SCAN_STEP);
|
||||
|
|
@ -247,17 +247,17 @@ bool gen_pos_extra_nonce::generate(std::vector<test_event_entry>& events) const
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, blk_0r.timestamp);
|
||||
|
||||
// use biggest possible extra nonce (255 bytes) + largest alias
|
||||
currency::blobdata extra_none(255, 'x');
|
||||
currency::extra_alias_entry alias = AUTO_VAL_INIT(alias);
|
||||
alias.m_alias = std::string(255, 'a');
|
||||
alias.m_address = miner.get_keys().account_address;
|
||||
alias.m_text_comment = std::string(255, 'y');
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(blk_0r), alice.get_public_address(), extra_none, CURRENCY_MINER_TX_MAX_OUTS, alias);
|
||||
currency::blobdata extra_nonce(255, 'x');
|
||||
//currency::extra_alias_entry alias = AUTO_VAL_INIT(alias); // TODO: this alias entry was ignored for a long time, now I commented it out, make sure it's okay -- sowle
|
||||
//alias.m_alias = std::string(255, 'a');
|
||||
//alias.m_address = miner.get_keys().account_address;
|
||||
//alias.m_text_comment = std::string(255, 'y');
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(blk_0r), alice.get_public_address(), extra_nonce, CURRENCY_MINER_TX_MAX_OUTS);
|
||||
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, miner);
|
||||
block blk_1 = pb.m_block;
|
||||
|
||||
|
|
@ -301,7 +301,7 @@ bool gen_pos_min_allowed_height::generate(std::vector<test_event_entry>& events)
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>(1, tx_1));
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, blk_0r.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(blk_0r), alice.get_public_address());
|
||||
|
|
@ -353,7 +353,7 @@ bool gen_pos_invalid_coinbase::generate(std::vector<test_event_entry>& events) c
|
|||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), alice_acc.get_public_address());
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ struct tx_builder
|
|||
for(const currency::tx_source_entry::output_entry& out_entry : src_entr.outputs)
|
||||
input_to_key.key_offsets.push_back(out_entry.out_reference);
|
||||
|
||||
input_to_key.key_offsets = currency::absolute_output_offsets_to_relative(input_to_key.key_offsets);
|
||||
input_to_key.key_offsets = currency::absolute_output_offsets_to_relative(input_to_key.key_offsets); // TODO @#@#
|
||||
m_tx.vin.push_back(input_to_key);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,16 @@ bool wallet_test_core_proxy::update_blockchain(const std::vector<test_event_entr
|
|||
for (auto b : m_blocks)
|
||||
std::for_each(b->b.tx_hashes.begin(), b->b.tx_hashes.end(), [&confirmed_txs](const crypto::hash& h) { confirmed_txs.insert(h); });
|
||||
|
||||
for (auto e : events)
|
||||
size_t invalid_tx_index = UINT64_MAX;
|
||||
for (size_t i = 0; i < events.size(); ++i)
|
||||
{
|
||||
if (e.type() != typeid(currency::transaction))
|
||||
const test_event_entry& e = events[i];
|
||||
if (test_chain_unit_enchanced::is_event_mark_invalid_tx(e))
|
||||
{
|
||||
invalid_tx_index = i + 1;
|
||||
continue;
|
||||
}
|
||||
if (e.type() != typeid(currency::transaction) || i == invalid_tx_index)
|
||||
continue;
|
||||
|
||||
const currency::transaction& tx = boost::get<currency::transaction>(e);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ bool wallet_test::check_balance_via_build_wallets(currency::core& c, size_t ev_i
|
|||
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].wallet != 0, false, "check_balance: failed to build wallets");
|
||||
|
||||
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))
|
||||
if (!check_balance_via_wallet(*w[0].wallet, get_test_account_name_by_id(pcb.account_index).c_str(), pcb.total_balance, pcb.mined_balance, pcb.unlocked_balance, pcb.awaiting_in, pcb.awaiting_out))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
@ -67,12 +67,25 @@ bool wallet_test::check_balance(currency::core& c, size_t ev_index, const std::v
|
|||
bool has_aliases = false;
|
||||
w->scan_tx_pool(has_aliases);
|
||||
|
||||
if (!check_balance_via_wallet(*w.get(), 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.get(), get_test_account_name_by_id(pcb.account_index).c_str(), pcb.total_balance, pcb.mined_balance, pcb.unlocked_balance, pcb.awaiting_in, pcb.awaiting_out))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string wallet_test::get_test_account_name_by_id(size_t acc_id)
|
||||
{
|
||||
switch(acc_id)
|
||||
{
|
||||
case MINER_ACC_IDX: return "miner";
|
||||
case ALICE_ACC_IDX: return "Alice";
|
||||
case BOB_ACC_IDX: return "Bob";
|
||||
case CAROL_ACC_IDX: return "Carol";
|
||||
case DAN_ACC_IDX: return "Dan";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<tools::wallet2> wallet_test::init_playtime_test_wallet(const std::vector<test_event_entry>& events, currency::core& c, const account_base& acc) const
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(events.size() > 0 && events[0].type() == typeid(currency::block), "Invalid events queue, can't find genesis block at the beginning");
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ struct wallet_test : virtual public test_chain_unit_enchanced
|
|||
bool check_balance_via_build_wallets(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool check_balance(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
static std::string get_test_account_name_by_id(size_t acc_id);
|
||||
|
||||
protected:
|
||||
|
||||
struct params_check_balance
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2022 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "random_helper.h"
|
||||
#include "tx_builder.h"
|
||||
#include "pos_block_builder.h"
|
||||
|
||||
|
||||
#define AMOUNT_TO_TRANSFER_ZARCANUM_BASIC (TESTS_DEFAULT_FEE*10)
|
||||
|
|
@ -17,6 +18,7 @@
|
|||
using namespace currency;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
zarcanum_basic_test::zarcanum_basic_test()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(zarcanum_basic_test, configure_core);
|
||||
|
|
@ -30,13 +32,15 @@ zarcanum_basic_test::zarcanum_basic_test()
|
|||
|
||||
bool zarcanum_basic_test::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
m_accounts.resize(MINER_ACC_IDX+1);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX];
|
||||
miner_acc.generate();
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
|
||||
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
|
||||
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); bob_acc.set_createtime(ts);
|
||||
//account_base& carol_acc = m_accounts[CAROL_ACC_IDX]; carol_acc.generate(); carol_acc.set_createtime(ts);
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
|
||||
DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks
|
||||
set_hard_fork_heights_to_generator(generator);
|
||||
//TODO: Need to make sure REWIND_BLOCKS_N and other coretests codebase are capable of following hardfork4 rules
|
||||
//in this test hardfork4 moment moved to runtime section
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
|
||||
|
|
@ -50,58 +54,46 @@ bool zarcanum_basic_test::c1(currency::core& c, size_t ev_index, const std::vect
|
|||
{
|
||||
bool r = false;
|
||||
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
|
||||
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
|
||||
|
||||
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
|
||||
// check passing over the hardfork
|
||||
CHECK_AND_ASSERT_MES(!c.get_blockchain_storage().is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM), false, "ZANO_HARDFORK_04_ZARCANUM is active");
|
||||
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 2);
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_blockchain_storage().is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM), false, "ZANO_HARDFORK_04_ZARCANUM is not active");
|
||||
|
||||
miner_wlt->refresh();
|
||||
alice_wlt->refresh();
|
||||
|
||||
|
||||
|
||||
CHECK_AND_FORCE_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool");
|
||||
|
||||
//create transfer from pre-zarcanum inputs to post-zarcanum inputs
|
||||
uint64_t transfer_amount = AMOUNT_TO_TRANSFER_ZARCANUM_BASIC + TESTS_DEFAULT_FEE;
|
||||
miner_wlt->transfer(transfer_amount, alice_wlt->get_account().get_public_address());
|
||||
LOG_PRINT_MAGENTA("Legacy-2-zarcanum transaction sent to Alice: " << transfer_amount, LOG_LEVEL_0);
|
||||
miner_wlt->transfer(transfer_amount, alice_wlt->get_account().get_public_address());
|
||||
LOG_PRINT_MAGENTA("Legacy-2-zarcanum transaction sent to Alice: " << transfer_amount, LOG_LEVEL_0);
|
||||
miner_wlt->transfer(transfer_amount, alice_wlt->get_account().get_public_address());
|
||||
LOG_PRINT_MAGENTA("Legacy-2-zarcanum transaction sent to Alice: " << transfer_amount, LOG_LEVEL_0);
|
||||
miner_wlt->transfer(transfer_amount, alice_wlt->get_account().get_public_address());
|
||||
LOG_PRINT_MAGENTA("Legacy-2-zarcanum transaction sent to Alice: " << transfer_amount, LOG_LEVEL_0);
|
||||
const size_t batches_to_Alice_count = 4;
|
||||
for(size_t i = 0; i < batches_to_Alice_count; ++i)
|
||||
{
|
||||
miner_wlt->transfer(transfer_amount, alice_wlt->get_account().get_public_address());
|
||||
LOG_PRINT_MAGENTA("Legacy-2-zarcanum transaction sent to Alice: " << print_money_brief(transfer_amount), LOG_LEVEL_0);
|
||||
}
|
||||
|
||||
|
||||
CHECK_AND_FORCE_ASSERT_MES(c.get_pool_transactions_count() == 4, false, "Incorrect txs count in the pool");
|
||||
CHECK_AND_FORCE_ASSERT_MES(c.get_pool_transactions_count() == batches_to_Alice_count, false, "Incorrect txs count in the pool");
|
||||
|
||||
|
||||
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
|
||||
|
||||
//miner_wlt->refresh();
|
||||
CHECK_AND_FORCE_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool");
|
||||
|
||||
alice_wlt->refresh();
|
||||
|
||||
//uint64_t unlocked = 0;
|
||||
//uint64_t balance = alice_wlt->balance(unlocked);
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", transfer_amount * 4, UINT64_MAX, transfer_amount * 4), false, "");
|
||||
|
||||
account_base bob_acc;
|
||||
bob_acc.generate();
|
||||
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, bob_acc);
|
||||
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", transfer_amount * batches_to_Alice_count, UINT64_MAX, transfer_amount * batches_to_Alice_count), false, "");
|
||||
|
||||
//create transfer from post-zarcanum inputs to post-zarcanum inputs
|
||||
uint64_t transfer_amount2 = AMOUNT_TO_TRANSFER_ZARCANUM_BASIC;
|
||||
alice_wlt->transfer(transfer_amount2, bob_acc.get_public_address());
|
||||
LOG_PRINT_MAGENTA("Zarcanum-2-zarcanum transaction sent from Alice to Bob " << transfer_amount2, LOG_LEVEL_0);
|
||||
alice_wlt->transfer(transfer_amount2, m_accounts[BOB_ACC_IDX].get_public_address());
|
||||
LOG_PRINT_MAGENTA("Zarcanum-2-zarcanum transaction sent from Alice to Bob " << print_money_brief(transfer_amount2), LOG_LEVEL_0);
|
||||
|
||||
|
||||
CHECK_AND_FORCE_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool");
|
||||
|
|
@ -110,8 +102,6 @@ bool zarcanum_basic_test::c1(currency::core& c, size_t ev_index, const std::vect
|
|||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
|
||||
|
||||
bob_wlt->refresh();
|
||||
//balance = bob_wlt->balance(unlocked);
|
||||
//CHECK_AND_ASSERT_MES(unlocked == transfer_amount2, false, "wrong amount");
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt, "Bob", transfer_amount2, UINT64_MAX, transfer_amount2), false, "");
|
||||
|
||||
account_base staker_benefeciary_acc;
|
||||
|
|
@ -122,27 +112,36 @@ bool zarcanum_basic_test::c1(currency::core& c, size_t ev_index, const std::vect
|
|||
miner_benefeciary_acc.generate();
|
||||
std::shared_ptr<tools::wallet2> miner_benefeciary_acc_wlt = init_playtime_test_wallet(events, c, miner_benefeciary_acc);
|
||||
|
||||
alice_wlt->refresh();
|
||||
|
||||
size_t pos_entries_count = 0;
|
||||
//do staking
|
||||
for(size_t i = 0; i != CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4; i++)
|
||||
for(size_t i = 0; i < batches_to_Alice_count - 1; i++)
|
||||
{
|
||||
alice_wlt->refresh();
|
||||
r = mine_next_pos_block_in_playtime_with_wallet(*alice_wlt.get(), staker_benefeciary_acc_wlt->get_account().get_public_address(), pos_entries_count);
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pos_block_in_playtime_with_wallet failed");
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pos_block_in_playtime_with_wallet failed, pos_entries_count = " << pos_entries_count);
|
||||
|
||||
r = mine_next_pow_block_in_playtime(miner_benefeciary_acc.get_public_address(), c);
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
|
||||
}
|
||||
|
||||
// make sure all mined coins in staker_benefeciary_acc_wlt and miner_benefeciary_acc_wlt are now spendable
|
||||
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
|
||||
|
||||
//attempt to spend staked and mined coinbase outs
|
||||
staker_benefeciary_acc_wlt->refresh();
|
||||
miner_benefeciary_acc_wlt->refresh();
|
||||
|
||||
staker_benefeciary_acc_wlt->transfer(transfer_amount2, bob_acc.get_public_address());
|
||||
uint64_t mined_amount = (batches_to_Alice_count - 1) * COIN;
|
||||
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*staker_benefeciary_acc_wlt, "staker_benefeciary", mined_amount, mined_amount, mined_amount), false, "");
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_benefeciary_acc_wlt, "miner_benefeciary", mined_amount, mined_amount, mined_amount), false, "");
|
||||
|
||||
|
||||
staker_benefeciary_acc_wlt->transfer(transfer_amount2, bob_wlt->get_account().get_public_address());
|
||||
LOG_PRINT_MAGENTA("Zarcanum(pos-coinbase)-2-zarcanum transaction sent from Staker to Bob " << print_money_brief(transfer_amount2), LOG_LEVEL_0);
|
||||
|
||||
miner_benefeciary_acc_wlt->transfer(transfer_amount2, bob_acc.get_public_address());
|
||||
miner_benefeciary_acc_wlt->transfer(transfer_amount2, bob_wlt->get_account().get_public_address());
|
||||
LOG_PRINT_MAGENTA("Zarcanum(pow-coinbase)-2-zarcanum transaction sent from Staker to Bob " << print_money_brief(transfer_amount2), LOG_LEVEL_0);
|
||||
|
||||
CHECK_AND_FORCE_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect txs count in the pool");
|
||||
|
|
@ -154,13 +153,14 @@ bool zarcanum_basic_test::c1(currency::core& c, size_t ev_index, const std::vect
|
|||
|
||||
|
||||
bob_wlt->refresh();
|
||||
//balance = bob_wlt->balance(unlocked);
|
||||
//CHECK_AND_ASSERT_MES(unlocked == transfer_amount2*3, false, "wrong amount");
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt, "Bob", transfer_amount2*3, UINT64_MAX, transfer_amount2*3), false, "");
|
||||
|
||||
//try to make pre-zarcanum block after hardfork 4
|
||||
currency::core_runtime_config rc = alice_wlt->get_core_runtime_config();
|
||||
rc.hard_forks.set_hardfork_height(4, ZANO_HARDFORK_04_AFTER_HEIGHT);
|
||||
rc.hard_forks.set_hardfork_height(4, ZANO_HARDFORK_04_AFTER_HEIGHT); // <-- TODO: this won't help to build pre-hardfork block,
|
||||
// because blocktemplate is created by the core.
|
||||
// (wallet2::build_minted_block will fail instead)
|
||||
// We need to use pos block builder or smth -- sowle
|
||||
alice_wlt->set_core_runtime_config(rc);
|
||||
r = mine_next_pos_block_in_playtime_with_wallet(*alice_wlt.get(), staker_benefeciary_acc_wlt->get_account().get_public_address(), pos_entries_count);
|
||||
CHECK_AND_ASSERT_MES(!r, false, "Pre-zarcanum block accepted in post-zarcanum era");
|
||||
|
|
@ -169,7 +169,7 @@ 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()
|
||||
{
|
||||
|
|
@ -226,4 +226,305 @@ bool zarcanum_test_n_inputs_validation::generate(std::vector<test_event_entry>&
|
|||
REWIND_BLOCKS_N(events, blk_16, blk_14, miner_account, 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
zarcanum_gen_time_balance::zarcanum_gen_time_balance()
|
||||
{
|
||||
m_hardforks.set_hardfork_height(ZANO_HARDFORK_04_ZARCANUM, 1);
|
||||
}
|
||||
|
||||
bool zarcanum_gen_time_balance::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
// Test idea: make sure post HF4 transactions with ZC inputs and outputs are handled properly by chaingen gen-time routines
|
||||
// (including balance check)
|
||||
|
||||
bool r = false;
|
||||
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
|
||||
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
|
||||
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); bob_acc.set_createtime(ts);
|
||||
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
|
||||
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
|
||||
|
||||
std::vector<tx_source_entry> sources;
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
|
||||
//
|
||||
// tx_0: alice_amount from miner to Alice
|
||||
uint64_t alice_amount = MK_TEST_COINS(99);
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(events, blk_0r, miner_acc, alice_acc, alice_amount, TESTS_DEFAULT_FEE, 0, sources, destinations), false, "");
|
||||
|
||||
std::vector<extra_v> extra;
|
||||
transaction tx_0 = AUTO_VAL_INIT(tx_0);
|
||||
crypto::secret_key tx_sec_key;
|
||||
r = construct_tx(miner_acc.get_keys(), sources, destinations, extra, empty_attachment, tx_0, get_tx_version_from_events(events), tx_sec_key, 0);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
ADD_CUSTOM_EVENT(events, tx_0);
|
||||
|
||||
// add tx_0 to the block
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0);
|
||||
|
||||
// rewind and check unlocked balance
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, alice_amount, alice_amount, 0, 0, 0));
|
||||
|
||||
// do a gen-time balance check
|
||||
CREATE_TEST_WALLET(alice_wlt, alice_acc, blk_0);
|
||||
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_1r, 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4);
|
||||
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, alice_amount);
|
||||
|
||||
//
|
||||
// tx_1: bob_amount, Alice -> Bob
|
||||
uint64_t bob_amount = MK_TEST_COINS(15);
|
||||
|
||||
MAKE_TX(events, tx_1, alice_acc, bob_acc, bob_amount, blk_1r);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, tx_1);
|
||||
|
||||
// check Bob's balance in play time...
|
||||
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(BOB_ACC_IDX, bob_amount, 0, 0, 0, 0));
|
||||
|
||||
// ... and in gen time
|
||||
CREATE_TEST_WALLET(bob_wlt, bob_acc, blk_0);
|
||||
REFRESH_TEST_WALLET_AT_GEN_TIME(events, bob_wlt, blk_2, 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5);
|
||||
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(bob_wlt, bob_amount);
|
||||
|
||||
// try to construct tx with only one output (that is wrong for HF4)
|
||||
test_gentime_settings_restorer tgsr;
|
||||
test_gentime_settings tgs = test_generator::get_test_gentime_settings();
|
||||
tgs.split_strategy = tests_void_split_strategy; // amount won't be splitted by test_genertor::construct_tx()
|
||||
test_generator::set_test_gentime_settings(tgs);
|
||||
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
// transfer all Bob's coins -- they should be put in one out
|
||||
MAKE_TX(events, tx_2_bad, bob_acc, alice_acc, bob_amount - TESTS_DEFAULT_FEE, blk_2);
|
||||
CHECK_AND_ASSERT_MES(tx_2_bad.vout.size() == 1, false, "tx_2_bad.vout.size() = " << tx_2_bad.vout.size());
|
||||
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_3_bad, blk_2, miner_acc, tx_2_bad);
|
||||
|
||||
// now change split strategy and make a tx with more outputs
|
||||
tgs.split_strategy = tests_random_split_strategy;
|
||||
test_generator::set_test_gentime_settings(tgs);
|
||||
|
||||
size_t nmix = 7;
|
||||
MAKE_TX_FEE_MIX(events, tx_2, bob_acc, alice_acc, bob_amount - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, nmix, blk_2);
|
||||
CHECK_AND_ASSERT_MES(tx_2.vout.size() != 1, false, "tx_2.vout.size() = " << tx_2.vout.size());
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_acc, tx_2);
|
||||
|
||||
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_3, 2);
|
||||
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, alice_amount - 2 * TESTS_DEFAULT_FEE);
|
||||
|
||||
REFRESH_TEST_WALLET_AT_GEN_TIME(events, bob_wlt, blk_3, 1);
|
||||
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(bob_wlt, 0);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, alice_amount - 2 * TESTS_DEFAULT_FEE, 0, 0, 0, 0));
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(BOB_ACC_IDX, 0, 0, 0, 0, 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
zarcanum_pos_block_math::zarcanum_pos_block_math()
|
||||
{
|
||||
m_hardforks.set_hardfork_height(ZANO_HARDFORK_04_ZARCANUM, 0);
|
||||
}
|
||||
|
||||
bool zarcanum_pos_block_math::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
|
||||
MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_acc);
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
//generator.get_tx_out_gindex
|
||||
|
||||
// try to make a PoS block with locked stake after the hardfork
|
||||
|
||||
block blk_1_pos;
|
||||
{
|
||||
const block& prev_block = blk_1r;
|
||||
const transaction& stake_tx = blk_1.miner_tx;
|
||||
const account_base& stake_acc = miner_acc;
|
||||
size_t stake_out_in_tx_index = 0;
|
||||
size_t stake_output_gindex = 0;
|
||||
|
||||
crypto::hash prev_id = get_block_hash(prev_block);
|
||||
size_t height = get_block_height(prev_block) + 1;
|
||||
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
|
||||
crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake_tx);
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
|
||||
pb.step3a(diff, prev_id, null_hash);
|
||||
|
||||
crypto::key_derivation derivation {};
|
||||
crypto::scalar_t stake_out_blinding_mask {};
|
||||
uint64_t stake_output_amount = 0;
|
||||
crypto::public_key stealth_address {};
|
||||
crypto::secret_key secret_x {};
|
||||
crypto::key_image stake_output_key_image {};
|
||||
|
||||
r = generate_key_derivation(stake_tx_pub_key, stake_acc.get_keys().view_secret_key, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_key_derivation failed");
|
||||
r = is_out_to_acc(stake_acc.get_public_address(), boost::get<currency::tx_out_zarcanum>(stake_tx.vout[stake_out_in_tx_index]), derivation, stake_out_in_tx_index, stake_output_amount, stake_out_blinding_mask);
|
||||
CHECK_AND_ASSERT_MES(r, false, "is_out_to_acc failed");
|
||||
r = crypto::derive_public_key(derivation, stake_out_in_tx_index, stake_acc.get_public_address().spend_public_key, stealth_address);
|
||||
CHECK_AND_ASSERT_MES(r, false, "derive_public_key failed");
|
||||
crypto::derive_secret_key(derivation, stake_out_in_tx_index, stake_acc.get_keys().spend_secret_key, secret_x);
|
||||
crypto::generate_key_image(stealth_address, secret_x, stake_output_key_image);
|
||||
|
||||
|
||||
pb.step3b(stake_output_amount, stake_output_key_image, stake_tx_pub_key, stake_out_in_tx_index, stake_out_blinding_mask, stake_acc.get_keys().view_secret_key,
|
||||
stake_output_gindex, prev_block.timestamp, POS_SCAN_WINDOW, POS_SCAN_STEP);
|
||||
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), stake_acc.get_public_address());
|
||||
|
||||
pb.step5_sign(stake_tx_pub_key, stake_out_in_tx_index, stake_tx_pub_key, stake_acc);
|
||||
|
||||
blk_1_pos = pb.m_block;
|
||||
}
|
||||
|
||||
ADD_CUSTOM_EVENT(events, blk_1_pos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
zarcanum_txs_with_big_shuffled_decoy_set_shuffled::zarcanum_txs_with_big_shuffled_decoy_set_shuffled()
|
||||
{
|
||||
m_hardforks.set_hardfork_height(ZANO_HARDFORK_04_ZARCANUM, 24);
|
||||
}
|
||||
|
||||
bool zarcanum_txs_with_big_shuffled_decoy_set_shuffled::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
// Test idea: make few txs with a big decoy set, each time shuffling the sources (decoy set) before constructing a tx => to make sure real_output can be any.
|
||||
// Then do the same after HF4.
|
||||
|
||||
bool r = false;
|
||||
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
|
||||
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
|
||||
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); bob_acc.set_createtime(ts);
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
|
||||
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
uint64_t alice_amount = CURRENCY_BLOCK_REWARD;
|
||||
MAKE_TX(events, tx_0_a, miner_acc, alice_acc, alice_amount, blk_0r);
|
||||
MAKE_TX(events, tx_0_b, miner_acc, alice_acc, alice_amount, blk_0r);
|
||||
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list<transaction>({ tx_0_a, tx_0_b }));
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// do a gen-time balance check
|
||||
CREATE_TEST_WALLET(alice_wlt, alice_acc, blk_0);
|
||||
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_1r, 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
|
||||
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, 2 * alice_amount);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, 2 * alice_amount, 2 * alice_amount, 0, 0, 0));
|
||||
|
||||
std::vector<tx_source_entry> sources;
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
|
||||
// tx_1: Alice -> miner with big decoy set
|
||||
size_t nmix = 10;
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(events, blk_1r, alice_acc, miner_acc, alice_amount - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, nmix, sources, destinations), false, "");
|
||||
|
||||
// randomly source entries (real_output will be changed accordingly)
|
||||
CHECK_AND_ASSERT_MES(shuffle_source_entries(sources), false, "shuffle_source_entries failed");
|
||||
|
||||
transaction tx_1_a{};
|
||||
r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_1_a, get_tx_version_from_events(events), 0 /* unlock time */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
ADD_CUSTOM_EVENT(events, tx_1_a);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, tx_1_a);
|
||||
|
||||
// tx_2 (the same as tx_1): Alice -> miner, big decoy set, all coins are back now
|
||||
sources.clear();
|
||||
destinations.clear();
|
||||
nmix = 10;
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(events, blk_2, alice_acc, miner_acc, alice_amount - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, nmix, sources, destinations), false, "");
|
||||
CHECK_AND_ASSERT_MES(shuffle_source_entries(sources), false, "shuffle_source_entries failed");
|
||||
transaction tx_1_b{};
|
||||
r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_1_b, get_tx_version_from_events(events), 0 /* unlock time */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
ADD_CUSTOM_EVENT(events, tx_1_b);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_acc, tx_1_b);
|
||||
|
||||
// make sure Alice has no coins left
|
||||
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, 0, 0, 0, 0, 0));
|
||||
|
||||
|
||||
//
|
||||
// now do the same after HF4
|
||||
//
|
||||
|
||||
|
||||
// make sure the hardfork goes well
|
||||
DO_CALLBACK_PARAMS(events, "check_hardfork_inactive", static_cast<size_t>(ZANO_HARDFORK_04_ZARCANUM));
|
||||
MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_acc);
|
||||
DO_CALLBACK_PARAMS(events, "check_hardfork_active", static_cast<size_t>(ZANO_HARDFORK_04_ZARCANUM));
|
||||
|
||||
// tx_3_a, tx_3_b: miner -> Alice, alice_amount x 2
|
||||
MAKE_TX(events, tx_2_a, miner_acc, alice_acc, alice_amount, blk_4);
|
||||
MAKE_TX(events, tx_2_b, miner_acc, alice_acc, alice_amount, blk_4);
|
||||
MAKE_NEXT_BLOCK_TX_LIST(events, blk_5, blk_4, miner_acc, std::list<transaction>({ tx_2_a, tx_2_b }));
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_5r, blk_5, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// do a gen-time balance check
|
||||
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_5r, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4);
|
||||
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, 2 * alice_amount);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, 2 * alice_amount, 2 * alice_amount, 0, 0, 0));
|
||||
|
||||
// tx_3_a: Alice -> miner, alice_amount - TESTS_DEFAULT_FEE, big decoy set
|
||||
sources.clear();
|
||||
destinations.clear();
|
||||
nmix = 10;
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(events, blk_5r, alice_acc, miner_acc, alice_amount - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, nmix, sources, destinations), false, "");
|
||||
CHECK_AND_ASSERT_MES(shuffle_source_entries(sources), false, "shuffle_source_entries failed");
|
||||
transaction tx_3_a{};
|
||||
r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_3_a, get_tx_version_from_events(events), 0 /* unlock time */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
ADD_CUSTOM_EVENT(events, tx_3_a);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_6, blk_5r, miner_acc, tx_3_a);
|
||||
|
||||
// tx_3_b: Alice -> miner, alice_amount - TESTS_DEFAULT_FEE, big decoy set
|
||||
sources.clear();
|
||||
destinations.clear();
|
||||
nmix = 10;
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(events, blk_6, alice_acc, miner_acc, alice_amount - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, nmix, sources, destinations), false, "");
|
||||
CHECK_AND_ASSERT_MES(shuffle_source_entries(sources), false, "shuffle_source_entries failed");
|
||||
transaction tx_3_b{};
|
||||
r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_3_b, get_tx_version_from_events(events), 0 /* unlock time */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
ADD_CUSTOM_EVENT(events, tx_3_b);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_7, blk_6, miner_acc, tx_3_b);
|
||||
|
||||
// make sure Alice has no coins left
|
||||
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, 0, 0, 0, 0, 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2022 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include "chaingen.h"
|
||||
#include "wallet_tests_basic.h"
|
||||
|
|
@ -21,4 +20,22 @@ struct zarcanum_test_n_inputs_validation : public wallet_test
|
|||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct zarcanum_gen_time_balance : public wallet_test
|
||||
{
|
||||
zarcanum_gen_time_balance();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct zarcanum_pos_block_math : public test_chain_unit_enchanced
|
||||
{
|
||||
zarcanum_pos_block_math();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct zarcanum_txs_with_big_shuffled_decoy_set_shuffled : public wallet_test
|
||||
{
|
||||
zarcanum_txs_with_big_shuffled_decoy_set_shuffled();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ bool generate_events(currency::core& c, cct_events_t& events, const cct_wallets_
|
|||
wide_difficulty_type diff = 0;
|
||||
if (prev_block.height != 0)
|
||||
test_core_time::adjust(prev_block.bl.timestamp + DIFFICULTY_POW_TARGET);
|
||||
r = bcs.create_block_template(b, miner_addr, diff, height, ex_nonce);
|
||||
r = bcs.create_block_template(miner_addr, ex_nonce, b, diff, height);
|
||||
CHECK_AND_ASSERT_MES(r, false, "create_block_template failed");
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -288,5 +288,98 @@ TEST(bppe, two)
|
|||
ASSERT_TRUE(r);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(bppe, power_128)
|
||||
{
|
||||
std::vector<bppe_signature> signatures_vector;
|
||||
signatures_vector.reserve(200);
|
||||
std::vector<std::vector<point_t>> commitments_vector;
|
||||
commitments_vector.reserve(200);
|
||||
|
||||
std::vector<bppe_sig_commit_ref_t> sigs;
|
||||
uint8_t err = 0;
|
||||
bool r = false;
|
||||
|
||||
auto gen_rp_for_vec = [&](const scalar_vec_t& values)
|
||||
{
|
||||
signatures_vector.resize(signatures_vector.size() + 1);
|
||||
bppe_signature &bppe_sig = signatures_vector.back();
|
||||
commitments_vector.resize(commitments_vector.size() + 1);
|
||||
std::vector<point_t>& commitments = commitments_vector.back();
|
||||
|
||||
scalar_vec_t masks, masks2;
|
||||
for(auto& el: values)
|
||||
{
|
||||
masks.emplace_back(scalar_t::random());
|
||||
masks2.emplace_back(scalar_t::random());
|
||||
}
|
||||
|
||||
r = bppe_gen<bpp_crypto_trait_zano<128>>(values, masks, masks2, bppe_sig, commitments, &err);
|
||||
ASSERT_TRUE(r);
|
||||
sigs.emplace_back(bppe_sig, commitments);
|
||||
return true;
|
||||
};
|
||||
|
||||
auto gen_rp_for_value = [&](const scalar_t& v) { return gen_rp_for_vec(scalar_vec_t{ v }); };
|
||||
|
||||
const scalar_t s_128_max = scalar_t(UINT64_MAX, UINT64_MAX, 0, 0);
|
||||
|
||||
LOG_PRINT_L0("1");
|
||||
ASSERT_TRUE(gen_rp_for_value(s_128_max));
|
||||
ASSERT_TRUE(bppe_verify<bpp_crypto_trait_zano<128>>(sigs, &err));
|
||||
signatures_vector.clear(), commitments_vector.clear(), sigs.clear();
|
||||
|
||||
LOG_PRINT_L0("2");
|
||||
ASSERT_TRUE(gen_rp_for_value(scalar_t(crypto::rand<uint64_t>(), crypto::rand<uint64_t>(), 0, 0)));
|
||||
ASSERT_TRUE(bppe_verify<bpp_crypto_trait_zano<128>>(sigs, &err));
|
||||
signatures_vector.clear(), commitments_vector.clear(), sigs.clear();
|
||||
|
||||
LOG_PRINT_L0("3");
|
||||
ASSERT_TRUE(gen_rp_for_value(scalar_t(0, 0, 1, 0)));
|
||||
ASSERT_FALSE(bppe_verify<bpp_crypto_trait_zano<128>>(sigs, &err));
|
||||
signatures_vector.clear(), commitments_vector.clear(), sigs.clear();
|
||||
|
||||
LOG_PRINT_L0("4");
|
||||
ASSERT_TRUE(gen_rp_for_value(scalar_t(0, 0, crypto::rand<uint64_t>(), 0)));
|
||||
ASSERT_FALSE(bppe_verify<bpp_crypto_trait_zano<128>>(sigs, &err));
|
||||
signatures_vector.clear(), commitments_vector.clear(), sigs.clear();
|
||||
|
||||
LOG_PRINT_L0("5");
|
||||
ASSERT_TRUE(gen_rp_for_value(scalar_t(0, 0, 0, crypto::rand<uint64_t>())));
|
||||
ASSERT_FALSE(bppe_verify<bpp_crypto_trait_zano<128>>(sigs, &err));
|
||||
signatures_vector.clear(), commitments_vector.clear(), sigs.clear();
|
||||
|
||||
LOG_PRINT_L0("6");
|
||||
ASSERT_TRUE(gen_rp_for_value(scalar_t(0, 0, 0, UINT64_MAX)));
|
||||
ASSERT_FALSE(bppe_verify<bpp_crypto_trait_zano<128>>(sigs, &err));
|
||||
signatures_vector.clear(), commitments_vector.clear(), sigs.clear();
|
||||
|
||||
LOG_PRINT_L0("7");
|
||||
ASSERT_TRUE(gen_rp_for_vec(scalar_vec_t{s_128_max, s_128_max, s_128_max, s_128_max}));
|
||||
LOG_PRINT_L0("simple generated");
|
||||
ASSERT_TRUE(bppe_verify<bpp_crypto_trait_zano<128>>(sigs, &err));
|
||||
LOG_PRINT_L0("simple verified");
|
||||
for(size_t i = 0; i < 16; ++i)
|
||||
{
|
||||
LOG_PRINT_L0(" #" << i << " simple generated");
|
||||
scalar_vec_t vec;
|
||||
for(size_t j = 0, n = crypto::rand<size_t>() % 4 + 1; j < n; ++j)
|
||||
vec.emplace_back(scalar_t(crypto::rand<uint64_t>(), crypto::rand<uint64_t>(), 0, 0));
|
||||
ASSERT_TRUE(gen_rp_for_vec(vec));
|
||||
}
|
||||
LOG_PRINT_L0("verification started");
|
||||
ASSERT_TRUE(bppe_verify<bpp_crypto_trait_zano<128>>(sigs, &err));
|
||||
signatures_vector.clear(), commitments_vector.clear(), sigs.clear();
|
||||
LOG_PRINT_L0("verification finished" << ENDL);
|
||||
|
||||
LOG_PRINT_L0("8");
|
||||
ASSERT_TRUE(gen_rp_for_value(s_128_max));
|
||||
ASSERT_TRUE(gen_rp_for_value(scalar_t(0, 0, 0, UINT64_MAX)));
|
||||
ASSERT_TRUE(gen_rp_for_value(s_128_max));
|
||||
ASSERT_FALSE(bppe_verify<bpp_crypto_trait_zano<128>>(sigs, &err));
|
||||
signatures_vector.clear(), commitments_vector.clear(), sigs.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,9 +84,10 @@ TEST(tx_signatures_packing, 1)
|
|||
|
||||
{
|
||||
// empty NLSAG
|
||||
// v(0) + (1 + v(0) + 0 * 2 * 32) = 3
|
||||
// v(1) + (1 + v(0) + 0 * 2 * 32) = 3
|
||||
sigs.clear();
|
||||
sigs.emplace_back(std::move(NLSAG_sig()));
|
||||
ASSERT_EQ(3, t_serializable_object_to_blob(sigs).size());
|
||||
ASSERT_EQ(3, get_object_blobsize(sigs));
|
||||
}
|
||||
|
||||
|
|
@ -96,14 +97,28 @@ TEST(tx_signatures_packing, 1)
|
|||
sigs.clear();
|
||||
for(size_t i = 0; i < 128; ++i)
|
||||
sigs.emplace_back(std::move(NLSAG_sig()));
|
||||
ASSERT_EQ(258, t_serializable_object_to_blob(sigs).size());
|
||||
ASSERT_EQ(258, get_object_blobsize(sigs));
|
||||
}
|
||||
|
||||
{
|
||||
// 128 10-ring NLSAGs
|
||||
// v(128) + 128 * (1 + v(10) + 10 * 2 * 32) = 82178
|
||||
sigs.clear();
|
||||
NLSAG_sig nlsag = AUTO_VAL_INIT(nlsag);
|
||||
nlsag.s.resize(10);
|
||||
for(size_t i = 0; i < 128; ++i)
|
||||
sigs.push_back(nlsag);
|
||||
ASSERT_EQ(82178, t_serializable_object_to_blob(sigs).size());
|
||||
ASSERT_EQ(82178, get_object_blobsize(sigs));
|
||||
}
|
||||
|
||||
{
|
||||
// empty ZC_sig
|
||||
// v(0) + (1 + 32 + 32 + (1 + 10*32) + 32) = 99
|
||||
// v(1) + (1 + 32 + 32 + (1 + 10*32) + 32) = 99
|
||||
sigs.clear();
|
||||
sigs.emplace_back(std::move(ZC_sig()));
|
||||
ASSERT_EQ(99, t_serializable_object_to_blob(sigs).size());
|
||||
ASSERT_EQ(99, get_object_blobsize(sigs));
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +128,7 @@ TEST(tx_signatures_packing, 1)
|
|||
sigs.clear();
|
||||
for(size_t i = 0; i < 128; ++i)
|
||||
sigs.emplace_back(std::move(ZC_sig()));
|
||||
ASSERT_EQ(12546, t_serializable_object_to_blob(sigs).size());
|
||||
ASSERT_EQ(12546, get_object_blobsize(sigs));
|
||||
}
|
||||
|
||||
|
|
@ -124,6 +140,7 @@ TEST(tx_signatures_packing, 1)
|
|||
sigs.clear();
|
||||
for(size_t i = 0; i < 128; ++i)
|
||||
sigs.emplace_back(zc);
|
||||
ASSERT_EQ(53506, t_serializable_object_to_blob(sigs).size());
|
||||
ASSERT_EQ(53506, get_object_blobsize(sigs));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue