Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disqualification transactions #288

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/cryptonote_basic/cryptonote_basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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();
Expand Down
33 changes: 33 additions & 0 deletions src/cryptonote_basic/cryptonote_format_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_field> 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_field> 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;
}

}
3 changes: 3 additions & 0 deletions src/cryptonote_basic/cryptonote_format_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ namespace cryptonote
*/
bool get_graft_rta_signatures_from_extra2(const transaction& tx, std::vector<rta_signature> &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<uint8_t>& tx_extra, const blobdata& extra_nonce);
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type);
void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id);
Expand Down
48 changes: 47 additions & 1 deletion src/cryptonote_basic/tx_extra.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -220,14 +221,58 @@ 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<signer_item> 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;
// varint data[];
typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce, tx_extra_merge_mining_tag,
tx_extra_mysterious_minergate, tx_extra_graft_extra, tx_extra_graft_stake_tx,
tx_extra_graft_tx_secret_key, tx_extra_graft_rta_header, tx_extra_graft_rta_signatures> 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);
Expand All @@ -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);
10 changes: 9 additions & 1 deletion src/cryptonote_core/cryptonote_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down
7 changes: 6 additions & 1 deletion src/cryptonote_core/stake_transaction_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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; i<depth; i++)
m_on_blockchain_based_list_update(height - i, m_blockchain_based_list->tiers(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;
}
Expand Down
2 changes: 1 addition & 1 deletion src/cryptonote_core/stake_transaction_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<void(uint64_t block_number, const supernode_tier_array&)> blockchain_based_list_update_handler;
typedef std::function<void(uint64_t block_number, const crypto::hash& block_hash, const supernode_tier_array&)> 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&);
Expand Down
14 changes: 12 additions & 2 deletions src/cryptonote_core/tx_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/p2p/net_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<int, std::string> m_supernode_requests_timestamps;
Expand Down
5 changes: 3 additions & 2 deletions src/p2p/net_node.inl
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string> full_addrs;
Expand Down Expand Up @@ -2974,7 +2974,7 @@ namespace nodetool
}

template<class t_payload_net_handler>
void node_server<t_payload_net_handler>::handle_blockchain_based_list_update(uint64_t block_height, const cryptonote::StakeTransactionProcessor::supernode_tier_array& tiers)
void node_server<t_payload_net_handler>::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");

Expand All @@ -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.size(); i++)
{
Expand Down
2 changes: 2 additions & 0 deletions src/rpc/core_rpc_server_commands_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1813,9 +1813,11 @@ namespace cryptonote
struct request
{
uint64_t block_height;
std::string block_hash;
std::vector<tier> tiers;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_height)
KV_SERIALIZE(block_hash)
KV_SERIALIZE(tiers)
END_KV_SERIALIZE_MAP()
};
Expand Down