From 6d5b86a8e597491b66951cab9671343f4c5f9961 Mon Sep 17 00:00:00 2001 From: obucinac Date: Wed, 18 Dec 2019 19:30:38 +0100 Subject: [PATCH 1/3] User sidechain address mappings (#240) * WIP: Sidechain objects * Revert "WIP: Sidechain objects" This reverts commit 8676940a281604688771e96ceb1e65a35d98e8e5. * WIP: User sidechain address mappings * Fix reflection problem * Reflect missing members of sidechain_address_update_operation * Add sidechain address operation tests * Enable RPC calls * Fix build errors due to merge conflict * Fix RPC, add CLI wallet commands for sidechain addresses * Improved peerplays_sidechain_plugin_impl * Remove short param for son-id * Fix crashing errors on bitcoin event received * Code review changes --- libraries/app/CMakeLists.txt | 2 +- libraries/app/api.cpp | 5 + libraries/app/database_api.cpp | 110 ++++++++++-- libraries/app/impacted.cpp | 9 + .../app/include/graphene/app/database_api.hpp | 48 ++++++ libraries/chain/CMakeLists.txt | 4 +- libraries/chain/db_init.cpp | 7 + libraries/chain/db_notify.cpp | 14 ++ .../graphene/chain/protocol/operations.hpp | 6 +- .../chain/protocol/sidechain_address.hpp | 66 ++++++++ .../include/graphene/chain/protocol/types.hpp | 5 + .../chain/sidechain_address_evaluator.hpp | 34 ++++ .../chain/sidechain_address_object.hpp | 70 ++++++++ .../chain/sidechain_address_evaluator.cpp | 70 ++++++++ .../graphene/peerplays_sidechain/defs.hpp | 8 +- .../peerplays_sidechain_plugin.hpp | 2 + .../sidechain_net_handler.hpp | 10 +- .../sidechain_net_handler_bitcoin.hpp | 19 +-- .../sidechain_net_manager.hpp | 7 +- .../peerplays_sidechain_plugin.cpp | 139 +++++++++++---- .../sidechain_net_handler.cpp | 45 +++-- .../sidechain_net_handler_bitcoin.cpp | 158 ++++-------------- .../sidechain_net_manager.cpp | 13 +- libraries/wallet/CMakeLists.txt | 2 +- .../wallet/include/graphene/wallet/wallet.hpp | 84 ++++++++++ libraries/wallet/wallet.cpp | 117 +++++++++++++ programs/js_operation_serializer/main.cpp | 1 + tests/CMakeLists.txt | 2 +- tests/tests/sidechain_addresses_test.cpp | 143 ++++++++++++++++ 29 files changed, 972 insertions(+), 228 deletions(-) create mode 100644 libraries/chain/include/graphene/chain/protocol/sidechain_address.hpp create mode 100644 libraries/chain/include/graphene/chain/sidechain_address_evaluator.hpp create mode 100644 libraries/chain/include/graphene/chain/sidechain_address_object.hpp create mode 100644 libraries/chain/sidechain_address_evaluator.cpp create mode 100644 tests/tests/sidechain_addresses_test.cpp diff --git a/libraries/app/CMakeLists.txt b/libraries/app/CMakeLists.txt index 93e540f9..e6f8940c 100644 --- a/libraries/app/CMakeLists.txt +++ b/libraries/app/CMakeLists.txt @@ -14,7 +14,7 @@ add_library( graphene_app # need to link graphene_debug_witness because plugins aren't sufficiently isolated #246 #target_link_libraries( graphene_app graphene_market_history graphene_account_history graphene_chain fc graphene_db graphene_net graphene_utilities graphene_debug_witness ) -target_link_libraries( graphene_app graphene_market_history graphene_account_history graphene_accounts_list graphene_affiliate_stats graphene_chain fc graphene_db graphene_net graphene_time graphene_utilities graphene_debug_witness graphene_bookie ) +target_link_libraries( graphene_app graphene_market_history graphene_account_history graphene_accounts_list graphene_affiliate_stats graphene_chain fc graphene_db graphene_net graphene_time graphene_utilities graphene_debug_witness graphene_bookie peerplays_sidechain ) target_include_directories( graphene_app PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../egenesis/include" ) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 833069f8..d31abe19 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -443,6 +443,11 @@ namespace graphene { namespace app { assert( aobj != nullptr ); accounts.insert( aobj->son_account ); break; + } case sidechain_address_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->sidechain_address_account ); + break; } case sport_object_type: case event_group_object_type: diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index b9ae31b6..c4566d24 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -103,7 +103,7 @@ class database_api_impl : public std::enable_shared_from_this uint64_t get_asset_count()const; // Peerplays - vector list_sports() const; + vector list_sports() const; vector list_event_groups(sport_id_type sport_id) const; vector list_events_in_group(event_group_id_type event_group_id) const; vector list_betting_market_groups(event_id_type) const; @@ -115,14 +115,14 @@ class database_api_impl : public std::enable_shared_from_this vector get_lotteries( asset_id_type stop = asset_id_type(), unsigned limit = 100, asset_id_type start = asset_id_type() )const; - vector get_account_lotteries( account_id_type issuer, + vector get_account_lotteries( account_id_type issuer, asset_id_type stop, unsigned limit, asset_id_type start )const; asset get_lottery_balance( asset_id_type lottery_id )const; sweeps_vesting_balance_object get_sweeps_vesting_balance_object( account_id_type account )const; asset get_sweeps_vesting_balance_available_for_claim( account_id_type account )const; - + // Markets / feeds vector get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const; vector get_call_orders(asset_id_type a, uint32_t limit)const; @@ -152,6 +152,13 @@ class database_api_impl : public std::enable_shared_from_this map lookup_son_accounts(const string& lower_bound_name, uint32_t limit)const; uint64_t get_son_count()const; + // Sidechain addresses + vector> get_sidechain_addresses(const vector& sidechain_address_ids)const; + vector> get_sidechain_addresses_by_account(account_id_type account)const; + vector> get_sidechain_addresses_by_sidechain(peerplays_sidechain::sidechain_type sidechain)const; + fc::optional get_sidechain_address_by_account_and_sidechain(account_id_type account, peerplays_sidechain::sidechain_type sidechain)const; + uint64_t get_sidechain_addresses_count()const; + // Votes vector lookup_vote_ids( const vector& votes )const; @@ -528,11 +535,11 @@ vector> database_api::get_key_references( vector> database_api_impl::get_key_references( vector keys )const { wdump( (keys) ); - + const auto& idx = _db.get_index_type(); const auto& aidx = dynamic_cast(idx); const auto& refs = aidx.get_secondary_index(); - + vector< vector > final_result; final_result.reserve(keys.size()); @@ -648,7 +655,7 @@ std::map database_api_impl::get_full_accounts( const const auto& proposal_idx = _db.get_index_type(); const auto& pidx = dynamic_cast(proposal_idx); const auto& proposals_by_account = pidx.get_secondary_index(); - + std::map results; for (const std::string& account_name_or_id : names_or_ids) @@ -738,7 +745,7 @@ std::map database_api_impl::get_full_accounts( const acnt.withdraws.emplace_back(withdraw); }); - auto pending_payouts_range = + auto pending_payouts_range = _db.get_index_type().indices().get().equal_range(boost::make_tuple(account->id)); std::copy(pending_payouts_range.first, pending_payouts_range.second, std::back_inserter(acnt.pending_dividend_payments)); @@ -1058,7 +1065,7 @@ vector database_api_impl::get_lotteries( asset_id_type stop, return result; } -vector database_api::get_account_lotteries( account_id_type issuer, +vector database_api::get_account_lotteries( account_id_type issuer, asset_id_type stop, unsigned limit, asset_id_type start )const @@ -1066,7 +1073,7 @@ vector database_api::get_account_lotteries( account_id_type issuer return my->get_account_lotteries( issuer, stop, limit, start ); } -vector database_api_impl::get_account_lotteries( account_id_type issuer, +vector database_api_impl::get_account_lotteries( account_id_type issuer, asset_id_type stop, unsigned limit, asset_id_type start )const @@ -1763,6 +1770,85 @@ uint64_t database_api_impl::get_son_count()const return _db.get_index_type().indices().size(); } +////////////////////////////////////////////////////////////////////// +// // +// Sidechain Accounts // +// // +////////////////////////////////////////////////////////////////////// + +vector> database_api::get_sidechain_addresses(const vector& sidechain_address_ids)const +{ + return my->get_sidechain_addresses( sidechain_address_ids ); +} + +vector> database_api_impl::get_sidechain_addresses(const vector& sidechain_address_ids)const +{ + vector> result; result.reserve(sidechain_address_ids.size()); + std::transform(sidechain_address_ids.begin(), sidechain_address_ids.end(), std::back_inserter(result), + [this](sidechain_address_id_type id) -> optional { + if(auto o = _db.find(id)) + return *o; + return {}; + }); + return result; +} + +vector> database_api::get_sidechain_addresses_by_account(account_id_type account)const +{ + return my->get_sidechain_addresses_by_account( account ); +} + +vector> database_api_impl::get_sidechain_addresses_by_account(account_id_type account)const +{ + vector> result; + const auto& sidechain_addresses_range = _db.get_index_type().indices().get().equal_range(account); + std::for_each(sidechain_addresses_range.first, sidechain_addresses_range.second, + [&result] (const sidechain_address_object& sao) { + result.push_back(sao); + }); + return result; +} + +vector> database_api::get_sidechain_addresses_by_sidechain(peerplays_sidechain::sidechain_type sidechain)const +{ + return my->get_sidechain_addresses_by_sidechain( sidechain ); +} + +vector> database_api_impl::get_sidechain_addresses_by_sidechain(peerplays_sidechain::sidechain_type sidechain)const +{ + vector> result; + const auto& sidechain_addresses_range = _db.get_index_type().indices().get().equal_range(sidechain); + std::for_each(sidechain_addresses_range.first, sidechain_addresses_range.second, + [&result] (const sidechain_address_object& sao) { + result.push_back(sao); + }); + return result; +} + +fc::optional database_api::get_sidechain_address_by_account_and_sidechain(account_id_type account, peerplays_sidechain::sidechain_type sidechain)const +{ + return my->get_sidechain_address_by_account_and_sidechain( account, sidechain ); +} + +fc::optional database_api_impl::get_sidechain_address_by_account_and_sidechain(account_id_type account, peerplays_sidechain::sidechain_type sidechain)const +{ + const auto& idx = _db.get_index_type().indices().get(); + auto itr = idx.find( boost::make_tuple( account, sidechain ) ); + if( itr != idx.end() ) + return *itr; + return {}; +} + +uint64_t database_api::get_sidechain_addresses_count()const +{ + return my->get_sidechain_addresses_count(); +} + +uint64_t database_api_impl::get_sidechain_addresses_count()const +{ + return _db.get_index_type().indices().size(); +} + ////////////////////////////////////////////////////////////////////// // // // Votes // @@ -2164,7 +2250,7 @@ vector database_api::get_tournaments(tournament_id_type stop, vector database_api_impl::get_tournaments(tournament_id_type stop, unsigned limit, - tournament_id_type start) + tournament_id_type start) { vector result; const auto& tournament_idx = _db.get_index_type().indices().get(); @@ -2191,7 +2277,7 @@ vector database_api_impl::get_tournaments_by_state(tournament unsigned limit, tournament_id_type start, tournament_state state) -{ +{ vector result; const auto& tournament_idx = _db.get_index_type().indices().get(); for (auto elem: tournament_idx) { @@ -2320,7 +2406,7 @@ void database_api_impl::handle_object_changed(bool force_notify, bool full_objec /// if a connection hangs then this could get backed up and result in /// a failure to exit cleanly. //fc::async([capture_this,this,updates,market_broadcast_queue](){ - //if( _subscribe_callback ) + //if( _subscribe_callback ) // _subscribe_callback( updates ); for(auto id : ids) diff --git a/libraries/app/impacted.cpp b/libraries/app/impacted.cpp index 66dc2939..5b6f5411 100644 --- a/libraries/app/impacted.cpp +++ b/libraries/app/impacted.cpp @@ -310,6 +310,15 @@ struct get_impacted_account_visitor void operator()( const son_heartbeat_operation& op ){ _impacted.insert( op.owner_account ); } + void operator()( const sidechain_address_add_operation& op ){ + _impacted.insert( op.sidechain_address_account ); + } + void operator()( const sidechain_address_update_operation& op ){ + _impacted.insert( op.sidechain_address_account ); + } + void operator()( const sidechain_address_delete_operation& op ){ + _impacted.insert( op.sidechain_address_account ); + } }; void operation_get_impacted_accounts( const operation& op, flat_set& result ) diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index d597110e..e3252ec6 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -602,6 +603,46 @@ class database_api */ uint64_t get_son_count()const; + ///////////////////////// + // Sidechain Addresses // + ///////////////////////// + + /** + * @brief Get a list of sidechain addresses + * @param sidechain_address_ids IDs of the sidechain addresses to retrieve + * @return The sidechain accounts corresponding to the provided IDs + * + * This function has semantics identical to @ref get_objects + */ + vector> get_sidechain_addresses(const vector& sidechain_address_ids)const; + + /** + * @brief Get the sidechain addresses for a given account + * @param account The ID of the account whose sidechain addresses should be retrieved + * @return The sidechain addresses objects, or null if the account does not have a sidechain addresses + */ + vector> get_sidechain_addresses_by_account(account_id_type account)const; + + /** + * @brief Get the sidechain addresses for a given sidechain + * @param sidechain Sidechain for which addresses should be retrieved + * @return The sidechain addresses objects, or null if the sidechain does not have any addresses + */ + vector> get_sidechain_addresses_by_sidechain(peerplays_sidechain::sidechain_type sidechain)const; + + /** + * @brief Get the sidechain addresses for a given account and sidechain + * @param account The ID of the account whose sidechain addresses should be retrieved + * @param sidechain Sidechain for which address should be retrieved + * @return The sidechain addresses objects, or null if the account does not have a sidechain addresses for a given sidechain + */ + fc::optional get_sidechain_address_by_account_and_sidechain(account_id_type account, peerplays_sidechain::sidechain_type sidechain)const; + + /** + * @brief Get the total number of sidechain addresses registered with the blockchain + */ + uint64_t get_sidechain_addresses_count()const; + /// WORKERS /** @@ -814,6 +855,13 @@ FC_API(graphene::app::database_api, (lookup_son_accounts) (get_son_count) + // Sidechain addresses + (get_sidechain_addresses) + (get_sidechain_addresses_by_account) + (get_sidechain_addresses_by_sidechain) + (get_sidechain_address_by_account_and_sidechain) + (get_sidechain_addresses_count) + // workers (get_workers_by_account) // Votes diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 5688eabf..4e3d4625 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -116,13 +116,15 @@ add_library( graphene_chain son_evaluator.cpp son_object.cpp + sidechain_address_evaluator.cpp + ${HEADERS} ${PROTOCOL_HEADERS} "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) add_dependencies( graphene_chain build_hardfork_hpp ) -target_link_libraries( graphene_chain fc graphene_db ) +target_link_libraries( graphene_chain fc graphene_db peerplays_sidechain ) target_include_directories( graphene_chain PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include" ) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 956e34a7..c4ddad18 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -78,6 +79,7 @@ #include #include #include +#include #include @@ -248,6 +250,9 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); + register_evaluator(); + register_evaluator(); } void database::initialize_indexes() @@ -292,6 +297,8 @@ void database::initialize_indexes() add_index< primary_index >(); add_index< primary_index >(); + add_index< primary_index >(); + //Implementation object indexes add_index< primary_index >(); diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index c71b2930..83a58c45 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -297,6 +297,15 @@ struct get_impacted_account_visitor void operator()( const son_heartbeat_operation& op ) { _impacted.insert( op.owner_account ); } + void operator()( const sidechain_address_add_operation& op ) { + _impacted.insert( op.sidechain_address_account ); + } + void operator()( const sidechain_address_update_operation& op ) { + _impacted.insert( op.sidechain_address_account ); + } + void operator()( const sidechain_address_delete_operation& op ) { + _impacted.insert( op.sidechain_address_account ); + } }; void operation_get_impacted_accounts( const operation& op, flat_set& result ) @@ -390,6 +399,11 @@ void get_relevant_accounts( const object* obj, flat_set& accoun assert( aobj != nullptr ); accounts.insert( aobj->son_account ); break; + } case sidechain_address_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->sidechain_address_account ); + break; } } } diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index a0e72094..e1cc5225 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -46,6 +46,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -140,7 +141,10 @@ namespace graphene { namespace chain { son_create_operation, son_update_operation, son_delete_operation, - son_heartbeat_operation + son_heartbeat_operation, + sidechain_address_add_operation, + sidechain_address_update_operation, + sidechain_address_delete_operation > operation; /// @} // operations group diff --git a/libraries/chain/include/graphene/chain/protocol/sidechain_address.hpp b/libraries/chain/include/graphene/chain/protocol/sidechain_address.hpp new file mode 100644 index 00000000..d0e658b4 --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/sidechain_address.hpp @@ -0,0 +1,66 @@ +#pragma once +#include + +#include + +namespace graphene { namespace chain { + + struct sidechain_address_add_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 0; }; + + asset fee; + account_id_type sidechain_address_account; + graphene::peerplays_sidechain::sidechain_type sidechain; + string address; + string private_key; + string public_key; + + account_id_type fee_payer()const { return sidechain_address_account; } + share_type calculate_fee(const fee_parameters_type& k)const { return 0; } + }; + + struct sidechain_address_update_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 0; }; + + asset fee; + sidechain_address_id_type sidechain_address_id; + account_id_type sidechain_address_account; + graphene::peerplays_sidechain::sidechain_type sidechain; + optional address; + optional private_key; + optional public_key; + + account_id_type fee_payer()const { return sidechain_address_account; } + share_type calculate_fee(const fee_parameters_type& k)const { return 0; } + }; + + struct sidechain_address_delete_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 0; }; + + asset fee; + sidechain_address_id_type sidechain_address_id; + account_id_type sidechain_address_account; + graphene::peerplays_sidechain::sidechain_type sidechain; + + account_id_type fee_payer()const { return sidechain_address_account; } + share_type calculate_fee(const fee_parameters_type& k)const { return 0; } + }; + +} } // namespace graphene::chain + +FC_REFLECT(graphene::chain::sidechain_address_add_operation::fee_parameters_type, (fee) ) +FC_REFLECT(graphene::chain::sidechain_address_add_operation, (fee) + (sidechain_address_account)(sidechain)(address)(private_key)(public_key) ) + +FC_REFLECT(graphene::chain::sidechain_address_update_operation::fee_parameters_type, (fee) ) +FC_REFLECT(graphene::chain::sidechain_address_update_operation, (fee) + (sidechain_address_id) + (sidechain_address_account)(sidechain)(address)(private_key)(public_key) ) + +FC_REFLECT(graphene::chain::sidechain_address_delete_operation::fee_parameters_type, (fee) ) +FC_REFLECT(graphene::chain::sidechain_address_delete_operation, (fee) + (sidechain_address_id) + (sidechain_address_account)(sidechain) ) diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index bcdd1a83..463c862f 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -147,6 +147,7 @@ namespace graphene { namespace chain { bet_object_type, son_object_type, son_proposal_object_type, + sidechain_address_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; @@ -209,6 +210,7 @@ namespace graphene { namespace chain { class bet_object; class son_object; class son_proposal_object; + class sidechain_address_object; typedef object_id< protocol_ids, account_object_type, account_object> account_id_type; typedef object_id< protocol_ids, asset_object_type, asset_object> asset_id_type; @@ -237,6 +239,7 @@ namespace graphene { namespace chain { typedef object_id< protocol_ids, bet_object_type, bet_object> bet_id_type; typedef object_id< protocol_ids, son_object_type, son_object> son_id_type; typedef object_id< protocol_ids, son_proposal_object_type, son_proposal_object> son_proposal_id_type; + typedef object_id< protocol_ids, sidechain_address_object_type, sidechain_address_object> sidechain_address_id_type; // implementation types class global_property_object; @@ -421,6 +424,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type, (bet_object_type) (son_object_type) (son_proposal_object_type) + (sidechain_address_object_type) (OBJECT_TYPE_COUNT) ) FC_REFLECT_ENUM( graphene::chain::impl_object_type, @@ -493,6 +497,7 @@ FC_REFLECT_TYPENAME( graphene::chain::global_betting_statistics_id_type ) FC_REFLECT_TYPENAME( graphene::chain::tournament_details_id_type ) FC_REFLECT_TYPENAME( graphene::chain::son_id_type ) FC_REFLECT_TYPENAME( graphene::chain::son_proposal_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::sidechain_address_id_type ) FC_REFLECT( graphene::chain::void_t, ) diff --git a/libraries/chain/include/graphene/chain/sidechain_address_evaluator.hpp b/libraries/chain/include/graphene/chain/sidechain_address_evaluator.hpp new file mode 100644 index 00000000..82bfcf1a --- /dev/null +++ b/libraries/chain/include/graphene/chain/sidechain_address_evaluator.hpp @@ -0,0 +1,34 @@ +#pragma once +#include +#include + +namespace graphene { namespace chain { + +class add_sidechain_address_evaluator : public evaluator +{ +public: + typedef sidechain_address_add_operation operation_type; + + void_result do_evaluate(const sidechain_address_add_operation& o); + object_id_type do_apply(const sidechain_address_add_operation& o); +}; + +class update_sidechain_address_evaluator : public evaluator +{ +public: + typedef sidechain_address_update_operation operation_type; + + void_result do_evaluate(const sidechain_address_update_operation& o); + object_id_type do_apply(const sidechain_address_update_operation& o); +}; + +class delete_sidechain_address_evaluator : public evaluator +{ +public: + typedef sidechain_address_delete_operation operation_type; + + void_result do_evaluate(const sidechain_address_delete_operation& o); + void_result do_apply(const sidechain_address_delete_operation& o); +}; + +} } // namespace graphene::chain diff --git a/libraries/chain/include/graphene/chain/sidechain_address_object.hpp b/libraries/chain/include/graphene/chain/sidechain_address_object.hpp new file mode 100644 index 00000000..8c77fad2 --- /dev/null +++ b/libraries/chain/include/graphene/chain/sidechain_address_object.hpp @@ -0,0 +1,70 @@ +#pragma once +#include +#include +#include + +#include + +namespace graphene { namespace chain { + using namespace graphene::db; + + /** + * @class sidechain_address_object + * @brief tracks information about a sidechain addresses for user accounts. + * @ingroup object + */ + class sidechain_address_object : public abstract_object + { + public: + static const uint8_t space_id = protocol_ids; + static const uint8_t type_id = sidechain_address_object_type; + + account_id_type sidechain_address_account; + graphene::peerplays_sidechain::sidechain_type sidechain; + string address; + string private_key; + string public_key; + + sidechain_address_object() : + sidechain(graphene::peerplays_sidechain::sidechain_type::bitcoin), + address(""), + private_key(""), + public_key("") {} + }; + + struct by_account; + struct by_sidechain; + struct by_account_and_sidechain; + struct by_sidechain_and_address; + using sidechain_address_multi_index_type = multi_index_container< + sidechain_address_object, + indexed_by< + ordered_unique< tag, + member + >, + ordered_non_unique< tag, + member + >, + ordered_non_unique< tag, + member + >, + ordered_unique< tag, + composite_key, + member + > + >, + ordered_unique< tag, + composite_key, + member + > + > + > + >; + using sidechain_address_index = generic_index; + +} } // graphene::chain + +FC_REFLECT_DERIVED( graphene::chain::sidechain_address_object, (graphene::db::object), + (sidechain_address_account)(sidechain)(address)(private_key)(public_key) ) diff --git a/libraries/chain/sidechain_address_evaluator.cpp b/libraries/chain/sidechain_address_evaluator.cpp new file mode 100644 index 00000000..d79d4cb1 --- /dev/null +++ b/libraries/chain/sidechain_address_evaluator.cpp @@ -0,0 +1,70 @@ +#include + +#include +#include +#include + +namespace graphene { namespace chain { + +void_result add_sidechain_address_evaluator::do_evaluate(const sidechain_address_add_operation& op) +{ try{ + + const auto& idx = db().get_index_type().indices().get(); + FC_ASSERT( idx.find(boost::make_tuple(op.sidechain_address_account, op.sidechain)) == idx.end(), "Duplicated item" ); + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +object_id_type add_sidechain_address_evaluator::do_apply(const sidechain_address_add_operation& op) +{ try { + const auto& new_sidechain_address_object = db().create( [&]( sidechain_address_object& obj ){ + obj.sidechain_address_account = op.sidechain_address_account; + obj.sidechain = op.sidechain; + obj.address = op.address; + obj.private_key = op.private_key; + obj.public_key = op.public_key; + }); + return new_sidechain_address_object.id; +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result update_sidechain_address_evaluator::do_evaluate(const sidechain_address_update_operation& op) +{ try { + FC_ASSERT(db().get(op.sidechain_address_id).sidechain_address_account == op.sidechain_address_account); + const auto& idx = db().get_index_type().indices().get(); + FC_ASSERT( idx.find(op.sidechain_address_id) != idx.end() ); + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +object_id_type update_sidechain_address_evaluator::do_apply(const sidechain_address_update_operation& op) +{ try { + const auto& idx = db().get_index_type().indices().get(); + auto itr = idx.find(op.sidechain_address_id); + if(itr != idx.end()) + { + db().modify(*itr, [&op](sidechain_address_object &sao) { + if(op.address.valid()) sao.address = *op.address; + if(op.private_key.valid()) sao.private_key = *op.private_key; + if(op.public_key.valid()) sao.public_key = *op.public_key; + }); + } + return op.sidechain_address_id; +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result delete_sidechain_address_evaluator::do_evaluate(const sidechain_address_delete_operation& op) +{ try { + FC_ASSERT(db().get(op.sidechain_address_id).sidechain_address_account == op.sidechain_address_account); + const auto& idx = db().get_index_type().indices().get(); + FC_ASSERT( idx.find(op.sidechain_address_id) != idx.end() ); + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result delete_sidechain_address_evaluator::do_apply(const sidechain_address_delete_operation& op) +{ try { + const auto& idx = db().get_index_type().indices().get(); + auto sidechain_address = idx.find(op.sidechain_address_id); + if(sidechain_address != idx.end()) { + db().remove(*sidechain_address); + } + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +} } // namespace graphene::chain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp index 1b6a9099..498784de 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp @@ -8,9 +8,10 @@ namespace graphene { namespace peerplays_sidechain { -enum network { +enum class sidechain_type { bitcoin, - //ethereum + //ethereum, + //eos }; using bytes = std::vector; @@ -59,7 +60,7 @@ struct info_for_vin }; struct sidechain_event_data { - network sidechain; + sidechain_type sidechain; std::string transaction_id; std::string from; std::string to; @@ -68,3 +69,4 @@ struct sidechain_event_data { } } // graphene::peerplays_sidechain +FC_REFLECT_ENUM(graphene::peerplays_sidechain::sidechain_type, (bitcoin) ) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp index 45628223..2f72ae06 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp @@ -5,6 +5,8 @@ #include #include +#include + namespace graphene { namespace peerplays_sidechain { using namespace chain; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp index fa4f0b50..e841a639 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -10,13 +11,16 @@ namespace graphene { namespace peerplays_sidechain { class sidechain_net_handler { public: - sidechain_net_handler(const boost::program_options::variables_map& options); + sidechain_net_handler(std::shared_ptr db, const boost::program_options::variables_map& options); virtual ~sidechain_net_handler(); - std::vector get_user_sidechain_address_mapping(); + std::vector get_sidechain_addresses(); protected: - graphene::peerplays_sidechain::network network; + std::shared_ptr 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 public_keys ) = 0; virtual std::string transfer( const std::string& from, const std::string& to, const uint64_t amount ) = 0; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp index 792aaf45..4c37c530 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp @@ -56,17 +56,9 @@ private: class sidechain_net_handler_bitcoin : public sidechain_net_handler { public: - sidechain_net_handler_bitcoin(const boost::program_options::variables_map& options); + sidechain_net_handler_bitcoin(std::shared_ptr db, const boost::program_options::variables_map& options); virtual ~sidechain_net_handler_bitcoin(); - void update_tx_infos( const std::string& block_hash ); - - //void update_tx_approvals(); - - //void update_estimated_fee(); - - //void send_btc_tx( const sidechain::bitcoin_transaction& trx ); - bool connection_is_not_defined() const; std::string create_multisignature_wallet( const std::vector public_keys ); @@ -83,18 +75,9 @@ private: std::unique_ptr listener; std::unique_ptr bitcoin_client; - graphene::chain::database* db; void handle_event( const std::string& event_data); - std::vector extract_info_from_block( const std::string& _block ); - - void update_transaction_status( std::vector trx_for_check ); - - std::set get_valid_vins( const std::string tx_hash ); - - inline uint64_t parse_amount(std::string raw); - }; } } // graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp index 49073314..c60aa73b 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -11,12 +12,12 @@ namespace graphene { namespace peerplays_sidechain { class sidechain_net_manager { public: - sidechain_net_manager(); + sidechain_net_manager(std::shared_ptr db); virtual ~sidechain_net_manager(); - bool create_handler(peerplays_sidechain::network network, const boost::program_options::variables_map& options); + bool create_handler(peerplays_sidechain::sidechain_type sidechain, const boost::program_options::variables_map& options); private: - + std::shared_ptr database; std::vector> net_handlers; }; diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 50739bef..a8741cff 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -14,20 +15,111 @@ namespace detail class peerplays_sidechain_plugin_impl { public: - peerplays_sidechain_plugin_impl(peerplays_sidechain_plugin& _plugin) - : _self( _plugin ) - { } + peerplays_sidechain_plugin_impl(peerplays_sidechain_plugin& _plugin); virtual ~peerplays_sidechain_plugin_impl(); - peerplays_sidechain_plugin& _self; + void plugin_set_program_options( + boost::program_options::options_description& cli, + boost::program_options::options_description& cfg); + void plugin_initialize(const boost::program_options::variables_map& options); + void plugin_startup(); - peerplays_sidechain::sidechain_net_manager _net_manager; +private: + peerplays_sidechain_plugin& plugin; + bool config_ready_son; + bool config_ready_bitcoin; + + std::unique_ptr net_manager; }; +peerplays_sidechain_plugin_impl::peerplays_sidechain_plugin_impl(peerplays_sidechain_plugin& _plugin) : + plugin( _plugin ), + config_ready_son(false), + config_ready_bitcoin(false), + net_manager(nullptr) +{ +} + peerplays_sidechain_plugin_impl::~peerplays_sidechain_plugin_impl() { - return; +} + +void peerplays_sidechain_plugin_impl::plugin_set_program_options( + boost::program_options::options_description& cli, + boost::program_options::options_description& cfg) +{ + auto default_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("nathan"))); + string son_id_example = fc::json::to_string(chain::son_id_type(5)); + + cli.add_options() + ("son-id", bpo::value>(), ("ID of SON controlled by this node (e.g. " + son_id_example + ", quotes are required)").c_str()) + ("peerplays-private-key", bpo::value>()->composing()->multitoken()-> + DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))), + "Tuple of [PublicKey, WIF private key]") + + ("bitcoin-node-ip", bpo::value()->default_value("99.79.189.95"), "IP address of Bitcoin node") + ("bitcoin-node-zmq-port", bpo::value()->default_value(11111), "ZMQ port of Bitcoin node") + ("bitcoin-node-rpc-port", bpo::value()->default_value(22222), "RPC port of Bitcoin node") + ("bitcoin-node-rpc-user", bpo::value()->default_value("1"), "Bitcoin RPC user") + ("bitcoin-node-rpc-password", bpo::value()->default_value("1"), "Bitcoin RPC password") + ("bitcoin-address", bpo::value()->default_value("2N911a7smwDzUGARg8s7Q1ViizFCw6gWcbR"), "Bitcoin address") + ("bitcoin-public-key", bpo::value()->default_value("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772"), "Bitcoin public key") + ("bitcoin-private-key", bpo::value()->default_value("cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr"), "Bitcoin private key") + ; + cfg.add(cli); +} + +void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_options::variables_map& options) +{ + config_ready_son = options.count( "son-id" ) && options.count( "peerplays-private-key" ); + if (config_ready_son) { + } else { + wlog("Haven't set up SON parameters"); + throw; + } + + net_manager = std::unique_ptr(new sidechain_net_manager(plugin.app().chain_database())); + + config_ready_bitcoin = options.count( "bitcoin-node-ip" ) && + options.count( "bitcoin-node-zmq-port" ) && options.count( "bitcoin-node-rpc-port" ) && + options.count( "bitcoin-node-rpc-user" ) && options.count( "bitcoin-node-rpc-password" ) && + options.count( "bitcoin-address" ) && options.count( "bitcoin-public-key" ) && options.count( "bitcoin-private-key" ); + if (config_ready_bitcoin) { + net_manager->create_handler(sidechain_type::bitcoin, options); + ilog("Bitcoin sidechain handler created"); + } else { + wlog("Haven't set up Bitcoin sidechain parameters"); + } + + //config_ready_ethereum = options.count( "ethereum-node-ip" ) && + // options.count( "ethereum-address" ) && options.count( "ethereum-public-key" ) && options.count( "ethereum-private-key" ); + //if (config_ready_ethereum) { + // net_manager->create_handler(sidechain_type::ethereum, options); + // ilog("Ethereum sidechain handler created"); + //} else { + // wlog("Haven't set up Ethereum sidechain parameters"); + //} + + if (!(config_ready_bitcoin /*&& config_ready_ethereum*/)) { + wlog("Haven't set up any sidechain parameters"); + throw; + } +} + +void peerplays_sidechain_plugin_impl::plugin_startup() +{ + if (config_ready_son) { + ilog("SON running"); + } + + if (config_ready_bitcoin) { + ilog("Bitcoin sidechain handler running"); + } + + //if (config_ready_ethereum) { + // ilog("Ethereum sidechain handler running"); + //} } } // end namespace detail @@ -49,47 +141,22 @@ std::string peerplays_sidechain_plugin::plugin_name()const void peerplays_sidechain_plugin::plugin_set_program_options( boost::program_options::options_description& cli, - boost::program_options::options_description& cfg - ) + boost::program_options::options_description& cfg) { - auto default_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("nathan"))); - string son_id_example = fc::json::to_string(chain::son_id_type(5)); - - cli.add_options() - ("son-id,w", bpo::value>(), ("ID of SON controlled by this node (e.g. " + son_id_example + ", quotes are required)").c_str()) - ("peerplays-private-key", bpo::value>()->composing()->multitoken()-> - DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))), - "Tuple of [PublicKey, WIF private key]") - - ("bitcoin-node-ip", bpo::value()->default_value("99.79.189.95"), "IP address of Bitcoin node") - ("bitcoin-node-zmq-port", bpo::value()->default_value(11111), "ZMQ port of Bitcoin node") - ("bitcoin-node-rpc-port", bpo::value()->default_value(22222), "RPC port of Bitcoin node") - ("bitcoin-node-rpc-user", bpo::value()->default_value("1"), "Bitcoin RPC user") - ("bitcoin-node-rpc-password", bpo::value()->default_value("1"), "Bitcoin RPC password") - ("bitcoin-address", bpo::value()->default_value("2N911a7smwDzUGARg8s7Q1ViizFCw6gWcbR"), "Bitcoin address") - ("bitcoin-public-key", bpo::value()->default_value("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772"), "Bitcoin public key") - ("bitcoin-private-key", bpo::value()->default_value("cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr"), "Bitcoin private key") - ; - cfg.add(cli); + ilog("peerplays sidechain plugin: plugin_set_program_options()"); + my->plugin_set_program_options(cli, cfg); } void peerplays_sidechain_plugin::plugin_initialize(const boost::program_options::variables_map& options) { ilog("peerplays sidechain plugin: plugin_initialize()"); - - if( options.count( "bitcoin-node-ip" ) && options.count( "bitcoin-node-zmq-port" ) && options.count( "bitcoin-node-rpc-port" ) - && options.count( "bitcoin-node-rpc-user" ) && options.count( "bitcoin-node-rpc-password" ) - && options.count( "bitcoin-address" ) && options.count( "bitcoin-public-key" ) && options.count( "bitcoin-private-key" ) ) - { - my->_net_manager.create_handler(network::bitcoin, options); - } else { - wlog("Haven't set up bitcoin sidechain parameters"); - } + my->plugin_initialize(options); } void peerplays_sidechain_plugin::plugin_startup() { ilog("peerplays sidechain plugin: plugin_startup()"); + my->plugin_startup(); } } } // graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index fefeacc1..85196685 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -1,29 +1,34 @@ #include +#include + +#include + namespace graphene { namespace peerplays_sidechain { -sidechain_net_handler::sidechain_net_handler(const boost::program_options::variables_map& options) { +sidechain_net_handler::sidechain_net_handler(std::shared_ptr db, const boost::program_options::variables_map& options) : + database(db) +{ } sidechain_net_handler::~sidechain_net_handler() { } -std::vector sidechain_net_handler::get_user_sidechain_address_mapping() { +std::vector sidechain_net_handler::get_sidechain_addresses() { std::vector result; - switch (network) { - case network::bitcoin: - result.push_back("2N5aFW5WFaYZLuJWx9RGziHBdEMj9Zf8s3J"); - result.push_back("2MxAnE469fhhdvUqUB7daU997VSearb2mn7"); - result.push_back("2NAYptFvTU8vJ1pC7CxvVA9R7D3NdBJHpwL"); - result.push_back("2N9zPaLDfaJazUmVfr3wgn8BK75tid2kkzR"); - result.push_back("2NDN7cDH3E57E1B8TwTYvBgF7CndL4FTBPL"); - //result.push_back("2MzEmSiwrRzozxE6gfZ14LAyDHZ4DYP1zVG"); - //result.push_back("2NDCdm1WVJVCMWJzRaSSy9NDvpNKiqkbrMg"); - //result.push_back("2Mu2iz3Jfqjyv3hBQGQZSGmZGZxhJp91TNX"); - //result.push_back("2N1sFbwcn4QVbvjp7yRsN4mg4mBFbvC8gKM"); - //result.push_back("2NDmxr6ufBE7Zgdgq9hShF2grx2YPEiTyNy"); - + switch (sidechain) { + case sidechain_type::bitcoin: + { + const auto& sidechain_addresses_idx = database->get_index_type(); + const auto& sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get(); + const auto& sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain); + std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second, + [&result] (const sidechain_address_object& sao) { + result.push_back(sao.address); + }); + break; + } default: assert(false); } @@ -31,5 +36,15 @@ std::vector sidechain_net_handler::get_user_sidechain_address_mappi return result; } +void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_data& sed) { + ilog( __FUNCTION__ ); + ilog( "sidechain_event_data:" ); + ilog( " sidechain: ${sidechain}", ( "sidechain", sed.sidechain ) ); + ilog( " transaction_id: ${transaction_id}", ( "transaction_id", sed.transaction_id ) ); + ilog( " from: ${from}", ( "from", sed.from ) ); + ilog( " to: ${to}", ( "to", sed.to ) ); + ilog( " amount: ${amount}", ( "amount", sed.amount ) ); +} + } } // graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 1fce21ea..a2bd8d94 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -11,7 +11,7 @@ #include #include -#include "graphene/peerplays_sidechain/sidechain_net_manager.hpp" +#include namespace graphene { namespace peerplays_sidechain { @@ -178,17 +178,17 @@ void zmq_listener::handle_zmq() { while ( true ) { auto msg = receive_multipart(); const auto header = std::string( static_cast( msg[0].data() ), msg[0].size() ); - const auto hash = boost::algorithm::hex( std::string( static_cast( msg[1].data() ), msg[1].size() ) ); + const auto block_hash = boost::algorithm::hex( std::string( static_cast( msg[1].data() ), msg[1].size() ) ); - event_received( hash ); + event_received( block_hash ); } } // ============================================================================= -sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(const boost::program_options::variables_map& options) : - sidechain_net_handler(options) { - network = peerplays_sidechain::network::bitcoin; +sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(std::shared_ptr db, const boost::program_options::variables_map& options) : + sidechain_net_handler(db, options) { + sidechain = sidechain_type::bitcoin; ip = options.at("bitcoin-node-ip").as(); zmq_port = options.at("bitcoin-node-zmq-port").as(); @@ -206,74 +206,15 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(const boost::progra listener = std::unique_ptr( new zmq_listener( ip, zmq_port ) ); bitcoin_client = std::unique_ptr( new bitcoin_rpc_client( ip, rpc_port, rpc_user, rpc_password ) ); - //db = _db; listener->event_received.connect([this]( const std::string& event_data ) { std::thread( &sidechain_net_handler_bitcoin::handle_event, this, event_data ).detach(); } ); - - //db->send_btc_tx.connect([this]( const sidechain::bitcoin_transaction& trx ) { - // std::thread( &sidechain_net_handler_bitcoin::send_btc_tx, this, trx ).detach(); - //} ); } sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() { } -void sidechain_net_handler_bitcoin::update_tx_infos( const std::string& block_hash ) -{ - std::string block = bitcoin_client->receive_full_block( block_hash ); - if( block != "" ) { - const auto& vins = extract_info_from_block( block ); -// const auto& addr_idx = db->get_index_type().indices().get(); -// for( const auto& v : vins ) { -// const auto& addr_itr = addr_idx.find( v.address ); -// FC_ASSERT( addr_itr != addr_idx.end() ); -// db->i_w_info.insert_info_for_vin( prev_out{ v.out.hash_tx, v.out.n_vout, v.out.amount }, v.address, addr_itr->address.get_witness_script() ); -// } - } -} - -//void sidechain_net_handler_bitcoin::update_tx_approvals() -//{ -// std::vector trx_for_check; -// const auto& confirmations_num = db->get_sidechain_params().confirmations_num; -// -// db->bitcoin_confirmations.safe_for([&]( btc_tx_confirmations_index::iterator itr_b, btc_tx_confirmations_index::iterator itr_e ){ -// for(auto iter = itr_b; iter != itr_e; iter++) { -// db->bitcoin_confirmations.modify( iter->transaction_id, [&]( bitcoin_transaction_confirmations& obj ) { -// obj.count_block++; -// }); -// -// if( iter->count_block == confirmations_num ) { -// trx_for_check.push_back( iter->transaction_id ); -// } -// } -// }); -// -// update_transaction_status( trx_for_check ); -// -//} - -//void sidechain_net_handler_bitcoin::update_estimated_fee() -//{ -// db->estimated_feerate = bitcoin_client->receive_estimated_fee(); -//} - -//void sidechain_net_handler_bitcoin::send_btc_tx( const sidechain::bitcoin_transaction& trx ) -//{ -// std::set valid_vins; -// for( const auto& v : trx.vin ) { -// valid_vins.insert( v.prevout.hash ); -// } -// db->bitcoin_confirmations.insert( bitcoin_transaction_confirmations( trx.get_txid(), valid_vins ) ); -// -// FC_ASSERT( !bitcoin_client->connection_is_not_defined() ); -// const auto tx_hex = fc::to_hex( pack( trx ) ); -// -// bitcoin_client->send_btc_tx( tx_hex ); -//} - bool sidechain_net_handler_bitcoin::connection_is_not_defined() const { return listener->connection_is_not_defined() && bitcoin_client->connection_is_not_defined(); @@ -302,9 +243,27 @@ std::string sidechain_net_handler_bitcoin::send_transaction( const std::string& void sidechain_net_handler_bitcoin::handle_event( const std::string& event_data ) { ilog("peerplays sidechain plugin: sidechain_net_handler_bitcoin::handle_event"); ilog(" event_data: ${event_data}", ("event_data", event_data)); - //update_tx_approvals(); - //update_estimated_fee(); - //update_tx_infos( block_hash ); + + std::string block = bitcoin_client->receive_full_block( event_data ); + if( block != "" ) { + const auto& vins = extract_info_from_block( block ); + + const auto& sidechain_addresses_idx = database->get_index_type().indices().get(); + + for( const auto& v : vins ) { + const auto& addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain_type::bitcoin, v.address)); + if ( addr_itr == sidechain_addresses_idx.end() ) + continue; + + sidechain_event_data sed; + sed.sidechain = addr_itr->sidechain; + sed.transaction_id = v.out.hash_tx; + sed.from = ""; + sed.to = v.address; + sed.amount = v.out.amount; + sidechain_event_data_received(sed); + } + } } std::vector sidechain_net_handler_bitcoin::extract_info_from_block( const std::string& _block ) @@ -315,8 +274,6 @@ std::vector sidechain_net_handler_bitcoin::extract_info_from_block std::vector result; - const auto& addr_idx = get_user_sidechain_address_mapping();// db->get_index_type().indices().get(); - for (const auto& tx_child : block.get_child("tx")) { const auto& tx = tx_child.second; @@ -327,13 +284,11 @@ std::vector sidechain_net_handler_bitcoin::extract_info_from_block for (const auto& addr : script.get_child("addresses")) { // in which cases there can be more addresses? const auto address_base58 = addr.second.get_value(); - - auto it = find(addr_idx.begin(), addr_idx.end(), address_base58); - if (it == addr_idx.end()) continue; - info_for_vin vin; vin.out.hash_tx = tx.get_child("txid").get_value(); - vin.out.amount = parse_amount( o.second.get_child( "value" ).get_value() ); + string amount = o.second.get_child( "value" ).get_value(); + amount.erase(std::remove(amount.begin(), amount.end(), '.'), amount.end()); + vin.out.amount = std::stoll(amount); vin.out.n_vout = o.second.get_child( "n" ).get_value(); vin.address = address_base58; result.push_back( vin ); @@ -344,59 +299,6 @@ std::vector sidechain_net_handler_bitcoin::extract_info_from_block return result; } -//void sidechain_net_handler_bitcoin::update_transaction_status( std::vector trx_for_check ) -//{ -// const auto& confirmations_num = db->get_sidechain_params().confirmations_num; -// -// for( const auto& trx : trx_for_check ) { -// auto confirmations = bitcoin_client->receive_confirmations_tx( trx.str() ); -// db->bitcoin_confirmations.modify( trx, [&]( bitcoin_transaction_confirmations& obj ) { -// obj.count_block = confirmations; -// }); -// -// if( confirmations >= confirmations_num ) { -// db->bitcoin_confirmations.modify( trx, [&]( bitcoin_transaction_confirmations& obj ) { -// obj.confirmed = true; -// }); -// -// } else if( confirmations == 0 ) { -// auto is_in_mempool = bitcoin_client->receive_mempool_entry_tx( trx.str() ); -// -// std::set valid_vins; -// if( !is_in_mempool ) { -// valid_vins = get_valid_vins( trx.str() ); -// } -// -// db->bitcoin_confirmations.modify( trx, [&]( bitcoin_transaction_confirmations& obj ) { -// obj.missing = !is_in_mempool; -// obj.valid_vins = valid_vins; -// }); -// } -// } -//} - -//std::set sidechain_net_handler_bitcoin::get_valid_vins( const std::string tx_hash ) -//{ -// const auto& confirmations_obj = db->bitcoin_confirmations.find( fc::sha256( tx_hash ) ); -// FC_ASSERT( confirmations_obj.valid() ); -// -// std::set valid_vins; -// for( const auto& v : confirmations_obj->valid_vins ) { -// auto confirmations = bitcoin_client->receive_confirmations_tx( v.str() ); -// if( confirmations == 0 ) { -// continue; -// } -// valid_vins.insert( v ); -// } -// return valid_vins; -//} - -// Removes dot from amount output: "50.00000000" -inline uint64_t sidechain_net_handler_bitcoin::parse_amount(std::string raw) { - raw.erase(std::remove(raw.begin(), raw.end(), '.'), raw.end()); - return std::stoll(raw); -} - // ============================================================================= } } // graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp index e1c0bce6..7c39fd81 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp @@ -5,7 +5,9 @@ namespace graphene { namespace peerplays_sidechain { -sidechain_net_manager::sidechain_net_manager() { +sidechain_net_manager::sidechain_net_manager(std::shared_ptr db) : + database(db) +{ ilog(__FUNCTION__); } @@ -13,16 +15,17 @@ sidechain_net_manager::~sidechain_net_manager() { ilog(__FUNCTION__); } -bool sidechain_net_manager::create_handler(peerplays_sidechain::network network, const boost::program_options::variables_map& options) { +bool sidechain_net_manager::create_handler(peerplays_sidechain::sidechain_type sidechain, const boost::program_options::variables_map& options) { ilog(__FUNCTION__); bool ret_val = false; - switch (network) { - case network::bitcoin: { - std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_bitcoin(options)); + switch (sidechain) { + case sidechain_type::bitcoin: { + std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_bitcoin(database, options)); net_handlers.push_back(std::move(h)); ret_val = true; + break; } default: assert(false); diff --git a/libraries/wallet/CMakeLists.txt b/libraries/wallet/CMakeLists.txt index 8c9f8790..382adda1 100644 --- a/libraries/wallet/CMakeLists.txt +++ b/libraries/wallet/CMakeLists.txt @@ -23,7 +23,7 @@ else() endif() add_library( graphene_wallet wallet.cpp ${CMAKE_CURRENT_BINARY_DIR}/api_documentation.cpp ${HEADERS} ) -target_link_libraries( graphene_wallet PRIVATE graphene_app graphene_net graphene_chain graphene_utilities fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( graphene_wallet PRIVATE graphene_app graphene_net graphene_chain graphene_utilities fc peerplays_sidechain ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) target_include_directories( graphene_db PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) if(MSVC) diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 6a78d8d3..4c95b5f7 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1368,6 +1368,83 @@ class wallet_api */ map list_active_sons(); + /** Adds sidechain address owned by the given account for a given sidechain. + * + * An account can have at most one sidechain address for one sidechain. + * + * @param account the name or id of the account who owns the address + * @param sidechain a sidechain to whom address belongs + * @param address sidechain address + * @param private_key private key for sidechain address + * @param public_key public key for sidechain address + * @param broadcast true to broadcast the transaction on the network + * @returns the signed transaction adding sidechain address + */ + signed_transaction add_sidechain_address(string account, + peerplays_sidechain::sidechain_type sidechain, + string address, + string private_key, + string public_key, + bool broadcast = false); + + /** Updates existing sidechain address owned by the given account for a given sidechain. + * + * Only address, private key and public key might be updated. + * + * @param account the name or id of the account who owns the address + * @param sidechain a sidechain to whom address belongs + * @param address sidechain address + * @param private_key private key for sidechain address + * @param public_key public key for sidechain address + * @param broadcast true to broadcast the transaction on the network + * @returns the signed transaction updating sidechain address + */ + signed_transaction update_sidechain_address(string account, + peerplays_sidechain::sidechain_type sidechain, + string address, + string private_key, + string public_key, + bool broadcast = false); + + /** Deletes existing sidechain address owned by the given account for a given sidechain. + * + * @param account the name or id of the account who owns the address + * @param sidechain a sidechain to whom address belongs + * @param broadcast true to broadcast the transaction on the network + * @returns the signed transaction updating sidechain address + */ + signed_transaction delete_sidechain_address(string account, + peerplays_sidechain::sidechain_type sidechain, + bool broadcast = false); + + /** Retrieves all sidechain addresses owned by given account. + * + * @param account the name or id of the account who owns the address + * @returns the list of all sidechain addresses owned by given account. + */ + vector> get_sidechain_addresses_by_account(string account); + + /** Retrieves all sidechain addresses registered for a given sidechain. + * + * @param sidechain the name of the sidechain + * @returns the list of all sidechain addresses registered for a given sidechain. + */ + vector> get_sidechain_addresses_by_sidechain(peerplays_sidechain::sidechain_type sidechain); + + /** Retrieves sidechain address owned by given account for a given sidechain. + * + * @param account the name or id of the account who owns the address + * @param sidechain the name of the sidechain + * @returns the sidechain address owned by given account for a given sidechain. + */ + fc::optional get_sidechain_address_by_account_and_sidechain(string account, peerplays_sidechain::sidechain_type sidechain); + + /** Retrieves the total number of sidechain addresses registered in the system. + * + * @returns the total number of sidechain addresses registered in the system. + */ + uint64_t get_sidechain_addresses_count(); + /** Creates a witness object owned by the given account. * * An account can have at most one witness object. @@ -2121,6 +2198,13 @@ FC_API( graphene::wallet::wallet_api, (update_son) (delete_son) (list_sons) + (add_sidechain_address) + (update_sidechain_address) + (delete_sidechain_address) + (get_sidechain_addresses_by_account) + (get_sidechain_addresses_by_sidechain) + (get_sidechain_address_by_account_and_sidechain) + (get_sidechain_addresses_count) (create_witness) (update_witness) (create_worker) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index f7cc2a51..6946a2cc 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -73,6 +73,7 @@ #include #include +#include #include #include @@ -1954,6 +1955,73 @@ public: return result; } FC_CAPTURE_AND_RETHROW() } + signed_transaction add_sidechain_address(string account, + peerplays_sidechain::sidechain_type sidechain, + string address, + string private_key, + string public_key, + bool broadcast /* = false */) + { try { + account_id_type sidechain_address_account_id = get_account_id(account); + + sidechain_address_add_operation op; + op.sidechain_address_account = sidechain_address_account_id; + op.sidechain = sidechain; + op.address = address; + op.private_key = private_key; + op.public_key = public_key; + + signed_transaction tx; + tx.operations.push_back( op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); + tx.validate(); + + return sign_transaction( tx, broadcast ); + } FC_CAPTURE_AND_RETHROW() } + + signed_transaction update_sidechain_address(string account, + peerplays_sidechain::sidechain_type sidechain, + string address, + string private_key, + string public_key, + bool broadcast /* = false */) + { try { + account_id_type sidechain_address_account_id = get_account_id(account); + + sidechain_address_update_operation op; + op.sidechain_address_account = sidechain_address_account_id; + op.sidechain = sidechain; + op.address = address; + op.private_key = private_key; + op.public_key = public_key; + + signed_transaction tx; + tx.operations.push_back( op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); + tx.validate(); + + return sign_transaction( tx, broadcast ); + } FC_CAPTURE_AND_RETHROW() } + + signed_transaction delete_sidechain_address(string account, + peerplays_sidechain::sidechain_type sidechain, + bool broadcast /* = false */) + { try { + account_id_type sidechain_address_account_id = get_account_id(account); + + sidechain_address_delete_operation op; + op.sidechain_address_account = sidechain_address_account_id; + op.sidechain = sidechain; + + signed_transaction tx; + tx.operations.push_back( op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); + tx.validate(); + + return sign_transaction( tx, broadcast ); + + } FC_CAPTURE_AND_RETHROW() } + signed_transaction create_witness(string owner_account, string url, bool broadcast /* = false */) @@ -4330,6 +4398,55 @@ map wallet_api::list_active_sons() return my->list_active_sons(); } +signed_transaction wallet_api::add_sidechain_address(string account, + peerplays_sidechain::sidechain_type sidechain, + string address, + string private_key, + string public_key, + bool broadcast /* = false */) +{ + return my->add_sidechain_address(account, sidechain, address, private_key, public_key, broadcast); +} + +signed_transaction wallet_api::update_sidechain_address(string account, + peerplays_sidechain::sidechain_type sidechain, + string address, + string private_key, + string public_key, + bool broadcast /* = false */) +{ + return my->update_sidechain_address(account, sidechain, address, private_key, public_key, broadcast); +} + +signed_transaction wallet_api::delete_sidechain_address(string account, + peerplays_sidechain::sidechain_type sidechain, + bool broadcast /* = false */) +{ + return my->delete_sidechain_address(account, sidechain, broadcast); +} + +vector> wallet_api::get_sidechain_addresses_by_account(string account) +{ + account_id_type account_id = get_account_id(account); + return my->_remote_db->get_sidechain_addresses_by_account(account_id); +} + +vector> wallet_api::get_sidechain_addresses_by_sidechain(peerplays_sidechain::sidechain_type sidechain) +{ + return my->_remote_db->get_sidechain_addresses_by_sidechain(sidechain); +} + +fc::optional wallet_api::get_sidechain_address_by_account_and_sidechain(string account, peerplays_sidechain::sidechain_type sidechain) +{ + account_id_type account_id = get_account_id(account); + return my->_remote_db->get_sidechain_address_by_account_and_sidechain(account_id, sidechain); +} + +uint64_t wallet_api::get_sidechain_addresses_count() +{ + return my->_remote_db->get_sidechain_addresses_count(); +} + signed_transaction wallet_api::create_witness(string owner_account, string url, bool broadcast /* = false */) diff --git a/programs/js_operation_serializer/main.cpp b/programs/js_operation_serializer/main.cpp index a921c0c3..2901f2e0 100644 --- a/programs/js_operation_serializer/main.cpp +++ b/programs/js_operation_serializer/main.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cf633dfd..b49e089e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,7 +8,7 @@ endif() file(GLOB UNIT_TESTS "tests/*.cpp") add_executable( chain_test ${UNIT_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( chain_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( chain_test graphene_chain graphene_app graphene_account_history graphene_bookie peerplays_sidechain graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) if(MSVC) set_source_files_properties( tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) endif(MSVC) diff --git a/tests/tests/sidechain_addresses_test.cpp b/tests/tests/sidechain_addresses_test.cpp new file mode 100644 index 00000000..eef76784 --- /dev/null +++ b/tests/tests/sidechain_addresses_test.cpp @@ -0,0 +1,143 @@ +#include + +#include "../common/database_fixture.hpp" + +#include +#include +#include + +using namespace graphene::chain; +using namespace graphene::chain::test; + +BOOST_FIXTURE_TEST_SUITE( sidechain_addresses_tests, database_fixture ) + +BOOST_AUTO_TEST_CASE( sidechain_address_add_test ) { + + BOOST_TEST_MESSAGE("sidechain_address_add_test"); + + generate_block(); + set_expiration(db, trx); + + ACTORS((alice)); + + generate_block(); + set_expiration(db, trx); + + { + BOOST_TEST_MESSAGE("Send sidechain_address_add_operation"); + + sidechain_address_add_operation op; + + op.sidechain_address_account = alice_id; + op.sidechain = graphene::peerplays_sidechain::sidechain_type::bitcoin; + op.address = "address"; + op.private_key = "private_key"; + op.public_key = "public_key"; + + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); + } + generate_block(); + + BOOST_TEST_MESSAGE("Check sidechain_address_add_operation results"); + + const auto& idx = db.get_index_type().indices().get(); + BOOST_REQUIRE( idx.size() == 1 ); + auto obj = idx.find( boost::make_tuple( alice_id, graphene::peerplays_sidechain::sidechain_type::bitcoin ) ); + BOOST_REQUIRE( obj != idx.end() ); + BOOST_CHECK( obj->sidechain_address_account == alice_id ); + BOOST_CHECK( obj->sidechain == graphene::peerplays_sidechain::sidechain_type::bitcoin ); + BOOST_CHECK( obj->address == "address" ); + BOOST_CHECK( obj->private_key == "private_key" ); + BOOST_CHECK( obj->public_key == "public_key" ); +} + +BOOST_AUTO_TEST_CASE( sidechain_address_update_test ) { + + BOOST_TEST_MESSAGE("sidechain_address_update_test"); + + INVOKE(sidechain_address_add_test); + + GET_ACTOR(alice); + + const auto& idx = db.get_index_type().indices().get(); + BOOST_REQUIRE( idx.size() == 1 ); + auto obj = idx.find( boost::make_tuple( alice_id, graphene::peerplays_sidechain::sidechain_type::bitcoin ) ); + BOOST_REQUIRE( obj != idx.end() ); + + std::string new_address = "new_address"; + std::string new_private_key = "new_private_key"; + std::string new_public_key = "new_public_key"; + + { + BOOST_TEST_MESSAGE("Send sidechain_address_update_operation"); + + sidechain_address_update_operation op; + op.sidechain_address_id = sidechain_address_id_type(0); + op.sidechain_address_account = obj->sidechain_address_account; + op.sidechain = obj->sidechain; + op.address = new_address; + op.private_key = new_private_key; + op.public_key = new_public_key; + + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); + } + generate_block(); + + { + BOOST_TEST_MESSAGE("Check sidechain_address_update_operation results"); + + const auto& idx = db.get_index_type().indices().get(); + BOOST_REQUIRE( idx.size() == 1 ); + auto obj = idx.find( boost::make_tuple( alice_id, graphene::peerplays_sidechain::sidechain_type::bitcoin ) ); + BOOST_REQUIRE( obj != idx.end() ); + BOOST_CHECK( obj->sidechain_address_account == obj->sidechain_address_account ); + BOOST_CHECK( obj->sidechain == obj->sidechain ); + BOOST_CHECK( obj->address == new_address ); + BOOST_CHECK( obj->private_key == new_private_key ); + BOOST_CHECK( obj->public_key == new_public_key ); + } +} + +BOOST_AUTO_TEST_CASE( sidechain_address_delete_test ) { + + BOOST_TEST_MESSAGE("sidechain_address_delete_test"); + + INVOKE(sidechain_address_add_test); + + GET_ACTOR(alice); + + const auto& idx = db.get_index_type().indices().get(); + BOOST_REQUIRE( idx.size() == 1 ); + auto obj = idx.find( boost::make_tuple( alice_id, graphene::peerplays_sidechain::sidechain_type::bitcoin ) ); + BOOST_REQUIRE( obj != idx.end() ); + + { + BOOST_TEST_MESSAGE("Send sidechain_address_delete_operation"); + + sidechain_address_delete_operation op; + op.sidechain_address_id = sidechain_address_id_type(0); + op.sidechain_address_account = obj->sidechain_address_account; + op.sidechain = obj->sidechain; + + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); + } + generate_block(); + + { + BOOST_TEST_MESSAGE("Check sidechain_address_delete_operation results"); + + const auto& idx = db.get_index_type().indices().get(); + BOOST_REQUIRE( idx.size() == 0 ); + auto obj = idx.find( boost::make_tuple( alice_id, graphene::peerplays_sidechain::sidechain_type::bitcoin ) ); + BOOST_REQUIRE( obj == idx.end() ); + } +} + +BOOST_AUTO_TEST_SUITE_END() + From a347e9764908e6af252e881adc91a1a649437e27 Mon Sep 17 00:00:00 2001 From: satyakoneru Date: Tue, 24 Dec 2019 00:30:49 +1100 Subject: [PATCH 2/3] SON207 - Introduce scheduling for SONs similar to witnesses (#251) --- libraries/chain/db_block.cpp | 18 ++- libraries/chain/db_init.cpp | 24 +++ libraries/chain/db_maint.cpp | 11 +- libraries/chain/db_witness_schedule.cpp | 142 ++++++++++++++++++ .../chain/include/graphene/chain/database.hpp | 18 +++ .../include/graphene/chain/protocol/types.hpp | 6 +- .../chain/witness_schedule_object.hpp | 57 +++++++ 7 files changed, 266 insertions(+), 10 deletions(-) diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index dafdc3ff..c6b4564c 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -649,8 +649,13 @@ void database::_apply_block( const signed_block& next_block ) _current_virtual_op = 0; } - if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM) - update_witness_schedule(next_block); + if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM) { + update_witness_schedule(next_block); + if(global_props.active_sons.size() > 0) { + update_son_schedule(next_block); + } + } + const uint32_t missed = update_witness_missed_blocks( next_block ); update_global_dynamic_data( next_block, missed ); update_signing_witness(signing_witness, next_block); @@ -678,8 +683,13 @@ void database::_apply_block( const signed_block& next_block ) // update_global_dynamic_data() as perhaps these methods only need // to be called for header validation? update_maintenance_flag( maint_needed ); - if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) - update_witness_schedule(); + if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) { + update_witness_schedule(); + if(global_props.active_sons.size() > 0) { + update_son_schedule(); + } + } + if( !_node_property_object.debug_updates.empty() ) apply_debug_updates(); diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index c4ddad18..31c0dcd5 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -314,6 +314,7 @@ void database::initialize_indexes() add_index< primary_index> >(); add_index< primary_index > >(); add_index< primary_index > >(); + add_index< primary_index > >(); add_index< primary_index > >(); add_index< primary_index< special_authority_index > >(); add_index< primary_index< buyback_index > >(); @@ -947,6 +948,29 @@ void database::init_genesis(const genesis_state_type& genesis_state) }); assert( wso.id == witness_schedule_id_type() ); + // Initialize witness schedule +#ifndef NDEBUG + const son_schedule_object& sso = +#endif + create([&](son_schedule_object& _sso) + { + // for scheduled + memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size()); + + witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); + + auto init_witnesses = get_global_properties().active_witnesses; + + _sso.scheduler = son_scheduler(); + _sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1); + + + _sso.last_scheduling_block = 0; + + _sso.recent_slots_filled = fc::uint128::max_value(); + }); + assert( sso.id == son_schedule_id_type() ); + // Enable fees modify(get_global_properties(), [&genesis_state](global_property_object& p) { p.parameters.current_fees = genesis_state.initial_parameters.current_fees; diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index cae17eda..8fb72566 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -455,11 +455,12 @@ void database::update_active_sons() }); }); - //const witness_schedule_object& wso = witness_schedule_id_type()(*this); - //modify(wso, [&](witness_schedule_object& _wso) - //{ - // _wso.scheduler.update(gpo.active_witnesses); - //}); + const son_schedule_object& sso = son_schedule_id_type()(*this); + modify(sso, [&](son_schedule_object& _sso) + { + flat_set active_sons(gpo.active_sons.begin(), gpo.active_sons.end()); + _sso.scheduler.update(active_sons); + }); } FC_CAPTURE_AND_RETHROW() } void database::initialize_budget_record( fc::time_point_sec now, budget_record& rec )const diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index e12c81dc..3ce11443 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -72,6 +73,47 @@ witness_id_type database::get_scheduled_witness( uint32_t slot_num )const return wid; } +son_id_type database::get_scheduled_son( uint32_t slot_num )const +{ + son_id_type sid; + const global_property_object& gpo = get_global_properties(); + if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) + { + const dynamic_global_property_object& dpo = get_dynamic_global_properties(); + const son_schedule_object& sso = son_schedule_id_type()(*this); + uint64_t current_aslot = dpo.current_aslot + slot_num; + return sso.current_shuffled_sons[ current_aslot % sso.current_shuffled_sons.size() ]; + } + if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM && + slot_num != 0 ) + { + const son_schedule_object& sso = son_schedule_id_type()(*this); + // ask the near scheduler who goes in the given slot + bool slot_is_near = sso.scheduler.get_slot(slot_num-1, sid); + if(! slot_is_near) + { + // if the near scheduler doesn't know, we have to extend it to + // a far scheduler. + // n.b. instantiating it is slow, but block gaps long enough to + // need it are likely pretty rare. + + witness_scheduler_rng far_rng(sso.rng_seed.begin(), GRAPHENE_FAR_SCHEDULE_CTR_IV); + + far_future_son_scheduler far_scheduler = + far_future_son_scheduler(sso.scheduler, far_rng); + if(!far_scheduler.get_slot(slot_num-1, sid)) + { + // no scheduled son -- somebody set up us the bomb + // n.b. this code path is impossible, the present + // implementation of far_future_son_scheduler + // returns true unconditionally + assert( false ); + } + } + } + return sid; +} + fc::time_point_sec database::get_slot_time(uint32_t slot_num)const { if( slot_num == 0 ) @@ -146,6 +188,41 @@ void database::update_witness_schedule() } } +void database::update_son_schedule() +{ + const son_schedule_object& sso = son_schedule_id_type()(*this); + const global_property_object& gpo = get_global_properties(); + + if( head_block_num() % gpo.active_sons.size() == 0 ) + { + modify( sso, [&]( son_schedule_object& _sso ) + { + _sso.current_shuffled_sons.clear(); + _sso.current_shuffled_sons.reserve( gpo.active_sons.size() ); + + for( const son_id_type& w : gpo.active_sons ) + _sso.current_shuffled_sons.push_back( w ); + + auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32; + for( uint32_t i = 0; i < _sso.current_shuffled_sons.size(); ++i ) + { + /// High performance random generator + /// http://xorshift.di.unimi.it/ + uint64_t k = now_hi + uint64_t(i)*2685821657736338717ULL; + k ^= (k >> 12); + k ^= (k << 25); + k ^= (k >> 27); + k *= 2685821657736338717ULL; + + uint32_t jmax = _sso.current_shuffled_sons.size() - i; + uint32_t j = i + k%jmax; + std::swap( _sso.current_shuffled_sons[i], + _sso.current_shuffled_sons[j] ); + } + }); + } +} + vector database::get_near_witness_schedule()const { const witness_schedule_object& wso = witness_schedule_id_type()(*this); @@ -226,6 +303,71 @@ void database::update_witness_schedule(const signed_block& next_block) idump( ( double(total_time/1000000.0)/calls) ); } +void database::update_son_schedule(const signed_block& next_block) +{ + auto start = fc::time_point::now(); + const global_property_object& gpo = get_global_properties(); + const son_schedule_object& sso = get(son_schedule_id_type()); + uint32_t schedule_needs_filled = gpo.active_sons.size(); + uint32_t schedule_slot = get_slot_at_time(next_block.timestamp); + + // We shouldn't be able to generate _pending_block with timestamp + // in the past, and incoming blocks from the network with timestamp + // in the past shouldn't be able to make it this far without + // triggering FC_ASSERT elsewhere + + assert( schedule_slot > 0 ); + + son_id_type first_son; + bool slot_is_near = sso.scheduler.get_slot( schedule_slot-1, first_son ); + + son_id_type son; + + const dynamic_global_property_object& dpo = get_dynamic_global_properties(); + + assert( dpo.random.data_size() == witness_scheduler_rng::seed_length ); + assert( witness_scheduler_rng::seed_length == sso.rng_seed.size() ); + + modify(sso, [&](son_schedule_object& _sso) + { + _sso.slots_since_genesis += schedule_slot; + witness_scheduler_rng rng(sso.rng_seed.data, _sso.slots_since_genesis); + + _sso.scheduler._min_token_count = std::max(int(gpo.active_sons.size()) / 2, 1); + + if( slot_is_near ) + { + uint32_t drain = schedule_slot; + while( drain > 0 ) + { + if( _sso.scheduler.size() == 0 ) + break; + _sso.scheduler.consume_schedule(); + --drain; + } + } + else + { + _sso.scheduler.reset_schedule( first_son ); + } + while( !_sso.scheduler.get_slot(schedule_needs_filled, son) ) + { + if( _sso.scheduler.produce_schedule(rng) & emit_turn ) + memcpy(_sso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size()); + } + _sso.last_scheduling_block = next_block.block_num(); + _sso.recent_slots_filled = ( + (_sso.recent_slots_filled << 1) + + 1) << (schedule_slot - 1); + }); + auto end = fc::time_point::now(); + static uint64_t total_time = 0; + static uint64_t calls = 0; + total_time += (end - start).count(); + if( ++calls % 1000 == 0 ) + idump( ( double(total_time/1000000.0)/calls) ); +} + uint32_t database::update_witness_missed_blocks( const signed_block& b ) { uint32_t missed_blocks = get_slot_at_time( b.timestamp ); diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 1e989a21..719c6240 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -240,6 +240,22 @@ namespace graphene { namespace chain { */ witness_id_type get_scheduled_witness(uint32_t slot_num)const; + /** + * @brief Get the son scheduled for block production in a slot. + * + * slot_num always corresponds to a time in the future. + * + * If slot_num == 1, returns the next scheduled son. + * If slot_num == 2, returns the next scheduled son after + * 1 block gap. + * + * Use the get_slot_time() and get_slot_at_time() functions + * to convert between slot_num and timestamp. + * + * Passing slot_num == 0 returns GRAPHENE_NULL_WITNESS + */ + son_id_type get_scheduled_son(uint32_t slot_num)const; + /** * Get the time at which the given slot occurs. * @@ -263,6 +279,8 @@ namespace graphene { namespace chain { vector get_near_witness_schedule()const; void update_witness_schedule(); void update_witness_schedule(const signed_block& next_block); + void update_son_schedule(); + void update_son_schedule(const signed_block& next_block); void check_lottery_end_by_participants( asset_id_type asset_id ); void check_ending_lotteries(); diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index 463c862f..5b040850 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -177,7 +177,8 @@ namespace graphene { namespace chain { impl_global_betting_statistics_object_type, impl_lottery_balance_object_type, impl_sweeps_vesting_balance_object_type, - impl_son_statistics_object_type + impl_son_statistics_object_type, + impl_son_schedule_object_type }; //typedef fc::unsigned_int object_id_type; @@ -264,6 +265,7 @@ namespace graphene { namespace chain { class lottery_balance_object; class sweeps_vesting_balance_object; class son_statistics_object; + class son_schedule_object; typedef object_id< implementation_ids, impl_global_property_object_type, global_property_object> global_property_id_type; typedef object_id< implementation_ids, impl_dynamic_global_property_object_type, dynamic_global_property_object> dynamic_global_property_id_type; @@ -293,6 +295,7 @@ namespace graphene { namespace chain { typedef object_id< implementation_ids, impl_lottery_balance_object_type, lottery_balance_object > lottery_balance_id_type; typedef object_id< implementation_ids, impl_sweeps_vesting_balance_object_type, sweeps_vesting_balance_object> sweeps_vesting_balance_id_type; typedef object_id< implementation_ids, impl_son_statistics_object_type, son_statistics_object > son_statistics_id_type; + typedef object_id< implementation_ids, impl_son_schedule_object_type, son_schedule_object> son_schedule_id_type; typedef fc::array symbol_type; typedef fc::ripemd160 block_id_type; @@ -453,6 +456,7 @@ FC_REFLECT_ENUM( graphene::chain::impl_object_type, (impl_lottery_balance_object_type) (impl_sweeps_vesting_balance_object_type) (impl_son_statistics_object_type) + (impl_son_schedule_object_type) ) FC_REFLECT_TYPENAME( graphene::chain::share_type ) diff --git a/libraries/chain/include/graphene/chain/witness_schedule_object.hpp b/libraries/chain/include/graphene/chain/witness_schedule_object.hpp index e4c4bb51..fc7d6d10 100644 --- a/libraries/chain/include/graphene/chain/witness_schedule_object.hpp +++ b/libraries/chain/include/graphene/chain/witness_schedule_object.hpp @@ -31,6 +31,7 @@ namespace graphene { namespace chain { class witness_schedule_object; +class son_schedule_object; typedef hash_ctr_rng< /* HashClass = */ fc::sha256, @@ -53,6 +54,22 @@ typedef generic_far_future_witness_scheduler< /* debug = */ true > far_future_witness_scheduler; +typedef generic_witness_scheduler< + /* WitnessID = */ son_id_type, + /* RNG = */ witness_scheduler_rng, + /* CountType = */ decltype( chain_parameters::maximum_son_count ), + /* OffsetType = */ uint32_t, + /* debug = */ true + > son_scheduler; + +typedef generic_far_future_witness_scheduler< + /* WitnessID = */ son_id_type, + /* RNG = */ witness_scheduler_rng, + /* CountType = */ decltype( chain_parameters::maximum_son_count ), + /* OffsetType = */ uint32_t, + /* debug = */ true + > far_future_son_scheduler; + class witness_schedule_object : public graphene::db::abstract_object { public: @@ -73,6 +90,26 @@ class witness_schedule_object : public graphene::db::abstract_object +{ + public: + static const uint8_t space_id = implementation_ids; + static const uint8_t type_id = impl_son_schedule_object_type; + + vector< son_id_type > current_shuffled_sons; + + son_scheduler scheduler; + uint32_t last_scheduling_block; + uint64_t slots_since_genesis = 0; + fc::array< char, sizeof(secret_hash_type) > rng_seed; + + /** + * Not necessary for consensus, but used for figuring out the participation rate. + * The nth bit is 0 if the nth slot was unfilled, else it is 1. + */ + fc::uint128 recent_slots_filled; +}; + } } @@ -96,3 +133,23 @@ FC_REFLECT_DERIVED( (recent_slots_filled) (current_shuffled_witnesses) ) +FC_REFLECT( graphene::chain::son_scheduler, + (_turns) + (_tokens) + (_min_token_count) + (_ineligible_waiting_for_token) + (_ineligible_no_turn) + (_eligible) + (_schedule) + (_lame_duck) + ) +FC_REFLECT_DERIVED( + graphene::chain::son_schedule_object, + (graphene::db::object), + (scheduler) + (last_scheduling_block) + (slots_since_genesis) + (rng_seed) + (recent_slots_filled) + (current_shuffled_sons) +) From 31ec55514bba09f846e5d622386f56f7f60cd196 Mon Sep 17 00:00:00 2001 From: obucinac Date: Mon, 23 Dec 2019 19:20:26 +0100 Subject: [PATCH 3/3] Extend SON objects to contain sidechain public keys (#254) --- .../include/graphene/chain/protocol/son.hpp | 7 +- .../include/graphene/chain/son_object.hpp | 4 +- libraries/chain/son_evaluator.cpp | 2 + .../graphene/peerplays_sidechain/defs.hpp | 7 +- .../wallet/include/graphene/wallet/wallet.hpp | 4 + libraries/wallet/wallet.cpp | 12 +- tests/cli/son.cpp | 109 +++++++++++++++--- tests/tests/son_operations_tests.cpp | 18 ++- 8 files changed, 132 insertions(+), 31 deletions(-) diff --git a/libraries/chain/include/graphene/chain/protocol/son.hpp b/libraries/chain/include/graphene/chain/protocol/son.hpp index 08e74a2d..914928a6 100644 --- a/libraries/chain/include/graphene/chain/protocol/son.hpp +++ b/libraries/chain/include/graphene/chain/protocol/son.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include namespace graphene { namespace chain { @@ -12,6 +13,7 @@ namespace graphene { namespace chain { std::string url; vesting_balance_id_type deposit; public_key_type signing_key; + flat_map sidechain_public_keys; vesting_balance_id_type pay_vb; account_id_type fee_payer()const { return owner_account; } @@ -28,6 +30,7 @@ namespace graphene { namespace chain { optional new_url; optional new_deposit; optional new_signing_key; + optional> new_sidechain_public_keys; optional new_pay_vb; account_id_type fee_payer()const { return owner_account; } @@ -63,12 +66,12 @@ namespace graphene { namespace chain { } } // namespace graphene::chain FC_REFLECT(graphene::chain::son_create_operation::fee_parameters_type, (fee) ) -FC_REFLECT(graphene::chain::son_create_operation, (fee)(owner_account)(url)(deposit)(signing_key) +FC_REFLECT(graphene::chain::son_create_operation, (fee)(owner_account)(url)(deposit)(signing_key)(sidechain_public_keys) (pay_vb) ) FC_REFLECT(graphene::chain::son_update_operation::fee_parameters_type, (fee) ) FC_REFLECT(graphene::chain::son_update_operation, (fee)(son_id)(owner_account)(new_url)(new_deposit) - (new_signing_key)(new_pay_vb) ) + (new_signing_key)(new_sidechain_public_keys)(new_pay_vb) ) FC_REFLECT(graphene::chain::son_delete_operation::fee_parameters_type, (fee) ) FC_REFLECT(graphene::chain::son_delete_operation, (fee)(son_id)(payer)(owner_account) ) diff --git a/libraries/chain/include/graphene/chain/son_object.hpp b/libraries/chain/include/graphene/chain/son_object.hpp index 4cbff5ed..11cabc2a 100644 --- a/libraries/chain/include/graphene/chain/son_object.hpp +++ b/libraries/chain/include/graphene/chain/son_object.hpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace graphene { namespace chain { using namespace graphene::db; @@ -60,6 +61,7 @@ namespace graphene { namespace chain { vesting_balance_id_type pay_vb; son_statistics_id_type statistics; son_status status = son_status::inactive; + flat_map sidechain_public_keys; void pay_son_fee(share_type pay, database& db); }; @@ -95,7 +97,7 @@ namespace graphene { namespace chain { FC_REFLECT_ENUM(graphene::chain::son_status, (inactive)(active)(in_maintenance)(deregistered) ) FC_REFLECT_DERIVED( graphene::chain::son_object, (graphene::db::object), - (son_account)(vote_id)(total_votes)(url)(deposit)(signing_key)(pay_vb) ) + (son_account)(vote_id)(total_votes)(url)(deposit)(signing_key)(pay_vb)(sidechain_public_keys) ) FC_REFLECT_DERIVED( graphene::chain::son_statistics_object, (graphene::db::object), diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index 4300bdbb..cee9740a 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -30,6 +30,7 @@ object_id_type create_son_evaluator::do_apply(const son_create_operation& op) obj.url = op.url; obj.deposit = op.deposit; obj.signing_key = op.signing_key; + obj.sidechain_public_keys = op.sidechain_public_keys; obj.pay_vb = op.pay_vb; obj.statistics = db().create([&](son_statistics_object& s){s.owner = obj.id;}).id; }); @@ -55,6 +56,7 @@ object_id_type update_son_evaluator::do_apply(const son_update_operation& op) if(op.new_url.valid()) so.url = *op.new_url; if(op.new_deposit.valid()) so.deposit = *op.new_deposit; if(op.new_signing_key.valid()) so.signing_key = *op.new_signing_key; + if(op.new_sidechain_public_keys.valid()) so.sidechain_public_keys = *op.new_sidechain_public_keys; if(op.new_pay_vb.valid()) so.pay_vb = *op.new_pay_vb; }); } diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp index 498784de..836cecb7 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp @@ -10,8 +10,9 @@ namespace graphene { namespace peerplays_sidechain { enum class sidechain_type { bitcoin, - //ethereum, - //eos + ethereum, + eos, + peerplays }; using bytes = std::vector; @@ -69,4 +70,4 @@ struct sidechain_event_data { } } // graphene::peerplays_sidechain -FC_REFLECT_ENUM(graphene::peerplays_sidechain::sidechain_type, (bitcoin) ) +FC_REFLECT_ENUM(graphene::peerplays_sidechain::sidechain_type, (bitcoin)(ethereum)(eos)(peerplays) ) diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 4c95b5f7..a158587a 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1312,6 +1312,7 @@ class wallet_api * display this when showing a list of SONs. May be blank. * @param deposit_id vesting balance id for SON deposit * @param pay_vb_id vesting balance id for SON pay_vb + * @param sidechain_public_keys The new set of sidechain public keys. * @param broadcast true to broadcast the transaction on the network * @returns the signed transaction registering a SON */ @@ -1319,6 +1320,7 @@ class wallet_api string url, vesting_balance_id_type deposit_id, vesting_balance_id_type pay_vb_id, + flat_map sidechain_public_keys, bool broadcast = false); /** @@ -1327,11 +1329,13 @@ class wallet_api * @param witness The name of the SON's owner account. Also accepts the ID of the owner account or the ID of the SON. * @param url Same as for create_son. The empty string makes it remain the same. * @param block_signing_key The new block signing public key. The empty string makes it remain the same. + * @param sidechain_public_keys The new set of sidechain public keys. The empty string makes it remain the same. * @param broadcast true if you wish to broadcast the transaction. */ signed_transaction update_son(string owner_account, string url, string block_signing_key, + flat_map sidechain_public_keys, bool broadcast = false); diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 6946a2cc..e88f4a00 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1863,6 +1863,7 @@ public: string url, vesting_balance_id_type deposit_id, vesting_balance_id_type pay_vb_id, + flat_map sidechain_public_keys, bool broadcast /* = false */) { try { account_object son_account = get_account(owner_account); @@ -1877,6 +1878,7 @@ public: son_create_op.url = url; son_create_op.deposit = deposit_id; son_create_op.pay_vb = pay_vb_id; + son_create_op.sidechain_public_keys = sidechain_public_keys; if (_remote_db->get_son_by_account(son_create_op.owner_account)) FC_THROW("Account ${owner_account} is already a SON", ("owner_account", owner_account)); @@ -1894,6 +1896,7 @@ public: signed_transaction update_son(string owner_account, string url, string block_signing_key, + flat_map sidechain_public_keys, bool broadcast /* = false */) { try { son_object son = get_son(owner_account); @@ -1906,6 +1909,9 @@ public: if( block_signing_key != "" ) { son_update_op.new_signing_key = public_key_type( block_signing_key ); } + if( !sidechain_public_keys.empty() ) { + son_update_op.new_sidechain_public_keys = sidechain_public_keys; + } signed_transaction tx; tx.operations.push_back( son_update_op ); @@ -4369,17 +4375,19 @@ signed_transaction wallet_api::create_son(string owner_account, string url, vesting_balance_id_type deposit_id, vesting_balance_id_type pay_vb_id, + flat_map sidechain_public_keys, bool broadcast /* = false */) { - return my->create_son(owner_account, url, deposit_id, pay_vb_id, broadcast); + return my->create_son(owner_account, url, deposit_id, pay_vb_id, sidechain_public_keys, broadcast); } signed_transaction wallet_api::update_son(string owner_account, string url, string block_signing_key, + flat_map sidechain_public_keys, bool broadcast /* = false */) { - return my->update_son(owner_account, url, block_signing_key, broadcast); + return my->update_son(owner_account, url, block_signing_key, sidechain_public_keys, broadcast); } signed_transaction wallet_api::delete_son(string owner_account, diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index b72bf567..b3b596c7 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -40,6 +40,7 @@ public: } void create_son(const std::string& account_name, const std::string& son_url, + flat_map& sidechain_public_keys, bool generate_maintenance = true) { graphene::wallet::brain_key_info bki; @@ -92,6 +93,7 @@ public: create_tx = fixture_.con.wallet_api_ptr->create_son(account_name, son_url, deposits[0].id, deposits[1].id, + sidechain_public_keys, true); if (generate_maintenance) @@ -110,9 +112,17 @@ BOOST_AUTO_TEST_CASE( create_sons ) BOOST_TEST_MESSAGE("SON cli wallet tests begin"); try { + flat_map sidechain_public_keys; + son_test_helper sth(*this); - sth.create_son("son1account", "http://son1"); - sth.create_son("son2account", "http://son2"); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 1"; + sth.create_son("son1account", "http://son1", sidechain_public_keys); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 2"; + sth.create_son("son2account", "http://son2", sidechain_public_keys); auto son1_obj = con.wallet_api_ptr->get_son("son1account"); BOOST_CHECK(son1_obj.son_account == con.wallet_api_ptr->get_account_id("son1account")); @@ -136,8 +146,13 @@ BOOST_AUTO_TEST_CASE( cli_update_son ) { BOOST_TEST_MESSAGE("Cli get_son and update_son Test"); + flat_map sidechain_public_keys; + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 1"; + son_test_helper sth(*this); - sth.create_son("sonmember", "http://sonmember"); + sth.create_son("sonmember", "http://sonmember", sidechain_public_keys); auto sonmember_acct = con.wallet_api_ptr->get_account("sonmember"); @@ -147,12 +162,16 @@ BOOST_AUTO_TEST_CASE( cli_update_son ) BOOST_CHECK(son_data.son_account == sonmember_acct.get_id()); // update SON - con.wallet_api_ptr->update_son("sonmember", "http://sonmember_updated", "", true); + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 2"; + + con.wallet_api_ptr->update_son("sonmember", "http://sonmember_updated", "", sidechain_public_keys, true); son_data = con.wallet_api_ptr->get_son("sonmember"); BOOST_CHECK(son_data.url == "http://sonmember_updated"); // update SON signing key - con.wallet_api_ptr->update_son("sonmember", "http://sonmember_updated2", "TEST6Yaq5ZNTTkMM2kBBzV5jktr8ETsniCC3bnVD7eFmegRrLXfGGG", true); + sidechain_public_keys.clear(); + con.wallet_api_ptr->update_son("sonmember", "http://sonmember_updated2", "TEST6Yaq5ZNTTkMM2kBBzV5jktr8ETsniCC3bnVD7eFmegRrLXfGGG", sidechain_public_keys, true); son_data = con.wallet_api_ptr->get_son("sonmember"); BOOST_CHECK(son_data.url == "http://sonmember_updated2"); BOOST_CHECK(std::string(son_data.signing_key) == "TEST6Yaq5ZNTTkMM2kBBzV5jktr8ETsniCC3bnVD7eFmegRrLXfGGG"); @@ -168,9 +187,17 @@ BOOST_AUTO_TEST_CASE( son_voting ) BOOST_TEST_MESSAGE("SON Vote cli wallet tests begin"); try { + flat_map sidechain_public_keys; + son_test_helper sth(*this); - sth.create_son("son1account", "http://son1"); - sth.create_son("son2account", "http://son2"); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 1"; + sth.create_son("son1account", "http://son1", sidechain_public_keys); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 2"; + sth.create_son("son2account", "http://son2", sidechain_public_keys); BOOST_TEST_MESSAGE("Voting for SONs"); @@ -239,9 +266,17 @@ BOOST_AUTO_TEST_CASE( delete_son ) BOOST_TEST_MESSAGE("SON delete cli wallet tests begin"); try { - son_test_helper sth(*this); - sth.create_son("son1account", "http://son1"); - sth.create_son("son2account", "http://son2"); + flat_map sidechain_public_keys; + + son_test_helper sth(*this); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 1"; + sth.create_son("son1account", "http://son1", sidechain_public_keys); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 2"; + sth.create_son("son2account", "http://son2", sidechain_public_keys); BOOST_TEST_MESSAGE("Deleting SONs"); signed_transaction delete_tx; @@ -279,11 +314,17 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture ) gpo = con.wallet_api_ptr->get_global_properties(); unsigned int son_number = gpo.parameters.maximum_son_count; + flat_map sidechain_public_keys; + // create son accounts for(unsigned int i = 0; i < son_number + 1; i++) { + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); sth.create_son("sonaccount" + fc::to_pretty_string(i), - "http://son" + fc::to_pretty_string(i), false); + "http://son" + fc::to_pretty_string(i), + sidechain_public_keys, + false); } BOOST_CHECK(generate_maintenance_block()); @@ -344,9 +385,17 @@ BOOST_AUTO_TEST_CASE( list_son ) BOOST_TEST_MESSAGE("List SONs cli wallet tests begin"); try { + flat_map sidechain_public_keys; + son_test_helper sth(*this); - sth.create_son("son1account", "http://son1"); - sth.create_son("son2account", "http://son2"); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 1"; + sth.create_son("son1account", "http://son1", sidechain_public_keys); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 2"; + sth.create_son("son2account", "http://son2", sidechain_public_keys); auto res = con.wallet_api_ptr->list_sons("", 100); BOOST_REQUIRE(res.size() == 2); @@ -366,9 +415,17 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test ) BOOST_TEST_MESSAGE("SON update_son_votes cli wallet tests begin"); try { - son_test_helper sth(*this); - sth.create_son("son1account", "http://son1"); - sth.create_son("son2account", "http://son2"); + flat_map sidechain_public_keys; + + son_test_helper sth(*this); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 1"; + sth.create_son("son1account", "http://son1", sidechain_public_keys); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 2"; + sth.create_son("son2account", "http://son2", sidechain_public_keys); BOOST_TEST_MESSAGE("Vote for 2 accounts with update_son_votes"); @@ -515,9 +572,17 @@ BOOST_AUTO_TEST_CASE( related_functions ) global_property_object gpo = con.wallet_api_ptr->get_global_properties(); BOOST_CHECK(gpo.active_sons.size() == 0); + flat_map sidechain_public_keys; + son_test_helper sth(*this); - sth.create_son("son1account", "http://son1"); - sth.create_son("son2account", "http://son2"); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 1"; + sth.create_son("son1account", "http://son1", sidechain_public_keys); + + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address 2"; + sth.create_son("son2account", "http://son2", sidechain_public_keys); gpo = con.wallet_api_ptr->get_global_properties(); BOOST_CHECK(gpo.active_sons.size() == 2); @@ -543,11 +608,17 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture ) gpo = con.wallet_api_ptr->get_global_properties(); unsigned int son_number = gpo.parameters.maximum_son_count; + flat_map sidechain_public_keys; + // create son accounts for(unsigned int i = 0; i < son_number + 1; i++) { + sidechain_public_keys.clear(); + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); sth.create_son("sonaccount" + fc::to_pretty_string(i), - "http://son" + fc::to_pretty_string(i), false); + "http://son" + fc::to_pretty_string(i), + sidechain_public_keys, + false); } BOOST_CHECK(generate_maintenance_block()); diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 3740335c..6751ff03 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -83,12 +83,16 @@ BOOST_AUTO_TEST_CASE( create_son_test ) { // alice became son { + flat_map sidechain_public_keys; + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin address"; + son_create_operation op; op.owner_account = alice_id; op.url = test_url; op.deposit = deposit; op.pay_vb = payment; op.signing_key = alice_public_key; + op.sidechain_public_keys = sidechain_public_keys; trx.operations.push_back(op); sign(trx, alice_private_key); PUSH_TX(db, trx, ~0); @@ -101,6 +105,7 @@ BOOST_AUTO_TEST_CASE( create_son_test ) { BOOST_REQUIRE( obj != idx.end() ); BOOST_CHECK( obj->url == test_url ); BOOST_CHECK( obj->signing_key == alice_public_key ); + BOOST_CHECK( obj->sidechain_public_keys.at(graphene::peerplays_sidechain::sidechain_type::bitcoin) == "bitcoin address" ); BOOST_CHECK( obj->deposit.instance == deposit.instance.value ); BOOST_CHECK( obj->pay_vb.instance == payment.instance.value ); } @@ -113,10 +118,14 @@ BOOST_AUTO_TEST_CASE( update_son_test ) { std::string new_url = "https://anewurl.com"; { + flat_map sidechain_public_keys; + sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "new bitcoin address"; + son_update_operation op; + op.son_id = son_id_type(0); op.owner_account = alice_id; op.new_url = new_url; - op.son_id = son_id_type(0); + op.new_sidechain_public_keys = sidechain_public_keys; trx.operations.push_back(op); sign(trx, alice_private_key); @@ -129,6 +138,7 @@ BOOST_AUTO_TEST_CASE( update_son_test ) { auto obj = idx.find( alice_id ); BOOST_REQUIRE( obj != idx.end() ); BOOST_CHECK( obj->url == new_url ); + BOOST_CHECK( obj->sidechain_public_keys.at(graphene::peerplays_sidechain::sidechain_type::bitcoin) == "new bitcoin address" ); } BOOST_AUTO_TEST_CASE( delete_son_test ) { @@ -335,7 +345,7 @@ BOOST_AUTO_TEST_CASE( son_pay_test ) op.amount = asset(50*GRAPHENE_BLOCKCHAIN_PRECISION); op.balance_type = vesting_balance_type::son; op.policy = dormant_vesting_policy_initializer {}; - + trx.operations.push_back(op); for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op); set_expiration(db, trx); @@ -352,7 +362,7 @@ BOOST_AUTO_TEST_CASE( son_pay_test ) op.owner = bob_id; op.amount = asset(1*GRAPHENE_BLOCKCHAIN_PRECISION); op.balance_type = vesting_balance_type::normal; - + trx.operations.push_back(op); for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op); set_expiration(db, trx); @@ -652,7 +662,7 @@ BOOST_AUTO_TEST_CASE( son_witness_proposal_test ) generate_block(); } FC_LOG_AND_RETHROW() -} +} BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {