From 32d62a071f37afd317e0cfe76f608b8072da6871 Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Thu, 23 May 2019 04:46:16 +0300 Subject: [PATCH] Auth sample disqualification transactions added. --- .../cryptonote_format_utils.cpp | 41 ++- .../cryptonote_format_utils.h | 4 + src/cryptonote_basic/tx_extra.h | 38 ++- src/cryptonote_core/cryptonote_core.cpp | 8 + .../stake_transaction_processor.cpp | 251 ++++++++++++------ .../stake_transaction_processor.h | 3 + .../stake_transaction_storage.cpp | 66 ++++- .../stake_transaction_storage.h | 37 +++ src/cryptonote_core/tx_pool.cpp | 12 +- src/rpc/core_rpc_server_commands_defs.h | 2 +- src/utils/sample_generator.h | 1 + 11 files changed, 375 insertions(+), 88 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index a76dec9f6..69ee90791 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -1033,9 +1033,7 @@ namespace cryptonote return false; std::vector tx_extra_fields; parse_tx_extra(tx.extra, tx_extra_fields); - if(!find_tx_extra_field_by_type(tx_extra_fields, disq)) - return false; - return true; + return find_tx_extra_field_by_type(tx_extra_fields, disq); } bool graft_is_disqualification(const transaction &tx) @@ -1064,4 +1062,41 @@ namespace cryptonote return true; } + bool graft_get_disqualification2(const transaction &tx, tx_extra_graft_disqualification2& disq) + { + if(tx.version != 124) + return false; + if(!tx.vin.empty() || !tx.vout.empty() || tx.rct_signatures.txnFee !=0) + return false; + std::vector tx_extra_fields; + parse_tx_extra(tx.extra, tx_extra_fields); + return find_tx_extra_field_by_type(tx_extra_fields, disq); + } + + bool graft_is_disqualification2(const transaction &tx) + { + tx_extra_graft_disqualification2 disq; + return graft_get_disqualification2(tx, disq); + } + + bool graft_check_disqualification2(const transaction &tx, tx_extra_graft_disqualification2* pdisq) + { + tx_extra_graft_disqualification2 disq; + if(!graft_get_disqualification2(tx, disq)) + return false; + {//check signs + std::string item_str; + ::serialization::dump_binary(disq.item, item_str); + crypto::hash hash; + crypto::cn_fast_hash(item_str.data(), item_str.size(), hash); + for(auto& si : disq.signers) + { + if(!crypto::check_signature(hash, si.signer_id, si.sign)) + return false; + } + } + if(pdisq) *pdisq = std::move(disq); + return true; + } + } diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index 45600cb65..12f11d806 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -160,6 +160,10 @@ namespace cryptonote bool graft_is_disqualification(const transaction &tx); bool graft_check_disqualification(const transaction &tx, tx_extra_graft_disqualification* pdisq = nullptr); + bool graft_get_disqualification2(const transaction &tx, tx_extra_graft_disqualification2& disq); + bool graft_is_disqualification2(const transaction &tx); + bool graft_check_disqualification2(const transaction &tx, tx_extra_graft_disqualification2* pdisq = nullptr); + bool add_extra_nonce_to_tx_extra(std::vector& tx_extra, const blobdata& extra_nonce); bool remove_field_from_tx_extra(std::vector& tx_extra, const std::type_info &type); void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id); diff --git a/src/cryptonote_basic/tx_extra.h b/src/cryptonote_basic/tx_extra.h index 9c7898e53..2392f5b59 100644 --- a/src/cryptonote_basic/tx_extra.h +++ b/src/cryptonote_basic/tx_extra.h @@ -48,6 +48,7 @@ #define TX_EXTRA_GRAFT_RTA_HEADER_TAG 0x83 #define TX_EXTRA_GRAFT_RTA_SIGNATURES_TAG 0x84 #define TX_EXTRA_GRAFT_DISQUALIFICATION_TAG 0x85 +#define TX_EXTRA_GRAFT_DISQUALIFICATION2_TAG 0x86 #define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE @@ -265,6 +266,40 @@ namespace cryptonote END_SERIALIZE() }; + struct tx_extra_graft_disqualification2 + { + struct disqualification_item + { + std::string payment_id; + uint64_t block_height; + crypto::hash block_hash; + std::vector ids; + BEGIN_SERIALIZE() + FIELD(payment_id) + FIELD(block_height) + FIELD(block_hash) + FIELD(ids) + END_SERIALIZE() + }; + + struct signer_item + { + crypto::public_key signer_id; + crypto::signature sign; + BEGIN_SERIALIZE() + FIELD(signer_id) + FIELD(sign) + END_SERIALIZE() + }; + + disqualification_item item; + std::vector signers; + BEGIN_SERIALIZE() + FIELD(item) + FIELD(signers) + END_SERIALIZE() + }; + // tx_extra_field format, except tx_extra_padding and tx_extra_pub_key: // varint tag; // varint size; @@ -272,7 +307,7 @@ namespace cryptonote typedef boost::variant tx_extra_field; + tx_extra_graft_disqualification, tx_extra_graft_disqualification2> tx_extra_field; } VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING); @@ -286,3 +321,4 @@ VARIANT_TAG(binary_archive, cryptonote::tx_extra_graft_tx_secret_key, TX_EXTRA_G VARIANT_TAG(binary_archive, cryptonote::tx_extra_graft_rta_header, TX_EXTRA_GRAFT_RTA_HEADER_TAG); VARIANT_TAG(binary_archive, cryptonote::tx_extra_graft_rta_signatures, TX_EXTRA_GRAFT_RTA_SIGNATURES_TAG); VARIANT_TAG(binary_archive, cryptonote::tx_extra_graft_disqualification, TX_EXTRA_GRAFT_DISQUALIFICATION_TAG); +VARIANT_TAG(binary_archive, cryptonote::tx_extra_graft_disqualification2, TX_EXTRA_GRAFT_DISQUALIFICATION2_TAG); diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 230fd376f..41cb5139e 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -699,6 +699,14 @@ namespace cryptonote } return graft_is_disqualification(tx); } + if(tx.version == 124) + { + if(tx.vin.size() || tx.vout.size()) + { + MERROR_VER("qualification2 tx with non-empty inputs or outputs, rejected for tx id= " << get_transaction_hash(tx)); + } + return graft_is_disqualification2(tx); + } if(!tx.vin.size()) { MERROR_VER("tx with empty inputs, rejected for tx id= " << get_transaction_hash(tx)); diff --git a/src/cryptonote_core/stake_transaction_processor.cpp b/src/cryptonote_core/stake_transaction_processor.cpp index 7413b784c..aaff5312c 100644 --- a/src/cryptonote_core/stake_transaction_processor.cpp +++ b/src/cryptonote_core/stake_transaction_processor.cpp @@ -185,6 +185,172 @@ Ids fromIndexes(const Tiers& bbl_tiers, const std::vector& idxs) } //namespace +void StakeTransactionProcessor::process_disqualification_transaction(const transaction& tx, const crypto::hash tx_hash, uint64_t block_index, const crypto::hash& block_hash, StakeTransactionStorage::disqualification_array& disquals) +{ + assert(tx.version == 123); + + tx_extra_graft_disqualification disq_extra; + if(graft_check_disqualification(tx, &disq_extra)) + { + MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash); + return; + } + if(block_index <= disq_extra.item.block_height) + { + MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; invalid block_height " << disq_extra.item.block_height << " current " << block_index); + return; + } + crypto::hash b_hash = m_blockchain.get_block_id_by_height(disq_extra.item.block_height); + if(b_hash != disq_extra.item.block_hash) + { + MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; invalid block_hash "); + return; + } + + //get BBL + size_t depth = m_blockchain_based_list->block_height() - disq_extra.item.block_height; + if(m_blockchain_based_list->history_depth() <= depth) + { + MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; out of history "); + return; + } + + if(disq_extra.signers.size() < graft::generator::REQUIRED_BBQS_VOTES) + { + MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; lack of signers "); + return; + } + auto& tiers = m_blockchain_based_list->tiers(depth); + + auto bbl_idxs = makeBBLindexes(tiers); + + std::vector bbqs_idxs, qcl_idxs; + graft::generator::select_BBQS_QCL(disq_extra.item.block_hash, bbl_idxs, bbqs_idxs, qcl_idxs); + Ids bbqs = fromIndexes(tiers, bbqs_idxs); + Ids qcl = fromIndexes(tiers, qcl_idxs); + + if(std::none_of(qcl.begin(), qcl.end(), [&disq_extra](crypto::public_key& v)->bool { return v == disq_extra.item.id; } )) + { + std::string id_str = epee::string_tools::pod_to_hex(disq_extra.item.id); + MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; disqualified id " << id_str << " is not in QCL"); + return; + } + + for(auto& si : disq_extra.signers) + { + if(std::none_of(bbqs.begin(), bbqs.end(), [&si](crypto::public_key& v)->bool { return v == si.signer_id; } )) + { + std::string id_str = epee::string_tools::pod_to_hex(si.signer_id); + MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; signer id " << id_str << " is not in BBQS"); + return; + } + } + + disqualification disq; + serialization::dump_binary(disq_extra, disq.blob); + disq.block_index = block_index; + disq.id = disq_extra.item.id; + disq.id_str = epee::string_tools::pod_to_hex(disq.id); + + MDEBUG("New disqualification transaction found at block #" << block_index << ", tx_hash=" << tx_hash << ", supernode_id '" << disq.id_str << "'"); + + disquals.push_back(std::move(disq)); +} + +void StakeTransactionProcessor::process_disqualification2_transaction(const transaction& tx, const crypto::hash tx_hash, uint64_t block_index, const crypto::hash& block_hash, StakeTransactionStorage::disqualification2_storage_array& disquals2) +{ + assert(tx.version == 124); + + tx_extra_graft_disqualification2 disq_extra; + if(graft_check_disqualification2(tx, &disq_extra)) + { + MWARNING("Ignore invalid disqualification2 transaction at block #" << block_index << ", tx_hash=" << tx_hash); + return; + } + if(block_index <= disq_extra.item.block_height) + { + MWARNING("Ignore invalid disqualification2 transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; invalid block_height " << disq_extra.item.block_height << " current " << block_index); + return; + } + crypto::hash b_hash = m_blockchain.get_block_id_by_height(disq_extra.item.block_height); + if(b_hash != disq_extra.item.block_hash) + { + MWARNING("Ignore invalid disqualification2 transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; invalid block_hash "); + return; + } + + //get BBL + size_t depth = m_blockchain_based_list->block_height() - disq_extra.item.block_height; + if(m_blockchain_based_list->history_depth() <= depth) + { + MWARNING("Ignore invalid disqualification2 transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; out of history "); + return; + } + + if(disq_extra.signers.size() < graft::generator::REQUIRED_DISQUAL2_VOTES) + { + MWARNING("Ignore invalid disqualification2 transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; lack of signers "); + return; + } + auto& tiers = m_blockchain_based_list->tiers(depth); + + auto bbl_idxs = makeBBLindexes(tiers); + + std::vector auths_idxs; + graft::generator::select_AuthSample(disq_extra.item.payment_id, bbl_idxs, auths_idxs); + Ids auths = fromIndexes(tiers, auths_idxs); + + for(const auto& id : disq_extra.item.ids) + { + if(std::none_of(auths.begin(), auths.end(), [&id](crypto::public_key& v)->bool { return v == id; } )) + { + std::string id_str = epee::string_tools::pod_to_hex(id); + MWARNING("Ignore invalid disqualification2 transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; disqualified id " << id_str << " is not in the auth sample"); + return; + } + } + + for(const auto& si : disq_extra.signers) + { + if(std::none_of(auths.begin(), auths.end(), [&si](crypto::public_key& v)->bool { return v == si.signer_id; } )) + { + std::string id_str = epee::string_tools::pod_to_hex(si.signer_id); + MWARNING("Ignore invalid disqualification2 transaction at block #" << block_index << ", tx_hash=" << tx_hash + << "; signer id " << id_str << " is not in the auth sample"); + return; + } + } + + disqualification2_storage_item disq; + serialization::dump_binary(disq_extra, disq.blob); + disq.block_index = block_index; + + std::string ids_str = "("; + { + bool comma = false; + for(const auto& id : disq_extra.item.ids) + { + if(comma) ids_str += ", "; + ids_str += epee::string_tools::pod_to_hex(id); + } + ids_str += ")"; + } + MDEBUG("New disqualification transaction found at block #" << block_index << ", tx_hash=" << tx_hash << ", disqualified supernode ids " << ids_str); + + disquals2.push_back(std::move(disq)); +} + void StakeTransactionProcessor::process_block_stake_transaction(uint64_t block_index, const block& block, const crypto::hash& block_hash, bool update_storage) { if (block_index <= m_storage->get_last_processed_block_index()) @@ -212,6 +378,7 @@ void StakeTransactionProcessor::process_block_stake_transaction(uint64_t block_i } StakeTransactionStorage::disqualification_array disquals; + StakeTransactionStorage::disqualification2_storage_array disquals2; for (const transaction& tx : txs) { @@ -221,83 +388,14 @@ void StakeTransactionProcessor::process_block_stake_transaction(uint64_t block_i { if(tx.version == 123) { - continue; - tx_extra_graft_disqualification disq_extra; - if(graft_check_disqualification(tx, &disq_extra)) - { - MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash); - continue; - } - if(block_index <= disq_extra.item.block_height) - { - MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash - << "; invalid block_height " << disq_extra.item.block_height << " current " << block_index); - continue; - } - crypto::hash b_hash = m_blockchain.get_block_id_by_height(disq_extra.item.block_height); - if(b_hash != disq_extra.item.block_hash) - { - MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash - << "; invalid block_hash "); - continue; - } - - //get BBL - size_t depth = m_blockchain_based_list->block_height() - disq_extra.item.block_height; - if(m_blockchain_based_list->history_depth() <= depth) - { - MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash - << "; out of history "); - continue; - } - - if(disq_extra.signers.size() < graft::generator::REQUIRED_BBQS_VOTES) - { - MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash - << "; lack of signers "); - continue; - } - auto& tiers = m_blockchain_based_list->tiers(depth); - - auto bbl_idxs = makeBBLindexes(tiers); - - std::vector bbqs_idxs, qcl_idxs; - graft::generator::select_BBQS_QCL(disq_extra.item.block_hash, bbl_idxs, bbqs_idxs, qcl_idxs); - Ids bbqs = fromIndexes(tiers, bbqs_idxs); - Ids qcl = fromIndexes(tiers, qcl_idxs); - - if(std::none_of(qcl.begin(), qcl.end(), [&disq_extra](crypto::public_key& v)->bool { return v == disq_extra.item.id; } )) - { - std::string id_str; - epee::string_tools::pod_to_hex(disq_extra.item.id); - MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash - << "; disqualified id " << id_str << " is not in QCL"); - continue; - } - - for(auto& si : disq_extra.signers) - { - if(std::none_of(bbqs.begin(), bbqs.end(), [&si](crypto::public_key& v)->bool { return v == si.signer_id; } )) - { - std::string id_str; - epee::string_tools::pod_to_hex(si.signer_id); - MWARNING("Ignore invalid disqualification transaction at block #" << block_index << ", tx_hash=" << tx_hash - << "; signer id " << id_str << " is not in BBQS"); - continue; - } - } - - disqualification disq; - ::serialization::dump_binary(disq_extra, disq.blob); - disq.block_index = block_index; - disq.id = disq_extra.item.id; - disq.id_str = epee::string_tools::pod_to_hex(disq.id); - - MDEBUG("New disqualification transaction found at block #" << block_index << ", tx_hash=" << tx_hash << ", supernode_id '" << disq.id_str << "'"); - - disquals.push_back(std::move(disq)); + process_disqualification_transaction(tx, tx_hash, block_index, block_hash, disquals); + continue; + } + if(tx.version == 124) + { + process_disqualification2_transaction(tx, tx_hash, block_index, block_hash, disquals2); continue; - } //if(tx.version == 123) + } stake_transaction stake_tx; @@ -370,6 +468,7 @@ void StakeTransactionProcessor::process_block_stake_transaction(uint64_t block_i } m_storage->add_disquals(disquals); + m_storage->add_disquals2(disquals2); m_stakes_need_update = true; //TODO: cache for stakes diff --git a/src/cryptonote_core/stake_transaction_processor.h b/src/cryptonote_core/stake_transaction_processor.h index aa020bc69..0ec5f5a7c 100644 --- a/src/cryptonote_core/stake_transaction_processor.h +++ b/src/cryptonote_core/stake_transaction_processor.h @@ -52,6 +52,9 @@ class StakeTransactionProcessor void process_block_stake_transaction(uint64_t block_index, const block& block, const crypto::hash& block_hash, bool update_storage = true); void process_block_blockchain_based_list(uint64_t block_index, const block& block, const crypto::hash& block_hash, bool update_storage = true); + void process_disqualification_transaction(const transaction& tx, const crypto::hash tx_hash, uint64_t block_index, const crypto::hash& block_hash, StakeTransactionStorage::disqualification_array& disquals); + void process_disqualification2_transaction(const transaction& tx, const crypto::hash tx_hash, uint64_t block_index, const crypto::hash& block_hash, StakeTransactionStorage::disqualification2_storage_array& disquals2); + private: std::string m_config_dir; Blockchain& m_blockchain; diff --git a/src/cryptonote_core/stake_transaction_storage.cpp b/src/cryptonote_core/stake_transaction_storage.cpp index ef5315a9a..9936fe3e0 100644 --- a/src/cryptonote_core/stake_transaction_storage.cpp +++ b/src/cryptonote_core/stake_transaction_storage.cpp @@ -23,15 +23,18 @@ struct stake_transaction_file_data StakeTransactionStorage::stake_transaction_array& stake_txs; StakeTransactionStorage::block_hash_list& block_hashes; StakeTransactionStorage::disqualification_array& disqualifications; + StakeTransactionStorage::disqualification2_storage_array& disqualifications2_storage; stake_transaction_file_data(uint64_t in_last_processed_block_index, StakeTransactionStorage::stake_transaction_array& in_stake_txs, - size_t in_last_processed_block_hashes_count, StakeTransactionStorage::block_hash_list& in_block_hashes, StakeTransactionStorage::disqualification_array& disqualifications) + size_t in_last_processed_block_hashes_count, StakeTransactionStorage::block_hash_list& in_block_hashes, + StakeTransactionStorage::disqualification_array& disqualifications, StakeTransactionStorage::disqualification2_storage_array& disqualifications2_storage) : last_processed_block_index(in_last_processed_block_index) , last_processed_block_hashes_count(in_last_processed_block_hashes_count) , stake_txs(in_stake_txs) , block_hashes(in_block_hashes) , disqualifications(disqualifications) + , disqualifications2_storage(disqualifications2_storage) { } @@ -41,6 +44,7 @@ struct stake_transaction_file_data FIELD(block_hashes) FIELD(stake_txs) FIELD(disqualifications) + FIELD(disqualifications2_storage) END_SERIALIZE() }; @@ -66,6 +70,7 @@ void StakeTransactionStorage::add_tx(const stake_transaction& tx) void StakeTransactionStorage::add_disquals(const disqualification_array& disqs) { + if(disqs.empty()) return; //sort and merge auto middle = m_disqualifications.insert(m_disqualifications.end(), disqs.begin(), disqs.end()); std::sort(middle, m_disqualifications.end(), disqualification::less_id_str); @@ -74,11 +79,54 @@ void StakeTransactionStorage::add_disquals(const disqualification_array& disqs) m_need_store = true; } +StakeTransactionStorage::disqualification2_array StakeTransactionStorage::disquals2_from_storage(const disqualification2_storage_array& disqs_store) +{ + disqualification2_array disqs; + disqs.reserve(disqs_store.size()); //at least + for(const auto& item_store : disqs_store) + { + tx_extra_graft_disqualification2 extra_d2; + bool res = serialization::parse_binary(item_store.blob, extra_d2); + assert(res); + for(const auto& id : extra_d2.item.ids) + { + disqualification2 d2; + d2.block_index = item_store.block_index; + d2.id_str = epee::string_tools::pod_to_hex(id); + disqs.emplace_back( std::move(d2) ); + } + } + //sort + std::sort(disqs.begin(), disqs.end(), disqualification2::less_id_str); + return disqs; +} + +void StakeTransactionStorage::add_disquals2(const disqualification2_storage_array& disqs_store) +{ + if(disqs_store.empty()) return; + m_disqualifications2_storage.insert(m_disqualifications2_storage.end(), disqs_store.begin(), disqs_store.end()); + //make disqualification2 array from storage items + disqualification2_array disqs = disquals2_from_storage(disqs_store); + //merge + auto middle = m_disqualifications2.insert(m_disqualifications2.end(), disqs.begin(), disqs.end()); + std::inplace_merge(m_disqualifications2.begin(), middle, m_disqualifications2.end(), disqualification2::less_id_str); + + m_need_store = true; +} + bool StakeTransactionStorage::is_disqualified(uint64_t block_number, const std::string& supernode_public_id) const { - disqualification tmp; tmp.id_str = supernode_public_id; - auto pair = std::equal_range(m_disqualifications.begin(), m_disqualifications.end(), tmp, disqualification::less_id_str); - return std::any_of(pair.first, pair.second, [block_number](const disqualification& v){ return v.is_active_for(block_number); }); + {//disqualification + disqualification tmp; tmp.id_str = supernode_public_id; + auto pair = std::equal_range(m_disqualifications.begin(), m_disqualifications.end(), tmp, disqualification::less_id_str); + bool res = std::any_of(pair.first, pair.second, [block_number](const disqualification& v){ return v.is_active_for(block_number); }); + if(res) return true; + } + {//disqualification2 + disqualification2 tmp; tmp.id_str = supernode_public_id; + auto pair = std::equal_range(m_disqualifications2.begin(), m_disqualifications2.end(), tmp, disqualification2::less_id_str); + return std::any_of(pair.first, pair.second, [block_number](const disqualification2& v){ return v.is_active_for(block_number); }); + } } const crypto::hash& StakeTransactionStorage::get_last_processed_block_hash() const @@ -347,7 +395,8 @@ void StakeTransactionStorage::load() StakeTransactionStorage::stake_transaction_array tmp_stake_txs; StakeTransactionStorage::block_hash_list tmp_block_hashes; StakeTransactionStorage::disqualification_array tmp_disqualifications; - stake_transaction_file_data data(0, tmp_stake_txs, 0, tmp_block_hashes, tmp_disqualifications); + StakeTransactionStorage::disqualification2_storage_array tmp_disqualifications2_storage; + stake_transaction_file_data data(0, tmp_stake_txs, 0, tmp_block_hashes, tmp_disqualifications, tmp_disqualifications2_storage); r = ::serialization::parse_binary(buffer, data); @@ -359,6 +408,10 @@ void StakeTransactionStorage::load() std::swap(m_stake_txs, data.stake_txs); std::swap(m_last_processed_block_hashes, data.block_hashes); std::swap(m_disqualifications, data.disqualifications); + std::swap(m_disqualifications2_storage, data.disqualifications2_storage); + + disqualification2_array disqs2 = disquals2_from_storage(m_disqualifications2_storage); + m_disqualifications2.swap(disqs2); m_need_store = false; } @@ -373,7 +426,8 @@ void StakeTransactionStorage::store() const { stake_transaction_file_data data(m_last_processed_block_index, const_cast(m_stake_txs), m_last_processed_block_hashes_count, const_cast(m_last_processed_block_hashes) - , const_cast(m_disqualifications)); + , const_cast(m_disqualifications) + , const_cast(m_disqualifications2_storage)); std::ofstream ostr; ostr.open(m_storage_file_name, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); diff --git a/src/cryptonote_core/stake_transaction_storage.h b/src/cryptonote_core/stake_transaction_storage.h index e3db2ad73..4f9a1b2fa 100644 --- a/src/cryptonote_core/stake_transaction_storage.h +++ b/src/cryptonote_core/stake_transaction_storage.h @@ -48,6 +48,7 @@ struct supernode_stake //TODO: find good place for it common with supernode constexpr size_t DISQUALIFICATION_DURATION_BLOCK_COUNT = 10; +constexpr size_t DISQUALIFICATION2_DURATION_BLOCK_COUNT = 10; struct disqualification { @@ -79,6 +80,34 @@ struct disqualification } }; +struct disqualification2_storage_item +{ + std::string blob; //tx_extra_graft_disqualification2 + uint64_t block_index; //block_index where transaction is stored, not that from the blob. disqualifications should be applied from next block + BEGIN_SERIALIZE_OBJECT() + FIELD(blob) + FIELD(block_index) + END_SERIALIZE() +}; + +struct disqualification2 +{ + std::string id_str; + uint64_t block_index; //block_index where transaction is stored, not that from the blob. disqualifications should be applied from next block + //uint64_t unlock_time == block_height + DISQUALIFICATION2_DURATION_BLOCK_COUNT + + bool is_active_for(uint64_t block_index_target) const + { + //from next block where the transaction is stored + return block_index < block_index_target && block_index_target <= block_index + DISQUALIFICATION2_DURATION_BLOCK_COUNT; + } + + static bool less_id_str(const disqualification2& l, const disqualification2& r) + { + return l.id_str < r.id_str; + } +}; + class StakeTransactionStorage { public: @@ -86,6 +115,8 @@ class StakeTransactionStorage typedef std::list block_hash_list; typedef std::vector supernode_stake_array; typedef std::vector disqualification_array; + typedef std::vector disqualification2_storage_array; + typedef std::vector disqualification2_array; typedef vector supernode_disqualification_array; StakeTransactionStorage(const std::string& storage_file_name, uint64_t first_block_number); @@ -114,6 +145,7 @@ class StakeTransactionStorage /// Add transaction void add_tx(const stake_transaction&); void add_disquals(const disqualification_array& disqs); + void add_disquals2(const disqualification2_storage_array& disqs_store); /// List of supernode stakes const supernode_stake_array& get_supernode_stakes(uint64_t block_number); @@ -141,6 +173,9 @@ class StakeTransactionStorage typedef std::unordered_map supernode_stake_index_map; + //returns sorted array of disqualification2 from storage items + disqualification2_array disquals2_from_storage(const disqualification2_storage_array& disqs_store); + private: std::string m_storage_file_name; uint64_t m_last_processed_block_index; @@ -154,6 +189,8 @@ class StakeTransactionStorage mutable bool m_need_store; disqualification_array m_disqualifications; //sorted by id_str + disqualification2_array m_disqualifications2; //sorted by id_str + disqualification2_storage_array m_disqualifications2_storage; supernode_disqualification_array m_supernode_disqualifications; //an array valid for m_supernode_stakes_update_block_number }; diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 5188156dd..54969651c 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -176,6 +176,7 @@ namespace cryptonote // 2. if tx.version >= 3 and tx.rta_signatures.size() > 0 bool is_disqualification_tx = (tx.version == 123); + bool is_disqualification2_tx = (tx.version == 124); bool is_rta_tx = tx.type == transaction::tx_type_rta; if(is_disqualification_tx) { @@ -186,6 +187,15 @@ namespace cryptonote return false; } } + else if (is_disqualification2_tx) + { + if(!graft_check_disqualification2(tx)) + { + MERROR("Invalid disqualification2 transaction with id " << id); + tvc.m_verifivation_failed = true; + return false; + } + } else if (is_rta_tx) { cryptonote::rta_header rta_hdr; if (!cryptonote::get_graft_rta_header_from_extra(tx, rta_hdr)) { @@ -255,7 +265,7 @@ namespace cryptonote crypto::hash max_used_block_id = null_hash; uint64_t max_used_block_height = 0; cryptonote::txpool_tx_meta_t meta; - bool ch_inp_res = is_disqualification_tx || m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id, tvc, kept_by_block); + bool ch_inp_res = is_disqualification_tx || is_disqualification2_tx || m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id, tvc, kept_by_block); if(!ch_inp_res) { // if the transaction was valid before (kept_by_block), then it diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 433ff1c70..017206085 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -1750,7 +1750,7 @@ namespace cryptonote { uint64_t block_height; std::vector stakes; - std::vector disqualifications; //tx_extra_graft_disqualification; + std::vector disqualifications; //tx_extra_graft_disqualification; is it required? looks like is not BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(block_height) KV_SERIALIZE(stakes) diff --git a/src/utils/sample_generator.h b/src/utils/sample_generator.h index 77183a2b8..6765097cd 100644 --- a/src/utils/sample_generator.h +++ b/src/utils/sample_generator.h @@ -112,6 +112,7 @@ constexpr int32_t AUTH_SAMPLE_SIZE = TIERS * ITEMS_PER_TIER; constexpr int32_t BBQS_SIZE = TIERS * ITEMS_PER_TIER; constexpr int32_t QCL_SIZE = TIERS * ITEMS_PER_TIER; constexpr int32_t REQUIRED_BBQS_VOTES = (BBQS_SIZE*2 + (3-1))/3; +constexpr int32_t REQUIRED_DISQUAL2_VOTES = 5; /*! * \brief selectSample - selects a sample such as BBQS and QCl.