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-11-16 00:32:56 +01:00
# include <algorithm>
2018-07-12 03:58:17 +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"
2018-12-11 03:46:35 +01:00
# include "int-util.h"
2018-07-21 03:27:13 +02:00
# include "common/scoped_message_writer.h"
# include "common/i18n.h"
2018-12-21 01:33:05 +01:00
# include "service_node_quorum_cop.h"
2018-06-29 06:47:00 +02:00
# include "service_node_list.h"
2018-11-15 03:22:14 +01:00
# include "service_node_rules.h"
2019-04-08 04:03:47 +02:00
# include "service_node_swarm.h"
2018-06-29 06:47:00 +02:00
# undef LOKI_DEFAULT_LOG_CATEGORY
# define LOKI_DEFAULT_LOG_CATEGORY "service_nodes"
namespace service_nodes
{
2019-01-25 04:15:52 +01:00
static int get_min_service_node_info_version_for_hf ( int hf_version )
{
if ( hf_version > = cryptonote : : network_version_7 & & hf_version < = cryptonote : : network_version_9_service_nodes )
return service_node_info : : version_0 ;
if ( hf_version = = cryptonote : : network_version_10_bulletproofs )
return service_node_info : : version_1_swarms ;
2019-05-01 08:01:17 +02:00
if ( hf_version = = cryptonote : : network_version_11_infinite_staking )
return service_node_info : : version_2_infinite_staking ;
return service_node_info : : version_3_checkpointing ;
2019-01-25 04:15:52 +01:00
}
2018-06-29 06:47:00 +02:00
service_node_list : : service_node_list ( cryptonote : : Blockchain & blockchain )
2019-05-01 08:01:17 +02:00
: m_blockchain ( blockchain ) , m_hooks_registered ( false ) , m_db ( nullptr ) , m_service_node_pubkey ( nullptr )
2018-06-29 06:47:00 +02:00
{
2019-05-01 08:01:17 +02:00
m_transient_state = { } ;
2018-07-12 03:58:17 +02:00
}
void service_node_list : : register_hooks ( service_nodes : : quorum_cop & quorum_cop )
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2018-08-03 03:34:41 +02:00
if ( ! m_hooks_registered )
2018-07-12 03:58:17 +02:00
{
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
2018-08-10 06:15:47 +02:00
m_blockchain . hook_init ( quorum_cop ) ;
2018-07-12 03:58:17 +02:00
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 ( )
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2018-10-17 02:07:04 +02:00
if ( m_blockchain . get_current_hard_fork_version ( ) < 9 )
{
clear ( true ) ;
return ;
}
2018-08-16 05:08:36 +02:00
uint64_t current_height = m_blockchain . get_current_blockchain_height ( ) ;
bool loaded = load ( ) ;
2019-05-01 08:01:17 +02:00
if ( loaded & & m_transient_state . height = = current_height ) return ;
2018-08-08 06:04:21 +02:00
2019-05-01 08:01:17 +02:00
if ( ! loaded | | m_transient_state . height > current_height ) clear ( true ) ;
2018-07-12 03:58:17 +02:00
2019-05-01 08:01:17 +02:00
LOG_PRINT_L0 ( " Recalculating service nodes list, scanning blockchain from height " < < m_transient_state . height ) ;
2018-08-17 04:25:28 +02:00
LOG_PRINT_L0 ( " This may take some time... " ) ;
2018-09-13 10:42:49 +02:00
std : : vector < std : : pair < cryptonote : : blobdata , cryptonote : : block > > blocks ;
2019-05-01 08:01:17 +02:00
while ( m_transient_state . height < current_height )
2018-06-29 06:47:00 +02:00
{
2018-09-13 10:42:49 +02:00
blocks . clear ( ) ;
2019-05-01 08:01:17 +02:00
if ( ! m_blockchain . get_blocks ( m_transient_state . height , 1000 , blocks ) )
2018-06-29 06:47:00 +02:00
{
2019-01-25 04:15:52 +01:00
MERROR ( " Unable to initialize service nodes list " ) ;
2018-06-29 06:47:00 +02:00
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-09-13 10:42:49 +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 )
{
2018-09-13 10:42:49 +02:00
txs . clear ( ) ;
missed_txs . clear ( ) ;
2018-09-19 05:23:56 +02:00
2018-06-29 06:47:00 +02:00
const cryptonote : : block & block = block_pair . second ;
if ( ! m_blockchain . get_transactions ( block . tx_hashes , txs , missed_txs ) )
{
2019-01-25 04:15:52 +01:00
MERROR ( " Unable to get transactions for block " < < block . hash ) ;
2018-06-29 06:47:00 +02:00
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
2019-04-11 07:08:26 +02:00
process_block ( block , txs ) ;
2018-06-29 06:47:00 +02:00
}
}
}
2018-07-12 03:58:17 +02:00
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 ;
2019-05-01 08:01:17 +02:00
for ( const auto & iter : m_transient_state . service_nodes_infos )
2018-07-28 08:27:04 +02:00
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 ;
}
2019-05-01 08:01:17 +02:00
const std : : shared_ptr < const quorum_uptime_proof > service_node_list : : get_uptime_quorum ( 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
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2019-05-01 08:01:17 +02:00
const auto & it = m_transient_state . quorum_states . find ( height ) ;
if ( it ! = m_transient_state . quorum_states . end ( ) )
return it - > second . uptime_proof ;
return nullptr ;
}
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
2019-05-01 08:01:17 +02:00
const std : : shared_ptr < const quorum_checkpointing > service_node_list : : get_checkpointing_quorum ( uint64_t height ) const
{
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
const auto & it = m_transient_state . quorum_states . find ( height ) ;
if ( it ! = m_transient_state . quorum_states . end ( ) )
return it - > second . checkpointing ;
2018-12-18 07:50:49 +01:00
return nullptr ;
2018-06-29 06:47:00 +02:00
}
2018-08-15 04:59:05 +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
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2018-08-15 04:59:05 +02:00
std : : vector < service_node_pubkey_info > result ;
if ( service_node_pubkeys . empty ( ) )
{
2019-05-01 08:01:17 +02:00
result . reserve ( m_transient_state . service_nodes_infos . size ( ) ) ;
2018-08-15 04:59:05 +02:00
2019-05-01 08:01:17 +02:00
for ( const auto & it : m_transient_state . service_nodes_infos )
2018-08-15 04:59:05 +02:00
{
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 )
{
2019-05-01 08:01:17 +02:00
const auto & find_it = m_transient_state . service_nodes_infos . find ( it ) ;
if ( find_it = = m_transient_state . service_nodes_infos . end ( ) )
2018-08-15 04:59:05 +02:00
continue ;
service_node_pubkey_info entry = { } ;
entry . pubkey = ( * find_it ) . first ;
entry . info = ( * find_it ) . second ;
result . push_back ( entry ) ;
}
}
return result ;
}
2018-10-10 07:24:01 +02:00
void service_node_list : : set_db_pointer ( cryptonote : : BlockchainDB * db )
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2018-10-10 07:24:01 +02:00
m_db = db ;
}
void service_node_list : : set_my_service_node_keys ( crypto : : public_key const * pub_key )
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2018-10-10 07:24:01 +02:00
m_service_node_pubkey = pub_key ;
}
2018-07-12 04:07:34 +02:00
bool service_node_list : : is_service_node ( const crypto : : public_key & pubkey ) const
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2019-05-01 08:01:17 +02:00
return m_transient_state . service_nodes_infos . find ( pubkey ) ! = m_transient_state . service_nodes_infos . end ( ) ;
2018-07-12 04:07:34 +02:00
}
2019-01-25 04:15:52 +01:00
bool service_node_list : : is_key_image_locked ( crypto : : key_image const & check_image , uint64_t * unlock_height , service_node_info : : contribution_t * the_locked_contribution ) const
2018-06-29 06:47:00 +02:00
{
2019-05-01 08:01:17 +02:00
for ( const auto & pubkey_info : m_transient_state . service_nodes_infos )
2019-01-25 04:15:52 +01:00
{
const service_node_info & info = pubkey_info . second ;
for ( const service_node_info : : contributor_t & contributor : info . contributors )
{
for ( const service_node_info : : contribution_t & contribution : contributor . locked_contributions )
{
if ( check_image = = contribution . key_image )
{
if ( the_locked_contribution ) * the_locked_contribution = contribution ;
if ( unlock_height ) * unlock_height = info . requested_unlock_height ;
return true ;
}
}
}
}
return false ;
2018-06-29 06:47:00 +02:00
}
2019-01-25 04:15:52 +01: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 )
2018-06-29 06:47:00 +02:00
{
2018-07-18 08:51:26 +02:00
cryptonote : : tx_extra_service_node_register registration ;
2018-07-21 03:27:13 +02:00
if ( ! get_service_node_register_from_tx_extra ( tx . extra , registration ) )
return false ;
2018-07-28 08:27:04 +02:00
if ( ! cryptonote : : get_service_node_pubkey_from_tx_extra ( tx . extra , service_node_key ) )
return false ;
2018-07-21 03:27:13 +02:00
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 ] } ) ;
2018-07-28 08:27:04 +02:00
2018-08-07 04:28:59 +02:00
portions_for_operator = registration . m_portions_for_operator ;
2018-07-31 04:46:12 +02:00
portions = registration . m_portions ;
2018-07-21 03:27:13 +02:00
expiration_timestamp = registration . m_expiration_timestamp ;
signature = registration . m_service_node_signature ;
return true ;
2018-06-29 06:47:00 +02:00
}
2019-01-25 04:15:52 +01:00
struct parsed_tx_contribution
{
cryptonote : : account_public_address address ;
uint64_t transferred ;
crypto : : secret_key tx_key ;
std : : vector < service_node_info : : contribution_t > locked_contributions ;
} ;
static uint64_t get_reg_tx_staking_output_contribution ( const cryptonote : : transaction & tx , int i , crypto : : key_derivation const & derivation , hw : : device & hwdev )
2018-06-29 06:47:00 +02:00
{
if ( tx . vout [ i ] . target . type ( ) ! = typeid ( cryptonote : : txout_to_key ) )
{
2018-07-18 08:51:26 +02:00
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 :
2018-10-08 04:34:36 +02:00
case rct : : RCTTypeBulletproof :
2019-01-30 04:44:00 +01:00
case rct : : RCTTypeBulletproof2 :
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 :
2018-08-03 08:52:44 +02:00
LOG_PRINT_L0 ( " Unsupported rct type: " < < tx . rct_signatures . type ) ;
2018-07-18 08:51:26 +02:00
return 0 ;
2018-06-29 06:47:00 +02:00
}
}
catch ( const std : : exception & e )
{
2018-08-03 08:52:44 +02:00
LOG_PRINT_L0 ( " Failed to decode input " < < i ) ;
2018-07-18 08:51:26 +02:00
return 0 ;
2018-06-29 06:47:00 +02:00
}
2018-07-18 08:51:26 +02:00
return money_transferred ;
2018-06-29 06:47:00 +02:00
}
2018-11-16 00:32:56 +01:00
bool 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
{
2019-01-25 04:15:52 +01:00
if ( tx . get_type ( ) ! = cryptonote : : transaction : : type_deregister )
2018-11-16 00:32:56 +01:00
return false ;
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 ) )
{
2019-01-25 04:15:52 +01:00
MERROR ( " Transaction deregister did not have deregister data in tx extra, possibly corrupt tx in blockchain " ) ;
2018-11-16 00:32:56 +01:00
return false ;
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
}
2019-05-01 08:01:17 +02:00
const auto state = get_uptime_quorum ( 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
2018-07-18 08:51:26 +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.
2019-05-01 08:01:17 +02:00
MERROR ( " Uptime quorum for height: " < < deregister . block_height < < " , was not stored by the daemon " ) ;
2018-11-16 00:32:56 +01:00
return false ;
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-07-18 08:51:26 +02:00
if ( deregister . service_node_index > = state - > nodes_to_test . size ( ) )
{
2019-01-25 04:15:52 +01:00
MERROR ( " Service node index to vote off has become invalid, quorum rules have changed without a hardfork. " ) ;
2018-11-16 00:32:56 +01:00
return false ;
2018-07-18 08:51:26 +02:00
}
2018-07-28 08:27:04 +02:00
const crypto : : public_key & key = state - > nodes_to_test [ deregister . service_node_index ] ;
2018-07-18 08:51:26 +02:00
2019-05-01 08:01:17 +02:00
auto iter = m_transient_state . service_nodes_infos . find ( key ) ;
if ( iter = = m_transient_state . service_nodes_infos . end ( ) )
2018-11-16 00:32:56 +01:00
return false ;
2018-07-28 08:27:04 +02:00
2018-09-27 10:31:08 +02:00
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 ) ;
}
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back ( std : : unique_ptr < rollback_event > ( new rollback_change ( block_height , key , iter - > second ) ) ) ;
2018-11-16 00:32:56 +01:00
2019-01-25 04:15:52 +01:00
int hard_fork_version = m_blockchain . get_hard_fork_version ( block_height ) ;
2019-02-25 08:05:20 +01:00
if ( hard_fork_version > = cryptonote : : network_version_11_infinite_staking )
2019-01-25 04:15:52 +01:00
{
for ( const auto & contributor : iter - > second . contributors )
{
for ( const auto & contribution : contributor . locked_contributions )
{
key_image_blacklist_entry entry = { } ;
entry . key_image = contribution . key_image ;
Infinite Staking Part 2 (#406)
* Cleanup and undoing some protocol breakages
* Simplify expiration of nodes
* Request unlock schedules entire node for expiration
* Fix off by one in expiring nodes
* Undo expiring code for pre v10 nodes
* Fix RPC returning register as unlock height and not checking 0
* Rename key image unlock height const
* Undo testnet hardfork debug changes
* Remove is_type for get_type, fix missing var rename
* Move serialisable data into public namespace
* Serialise tx types properly
* Fix typo in no service node known msg
* Code review
* Fix == to >= on serialising tx type
* Code review 2
* Fix tests and key image unlock
* Add command to print locked key images
* Update ui to display lock stakes, query in print cmd blacklist
* Modify print stakes to be less slow
* Remove autostaking code
* Refactor staking into sweep functions
It appears staking was derived off stake_main written separately at
implementation at the beginning. This merges them back into a common
code path, after removing autostake there's only some minor differences.
It also makes sure that any changes to sweeping upstream are going to be
considered in the staking process which we want.
* Display unlock height for stakes
* Begin creating output blacklist
* Make blacklist output a migration step
* Implement get_output_blacklist for lmdb
* In wallet output selection ignore blacklisted outputs
* Apply blacklisted outputs to output selection
* Fix broken tests, switch key image unlock
* Fix broken unit_tests
* Begin change to limit locked key images to 4 globally
* Revamp prepare registration for new min contribution rules
* Fix up old back case in prepare registration
* Remove debug code
* Cleanup debug code and some unecessary changes
* Fix migration step on mainnet db
* Fix blacklist outputs for pre-existing DB's
* Remove irrelevant note
* Tweak scanning addresses for locked stakes
Since we only now allow contributions from the primary address we can
skip checking all subaddress + lookahead to speed up wallet scanning
* Define macro for SCNu64 for Mingw
* Fix failure on empty DB
* Add missing error msg, remove contributor from stake
* Improve staking messages
* Flush prompt to always display
* Return the msg from stake failure and fix stake parsing error
* Tweak fork rules for smaller bulletproofs
* Tweak pooled nodes minimum amounts
* Fix crash on exit, there's no need to store on destructor
Since all information about service nodes is derived from the blockchain
and we store state every time we receive a block, storing in the
destructor is redundant as there is no new information to store.
* Make prompt be consistent with CLI
* Check max number of key images from per user to node
* Implement error message on get_output_blacklist failure
* Remove resolved TODO's/comments
* Handle infinite staking in print_sn
* Atoi->strtol, fix prepare_registration, virtual override, stale msgs
2019-02-14 02:12:57 +01:00
entry . unlock_height = block_height + staking_num_lock_blocks ( m_blockchain . nettype ( ) ) ;
2019-05-01 08:01:17 +02:00
m_transient_state . key_image_blacklist . push_back ( entry ) ;
2019-01-25 04:15:52 +01:00
const bool adding_to_blacklist = true ;
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back ( std : : unique_ptr < rollback_event > ( new rollback_key_image_blacklist ( block_height , entry , adding_to_blacklist ) ) ) ;
2019-01-25 04:15:52 +01:00
}
}
}
2019-05-01 08:01:17 +02:00
m_transient_state . service_nodes_infos . erase ( iter ) ;
2018-11-16 00:32:56 +01:00
return true ;
}
void service_node_list : : update_swarms ( uint64_t height ) {
crypto : : hash hash = m_blockchain . get_block_id_by_height ( height ) ;
uint64_t seed = 0 ;
std : : memcpy ( & seed , hash . data , sizeof ( seed ) ) ;
/// Gather existing swarms from infos
2019-04-08 04:03:47 +02:00
swarm_snode_map_t existing_swarms ;
2018-11-16 00:32:56 +01:00
2019-05-01 08:01:17 +02:00
for ( const auto & entry : m_transient_state . service_nodes_infos ) {
2018-11-16 00:32:56 +01:00
const auto id = entry . second . swarm_id ;
existing_swarms [ id ] . push_back ( entry . first ) ;
}
calc_swarm_changes ( existing_swarms , seed ) ;
/// Apply changes
for ( const auto entry : existing_swarms ) {
const swarm_id_t swarm_id = entry . first ;
const std : : vector < crypto : : public_key > & snodes = entry . second ;
for ( const auto snode : snodes ) {
2019-05-01 08:01:17 +02:00
auto & sn_info = m_transient_state . service_nodes_infos . at ( snode ) ;
2018-11-16 00:32:56 +01:00
if ( sn_info . swarm_id = = swarm_id ) continue ; /// nothing changed for this snode
/// modify info and record the change
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back ( std : : unique_ptr < rollback_event > ( new rollback_change ( height , snode , sn_info ) ) ) ;
2018-11-16 00:32:56 +01:00
sn_info . swarm_id = swarm_id ;
}
}
2019-01-25 04:15:52 +01:00
}
static bool get_contribution ( cryptonote : : network_type nettype , int hard_fork_version , const cryptonote : : transaction & tx , uint64_t block_height , parsed_tx_contribution & parsed_contribution )
{
if ( ! cryptonote : : get_service_node_contributor_from_tx_extra ( tx . extra , parsed_contribution . address ) )
return false ;
if ( ! cryptonote : : get_tx_secret_key_from_tx_extra ( tx . extra , parsed_contribution . tx_key ) )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Contribution TX: There was a service node contributor but no secret key in the tx extra on height: " < < block_height < < " for tx: " < < get_transaction_hash ( tx ) ) ;
2019-01-25 04:15:52 +01:00
return false ;
}
crypto : : key_derivation derivation ;
if ( ! crypto : : generate_key_derivation ( parsed_contribution . address . m_view_public_key , parsed_contribution . tx_key , derivation ) )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Contribution TX: Failed to generate key derivation on height: " < < block_height < < " for tx: " < < get_transaction_hash ( tx ) ) ;
2019-01-25 04:15:52 +01:00
return false ;
}
hw : : device & hwdev = hw : : get_device ( " default " ) ;
parsed_contribution . transferred = 0 ;
2019-02-25 08:05:20 +01:00
if ( hard_fork_version > = cryptonote : : network_version_11_infinite_staking )
2019-01-25 04:15:52 +01:00
{
cryptonote : : tx_extra_tx_key_image_proofs key_image_proofs ;
if ( ! get_tx_key_image_proofs_from_tx_extra ( tx . extra , key_image_proofs ) )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Contribution TX: Didn't have key image proofs in the tx_extra, rejected on height: " < < block_height < < " for tx: " < < get_transaction_hash ( tx ) ) ;
2019-01-25 04:15:52 +01:00
return false ;
}
for ( size_t output_index = 0 ; output_index < tx . vout . size ( ) ; + + output_index )
{
uint64_t transferred = get_reg_tx_staking_output_contribution ( tx , output_index , derivation , hwdev ) ;
if ( transferred = = 0 )
continue ;
crypto : : public_key ephemeral_pub_key ;
{
if ( ! hwdev . derive_public_key ( derivation , output_index , parsed_contribution . address . m_spend_public_key , ephemeral_pub_key ) )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Contribution TX: Could not derive TX ephemeral key on height: " < < block_height < < " for tx: " < < get_transaction_hash ( tx ) < < " for output: " < < output_index ) ;
2019-01-25 04:15:52 +01:00
continue ;
}
const auto & out_to_key = boost : : get < cryptonote : : txout_to_key > ( tx . vout [ output_index ] . target ) ;
if ( out_to_key . key ! = ephemeral_pub_key )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Contribution TX: Derived TX ephemeral key did not match tx stored key on height: " < < block_height < < " for tx: " < < get_transaction_hash ( tx ) < < " for output: " < < output_index ) ;
2019-01-25 04:15:52 +01:00
continue ;
}
}
crypto : : public_key const * ephemeral_pub_key_ptr = & ephemeral_pub_key ;
for ( auto proof = key_image_proofs . proofs . begin ( ) ; proof ! = key_image_proofs . proofs . end ( ) ; proof + + )
{
if ( ! crypto : : check_ring_signature ( ( const crypto : : hash & ) ( proof - > key_image ) , proof - > key_image , & ephemeral_pub_key_ptr , 1 , & proof - > signature ) )
continue ;
service_node_info : : contribution_t entry = { } ;
entry . key_image_pub_key = ephemeral_pub_key ;
entry . key_image = proof - > key_image ;
entry . amount = transferred ;
parsed_contribution . locked_contributions . push_back ( entry ) ;
parsed_contribution . transferred + = transferred ;
key_image_proofs . proofs . erase ( proof ) ;
break ;
}
}
}
else
{
for ( size_t i = 0 ; i < tx . vout . size ( ) ; i + + )
{
bool has_correct_unlock_time = false ;
{
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 ] ;
2019-03-13 06:35:02 +01:00
uint64_t min_height = block_height + staking_num_lock_blocks ( nettype ) ;
has_correct_unlock_time = unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER & & unlock_time > = min_height ;
2019-01-25 04:15:52 +01:00
}
if ( has_correct_unlock_time )
parsed_contribution . transferred + = get_reg_tx_staking_output_contribution ( tx , i , derivation , hwdev ) ;
}
}
2018-11-16 00:32:56 +01:00
2019-01-25 04:15:52 +01:00
return true ;
Service Node Deregister Part 5 (#89)
* Retrieve quorum list from height, reviewed
* Setup data structures for de/register TX
* Submit and validate partial/full deregisters
* Add P2P relaying of partial deregistration votes
* Code review adjustments for deregistration part 1
- Fix check_tx_semantic
- Remove signature_pod as votes are now stored as blobs. Serialization
overrides don't intefere with crypto::signature anymore.
* deregistration_vote_pool - changed sign/verify interface and removed repeated code
* Misc review, fix sign/verify api, vote threshold
* Deregister/tx edge case handling for combinatoric votes
* core, service_node_list: separated address from service node pubkey
* Retrieve quorum list from height, reviewed
* Setup data structures for de/register TX
* Submit and validate partial/full deregisters
* Add P2P relaying of partial deregistration votes
* Code review adjustments for deregistration part 1
- Fix check_tx_semantic
- Remove signature_pod as votes are now stored as blobs. Serialization
overrides don't intefere with crypto::signature anymore.
* deregistration_vote_pool - changed sign/verify interface and removed repeated code
* Misc review, fix sign/verify api, vote threshold
* Deregister/tx edge case handling for combinatoric votes
* Store service node lists for the duration of deregister lifetimes
* Quorum min/max bug, sort node list, fix node to test list
* Change quorum to store acc pub address, fix oob bug
* Code review for expiring votes, acc keys to pub_key, improve err msgs
* Add early out for is_deregistration_tx and protect against quorum changes
* Remove debug code, fix segfault
* Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states
Incorrect assumption that a transaction can be kept in the chain if it could
eventually become invalid, because if it were the chain would be split and
eventually these transaction would be dropped. But also that we should not
override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
}
2018-07-31 06:06:22 +02:00
bool service_node_list : : is_registration_tx ( const cryptonote : : transaction & tx , uint64_t block_timestamp , uint64_t block_height , uint32_t index , crypto : : public_key & key , service_node_info & info ) const
2018-06-29 06:47:00 +02:00
{
2019-01-25 04:15:52 +01:00
crypto : : public_key service_node_key ;
2018-07-18 08:51:26 +02:00
std : : vector < cryptonote : : account_public_address > service_node_addresses ;
2018-08-18 06:36:16 +02:00
std : : vector < uint64_t > service_node_portions ;
uint64_t portions_for_operator ;
2018-07-21 03:27:13 +02:00
uint64_t expiration_timestamp ;
crypto : : signature signature ;
2018-07-18 08:51:26 +02:00
2019-01-25 04:15:52 +01:00
if ( ! reg_tx_extract_fields ( tx , service_node_addresses , portions_for_operator , service_node_portions , expiration_timestamp , service_node_key , signature ) )
2018-07-18 08:51:26 +02:00
return false ;
2018-08-07 04:28:59 +02:00
if ( service_node_portions . size ( ) ! = service_node_addresses . size ( ) | | service_node_portions . empty ( ) )
2019-01-25 04:15:52 +01:00
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Register TX: Extracted portions size: ( " < < service_node_portions . size ( ) < <
" ) was empty or did not match address size: ( " < < service_node_addresses . size ( ) < <
" ) on height: " < < block_height < <
" for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-08-07 04:28:59 +02:00
return false ;
2019-01-25 04:15:52 +01:00
}
2018-07-21 03:27:13 +02:00
2019-01-25 04:15:52 +01:00
int hf_version = m_blockchain . get_hard_fork_version ( block_height ) ;
2018-07-21 03:27:13 +02:00
2019-01-22 00:44:30 +01:00
if ( ! check_service_node_portions ( hf_version , service_node_portions ) ) return false ;
2018-06-29 06:47:00 +02:00
2018-08-07 04:28:59 +02:00
if ( portions_for_operator > STAKING_PORTIONS )
2019-01-25 04:15:52 +01:00
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Register TX: Operator portions: " < < portions_for_operator < <
" exceeded staking portions: " < < STAKING_PORTIONS < <
" on height: " < < block_height < <
" for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-08-07 04:28:59 +02:00
return false ;
2019-01-25 04:15:52 +01:00
}
2018-08-07 04:28:59 +02:00
2018-08-06 15:08:44 +02:00
// check the signature is all good
2018-07-21 03:27:13 +02:00
crypto : : hash hash ;
2018-08-07 04:28:59 +02:00
if ( ! get_registration_hash ( service_node_addresses , portions_for_operator , service_node_portions , expiration_timestamp , hash ) )
2019-01-25 04:15:52 +01:00
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Register TX: Failed to extract registration hash, on height: " < < block_height < < " for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-07-21 03:27:13 +02:00
return false ;
2019-01-25 04:15:52 +01:00
}
2018-08-14 08:12:42 +02:00
if ( ! crypto : : check_key ( service_node_key ) | | ! crypto : : check_signature ( hash , service_node_key , signature ) )
2019-01-25 04:15:52 +01:00
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Register TX: Has invalid key and/or signature, on height: " < < block_height < < " for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-07-21 03:27:13 +02:00
return false ;
2019-01-25 04:15:52 +01:00
}
2018-07-21 03:27:13 +02:00
if ( expiration_timestamp < block_timestamp )
2019-01-25 04:15:52 +01:00
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Register TX: Has expired. The block timestamp: " < < block_timestamp < <
" is greater than the expiration timestamp: " < < expiration_timestamp < <
" on height: " < < block_height < <
" for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-07-12 04:07:34 +02:00
return false ;
2019-01-25 04:15:52 +01:00
}
2018-06-29 06:47:00 +02:00
2018-08-06 15:08:44 +02:00
// check the initial contribution exists
2019-03-21 01:03:06 +01:00
info . staking_requirement = get_staking_requirement ( m_blockchain . nettype ( ) , block_height , hf_version ) ;
2018-08-06 15:08:44 +02:00
cryptonote : : account_public_address address ;
2019-01-25 04:15:52 +01:00
parsed_tx_contribution parsed_contribution = { } ;
if ( ! get_contribution ( m_blockchain . nettype ( ) , hf_version , tx , block_height , parsed_contribution ) )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Register TX: Had service node registration fields, but could not decode contribution on height: " < < block_height < < " for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-08-06 15:08:44 +02:00
return false ;
2019-01-25 04:15:52 +01:00
}
Infinite Staking Part 2 (#406)
* Cleanup and undoing some protocol breakages
* Simplify expiration of nodes
* Request unlock schedules entire node for expiration
* Fix off by one in expiring nodes
* Undo expiring code for pre v10 nodes
* Fix RPC returning register as unlock height and not checking 0
* Rename key image unlock height const
* Undo testnet hardfork debug changes
* Remove is_type for get_type, fix missing var rename
* Move serialisable data into public namespace
* Serialise tx types properly
* Fix typo in no service node known msg
* Code review
* Fix == to >= on serialising tx type
* Code review 2
* Fix tests and key image unlock
* Add command to print locked key images
* Update ui to display lock stakes, query in print cmd blacklist
* Modify print stakes to be less slow
* Remove autostaking code
* Refactor staking into sweep functions
It appears staking was derived off stake_main written separately at
implementation at the beginning. This merges them back into a common
code path, after removing autostake there's only some minor differences.
It also makes sure that any changes to sweeping upstream are going to be
considered in the staking process which we want.
* Display unlock height for stakes
* Begin creating output blacklist
* Make blacklist output a migration step
* Implement get_output_blacklist for lmdb
* In wallet output selection ignore blacklisted outputs
* Apply blacklisted outputs to output selection
* Fix broken tests, switch key image unlock
* Fix broken unit_tests
* Begin change to limit locked key images to 4 globally
* Revamp prepare registration for new min contribution rules
* Fix up old back case in prepare registration
* Remove debug code
* Cleanup debug code and some unecessary changes
* Fix migration step on mainnet db
* Fix blacklist outputs for pre-existing DB's
* Remove irrelevant note
* Tweak scanning addresses for locked stakes
Since we only now allow contributions from the primary address we can
skip checking all subaddress + lookahead to speed up wallet scanning
* Define macro for SCNu64 for Mingw
* Fix failure on empty DB
* Add missing error msg, remove contributor from stake
* Improve staking messages
* Flush prompt to always display
* Return the msg from stake failure and fix stake parsing error
* Tweak fork rules for smaller bulletproofs
* Tweak pooled nodes minimum amounts
* Fix crash on exit, there's no need to store on destructor
Since all information about service nodes is derived from the blockchain
and we store state every time we receive a block, storing in the
destructor is redundant as there is no new information to store.
* Make prompt be consistent with CLI
* Check max number of key images from per user to node
* Implement error message on get_output_blacklist failure
* Remove resolved TODO's/comments
* Handle infinite staking in print_sn
* Atoi->strtol, fix prepare_registration, virtual override, stale msgs
2019-02-14 02:12:57 +01:00
const uint64_t min_transfer = get_min_node_contribution ( hf_version , info . staking_requirement , info . total_reserved , info . total_num_locked_contributions ( ) ) ;
2019-01-25 04:15:52 +01:00
if ( parsed_contribution . transferred < min_transfer )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Register TX: Contribution transferred: " < < parsed_contribution . transferred < < " didn't meet the minimum transfer requirement: " < < min_transfer < < " on height: " < < block_height < < " for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-08-06 15:08:44 +02:00
return false ;
2019-01-25 04:15:52 +01:00
}
size_t total_num_of_addr = service_node_addresses . size ( ) ;
if ( std : : find ( service_node_addresses . begin ( ) , service_node_addresses . end ( ) , parsed_contribution . address ) = = service_node_addresses . end ( ) )
total_num_of_addr + + ;
if ( total_num_of_addr > MAX_NUMBER_OF_CONTRIBUTORS )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Register TX: Number of participants: " < < total_num_of_addr < <
" exceeded the max number of contributors: " < < MAX_NUMBER_OF_CONTRIBUTORS < <
" on height: " < < block_height < <
" for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-07-28 08:27:04 +02:00
return false ;
2019-01-25 04:15:52 +01:00
}
2018-07-28 08:27:04 +02:00
2018-08-06 15:08:44 +02:00
// don't actually process this contribution now, do it when we fall through later.
2018-07-28 08:27:04 +02:00
key = service_node_key ;
2018-08-07 04:28:59 +02:00
info . operator_address = service_node_addresses [ 0 ] ;
info . portions_for_operator = portions_for_operator ;
2018-08-16 05:12:41 +02:00
info . registration_height = block_height ;
2018-07-28 08:27:04 +02:00
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 ;
2019-01-25 04:15:52 +01:00
info . version = get_min_service_node_info_version_for_hf ( hf_version ) ;
2018-11-16 00:32:56 +01:00
2019-01-25 04:15:52 +01:00
if ( info . version > = service_node_info : : version_1_swarms )
2019-04-08 04:03:47 +02:00
info . swarm_id = UNASSIGNED_SWARM_ID ;
2018-11-16 00:32:56 +01:00
2018-08-06 15:08:44 +02:00
info . contributors . clear ( ) ;
for ( size_t i = 0 ; i < service_node_addresses . size ( ) ; i + + )
{
2018-08-07 05:21:56 +02:00
// Check for duplicates
auto iter = std : : find ( service_node_addresses . begin ( ) , service_node_addresses . begin ( ) + i , service_node_addresses [ i ] ) ;
2018-08-07 06:27:13 +02:00
if ( iter ! = service_node_addresses . begin ( ) + i )
2019-01-25 04:15:52 +01:00
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Register TX: There was a duplicate participant for service node on height: " < < block_height < < " for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-08-06 15:08:44 +02:00
return false ;
2019-01-25 04:15:52 +01:00
}
2018-08-06 15:08:44 +02:00
uint64_t hi , lo , resulthi , resultlo ;
lo = mul128 ( info . staking_requirement , service_node_portions [ i ] , & hi ) ;
2018-08-18 06:36:16 +02:00
div128_64 ( hi , lo , STAKING_PORTIONS , & resulthi , & resultlo ) ;
2019-01-25 04:15:52 +01:00
service_node_info : : contributor_t contributor = { } ;
contributor . version = get_min_service_node_info_version_for_hf ( hf_version ) ;
contributor . reserved = resultlo ;
contributor . address = service_node_addresses [ i ] ;
info . contributors . push_back ( contributor ) ;
2018-08-20 06:15:31 +02:00
info . total_reserved + = resultlo ;
2018-08-06 15:08:44 +02:00
}
2018-07-28 08:27:04 +02:00
return true ;
}
2018-11-16 00:32:56 +01:00
bool service_node_list : : process_registration_tx ( const cryptonote : : transaction & tx , uint64_t block_timestamp , uint64_t block_height , uint32_t index )
2018-07-28 08:27:04 +02:00
{
crypto : : public_key key ;
2018-11-16 00:32:56 +01:00
service_node_info info = { } ;
2018-07-28 08:27:04 +02:00
if ( ! is_registration_tx ( tx , block_timestamp , block_height , index , key , info ) )
2018-11-16 00:32:56 +01:00
return false ;
2018-07-28 08:27:04 +02:00
2019-01-25 04:15:52 +01:00
int hard_fork_version = m_blockchain . get_hard_fork_version ( block_height ) ;
2019-02-25 08:05:20 +01:00
if ( hard_fork_version > = cryptonote : : network_version_11_infinite_staking )
2018-10-16 01:32:35 +02:00
{
2019-01-25 04:15:52 +01:00
// NOTE(loki): Grace period is not used anymore with infinite staking. So, if someone somehow reregisters, we just ignore it
2019-05-01 08:01:17 +02:00
const auto iter = m_transient_state . service_nodes_infos . find ( key ) ;
if ( iter ! = m_transient_state . service_nodes_infos . end ( ) )
2019-01-25 04:15:52 +01:00
return false ;
2018-10-16 01:32:35 +02:00
2019-01-25 04:15:52 +01:00
if ( m_service_node_pubkey & & * m_service_node_pubkey = = key ) MGINFO_GREEN ( " Service node registered (yours): " < < key < < " on height: " < < block_height ) ;
else LOG_PRINT_L1 ( " New service node registered: " < < key < < " on height: " < < block_height ) ;
}
else
{
// 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 ;
2019-05-01 08:01:17 +02:00
const auto iter = m_transient_state . service_nodes_infos . find ( key ) ;
if ( iter ! = m_transient_state . service_nodes_infos . end ( ) )
2018-10-16 01:32:35 +02:00
{
2019-01-25 04:15:52 +01:00
if ( hard_fork_version > = cryptonote : : network_version_10_bulletproofs )
{
service_node_info const & old_info = iter - > second ;
Infinite Staking Part 2 (#406)
* Cleanup and undoing some protocol breakages
* Simplify expiration of nodes
* Request unlock schedules entire node for expiration
* Fix off by one in expiring nodes
* Undo expiring code for pre v10 nodes
* Fix RPC returning register as unlock height and not checking 0
* Rename key image unlock height const
* Undo testnet hardfork debug changes
* Remove is_type for get_type, fix missing var rename
* Move serialisable data into public namespace
* Serialise tx types properly
* Fix typo in no service node known msg
* Code review
* Fix == to >= on serialising tx type
* Code review 2
* Fix tests and key image unlock
* Add command to print locked key images
* Update ui to display lock stakes, query in print cmd blacklist
* Modify print stakes to be less slow
* Remove autostaking code
* Refactor staking into sweep functions
It appears staking was derived off stake_main written separately at
implementation at the beginning. This merges them back into a common
code path, after removing autostake there's only some minor differences.
It also makes sure that any changes to sweeping upstream are going to be
considered in the staking process which we want.
* Display unlock height for stakes
* Begin creating output blacklist
* Make blacklist output a migration step
* Implement get_output_blacklist for lmdb
* In wallet output selection ignore blacklisted outputs
* Apply blacklisted outputs to output selection
* Fix broken tests, switch key image unlock
* Fix broken unit_tests
* Begin change to limit locked key images to 4 globally
* Revamp prepare registration for new min contribution rules
* Fix up old back case in prepare registration
* Remove debug code
* Cleanup debug code and some unecessary changes
* Fix migration step on mainnet db
* Fix blacklist outputs for pre-existing DB's
* Remove irrelevant note
* Tweak scanning addresses for locked stakes
Since we only now allow contributions from the primary address we can
skip checking all subaddress + lookahead to speed up wallet scanning
* Define macro for SCNu64 for Mingw
* Fix failure on empty DB
* Add missing error msg, remove contributor from stake
* Improve staking messages
* Flush prompt to always display
* Return the msg from stake failure and fix stake parsing error
* Tweak fork rules for smaller bulletproofs
* Tweak pooled nodes minimum amounts
* Fix crash on exit, there's no need to store on destructor
Since all information about service nodes is derived from the blockchain
and we store state every time we receive a block, storing in the
destructor is redundant as there is no new information to store.
* Make prompt be consistent with CLI
* Check max number of key images from per user to node
* Implement error message on get_output_blacklist failure
* Remove resolved TODO's/comments
* Handle infinite staking in print_sn
* Atoi->strtol, fix prepare_registration, virtual override, stale msgs
2019-02-14 02:12:57 +01:00
uint64_t expiry_height = old_info . registration_height + staking_num_lock_blocks ( m_blockchain . nettype ( ) ) ;
2019-01-25 04:15:52 +01:00
if ( block_height < expiry_height )
return false ;
// 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 false ;
}
2018-10-16 01:32:35 +02:00
}
2018-07-28 08:27:04 +02:00
2019-01-25 04:15:52 +01:00
if ( m_service_node_pubkey & & * m_service_node_pubkey = = key )
2018-10-16 01:32:35 +02:00
{
2019-01-25 04:15:52 +01:00
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 ) ;
}
2018-10-16 01:32:35 +02:00
}
else
{
2019-01-25 04:15:52 +01:00
LOG_PRINT_L1 ( " New service node registered: " < < key < < " at block height: " < < block_height ) ;
2018-10-16 01:32:35 +02:00
}
2018-09-27 10:31:08 +02:00
}
2018-07-28 08:27:04 +02:00
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back ( std : : unique_ptr < rollback_event > ( new rollback_new ( block_height , key ) ) ) ;
m_transient_state . service_nodes_infos [ key ] = info ;
2018-08-06 15:08:44 +02:00
return true ;
}
2018-07-31 06:06:22 +02:00
void service_node_list : : process_contribution_tx ( const cryptonote : : transaction & tx , uint64_t block_height , uint32_t index )
2018-07-28 08:27:04 +02:00
{
crypto : : public_key pubkey ;
if ( ! cryptonote : : get_service_node_pubkey_from_tx_extra ( tx . extra , pubkey ) )
2019-01-25 04:15:52 +01:00
return ; // Is not a contribution TX don't need to check it.
parsed_tx_contribution parsed_contribution = { } ;
const int hf_version = m_blockchain . get_hard_fork_version ( block_height ) ;
if ( ! get_contribution ( m_blockchain . nettype ( ) , hf_version , tx , block_height , parsed_contribution ) )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Contribution TX: Could not decode contribution for service node: " < < pubkey < < " on height: " < < block_height < < " for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-07-28 08:27:04 +02:00
return ;
2019-01-25 04:15:52 +01:00
}
2018-07-28 08:27:04 +02:00
2019-01-22 00:44:30 +01:00
/// Service node must be registered
2019-05-01 08:01:17 +02:00
auto iter = m_transient_state . service_nodes_infos . find ( pubkey ) ;
if ( iter = = m_transient_state . service_nodes_infos . end ( ) )
2019-01-25 04:15:52 +01:00
{
LOG_PRINT_L1 ( " Contribution TX: Contribution received for service node: " < < pubkey < <
" , but could not be found in the service node list on height: " < < block_height < <
" for tx: " < < cryptonote : : get_transaction_hash ( tx ) < < " \n "
" This could mean that the service node was deregistered before the contribution was processed. " ) ;
2018-07-28 08:27:04 +02:00
return ;
2019-01-25 04:15:52 +01:00
}
2018-07-28 08:27:04 +02:00
2018-08-06 15:08:44 +02:00
service_node_info & info = iter - > second ;
if ( info . is_fully_funded ( ) )
2019-01-25 04:15:52 +01:00
{
LOG_PRINT_L1 ( " Contribution TX: Service node: " < < pubkey < <
" is already fully funded, but contribution received on height: " < < block_height < <
" for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-07-28 08:27:04 +02:00
return ;
2019-01-25 04:15:52 +01:00
}
if ( ! cryptonote : : get_tx_secret_key_from_tx_extra ( tx . extra , parsed_contribution . tx_key ) )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Contribution TX: Failed to get tx secret key from contribution received on height: " < < block_height < < " for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2019-01-25 04:15:52 +01:00
return ;
}
2018-07-28 08:27:04 +02:00
2018-08-06 15:08:44 +02:00
auto & contributors = info . contributors ;
2018-08-07 05:21:56 +02:00
auto contrib_iter = std : : find_if ( contributors . begin ( ) , contributors . end ( ) ,
2019-01-25 04:15:52 +01:00
[ & parsed_contribution ] ( const service_node_info : : contributor_t & contributor ) { return contributor . address = = parsed_contribution . address ; } ) ;
2019-01-22 00:44:30 +01:00
const bool new_contributor = ( contrib_iter = = contributors . end ( ) ) ;
2019-01-25 04:15:52 +01:00
if ( new_contributor )
2018-08-07 05:21:56 +02:00
{
2019-01-25 04:15:52 +01:00
if ( contributors . size ( ) > = MAX_NUMBER_OF_CONTRIBUTORS )
{
LOG_PRINT_L1 ( " Contribution TX: Node is full with max contributors: " < < MAX_NUMBER_OF_CONTRIBUTORS < <
" for service node: " < < pubkey < <
" on height: " < < block_height < <
" for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
2018-08-07 05:21:56 +02:00
return ;
2019-01-25 04:15:52 +01:00
}
2019-01-22 00:44:30 +01:00
/// Check that the contribution is large enough
const uint8_t hf_version = m_blockchain . get_hard_fork_version ( block_height ) ;
Infinite Staking Part 2 (#406)
* Cleanup and undoing some protocol breakages
* Simplify expiration of nodes
* Request unlock schedules entire node for expiration
* Fix off by one in expiring nodes
* Undo expiring code for pre v10 nodes
* Fix RPC returning register as unlock height and not checking 0
* Rename key image unlock height const
* Undo testnet hardfork debug changes
* Remove is_type for get_type, fix missing var rename
* Move serialisable data into public namespace
* Serialise tx types properly
* Fix typo in no service node known msg
* Code review
* Fix == to >= on serialising tx type
* Code review 2
* Fix tests and key image unlock
* Add command to print locked key images
* Update ui to display lock stakes, query in print cmd blacklist
* Modify print stakes to be less slow
* Remove autostaking code
* Refactor staking into sweep functions
It appears staking was derived off stake_main written separately at
implementation at the beginning. This merges them back into a common
code path, after removing autostake there's only some minor differences.
It also makes sure that any changes to sweeping upstream are going to be
considered in the staking process which we want.
* Display unlock height for stakes
* Begin creating output blacklist
* Make blacklist output a migration step
* Implement get_output_blacklist for lmdb
* In wallet output selection ignore blacklisted outputs
* Apply blacklisted outputs to output selection
* Fix broken tests, switch key image unlock
* Fix broken unit_tests
* Begin change to limit locked key images to 4 globally
* Revamp prepare registration for new min contribution rules
* Fix up old back case in prepare registration
* Remove debug code
* Cleanup debug code and some unecessary changes
* Fix migration step on mainnet db
* Fix blacklist outputs for pre-existing DB's
* Remove irrelevant note
* Tweak scanning addresses for locked stakes
Since we only now allow contributions from the primary address we can
skip checking all subaddress + lookahead to speed up wallet scanning
* Define macro for SCNu64 for Mingw
* Fix failure on empty DB
* Add missing error msg, remove contributor from stake
* Improve staking messages
* Flush prompt to always display
* Return the msg from stake failure and fix stake parsing error
* Tweak fork rules for smaller bulletproofs
* Tweak pooled nodes minimum amounts
* Fix crash on exit, there's no need to store on destructor
Since all information about service nodes is derived from the blockchain
and we store state every time we receive a block, storing in the
destructor is redundant as there is no new information to store.
* Make prompt be consistent with CLI
* Check max number of key images from per user to node
* Implement error message on get_output_blacklist failure
* Remove resolved TODO's/comments
* Handle infinite staking in print_sn
* Atoi->strtol, fix prepare_registration, virtual override, stale msgs
2019-02-14 02:12:57 +01:00
const uint64_t min_contribution = get_min_node_contribution ( hf_version , info . staking_requirement , info . total_reserved , info . total_num_locked_contributions ( ) ) ;
2019-01-25 04:15:52 +01:00
if ( parsed_contribution . transferred < min_contribution )
{
LOG_PRINT_L1 ( " Contribution TX: Amount " < < parsed_contribution . transferred < <
" did not meet min " < < min_contribution < <
" for service node: " < < pubkey < <
" on height: " < < block_height < <
" for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
return ;
}
2018-08-07 05:21:56 +02:00
}
2018-06-29 06:47:00 +02:00
2019-01-25 04:15:52 +01:00
//
// Successfully Validated
//
2018-06-29 06:47:00 +02:00
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back ( std : : unique_ptr < rollback_event > ( new rollback_change ( block_height , pubkey , info ) ) ) ;
2019-01-22 00:44:30 +01:00
if ( new_contributor )
2018-08-07 05:21:56 +02:00
{
2019-01-25 04:15:52 +01:00
service_node_info : : contributor_t new_contributor = { } ;
new_contributor . version = get_min_service_node_info_version_for_hf ( hf_version ) ;
new_contributor . address = parsed_contribution . address ;
info . contributors . push_back ( new_contributor ) ;
2018-08-07 05:21:56 +02:00
contrib_iter = - - contributors . end ( ) ;
}
2018-06-29 06:47:00 +02:00
2019-01-25 04:15:52 +01:00
service_node_info : : contributor_t & 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 ;
2019-01-25 04:15:52 +01:00
uint64_t max_amount = contributor . reserved + can_increase_reserved_by ;
parsed_contribution . transferred = std : : min ( max_amount - contributor . amount , parsed_contribution . transferred ) ;
2018-06-29 06:47:00 +02:00
2019-01-25 04:15:52 +01:00
contributor . amount + = parsed_contribution . transferred ;
info . total_contributed + = parsed_contribution . transferred ;
2018-08-06 15:08:44 +02:00
if ( contributor . amount > contributor . reserved )
{
info . total_reserved + = contributor . amount - contributor . reserved ;
contributor . reserved = contributor . amount ;
}
2018-06-29 06:47:00 +02:00
2019-01-25 04:15:52 +01:00
info . last_reward_block_height = block_height ;
info . last_reward_transaction_index = index ;
Infinite Staking Part 2 (#406)
* Cleanup and undoing some protocol breakages
* Simplify expiration of nodes
* Request unlock schedules entire node for expiration
* Fix off by one in expiring nodes
* Undo expiring code for pre v10 nodes
* Fix RPC returning register as unlock height and not checking 0
* Rename key image unlock height const
* Undo testnet hardfork debug changes
* Remove is_type for get_type, fix missing var rename
* Move serialisable data into public namespace
* Serialise tx types properly
* Fix typo in no service node known msg
* Code review
* Fix == to >= on serialising tx type
* Code review 2
* Fix tests and key image unlock
* Add command to print locked key images
* Update ui to display lock stakes, query in print cmd blacklist
* Modify print stakes to be less slow
* Remove autostaking code
* Refactor staking into sweep functions
It appears staking was derived off stake_main written separately at
implementation at the beginning. This merges them back into a common
code path, after removing autostake there's only some minor differences.
It also makes sure that any changes to sweeping upstream are going to be
considered in the staking process which we want.
* Display unlock height for stakes
* Begin creating output blacklist
* Make blacklist output a migration step
* Implement get_output_blacklist for lmdb
* In wallet output selection ignore blacklisted outputs
* Apply blacklisted outputs to output selection
* Fix broken tests, switch key image unlock
* Fix broken unit_tests
* Begin change to limit locked key images to 4 globally
* Revamp prepare registration for new min contribution rules
* Fix up old back case in prepare registration
* Remove debug code
* Cleanup debug code and some unecessary changes
* Fix migration step on mainnet db
* Fix blacklist outputs for pre-existing DB's
* Remove irrelevant note
* Tweak scanning addresses for locked stakes
Since we only now allow contributions from the primary address we can
skip checking all subaddress + lookahead to speed up wallet scanning
* Define macro for SCNu64 for Mingw
* Fix failure on empty DB
* Add missing error msg, remove contributor from stake
* Improve staking messages
* Flush prompt to always display
* Return the msg from stake failure and fix stake parsing error
* Tweak fork rules for smaller bulletproofs
* Tweak pooled nodes minimum amounts
* Fix crash on exit, there's no need to store on destructor
Since all information about service nodes is derived from the blockchain
and we store state every time we receive a block, storing in the
destructor is redundant as there is no new information to store.
* Make prompt be consistent with CLI
* Check max number of key images from per user to node
* Implement error message on get_output_blacklist failure
* Remove resolved TODO's/comments
* Handle infinite staking in print_sn
* Atoi->strtol, fix prepare_registration, virtual override, stale msgs
2019-02-14 02:12:57 +01:00
const size_t max_contributions_per_node = service_nodes : : MAX_KEY_IMAGES_PER_CONTRIBUTOR * MAX_NUMBER_OF_CONTRIBUTORS ;
2019-02-25 08:05:20 +01:00
if ( hf_version > = cryptonote : : network_version_11_infinite_staking )
2019-01-25 04:15:52 +01:00
{
std : : vector < service_node_info : : contribution_t > & locked_contributions = contributor . locked_contributions ;
2018-07-28 08:27:04 +02:00
2019-01-25 04:15:52 +01:00
for ( const service_node_info : : contribution_t & contribution : parsed_contribution . locked_contributions )
Infinite Staking Part 2 (#406)
* Cleanup and undoing some protocol breakages
* Simplify expiration of nodes
* Request unlock schedules entire node for expiration
* Fix off by one in expiring nodes
* Undo expiring code for pre v10 nodes
* Fix RPC returning register as unlock height and not checking 0
* Rename key image unlock height const
* Undo testnet hardfork debug changes
* Remove is_type for get_type, fix missing var rename
* Move serialisable data into public namespace
* Serialise tx types properly
* Fix typo in no service node known msg
* Code review
* Fix == to >= on serialising tx type
* Code review 2
* Fix tests and key image unlock
* Add command to print locked key images
* Update ui to display lock stakes, query in print cmd blacklist
* Modify print stakes to be less slow
* Remove autostaking code
* Refactor staking into sweep functions
It appears staking was derived off stake_main written separately at
implementation at the beginning. This merges them back into a common
code path, after removing autostake there's only some minor differences.
It also makes sure that any changes to sweeping upstream are going to be
considered in the staking process which we want.
* Display unlock height for stakes
* Begin creating output blacklist
* Make blacklist output a migration step
* Implement get_output_blacklist for lmdb
* In wallet output selection ignore blacklisted outputs
* Apply blacklisted outputs to output selection
* Fix broken tests, switch key image unlock
* Fix broken unit_tests
* Begin change to limit locked key images to 4 globally
* Revamp prepare registration for new min contribution rules
* Fix up old back case in prepare registration
* Remove debug code
* Cleanup debug code and some unecessary changes
* Fix migration step on mainnet db
* Fix blacklist outputs for pre-existing DB's
* Remove irrelevant note
* Tweak scanning addresses for locked stakes
Since we only now allow contributions from the primary address we can
skip checking all subaddress + lookahead to speed up wallet scanning
* Define macro for SCNu64 for Mingw
* Fix failure on empty DB
* Add missing error msg, remove contributor from stake
* Improve staking messages
* Flush prompt to always display
* Return the msg from stake failure and fix stake parsing error
* Tweak fork rules for smaller bulletproofs
* Tweak pooled nodes minimum amounts
* Fix crash on exit, there's no need to store on destructor
Since all information about service nodes is derived from the blockchain
and we store state every time we receive a block, storing in the
destructor is redundant as there is no new information to store.
* Make prompt be consistent with CLI
* Check max number of key images from per user to node
* Implement error message on get_output_blacklist failure
* Remove resolved TODO's/comments
* Handle infinite staking in print_sn
* Atoi->strtol, fix prepare_registration, virtual override, stale msgs
2019-02-14 02:12:57 +01:00
{
if ( info . total_num_locked_contributions ( ) < max_contributions_per_node )
contributor . locked_contributions . push_back ( contribution ) ;
else
{
LOG_PRINT_L1 ( " Contribution TX: Already hit the max number of contributions: " < < max_contributions_per_node < <
" for contributor: " < < cryptonote : : get_account_address_as_str ( m_blockchain . nettype ( ) , false , contributor . address ) < <
" on height: " < < block_height < <
" for tx: " < < cryptonote : : get_transaction_hash ( tx ) ) ;
break ;
}
}
2019-01-25 04:15:52 +01:00
}
2018-07-28 08:27:04 +02:00
2019-01-25 04:15:52 +01:00
LOG_PRINT_L1 ( " Contribution of " < < parsed_contribution . transferred < < " received for service node " < < pubkey ) ;
2018-07-18 08:51:26 +02:00
}
2018-06-29 06:47:00 +02:00
2018-07-18 08:51:26 +02:00
void service_node_list : : block_added ( const cryptonote : : block & block , const std : : vector < cryptonote : : transaction > & txs )
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2019-04-11 07:08:26 +02:00
process_block ( block , txs ) ;
2018-08-16 05:08:36 +02:00
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
2019-04-11 07:08:26 +02:00
void service_node_list : : process_block ( const cryptonote : : block & block , const std : : vector < cryptonote : : transaction > & txs )
2018-06-29 06:47:00 +02:00
{
uint64_t block_height = cryptonote : : get_block_height ( block ) ;
int hard_fork_version = m_blockchain . get_hard_fork_version ( block_height ) ;
2018-07-18 08:51:26 +02:00
if ( hard_fork_version < 9 )
2018-06-29 06:47:00 +02:00
return ;
2019-01-25 04:15:52 +01:00
//
// Remove old rollback events
//
2018-06-29 06:47:00 +02:00
{
2019-05-01 08:01:17 +02:00
assert ( m_transient_state . height = = block_height ) ;
+ + m_transient_state . height ;
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 ;
2019-05-01 08:01:17 +02:00
while ( ! m_transient_state . rollback_events . empty ( ) & & m_transient_state . rollback_events . front ( ) - > m_block_height < cull_height )
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
{
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . pop_front ( ) ;
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
}
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_front ( std : : unique_ptr < rollback_event > ( new prevent_rollback ( cull_height ) ) ) ;
2018-06-29 06:47:00 +02:00
}
2019-01-25 04:15:52 +01:00
//
// Remove expired blacklisted key images
//
2019-05-01 08:01:17 +02:00
for ( auto entry = m_transient_state . key_image_blacklist . begin ( ) ; entry ! = m_transient_state . key_image_blacklist . end ( ) ; )
2019-01-25 04:15:52 +01:00
{
if ( block_height > = entry - > unlock_height )
{
const bool adding_to_blacklist = false ;
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back ( std : : unique_ptr < rollback_event > ( new rollback_key_image_blacklist ( block_height , ( * entry ) , adding_to_blacklist ) ) ) ;
entry = m_transient_state . key_image_blacklist . erase ( entry ) ;
2019-01-25 04:15:52 +01:00
}
else
entry + + ;
}
2018-11-16 00:32:56 +01:00
2019-01-25 04:15:52 +01:00
//
// Expire Nodes
//
size_t expired_count = 0 ;
for ( const crypto : : public_key & pubkey : update_and_get_expired_nodes ( txs , block_height ) )
2018-08-05 05:08:51 +02:00
{
2019-05-01 08:01:17 +02:00
auto i = m_transient_state . service_nodes_infos . find ( pubkey ) ;
if ( i ! = m_transient_state . service_nodes_infos . end ( ) )
2018-08-05 05:08:51 +02:00
{
2018-10-16 01:32:35 +02:00
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 ) ;
}
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back ( std : : unique_ptr < rollback_event > ( new rollback_change ( block_height , pubkey , i - > second ) ) ) ;
2018-11-16 00:32:56 +01:00
expired_count + + ;
2019-05-01 08:01:17 +02:00
m_transient_state . service_nodes_infos . erase ( i ) ;
2018-08-05 05:08:51 +02:00
}
}
2019-01-25 04:15:52 +01:00
//
// Advance the list to the next candidate for a reward
//
2018-06-29 06:47:00 +02:00
{
2019-01-25 04:15:52 +01:00
crypto : : public_key winner_pubkey = cryptonote : : get_service_node_winner_from_tx_extra ( block . miner_tx . extra ) ;
2019-05-01 08:01:17 +02:00
if ( m_transient_state . service_nodes_infos . count ( winner_pubkey ) = = 1 )
2019-01-25 04:15:52 +01:00
{
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back (
2019-01-25 04:15:52 +01:00
std : : unique_ptr < rollback_event > (
2019-05-01 08:01:17 +02:00
new rollback_change ( block_height , winner_pubkey , m_transient_state . service_nodes_infos [ winner_pubkey ] )
2019-01-25 04:15:52 +01:00
)
) ;
// set the winner as though it was re-registering at transaction index=UINT32_MAX for this block
2019-05-01 08:01:17 +02:00
m_transient_state . service_nodes_infos [ winner_pubkey ] . last_reward_block_height = block_height ;
m_transient_state . service_nodes_infos [ winner_pubkey ] . last_reward_transaction_index = UINT32_MAX ;
2019-01-25 04:15:52 +01:00
}
2018-06-29 06:47:00 +02:00
}
2019-01-25 04:15:52 +01:00
//
// Process TXs in the Block
//
2018-11-16 00:32:56 +01:00
size_t registrations = 0 ;
size_t deregistrations = 0 ;
2019-01-25 04:15:52 +01:00
for ( uint32_t index = 0 ; index < txs . size ( ) ; + + index )
2018-06-29 06:47:00 +02:00
{
2019-01-25 04:15:52 +01:00
const cryptonote : : transaction & tx = txs [ index ] ;
const cryptonote : : transaction : : type_t tx_type = tx . get_type ( ) ;
if ( tx_type = = cryptonote : : transaction : : type_standard )
{
if ( process_registration_tx ( tx , block . timestamp , block_height , index ) )
registrations + + ;
process_contribution_tx ( tx , block_height , index ) ;
2018-11-16 00:32:56 +01:00
}
2019-01-25 04:15:52 +01:00
else if ( tx_type = = cryptonote : : transaction : : type_deregister )
{
if ( process_deregistration_tx ( tx , block_height ) )
deregistrations + + ;
}
else if ( tx_type = = cryptonote : : transaction : : type_key_image_unlock )
{
crypto : : public_key snode_key ;
if ( ! cryptonote : : get_service_node_pubkey_from_tx_extra ( tx . extra , snode_key ) )
continue ;
2019-05-01 08:01:17 +02:00
auto it = m_transient_state . service_nodes_infos . find ( snode_key ) ;
if ( it = = m_transient_state . service_nodes_infos . end ( ) )
2019-01-25 04:15:52 +01:00
continue ;
service_node_info & node_info = ( * it ) . second ;
if ( node_info . requested_unlock_height ! = KEY_IMAGE_AWAITING_UNLOCK_HEIGHT )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Unlock TX: Node already requested an unlock at height: " < < node_info . requested_unlock_height < < " rejected on height: " < < block_height < < " for tx: " < < get_transaction_hash ( tx ) ) ;
2019-01-25 04:15:52 +01:00
continue ;
}
cryptonote : : tx_extra_tx_key_image_unlock unlock ;
if ( ! cryptonote : : get_tx_key_image_unlock_from_tx_extra ( tx . extra , unlock ) )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Unlock TX: Didn't have key image unlock in the tx_extra, rejected on height: " < < block_height < < " for tx: " < < get_transaction_hash ( tx ) ) ;
2019-01-25 04:15:52 +01:00
continue ;
}
uint64_t unlock_height = get_locked_key_image_unlock_height ( m_blockchain . nettype ( ) , node_info . registration_height , block_height ) ;
bool early_exit = false ;
for ( auto contributor = node_info . contributors . begin ( ) ;
contributor ! = node_info . contributors . end ( ) & & ! early_exit ;
contributor + + )
{
for ( auto locked_contribution = contributor - > locked_contributions . begin ( ) ;
locked_contribution ! = contributor - > locked_contributions . end ( ) & & ! early_exit ;
locked_contribution + + )
{
if ( unlock . key_image ! = locked_contribution - > key_image )
continue ;
// NOTE(loki): This should be checked in blockchain check_tx_inputs already
crypto : : hash const hash = service_nodes : : generate_request_stake_unlock_hash ( unlock . nonce ) ;
2019-01-29 01:34:33 +01:00
if ( ! crypto : : check_signature ( hash , locked_contribution - > key_image_pub_key , unlock . signature ) )
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Unlock TX: Couldn't verify key image unlock in the tx_extra, rejected on height: " < < block_height < < " for tx: " < < get_transaction_hash ( tx ) ) ;
2019-01-29 01:34:33 +01:00
early_exit = true ;
break ;
}
2019-01-25 04:15:52 +01:00
node_info . requested_unlock_height = unlock_height ;
early_exit = true ;
}
}
2018-11-16 00:32:56 +01:00
}
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-11-16 00:32:56 +01:00
if ( registrations | | deregistrations | | expired_count ) {
update_swarms ( block_height ) ;
}
2019-01-25 04:15:52 +01:00
//
// Update Quorum
//
2019-05-01 08:01:17 +02:00
generate_quorums ( block ) ;
2018-08-14 07:41:30 +02:00
const size_t cache_state_from_height = ( block_height < QUORUM_LIFETIME ) ? 0 : block_height - QUORUM_LIFETIME ;
2019-05-01 08:01:17 +02:00
while ( ! m_transient_state . quorum_states . empty ( ) & & m_transient_state . quorum_states . begin ( ) - > first < cache_state_from_height )
m_transient_state . quorum_states . erase ( m_transient_state . quorum_states . begin ( ) ) ;
2018-06-29 06:47:00 +02:00
}
void service_node_list : : blockchain_detached ( uint64_t height )
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2019-05-01 08:01:17 +02:00
while ( ! m_transient_state . rollback_events . empty ( ) & & m_transient_state . rollback_events . back ( ) - > m_block_height > = height )
2018-06-29 06:47:00 +02:00
{
2019-05-01 08:01:17 +02:00
rollback_event * event = & ( * m_transient_state . rollback_events . back ( ) ) ;
2019-01-25 04:15:52 +01:00
bool rollback_applied = true ;
switch ( event - > type )
{
case rollback_event : : change_type :
{
auto * rollback = reinterpret_cast < rollback_change * > ( event ) ;
2019-05-01 08:01:17 +02:00
m_transient_state . service_nodes_infos [ rollback - > m_key ] = rollback - > m_info ;
2019-01-25 04:15:52 +01:00
}
break ;
case rollback_event : : new_type :
{
auto * rollback = reinterpret_cast < rollback_new * > ( event ) ;
2019-05-01 08:01:17 +02:00
auto iter = m_transient_state . service_nodes_infos . find ( rollback - > m_key ) ;
if ( iter = = m_transient_state . service_nodes_infos . end ( ) )
2019-01-25 04:15:52 +01:00
{
MERROR ( " Could not find service node pubkey in rollback new " ) ;
rollback_applied = false ;
break ;
}
2019-05-01 08:01:17 +02:00
m_transient_state . service_nodes_infos . erase ( iter ) ;
2019-01-25 04:15:52 +01:00
}
break ;
case rollback_event : : prevent_type : { rollback_applied = false ; } break ;
case rollback_event : : key_image_blacklist_type :
{
auto * rollback = reinterpret_cast < rollback_key_image_blacklist * > ( event ) ;
if ( rollback - > m_was_adding_to_blacklist )
{
2019-05-01 08:01:17 +02:00
auto it = std : : find_if ( m_transient_state . key_image_blacklist . begin ( ) , m_transient_state . key_image_blacklist . end ( ) ,
2019-01-25 04:15:52 +01:00
[ rollback ] ( key_image_blacklist_entry const & a ) {
return ( rollback - > m_entry . unlock_height = = a . unlock_height & & rollback - > m_entry . key_image = = a . key_image ) ;
} ) ;
2019-05-01 08:01:17 +02:00
if ( it = = m_transient_state . key_image_blacklist . end ( ) )
2019-01-25 04:15:52 +01:00
{
2019-03-13 06:34:46 +01:00
LOG_PRINT_L1 ( " Could not find blacklisted key image to remove " ) ;
2019-01-25 04:15:52 +01:00
rollback_applied = false ;
break ;
}
2019-05-01 08:01:17 +02:00
m_transient_state . key_image_blacklist . erase ( it ) ;
2019-01-25 04:15:52 +01:00
}
else
{
2019-05-01 08:01:17 +02:00
m_transient_state . key_image_blacklist . push_back ( rollback - > m_entry ) ;
2019-01-25 04:15:52 +01:00
}
}
break ;
default :
{
MERROR ( " Unhandled rollback type " ) ;
rollback_applied = false ;
}
break ;
}
if ( ! rollback_applied )
2018-06-29 06:47:00 +02:00
{
init ( ) ;
break ;
}
2019-01-25 04:15:52 +01:00
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . pop_back ( ) ;
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
2019-05-01 08:01:17 +02:00
while ( ! m_transient_state . quorum_states . empty ( ) & & ( - - m_transient_state . quorum_states . end ( ) ) - > first > = height )
m_transient_state . quorum_states . erase ( - - m_transient_state . quorum_states . end ( ) ) ;
2018-08-08 10:51:14 +02:00
2019-05-01 08:01:17 +02:00
m_transient_state . height = height ;
2018-08-16 05:08:36 +02:00
store ( ) ;
2018-06-29 06:47:00 +02:00
}
2019-01-25 04:15:52 +01:00
std : : vector < crypto : : public_key > service_node_list : : update_and_get_expired_nodes ( const std : : vector < cryptonote : : transaction > & txs , uint64_t block_height )
2018-06-29 06:47:00 +02:00
{
2018-07-18 08:51:26 +02:00
std : : vector < crypto : : public_key > expired_nodes ;
Infinite Staking Part 2 (#406)
* Cleanup and undoing some protocol breakages
* Simplify expiration of nodes
* Request unlock schedules entire node for expiration
* Fix off by one in expiring nodes
* Undo expiring code for pre v10 nodes
* Fix RPC returning register as unlock height and not checking 0
* Rename key image unlock height const
* Undo testnet hardfork debug changes
* Remove is_type for get_type, fix missing var rename
* Move serialisable data into public namespace
* Serialise tx types properly
* Fix typo in no service node known msg
* Code review
* Fix == to >= on serialising tx type
* Code review 2
* Fix tests and key image unlock
* Add command to print locked key images
* Update ui to display lock stakes, query in print cmd blacklist
* Modify print stakes to be less slow
* Remove autostaking code
* Refactor staking into sweep functions
It appears staking was derived off stake_main written separately at
implementation at the beginning. This merges them back into a common
code path, after removing autostake there's only some minor differences.
It also makes sure that any changes to sweeping upstream are going to be
considered in the staking process which we want.
* Display unlock height for stakes
* Begin creating output blacklist
* Make blacklist output a migration step
* Implement get_output_blacklist for lmdb
* In wallet output selection ignore blacklisted outputs
* Apply blacklisted outputs to output selection
* Fix broken tests, switch key image unlock
* Fix broken unit_tests
* Begin change to limit locked key images to 4 globally
* Revamp prepare registration for new min contribution rules
* Fix up old back case in prepare registration
* Remove debug code
* Cleanup debug code and some unecessary changes
* Fix migration step on mainnet db
* Fix blacklist outputs for pre-existing DB's
* Remove irrelevant note
* Tweak scanning addresses for locked stakes
Since we only now allow contributions from the primary address we can
skip checking all subaddress + lookahead to speed up wallet scanning
* Define macro for SCNu64 for Mingw
* Fix failure on empty DB
* Add missing error msg, remove contributor from stake
* Improve staking messages
* Flush prompt to always display
* Return the msg from stake failure and fix stake parsing error
* Tweak fork rules for smaller bulletproofs
* Tweak pooled nodes minimum amounts
* Fix crash on exit, there's no need to store on destructor
Since all information about service nodes is derived from the blockchain
and we store state every time we receive a block, storing in the
destructor is redundant as there is no new information to store.
* Make prompt be consistent with CLI
* Check max number of key images from per user to node
* Implement error message on get_output_blacklist failure
* Remove resolved TODO's/comments
* Handle infinite staking in print_sn
* Atoi->strtol, fix prepare_registration, virtual override, stale msgs
2019-02-14 02:12:57 +01:00
uint64_t const lock_blocks = staking_num_lock_blocks ( m_blockchain . nettype ( ) ) ;
2018-08-08 06:57:07 +02:00
2019-01-25 04:15:52 +01:00
// TODO(loki): This should really use the registration height instead of getting the block and expiring nodes.
// But there's something subtly off when using registration height causing syncing problems.
if ( m_blockchain . get_hard_fork_version ( block_height ) = = cryptonote : : network_version_9_service_nodes )
2018-06-29 06:47:00 +02:00
{
2019-01-25 04:15:52 +01:00
if ( block_height < lock_blocks )
return expired_nodes ;
2018-06-29 06:47:00 +02:00
2018-10-16 01:32:35 +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
{
2019-01-25 04:15:52 +01:00
LOG_ERROR ( " Unable to get historical blocks " ) ;
return expired_nodes ;
2018-10-16 01:32:35 +02:00
}
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 ;
2018-11-16 00:32:56 +01:00
service_node_info info = { } ;
2018-10-16 01:32:35 +02:00
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
}
}
2019-01-25 04:15:52 +01:00
else
{
2019-05-01 08:01:17 +02:00
for ( auto it = m_transient_state . service_nodes_infos . begin ( ) ; it ! = m_transient_state . service_nodes_infos . end ( ) ; it + + )
2019-01-25 04:15:52 +01:00
{
crypto : : public_key const & snode_key = it - > first ;
service_node_info & info = it - > second ;
int const hf_version = m_blockchain . get_hard_fork_version ( info . registration_height ) ;
2019-02-25 08:05:20 +01:00
if ( hf_version > = cryptonote : : network_version_11_infinite_staking )
2019-01-25 04:15:52 +01:00
{
if ( info . requested_unlock_height ! = KEY_IMAGE_AWAITING_UNLOCK_HEIGHT & & block_height > info . requested_unlock_height )
expired_nodes . push_back ( snode_key ) ;
}
else // Version 10 Bulletproofs
{
2019-03-18 00:48:50 +01:00
/// Note: this code exhibits a sublte unintended behaviour: a snode that
/// registered in hardfork 9 and was scheduled for deregistration in hardfork 10
/// will have its life is slightly prolonged by the "grace period", although it might
/// look like we use the registration height to determine the expiry height.
2019-01-25 04:15:52 +01:00
uint64_t node_expiry_height = info . registration_height + lock_blocks + STAKING_REQUIREMENT_LOCK_BLOCKS_EXCESS ;
if ( block_height > node_expiry_height )
expired_nodes . push_back ( snode_key ) ;
}
}
}
2018-06-29 06:47:00 +02:00
return expired_nodes ;
}
2019-01-25 04:15:52 +01:00
std : : vector < std : : pair < cryptonote : : account_public_address , uint64_t > > service_node_list : : get_winner_addresses_and_portions ( ) const
2018-07-18 08:51:26 +02:00
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2019-01-25 04:15:52 +01:00
crypto : : public_key key = select_winner ( ) ;
2018-07-18 08:51:26 +02:00
if ( key = = crypto : : null_pkey )
2018-07-31 04:46:12 +02:00
return { std : : make_pair ( null_address , STAKING_PORTIONS ) } ;
2018-08-06 15:08:44 +02:00
2018-08-18 06:36:16 +02:00
std : : vector < std : : pair < cryptonote : : account_public_address , uint64_t > > winners ;
2018-08-06 15:08:44 +02:00
2019-05-01 08:01:17 +02:00
const service_node_info & info = m_transient_state . service_nodes_infos . at ( key ) ;
2018-07-28 08:27:04 +02:00
2018-08-07 04:28:59 +02:00
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.
2018-08-07 05:21:56 +02:00
for ( const auto & contributor : info . contributors )
2018-08-06 15:08:44 +02:00
{
2018-07-28 08:27:04 +02:00
uint64_t hi , lo , resulthi , resultlo ;
2018-08-07 05:21:56 +02:00
lo = mul128 ( contributor . amount , remaining_portions , & hi ) ;
2018-08-06 15:08:44 +02:00
div128_64 ( hi , lo , info . staking_requirement , & resulthi , & resultlo ) ;
2018-07-28 08:27:04 +02:00
2018-08-07 04:28:59 +02:00
if ( contributor . address = = info . operator_address )
resultlo + = info . portions_for_operator ;
2018-08-07 05:21:56 +02:00
winners . push_back ( std : : make_pair ( contributor . address , resultlo ) ) ;
2018-07-28 08:27:04 +02:00
}
2018-07-18 08:51:26 +02:00
return winners ;
}
2019-01-25 04:15:52 +01:00
crypto : : public_key service_node_list : : select_winner ( ) const
2018-06-29 06:47:00 +02:00
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2018-07-31 06:06:22 +02:00
auto oldest_waiting = std : : pair < uint64_t , uint32_t > ( std : : numeric_limits < uint64_t > : : max ( ) , std : : numeric_limits < uint32_t > : : max ( ) ) ;
2018-07-18 08:51:26 +02:00
crypto : : public_key key = crypto : : null_pkey ;
2019-05-01 08:01:17 +02:00
for ( const auto & info : m_transient_state . service_nodes_infos )
2018-07-28 08:27:04 +02:00
if ( info . second . is_fully_funded ( ) )
2018-06-29 06:47:00 +02:00
{
2018-07-28 08:27:04 +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
}
2018-07-18 08:51:26 +02:00
return key ;
2018-06-29 06:47:00 +02:00
}
2018-11-12 04:02:21 +01:00
bool service_node_list : : validate_miner_tx ( const crypto : : hash & prev_id , const cryptonote : : transaction & miner_tx , uint64_t height , int hard_fork_version , cryptonote : : block_reward_parts const & reward_parts ) const
2018-06-29 06:47:00 +02:00
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2018-07-18 08:51:26 +02:00
if ( hard_fork_version < 9 )
2018-06-29 06:47:00 +02:00
return true ;
2018-11-12 04:02:21 +01:00
// NOTE(loki): Service node reward distribution is calculated from the
// original amount, i.e. 50% of the original base reward goes to service
// nodes not 50% of the reward after removing the governance component (the
// adjusted base reward post hardfork 10).
uint64_t base_reward = reward_parts . original_base_reward ;
uint64_t total_service_node_reward = cryptonote : : service_node_reward_formula ( base_reward , hard_fork_version ) ;
2018-06-29 06:47:00 +02:00
2019-01-25 04:15:52 +01:00
crypto : : public_key winner = select_winner ( ) ;
2018-07-18 08:51:26 +02:00
crypto : : public_key check_winner_pubkey = cryptonote : : get_service_node_winner_from_tx_extra ( miner_tx . extra ) ;
2019-03-19 08:29:27 +01:00
if ( check_winner_pubkey ! = winner ) {
MERROR ( " Service node reward winner is incorrect " ) ;
2018-06-29 06:47:00 +02:00
return false ;
2019-03-19 08:29:27 +01:00
}
2018-06-29 06:47:00 +02:00
2019-01-25 04:15:52 +01:00
const std : : vector < std : : pair < cryptonote : : account_public_address , uint64_t > > addresses_and_portions = get_winner_addresses_and_portions ( ) ;
2018-07-28 08:27:04 +02:00
2018-07-31 04:46:12 +02:00
if ( miner_tx . vout . size ( ) - 1 < addresses_and_portions . size ( ) )
2018-06-29 06:47:00 +02:00
return false ;
2018-07-31 04:46:12 +02:00
for ( size_t i = 0 ; i < addresses_and_portions . size ( ) ; i + + )
2018-06-29 06:47:00 +02:00
{
2018-11-12 04:02:21 +01:00
size_t vout_index = i + 1 ;
2018-07-31 04:46:12 +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
2018-07-18 08:51:26 +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
2018-07-18 08:51:26 +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 ) ;
2018-07-31 04:46:12 +02:00
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 < < " ) " ) ;
2018-07-18 08:51:26 +02:00
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 ;
}
2019-05-01 08:01:17 +02:00
std : : vector < size_t > generate_shuffled_service_node_index_list ( std : : vector < crypto : : public_key > const & snode_list , crypto : : hash const & block_hash , quorum_type type )
{
std : : vector < size_t > result ( snode_list . size ( ) ) ;
size_t index = 0 ;
for ( size_t i = 0 ; i < snode_list . size ( ) ; i + + ) result [ i ] = i ;
uint64_t seed = 0 ;
std : : memcpy ( & seed , block_hash . data , std : : min ( sizeof ( seed ) , sizeof ( block_hash . data ) ) ) ;
seed + = static_cast < uint64_t > ( type ) ;
loki_shuffle ( result , seed ) ;
return result ;
}
void service_node_list : : generate_quorums ( cryptonote : : block const & block )
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
{
2019-05-01 08:01:17 +02:00
crypto : : hash block_hash ;
uint64_t const height = cryptonote : : get_block_height ( block ) ;
if ( ! cryptonote : : get_block_hash ( block , block_hash ) )
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
{
MERROR ( " Block height: " < < height < < " returned null hash " ) ;
return ;
}
2019-05-01 08:01:17 +02:00
std : : vector < crypto : : public_key > const snode_list = get_service_nodes_pubkeys ( ) ;
for ( int type_int = 0 ; type_int < static_cast < int > ( quorum_type : : count ) ; type_int + + )
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
{
2019-05-01 08:01:17 +02:00
auto type = static_cast < quorum_type > ( type_int ) ;
std : : vector < size_t > const pub_keys_indexes = generate_shuffled_service_node_index_list ( snode_list , block_hash , type ) ;
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
2019-05-01 08:01:17 +02:00
switch ( type )
{
case quorum_type : : uptime_proof :
{
// Assign indexes from shuffled list into quorum and list of nodes to test
auto new_state = std : : make_shared < quorum_uptime_proof > ( ) ;
std : : vector < crypto : : public_key > & quorum = new_state - > quorum_nodes ;
{
quorum . resize ( std : : min ( snode_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 = snode_list [ node_index ] ;
quorum [ i ] = key ;
}
}
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
2019-05-01 08:01:17 +02:00
std : : vector < crypto : : public_key > & nodes_to_test = new_state - > nodes_to_test ;
{
size_t num_remaining_nodes = pub_keys_indexes . size ( ) - quorum . size ( ) ;
size_t num_nodes_to_test = std : : max ( num_remaining_nodes / NTH_OF_THE_NETWORK_TO_TEST ,
std : : min ( MIN_NODES_TO_TEST , num_remaining_nodes ) ) ;
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
2019-05-01 08:01:17 +02:00
nodes_to_test . resize ( num_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
2019-05-01 08:01:17 +02:00
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 = snode_list [ node_index ] ;
nodes_to_test [ i ] = key ;
}
}
2018-10-10 07:24:01 +02:00
2019-05-01 08:01:17 +02:00
m_transient_state . quorum_states [ height ] . uptime_proof = 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
}
2019-05-01 08:01:17 +02:00
break ;
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
2019-05-01 08:01:17 +02:00
case quorum_type : : checkpointing :
{
auto new_state = std : : make_shared < quorum_checkpointing > ( ) ;
std : : vector < crypto : : public_key > & quorum = new_state - > quorum_nodes ;
quorum . resize ( std : : min ( snode_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 = snode_list [ node_index ] ;
quorum [ i ] = key ;
}
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
2019-05-01 08:01:17 +02:00
m_transient_state . quorum_states [ height ] . checkpointing = new_state ;
}
break ;
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
2019-05-01 08:01:17 +02:00
default :
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
{
2019-05-01 08:01:17 +02:00
assert ( " Loki Developer Error: Unhandled enum " = = 0 ) ;
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
}
2019-05-01 08:01:17 +02:00
break ;
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-10-10 07:24:01 +02:00
2019-05-01 08:01:17 +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-08-08 06:57:07 +02:00
2018-06-29 06:47:00 +02:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2018-08-16 06:13:57 +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
{
}
2018-07-18 08:51:26 +02:00
service_node_list : : rollback_change : : rollback_change ( uint64_t block_height , const crypto : : public_key & key , const service_node_info & info )
2018-08-16 06:13:57 +02:00
: service_node_list : : rollback_event ( block_height , change_type ) , m_key ( key ) , m_info ( info )
2018-06-29 06:47:00 +02:00
{
}
2018-07-18 08:51:26 +02:00
service_node_list : : rollback_new : : rollback_new ( uint64_t block_height , const crypto : : public_key & key )
2018-08-16 06:13:57 +02:00
: service_node_list : : rollback_event ( block_height , new_type ) , m_key ( key )
2018-06-29 06:47:00 +02:00
{
}
2019-01-25 04:15:52 +01:00
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
2019-01-25 04:15:52 +01:00
service_node_list : : rollback_key_image_blacklist : : rollback_key_image_blacklist ( uint64_t block_height , key_image_blacklist_entry const & entry , bool is_adding_to_blacklist )
: service_node_list : : rollback_event ( block_height , key_image_blacklist_type ) , m_entry ( entry ) , m_was_adding_to_blacklist ( is_adding_to_blacklist )
2018-06-29 06:47:00 +02:00
{
}
2018-08-16 05:08:36 +02:00
bool service_node_list : : store ( )
{
2019-05-01 08:01:17 +02:00
int hf_version = m_blockchain . get_current_hard_fork_version ( ) ;
if ( hf_version < cryptonote : : network_version_9_service_nodes )
2019-01-25 04:15:52 +01:00
return true ;
2018-10-15 03:22:46 +02:00
2018-08-16 06:13:57 +02:00
CHECK_AND_ASSERT_MES ( m_db ! = nullptr , false , " Failed to store service node info, m_db == nullptr " ) ;
2018-08-16 05:08:36 +02:00
data_members_for_serialization data_to_store ;
2018-08-17 07:14:45 +02:00
{
2018-10-15 03:22:46 +02:00
std : : lock_guard < boost : : recursive_mutex > lock ( m_sn_mutex ) ;
2018-08-17 07:14:45 +02:00
2019-05-01 08:01:17 +02:00
for ( const auto & kv_pair : m_transient_state . quorum_states )
2018-10-15 03:22:46 +02:00
{
2019-05-01 08:01:17 +02:00
quorum_for_serialization quorum = { } ;
quorum . version = get_min_service_node_info_version_for_hf ( hf_version ) ;
quorum . height = kv_pair . first ;
quorum_manager const & manager = kv_pair . second ;
if ( manager . uptime_proof )
quorum . uptime_quorum = * manager . uptime_proof ;
if ( quorum . version > = service_node_info : : version_3_checkpointing )
{
if ( manager . checkpointing )
quorum . checkpointing_quorum = * manager . checkpointing ;
}
2018-10-15 03:22:46 +02:00
data_to_store . quorum_states . push_back ( quorum ) ;
}
2018-08-16 05:08:36 +02:00
2019-01-25 04:15:52 +01:00
service_node_pubkey_info info ;
2019-05-01 08:01:17 +02:00
for ( const auto & kv_pair : m_transient_state . service_nodes_infos )
2018-08-16 05:08:36 +02:00
{
2019-01-25 04:15:52 +01:00
info . pubkey = kv_pair . first ;
info . info = kv_pair . second ;
2018-10-15 03:22:46 +02:00
data_to_store . infos . push_back ( info ) ;
2018-08-16 05:08:36 +02:00
}
2018-10-15 03:22:46 +02:00
2019-05-01 08:01:17 +02:00
for ( const auto & event_ptr : m_transient_state . rollback_events )
2018-10-15 03:22:46 +02:00
{
switch ( event_ptr - > type )
{
2019-01-25 04:15:52 +01:00
case rollback_event : : change_type : data_to_store . events . push_back ( * reinterpret_cast < rollback_change * > ( event_ptr . get ( ) ) ) ; break ;
case rollback_event : : new_type : data_to_store . events . push_back ( * reinterpret_cast < rollback_new * > ( event_ptr . get ( ) ) ) ; break ;
case rollback_event : : prevent_type : data_to_store . events . push_back ( * reinterpret_cast < prevent_rollback * > ( event_ptr . get ( ) ) ) ; break ;
case rollback_event : : key_image_blacklist_type : data_to_store . events . push_back ( * reinterpret_cast < rollback_key_image_blacklist * > ( event_ptr . get ( ) ) ) ; break ;
2018-10-15 03:22:46 +02:00
default :
MERROR ( " On storing service node data, unknown rollback event type encountered " ) ;
return false ;
}
}
2019-05-01 08:01:17 +02:00
data_to_store . key_image_blacklist = m_transient_state . key_image_blacklist ;
2018-08-16 05:08:36 +02:00
}
2019-05-01 08:01:17 +02:00
data_to_store . height = m_transient_state . height ;
2019-01-25 04:15:52 +01:00
data_to_store . version = get_min_service_node_info_version_for_hf ( hf_version ) ;
2018-08-16 05:08:36 +02:00
std : : stringstream ss ;
binary_archive < true > ba ( ss ) ;
2018-08-16 06:13:57 +02:00
2018-08-16 05:08:36 +02:00
bool r = : : serialization : : serialize ( ba , data_to_store ) ;
2018-08-16 06:13:57 +02:00
CHECK_AND_ASSERT_MES ( r , false , " Failed to store service node info: failed to serialize data " ) ;
2018-08-16 05:08:36 +02:00
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 ;
}
2019-01-25 00:50:42 +01:00
void service_node_list : : get_all_service_nodes_public_keys ( std : : vector < crypto : : public_key > & keys , bool fully_funded_nodes_only ) const
{
keys . clear ( ) ;
2019-05-01 08:01:17 +02:00
keys . resize ( m_transient_state . service_nodes_infos . size ( ) ) ;
2019-01-25 00:50:42 +01:00
size_t i = 0 ;
if ( fully_funded_nodes_only )
{
2019-05-01 08:01:17 +02:00
for ( const auto & it : m_transient_state . service_nodes_infos )
2019-01-25 00:50:42 +01:00
{
service_node_info const & info = it . second ;
if ( info . is_fully_funded ( ) )
keys [ i + + ] = it . first ;
}
}
else
{
2019-05-01 08:01:17 +02:00
for ( const auto & it : m_transient_state . service_nodes_infos )
2019-01-25 00:50:42 +01:00
keys [ i + + ] = it . first ;
}
}
2018-08-16 05:08:36 +02:00
bool service_node_list : : load ( )
{
2018-08-16 06:13:57 +02:00
LOG_PRINT_L1 ( " service_node_list::load() " ) ;
2018-08-16 05:08:36 +02:00
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 " ) ;
2019-05-01 08:01:17 +02:00
m_transient_state . height = data_in . height ;
m_transient_state . key_image_blacklist = data_in . key_image_blacklist ;
2018-08-16 05:08:36 +02:00
2019-05-01 08:01:17 +02:00
for ( const auto & states : data_in . quorum_states )
2018-08-17 07:14:45 +02:00
{
2019-05-01 08:01:17 +02:00
if ( states . uptime_quorum . quorum_nodes . size ( ) > 0 )
m_transient_state . quorum_states [ states . height ] . uptime_proof = std : : make_shared < quorum_uptime_proof > ( states . uptime_quorum ) ;
if ( states . version > = service_node_info : : version_3_checkpointing )
{
if ( states . checkpointing_quorum . quorum_nodes . size ( ) > 0 )
m_transient_state . quorum_states [ states . height ] . checkpointing = std : : make_shared < quorum_checkpointing > ( states . checkpointing_quorum ) ;
}
2018-08-17 07:14:45 +02:00
}
2018-08-16 05:08:36 +02:00
for ( const auto & info : data_in . infos )
{
2019-05-01 08:01:17 +02:00
m_transient_state . service_nodes_infos [ info . pubkey ] = info . info ;
2018-08-16 05:08:36 +02:00
}
for ( const auto & event : data_in . events )
{
if ( event . type ( ) = = typeid ( rollback_change ) )
{
2019-01-25 04:15:52 +01:00
const auto & from = boost : : get < rollback_change > ( event ) ;
auto * i = new rollback_change ( ) ;
* i = from ;
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back ( std : : unique_ptr < rollback_event > ( i ) ) ;
2018-08-16 05:08:36 +02:00
}
else if ( event . type ( ) = = typeid ( rollback_new ) )
{
2019-01-25 04:15:52 +01:00
const auto & from = boost : : get < rollback_new > ( event ) ;
auto * i = new rollback_new ( ) ;
* i = from ;
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back ( std : : unique_ptr < rollback_event > ( i ) ) ;
2018-08-16 05:08:36 +02:00
}
else if ( event . type ( ) = = typeid ( prevent_rollback ) )
{
2019-01-25 04:15:52 +01:00
const auto & from = boost : : get < prevent_rollback > ( event ) ;
auto * i = new prevent_rollback ( ) ;
* i = from ;
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back ( std : : unique_ptr < rollback_event > ( i ) ) ;
2019-01-25 04:15:52 +01:00
}
else if ( event . type ( ) = = typeid ( rollback_key_image_blacklist ) )
{
const auto & from = boost : : get < rollback_key_image_blacklist > ( event ) ;
auto * i = new rollback_key_image_blacklist ( ) ;
* i = from ;
2019-05-01 08:01:17 +02:00
m_transient_state . rollback_events . push_back ( std : : unique_ptr < rollback_event > ( i ) ) ;
2018-08-16 05:08:36 +02:00
}
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. " ) ;
2018-08-16 05:08:36 +02:00
return false ;
}
}
2019-05-01 08:01:17 +02:00
MGINFO ( " Service node data loaded successfully, height: " < < m_transient_state . height ) ;
MGINFO ( m_transient_state . service_nodes_infos . size ( ) < < " nodes and " < < m_transient_state . rollback_events . size ( ) < < " rollback events loaded. " ) ;
2018-08-16 06:13:57 +02:00
LOG_PRINT_L1 ( " service_node_list::load() returning success " ) ;
2018-08-16 05:08:36 +02:00
return true ;
}
void service_node_list : : clear ( bool delete_db_entry )
{
2019-05-01 08:01:17 +02:00
m_transient_state = { } ;
2018-08-16 05:08:36 +02:00
if ( m_db & & delete_db_entry )
{
m_db - > block_txn_start ( false /*readonly*/ ) ;
m_db - > clear_service_node_data ( ) ;
m_db - > block_txn_stop ( ) ;
}
2018-10-17 02:07:04 +02:00
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 ) ;
}
2019-05-01 08:01:17 +02:00
m_transient_state . height = hardfork_9_from_height ;
2018-08-16 05:08:36 +02:00
}
Infinite Staking Part 2 (#406)
* Cleanup and undoing some protocol breakages
* Simplify expiration of nodes
* Request unlock schedules entire node for expiration
* Fix off by one in expiring nodes
* Undo expiring code for pre v10 nodes
* Fix RPC returning register as unlock height and not checking 0
* Rename key image unlock height const
* Undo testnet hardfork debug changes
* Remove is_type for get_type, fix missing var rename
* Move serialisable data into public namespace
* Serialise tx types properly
* Fix typo in no service node known msg
* Code review
* Fix == to >= on serialising tx type
* Code review 2
* Fix tests and key image unlock
* Add command to print locked key images
* Update ui to display lock stakes, query in print cmd blacklist
* Modify print stakes to be less slow
* Remove autostaking code
* Refactor staking into sweep functions
It appears staking was derived off stake_main written separately at
implementation at the beginning. This merges them back into a common
code path, after removing autostake there's only some minor differences.
It also makes sure that any changes to sweeping upstream are going to be
considered in the staking process which we want.
* Display unlock height for stakes
* Begin creating output blacklist
* Make blacklist output a migration step
* Implement get_output_blacklist for lmdb
* In wallet output selection ignore blacklisted outputs
* Apply blacklisted outputs to output selection
* Fix broken tests, switch key image unlock
* Fix broken unit_tests
* Begin change to limit locked key images to 4 globally
* Revamp prepare registration for new min contribution rules
* Fix up old back case in prepare registration
* Remove debug code
* Cleanup debug code and some unecessary changes
* Fix migration step on mainnet db
* Fix blacklist outputs for pre-existing DB's
* Remove irrelevant note
* Tweak scanning addresses for locked stakes
Since we only now allow contributions from the primary address we can
skip checking all subaddress + lookahead to speed up wallet scanning
* Define macro for SCNu64 for Mingw
* Fix failure on empty DB
* Add missing error msg, remove contributor from stake
* Improve staking messages
* Flush prompt to always display
* Return the msg from stake failure and fix stake parsing error
* Tweak fork rules for smaller bulletproofs
* Tweak pooled nodes minimum amounts
* Fix crash on exit, there's no need to store on destructor
Since all information about service nodes is derived from the blockchain
and we store state every time we receive a block, storing in the
destructor is redundant as there is no new information to store.
* Make prompt be consistent with CLI
* Check max number of key images from per user to node
* Implement error message on get_output_blacklist failure
* Remove resolved TODO's/comments
* Handle infinite staking in print_sn
* Atoi->strtol, fix prepare_registration, virtual override, stale msgs
2019-02-14 02:12:57 +01:00
size_t service_node_info : : total_num_locked_contributions ( ) const
{
size_t result = 0 ;
for ( service_node_info : : contributor_t const & contributor : this - > contributors )
result + = contributor . locked_contributions . size ( ) ;
return result ;
}
2019-03-13 06:35:02 +01:00
converted_registration_args convert_registration_args ( cryptonote : : network_type nettype ,
const std : : vector < std : : string > & args ,
uint64_t staking_requirement ,
int hf_version )
2018-07-21 03:27:13 +02:00
{
2019-03-13 06:35:02 +01:00
converted_registration_args result = { } ;
2018-08-16 07:14:28 +02:00
if ( args . size ( ) % 2 = = 0 | | args . size ( ) < 3 )
2018-08-03 07:17:15 +02:00
{
2019-03-13 06:35:02 +01:00
result . err_msg = tr ( " Usage: <operator cut> <address> <fraction> [<address> <fraction> [...]]] " ) ;
return result ;
2018-08-03 07:17:15 +02:00
}
2019-03-13 06:35:02 +01:00
2018-08-16 07:14:28 +02:00
if ( ( args . size ( ) - 1 ) / 2 > MAX_NUMBER_OF_CONTRIBUTORS )
2018-07-31 04:46:12 +02:00
{
2019-03-13 06:35:02 +01:00
result . err_msg = tr ( " Exceeds the maximum number of contributors, which is " ) + std : : to_string ( MAX_NUMBER_OF_CONTRIBUTORS ) ;
return result ;
2018-07-21 03:27:13 +02:00
}
2019-03-13 06:35:02 +01:00
2018-08-07 04:28:59 +02:00
try
{
2019-03-13 06:35:02 +01:00
result . portions_for_operator = boost : : lexical_cast < uint64_t > ( args [ 0 ] ) ;
if ( result . portions_for_operator > STAKING_PORTIONS )
2018-08-07 04:28:59 +02:00
{
2019-03-13 06:35:02 +01:00
result . err_msg = tr ( " Invalid portion amount: " ) + args [ 0 ] + tr ( " . Must be between 0 and " ) + std : : to_string ( STAKING_PORTIONS ) ;
return result ;
2018-08-07 04:28:59 +02:00
}
}
catch ( const std : : exception & e )
{
2019-03-13 06:35:02 +01:00
result . err_msg = tr ( " Invalid portion amount: " ) + args [ 0 ] + tr ( " . Must be between 0 and " ) + std : : to_string ( STAKING_PORTIONS ) ;
return result ;
2018-08-07 04:28:59 +02:00
}
2019-03-13 06:35:02 +01:00
2019-03-28 08:18:23 +01:00
struct addr_to_portion_t
{
cryptonote : : address_parse_info info ;
uint64_t portions ;
} ;
std : : vector < addr_to_portion_t > addr_to_portions ;
2019-03-13 06:35:02 +01:00
size_t const OPERATOR_ARG_INDEX = 1 ;
for ( size_t i = OPERATOR_ARG_INDEX , num_contributions = 0 ;
i < args . size ( ) ;
i + = 2 , + + num_contributions )
2018-07-21 03:27:13 +02:00
{
cryptonote : : address_parse_info info ;
if ( ! cryptonote : : get_account_address_from_str ( info , nettype , args [ i ] ) )
{
2019-03-13 06:35:02 +01:00
result . err_msg = tr ( " Failed to parse address: " ) + args [ i ] ;
return result ;
2018-07-21 03:27:13 +02:00
}
if ( info . has_payment_id )
{
2019-03-13 06:35:02 +01:00
result . err_msg = tr ( " Can't use a payment id for staking tx " ) ;
return result ;
2018-07-21 03:27:13 +02:00
}
2018-07-28 08:27:04 +02:00
2018-07-21 03:27:13 +02:00
if ( info . is_subaddress )
{
2019-03-13 06:35:02 +01:00
result . err_msg = tr ( " Can't use a subaddress for staking tx " ) ;
return result ;
2018-07-21 03:27:13 +02:00
}
try
{
2018-08-18 06:36:16 +02:00
uint64_t num_portions = boost : : lexical_cast < uint64_t > ( args [ i + 1 ] ) ;
2019-03-28 08:18:23 +01:00
addr_to_portions . push_back ( { info , num_portions } ) ;
2018-07-21 03:27:13 +02:00
}
catch ( const std : : exception & e )
{
2019-03-13 06:35:02 +01:00
result . err_msg = tr ( " Invalid amount for contributor: " ) + args [ i ] + tr ( " , with portion amount that could not be converted to a number: " ) + args [ i + 1 ] ;
return result ;
2018-07-21 03:27:13 +02:00
}
}
2019-03-13 06:35:02 +01:00
2019-03-28 08:18:23 +01:00
//
// FIXME(doyle): FIXME(loki) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// This is temporary code to redistribute the insufficient portion dust
// amounts between contributors. It should be removed in HF12.
//
std : : array < uint64_t , MAX_NUMBER_OF_CONTRIBUTORS * service_nodes : : MAX_KEY_IMAGES_PER_CONTRIBUTOR > excess_portions ;
std : : array < uint64_t , MAX_NUMBER_OF_CONTRIBUTORS * service_nodes : : MAX_KEY_IMAGES_PER_CONTRIBUTOR > min_contributions ;
{
// NOTE: Calculate excess portions from each contributor
uint64_t loki_reserved = 0 ;
for ( size_t index = 0 ; index < addr_to_portions . size ( ) ; + + index )
{
addr_to_portion_t const & addr_to_portion = addr_to_portions [ index ] ;
uint64_t min_contribution_portions = service_nodes : : get_min_node_contribution_in_portions ( hf_version , staking_requirement , loki_reserved , index ) ;
uint64_t loki_amount = service_nodes : : portions_to_amount ( staking_requirement , addr_to_portion . portions ) ;
loki_reserved + = loki_amount ;
uint64_t excess = 0 ;
if ( addr_to_portion . portions > min_contribution_portions )
excess = addr_to_portion . portions - min_contribution_portions ;
min_contributions [ index ] = min_contribution_portions ;
excess_portions [ index ] = excess ;
}
}
uint64_t portions_left = STAKING_PORTIONS ;
uint64_t total_reserved = 0 ;
for ( size_t i = 0 ; i < addr_to_portions . size ( ) ; + + i )
{
addr_to_portion_t & addr_to_portion = addr_to_portions [ i ] ;
uint64_t min_portions = get_min_node_contribution_in_portions ( hf_version , staking_requirement , total_reserved , i ) ;
uint64_t portions_to_steal = 0 ;
if ( addr_to_portion . portions < min_portions )
{
// NOTE: Steal dust portions from other contributor if we fall below
// the minimum by a dust amount.
uint64_t needed = min_portions - addr_to_portion . portions ;
const uint64_t FUDGE_FACTOR = 10 ;
const uint64_t DUST_UNIT = ( STAKING_PORTIONS / staking_requirement ) ;
const uint64_t DUST = DUST_UNIT * FUDGE_FACTOR ;
if ( needed > DUST )
continue ;
for ( size_t sub_index = 0 ; sub_index < addr_to_portions . size ( ) ; sub_index + + )
{
if ( i = = sub_index ) continue ;
uint64_t & contributor_excess = excess_portions [ sub_index ] ;
if ( contributor_excess > 0 )
{
portions_to_steal = std : : min ( needed , contributor_excess ) ;
addr_to_portion . portions + = portions_to_steal ;
contributor_excess - = portions_to_steal ;
needed - = portions_to_steal ;
result . portions [ sub_index ] - = portions_to_steal ;
if ( needed = = 0 )
break ;
}
}
// NOTE: Operator is sending in the minimum amount and it falls below
// the minimum by dust, just increase the portions so it passes
if ( needed > 0 & & addr_to_portions . size ( ) < MAX_NUMBER_OF_CONTRIBUTORS * service_nodes : : MAX_KEY_IMAGES_PER_CONTRIBUTOR )
addr_to_portion . portions + = needed ;
}
2019-03-28 09:22:16 +01:00
if ( addr_to_portion . portions < min_portions | | ( addr_to_portion . portions - portions_to_steal ) > portions_left )
2019-03-28 08:18:23 +01:00
{
result . err_msg = tr ( " Invalid amount for contributor: " ) + args [ i ] + tr ( " , with portion amount: " ) + args [ i + 1 ] + tr ( " . The contributors must each have at least 25%, except for the last contributor which may have the remaining amount " ) ;
return result ;
}
if ( min_portions = = UINT64_MAX )
{
result . err_msg = tr ( " Too many contributors specified, you can only split a node with up to: " ) + std : : to_string ( MAX_NUMBER_OF_CONTRIBUTORS ) + tr ( " people. " ) ;
return result ;
}
portions_left - = addr_to_portion . portions ;
portions_left + = portions_to_steal ;
result . addresses . push_back ( addr_to_portion . info . address ) ;
result . portions . push_back ( addr_to_portion . portions ) ;
uint64_t loki_amount = service_nodes : : portions_to_amount ( addr_to_portion . portions , staking_requirement ) ;
total_reserved + = loki_amount ;
}
2019-03-13 06:35:02 +01:00
result . success = true ;
return result ;
2018-07-31 08:13:03 +02:00
}
2019-03-13 06:35:02 +01:00
bool make_registration_cmd ( cryptonote : : network_type nettype ,
int hf_version ,
uint64_t staking_requirement ,
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 ,
boost : : optional < std : : string & > err_msg )
2018-07-31 08:13:03 +02:00
{
2019-03-13 06:35:02 +01:00
converted_registration_args converted_args = convert_registration_args ( nettype , args , staking_requirement , hf_version ) ;
if ( ! converted_args . success )
2018-07-31 08:13:03 +02:00
{
2019-03-13 06:35:02 +01:00
MERROR ( tr ( " Could not convert registration args, reason: " ) < < converted_args . err_msg ) ;
2018-07-31 08:13:03 +02:00
return false ;
}
Infinite Staking Part 2 (#406)
* Cleanup and undoing some protocol breakages
* Simplify expiration of nodes
* Request unlock schedules entire node for expiration
* Fix off by one in expiring nodes
* Undo expiring code for pre v10 nodes
* Fix RPC returning register as unlock height and not checking 0
* Rename key image unlock height const
* Undo testnet hardfork debug changes
* Remove is_type for get_type, fix missing var rename
* Move serialisable data into public namespace
* Serialise tx types properly
* Fix typo in no service node known msg
* Code review
* Fix == to >= on serialising tx type
* Code review 2
* Fix tests and key image unlock
* Add command to print locked key images
* Update ui to display lock stakes, query in print cmd blacklist
* Modify print stakes to be less slow
* Remove autostaking code
* Refactor staking into sweep functions
It appears staking was derived off stake_main written separately at
implementation at the beginning. This merges them back into a common
code path, after removing autostake there's only some minor differences.
It also makes sure that any changes to sweeping upstream are going to be
considered in the staking process which we want.
* Display unlock height for stakes
* Begin creating output blacklist
* Make blacklist output a migration step
* Implement get_output_blacklist for lmdb
* In wallet output selection ignore blacklisted outputs
* Apply blacklisted outputs to output selection
* Fix broken tests, switch key image unlock
* Fix broken unit_tests
* Begin change to limit locked key images to 4 globally
* Revamp prepare registration for new min contribution rules
* Fix up old back case in prepare registration
* Remove debug code
* Cleanup debug code and some unecessary changes
* Fix migration step on mainnet db
* Fix blacklist outputs for pre-existing DB's
* Remove irrelevant note
* Tweak scanning addresses for locked stakes
Since we only now allow contributions from the primary address we can
skip checking all subaddress + lookahead to speed up wallet scanning
* Define macro for SCNu64 for Mingw
* Fix failure on empty DB
* Add missing error msg, remove contributor from stake
* Improve staking messages
* Flush prompt to always display
* Return the msg from stake failure and fix stake parsing error
* Tweak fork rules for smaller bulletproofs
* Tweak pooled nodes minimum amounts
* Fix crash on exit, there's no need to store on destructor
Since all information about service nodes is derived from the blockchain
and we store state every time we receive a block, storing in the
destructor is redundant as there is no new information to store.
* Make prompt be consistent with CLI
* Check max number of key images from per user to node
* Implement error message on get_output_blacklist failure
* Remove resolved TODO's/comments
* Handle infinite staking in print_sn
* Atoi->strtol, fix prepare_registration, virtual override, stale msgs
2019-02-14 02:12:57 +01:00
uint64_t exp_timestamp = time ( nullptr ) + STAKING_AUTHORIZATION_EXPIRATION_WINDOW ;
2018-07-31 08:13:03 +02:00
crypto : : hash hash ;
2019-03-13 06:35:02 +01:00
bool hashed = cryptonote : : get_registration_hash ( converted_args . addresses , converted_args . portions_for_operator , converted_args . portions , exp_timestamp , hash ) ;
2018-07-31 08:13:03 +02:00
if ( ! hashed )
{
2018-08-07 04:28:59 +02:00
MERROR ( tr ( " Could not make registration hash from addresses and portions " ) ) ;
2018-07-31 08:13:03 +02:00
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 ) < < " " ;
2018-08-03 08:52:44 +02:00
stream < < epee : : string_tools : : pod_to_hex ( signature ) ;
2018-07-31 08:13:03 +02:00
if ( make_friendly )
{
stream < < " \n \n " ;
time_t tt = exp_timestamp ;
2018-12-11 07:42:06 +01:00
2018-07-31 08:13:03 +02:00
struct tm tm ;
2018-12-11 07:42:06 +01:00
epee : : misc_utils : : get_gmt_time ( tt , tm ) ;
2018-07-31 08:13:03 +02:00
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 " ) ;
2019-03-20 01:18:30 +01:00
stream < < tr ( " This should be in about 2 weeks, if it isn't, check this computer's clock. \n " ) ;
2018-07-31 08:13:03 +02:00
stream < < tr ( " Please submit your registration into the blockchain before this time or it will be invalid. " ) ;
}
cmd = stream . str ( ) ;
2018-07-21 03:27:13 +02:00
return true ;
}
2018-06-29 06:47:00 +02:00
}
2018-07-21 03:27:13 +02:00