forked from lthn/blockchain
Zarcanum PoS blocks validation: WIP + wallet decoys
This commit is contained in:
parent
bb61396c10
commit
3aafd31992
3 changed files with 43 additions and 16 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue