PW recreation refactoring, prevent duplicated recreations, update wallet address through proposal

This commit is contained in:
Srdjan Obucina 2020-01-31 23:28:20 +01:00
parent 0c7ef96178
commit c5ea418321
17 changed files with 121 additions and 138 deletions

View file

@ -135,7 +135,7 @@ else( WIN32 ) # Apple AND Linux
endif( APPLE )
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-builtin-memcmp -Wno-parentheses -Wno-invalid-offsetof" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-builtin-memcmp -Wno-parentheses -Wno-invalid-offsetof -Wno-terminate -Wno-sign-compare" )
elseif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
if( CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.0.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0.0 )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-partial-specialization" )

View file

@ -316,15 +316,12 @@ struct get_impacted_account_visitor
void operator()( const son_maintenance_operation& op ){
_impacted.insert( op.owner_account );
}
void operator()( const son_wallet_create_operation& op ){
void operator()( const son_wallet_recreate_operation& op ){
_impacted.insert( op.payer );
}
void operator()( const son_wallet_update_operation& op ){
_impacted.insert( op.payer );
}
void operator()( const son_wallet_close_operation& op ){
_impacted.insert( op.payer );
}
void operator()( const sidechain_address_add_operation& op ){
_impacted.insert( op.sidechain_address_account );
}

View file

@ -117,10 +117,10 @@ add_library( graphene_chain
son_evaluator.cpp
son_object.cpp
sidechain_address_evaluator.cpp
son_wallet_evaluator.cpp
sidechain_address_evaluator.cpp
${HEADERS}
${PROTOCOL_HEADERS}
"${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp"

View file

@ -254,9 +254,8 @@ void database::initialize_evaluators()
register_evaluator<son_heartbeat_evaluator>();
register_evaluator<son_report_down_evaluator>();
register_evaluator<son_maintenance_evaluator>();
register_evaluator<create_son_wallet_evaluator>();
register_evaluator<recreate_son_wallet_evaluator>();
register_evaluator<update_son_wallet_evaluator>();
register_evaluator<close_son_wallet_evaluator>();
register_evaluator<add_sidechain_address_evaluator>();
register_evaluator<update_sidechain_address_evaluator>();
register_evaluator<delete_sidechain_address_evaluator>();

View file

@ -471,21 +471,39 @@ void database::update_active_sons()
} else {
ilog( "Active SONs set CHANGED" );
bool should_recreate_pw = true;
// Expire for current son_wallet_object wallet, if exists
const auto& idx_swi = get_index_type<son_wallet_index>().indices().get<by_id>();
auto obj = idx_swi.rbegin();
if (obj != idx_swi.rend()) {
modify(*obj, [&, &obj](son_wallet_object &swo) {
swo.expires = head_block_time();
});
// Compare current wallet SONs and to-be lists of active sons
auto cur_wallet_sons = (*obj).sons;
bool wallet_son_sets_equal = (cur_wallet_sons.size() == new_active_sons.size());
if (wallet_son_sets_equal) {
for( size_t i = 0; i < cur_wallet_sons.size(); i++ ) {
wallet_son_sets_equal = wallet_son_sets_equal && cur_wallet_sons.at(i) == new_active_sons.at(i);
}
}
should_recreate_pw = !wallet_son_sets_equal;
if (should_recreate_pw) {
modify(*obj, [&, obj](son_wallet_object &swo) {
swo.expires = head_block_time();
});
}
}
// Create new son_wallet_object, to initiate wallet recreation
const auto& new_son_wallet_object = create<son_wallet_object>( [&]( son_wallet_object& obj ){
obj.valid_from = head_block_time();
obj.expires = time_point_sec::maximum();
obj.sons.insert(obj.sons.end(), new_active_sons.begin(), new_active_sons.end());
});
if (should_recreate_pw) {
// Create new son_wallet_object, to initiate wallet recreation
create<son_wallet_object>( [&]( son_wallet_object& obj ) {
obj.valid_from = head_block_time();
obj.expires = time_point_sec::maximum();
obj.sons.insert(obj.sons.end(), new_active_sons.begin(), new_active_sons.end());
});
}
vector<son_info> sons_to_remove;
// find all cur_active_sons members that is not in new_active_sons

View file

@ -303,15 +303,12 @@ struct get_impacted_account_visitor
void operator()( const son_maintenance_operation& op ) {
_impacted.insert( op.owner_account );
}
void operator()( const son_wallet_create_operation& op ) {
void operator()( const son_wallet_recreate_operation& op ) {
_impacted.insert( op.payer );
}
void operator()( const son_wallet_update_operation& op ) {
_impacted.insert( op.payer );
}
void operator()( const son_wallet_close_operation& op ) {
_impacted.insert( op.payer );
}
void operator()( const sidechain_address_add_operation& op ) {
_impacted.insert( op.sidechain_address_account );
}

View file

@ -1,5 +1,6 @@
// SON HARDFORK Monday, September 21, 2020 1:43:11 PM
// SON HARDFORK Wednesday, January 1, 2020 12:00:00 AM - 1577836800
// SON HARDFORK Monday, September 21, 2020 1:43:11 PM - 1600695791
#ifndef HARDFORK_SON_TIME
#include <ctime>
#define HARDFORK_SON_TIME (fc::time_point_sec( time(NULL) - (60 * 60) ))
#define HARDFORK_SON_TIME (fc::time_point_sec( 1577836800 ))
#endif

View file

@ -145,9 +145,8 @@ namespace graphene { namespace chain {
son_heartbeat_operation,
son_report_down_operation,
son_maintenance_operation,
son_wallet_create_operation,
son_wallet_recreate_operation,
son_wallet_update_operation,
son_wallet_close_operation,
sidechain_address_add_operation,
sidechain_address_update_operation,
sidechain_address_delete_operation

View file

@ -1,15 +1,18 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/son_info.hpp>
namespace graphene { namespace chain {
struct son_wallet_create_operation : public base_operation
struct son_wallet_recreate_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 0; };
asset fee;
account_id_type payer;
vector<son_info> sons;
account_id_type fee_payer()const { return payer; }
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
};
@ -20,6 +23,7 @@ namespace graphene { namespace chain {
asset fee;
account_id_type payer;
son_wallet_id_type son_wallet_id;
graphene::peerplays_sidechain::sidechain_type sidechain;
string address;
@ -28,23 +32,9 @@ namespace graphene { namespace chain {
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
};
struct son_wallet_close_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 0; };
asset fee;
account_id_type payer;
son_wallet_id_type son_wallet_id;
account_id_type fee_payer()const { return payer; }
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
};
} } // namespace graphene::chain
FC_REFLECT(graphene::chain::son_wallet_create_operation::fee_parameters_type, (fee) )
FC_REFLECT(graphene::chain::son_wallet_create_operation, (fee)(payer) )
FC_REFLECT(graphene::chain::son_wallet_recreate_operation::fee_parameters_type, (fee) )
FC_REFLECT(graphene::chain::son_wallet_recreate_operation, (fee)(payer)(sons) )
FC_REFLECT(graphene::chain::son_wallet_update_operation::fee_parameters_type, (fee) )
FC_REFLECT(graphene::chain::son_wallet_update_operation, (fee)(payer)(son_wallet_id)(sidechain)(address) )
FC_REFLECT(graphene::chain::son_wallet_close_operation::fee_parameters_type, (fee) )
FC_REFLECT(graphene::chain::son_wallet_close_operation, (fee)(payer)(son_wallet_id) )

View file

@ -4,13 +4,13 @@
namespace graphene { namespace chain {
class create_son_wallet_evaluator : public evaluator<create_son_wallet_evaluator>
class recreate_son_wallet_evaluator : public evaluator<recreate_son_wallet_evaluator>
{
public:
typedef son_wallet_create_operation operation_type;
typedef son_wallet_recreate_operation operation_type;
void_result do_evaluate(const son_wallet_create_operation& o);
object_id_type do_apply(const son_wallet_create_operation& o);
void_result do_evaluate(const son_wallet_recreate_operation& o);
object_id_type do_apply(const son_wallet_recreate_operation& o);
};
class update_son_wallet_evaluator : public evaluator<update_son_wallet_evaluator>
@ -22,13 +22,4 @@ public:
object_id_type do_apply(const son_wallet_update_operation& o);
};
class close_son_wallet_evaluator : public evaluator<close_son_wallet_evaluator>
{
public:
typedef son_wallet_close_operation operation_type;
void_result do_evaluate(const son_wallet_close_operation& o);
object_id_type do_apply(const son_wallet_close_operation& o);
};
} } // namespace graphene::chain

View file

@ -5,29 +5,62 @@
namespace graphene { namespace chain {
void_result create_son_wallet_evaluator::do_evaluate(const son_wallet_create_operation& op)
void_result recreate_son_wallet_evaluator::do_evaluate(const son_wallet_recreate_operation& op)
{ try{
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
FC_ASSERT(db().get_global_properties().parameters.get_son_btc_account_id() != GRAPHENE_NULL_ACCOUNT, "SON paying account not set.");
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
auto itr = idx.rbegin();
FC_ASSERT( itr->payer == db().get_global_properties().parameters.get_son_btc_account_id() );
if(itr != idx.rend())
{
// Compare current wallet SONs and to-be lists of active sons
auto cur_wallet_sons = (*itr).sons;
auto new_wallet_sons = op.sons;
bool son_sets_equal = (cur_wallet_sons.size() == new_wallet_sons.size());
if (son_sets_equal) {
for( size_t i = 0; i < cur_wallet_sons.size(); i++ ) {
son_sets_equal = son_sets_equal && cur_wallet_sons.at(i) == new_wallet_sons.at(i);
}
}
FC_ASSERT(son_sets_equal == false, "Wallet recreation not needed, active SONs set is not changed.");
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
object_id_type create_son_wallet_evaluator::do_apply(const son_wallet_create_operation& op)
object_id_type recreate_son_wallet_evaluator::do_apply(const son_wallet_recreate_operation& op)
{ try {
const auto& new_son_wallet_object = db().create<son_wallet_object>( [&]( son_wallet_object& obj ){
obj.valid_from = db().head_block_time();
obj.expires = time_point_sec::maximum();
obj.sons = db().get_global_properties().active_sons;
});
return new_son_wallet_object.id;
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
auto itr = idx.rbegin();
if(itr != idx.rend())
{
db().modify(*itr, [&, op](son_wallet_object &swo) {
swo.expires = db().head_block_time();
});
}
const auto& new_son_wallet_object = db().create<son_wallet_object>( [&]( son_wallet_object& obj ){
obj.valid_from = db().head_block_time();
obj.expires = time_point_sec::maximum();
obj.sons = op.sons;
});
return new_son_wallet_object.id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_operation& op)
{ try{
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
FC_ASSERT(db().get_global_properties().parameters.get_son_btc_account_id() != GRAPHENE_NULL_ACCOUNT, "SON paying account not set.");
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
FC_ASSERT( idx.find(op.son_wallet_id) != idx.end() );
auto itr = idx.find(op.son_wallet_id);
FC_ASSERT( itr->payer == db().get_global_properties().parameters.get_son_btc_account_id() );
FC_ASSERT( itr->addresses.find(peerplays_sidechain::sidechain_type::bitcoin) == itr->addresses.end() ||
itr->addresses.at(peerplays_sidechain::sidechain_type::bitcoin).empty(), "Sidechain wallet address already set");
return void_result();
@ -46,25 +79,4 @@ object_id_type update_son_wallet_evaluator::do_apply(const son_wallet_update_ope
return op.son_wallet_id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
void_result close_son_wallet_evaluator::do_evaluate(const son_wallet_close_operation& op)
{ try{
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
FC_ASSERT( idx.find(op.son_wallet_id) != idx.end() );
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
object_id_type close_son_wallet_evaluator::do_apply(const son_wallet_close_operation& op)
{ try {
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
auto itr = idx.find(op.son_wallet_id);
if(itr != idx.end())
{
db().modify(*itr, [&, &op](son_wallet_object &swo) {
swo.expires = db().head_block_time();
});
}
return op.son_wallet_id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
} } // namespace graphene::chain

View file

@ -2,11 +2,7 @@
#include <graphene/app/plugin.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/son_object.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/peerplays_sidechain/defs.hpp>
namespace graphene { namespace peerplays_sidechain {
using namespace chain;

View file

@ -1,12 +1,13 @@
#pragma once
#include <graphene/peerplays_sidechain/defs.hpp>
#include <graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp>
#include <vector>
#include <boost/program_options.hpp>
#include <fc/signals.hpp>
#include <graphene/peerplays_sidechain/defs.hpp>
#include <graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp>
namespace graphene { namespace peerplays_sidechain {
class sidechain_net_handler {
@ -17,6 +18,8 @@ public:
graphene::peerplays_sidechain::sidechain_type get_sidechain();
std::vector<std::string> get_sidechain_addresses();
void sidechain_event_data_received(const sidechain_event_data& sed);
virtual void recreate_primary_wallet() = 0;
protected:
@ -24,8 +27,6 @@ protected:
graphene::chain::database& database;
graphene::peerplays_sidechain::sidechain_type sidechain;
void sidechain_event_data_received(const sidechain_event_data& sed);
virtual std::string create_multisignature_wallet( const std::vector<std::string> public_keys ) = 0;
virtual std::string transfer( const std::string& from, const std::string& to, const uint64_t amount ) = 0;
virtual std::string sign_transaction( const std::string& transaction ) = 0;

View file

@ -137,6 +137,9 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt
throw;
}
plugin.database().applied_block.connect( [&] (const signed_block& b) { on_block_applied(b); } );
plugin.database().new_objects.connect( [&] (const vector<object_id_type>& ids, const flat_set<account_id_type>& impacted_accounts) { on_objects_new(ids); } );
net_manager = std::unique_ptr<sidechain_net_manager>(new sidechain_net_manager(plugin));
config_ready_bitcoin = options.count( "bitcoin-node-ip" ) &&
@ -420,6 +423,11 @@ void peerplays_sidechain_plugin_impl::on_objects_new(const vector<object_id_type
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_report_down_operation>::value) {
approve_proposal( proposal->id );
}
if(proposal->proposed_transaction.operations.size() == 1
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_update_operation>::value) {
approve_proposal( proposal->id );
}
}
}
}
@ -453,8 +461,6 @@ void peerplays_sidechain_plugin::plugin_initialize(const boost::program_options:
{
ilog("peerplays sidechain plugin: plugin_initialize()");
my->plugin_initialize(options);
database().applied_block.connect( [&]( const signed_block& b){ my->on_block_applied(b); } );
database().new_objects.connect([this](const vector<object_id_type>& ids, const flat_set<account_id_type>& impacted_accounts) { my->on_objects_new(ids); });
}
void peerplays_sidechain_plugin::plugin_startup()

View file

@ -260,7 +260,10 @@ void sidechain_net_handler_bitcoin::recreate_primary_wallet() {
if ((obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) ||
(obj->addresses.at(sidechain_type::bitcoin).empty())) {
auto active_sons = database.get_global_properties().active_sons;
const chain::global_property_object& gpo = database.get_global_properties();
auto active_sons = gpo.active_sons;
vector<string> son_pubkeys_bitcoin;
for ( const son_info& si : active_sons ) {
son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin));
@ -279,17 +282,22 @@ void sidechain_net_handler_bitcoin::recreate_primary_wallet() {
boost::property_tree::json_parser::write_json(res, pt.get_child("result"));
son_wallet_update_operation op;
op.payer = database.get_global_properties().parameters.get_son_btc_account_id();
op.payer = gpo.parameters.get_son_btc_account_id();
op.son_wallet_id = (*obj).id;
op.sidechain = sidechain_type::bitcoin;
op.address = res.str();
signed_transaction trx = database.create_signed_transaction(plugin.get_private_keys().begin()->second, op);
proposal_create_operation proposal_op;
proposal_op.fee_paying_account = plugin.get_son_object().son_account;
proposal_op.proposed_ops.push_back( op_wrapper( op ) );
uint32_t lifetime = ( gpo.parameters.block_interval * gpo.active_witnesses.size() ) * 3;
proposal_op.expiration_time = time_point_sec( database.head_block_time().sec_since_epoch() + lifetime );
signed_transaction trx = database.create_signed_transaction(plugin.get_private_keys().begin()->second, proposal_op);
try {
database.push_transaction(trx);
} catch (fc::exception e) {
ilog("sidechain_net_handler_bitcoin: sending son wallet update operation failed with exception ${e}",("e", e.what()));
} catch(fc::exception e){
ilog("sidechain_net_handler: sending proposal for son wallet update operation failed with exception ${e}",("e", e.what()));
}
}
}

View file

@ -7,8 +7,8 @@
namespace graphene { namespace peerplays_sidechain {
sidechain_net_manager::sidechain_net_manager(peerplays_sidechain_plugin& _plugin) :
plugin(_plugin),
database(_plugin.database())
plugin(_plugin),
database(_plugin.database())
{
ilog(__FUNCTION__);
}

View file

@ -24,15 +24,15 @@ BOOST_AUTO_TEST_CASE( son_wallet_create_test ) {
set_expiration(db, trx);
{
BOOST_TEST_MESSAGE("Send son_wallet_create_operation");
BOOST_TEST_MESSAGE("Send son_wallet_recreate_operation");
son_wallet_create_operation op;
son_wallet_recreate_operation op;
op.payer = db.get_global_properties().parameters.get_son_btc_account_id();
trx.operations.push_back(op);
sign(trx, alice_private_key);
PUSH_TX(db, trx, ~0);
//PUSH_TX(db, trx, ~0);
}
generate_block();
@ -79,36 +79,4 @@ BOOST_AUTO_TEST_CASE( son_wallet_update_test ) {
}
BOOST_AUTO_TEST_CASE( son_wallet_close_test ) {
BOOST_TEST_MESSAGE("son_wallet_close_test");
INVOKE(son_wallet_create_test);
GET_ACTOR(alice);
{
BOOST_TEST_MESSAGE("Send son_wallet_close_operation");
son_wallet_close_operation op;
op.payer = db.get_global_properties().parameters.get_son_btc_account_id();
op.son_wallet_id = son_wallet_id_type(0);
trx.operations.push_back(op);
sign(trx, alice_private_key);
PUSH_TX(db, trx, ~0);
}
generate_block();
{
BOOST_TEST_MESSAGE("Check son_wallet_close_operation results");
const auto& idx = db.get_index_type<son_wallet_index>().indices().get<by_id>();
BOOST_REQUIRE( idx.size() == 1 );
auto obj = idx.find(son_wallet_id_type(0));
BOOST_REQUIRE( obj->expires != time_point_sec::maximum() );
}
}
BOOST_AUTO_TEST_SUITE_END()