oxen-core/src/cryptonote_core/service_node_list.cpp

1104 lines
39 KiB
C++
Raw Normal View History

2018-06-29 06:47:00 +02:00
// Copyright (c) 2018, The Loki Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <functional>
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
#include <random>
2018-06-29 06:47:00 +02:00
2018-06-29 06:47:00 +02:00
#include "ringct/rctSigs.h"
#include "wallet/wallet2.h"
#include "cryptonote_tx_utils.h"
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
#include "cryptonote_basic/tx_extra.h"
#include "common/int-util.h"
#include "common/scoped_message_writer.h"
#include "common/i18n.h"
#include "quorum_cop.h"
#include "common/exp2.h"
2018-06-29 06:47:00 +02:00
#include "service_node_list.h"
#undef LOKI_DEFAULT_LOG_CATEGORY
#define LOKI_DEFAULT_LOG_CATEGORY "service_nodes"
namespace service_nodes
{
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
2018-06-29 06:47:00 +02:00
service_node_list::service_node_list(cryptonote::Blockchain& blockchain)
: m_blockchain(blockchain), m_hooks_registered(false)
2018-06-29 06:47:00 +02:00
{
}
void service_node_list::register_hooks(service_nodes::quorum_cop &quorum_cop)
{
if (!m_hooks_registered)
{
m_hooks_registered = true;
m_blockchain.hook_block_added(*this);
m_blockchain.hook_blockchain_detached(*this);
m_blockchain.hook_init(*this);
m_blockchain.hook_validate_miner_tx(*this);
// NOTE: There is an implicit dependency on service node lists hooks
m_blockchain.hook_block_added(quorum_cop);
m_blockchain.hook_blockchain_detached(quorum_cop);
}
2018-06-29 06:47:00 +02:00
}
void service_node_list::init()
{
// TODO: Save this calculation, only do it if it's not here.
LOG_PRINT_L0("Recalculating service nodes list, scanning last 30 days");
uint64_t current_height = m_blockchain.get_current_blockchain_height();
2018-06-29 06:47:00 +02:00
bool loaded = load();
2018-06-29 06:47:00 +02:00
if (loaded && m_height == current_height) return;
if (!loaded || m_height > current_height) clear(true);
uint64_t start_height = m_height;
2018-06-29 06:47:00 +02:00
if (current_height >= STAKING_REQUIREMENT_LOCK_BLOCKS + STAKING_RELOCK_WINDOW_BLOCKS)
start_height = std::max(start_height, current_height - STAKING_REQUIREMENT_LOCK_BLOCKS - STAKING_RELOCK_WINDOW_BLOCKS);
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
for (uint64_t height = start_height; height < current_height; height += 1000)
2018-06-29 06:47:00 +02:00
{
std::list<std::pair<cryptonote::blobdata, cryptonote::block>> blocks;
if (!m_blockchain.get_blocks(height, 1000, blocks))
{
LOG_ERROR("Unable to initialize service nodes list");
return;
}
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
2018-06-29 06:47:00 +02:00
for (const auto& block_pair : blocks)
{
const cryptonote::block& block = block_pair.second;
std::list<cryptonote::transaction> txs;
std::list<crypto::hash> missed_txs;
if (!m_blockchain.get_transactions(block.tx_hashes, txs, missed_txs))
{
LOG_ERROR("Unable to get transactions for block " << block.hash);
return;
}
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
2018-06-29 06:47:00 +02:00
block_added_generic(block, txs);
}
}
m_rollback_events.push_back(std::unique_ptr<rollback_event>(new prevent_rollback(current_height)));
}
std::vector<crypto::public_key> service_node_list::get_service_nodes_pubkeys() const
2018-06-29 06:47:00 +02:00
{
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
std::vector<crypto::public_key> result;
for (const auto& iter : m_service_nodes_infos)
if (iter.second.is_fully_funded())
result.push_back(iter.first);
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
std::sort(result.begin(), result.end(),
[](const crypto::public_key &a, const crypto::public_key &b) {
return memcmp(reinterpret_cast<const void*>(&a), reinterpret_cast<const void*>(&b), sizeof(a)) < 0;
});
return result;
}
const std::shared_ptr<quorum_state> service_node_list::get_quorum_state(uint64_t height) const
{
std::shared_ptr<service_nodes::quorum_state> result;
const auto &it = m_quorum_states.find(height);
if (it == m_quorum_states.end())
{
// TODO(loki): Not being able to find the quorum is going to be a fatal error.
}
else
{
result = it->second;
}
return result;
2018-06-29 06:47:00 +02:00
}
bool service_node_list::is_service_node(const crypto::public_key& pubkey) const
{
return m_service_nodes_infos.find(pubkey) != m_service_nodes_infos.end();
}
bool service_node_list::contribution_tx_output_has_correct_unlock_time(const cryptonote::transaction& tx, size_t i, uint64_t block_height) const
2018-06-29 06:47:00 +02:00
{
uint64_t unlock_time = tx.unlock_time;
if (tx.version >= cryptonote::transaction::version_3_per_output_unlock_times)
unlock_time = tx.output_unlock_times[i];
return unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && unlock_time >= block_height + STAKING_REQUIREMENT_LOCK_BLOCKS;
2018-06-29 06:47:00 +02:00
}
bool service_node_list::reg_tx_extract_fields(const cryptonote::transaction& tx, std::vector<cryptonote::account_public_address>& addresses, uint32_t& portions_for_operator, std::vector<uint32_t>& portions, uint64_t& expiration_timestamp, crypto::public_key& service_node_key, crypto::signature& signature, crypto::public_key& tx_pub_key) const
2018-06-29 06:47:00 +02:00
{
cryptonote::tx_extra_service_node_register registration;
if (!get_service_node_register_from_tx_extra(tx.extra, registration))
return false;
if (!cryptonote::get_service_node_pubkey_from_tx_extra(tx.extra, service_node_key))
return false;
addresses.clear();
addresses.reserve(registration.m_public_spend_keys.size());
for (size_t i = 0; i < registration.m_public_spend_keys.size(); i++)
addresses.push_back(cryptonote::account_public_address{ registration.m_public_spend_keys[i], registration.m_public_view_keys[i] });
portions_for_operator = registration.m_portions_for_operator;
portions = registration.m_portions;
expiration_timestamp = registration.m_expiration_timestamp;
signature = registration.m_service_node_signature;
2018-06-29 06:47:00 +02:00
tx_pub_key = cryptonote::get_tx_pub_key_from_extra(tx.extra);
return true;
2018-06-29 06:47:00 +02:00
}
uint64_t service_node_list::get_reg_tx_staking_output_contribution(const cryptonote::transaction& tx, int i, crypto::key_derivation derivation, hw::device& hwdev) const
2018-06-29 06:47:00 +02:00
{
if (tx.vout[i].target.type() != typeid(cryptonote::txout_to_key))
{
return 0;
2018-06-29 06:47:00 +02:00
}
rct::key mask;
uint64_t money_transferred = 0;
crypto::secret_key scalar1;
hwdev.derivation_to_scalar(derivation, i, scalar1);
try
{
switch (tx.rct_signatures.type)
{
case rct::RCTTypeSimple:
case rct::RCTTypeSimpleBulletproof:
money_transferred = rct::decodeRctSimple(tx.rct_signatures, rct::sk2rct(scalar1), i, mask, hwdev);
break;
case rct::RCTTypeFull:
case rct::RCTTypeFullBulletproof:
money_transferred = rct::decodeRct(tx.rct_signatures, rct::sk2rct(scalar1), i, mask, hwdev);
break;
default:
LOG_PRINT_L0("Unsupported rct type: " << tx.rct_signatures.type);
return 0;
2018-06-29 06:47:00 +02:00
}
}
catch (const std::exception &e)
{
LOG_PRINT_L0("Failed to decode input " << i);
return 0;
2018-06-29 06:47:00 +02:00
}
return money_transferred;
2018-06-29 06:47:00 +02:00
}
void service_node_list::process_deregistration_tx(const cryptonote::transaction& tx, uint64_t block_height)
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
{
if (!tx.is_deregister_tx())
return;
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
cryptonote::tx_extra_service_node_deregister deregister;
if (!cryptonote::get_service_node_deregister_from_tx_extra(tx.extra, deregister))
{
LOG_ERROR("Transaction deregister did not have deregister data in tx extra, possibly corrupt tx in blockchain");
return;
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
}
const std::shared_ptr<quorum_state> state = get_quorum_state(deregister.block_height);
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
if (!state)
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
{
// TODO(loki): Not being able to find a quorum is fatal! We want better caching abilities.
LOG_ERROR("Quorum state for height: " << deregister.block_height << ", was not stored by the daemon");
return;
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
}
if (deregister.service_node_index >= state->nodes_to_test.size())
{
LOG_ERROR("Service node index to vote off has become invalid, quorum rules have changed without a hardfork.");
return;
}
const crypto::public_key& key = state->nodes_to_test[deregister.service_node_index];
auto iter = m_service_nodes_infos.find(key);
if (iter == m_service_nodes_infos.end())
return;
MGINFO("Deregistration for service node: " << key);
m_rollback_events.push_back(std::unique_ptr<rollback_event>(new rollback_change(block_height, key, iter->second)));
m_service_nodes_infos.erase(iter);
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
}
bool service_node_list::is_registration_tx(const cryptonote::transaction& tx, uint64_t block_timestamp, uint64_t block_height, uint32_t index, crypto::public_key& key, service_node_info& info) const
2018-06-29 06:47:00 +02:00
{
crypto::public_key tx_pub_key, service_node_key;
std::vector<cryptonote::account_public_address> service_node_addresses;
std::vector<uint32_t> service_node_portions;
uint32_t portions_for_operator;
uint64_t expiration_timestamp;
crypto::signature signature;
if (!reg_tx_extract_fields(tx, service_node_addresses, portions_for_operator, service_node_portions, expiration_timestamp, service_node_key, signature, tx_pub_key))
return false;
if (service_node_portions.size() != service_node_addresses.size() || service_node_portions.empty())
return false;
2018-08-06 15:08:44 +02:00
// check the portions
uint64_t total = 0;
for (size_t i = 0; i < service_node_portions.size(); i++)
2018-08-06 15:08:44 +02:00
{
if (service_node_portions[i] < MIN_PORTIONS)
return false;
total += service_node_portions[i];
2018-08-06 15:08:44 +02:00
}
if (total > STAKING_PORTIONS)
2018-06-29 06:47:00 +02:00
return false;
if (portions_for_operator > STAKING_PORTIONS)
return false;
2018-08-06 15:08:44 +02:00
// check the signature is all good
crypto::hash hash;
if (!get_registration_hash(service_node_addresses, portions_for_operator, service_node_portions, expiration_timestamp, hash))
return false;
if (!crypto::check_signature(hash, service_node_key, signature))
return false;
if (expiration_timestamp < block_timestamp)
return false;
2018-06-29 06:47:00 +02:00
2018-08-06 15:08:44 +02:00
// check the initial contribution exists
info.staking_requirement = get_staking_requirement(m_blockchain.nettype(), block_height);
2018-08-06 15:08:44 +02:00
cryptonote::account_public_address address;
uint64_t transferred = 0;
if (!get_contribution(tx, block_height, address, transferred))
return false;
if (transferred < info.staking_requirement / MAX_NUMBER_OF_CONTRIBUTORS)
2018-08-06 15:08:44 +02:00
return false;
int is_this_a_new_address = 0;
if (std::find(service_node_addresses.begin(), service_node_addresses.end(), address) == service_node_addresses.end())
is_this_a_new_address = 1;
if (service_node_addresses.size() + is_this_a_new_address > MAX_NUMBER_OF_CONTRIBUTORS)
return false;
2018-08-06 15:08:44 +02:00
// don't actually process this contribution now, do it when we fall through later.
key = service_node_key;
info.operator_address = service_node_addresses[0];
info.portions_for_operator = portions_for_operator;
info.last_reward_block_height = block_height;
info.last_reward_transaction_index = index;
2018-08-06 15:08:44 +02:00
info.total_contributed = 0;
info.total_reserved = 0;
info.contributors.clear();
for (size_t i = 0; i < service_node_addresses.size(); i++)
{
// Check for duplicates
auto iter = std::find(service_node_addresses.begin(), service_node_addresses.begin() + i, service_node_addresses[i]);
if (iter != service_node_addresses.begin() + i)
2018-08-06 15:08:44 +02:00
return false;
uint64_t hi, lo, resulthi, resultlo;
lo = mul128(info.staking_requirement, service_node_portions[i], &hi);
div128_32(hi, lo, STAKING_PORTIONS, &resulthi, &resultlo);
info.contributors.push_back(service_node_info::contribution(resultlo, service_node_addresses[i]));
2018-08-06 15:08:44 +02:00
}
return true;
}
void service_node_list::process_registration_tx(const cryptonote::transaction& tx, uint64_t block_timestamp, uint64_t block_height, uint32_t index)
{
crypto::public_key key;
service_node_info info;
if (!is_registration_tx(tx, block_timestamp, block_height, index, key, info))
return;
auto iter = m_service_nodes_infos.find(key);
if (iter != m_service_nodes_infos.end())
return;
MGINFO("New service node registered: " << key);
m_rollback_events.push_back(std::unique_ptr<rollback_event>(new rollback_new(block_height, key)));
m_service_nodes_infos[key] = info;
}
2018-08-06 15:08:44 +02:00
bool service_node_list::get_contribution(const cryptonote::transaction& tx, uint64_t block_height, cryptonote::account_public_address& address, uint64_t& transferred) const
{
crypto::secret_key tx_key;
if (!cryptonote::get_service_node_contributor_from_tx_extra(tx.extra, address))
return false;
if (!cryptonote::get_tx_secret_key_from_tx_extra(tx.extra, tx_key))
return false;
crypto::key_derivation derivation;
if (!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation))
return false;
hw::device& hwdev = hw::get_device("default");
transferred = 0;
for (size_t i = 0; i < tx.vout.size(); i++)
if (contribution_tx_output_has_correct_unlock_time(tx, i, block_height))
transferred += get_reg_tx_staking_output_contribution(tx, i, derivation, hwdev);
return true;
}
void service_node_list::process_contribution_tx(const cryptonote::transaction& tx, uint64_t block_height, uint32_t index)
{
crypto::public_key pubkey;
cryptonote::account_public_address address;
2018-08-06 15:08:44 +02:00
uint64_t transferred;
if (!cryptonote::get_service_node_pubkey_from_tx_extra(tx.extra, pubkey))
return;
2018-08-06 15:08:44 +02:00
if (!get_contribution(tx, block_height, address, transferred))
2018-08-03 10:34:49 +02:00
return;
auto iter = m_service_nodes_infos.find(pubkey);
if (iter == m_service_nodes_infos.end())
return;
2018-08-06 15:08:44 +02:00
service_node_info& info = iter->second;
if (info.is_fully_funded())
return;
2018-08-06 15:08:44 +02:00
auto& contributors = info.contributors;
// Only create a new contributor if they stake at least a quarter
// and if we don't already have the maximum
auto contrib_iter = std::find_if(contributors.begin(), contributors.end(),
[&address](const service_node_info::contribution& contributor) { return contributor.address == address; });
if (contrib_iter == contributors.end())
{
if (contributors.size() >= MAX_NUMBER_OF_CONTRIBUTORS || transferred < info.get_min_contribution())
return;
}
2018-06-29 06:47:00 +02:00
2018-08-06 15:08:44 +02:00
m_rollback_events.push_back(std::unique_ptr<rollback_event>(new rollback_change(block_height, pubkey, info)));
2018-06-29 06:47:00 +02:00
if (contrib_iter == contributors.end())
{
contributors.push_back(service_node_info::contribution(0, address));
contrib_iter = --contributors.end();
}
2018-06-29 06:47:00 +02:00
service_node_info::contribution& contributor = *contrib_iter;
2018-06-29 06:47:00 +02:00
2018-08-06 15:08:44 +02:00
// In this action, we cannot
// increase total_reserved so much that it is >= staking_requirement
uint64_t can_increase_reserved_by = info.staking_requirement - info.total_reserved;
uint64_t max_amount = contributor.reserved + can_increase_reserved_by;
transferred = std::min(max_amount - contributor.amount, transferred);
2018-06-29 06:47:00 +02:00
2018-08-06 15:08:44 +02:00
contributor.amount += transferred;
info.total_contributed += transferred;
if (contributor.amount > contributor.reserved)
{
info.total_reserved += contributor.amount - contributor.reserved;
contributor.reserved = contributor.amount;
}
2018-06-29 06:47:00 +02:00
iter->second.last_reward_block_height = block_height;
iter->second.last_reward_transaction_index = index;
MGINFO("Contribution of " << transferred << " received for service node " << pubkey);
return;
}
2018-06-29 06:47:00 +02:00
void service_node_list::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs)
{
block_added_generic(block, txs);
store();
2018-06-29 06:47:00 +02:00
}
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
2018-06-29 06:47:00 +02:00
template<typename T>
void service_node_list::block_added_generic(const cryptonote::block& block, const T& txs)
{
uint64_t block_height = cryptonote::get_block_height(block);
int hard_fork_version = m_blockchain.get_hard_fork_version(block_height);
assert(m_height == block_height);
m_height++;
if (hard_fork_version < 9)
2018-06-29 06:47:00 +02:00
return;
while (!m_rollback_events.empty() && m_rollback_events.front()->m_block_height < block_height - ROLLBACK_EVENT_EXPIRATION_BLOCKS)
{
m_rollback_events.pop_front();
}
for (const crypto::public_key& pubkey : get_expired_nodes(block_height))
{
auto i = m_service_nodes_infos.find(pubkey);
if (i != m_service_nodes_infos.end())
{
m_rollback_events.push_back(std::unique_ptr<rollback_event>(new rollback_change(block_height, pubkey, i->second)));
m_service_nodes_infos.erase(i);
}
// Service nodes may expire early if they double staked by accident, so
// expiration doesn't mean the node is in the list.
}
crypto::public_key winner_pubkey = cryptonote::get_service_node_winner_from_tx_extra(block.miner_tx.extra);
if (m_service_nodes_infos.count(winner_pubkey) == 1)
2018-06-29 06:47:00 +02:00
{
m_rollback_events.push_back(
std::unique_ptr<rollback_event>(
new rollback_change(block_height, winner_pubkey, m_service_nodes_infos[winner_pubkey])
2018-06-29 06:47:00 +02:00
)
);
// set the winner as though it was re-registering at transaction index=UINT32_MAX for this block
m_service_nodes_infos[winner_pubkey].last_reward_block_height = block_height;
m_service_nodes_infos[winner_pubkey].last_reward_transaction_index = UINT32_MAX;
2018-06-29 06:47:00 +02:00
}
uint32_t index = 0;
2018-06-29 06:47:00 +02:00
for (const cryptonote::transaction& tx : txs)
{
crypto::public_key key;
service_node_info info;
cryptonote::account_public_address address;
process_registration_tx(tx, block.timestamp, block_height, index);
process_contribution_tx(tx, block_height, index);
process_deregistration_tx(tx, block_height);
2018-06-29 06:47:00 +02:00
index++;
}
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
const uint64_t curr_height = m_blockchain.get_current_blockchain_height();
const size_t QUORUM_LIFETIME = loki::service_node_deregister::DEREGISTER_LIFETIME_BY_HEIGHT;
const size_t cache_state_from_height = (curr_height < QUORUM_LIFETIME) ? 0 : curr_height - QUORUM_LIFETIME;
if (block_height >= cache_state_from_height)
{
store_quorum_state_from_rewards_list(block_height);
while (!m_quorum_states.empty() && m_quorum_states.begin()->first < cache_state_from_height)
{
m_quorum_states.erase(m_quorum_states.begin());
}
}
2018-06-29 06:47:00 +02:00
}
void service_node_list::blockchain_detached(uint64_t height)
{
m_height = height;
2018-06-29 06:47:00 +02:00
while (!m_rollback_events.empty() && m_rollback_events.back()->m_block_height >= height)
{
if (!m_rollback_events.back()->apply(m_service_nodes_infos))
2018-06-29 06:47:00 +02:00
{
init();
break;
}
m_rollback_events.pop_back();
}
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
while (!m_quorum_states.empty() && (--m_quorum_states.end())->first >= height)
{
m_quorum_states.erase(--m_quorum_states.end());
}
store();
2018-06-29 06:47:00 +02:00
}
std::vector<crypto::public_key> service_node_list::get_expired_nodes(uint64_t block_height) const
2018-06-29 06:47:00 +02:00
{
std::vector<crypto::public_key> expired_nodes;
2018-06-29 06:47:00 +02:00
if (block_height < STAKING_REQUIREMENT_LOCK_BLOCKS + STAKING_RELOCK_WINDOW_BLOCKS)
return expired_nodes;
const uint64_t expired_nodes_block_height = block_height - STAKING_REQUIREMENT_LOCK_BLOCKS - STAKING_RELOCK_WINDOW_BLOCKS;
std::list<std::pair<cryptonote::blobdata, cryptonote::block>> blocks;
if (!m_blockchain.get_blocks(expired_nodes_block_height, 1, blocks))
{
LOG_ERROR("Unable to get historical blocks");
return expired_nodes;
}
const cryptonote::block& block = blocks.begin()->second;
std::list<cryptonote::transaction> txs;
std::list<crypto::hash> missed_txs;
if (!m_blockchain.get_transactions(block.tx_hashes, txs, missed_txs))
{
LOG_ERROR("Unable to get transactions for block " << block.hash);
return expired_nodes;
}
uint32_t index = 0;
2018-06-29 06:47:00 +02:00
for (const cryptonote::transaction& tx : txs)
{
crypto::public_key key;
service_node_info info;
if (is_registration_tx(tx, block.timestamp, expired_nodes_block_height, index, key, info))
2018-06-29 06:47:00 +02:00
{
expired_nodes.push_back(key);
2018-06-29 06:47:00 +02:00
}
index++;
2018-06-29 06:47:00 +02:00
}
return expired_nodes;
}
std::vector<std::pair<cryptonote::account_public_address, uint32_t>> service_node_list::get_winner_addresses_and_portions(const crypto::hash& prev_id) const
{
crypto::public_key key = select_winner(prev_id);
if (key == crypto::null_pkey)
return { std::make_pair(null_address, STAKING_PORTIONS) };
2018-08-06 15:08:44 +02:00
std::vector<std::pair<cryptonote::account_public_address, uint32_t>> winners;
2018-08-06 15:08:44 +02:00
const service_node_info& info = m_service_nodes_infos.at(key);
const uint64_t remaining_portions = STAKING_PORTIONS - info.portions_for_operator;
2018-08-06 15:08:44 +02:00
// Add contributors and their portions to winners.
for (const auto& contributor : info.contributors)
2018-08-06 15:08:44 +02:00
{
uint64_t hi, lo, resulthi, resultlo;
lo = mul128(contributor.amount, remaining_portions, &hi);
2018-08-06 15:08:44 +02:00
div128_64(hi, lo, info.staking_requirement, &resulthi, &resultlo);
if (contributor.address == info.operator_address)
resultlo += info.portions_for_operator;
winners.push_back(std::make_pair(contributor.address, resultlo));
}
return winners;
}
crypto::public_key service_node_list::select_winner(const crypto::hash& prev_id) const
2018-06-29 06:47:00 +02:00
{
auto oldest_waiting = std::pair<uint64_t, uint32_t>(std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint32_t>::max());
crypto::public_key key = crypto::null_pkey;
for (const auto& info : m_service_nodes_infos)
if (info.second.is_fully_funded())
2018-06-29 06:47:00 +02:00
{
auto waiting_since = std::make_pair(info.second.last_reward_block_height, info.second.last_reward_transaction_index);
if (waiting_since < oldest_waiting)
{
oldest_waiting = waiting_since;
key = info.first;
}
2018-06-29 06:47:00 +02:00
}
return key;
2018-06-29 06:47:00 +02:00
}
/// validates the miner TX for the next block
//
bool service_node_list::validate_miner_tx(const crypto::hash& prev_id, const cryptonote::transaction& miner_tx, uint64_t height, int hard_fork_version, uint64_t base_reward)
{
if (hard_fork_version < 9)
2018-06-29 06:47:00 +02:00
return true;
uint64_t total_service_node_reward = cryptonote::get_service_node_reward(height, base_reward, hard_fork_version);
2018-06-29 06:47:00 +02:00
crypto::public_key winner = select_winner(prev_id);
crypto::public_key check_winner_pubkey = cryptonote::get_service_node_winner_from_tx_extra(miner_tx.extra);
if (check_winner_pubkey != winner)
2018-06-29 06:47:00 +02:00
return false;
const std::vector<std::pair<cryptonote::account_public_address, uint32_t>> addresses_and_portions = get_winner_addresses_and_portions(prev_id);
if (miner_tx.vout.size() - 1 < addresses_and_portions.size())
2018-06-29 06:47:00 +02:00
return false;
for (size_t i = 0; i < addresses_and_portions.size(); i++)
2018-06-29 06:47:00 +02:00
{
size_t vout_index = miner_tx.vout.size() - 1 /* governance */ - addresses_and_portions.size() + i;
2018-06-29 06:47:00 +02:00
uint64_t reward = cryptonote::get_portion_of_reward(addresses_and_portions[i].second, total_service_node_reward);
2018-06-29 06:47:00 +02:00
if (miner_tx.vout[vout_index].amount != reward)
{
MERROR("Service node reward amount incorrect. Should be " << cryptonote::print_money(reward) << ", is: " << cryptonote::print_money(miner_tx.vout[vout_index].amount));
return false;
}
2018-06-29 06:47:00 +02:00
if (miner_tx.vout[vout_index].target.type() != typeid(cryptonote::txout_to_key))
{
MERROR("Service node output target type should be txout_to_key");
return false;
}
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);;
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
cryptonote::keypair gov_key = cryptonote::get_deterministic_keypair_from_height(height);
bool r = crypto::generate_key_derivation(addresses_and_portions[i].first.m_view_public_key, gov_key.sec, derivation);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << addresses_and_portions[i].first.m_view_public_key << ", " << gov_key.sec << ")");
r = crypto::derive_public_key(derivation, vout_index, addresses_and_portions[i].first.m_spend_public_key, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << vout_index << ", "<< addresses_and_portions[i].first.m_spend_public_key << ")");
if (boost::get<cryptonote::txout_to_key>(miner_tx.vout[vout_index].target).key != out_eph_public_key)
{
MERROR("Invalid service node reward output");
return false;
}
2018-06-29 06:47:00 +02:00
}
return true;
}
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
void service_node_list::store_quorum_state_from_rewards_list(uint64_t height)
{
const crypto::hash block_hash = m_blockchain.get_block_id_by_height(height);
if (block_hash == crypto::null_hash)
{
MERROR("Block height: " << height << " returned null hash");
return;
}
std::vector<crypto::public_key> full_node_list = get_service_nodes_pubkeys();
Service Node Deregister Part 5 (#89) * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * core, service_node_list: separated address from service node pubkey * Retrieve quorum list from height, reviewed * Setup data structures for de/register TX * Submit and validate partial/full deregisters * Add P2P relaying of partial deregistration votes * Code review adjustments for deregistration part 1 - Fix check_tx_semantic - Remove signature_pod as votes are now stored as blobs. Serialization overrides don't intefere with crypto::signature anymore. * deregistration_vote_pool - changed sign/verify interface and removed repeated code * Misc review, fix sign/verify api, vote threshold * Deregister/tx edge case handling for combinatoric votes * Store service node lists for the duration of deregister lifetimes * Quorum min/max bug, sort node list, fix node to test list * Change quorum to store acc pub address, fix oob bug * Code review for expiring votes, acc keys to pub_key, improve err msgs * Add early out for is_deregistration_tx and protect against quorum changes * Remove debug code, fix segfault * Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states Incorrect assumption that a transaction can be kept in the chain if it could eventually become invalid, because if it were the chain would be split and eventually these transaction would be dropped. But also that we should not override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
std::vector<size_t> pub_keys_indexes(full_node_list.size());
{
size_t index = 0;
for (size_t i = 0; i < full_node_list.size(); i++) { pub_keys_indexes[i] = i; }
// Shuffle indexes
uint64_t seed = 0;
std::memcpy(&seed, block_hash.data, std::min(sizeof(seed), sizeof(block_hash.data)));
std::mt19937_64 mersenne_twister(seed);
std::shuffle(pub_keys_indexes.begin(), pub_keys_indexes.end(), mersenne_twister);
}
// Assign indexes from shuffled list into quorum and list of nodes to test
if (!m_quorum_states[height])
m_quorum_states[height] = std::shared_ptr<quorum_state>(new quorum_state());
std::shared_ptr<quorum_state> state = m_quorum_states[height];
state->clear();
{
std::vector<crypto::public_key>& quorum = state->quorum_nodes;
{
quorum.clear();
quorum.resize(std::min(full_node_list.size(), QUORUM_SIZE));
for (size_t i = 0; i < quorum.size(); i++)
{
size_t node_index = pub_keys_indexes[i];
const crypto::public_key &key = full_node_list[node_index];
quorum[i] = key;
}
}
std::vector<crypto::public_key>& nodes_to_test = state->nodes_to_test;
{
size_t num_remaining_nodes = pub_keys_indexes.size() - quorum.size();
size_t num_nodes_to_test = std::max(num_remaining_nodes/NTH_OF_THE_NETWORK_TO_TEST,
std::min(MIN_NODES_TO_TEST, num_remaining_nodes));
nodes_to_test.clear();
nodes_to_test.resize(num_nodes_to_test);
const int pub_keys_offset = quorum.size();
for (size_t i = 0; i < nodes_to_test.size(); i++)
{
size_t node_index = pub_keys_indexes[pub_keys_offset + i];
const crypto::public_key &key = full_node_list[node_index];
nodes_to_test[i] = key;
}
}
}
}
2018-06-29 06:47:00 +02:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
service_node_list::rollback_event::rollback_event(uint64_t block_height) : m_block_height(block_height)
{
}
service_node_list::rollback_change::rollback_change(uint64_t block_height, const crypto::public_key& key, const service_node_info& info)
: service_node_list::rollback_event(block_height), m_key(key), m_info(info)
2018-06-29 06:47:00 +02:00
{
}
bool service_node_list::rollback_change::apply(std::unordered_map<crypto::public_key, service_node_info>& service_nodes_infos) const
2018-06-29 06:47:00 +02:00
{
service_nodes_infos[m_key] = m_info;
2018-06-29 06:47:00 +02:00
return true;
}
service_node_list::rollback_new::rollback_new(uint64_t block_height, const crypto::public_key& key)
: service_node_list::rollback_event(block_height), m_key(key)
2018-06-29 06:47:00 +02:00
{
}
bool service_node_list::rollback_new::apply(std::unordered_map<crypto::public_key, service_node_info>& service_nodes_infos) const
2018-06-29 06:47:00 +02:00
{
auto iter = service_nodes_infos.find(m_key);
if (iter == service_nodes_infos.end())
{
MERROR("Could not find service node pubkey in rollback new");
return false;
}
service_nodes_infos.erase(iter);
2018-06-29 06:47:00 +02:00
return true;
}
service_node_list::prevent_rollback::prevent_rollback(uint64_t block_height) : service_node_list::rollback_event(block_height)
{
}
bool service_node_list::prevent_rollback::apply(std::unordered_map<crypto::public_key, service_node_info>& service_nodes_infos) const
2018-06-29 06:47:00 +02:00
{
MERROR("Unable to rollback any further!");
return false;
}
bool service_node_list::store()
{
if (!m_db)
{
return false;
}
data_members_for_serialization data_to_store;
node_info_for_serialization info;
for (const auto& kv_pair : m_service_nodes_infos)
{
info.key = kv_pair.first;
info.info = kv_pair.second;
data_to_store.infos.push_back(info);
}
rollback_event_variant event;
for (const auto& event_ptr : m_rollback_events)
{
switch (event_ptr->type)
{
case rollback_event::change_type:
event = *reinterpret_cast<rollback_change *>(event_ptr.get());
data_to_store.events.push_back(*reinterpret_cast<rollback_change *>(event_ptr.get()));
break;
case rollback_event::new_type:
event = *reinterpret_cast<rollback_new *>(event_ptr.get());
data_to_store.events.push_back(*reinterpret_cast<rollback_new *>(event_ptr.get()));
break;
case rollback_event::prevent_type:
event = *reinterpret_cast<prevent_rollback *>(event_ptr.get());
data_to_store.events.push_back(*reinterpret_cast<prevent_rollback *>(event_ptr.get()));
break;
default:
return false;
}
}
data_to_store.height = m_height;
std::stringstream ss;
binary_archive<true> ba(ss);
bool r = ::serialization::serialize(ba, data_to_store);
if (!r) return false;
std::string blob = ss.str();
m_db->block_txn_start(false/*readonly*/);
m_db->set_service_node_data(blob);
m_db->block_txn_stop();
return true;
}
bool service_node_list::load()
{
clear(false);
if (!m_db)
{
return false;
}
std::stringstream ss;
data_members_for_serialization data_in;
std::string blob;
m_db->block_txn_start(true/*readonly*/);
if (!m_db->get_service_node_data(blob))
{
m_db->block_txn_stop();
return false;
}
m_db->block_txn_stop();
ss << blob;
binary_archive<false> ba(ss);
bool r = ::serialization::serialize(ba, data_in);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse service node data from blob");
m_height = data_in.height;
for (const auto& info : data_in.infos)
{
m_service_nodes_infos[info.key] = info.info;
}
for (const auto& event : data_in.events)
{
if (event.type() == typeid(rollback_change))
{
rollback_change *i = new rollback_change();
const rollback_change& from = boost::get<rollback_change>(event);
i->m_block_height = from.m_block_height;
i->m_key = from.m_key;
i->m_info = from.m_info;
i->type = rollback_event::change_type;
m_rollback_events.push_back(std::unique_ptr<rollback_event>(i));
break;
}
else if (event.type() == typeid(rollback_new))
{
rollback_new *i = new rollback_new();
const rollback_new& from = boost::get<rollback_new>(event);
i->m_block_height = from.m_block_height;
i->m_key = from.m_key;
i->type = rollback_event::change_type;
m_rollback_events.push_back(std::unique_ptr<rollback_event>(i));
break;
}
else if (event.type() == typeid(prevent_rollback))
{
prevent_rollback *i = new prevent_rollback();
const prevent_rollback& from = boost::get<prevent_rollback>(event);
i->m_block_height = from.m_block_height;
i->type = rollback_event::change_type;
m_rollback_events.push_back(std::unique_ptr<rollback_event>(i));
break;
}
else
{
return false;
}
}
return true;
}
void service_node_list::clear(bool delete_db_entry)
{
m_service_nodes_infos.clear();
m_rollback_events.clear();
if (m_db && delete_db_entry)
{
m_db->block_txn_start(false/*readonly*/);
m_db->clear_service_node_data();
m_db->block_txn_stop();
}
// not currently done in init(), so maybe don't?
m_quorum_states.clear();
m_height = 0;
}
bool convert_registration_args(cryptonote::network_type nettype, const std::vector<std::string>& args, std::vector<cryptonote::account_public_address>& addresses, std::vector<uint32_t>& portions, uint32_t& portions_for_operator, uint64_t& initial_contribution)
{
if (args.size() % 2 == 1)
{
MERROR(tr("Expected an even number of arguments: <operator cut> <address> <fraction> [<address> <fraction> [...]]] <initial contribution>"));
return false;
}
if (args.size() < 4)
{
MERROR(tr("Usage: <operator cut> <address> <fraction> [<address> <fraction> [...]]] <initial contribution>"));
return false;
}
if ((args.size()-2)/ 2 > MAX_NUMBER_OF_CONTRIBUTORS)
{
MERROR(tr("Exceeds the maximum number of contributors, which is ") << MAX_NUMBER_OF_CONTRIBUTORS);
return false;
}
addresses.clear();
portions.clear();
try
{
double portion_fraction = boost::lexical_cast<double>(args[0]);
if (portion_fraction < 0 || portion_fraction > 1)
{
MERROR(tr("Invalid portion amount: ") << args[0] << tr(". ") << tr("Must be between 0 and 1"));
return false;
}
portions_for_operator = STAKING_PORTIONS * portion_fraction;
}
catch (const std::exception &e)
{
MERROR(tr("Invalid portion amount: ") << args[0] << tr(". ") << tr("Must be between 0 and 1"));
return false;
}
uint64_t total_portions = 0;
for (size_t i = 1; i < args.size()-1; i += 2)
{
cryptonote::address_parse_info info;
if (!cryptonote::get_account_address_from_str(info, nettype, args[i]))
{
MERROR(tr("failed to parse address"));
return false;
}
if (info.has_payment_id)
{
MERROR(tr("can't use a payment id for staking tx"));
return false;
}
if (info.is_subaddress)
{
MERROR(tr("can't use a subaddress for staking tx"));
return false;
}
addresses.push_back(info.address);
try
{
double portion_fraction = boost::lexical_cast<double>(args[i+1]);
if (portion_fraction < 1.0 / MAX_NUMBER_OF_CONTRIBUTORS || portion_fraction > 1)
{
MERROR(tr("Invalid portion amount: ") << args[i+1] << tr(". ") << tr("Must be at least ") << (1.0 / MAX_NUMBER_OF_CONTRIBUTORS) << " and no more than 1");
return false;
}
uint32_t num_portions = STAKING_PORTIONS * portion_fraction;
portions.push_back(num_portions);
total_portions += num_portions;
}
catch (const std::exception &e)
{
MERROR(tr("Invalid portion amount: ") << args[i+1] << tr(". ") << tr("Must be at least ") << (1.0 / MAX_NUMBER_OF_CONTRIBUTORS) << " and no more than 1");
return false;
}
}
if (!cryptonote::parse_amount(initial_contribution, args.back()) || initial_contribution == 0)
{
MERROR(tr("amount is wrong: ") << args.back() <<
", " << tr("expected number from ") << cryptonote::print_money(1) <<
" to " << cryptonote::print_money(std::numeric_limits<uint64_t>::max()));
return true;
}
if (total_portions > (uint64_t)STAKING_PORTIONS)
{
MERROR(tr("Invalid portion amounts, portions must sum to at most 1."));
MERROR(tr("If it looks correct, this may be because of rounding. Try reducing one of the portionholders portions by a very tiny amount"));
return false;
}
return true;
}
bool make_registration_cmd(cryptonote::network_type nettype, const std::vector<std::string> args, const crypto::public_key& service_node_pubkey,
const crypto::secret_key service_node_key, std::string &cmd, bool make_friendly)
{
std::vector<cryptonote::account_public_address> addresses;
std::vector<uint32_t> portions;
uint64_t initial_contribution;
uint32_t operator_portions;
if (!convert_registration_args(nettype, args, addresses, portions, operator_portions, initial_contribution))
{
MERROR(tr("Could not convert registration args"));
return false;
}
uint64_t exp_timestamp = time(nullptr) + STAKING_AUTHORIZATION_EXPIRATION_WINDOW;
crypto::hash hash;
bool hashed = cryptonote::get_registration_hash(addresses, operator_portions, portions, exp_timestamp, hash);
if (!hashed)
{
MERROR(tr("Could not make registration hash from addresses and portions"));
return false;
}
crypto::signature signature;
crypto::generate_signature(hash, service_node_pubkey, service_node_key, signature);
std::stringstream stream;
if (make_friendly)
{
stream << tr("Run this command in the wallet that will fund this registration:\n\n");
}
stream << "register_service_node";
for (size_t i = 0; i < args.size(); ++i)
{
stream << " " << args[i];
}
stream << " " << exp_timestamp << " ";
stream << epee::string_tools::pod_to_hex(service_node_pubkey) << " ";
stream << epee::string_tools::pod_to_hex(signature);
if (make_friendly)
{
stream << "\n\n";
time_t tt = exp_timestamp;
struct tm tm;
#ifdef WIN32
gmtime_s(&tm, &tt);
#else
gmtime_r(&tt, &tm);
#endif
char buffer[128];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %I:%M:%S %p", &tm);
stream << tr("This registration expires at ") << buffer << tr(". This should be in about 2 weeks. If it isn't, check this computer's clock") << std::endl;
stream << tr("Please submit your registration into the blockchain before this time or it will be invalid.");
}
cmd = stream.str();
return true;
}
uint64_t get_staking_requirement(cryptonote::network_type m_nettype, uint64_t height)
{
if (m_nettype == cryptonote::TESTNET)
return COIN * 100;
uint64_t height_adjusted = height-129600;
uint64_t base = 10000 * COIN;
uint64_t variable = (35000.0 * COIN) / loki_exp2(height_adjusted/129600.0);
uint64_t linear_up = 5 * COIN * height / 2592;
uint64_t flat = 15000 * COIN;
return std::max(base + variable, height < 3628800 ? linear_up : flat);
}
2018-06-29 06:47:00 +02:00
}