oxen-core/src/cryptonote_core/service_node_list.cpp

1310 lines
46 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
{
uint64_t service_node_info::get_min_contribution() const
{
uint64_t result = get_min_node_contribution(staking_requirement, total_reserved);
return result;
}
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), m_height(0), m_db(nullptr), m_service_node_pubkey(nullptr)
2018-06-29 06:47:00 +02:00
{
}
void service_node_list::register_hooks(service_nodes::quorum_cop &quorum_cop)
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
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_init(quorum_cop);
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()
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
if (m_blockchain.get_current_hard_fork_version() < 9)
{
clear(true);
return;
}
uint64_t current_height = m_blockchain.get_current_blockchain_height();
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);
LOG_PRINT_L0("Recalculating service nodes list, scanning blockchain from height " << m_height);
LOG_PRINT_L0("This may take some time...");
std::vector<std::pair<cryptonote::blobdata, cryptonote::block>> blocks;
while (m_height < current_height)
2018-06-29 06:47:00 +02:00
{
blocks.clear();
if (!m_blockchain.get_blocks(m_height, 1000, blocks))
2018-06-29 06:47:00 +02:00
{
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
std::vector<cryptonote::transaction> txs;
std::vector<crypto::hash> missed_txs;
2018-06-29 06:47:00 +02:00
for (const auto& block_pair : blocks)
{
txs.clear();
missed_txs.clear();
2018-06-29 06:47:00 +02:00
const cryptonote::block& block = block_pair.second;
std::vector<cryptonote::transaction> txs;
std::vector<crypto::hash> missed_txs;
2018-06-29 06:47:00 +02:00
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);
}
}
}
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<const quorum_state> service_node_list::get_quorum_state(uint64_t height) const
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::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
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 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
{
return it->second;
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
}
return std::make_shared<quorum_state>();
2018-06-29 06:47:00 +02:00
}
std::vector<service_node_pubkey_info> service_node_list::get_service_node_list_state(const std::vector<crypto::public_key> &service_node_pubkeys) const
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
std::vector<service_node_pubkey_info> result;
if (service_node_pubkeys.empty())
{
result.reserve(m_service_nodes_infos.size());
for (const auto &it : m_service_nodes_infos)
{
service_node_pubkey_info entry = {};
entry.pubkey = it.first;
entry.info = it.second;
result.push_back(entry);
}
}
else
{
result.reserve(service_node_pubkeys.size());
for (const auto &it : service_node_pubkeys)
{
const auto &find_it = m_service_nodes_infos.find(it);
if (find_it == m_service_nodes_infos.end())
continue;
service_node_pubkey_info entry = {};
entry.pubkey = (*find_it).first;
entry.info = (*find_it).second;
result.push_back(entry);
}
}
return result;
}
void service_node_list::set_db_pointer(cryptonote::BlockchainDB* db)
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
m_db = db;
}
void service_node_list::set_my_service_node_keys(crypto::public_key const *pub_key)
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
m_service_node_pubkey = pub_key;
}
bool service_node_list::is_service_node(const crypto::public_key& pubkey) const
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
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];
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * core_tests: check service node registration and deregistration * core_tests for service nodes: - include service nodes rewards when calculating account's balance - check that service nodes rewards have been received * fixed namespace error; reduced the scope of staking requirement constants * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
return unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && unlock_time >= block_height + get_staking_requirement_lock_blocks(m_blockchain.nettype());
2018-06-29 06:47:00 +02:00
}
bool reg_tx_extract_fields(const cryptonote::transaction& tx, std::vector<cryptonote::account_public_address>& addresses, uint64_t& portions_for_operator, std::vector<uint64_t>& portions, uint64_t& expiration_timestamp, crypto::public_key& service_node_key, crypto::signature& signature, crypto::public_key& tx_pub_key)
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 get_reg_tx_staking_output_contribution(const cryptonote::transaction& tx, int i, crypto::key_derivation derivation, hw::device& hwdev)
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::RCTTypeBulletproof:
2018-06-29 06:47:00 +02:00
money_transferred = rct::decodeRctSimple(tx.rct_signatures, rct::sk2rct(scalar1), i, mask, hwdev);
break;
case rct::RCTTypeFull:
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 auto 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;
if (m_service_node_pubkey && *m_service_node_pubkey == key)
{
MGINFO_RED("Deregistration for service node (yours): " << key);
}
else
{
LOG_PRINT_L1("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 check_service_node_portions(const std::vector<uint64_t>& portions)
{
uint64_t portions_left = STAKING_PORTIONS;
for (const auto portion : portions) {
const uint64_t min_portions = std::min(portions_left, MIN_PORTIONS);
if (portion < min_portions || portion > portions_left) return false;
portions_left -= portion;
}
return true;
}
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<uint64_t> service_node_portions;
uint64_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
if (!check_service_node_portions(service_node_portions)) return false;
2018-06-29 06:47:00 +02:00
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_key(service_node_key) || !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.registration_height = block_height;
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_64(hi, lo, STAKING_PORTIONS, &resulthi, &resultlo);
info.contributors.push_back(service_node_info::contribution(resultlo, service_node_addresses[i]));
info.total_reserved += resultlo;
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;
// NOTE: A node doesn't expire until registration_height + lock blocks excess now which acts as the grace period
// So it is possible to find the node still in our list.
bool registered_during_grace_period = false;
const auto iter = m_service_nodes_infos.find(key);
if (iter != m_service_nodes_infos.end())
{
int hard_fork_version = m_blockchain.get_hard_fork_version(block_height);
if (hard_fork_version >= cryptonote::Blockchain::version_10_swarms)
{
service_node_info const &old_info = iter->second;
uint64_t expiry_height = old_info.registration_height + get_staking_requirement_lock_blocks(m_blockchain.nettype());
if (block_height < expiry_height)
return;
// NOTE: Node preserves its position in list if it reregisters during grace period.
registered_during_grace_period = true;
info.last_reward_block_height = old_info.last_reward_block_height;
info.last_reward_transaction_index = old_info.last_reward_transaction_index;
}
else
{
return;
}
}
if (m_service_node_pubkey && *m_service_node_pubkey == key)
{
if (registered_during_grace_period)
{
MGINFO_GREEN("Service node re-registered (yours): " << key << " at block height: " << block_height);
}
else
{
MGINFO_GREEN("Service node registered (yours): " << key << " at block height: " << block_height);
}
}
else
{
LOG_PRINT_L1("New service node registered: " << key << " at block height: " << block_height);
}
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;
LOG_PRINT_L1("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)
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
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);
if (hard_fork_version < 9)
2018-06-29 06:47:00 +02:00
return;
assert(m_height == block_height);
m_height++;
2018-06-29 06:47:00 +02:00
{
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * core_tests: check service node registration and deregistration * core_tests for service nodes: - include service nodes rewards when calculating account's balance - check that service nodes rewards have been received * fixed namespace error; reduced the scope of staking requirement constants * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
const size_t ROLLBACK_EVENT_EXPIRATION_BLOCKS = 30;
uint64_t cull_height = (block_height < ROLLBACK_EVENT_EXPIRATION_BLOCKS) ? block_height : block_height - ROLLBACK_EVENT_EXPIRATION_BLOCKS;
while (!m_rollback_events.empty() && m_rollback_events.front()->m_block_height < cull_height)
{
m_rollback_events.pop_front();
}
m_rollback_events.push_front(std::unique_ptr<rollback_event>(new prevent_rollback(cull_height)));
2018-06-29 06:47:00 +02:00
}
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())
{
if (m_service_node_pubkey && *m_service_node_pubkey == pubkey)
{
MGINFO_GREEN("Service node expired (yours): " << pubkey << " at block height: " << block_height);
}
else
{
LOG_PRINT_L1("Service node expired: " << pubkey << " at block height: " << block_height);
}
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
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * core_tests: check service node registration and deregistration * core_tests for service nodes: - include service nodes rewards when calculating account's balance - check that service nodes rewards have been received * fixed namespace error; reduced the scope of staking requirement constants * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
const size_t QUORUM_LIFETIME = (6 * loki::service_node_deregister::DEREGISTER_LIFETIME_BY_HEIGHT);
// save six times the quorum lifetime, to be sure. also to help with debugging.
const size_t cache_state_from_height = (block_height < QUORUM_LIFETIME) ? 0 : block_height - QUORUM_LIFETIME;
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
store_quorum_state_from_rewards_list(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
while (!m_quorum_states.empty() && m_quorum_states.begin()->first < cache_state_from_height)
{
m_quorum_states.erase(m_quorum_states.begin());
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
}
void service_node_list::blockchain_detached(uint64_t height)
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
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());
}
m_height = height;
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;
int hard_fork_version = m_blockchain.get_hard_fork_version(block_height);
2018-06-29 06:47:00 +02:00
uint64_t lock_blocks = get_staking_requirement_lock_blocks(m_blockchain.nettype());
if (hard_fork_version >= cryptonote::Blockchain::version_10_swarms)
lock_blocks += STAKING_REQUIREMENT_LOCK_BLOCKS_EXCESS;
if (block_height < lock_blocks)
2018-06-29 06:47:00 +02:00
return expired_nodes;
if (hard_fork_version >= cryptonote::Blockchain::version_10_swarms)
2018-06-29 06:47:00 +02:00
{
for (auto &it : m_service_nodes_infos)
{
crypto::public_key const &pubkey = it.first;
service_node_info const &info = it.second;
2018-06-29 06:47:00 +02:00
uint64_t node_expiry_height = info.registration_height + lock_blocks;
if (block_height > node_expiry_height)
{
expired_nodes.push_back(pubkey);
}
}
2018-06-29 06:47:00 +02:00
}
else
2018-06-29 06:47:00 +02:00
{
const uint64_t expired_nodes_block_height = block_height - lock_blocks;
std::vector<std::pair<cryptonote::blobdata, cryptonote::block>> blocks;
if (!m_blockchain.get_blocks(expired_nodes_block_height, 1, blocks))
2018-06-29 06:47:00 +02:00
{
LOG_ERROR("Unable to get historical blocks");
return expired_nodes;
}
const cryptonote::block& block = blocks.begin()->second;
std::vector<cryptonote::transaction> txs;
std::vector<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;
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))
{
expired_nodes.push_back(key);
}
index++;
2018-06-29 06:47:00 +02:00
}
}
return expired_nodes;
}
std::vector<std::pair<cryptonote::account_public_address, uint64_t>> service_node_list::get_winner_addresses_and_portions(const crypto::hash& prev_id) const
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
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, uint64_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
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
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) const
2018-06-29 06:47:00 +02:00
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
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, uint64_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;
}
static uint64_t uniform_distribution_portable(std::mt19937_64& mersenne_twister, uint64_t n)
{
uint64_t secureMax = mersenne_twister.max() - mersenne_twister.max() % n;
uint64_t x;
do x = mersenne_twister(); while (x >= secureMax);
return x / (secureMax / n);
}
void loki_shuffle(std::vector<size_t>& a, uint64_t seed)
{
if (a.size() <= 1) return;
std::mt19937_64 mersenne_twister(seed);
for (size_t i = 1; i < a.size(); i++)
{
size_t j = (size_t)uniform_distribution_portable(mersenne_twister, i+1);
if (i != j)
std::swap(a[i], a[j]);
}
}
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)));
loki_shuffle(pub_keys_indexes, seed);
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
}
// Assign indexes from shuffled list into quorum and list of nodes to test
auto new_state = std::make_shared<quorum_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
{
std::vector<crypto::public_key>& quorum = new_state->quorum_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
{
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 = new_state->nodes_to_test;
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
{
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.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;
}
}
}
m_quorum_states[height] = new_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
}
2018-06-29 06:47:00 +02:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
service_node_list::rollback_event::rollback_event(uint64_t block_height, rollback_type type) : m_block_height(block_height), type(type)
2018-06-29 06:47:00 +02:00
{
}
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, change_type), 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, new_type), 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, prevent_type)
2018-06-29 06:47:00 +02:00
{
}
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()
{
CHECK_AND_ASSERT_MES(m_db != nullptr, false, "Failed to store service node info, m_db == nullptr");
data_members_for_serialization data_to_store;
{
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
quorum_state_for_serialization quorum;
for(const auto& kv_pair : m_quorum_states)
{
quorum.height = kv_pair.first;
quorum.state = *kv_pair.second;
data_to_store.quorum_states.push_back(quorum);
}
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:
MERROR("On storing service node data, unknown rollback event type encountered");
return false;
}
}
}
data_to_store.height = m_height;
std::stringstream ss;
binary_archive<true> ba(ss);
bool r = ::serialization::serialize(ba, data_to_store);
CHECK_AND_ASSERT_MES(r, false, "Failed to store service node info: failed to serialize data");
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()
{
LOG_PRINT_L1("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& quorum : data_in.quorum_states)
{
m_quorum_states[quorum.height] = std::make_shared<quorum_state>(quorum.state);
}
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));
}
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::new_type;
m_rollback_events.push_back(std::unique_ptr<rollback_event>(i));
}
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::prevent_type;
m_rollback_events.push_back(std::unique_ptr<rollback_event>(i));
}
else
{
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * core_tests: check service node registration and deregistration * core_tests for service nodes: - include service nodes rewards when calculating account's balance - check that service nodes rewards have been received * fixed namespace error; reduced the scope of staking requirement constants * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
MERROR("Unhandled rollback event type in restoring data to service node list.");
return false;
}
}
MGINFO("Service node data loaded successfully, m_height: " << m_height);
MGINFO(m_service_nodes_infos.size() << " nodes and " << m_rollback_events.size() << " rollback events loaded.");
LOG_PRINT_L1("service_node_list::load() returning success");
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();
}
m_quorum_states.clear();
uint64_t hardfork_9_from_height = 0;
{
uint32_t window, votes, threshold;
uint8_t voting;
m_blockchain.get_hard_fork_voting_info(9, window, votes, threshold, hardfork_9_from_height, voting);
}
m_height = hardfork_9_from_height;
}
bool convert_registration_args(cryptonote::network_type nettype, std::vector<std::string> args, std::vector<cryptonote::account_public_address>& addresses, std::vector<uint64_t>& portions, uint64_t& portions_for_operator, bool& autostake)
{
2018-08-16 07:14:28 +02:00
autostake = false;
if (!args.empty() && args[0] == "auto")
{
2018-08-16 07:14:28 +02:00
autostake = true;
args.erase(args.begin());
}
2018-08-16 07:14:28 +02:00
if (args.size() % 2 == 0 || args.size() < 3)
{
2018-08-16 07:14:28 +02:00
MERROR(tr("Usage: [auto] <operator cut> <address> <fraction> [<address> <fraction> [...]]]"));
return false;
}
2018-08-16 07:14:28 +02:00
if ((args.size()-1)/ 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
{
portions_for_operator = boost::lexical_cast<uint64_t>(args[0]);
if (portions_for_operator > STAKING_PORTIONS)
{
MERROR(tr("Invalid portion amount: ") << args[0] << tr(". ") << tr("Must be between 0 and ") << STAKING_PORTIONS);
return false;
}
}
catch (const std::exception &e)
{
MERROR(tr("Invalid portion amount: ") << args[0] << tr(". ") << tr("Must be between 0 and ") << STAKING_PORTIONS);
return false;
}
uint64_t portions_left = STAKING_PORTIONS;
2018-08-16 07:14:28 +02:00
for (size_t i = 1; i < args.size(); 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
{
uint64_t num_portions = boost::lexical_cast<uint64_t>(args[i+1]);
uint64_t min_portions = std::min(portions_left, MIN_PORTIONS);
if (num_portions < min_portions || num_portions > portions_left)
{
MERROR(tr("Invalid portion amount: ") << args[i+1] << tr(". ") << tr("The contributors must each have at least 25%, except for the last contributor which may have the remaining amount"));
return false;
}
portions_left -= num_portions;
portions.push_back(num_portions);
}
catch (const std::exception &e)
{
MERROR(tr("Invalid portion amount: ") << args[i+1] << tr(". ") << tr("The contributors must each have at least 25%, except for the last contributor which may have the remaining 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<uint64_t> portions;
uint64_t operator_portions;
2018-08-16 07:14:28 +02:00
bool autostake;
if (!convert_registration_args(nettype, args, addresses, portions, operator_portions, autostake))
{
MERROR(tr("Could not convert registration args"));
return false;
}
2018-08-16 07:14:28 +02:00
uint64_t exp_timestamp = time(nullptr) + (autostake ? STAKING_AUTHORIZATION_EXPIRATION_AUTOSTAKE : 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);
2018-08-16 07:14:28 +02:00
stream << tr("This registration expires at ") << buffer << tr(".\n");
stream << tr("This should be in about 2 weeks, or two years for autostaking.\n");
stream << tr("If it isn't, check this computer's clock.\n");
stream << tr("Please submit your registration into the blockchain before this time or it will be invalid.");
}
cmd = stream.str();
return true;
}
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * core_tests: check service node registration and deregistration * core_tests for service nodes: - include service nodes rewards when calculating account's balance - check that service nodes rewards have been received * fixed namespace error; reduced the scope of staking requirement constants * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
uint64_t get_staking_requirement_lock_blocks(cryptonote::network_type nettype)
{
constexpr static uint32_t STAKING_REQUIREMENT_LOCK_BLOCKS = 30*24*30;
constexpr static uint32_t STAKING_REQUIREMENT_LOCK_BLOCKS_TESTNET = 30*24*2;
constexpr static uint32_t STAKING_REQUIREMENT_LOCK_BLOCKS_FAKENET = 30;
switch(nettype) {
case cryptonote::TESTNET: return STAKING_REQUIREMENT_LOCK_BLOCKS_TESTNET;
case cryptonote::FAKECHAIN: return STAKING_REQUIREMENT_LOCK_BLOCKS_FAKENET;
default: return STAKING_REQUIREMENT_LOCK_BLOCKS;
}
}
uint64_t get_staking_requirement(cryptonote::network_type m_nettype, uint64_t height)
{
if (m_nettype == cryptonote::TESTNET || m_nettype == cryptonote::FAKECHAIN)
return COIN * 100;
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * core_tests: check service node registration and deregistration * core_tests for service nodes: - include service nodes rewards when calculating account's balance - check that service nodes rewards have been received * fixed namespace error; reduced the scope of staking requirement constants * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
uint64_t hardfork_height = m_nettype == cryptonote::MAINNET ? 101250 : 96210 /* stagenet */;
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * core_tests: check service node registration and deregistration * core_tests for service nodes: - include service nodes rewards when calculating account's balance - check that service nodes rewards have been received * fixed namespace error; reduced the scope of staking requirement constants * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
if (height < hardfork_height) height = hardfork_height;
uint64_t height_adjusted = height - hardfork_height;
uint64_t base = 10000 * COIN;
uint64_t variable = (35000.0 * COIN) / loki_exp2(height_adjusted/129600.0);
uint64_t linear_up = (uint64_t)(5 * COIN * height / 2592) + 8000 * COIN;
uint64_t flat = 15000 * COIN;
return std::max(base + variable, height < 3628800 ? linear_up : flat);
}
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * core_tests: check service node registration and deregistration * core_tests for service nodes: - include service nodes rewards when calculating account's balance - check that service nodes rewards have been received * fixed namespace error; reduced the scope of staking requirement constants * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
uint64_t portions_to_amount(uint64_t portions, uint64_t staking_requirement)
{
uint64_t hi, lo, resulthi, resultlo;
lo = mul128(staking_requirement, portions, &hi);
div128_64(hi, lo, STAKING_PORTIONS, &resulthi, &resultlo);
return resultlo;
}
2018-06-29 06:47:00 +02:00
}