diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index 213a05283..a70e4e22a 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -174,7 +174,7 @@ namespace cryptonote BEGIN_SERIALIZE() VARINT_FIELD(version) - if (version == 0 || CURRENT_TRANSACTION_VERSION < version) return false; + if (version == 0 || (version != 123 && CURRENT_TRANSACTION_VERSION < version)) return false; VARINT_FIELD(unlock_time) FIELD(vin) FIELD(vout) @@ -279,7 +279,7 @@ namespace cryptonote transaction(); transaction(const transaction &t): transaction_prefix(t), hash_valid(false), blob_size_valid(false), signatures(t.signatures), rct_signatures(t.rct_signatures), type(t.type), extra2(t.extra2) { if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } } - transaction &operator=(const transaction &t) { transaction_prefix::operator=(t); set_hash_valid(false); set_blob_size_valid(false); signatures = t.signatures; rct_signatures = t.rct_signatures; type = t.type; extra2 = extra2; if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } return *this; } + transaction &operator=(const transaction &t) { transaction_prefix::operator=(t); set_hash_valid(false); set_blob_size_valid(false); signatures = t.signatures; rct_signatures = t.rct_signatures; type = t.type; extra2 = t.extra2; if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } return *this; } virtual ~transaction(); void set_null(); void invalidate_hashes(); diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index c9e9f5bf5..d0451ed42 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -1025,4 +1025,37 @@ namespace cryptonote return ::serialization::parse_binary(rta_signatures_data.data, rta_signatures); } + bool graft_is_disqualification(const transaction &tx) + { + if(tx.version != 123) return false; + std::vector tx_extra_fields; + parse_tx_extra(tx.extra, tx_extra_fields); + tx_extra_graft_disqualification disq; + if(!find_tx_extra_field_by_type(tx_extra_fields, disq)) + return false; + return true; + } + + bool graft_check_disqualification(const transaction &tx) + { + if(tx.version != 123) 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); + tx_extra_graft_disqualification disq; + if(!find_tx_extra_field_by_type(tx_extra_fields, 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; + } + } + return true; + } + } diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index 1de517e8c..f90bc9ebc 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -156,6 +156,9 @@ namespace cryptonote */ bool get_graft_rta_signatures_from_extra2(const transaction& tx, std::vector &rta_signatures); + bool graft_is_disqualification(const transaction &tx); + bool graft_check_disqualification(const transaction &tx); + 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 1c040c7ce..c2db5517a 100644 --- a/src/cryptonote_basic/tx_extra.h +++ b/src/cryptonote_basic/tx_extra.h @@ -47,6 +47,7 @@ #define TX_EXTRA_GRAFT_TX_SECRET_KEY_TAG 0x81 #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_MYSTERIOUS_MINERGATE_TAG 0xDE @@ -220,6 +221,49 @@ namespace cryptonote END_SERIALIZE() }; + struct tx_extra_graft_signer_item + { + uint64_t block_height; + crypto::hash block_hash; + crypto::public_key id; + BEGIN_SERIALIZE() + FIELD(block_height) + FIELD(block_hash) + FIELD(id) + END_SERIALIZE() + }; + + struct tx_extra_graft_disqualification + { + struct disqualification_item + { + uint64_t block_height; + crypto::hash block_hash; + crypto::public_key id; + BEGIN_SERIALIZE() + FIELD(block_height) + FIELD(block_hash) + FIELD(id) + 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; @@ -227,7 +271,8 @@ namespace cryptonote // varint data[]; typedef boost::variant tx_extra_field; + tx_extra_graft_tx_secret_key, tx_extra_graft_rta_header, tx_extra_graft_rta_signatures, + tx_extra_graft_disqualification> tx_extra_field; } VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING); @@ -240,3 +285,4 @@ VARIANT_TAG(binary_archive, cryptonote::tx_extra_graft_stake_tx, TX_EXTRA_GRAFT_ VARIANT_TAG(binary_archive, cryptonote::tx_extra_graft_tx_secret_key, TX_EXTRA_GRAFT_TX_SECRET_KEY_TAG); 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); diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index ecc587483..230fd376f 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -533,7 +533,7 @@ namespace cryptonote uint8_t version = m_blockchain_storage.get_current_hard_fork_version(); // don't allow rta tx until hf 13 const size_t max_tx_version = version == 1 ? 1 : version < 13 ? 2 : CURRENT_TRANSACTION_VERSION; - if (tx.version == 0 || tx.version > max_tx_version) + if (tx.version == 0 || (tx.version != 123 && tx.version > max_tx_version)) { // v3 is the latest one we know tvc.m_verifivation_failed = true; @@ -691,6 +691,14 @@ namespace cryptonote //----------------------------------------------------------------------------------------------- bool core::check_tx_semantic(const transaction& tx, bool keeped_by_block) const { + if(tx.version == 123) + { + if(tx.vin.size() || tx.vout.size()) + { + MERROR_VER("qualification tx with non-empty inputs or outputs, rejected for tx id= " << get_transaction_hash(tx)); + } + return graft_is_disqualification(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 1f51b94b3..52b9e5d47 100644 --- a/src/cryptonote_core/stake_transaction_processor.cpp +++ b/src/cryptonote_core/stake_transaction_processor.cpp @@ -458,7 +458,12 @@ void StakeTransactionProcessor::invoke_update_blockchain_based_list_handler_impl uint64_t height = m_blockchain_based_list->block_height(); for (size_t i=0; itiers(i)); + { + uint64_t block_height = height - i; + crypto::hash block_hash = m_blockchain.get_block_id_by_height(block_height); + + m_on_blockchain_based_list_update(block_height, block_hash, m_blockchain_based_list->tiers(i)); + } m_blockchain_based_list_need_update = false; } diff --git a/src/cryptonote_core/stake_transaction_processor.h b/src/cryptonote_core/stake_transaction_processor.h index 6d1ce1d4f..26222cd58 100644 --- a/src/cryptonote_core/stake_transaction_processor.h +++ b/src/cryptonote_core/stake_transaction_processor.h @@ -35,7 +35,7 @@ class StakeTransactionProcessor void invoke_update_stakes_handler(bool force = true); typedef BlockchainBasedList::supernode_tier_array supernode_tier_array; - typedef std::function blockchain_based_list_update_handler; + typedef std::function blockchain_based_list_update_handler; /// Update handler for new blockchain based list void set_on_update_blockchain_based_list_handler(const blockchain_based_list_update_handler&); diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index e9fee98e5..8a103109b 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -175,8 +175,18 @@ namespace cryptonote // 1. if tx.type == tx_type_rta and tx.rta_signatures.size() > 0 // 2. if tx.version >= 3 and tx.rta_signatures.size() > 0 + bool is_disqualification_tx = (tx.version == 123); bool is_rta_tx = tx.type == transaction::tx_type_rta; - if (is_rta_tx) { + if(is_disqualification_tx) + { + if(!graft_check_disqualification(tx)) + { + MERROR("Invalid disqualification 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)) { MERROR("Failed to parse rta-header from tx extra: " << id); @@ -245,7 +255,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 = 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 || 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/p2p/net_node.h b/src/p2p/net_node.h index f5999538a..c4e49e1b8 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -417,7 +417,7 @@ namespace nodetool private: void handle_stakes_update(uint64_t block_number, const cryptonote::StakeTransactionProcessor::supernode_stake_array& stakes); - void handle_blockchain_based_list_update(uint64_t block_number, const cryptonote::StakeTransactionProcessor::supernode_tier_array& tiers); + void handle_blockchain_based_list_update(uint64_t block_number, const crypto::hash& block_hash, const cryptonote::StakeTransactionProcessor::supernode_tier_array& tiers); private: std::multimap m_supernode_requests_timestamps; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index a02e540c8..240e431aa 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -533,7 +533,7 @@ namespace nodetool ); m_payload_handler.get_core().set_update_blockchain_based_list_handler( - [&](uint64_t block_height, const cryptonote::StakeTransactionProcessor::supernode_tier_array& tiers) { handle_blockchain_based_list_update(block_height, tiers); } + [&](uint64_t block_height, const crypto::hash& block_hash, const cryptonote::StakeTransactionProcessor::supernode_tier_array& tiers) { handle_blockchain_based_list_update(block_height, block_hash, tiers); } ); std::set full_addrs; @@ -2974,7 +2974,7 @@ namespace nodetool } template - void node_server::handle_blockchain_based_list_update(uint64_t block_height, const cryptonote::StakeTransactionProcessor::supernode_tier_array& tiers) + void node_server::handle_blockchain_based_list_update(uint64_t block_height, const crypto::hash& block_hash, const cryptonote::StakeTransactionProcessor::supernode_tier_array& tiers) { static std::string supernode_endpoint("blockchain_based_list"); @@ -2988,6 +2988,7 @@ namespace nodetool cryptonote::COMMAND_RPC_SUPERNODE_BLOCKCHAIN_BASED_LIST::request request; request.block_height = block_height; + request.block_hash = epee::string_tools::pod_to_hex(block_hash); for (size_t i=0; i tiers; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(block_height) + KV_SERIALIZE(block_hash) KV_SERIALIZE(tiers) END_KV_SERIALIZE_MAP() };