1
0
Fork 0
forked from lthn/blockchain

Zarcanum PoS blocks validation: WIP + wallet decoys

This commit is contained in:
sowle 2022-10-18 04:34:32 +02:00
parent bb61396c10
commit 3aafd31992
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
3 changed files with 43 additions and 16 deletions

View file

@ -5419,6 +5419,31 @@ bool blockchain_storage::validate_pos_block(const block& b,
if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM))
{
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);
r = crypto::verify_CLSAG_GGXG(miner_tx_hash, ring, sig.pseudo_out_amount_commitment, sig.C, stake_input.k_image, sig.clsag_ggxg);
CHECK_AND_ASSERT_MES(r, false, "verify_CLSAG_GGXG failed");
return false; // not implemented yet, TODO @#@#
}
else

View file

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

View file

@ -3724,7 +3724,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 +3743,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,32 +3755,27 @@ 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 (absolute_output_offsets_to_relative)
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);
}
else
@ -3793,6 +3790,7 @@ 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