From 988a1771ede12b2dc272fd6e25bb0f044b448dbb Mon Sep 17 00:00:00 2001 From: PixelPlex Date: Fri, 26 Jul 2019 13:05:35 +0300 Subject: [PATCH 01/16] Added SON object --- libraries/app/api.cpp | 7 +- libraries/app/database_api.cpp | 23 +++++++ libraries/app/impacted.cpp | 6 ++ .../app/include/graphene/app/database_api.hpp | 16 +++++ libraries/chain/CMakeLists.txt | 2 + .../son_operations_evaluator.cpp | 45 +++++++++++++ libraries/chain/db_init.cpp | 9 +++ libraries/chain/db_notify.cpp | 11 +++ .../graphene/chain/btc-sidechain/son.hpp | 46 +++++++++++++ .../chain/btc-sidechain/son_operations.hpp | 35 ++++++++++ .../son_operations_evaluator.hpp | 25 +++++++ .../graphene/chain/global_property_object.hpp | 2 + .../graphene/chain/protocol/account.hpp | 3 + .../graphene/chain/protocol/operations.hpp | 6 +- .../include/graphene/chain/protocol/types.hpp | 4 ++ .../include/graphene/chain/protocol/vote.hpp | 3 +- libraries/net/CMakeLists.txt | 2 +- .../wallet/include/graphene/wallet/wallet.hpp | 23 +++++++ libraries/wallet/wallet.cpp | 42 ++++++++++++ tests/CMakeLists.txt | 4 ++ tests/btc_sidechain_tests/main.cpp | 17 +++++ .../son_operations_tests.cpp | 67 +++++++++++++++++++ tests/common/genesis_file_util.hpp | 2 +- 23 files changed, 395 insertions(+), 5 deletions(-) create mode 100644 libraries/chain/btc-sidechain/son_operations_evaluator.cpp create mode 100644 libraries/chain/include/graphene/chain/btc-sidechain/son.hpp create mode 100644 libraries/chain/include/graphene/chain/btc-sidechain/son_operations.hpp create mode 100644 libraries/chain/include/graphene/chain/btc-sidechain/son_operations_evaluator.hpp create mode 100644 tests/btc_sidechain_tests/main.cpp create mode 100644 tests/btc_sidechain_tests/son_operations_tests.cpp diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 0cb6ae0de..9d3148dbb 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -432,7 +432,12 @@ namespace graphene { namespace app { } case balance_object_type:{ /** these are free from any accounts */ break; - } + } case son_member_object_type:{ + const auto& son_object = dynamic_cast(obj); + assert( son_object != nullptr ); + accounts.insert( son_object->son_member_account ); + break; + } case sport_object_type: case event_group_object_type: case event_object_type: diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 3f95a8c16..d6bffe04e 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -136,6 +136,9 @@ class database_api_impl : public std::enable_shared_from_this fc::optional get_committee_member_by_account(account_id_type account)const; map lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const; + // SON members + fc::optional get_son_member_by_account(account_id_type account)const; + // Votes vector lookup_vote_ids( const vector& votes )const; @@ -1577,6 +1580,26 @@ map database_api_impl::lookup_committee_member return committee_members_by_account_name; } +////////////////////////////////////////////////////////////////////// +// // +// SON members // +// // +////////////////////////////////////////////////////////////////////// + +fc::optional database_api::get_son_member_by_account(account_id_type account)const +{ + return my->get_son_member_by_account( account ); +} + +fc::optional database_api_impl::get_son_member_by_account(account_id_type account) const +{ + const auto& idx = _db.get_index_type().indices().get(); + auto itr = idx.find(account); + if( itr != idx.end() ) + return *itr; + return {}; +} + ////////////////////////////////////////////////////////////////////// // // // Votes // diff --git a/libraries/app/impacted.cpp b/libraries/app/impacted.cpp index 9d64cf11b..1b7797ffd 100644 --- a/libraries/app/impacted.cpp +++ b/libraries/app/impacted.cpp @@ -282,6 +282,12 @@ struct get_impacted_account_visitor _impacted.insert( op.affiliate ); } void operator()( const affiliate_referral_payout_operation& op ) { } + void operator()( const son_member_create_operation& op ){ + _impacted.insert( op.owner_account ); + } + void operator()( const son_member_delete_operation& op ){ + _impacted.insert( op.owner_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 3fac4b5f0..0500023e3 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -44,6 +44,8 @@ #include #include +#include + #include #include #include @@ -546,6 +548,17 @@ class database_api */ map lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const; + ///////////////// + // SON members // + ///////////////// + + /** + * @brief Get the son_member owned by a given account + * @param account The ID of the account whose son_member should be retrieved + * @return The son_member object, or null if the account does not have a son_member + */ + fc::optional get_son_member_by_account(account_id_type account)const; + /// WORKERS @@ -757,6 +770,9 @@ FC_API(graphene::app::database_api, (get_committee_member_by_account) (lookup_committee_member_accounts) + // SON members + (get_son_member_by_account) + // workers (get_workers_by_account) // Votes diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index a328cf1f1..c7c8e7f81 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -111,6 +111,8 @@ add_library( graphene_chain affiliate_payout.cpp + btc-sidechain/son_operations_evaluator.cpp + ${HEADERS} ${PROTOCOL_HEADERS} "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" diff --git a/libraries/chain/btc-sidechain/son_operations_evaluator.cpp b/libraries/chain/btc-sidechain/son_operations_evaluator.cpp new file mode 100644 index 000000000..9ce855b3d --- /dev/null +++ b/libraries/chain/btc-sidechain/son_operations_evaluator.cpp @@ -0,0 +1,45 @@ +#include + +#include +#include + +namespace graphene { namespace chain { + +void_result create_son_member_evaluator::do_evaluate(const son_member_create_operation& op) +{ try{ + FC_ASSERT(db().get(op.owner_account).is_lifetime_member(), "Only Lifetime members may register a SON."); + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +object_id_type create_son_member_evaluator::do_apply(const son_member_create_operation& op) +{ try { + vote_id_type vote_id; + db().modify(db().get_global_properties(), [&vote_id](global_property_object& p) { + vote_id = get_next_vote_id(p, vote_id_type::son); + }); + + const auto& new_son_object = db().create( [&]( son_member_object& obj ){ + obj.son_member_account = op.owner_account; + obj.vote_id = vote_id; + obj.url = op.url; + }); + return new_son_object.id; +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result delete_son_member_evaluator::do_evaluate(const son_member_delete_operation& op) +{ try { + database& d = db(); + const auto& idx = d.get_index_type().indices().get(); + FC_ASSERT( idx.find(op.owner_account) != idx.end() ); + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result delete_son_member_evaluator::do_apply(const son_member_delete_operation& op) +{ try { + const auto& idx = db().get_index_type().indices().get(); + db().remove(*idx.find(op.owner_account)); + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +} } // namespace graphene::chain + \ No newline at end of file diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index d58c68f75..d3f797966 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -77,8 +77,12 @@ #include #include +#include + #include +#include + #include #include #include @@ -237,6 +241,9 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + + register_evaluator(); + register_evaluator(); } void database::initialize_indexes() @@ -301,6 +308,8 @@ void database::initialize_indexes() //add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); + + add_index< primary_index >(); } void database::init_genesis(const genesis_state_type& genesis_state) diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 53ec524df..2f3d89c3a 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -269,6 +269,12 @@ struct get_impacted_account_visitor _impacted.insert( op.affiliate ); } void operator()( const affiliate_referral_payout_operation& op ) { } + void operator()( const son_member_create_operation& op ) { + _impacted.insert( op.owner_account ); + } + void operator()( const son_member_delete_operation& op ) { + _impacted.insert( op.owner_account ); + } }; void operation_get_impacted_accounts( const operation& op, flat_set& result ) @@ -357,6 +363,11 @@ void get_relevant_accounts( const object* obj, flat_set& accoun } case balance_object_type:{ /** these are free from any accounts */ break; + } case son_member_object_type:{ + const auto& son_object = dynamic_cast(obj); + assert( son_object != nullptr ); + accounts.insert( son_object->son_member_account ); + break; } } } diff --git a/libraries/chain/include/graphene/chain/btc-sidechain/son.hpp b/libraries/chain/include/graphene/chain/btc-sidechain/son.hpp new file mode 100644 index 000000000..6b6d7bac7 --- /dev/null +++ b/libraries/chain/include/graphene/chain/btc-sidechain/son.hpp @@ -0,0 +1,46 @@ +#pragma once +#include +#include +#include + +namespace graphene { namespace chain { + using namespace graphene::db; + + /** + * @class son_member_object + * @brief tracks information about a son_member account. + * @ingroup object + */ + class son_member_object : public abstract_object + { + public: + static const uint8_t space_id = protocol_ids; + static const uint8_t type_id = son_member_object_type; + + account_id_type son_member_account; + vote_id_type vote_id; + uint64_t total_votes = 0; + string url; + }; + + struct by_account; + struct by_vote_id; + using son_member_multi_index_type = multi_index_container< + son_member_object, + indexed_by< + ordered_unique< tag, + member + >, + ordered_unique< tag, + member + >, + ordered_unique< tag, + member + > + > + >; + using son_member_index = generic_index; +} } // graphene::chain + +FC_REFLECT_DERIVED( graphene::chain::son_member_object, (graphene::db::object), + (son_member_account)(vote_id)(total_votes)(url) ) diff --git a/libraries/chain/include/graphene/chain/btc-sidechain/son_operations.hpp b/libraries/chain/include/graphene/chain/btc-sidechain/son_operations.hpp new file mode 100644 index 000000000..700dc5fcd --- /dev/null +++ b/libraries/chain/include/graphene/chain/btc-sidechain/son_operations.hpp @@ -0,0 +1,35 @@ +#pragma once +#include + +namespace graphene { namespace chain { + + struct son_member_create_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 0; }; + + asset fee; + account_id_type owner_account; + std::string url; + + account_id_type fee_payer()const { return owner_account; } + share_type calculate_fee(const fee_parameters_type& k)const { return 0; } + }; + + struct son_member_delete_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 0; }; + + asset fee; + account_id_type owner_account; + + account_id_type fee_payer()const { return owner_account; } + share_type calculate_fee(const fee_parameters_type& k)const { return 0; } + }; + +} } // namespace graphene::chain + +FC_REFLECT( graphene::chain::son_member_create_operation::fee_parameters_type, (fee) ) +FC_REFLECT( graphene::chain::son_member_create_operation, (fee)(owner_account)(url) ) + +FC_REFLECT( graphene::chain::son_member_delete_operation::fee_parameters_type, (fee) ) +FC_REFLECT( graphene::chain::son_member_delete_operation, (fee)(owner_account) ) diff --git a/libraries/chain/include/graphene/chain/btc-sidechain/son_operations_evaluator.hpp b/libraries/chain/include/graphene/chain/btc-sidechain/son_operations_evaluator.hpp new file mode 100644 index 000000000..f6a3e63ed --- /dev/null +++ b/libraries/chain/include/graphene/chain/btc-sidechain/son_operations_evaluator.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include + +namespace graphene { namespace chain { + +class create_son_member_evaluator : public evaluator +{ +public: + typedef son_member_create_operation operation_type; + + void_result do_evaluate(const son_member_create_operation& o); + object_id_type do_apply(const son_member_create_operation& o); +}; + +class delete_son_member_evaluator : public evaluator +{ +public: + typedef son_member_delete_operation operation_type; + + void_result do_evaluate(const son_member_delete_operation& o); + void_result do_apply(const son_member_delete_operation& o); +}; + +} } // namespace graphene::chain diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index 77f85df68..277f6cf53 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -52,6 +52,8 @@ namespace graphene { namespace chain { vector active_committee_members; // updated once per maintenance interval flat_set active_witnesses; // updated once per maintenance interval // n.b. witness scheduling is done by witness_schedule object + + flat_set active_son_members; // updated once per maintenance interval }; /** diff --git a/libraries/chain/include/graphene/chain/protocol/account.hpp b/libraries/chain/include/graphene/chain/protocol/account.hpp index 6d13a4d3e..496e9067b 100644 --- a/libraries/chain/include/graphene/chain/protocol/account.hpp +++ b/libraries/chain/include/graphene/chain/protocol/account.hpp @@ -52,6 +52,9 @@ namespace graphene { namespace chain { /// The number of active committee members this account votes the blockchain should appoint /// Must not exceed the actual number of committee members voted for in @ref votes uint16_t num_committee = 0; + /// The number of active son members this account votes the blockchain should appoint + /// Must not exceed the actual number of son members voted for in @ref votes + uint16_t num_son = 0; /// This is the list of vote IDs this account votes for. The weight of these votes is determined by this /// account's balance of core asset. flat_set votes; diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index 104a2ec38..73258a9d5 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -45,6 +45,8 @@ #include #include +#include + namespace graphene { namespace chain { /** @@ -129,7 +131,9 @@ namespace graphene { namespace chain { sport_delete_operation, event_group_delete_operation, affiliate_payout_operation, // VIRTUAL - affiliate_referral_payout_operation // VIRTUAL + affiliate_referral_payout_operation, // VIRTUAL + son_member_create_operation, + son_member_delete_operation > operation; /// @} // operations group diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index 4b6e1589e..cdac849ba 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -145,6 +145,7 @@ namespace graphene { namespace chain { betting_market_group_object_type, betting_market_object_type, bet_object_type, + son_member_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; @@ -202,6 +203,7 @@ namespace graphene { namespace chain { class betting_market_group_object; class betting_market_object; class bet_object; + class son_member_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; @@ -228,6 +230,7 @@ namespace graphene { namespace chain { typedef object_id< protocol_ids, betting_market_group_object_type, betting_market_group_object> betting_market_group_id_type; typedef object_id< protocol_ids, betting_market_object_type, betting_market_object> betting_market_id_type; typedef object_id< protocol_ids, bet_object_type, bet_object> bet_id_type; + typedef object_id< protocol_ids, son_member_object_type, son_member_object> son_member_id_type; // implementation types class global_property_object; @@ -402,6 +405,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type, (betting_market_group_object_type) (betting_market_object_type) (bet_object_type) + (son_member_object_type) (OBJECT_TYPE_COUNT) ) FC_REFLECT_ENUM( graphene::chain::impl_object_type, diff --git a/libraries/chain/include/graphene/chain/protocol/vote.hpp b/libraries/chain/include/graphene/chain/protocol/vote.hpp index 215d49029..d970ed74a 100644 --- a/libraries/chain/include/graphene/chain/protocol/vote.hpp +++ b/libraries/chain/include/graphene/chain/protocol/vote.hpp @@ -64,6 +64,7 @@ struct vote_id_type committee, witness, worker, + son, VOTE_TYPE_COUNT }; @@ -148,5 +149,5 @@ void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo ); FC_REFLECT_TYPENAME( fc::flat_set ) -FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(VOTE_TYPE_COUNT) ) +FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(son)(VOTE_TYPE_COUNT) ) FC_REFLECT( graphene::chain::vote_id_type, (content) ) diff --git a/libraries/net/CMakeLists.txt b/libraries/net/CMakeLists.txt index 39f9cd05c..f8f323c32 100644 --- a/libraries/net/CMakeLists.txt +++ b/libraries/net/CMakeLists.txt @@ -10,7 +10,7 @@ set(SOURCES node.cpp add_library( graphene_net ${SOURCES} ${HEADERS} ) target_link_libraries( graphene_net - PUBLIC fc graphene_db ) + PUBLIC graphene_chain ) target_include_directories( graphene_net PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../chain/include" diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index a71891381..c15c3954a 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1378,6 +1378,28 @@ class wallet_api bool approve, bool broadcast = false); + /** Vote for a given son_member. + * + * An account can publish a list of all son_memberes they approve of. This + * command allows you to add or remove son_memberes from this list. + * Each account's vote is weighted according to the number of shares of the + * core asset owned by that account at the time the votes are tallied. + * + * @note you cannot vote against a son_member, you can only vote for the son_member + * or not vote for the son_member. + * + * @param voting_account the name or id of the account who is voting with their shares + * @param son_member the name or id of the son_member' owner account + * @param approve true if you wish to vote in favor of that son_member, false to + * remove your vote in favor of that son_member + * @param broadcast true if you wish to broadcast the transaction + * @return the signed transaction changing your vote for the given son_member + */ + signed_transaction vote_for_son_member(string voting_account, + string son_member, + bool approve, + bool broadcast = false); + /** Vote for a given witness. * * An account can publish a list of all witnesses they approve of. This @@ -1965,6 +1987,7 @@ FC_API( graphene::wallet::wallet_api, (get_vesting_balances) (withdraw_vesting) (vote_for_committee_member) + (vote_for_son_member) (vote_for_witness) (update_witness_votes) (set_voting_proxy) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 812740e6d..3c0629db4 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2024,6 +2024,40 @@ class wallet_api_impl return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (voting_account)(committee_member)(approve)(broadcast) ) } + signed_transaction vote_for_son_member(string voting_account, + string son_member, + bool approve, + bool broadcast /* = false */) + { try { + account_object voting_account_object = get_account(voting_account); + account_id_type son_member_owner_account_id = get_account_id(son_member); + fc::optional son_member_obj = _remote_db->get_son_member_by_account(son_member_owner_account_id); + if (!son_member_obj) + FC_THROW("Account ${son_member} is not registered as a son_member", ("son_member", son_member)); + if (approve) + { + auto insert_result = voting_account_object.options.votes.insert(son_member_obj->vote_id); + if (!insert_result.second) + FC_THROW("Account ${account} was already voting for son_member ${son_member}", ("account", voting_account)("son_member", son_member)); + } + else + { + unsigned votes_removed = voting_account_object.options.votes.erase(son_member_obj->vote_id); + if (!votes_removed) + FC_THROW("Account ${account} is already not voting for son_member ${son_member}", ("account", voting_account)("son_member", son_member)); + } + account_update_operation account_update_op; + account_update_op.account = voting_account_object.id; + account_update_op.new_options = voting_account_object.options; + + signed_transaction tx; + tx.operations.push_back( account_update_op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); + tx.validate(); + + return sign_transaction( tx, broadcast ); + } FC_CAPTURE_AND_RETHROW( (voting_account)(son_member)(approve)(broadcast) ) } + signed_transaction vote_for_witness(string voting_account, string witness, bool approve, @@ -4044,6 +4078,14 @@ signed_transaction wallet_api::vote_for_committee_member(string voting_account, return my->vote_for_committee_member(voting_account, witness, approve, broadcast); } +signed_transaction wallet_api::vote_for_son_member(string voting_account, + string son_member, + bool approve, + bool broadcast /* = false */) +{ + return my->vote_for_son_member(voting_account, son_member, approve, broadcast); +} + signed_transaction wallet_api::vote_for_witness(string voting_account, string witness, bool approve, diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 57a451aa8..bd7e0791d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -41,4 +41,8 @@ file(GLOB RANDOM_SOURCES "random/*.cpp") add_executable( random_test ${RANDOM_SOURCES} ${COMMON_SOURCES} ) target_link_libraries( random_test graphene_chain graphene_app graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +file(GLOB UNIT_TESTS "btc_sidechain_tests/*.cpp") +add_executable( btc_sidechain_test ${UNIT_TESTS} ${COMMON_SOURCES} ) +target_link_libraries( btc_sidechain_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) + add_subdirectory( generate_empty_blocks ) diff --git a/tests/btc_sidechain_tests/main.cpp b/tests/btc_sidechain_tests/main.cpp new file mode 100644 index 000000000..40b64f9d9 --- /dev/null +++ b/tests/btc_sidechain_tests/main.cpp @@ -0,0 +1,17 @@ +#include +#include +#include + +extern uint32_t GRAPHENE_TESTING_GENESIS_TIMESTAMP; + +boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { + std::srand(time(NULL)); + std::cout << "Random number generator seeded to " << time(NULL) << std::endl; + const char* genesis_timestamp_str = getenv("GRAPHENE_TESTING_GENESIS_TIMESTAMP"); + if( genesis_timestamp_str != nullptr ) + { + GRAPHENE_TESTING_GENESIS_TIMESTAMP = std::stoul( genesis_timestamp_str ); + } + std::cout << "GRAPHENE_TESTING_GENESIS_TIMESTAMP is " << GRAPHENE_TESTING_GENESIS_TIMESTAMP << std::endl; + return nullptr; +} diff --git a/tests/btc_sidechain_tests/son_operations_tests.cpp b/tests/btc_sidechain_tests/son_operations_tests.cpp new file mode 100644 index 000000000..08f9ca68a --- /dev/null +++ b/tests/btc_sidechain_tests/son_operations_tests.cpp @@ -0,0 +1,67 @@ +#include + +#include + +#include "../common/database_fixture.hpp" + +#include +#include + +using namespace graphene::chain; +using namespace graphene::chain::test; + +class test_create_son_member_evaluator: public create_son_member_evaluator { +public: + test_create_son_member_evaluator( database& link_db ): + ptr_trx_state( new transaction_evaluation_state( &link_db ) ) + { + trx_state = ptr_trx_state.get(); + } + std::unique_ptr ptr_trx_state; +}; + +class test_delete_son_member_evaluator: public delete_son_member_evaluator { +public: + test_delete_son_member_evaluator( database& link_db ): + ptr_trx_state( new transaction_evaluation_state( &link_db ) ) + { + trx_state = ptr_trx_state.get(); + } + std::unique_ptr ptr_trx_state; +}; + +BOOST_FIXTURE_TEST_SUITE( son_operation_tests, database_fixture ) + +BOOST_AUTO_TEST_CASE( create_son_test ){ + std::string test_url = "https://create_son_test"; + test_create_son_member_evaluator test_eval( db ); + son_member_create_operation op; + op.owner_account = account_id_type(1); + op.url = test_url; + + BOOST_CHECK_NO_THROW( test_eval.do_evaluate( op ) ); + auto id = test_eval.do_apply( op ); + const auto& idx = db.get_index_type().indices().get(); + + BOOST_REQUIRE( idx.size() == 1 ); + + auto obj = idx.find( op.owner_account ); + BOOST_REQUIRE( obj != idx.end() ); + BOOST_CHECK( obj->url == test_url ); + BOOST_CHECK( id == obj->id ); +} + +BOOST_AUTO_TEST_CASE( delete_son_test ){ + INVOKE(create_son_test); + test_delete_son_member_evaluator test_eval( db ); + + son_member_delete_operation delete_op; + delete_op.owner_account = account_id_type(1); + BOOST_CHECK_NO_THROW( test_eval.do_evaluate( delete_op ) ); + test_eval.do_apply( delete_op ); + + const auto& idx = db.get_index_type().indices().get(); + BOOST_REQUIRE( idx.empty() ); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/tests/common/genesis_file_util.hpp b/tests/common/genesis_file_util.hpp index e058df02c..be56eaf4a 100644 --- a/tests/common/genesis_file_util.hpp +++ b/tests/common/genesis_file_util.hpp @@ -40,4 +40,4 @@ boost::filesystem::path create_genesis_file(fc::temp_directory& directory) { fc::json::save_to_file(genesis_state, genesis_out); return genesis_path; -} +} \ No newline at end of file From 7d6b2156e44cccb2e1837072a7a9eebd3b15a5bd Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 19 Sep 2019 11:52:23 -0300 Subject: [PATCH 02/16] rename and move stuff --- .../app/include/graphene/app/database_api.hpp | 3 +-- libraries/chain/CMakeLists.txt | 2 +- libraries/chain/db_init.cpp | 8 ++------ .../graphene/chain/protocol/operations.hpp | 3 +-- .../son_operations.hpp => protocol/son.hpp} | 0 ...erations_evaluator.hpp => son_evaluator.hpp} | 2 +- .../{btc-sidechain/son.hpp => son_object.hpp} | 0 ...erations_evaluator.cpp => son_evaluator.cpp} | 4 ++-- tests/CMakeLists.txt | 4 ---- tests/btc_sidechain_tests/main.cpp | 17 ----------------- .../son_operations_tests.cpp | 4 ++-- 11 files changed, 10 insertions(+), 37 deletions(-) rename libraries/chain/include/graphene/chain/{btc-sidechain/son_operations.hpp => protocol/son.hpp} (100%) rename libraries/chain/include/graphene/chain/{btc-sidechain/son_operations_evaluator.hpp => son_evaluator.hpp} (92%) rename libraries/chain/include/graphene/chain/{btc-sidechain/son.hpp => son_object.hpp} (100%) rename libraries/chain/{btc-sidechain/son_operations_evaluator.cpp => son_evaluator.cpp} (93%) delete mode 100644 tests/btc_sidechain_tests/main.cpp rename tests/{btc_sidechain_tests => tests}/son_operations_tests.cpp (94%) diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 0500023e3..c64302432 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -43,8 +43,7 @@ #include #include #include - -#include +#include #include #include diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index c7c8e7f81..5b3eea311 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -111,7 +111,7 @@ add_library( graphene_chain affiliate_payout.cpp - btc-sidechain/son_operations_evaluator.cpp + son_evaluator.cpp ${HEADERS} ${PROTOCOL_HEADERS} diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index d3f797966..647ffb5fb 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -49,13 +49,12 @@ #include #include #include - - #include #include #include #include #include +#include #include #include @@ -76,13 +75,10 @@ #include #include #include - -#include +#include #include -#include - #include #include #include diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index 73258a9d5..6760791f6 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -44,8 +44,7 @@ #include #include #include - -#include +#include namespace graphene { namespace chain { diff --git a/libraries/chain/include/graphene/chain/btc-sidechain/son_operations.hpp b/libraries/chain/include/graphene/chain/protocol/son.hpp similarity index 100% rename from libraries/chain/include/graphene/chain/btc-sidechain/son_operations.hpp rename to libraries/chain/include/graphene/chain/protocol/son.hpp diff --git a/libraries/chain/include/graphene/chain/btc-sidechain/son_operations_evaluator.hpp b/libraries/chain/include/graphene/chain/son_evaluator.hpp similarity index 92% rename from libraries/chain/include/graphene/chain/btc-sidechain/son_operations_evaluator.hpp rename to libraries/chain/include/graphene/chain/son_evaluator.hpp index f6a3e63ed..57b879b68 100644 --- a/libraries/chain/include/graphene/chain/btc-sidechain/son_operations_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/son_evaluator.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace graphene { namespace chain { diff --git a/libraries/chain/include/graphene/chain/btc-sidechain/son.hpp b/libraries/chain/include/graphene/chain/son_object.hpp similarity index 100% rename from libraries/chain/include/graphene/chain/btc-sidechain/son.hpp rename to libraries/chain/include/graphene/chain/son_object.hpp diff --git a/libraries/chain/btc-sidechain/son_operations_evaluator.cpp b/libraries/chain/son_evaluator.cpp similarity index 93% rename from libraries/chain/btc-sidechain/son_operations_evaluator.cpp rename to libraries/chain/son_evaluator.cpp index 9ce855b3d..b469a0de5 100644 --- a/libraries/chain/btc-sidechain/son_operations_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -1,7 +1,7 @@ -#include +#include #include -#include +#include namespace graphene { namespace chain { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 88c6e8ea0..fef122b5d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -45,8 +45,4 @@ file(GLOB RANDOM_SOURCES "random/*.cpp") add_executable( random_test ${RANDOM_SOURCES} ${COMMON_SOURCES} ) target_link_libraries( random_test graphene_chain graphene_app graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) -file(GLOB UNIT_TESTS "btc_sidechain_tests/*.cpp") -add_executable( btc_sidechain_test ${UNIT_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( btc_sidechain_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) - add_subdirectory( generate_empty_blocks ) diff --git a/tests/btc_sidechain_tests/main.cpp b/tests/btc_sidechain_tests/main.cpp deleted file mode 100644 index 40b64f9d9..000000000 --- a/tests/btc_sidechain_tests/main.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include -#include - -extern uint32_t GRAPHENE_TESTING_GENESIS_TIMESTAMP; - -boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { - std::srand(time(NULL)); - std::cout << "Random number generator seeded to " << time(NULL) << std::endl; - const char* genesis_timestamp_str = getenv("GRAPHENE_TESTING_GENESIS_TIMESTAMP"); - if( genesis_timestamp_str != nullptr ) - { - GRAPHENE_TESTING_GENESIS_TIMESTAMP = std::stoul( genesis_timestamp_str ); - } - std::cout << "GRAPHENE_TESTING_GENESIS_TIMESTAMP is " << GRAPHENE_TESTING_GENESIS_TIMESTAMP << std::endl; - return nullptr; -} diff --git a/tests/btc_sidechain_tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp similarity index 94% rename from tests/btc_sidechain_tests/son_operations_tests.cpp rename to tests/tests/son_operations_tests.cpp index 08f9ca68a..45ff8a4eb 100644 --- a/tests/btc_sidechain_tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -4,8 +4,8 @@ #include "../common/database_fixture.hpp" -#include -#include +#include +#include using namespace graphene::chain; using namespace graphene::chain::test; From 38ec5537734cb26bf8aeb63863c5bac77e101f97 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 19 Sep 2019 13:22:46 -0300 Subject: [PATCH 03/16] remove member from operation names --- libraries/app/impacted.cpp | 4 ++-- libraries/chain/db_init.cpp | 5 ++--- libraries/chain/db_notify.cpp | 4 ++-- .../graphene/chain/protocol/operations.hpp | 4 ++-- .../include/graphene/chain/protocol/son.hpp | 12 ++++++------ .../include/graphene/chain/son_evaluator.hpp | 16 ++++++++-------- libraries/chain/son_evaluator.cpp | 8 ++++---- tests/tests/son_operations_tests.cpp | 8 ++++---- 8 files changed, 30 insertions(+), 31 deletions(-) diff --git a/libraries/app/impacted.cpp b/libraries/app/impacted.cpp index 1b7797ffd..c67f220f3 100644 --- a/libraries/app/impacted.cpp +++ b/libraries/app/impacted.cpp @@ -282,10 +282,10 @@ struct get_impacted_account_visitor _impacted.insert( op.affiliate ); } void operator()( const affiliate_referral_payout_operation& op ) { } - void operator()( const son_member_create_operation& op ){ + void operator()( const son_create_operation& op ){ _impacted.insert( op.owner_account ); } - void operator()( const son_member_delete_operation& op ){ + void operator()( const son_delete_operation& op ){ _impacted.insert( op.owner_account ); } }; diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 647ffb5fb..4f3059509 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -237,9 +237,8 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); - - register_evaluator(); - register_evaluator(); + register_evaluator(); + register_evaluator(); } void database::initialize_indexes() diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 2f3d89c3a..de4f57b47 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -269,10 +269,10 @@ struct get_impacted_account_visitor _impacted.insert( op.affiliate ); } void operator()( const affiliate_referral_payout_operation& op ) { } - void operator()( const son_member_create_operation& op ) { + void operator()( const son_create_operation& op ) { _impacted.insert( op.owner_account ); } - void operator()( const son_member_delete_operation& op ) { + void operator()( const son_delete_operation& op ) { _impacted.insert( op.owner_account ); } }; diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index 6760791f6..5259c0dac 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -131,8 +131,8 @@ namespace graphene { namespace chain { event_group_delete_operation, affiliate_payout_operation, // VIRTUAL affiliate_referral_payout_operation, // VIRTUAL - son_member_create_operation, - son_member_delete_operation + son_create_operation, + son_delete_operation > operation; /// @} // operations group diff --git a/libraries/chain/include/graphene/chain/protocol/son.hpp b/libraries/chain/include/graphene/chain/protocol/son.hpp index 700dc5fcd..eb3554331 100644 --- a/libraries/chain/include/graphene/chain/protocol/son.hpp +++ b/libraries/chain/include/graphene/chain/protocol/son.hpp @@ -3,7 +3,7 @@ namespace graphene { namespace chain { - struct son_member_create_operation : public base_operation + struct son_create_operation : public base_operation { struct fee_parameters_type { uint64_t fee = 0; }; @@ -15,7 +15,7 @@ namespace graphene { namespace chain { share_type calculate_fee(const fee_parameters_type& k)const { return 0; } }; - struct son_member_delete_operation : public base_operation + struct son_delete_operation : public base_operation { struct fee_parameters_type { uint64_t fee = 0; }; @@ -28,8 +28,8 @@ namespace graphene { namespace chain { } } // namespace graphene::chain -FC_REFLECT( graphene::chain::son_member_create_operation::fee_parameters_type, (fee) ) -FC_REFLECT( graphene::chain::son_member_create_operation, (fee)(owner_account)(url) ) +FC_REFLECT( graphene::chain::son_create_operation::fee_parameters_type, (fee) ) +FC_REFLECT( graphene::chain::son_create_operation, (fee)(owner_account)(url) ) -FC_REFLECT( graphene::chain::son_member_delete_operation::fee_parameters_type, (fee) ) -FC_REFLECT( graphene::chain::son_member_delete_operation, (fee)(owner_account) ) +FC_REFLECT( graphene::chain::son_delete_operation::fee_parameters_type, (fee) ) +FC_REFLECT( graphene::chain::son_delete_operation, (fee)(owner_account) ) diff --git a/libraries/chain/include/graphene/chain/son_evaluator.hpp b/libraries/chain/include/graphene/chain/son_evaluator.hpp index 57b879b68..43cfd0fb3 100644 --- a/libraries/chain/include/graphene/chain/son_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/son_evaluator.hpp @@ -4,22 +4,22 @@ namespace graphene { namespace chain { -class create_son_member_evaluator : public evaluator +class create_son_evaluator : public evaluator { public: - typedef son_member_create_operation operation_type; + typedef son_create_operation operation_type; - void_result do_evaluate(const son_member_create_operation& o); - object_id_type do_apply(const son_member_create_operation& o); + void_result do_evaluate(const son_create_operation& o); + object_id_type do_apply(const son_create_operation& o); }; -class delete_son_member_evaluator : public evaluator +class delete_son_evaluator : public evaluator { public: - typedef son_member_delete_operation operation_type; + typedef son_delete_operation operation_type; - void_result do_evaluate(const son_member_delete_operation& o); - void_result do_apply(const son_member_delete_operation& o); + void_result do_evaluate(const son_delete_operation& o); + void_result do_apply(const son_delete_operation& o); }; } } // namespace graphene::chain diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index b469a0de5..a5551a64e 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -5,13 +5,13 @@ namespace graphene { namespace chain { -void_result create_son_member_evaluator::do_evaluate(const son_member_create_operation& op) +void_result create_son_evaluator::do_evaluate(const son_create_operation& op) { try{ FC_ASSERT(db().get(op.owner_account).is_lifetime_member(), "Only Lifetime members may register a SON."); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } -object_id_type create_son_member_evaluator::do_apply(const son_member_create_operation& op) +object_id_type create_son_evaluator::do_apply(const son_create_operation& op) { try { vote_id_type vote_id; db().modify(db().get_global_properties(), [&vote_id](global_property_object& p) { @@ -26,7 +26,7 @@ object_id_type create_son_member_evaluator::do_apply(const son_member_create_ope return new_son_object.id; } FC_CAPTURE_AND_RETHROW( (op) ) } -void_result delete_son_member_evaluator::do_evaluate(const son_member_delete_operation& op) +void_result delete_son_evaluator::do_evaluate(const son_delete_operation& op) { try { database& d = db(); const auto& idx = d.get_index_type().indices().get(); @@ -34,7 +34,7 @@ void_result delete_son_member_evaluator::do_evaluate(const son_member_delete_ope return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } -void_result delete_son_member_evaluator::do_apply(const son_member_delete_operation& op) +void_result delete_son_evaluator::do_apply(const son_delete_operation& op) { try { const auto& idx = db().get_index_type().indices().get(); db().remove(*idx.find(op.owner_account)); diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 45ff8a4eb..16ff197fb 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -10,7 +10,7 @@ using namespace graphene::chain; using namespace graphene::chain::test; -class test_create_son_member_evaluator: public create_son_member_evaluator { +class test_create_son_member_evaluator: public create_son_evaluator { public: test_create_son_member_evaluator( database& link_db ): ptr_trx_state( new transaction_evaluation_state( &link_db ) ) @@ -20,7 +20,7 @@ class test_create_son_member_evaluator: public create_son_member_evaluator { std::unique_ptr ptr_trx_state; }; -class test_delete_son_member_evaluator: public delete_son_member_evaluator { +class test_delete_son_member_evaluator: public delete_son_evaluator { public: test_delete_son_member_evaluator( database& link_db ): ptr_trx_state( new transaction_evaluation_state( &link_db ) ) @@ -35,7 +35,7 @@ BOOST_FIXTURE_TEST_SUITE( son_operation_tests, database_fixture ) BOOST_AUTO_TEST_CASE( create_son_test ){ std::string test_url = "https://create_son_test"; test_create_son_member_evaluator test_eval( db ); - son_member_create_operation op; + son_create_operation op; op.owner_account = account_id_type(1); op.url = test_url; @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE( delete_son_test ){ INVOKE(create_son_test); test_delete_son_member_evaluator test_eval( db ); - son_member_delete_operation delete_op; + son_delete_operation delete_op; delete_op.owner_account = account_id_type(1); BOOST_CHECK_NO_THROW( test_eval.do_evaluate( delete_op ) ); test_eval.do_apply( delete_op ); From 52e9c2a5a63cfa45088c1fae70b408fcfd43d256 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 19 Sep 2019 13:32:01 -0300 Subject: [PATCH 04/16] remove not needed library --- tests/tests/son_operations_tests.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 16ff197fb..c60055e21 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -1,7 +1,5 @@ #include -#include - #include "../common/database_fixture.hpp" #include From ba77a33711b79b9ae25871b1e232a0417fa27ef7 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Fri, 20 Sep 2019 08:38:22 -0300 Subject: [PATCH 05/16] rename object, add update operation skeleton --- libraries/app/api.cpp | 8 ++++---- libraries/app/database_api.cpp | 6 +++--- libraries/app/impacted.cpp | 3 +++ .../app/include/graphene/app/database_api.hpp | 2 +- libraries/chain/db_notify.cpp | 11 +++++++---- .../graphene/chain/global_property_object.hpp | 2 +- .../graphene/chain/protocol/operations.hpp | 1 + .../include/graphene/chain/protocol/son.hpp | 16 ++++++++++++++++ .../include/graphene/chain/protocol/types.hpp | 10 ++++++---- .../include/graphene/chain/son_evaluator.hpp | 9 +++++++++ .../chain/include/graphene/chain/son_object.hpp | 16 ++++++++-------- libraries/chain/son_evaluator.cpp | 15 ++++++++++++++- libraries/wallet/wallet.cpp | 2 +- programs/js_operation_serializer/main.cpp | 1 + 14 files changed, 75 insertions(+), 27 deletions(-) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 9d3148dbb..21542d9d3 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -432,10 +432,10 @@ namespace graphene { namespace app { } case balance_object_type:{ /** these are free from any accounts */ break; - } case son_member_object_type:{ - const auto& son_object = dynamic_cast(obj); - assert( son_object != nullptr ); - accounts.insert( son_object->son_member_account ); + } case son_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->son_member_account ); break; } case sport_object_type: diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index d6bffe04e..ccf68c53e 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -137,7 +137,7 @@ class database_api_impl : public std::enable_shared_from_this map lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const; // SON members - fc::optional get_son_member_by_account(account_id_type account)const; + fc::optional get_son_member_by_account(account_id_type account)const; // Votes vector lookup_vote_ids( const vector& votes )const; @@ -1586,12 +1586,12 @@ map database_api_impl::lookup_committee_member // // ////////////////////////////////////////////////////////////////////// -fc::optional database_api::get_son_member_by_account(account_id_type account)const +fc::optional database_api::get_son_member_by_account(account_id_type account)const { return my->get_son_member_by_account( account ); } -fc::optional database_api_impl::get_son_member_by_account(account_id_type account) const +fc::optional database_api_impl::get_son_member_by_account(account_id_type account) const { const auto& idx = _db.get_index_type().indices().get(); auto itr = idx.find(account); diff --git a/libraries/app/impacted.cpp b/libraries/app/impacted.cpp index c67f220f3..a202264e1 100644 --- a/libraries/app/impacted.cpp +++ b/libraries/app/impacted.cpp @@ -283,6 +283,9 @@ struct get_impacted_account_visitor } void operator()( const affiliate_referral_payout_operation& op ) { } void operator()( const son_create_operation& op ){ + _impacted.insert( op.owner_account ); + } + void operator()( const son_update_operation& op ){ _impacted.insert( op.owner_account ); } void operator()( const son_delete_operation& op ){ diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index c64302432..7d239b202 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -556,7 +556,7 @@ class database_api * @param account The ID of the account whose son_member should be retrieved * @return The son_member object, or null if the account does not have a son_member */ - fc::optional get_son_member_by_account(account_id_type account)const; + fc::optional get_son_member_by_account(account_id_type account)const; /// WORKERS diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index de4f57b47..3709382ca 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -272,6 +272,9 @@ struct get_impacted_account_visitor void operator()( const son_create_operation& op ) { _impacted.insert( op.owner_account ); } + void operator()( const son_update_operation& op ) { + _impacted.insert( op.owner_account ); + } void operator()( const son_delete_operation& op ) { _impacted.insert( op.owner_account ); } @@ -363,10 +366,10 @@ void get_relevant_accounts( const object* obj, flat_set& accoun } case balance_object_type:{ /** these are free from any accounts */ break; - } case son_member_object_type:{ - const auto& son_object = dynamic_cast(obj); - assert( son_object != nullptr ); - accounts.insert( son_object->son_member_account ); + } case son_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->son_member_account ); break; } } diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index 277f6cf53..771e912c8 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -53,7 +53,7 @@ namespace graphene { namespace chain { flat_set active_witnesses; // updated once per maintenance interval // n.b. witness scheduling is done by witness_schedule object - flat_set active_son_members; // updated once per maintenance interval + flat_set active_son_members; // updated once per maintenance interval }; /** diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index 5259c0dac..cd31a5d2b 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -132,6 +132,7 @@ namespace graphene { namespace chain { affiliate_payout_operation, // VIRTUAL affiliate_referral_payout_operation, // VIRTUAL son_create_operation, + son_update_operation, son_delete_operation > operation; diff --git a/libraries/chain/include/graphene/chain/protocol/son.hpp b/libraries/chain/include/graphene/chain/protocol/son.hpp index eb3554331..5d6bb18b9 100644 --- a/libraries/chain/include/graphene/chain/protocol/son.hpp +++ b/libraries/chain/include/graphene/chain/protocol/son.hpp @@ -15,6 +15,19 @@ namespace graphene { namespace chain { share_type calculate_fee(const fee_parameters_type& k)const { return 0; } }; + struct son_update_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 0; }; + + asset fee; + son_id_type son_id; + account_id_type owner_account; + std::string new_url; + + account_id_type fee_payer()const { return owner_account; } + share_type calculate_fee(const fee_parameters_type& k)const { return 0; } + }; + struct son_delete_operation : public base_operation { struct fee_parameters_type { uint64_t fee = 0; }; @@ -31,5 +44,8 @@ namespace graphene { namespace chain { FC_REFLECT( graphene::chain::son_create_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::son_create_operation, (fee)(owner_account)(url) ) +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) ) + FC_REFLECT( graphene::chain::son_delete_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::son_delete_operation, (fee)(owner_account) ) diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index cdac849ba..326f69c74 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -145,7 +145,7 @@ namespace graphene { namespace chain { betting_market_group_object_type, betting_market_object_type, bet_object_type, - son_member_object_type, + son_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; @@ -203,7 +203,7 @@ namespace graphene { namespace chain { class betting_market_group_object; class betting_market_object; class bet_object; - class son_member_object; + class son_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; @@ -230,7 +230,7 @@ namespace graphene { namespace chain { typedef object_id< protocol_ids, betting_market_group_object_type, betting_market_group_object> betting_market_group_id_type; typedef object_id< protocol_ids, betting_market_object_type, betting_market_object> betting_market_id_type; typedef object_id< protocol_ids, bet_object_type, bet_object> bet_id_type; - typedef object_id< protocol_ids, son_member_object_type, son_member_object> son_member_id_type; + typedef object_id< protocol_ids, son_object_type, son_object> son_id_type; // implementation types class global_property_object; @@ -405,7 +405,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type, (betting_market_group_object_type) (betting_market_object_type) (bet_object_type) - (son_member_object_type) + (son_object_type) (OBJECT_TYPE_COUNT) ) FC_REFLECT_ENUM( graphene::chain::impl_object_type, @@ -473,6 +473,8 @@ FC_REFLECT_TYPENAME( graphene::chain::fba_accumulator_id_type ) FC_REFLECT_TYPENAME( graphene::chain::betting_market_position_id_type ) 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( graphene::chain::void_t, ) diff --git a/libraries/chain/include/graphene/chain/son_evaluator.hpp b/libraries/chain/include/graphene/chain/son_evaluator.hpp index 43cfd0fb3..bb6a1820c 100644 --- a/libraries/chain/include/graphene/chain/son_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/son_evaluator.hpp @@ -13,6 +13,15 @@ class create_son_evaluator : public evaluator object_id_type do_apply(const son_create_operation& o); }; +class update_son_evaluator : public evaluator +{ +public: + typedef son_update_operation operation_type; + + void_result do_evaluate(const son_update_operation& o); + object_id_type do_apply(const son_update_operation& o); +}; + class delete_son_evaluator : public evaluator { public: diff --git a/libraries/chain/include/graphene/chain/son_object.hpp b/libraries/chain/include/graphene/chain/son_object.hpp index 6b6d7bac7..114b27cd2 100644 --- a/libraries/chain/include/graphene/chain/son_object.hpp +++ b/libraries/chain/include/graphene/chain/son_object.hpp @@ -7,15 +7,15 @@ namespace graphene { namespace chain { using namespace graphene::db; /** - * @class son_member_object + * @class son_object * @brief tracks information about a son_member account. * @ingroup object */ - class son_member_object : public abstract_object + class son_object : public abstract_object { public: static const uint8_t space_id = protocol_ids; - static const uint8_t type_id = son_member_object_type; + static const uint8_t type_id = son_object_type; account_id_type son_member_account; vote_id_type vote_id; @@ -26,21 +26,21 @@ namespace graphene { namespace chain { struct by_account; struct by_vote_id; using son_member_multi_index_type = multi_index_container< - son_member_object, + son_object, indexed_by< ordered_unique< tag, member >, ordered_unique< tag, - member + member >, ordered_unique< tag, - member + member > > >; - using son_member_index = generic_index; + using son_member_index = generic_index; } } // graphene::chain -FC_REFLECT_DERIVED( graphene::chain::son_member_object, (graphene::db::object), +FC_REFLECT_DERIVED( graphene::chain::son_object, (graphene::db::object), (son_member_account)(vote_id)(total_votes)(url) ) diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index a5551a64e..b12363d94 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -18,7 +18,7 @@ object_id_type create_son_evaluator::do_apply(const son_create_operation& op) vote_id = get_next_vote_id(p, vote_id_type::son); }); - const auto& new_son_object = db().create( [&]( son_member_object& obj ){ + const auto& new_son_object = db().create( [&]( son_object& obj ){ obj.son_member_account = op.owner_account; obj.vote_id = vote_id; obj.url = op.url; @@ -26,6 +26,19 @@ object_id_type create_son_evaluator::do_apply(const son_create_operation& op) return new_son_object.id; } FC_CAPTURE_AND_RETHROW( (op) ) } +void_result update_son_evaluator::do_evaluate(const son_update_operation& op) +{ try{ + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +object_id_type update_son_evaluator::do_apply(const son_update_operation& op) +{ try { + + + return son_id_type(0); +} FC_CAPTURE_AND_RETHROW( (op) ) } + void_result delete_son_evaluator::do_evaluate(const son_delete_operation& op) { try { database& d = db(); diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 3c0629db4..630add0f4 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2031,7 +2031,7 @@ class wallet_api_impl { try { account_object voting_account_object = get_account(voting_account); account_id_type son_member_owner_account_id = get_account_id(son_member); - fc::optional son_member_obj = _remote_db->get_son_member_by_account(son_member_owner_account_id); + fc::optional son_member_obj = _remote_db->get_son_member_by_account(son_member_owner_account_id); if (!son_member_obj) FC_THROW("Account ${son_member} is not registered as a son_member", ("son_member", son_member)); if (approve) diff --git a/programs/js_operation_serializer/main.cpp b/programs/js_operation_serializer/main.cpp index 8994b36b5..a921c0c30 100644 --- a/programs/js_operation_serializer/main.cpp +++ b/programs/js_operation_serializer/main.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include From 5dcb55c99281a8c5fd94d124a4dee387ade06268 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Sat, 21 Sep 2019 09:23:32 -0300 Subject: [PATCH 06/16] add modify logic, test case, modify delete --- .../include/graphene/chain/protocol/son.hpp | 3 +- libraries/chain/son_evaluator.cpp | 26 ++++++++------ tests/tests/son_operations_tests.cpp | 35 +++++++++++++++++++ 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/libraries/chain/include/graphene/chain/protocol/son.hpp b/libraries/chain/include/graphene/chain/protocol/son.hpp index 5d6bb18b9..7c007a8ed 100644 --- a/libraries/chain/include/graphene/chain/protocol/son.hpp +++ b/libraries/chain/include/graphene/chain/protocol/son.hpp @@ -33,6 +33,7 @@ namespace graphene { namespace chain { struct fee_parameters_type { uint64_t fee = 0; }; asset fee; + son_id_type son_id; account_id_type owner_account; account_id_type fee_payer()const { return owner_account; } @@ -48,4 +49,4 @@ 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) ) FC_REFLECT( graphene::chain::son_delete_operation::fee_parameters_type, (fee) ) -FC_REFLECT( graphene::chain::son_delete_operation, (fee)(owner_account) ) +FC_REFLECT( graphene::chain::son_delete_operation, (fee)(son_id)(owner_account) ) diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index b12363d94..a93cfda0f 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -27,30 +27,36 @@ object_id_type create_son_evaluator::do_apply(const son_create_operation& op) } FC_CAPTURE_AND_RETHROW( (op) ) } void_result update_son_evaluator::do_evaluate(const son_update_operation& op) -{ try{ - +{ try { + const auto& idx = db().get_index_type().indices().get(); + FC_ASSERT( idx.find(op.son_id) != idx.end() ); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } object_id_type update_son_evaluator::do_apply(const son_update_operation& op) { try { - - - return son_id_type(0); + const auto& idx = db().get_index_type().indices().get(); + auto itr = idx.find(op.son_id); + if(itr != idx.end()) + { + db().modify(*itr, [&op](son_object &so) { + so.url = op.new_url; + }); + } + return op.son_id; } FC_CAPTURE_AND_RETHROW( (op) ) } void_result delete_son_evaluator::do_evaluate(const son_delete_operation& op) { try { - database& d = db(); - const auto& idx = d.get_index_type().indices().get(); - FC_ASSERT( idx.find(op.owner_account) != idx.end() ); + const auto& idx = db().get_index_type().indices().get(); + FC_ASSERT( idx.find(op.son_id) != idx.end() ); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } void_result delete_son_evaluator::do_apply(const son_delete_operation& op) { try { - const auto& idx = db().get_index_type().indices().get(); - db().remove(*idx.find(op.owner_account)); + const auto& idx = db().get_index_type().indices().get(); + db().remove(*idx.find(op.son_id)); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index c60055e21..c4c3baf0d 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -18,6 +18,16 @@ class test_create_son_member_evaluator: public create_son_evaluator { std::unique_ptr ptr_trx_state; }; +class test_update_son_member_evaluator: public update_son_evaluator { +public: + test_update_son_member_evaluator( database& link_db ): + ptr_trx_state( new transaction_evaluation_state( &link_db ) ) + { + trx_state = ptr_trx_state.get(); + } + std::unique_ptr ptr_trx_state; +}; + class test_delete_son_member_evaluator: public delete_son_evaluator { public: test_delete_son_member_evaluator( database& link_db ): @@ -49,12 +59,37 @@ BOOST_AUTO_TEST_CASE( create_son_test ){ BOOST_CHECK( id == obj->id ); } +BOOST_AUTO_TEST_CASE( update_son_test ){ + + INVOKE(create_son_test); + + std::string new_url = "https://anewurl.com"; + test_update_son_member_evaluator test_eval( db ); + son_update_operation op; + op.owner_account = account_id_type(1); + op.new_url = new_url; + op.son_id = son_id_type(0); + + BOOST_CHECK_NO_THROW( test_eval.do_evaluate( op ) ); + auto id = test_eval.do_apply( op ); + const auto& idx = db.get_index_type().indices().get(); + + BOOST_REQUIRE( idx.size() == 1 ); + + auto obj = idx.find( op.owner_account ); + BOOST_REQUIRE( obj != idx.end() ); + BOOST_CHECK( obj->url == new_url ); + BOOST_CHECK( id == obj->id ); +} + BOOST_AUTO_TEST_CASE( delete_son_test ){ INVOKE(create_son_test); test_delete_son_member_evaluator test_eval( db ); son_delete_operation delete_op; delete_op.owner_account = account_id_type(1); + delete_op.son_id = son_id_type(0); + BOOST_CHECK_NO_THROW( test_eval.do_evaluate( delete_op ) ); test_eval.do_apply( delete_op ); From 6efbf84339eacad929627c1aa44cd57648cd0e2a Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Sat, 21 Sep 2019 09:56:23 -0300 Subject: [PATCH 07/16] change indentation of the son tests --- tests/tests/son_operations_tests.cpp | 112 +++++++++++++-------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index c4c3baf0d..609fe522d 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -10,91 +10,91 @@ using namespace graphene::chain::test; class test_create_son_member_evaluator: public create_son_evaluator { public: - test_create_son_member_evaluator( database& link_db ): - ptr_trx_state( new transaction_evaluation_state( &link_db ) ) - { - trx_state = ptr_trx_state.get(); - } - std::unique_ptr ptr_trx_state; + test_create_son_member_evaluator( database& link_db ): + ptr_trx_state( new transaction_evaluation_state( &link_db ) ) + { + trx_state = ptr_trx_state.get(); + } + std::unique_ptr ptr_trx_state; }; class test_update_son_member_evaluator: public update_son_evaluator { public: - test_update_son_member_evaluator( database& link_db ): - ptr_trx_state( new transaction_evaluation_state( &link_db ) ) - { - trx_state = ptr_trx_state.get(); - } - std::unique_ptr ptr_trx_state; + test_update_son_member_evaluator( database& link_db ): + ptr_trx_state( new transaction_evaluation_state( &link_db ) ) + { + trx_state = ptr_trx_state.get(); + } + std::unique_ptr ptr_trx_state; }; class test_delete_son_member_evaluator: public delete_son_evaluator { public: - test_delete_son_member_evaluator( database& link_db ): - ptr_trx_state( new transaction_evaluation_state( &link_db ) ) - { - trx_state = ptr_trx_state.get(); - } - std::unique_ptr ptr_trx_state; + test_delete_son_member_evaluator( database& link_db ): + ptr_trx_state( new transaction_evaluation_state( &link_db ) ) + { + trx_state = ptr_trx_state.get(); + } + std::unique_ptr ptr_trx_state; }; BOOST_FIXTURE_TEST_SUITE( son_operation_tests, database_fixture ) -BOOST_AUTO_TEST_CASE( create_son_test ){ - std::string test_url = "https://create_son_test"; - test_create_son_member_evaluator test_eval( db ); - son_create_operation op; - op.owner_account = account_id_type(1); - op.url = test_url; +BOOST_AUTO_TEST_CASE( create_son_test ) { + std::string test_url = "https://create_son_test"; + test_create_son_member_evaluator test_eval( db ); + son_create_operation op; + op.owner_account = account_id_type(1); + op.url = test_url; - BOOST_CHECK_NO_THROW( test_eval.do_evaluate( op ) ); - auto id = test_eval.do_apply( op ); - const auto& idx = db.get_index_type().indices().get(); + BOOST_CHECK_NO_THROW( test_eval.do_evaluate( op ) ); + auto id = test_eval.do_apply( op ); + const auto& idx = db.get_index_type().indices().get(); - BOOST_REQUIRE( idx.size() == 1 ); + BOOST_REQUIRE( idx.size() == 1 ); - auto obj = idx.find( op.owner_account ); - BOOST_REQUIRE( obj != idx.end() ); - BOOST_CHECK( obj->url == test_url ); - BOOST_CHECK( id == obj->id ); + auto obj = idx.find( op.owner_account ); + BOOST_REQUIRE( obj != idx.end() ); + BOOST_CHECK( obj->url == test_url ); + BOOST_CHECK( id == obj->id ); } BOOST_AUTO_TEST_CASE( update_son_test ){ - INVOKE(create_son_test); + INVOKE(create_son_test); - std::string new_url = "https://anewurl.com"; - test_update_son_member_evaluator test_eval( db ); - son_update_operation op; - op.owner_account = account_id_type(1); - op.new_url = new_url; - op.son_id = son_id_type(0); + std::string new_url = "https://anewurl.com"; + test_update_son_member_evaluator test_eval( db ); + son_update_operation op; + op.owner_account = account_id_type(1); + op.new_url = new_url; + op.son_id = son_id_type(0); - BOOST_CHECK_NO_THROW( test_eval.do_evaluate( op ) ); - auto id = test_eval.do_apply( op ); - const auto& idx = db.get_index_type().indices().get(); + BOOST_CHECK_NO_THROW( test_eval.do_evaluate( op ) ); + auto id = test_eval.do_apply( op ); + const auto& idx = db.get_index_type().indices().get(); - BOOST_REQUIRE( idx.size() == 1 ); + BOOST_REQUIRE( idx.size() == 1 ); - auto obj = idx.find( op.owner_account ); - BOOST_REQUIRE( obj != idx.end() ); - BOOST_CHECK( obj->url == new_url ); - BOOST_CHECK( id == obj->id ); + auto obj = idx.find( op.owner_account ); + BOOST_REQUIRE( obj != idx.end() ); + BOOST_CHECK( obj->url == new_url ); + BOOST_CHECK( id == obj->id ); } BOOST_AUTO_TEST_CASE( delete_son_test ){ - INVOKE(create_son_test); - test_delete_son_member_evaluator test_eval( db ); + INVOKE(create_son_test); + test_delete_son_member_evaluator test_eval( db ); - son_delete_operation delete_op; - delete_op.owner_account = account_id_type(1); - delete_op.son_id = son_id_type(0); + son_delete_operation delete_op; + delete_op.owner_account = account_id_type(1); + delete_op.son_id = son_id_type(0); - BOOST_CHECK_NO_THROW( test_eval.do_evaluate( delete_op ) ); - test_eval.do_apply( delete_op ); + BOOST_CHECK_NO_THROW( test_eval.do_evaluate( delete_op ) ); + test_eval.do_apply( delete_op ); - const auto& idx = db.get_index_type().indices().get(); - BOOST_REQUIRE( idx.empty() ); + const auto& idx = db.get_index_type().indices().get(); + BOOST_REQUIRE( idx.empty() ); } BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From 0a5d6945684bbf4b72d381d958ea0f7904563f0b Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Sat, 21 Sep 2019 12:19:57 -0300 Subject: [PATCH 08/16] add hardfork guards --- libraries/chain/proposal_evaluator.cpp | 12 ++++++++++++ libraries/chain/son_evaluator.cpp | 6 +++++- tests/tests/son_operations_tests.cpp | 7 +++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index 8306128dd..58af6888c 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -140,6 +140,18 @@ struct proposal_operation_hardfork_visitor FC_ASSERT( vbco.balance_type == vesting_balance_type::unspecified, "balance_type in vesting create not allowed yet!" ); } + void operator()(const son_create_operation &v) const { + FC_ASSERT( block_time >= HARDFORK_SON_TIME, "son_create_operation not allowed yet!" ); + } + + void operator()(const son_update_operation &v) const { + FC_ASSERT( block_time >= HARDFORK_SON_TIME, "son_update_operation not allowed yet!" ); + } + + void operator()(const son_delete_operation &v) const { + FC_ASSERT( block_time >= HARDFORK_SON_TIME, "son_delete_operation not allowed yet!" ); + } + // loop and self visit in proposals void operator()(const proposal_create_operation &v) const { for (const op_wrapper &op : v.proposed_ops) diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index a93cfda0f..920571ed1 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -2,12 +2,14 @@ #include #include +#include namespace graphene { namespace chain { void_result create_son_evaluator::do_evaluate(const son_create_operation& op) { try{ - FC_ASSERT(db().get(op.owner_account).is_lifetime_member(), "Only Lifetime members may register a SON."); + FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); + FC_ASSERT(db().get(op.owner_account).is_lifetime_member(), "Only Lifetime members may register a SON."); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -28,6 +30,7 @@ object_id_type create_son_evaluator::do_apply(const son_create_operation& op) void_result update_son_evaluator::do_evaluate(const son_update_operation& op) { try { + FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); // can be removed after HF date pass const auto& idx = db().get_index_type().indices().get(); FC_ASSERT( idx.find(op.son_id) != idx.end() ); return void_result(); @@ -48,6 +51,7 @@ object_id_type update_son_evaluator::do_apply(const son_update_operation& op) void_result delete_son_evaluator::do_evaluate(const son_delete_operation& op) { try { + FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON_HARDFORK"); // can be removed after HF date pass const auto& idx = db().get_index_type().indices().get(); FC_ASSERT( idx.find(op.son_id) != idx.end() ); return void_result(); diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 609fe522d..616e9492c 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -41,6 +41,11 @@ class test_delete_son_member_evaluator: public delete_son_evaluator { BOOST_FIXTURE_TEST_SUITE( son_operation_tests, database_fixture ) BOOST_AUTO_TEST_CASE( create_son_test ) { + generate_blocks( HARDFORK_SON_TIME ); + while( db.head_block_time() <= HARDFORK_SON_TIME ) + { + generate_block(); + } std::string test_url = "https://create_son_test"; test_create_son_member_evaluator test_eval( db ); son_create_operation op; @@ -60,9 +65,7 @@ BOOST_AUTO_TEST_CASE( create_son_test ) { } BOOST_AUTO_TEST_CASE( update_son_test ){ - INVOKE(create_son_test); - std::string new_url = "https://anewurl.com"; test_update_son_member_evaluator test_eval( db ); son_update_operation op; From 723c802006429ecf775c9b19f9a5d2e80ecf5216 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Sat, 21 Sep 2019 18:45:40 -0300 Subject: [PATCH 09/16] minor clean --- libraries/chain/db_init.cpp | 1 + libraries/chain/son_evaluator.cpp | 1 - tests/common/genesis_file_util.hpp | 2 +- tests/tests/son_operations_tests.cpp | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 4f3059509..7c949c6fe 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -238,6 +238,7 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); register_evaluator(); } diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index 920571ed1..e11799f8c 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -65,4 +65,3 @@ void_result delete_son_evaluator::do_apply(const son_delete_operation& op) } FC_CAPTURE_AND_RETHROW( (op) ) } } } // namespace graphene::chain - \ No newline at end of file diff --git a/tests/common/genesis_file_util.hpp b/tests/common/genesis_file_util.hpp index be56eaf4a..e058df02c 100644 --- a/tests/common/genesis_file_util.hpp +++ b/tests/common/genesis_file_util.hpp @@ -40,4 +40,4 @@ boost::filesystem::path create_genesis_file(fc::temp_directory& directory) { fc::json::save_to_file(genesis_state, genesis_out); return genesis_path; -} \ No newline at end of file +} diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 616e9492c..90b290994 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -100,4 +100,4 @@ BOOST_AUTO_TEST_CASE( delete_son_test ){ BOOST_REQUIRE( idx.empty() ); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() From 3a4445b20c04ece1c2e41c9cdfd23f9e66fcc65f Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Tue, 24 Sep 2019 17:10:34 -0300 Subject: [PATCH 10/16] add missing SON hardfork file --- libraries/chain/hardfork.d/SON.hf | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 libraries/chain/hardfork.d/SON.hf diff --git a/libraries/chain/hardfork.d/SON.hf b/libraries/chain/hardfork.d/SON.hf new file mode 100644 index 000000000..badde1f45 --- /dev/null +++ b/libraries/chain/hardfork.d/SON.hf @@ -0,0 +1,4 @@ +// SON HARDFORK Monday, September 21, 2020 1:43:11 PM +#ifndef HARDFORK_SON_TIME +#define HARDFORK_SON_TIME (fc::time_point_sec( 1600695791 )) +#endif \ No newline at end of file From 17dfc6af6449b4023e3290fbf2f805bb09e27680 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Wed, 25 Sep 2019 18:17:42 -0300 Subject: [PATCH 11/16] add protection to delete and modify son object only if owner --- libraries/chain/son_evaluator.cpp | 2 + tests/tests/son_operations_tests.cpp | 85 +++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index e11799f8c..2aa2f6e6c 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -31,6 +31,7 @@ object_id_type create_son_evaluator::do_apply(const son_create_operation& op) void_result update_son_evaluator::do_evaluate(const son_update_operation& op) { try { FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); // can be removed after HF date pass + FC_ASSERT(db().get(op.son_id).son_member_account == op.owner_account); const auto& idx = db().get_index_type().indices().get(); FC_ASSERT( idx.find(op.son_id) != idx.end() ); return void_result(); @@ -52,6 +53,7 @@ object_id_type update_son_evaluator::do_apply(const son_update_operation& op) void_result delete_son_evaluator::do_evaluate(const son_delete_operation& op) { try { FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON_HARDFORK"); // can be removed after HF date pass + FC_ASSERT(db().get(op.son_id).son_member_account == op.owner_account); const auto& idx = db().get_index_type().indices().get(); FC_ASSERT( idx.find(op.son_id) != idx.end() ); return void_result(); diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 90b290994..d8a0f61c1 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -85,7 +85,7 @@ BOOST_AUTO_TEST_CASE( update_son_test ){ BOOST_CHECK( id == obj->id ); } -BOOST_AUTO_TEST_CASE( delete_son_test ){ +BOOST_AUTO_TEST_CASE( delete_son_test ) { INVOKE(create_son_test); test_delete_son_member_evaluator test_eval( db ); @@ -100,4 +100,87 @@ BOOST_AUTO_TEST_CASE( delete_son_test ){ BOOST_REQUIRE( idx.empty() ); } +BOOST_AUTO_TEST_CASE( update_delete_not_own ) { // fee payer needs to be the son object owner +try { + generate_blocks(HARDFORK_SON_TIME); + while (db.head_block_time() <= HARDFORK_SON_TIME) { + generate_block(); + } + generate_block(); + set_expiration(db, trx); + + ACTORS((alice)(bob)); + + upgrade_to_lifetime_member(alice); + upgrade_to_lifetime_member(bob); + + set_expiration(db, trx); + std::string test_url = "https://create_son_test"; + + // alice became son + { + son_create_operation op; + op.owner_account = alice_id; + op.url = test_url; + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); + } + generate_block(); + + set_expiration(db, trx); + trx.clear(); + + const auto& idx = db.get_index_type().indices().get(); + BOOST_REQUIRE( idx.size() == 1 ); + auto obj = idx.find( alice_id ); + BOOST_REQUIRE( obj != idx.end() ); + BOOST_CHECK( obj->url == test_url ); + + // bob tries to update a son object he dont own + { + son_update_operation op; + op.owner_account = bob_id; + op.new_url = "whatever"; + op.son_id = son_id_type(0); + + trx.operations.push_back(op); + sign(trx, bob_private_key); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception); + } + generate_block(); + + set_expiration(db, trx); + trx.clear(); + + obj = idx.find( alice_id ); + BOOST_REQUIRE( obj != idx.end() ); + // not changing + BOOST_CHECK( obj->url == "https://create_son_test" ); + + // bob tries to delete a son object he dont own + { + son_delete_operation op; + op.owner_account = bob_id; + op.son_id = son_id_type(0); + + trx.operations.push_back(op); + sign(trx, bob_private_key); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception); + + } + generate_block(); + + obj = idx.find( alice_id ); + // not deleting + BOOST_REQUIRE( obj != idx.end() ); + BOOST_CHECK( obj->son_member_account.instance == alice_id.instance); + +} +catch (fc::exception &e) { + edump((e.to_detail_string())); + throw; +} +} + BOOST_AUTO_TEST_SUITE_END() From 4d0a5b683fef4ba607bab97c189064076829667c Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Fri, 27 Sep 2019 16:03:33 -0300 Subject: [PATCH 12/16] add son vote type to lookup_vote_ids --- libraries/app/database_api.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index ccf68c53e..0711bd049 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -1619,6 +1619,7 @@ vector database_api_impl::lookup_vote_ids( const vector& const auto& committee_idx = _db.get_index_type().indices().get(); const auto& for_worker_idx = _db.get_index_type().indices().get(); const auto& against_worker_idx = _db.get_index_type().indices().get(); + const auto& son_idx = _db.get_index_type().indices().get(); vector result; result.reserve( votes.size() ); @@ -1661,6 +1662,16 @@ vector database_api_impl::lookup_vote_ids( const vector& } break; } + case vote_id_type::son: + { + auto itr = son_idx.find( id ); + if( itr != son_idx.end() ) + result.emplace_back( variant( *itr ) ); + else + result.emplace_back( variant() ); + break; + } + case vote_id_type::VOTE_TYPE_COUNT: break; // supress unused enum value warnings } } From e2c579bb02668125bff13ee8b25c11498b8eb29a Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Sat, 28 Sep 2019 18:35:38 -0300 Subject: [PATCH 13/16] add additional fields to son object and operations --- .../include/graphene/chain/protocol/son.hpp | 24 ++- .../include/graphene/chain/son_object.hpp | 13 +- libraries/chain/son_evaluator.cpp | 12 +- tests/tests/son_operations_tests.cpp | 191 +++++++++--------- 4 files changed, 128 insertions(+), 112 deletions(-) diff --git a/libraries/chain/include/graphene/chain/protocol/son.hpp b/libraries/chain/include/graphene/chain/protocol/son.hpp index 7c007a8ed..efea3ef73 100644 --- a/libraries/chain/include/graphene/chain/protocol/son.hpp +++ b/libraries/chain/include/graphene/chain/protocol/son.hpp @@ -9,7 +9,10 @@ namespace graphene { namespace chain { asset fee; account_id_type owner_account; - std::string url; + std::string url; + vesting_balance_id_type deposit; + public_key_type signing_key; + vesting_balance_id_type pay_vb; account_id_type fee_payer()const { return owner_account; } share_type calculate_fee(const fee_parameters_type& k)const { return 0; } @@ -22,7 +25,10 @@ namespace graphene { namespace chain { asset fee; son_id_type son_id; account_id_type owner_account; - std::string new_url; + optional new_url; + optional new_deposit; + optional new_signing_key; + optional new_pay_vb; account_id_type fee_payer()const { return owner_account; } share_type calculate_fee(const fee_parameters_type& k)const { return 0; } @@ -42,11 +48,13 @@ 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) ) +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) + (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) ) +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) ) -FC_REFLECT( graphene::chain::son_delete_operation::fee_parameters_type, (fee) ) -FC_REFLECT( graphene::chain::son_delete_operation, (fee)(son_id)(owner_account) ) +FC_REFLECT(graphene::chain::son_delete_operation::fee_parameters_type, (fee) ) +FC_REFLECT(graphene::chain::son_delete_operation, (fee)(son_id)(owner_account) ) diff --git a/libraries/chain/include/graphene/chain/son_object.hpp b/libraries/chain/include/graphene/chain/son_object.hpp index 114b27cd2..92d21b317 100644 --- a/libraries/chain/include/graphene/chain/son_object.hpp +++ b/libraries/chain/include/graphene/chain/son_object.hpp @@ -17,10 +17,13 @@ namespace graphene { namespace chain { static const uint8_t space_id = protocol_ids; static const uint8_t type_id = son_object_type; - account_id_type son_member_account; - vote_id_type vote_id; - uint64_t total_votes = 0; - string url; + account_id_type son_member_account; + vote_id_type vote_id; + uint64_t total_votes = 0; + string url; + vesting_balance_id_type deposit; + public_key_type signing_key; + vesting_balance_id_type pay_vb; }; struct by_account; @@ -43,4 +46,4 @@ namespace graphene { namespace chain { } } // graphene::chain FC_REFLECT_DERIVED( graphene::chain::son_object, (graphene::db::object), - (son_member_account)(vote_id)(total_votes)(url) ) + (son_member_account)(vote_id)(total_votes)(url)(deposit)(signing_key)(pay_vb) ) diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index 2aa2f6e6c..8ac0cb24e 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -22,8 +22,11 @@ object_id_type create_son_evaluator::do_apply(const son_create_operation& op) const auto& new_son_object = db().create( [&]( son_object& obj ){ obj.son_member_account = op.owner_account; - obj.vote_id = vote_id; - obj.url = op.url; + obj.vote_id = vote_id; + obj.url = op.url; + obj.deposit = op.deposit; + obj.signing_key = op.signing_key; + obj.pay_vb = op.pay_vb; }); return new_son_object.id; } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -44,7 +47,10 @@ object_id_type update_son_evaluator::do_apply(const son_update_operation& op) if(itr != idx.end()) { db().modify(*itr, [&op](son_object &so) { - so.url = op.new_url; + 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_pay_vb.valid()) so.pay_vb = *op.new_pay_vb; }); } return op.son_id; diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index d8a0f61c1..75986ca77 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -8,134 +8,134 @@ using namespace graphene::chain; using namespace graphene::chain::test; -class test_create_son_member_evaluator: public create_son_evaluator { -public: - test_create_son_member_evaluator( database& link_db ): - ptr_trx_state( new transaction_evaluation_state( &link_db ) ) - { - trx_state = ptr_trx_state.get(); - } - std::unique_ptr ptr_trx_state; -}; +BOOST_FIXTURE_TEST_SUITE( son_operation_tests, database_fixture ) -class test_update_son_member_evaluator: public update_son_evaluator { -public: - test_update_son_member_evaluator( database& link_db ): - ptr_trx_state( new transaction_evaluation_state( &link_db ) ) - { - trx_state = ptr_trx_state.get(); +BOOST_AUTO_TEST_CASE( create_son_test ) { + generate_blocks(HARDFORK_SON_TIME); + while (db.head_block_time() <= HARDFORK_SON_TIME) { + generate_block(); } - std::unique_ptr ptr_trx_state; -}; + generate_block(); + set_expiration(db, trx); + + ACTORS((alice)(bob)); + + upgrade_to_lifetime_member(alice); + upgrade_to_lifetime_member(bob); -class test_delete_son_member_evaluator: public delete_son_evaluator { -public: - test_delete_son_member_evaluator( database& link_db ): - ptr_trx_state( new transaction_evaluation_state( &link_db ) ) + transfer( committee_account, alice_id, asset( 100000 ) ); + transfer( committee_account, bob_id, asset( 100000 ) ); + + set_expiration(db, trx); + std::string test_url = "https://create_son_test"; + + // create deposit vesting + vesting_balance_id_type deposit; { - trx_state = ptr_trx_state.get(); + vesting_balance_create_operation op; + op.creator = alice_id; + op.owner = alice_id; + op.amount = asset(10); + op.balance_type = vesting_balance_type::unspecified; + + trx.operations.push_back(op); + set_expiration(db, trx); + processed_transaction ptx = PUSH_TX(db, trx, ~0); + trx.clear(); + deposit = ptx.operation_results[0].get(); } - std::unique_ptr ptr_trx_state; -}; + // create payment vesting + vesting_balance_id_type payment; + { + vesting_balance_create_operation op; + op.creator = alice_id; + op.owner = alice_id; + op.amount = asset(10); + op.balance_type = vesting_balance_type::unspecified; -BOOST_FIXTURE_TEST_SUITE( son_operation_tests, database_fixture ) + trx.operations.push_back(op); + set_expiration(db, trx); + processed_transaction ptx = PUSH_TX(db, trx, ~0); + trx.clear(); + payment = ptx.operation_results[0].get(); + } -BOOST_AUTO_TEST_CASE( create_son_test ) { - generate_blocks( HARDFORK_SON_TIME ); - while( db.head_block_time() <= HARDFORK_SON_TIME ) + // alice became son { - generate_block(); + 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; + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); } - std::string test_url = "https://create_son_test"; - test_create_son_member_evaluator test_eval( db ); - son_create_operation op; - op.owner_account = account_id_type(1); - op.url = test_url; + generate_block(); - BOOST_CHECK_NO_THROW( test_eval.do_evaluate( op ) ); - auto id = test_eval.do_apply( op ); const auto& idx = db.get_index_type().indices().get(); - BOOST_REQUIRE( idx.size() == 1 ); - - auto obj = idx.find( op.owner_account ); + auto obj = idx.find( alice_id ); BOOST_REQUIRE( obj != idx.end() ); BOOST_CHECK( obj->url == test_url ); - BOOST_CHECK( id == obj->id ); + BOOST_CHECK( obj->signing_key == alice_public_key ); + BOOST_CHECK( obj->deposit.instance == deposit.instance.value ); + BOOST_CHECK( obj->pay_vb.instance == payment.instance.value ); } -BOOST_AUTO_TEST_CASE( update_son_test ){ - INVOKE(create_son_test); - std::string new_url = "https://anewurl.com"; - test_update_son_member_evaluator test_eval( db ); - son_update_operation op; - op.owner_account = account_id_type(1); - op.new_url = new_url; - op.son_id = son_id_type(0); - - BOOST_CHECK_NO_THROW( test_eval.do_evaluate( op ) ); - auto id = test_eval.do_apply( op ); - const auto& idx = db.get_index_type().indices().get(); - - BOOST_REQUIRE( idx.size() == 1 ); +BOOST_AUTO_TEST_CASE( update_son_test ) { - auto obj = idx.find( op.owner_account ); - BOOST_REQUIRE( obj != idx.end() ); - BOOST_CHECK( obj->url == new_url ); - BOOST_CHECK( id == obj->id ); -} - -BOOST_AUTO_TEST_CASE( delete_son_test ) { INVOKE(create_son_test); - test_delete_son_member_evaluator test_eval( db ); - - son_delete_operation delete_op; - delete_op.owner_account = account_id_type(1); - delete_op.son_id = son_id_type(0); + GET_ACTOR(alice); - BOOST_CHECK_NO_THROW( test_eval.do_evaluate( delete_op ) ); - test_eval.do_apply( delete_op ); + std::string new_url = "https://anewurl.com"; - const auto& idx = db.get_index_type().indices().get(); - BOOST_REQUIRE( idx.empty() ); -} + { + son_update_operation op; + op.owner_account = alice_id; + op.new_url = new_url; + op.son_id = son_id_type(0); -BOOST_AUTO_TEST_CASE( update_delete_not_own ) { // fee payer needs to be the son object owner -try { - generate_blocks(HARDFORK_SON_TIME); - while (db.head_block_time() <= HARDFORK_SON_TIME) { - generate_block(); + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); } generate_block(); - set_expiration(db, trx); - ACTORS((alice)(bob)); + const auto& idx = db.get_index_type().indices().get(); + BOOST_REQUIRE( idx.size() == 1 ); + auto obj = idx.find( alice_id ); + BOOST_REQUIRE( obj != idx.end() ); + BOOST_CHECK( obj->url == new_url ); +} - upgrade_to_lifetime_member(alice); - upgrade_to_lifetime_member(bob); +BOOST_AUTO_TEST_CASE( delete_son_test ) { - set_expiration(db, trx); - std::string test_url = "https://create_son_test"; + INVOKE(create_son_test); + GET_ACTOR(alice); - // alice became son { - son_create_operation op; + son_delete_operation op; op.owner_account = alice_id; - op.url = test_url; + op.son_id = son_id_type(0); + trx.operations.push_back(op); sign(trx, alice_private_key); PUSH_TX(db, trx, ~0); } generate_block(); - set_expiration(db, trx); - trx.clear(); - const auto& idx = db.get_index_type().indices().get(); - BOOST_REQUIRE( idx.size() == 1 ); - auto obj = idx.find( alice_id ); - BOOST_REQUIRE( obj != idx.end() ); - BOOST_CHECK( obj->url == test_url ); + BOOST_REQUIRE( idx.empty() ); +} + +BOOST_AUTO_TEST_CASE( update_delete_not_own ) { // fee payer needs to be the son object owner +try { + + INVOKE(create_son_test); + GET_ACTOR(alice); + GET_ACTOR(bob); // bob tries to update a son object he dont own { @@ -153,7 +153,8 @@ try { set_expiration(db, trx); trx.clear(); - obj = idx.find( alice_id ); + const auto& idx = db.get_index_type().indices().get(); + auto obj = idx.find( alice_id ); BOOST_REQUIRE( obj != idx.end() ); // not changing BOOST_CHECK( obj->url == "https://create_son_test" ); @@ -175,12 +176,10 @@ try { // not deleting BOOST_REQUIRE( obj != idx.end() ); BOOST_CHECK( obj->son_member_account.instance == alice_id.instance); - } catch (fc::exception &e) { edump((e.to_detail_string())); throw; } -} -BOOST_AUTO_TEST_SUITE_END() +} BOOST_AUTO_TEST_SUITE_END() From c6ef1870cb23b2641738e4202791610f2cdfcd66 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Wed, 9 Oct 2019 15:54:57 -0300 Subject: [PATCH 14/16] add son vesting config options --- libraries/chain/include/graphene/chain/config.hpp | 3 +++ .../graphene/chain/protocol/chain_parameters.hpp | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 7b3e87439..8ac7045b5 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -228,3 +228,6 @@ #define TOURNAMENT_MAX_START_DELAY (60*60*24*7) // 1 week #define GPOS_PERIOD (60*60*24*30*6) // 6 months #define GPOS_SUBPERIOD (60*60*24*30) // 1 month +#define SON_VESTING_AMOUNT 50 // 50 PPY +#define SON_VESTING_PERIOD (60*60*24*30) // 2 days + diff --git a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp index 87c2e3fef..98026dead 100644 --- a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp +++ b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp @@ -43,6 +43,8 @@ namespace graphene { namespace chain { optional < uint32_t > gpos_period; optional < uint32_t > gpos_subperiod; optional < uint32_t > gpos_period_start; + optional < uint32_t > son_vesting_amount; + optional < uint32_t > son_vesting_period; }; struct chain_parameters @@ -121,6 +123,12 @@ namespace graphene { namespace chain { inline uint32_t gpos_period_start()const { return extensions.value.gpos_period_start.valid() ? *extensions.value.gpos_period_start : HARDFORK_GPOS_TIME.sec_since_epoch(); /// current period start date } + inline uint32_t son_vesting_amount()const { + return extensions.value.son_vesting_amount.valid() ? *extensions.value.son_vesting_amount : SON_VESTING_AMOUNT; /// current period start date + } + inline uint32_t son_vesting_period()const { + return extensions.value.son_vesting_period.valid() ? *extensions.value.son_vesting_period : SON_VESTING_PERIOD; /// current period start date + } }; } } // graphene::chain @@ -134,6 +142,8 @@ FC_REFLECT( graphene::chain::parameter_extension, (gpos_period) (gpos_subperiod) (gpos_period_start) + (son_vesting_amount) + (son_vesting_period) ) FC_REFLECT( graphene::chain::chain_parameters, From fcdbce84eaa3ade3c689de981606e1fc5593fa87 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Wed, 9 Oct 2019 17:55:37 -0300 Subject: [PATCH 15/16] add son vesting balance type --- libraries/chain/include/graphene/chain/protocol/vesting.hpp | 4 ++-- tests/tests/son_operations_tests.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/chain/include/graphene/chain/protocol/vesting.hpp b/libraries/chain/include/graphene/chain/protocol/vesting.hpp index 5a78fd65c..4e7171c9a 100644 --- a/libraries/chain/include/graphene/chain/protocol/vesting.hpp +++ b/libraries/chain/include/graphene/chain/protocol/vesting.hpp @@ -26,7 +26,7 @@ namespace graphene { namespace chain { - enum class vesting_balance_type { unspecified, gpos }; + enum class vesting_balance_type { unspecified, gpos, son }; struct linear_vesting_policy_initializer { @@ -122,4 +122,4 @@ FC_REFLECT(graphene::chain::linear_vesting_policy_initializer, (begin_timestamp) FC_REFLECT(graphene::chain::cdd_vesting_policy_initializer, (start_claim)(vesting_seconds) ) FC_REFLECT_TYPENAME( graphene::chain::vesting_policy_initializer ) -FC_REFLECT_ENUM( graphene::chain::vesting_balance_type, (unspecified)(gpos) ) +FC_REFLECT_ENUM( graphene::chain::vesting_balance_type, (unspecified)(gpos)(son) ) diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 75986ca77..b38b8dc1d 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE( create_son_test ) { op.creator = alice_id; op.owner = alice_id; op.amount = asset(10); - op.balance_type = vesting_balance_type::unspecified; + op.balance_type = vesting_balance_type::son; trx.operations.push_back(op); set_expiration(db, trx); @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE( create_son_test ) { op.creator = alice_id; op.owner = alice_id; op.amount = asset(10); - op.balance_type = vesting_balance_type::unspecified; + op.balance_type = vesting_balance_type::son; trx.operations.push_back(op); set_expiration(db, trx); From 964d7e0dc01e4d0ffc21935c08d39f0d97c5fc1e Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Fri, 11 Oct 2019 19:04:10 -0300 Subject: [PATCH 16/16] add dormant vesting policy for son --- .../graphene/chain/protocol/vesting.hpp | 12 +++- .../graphene/chain/vesting_balance_object.hpp | 46 ++++++++++++++- libraries/chain/son_evaluator.cpp | 16 +++++- libraries/chain/vesting_balance_evaluator.cpp | 23 ++++++++ libraries/chain/vesting_balance_object.cpp | 53 ++++++++++++++++++ tests/tests/son_operations_tests.cpp | 56 +++++++++++++++---- 6 files changed, 191 insertions(+), 15 deletions(-) diff --git a/libraries/chain/include/graphene/chain/protocol/vesting.hpp b/libraries/chain/include/graphene/chain/protocol/vesting.hpp index 4e7171c9a..b6a2b1b60 100644 --- a/libraries/chain/include/graphene/chain/protocol/vesting.hpp +++ b/libraries/chain/include/graphene/chain/protocol/vesting.hpp @@ -44,9 +44,16 @@ namespace graphene { namespace chain { cdd_vesting_policy_initializer( uint32_t vest_sec = 0, fc::time_point_sec sc = fc::time_point_sec() ):start_claim(sc),vesting_seconds(vest_sec){} }; - typedef fc::static_variant vesting_policy_initializer; - + struct dormant_vesting_policy_initializer + { + /** none may be claimed if dormant is true, otherwise this is a linear policy */ + bool dormant = true; + fc::time_point_sec begin_timestamp; + uint32_t vesting_cliff_seconds = 0; + uint32_t vesting_duration_seconds = 0; + }; + typedef fc::static_variant vesting_policy_initializer; /** * @brief Create a vesting balance. @@ -120,6 +127,7 @@ FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation, (fee)(vesting_b FC_REFLECT(graphene::chain::linear_vesting_policy_initializer, (begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds) ) FC_REFLECT(graphene::chain::cdd_vesting_policy_initializer, (start_claim)(vesting_seconds) ) +FC_REFLECT(graphene::chain::dormant_vesting_policy_initializer, (dormant)(begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds) ) FC_REFLECT_TYPENAME( graphene::chain::vesting_policy_initializer ) FC_REFLECT_ENUM( graphene::chain::vesting_balance_type, (unspecified)(gpos)(son) ) diff --git a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp index b2b2e7a29..f13d9533a 100644 --- a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp +++ b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp @@ -123,10 +123,44 @@ namespace graphene { namespace chain { void on_withdraw(const vesting_policy_context& ctx); }; + /** + * @brief Cant withdraw anything while dormant mode is true, linear policy after that changes. + * + * This vesting balance type is needed to register SON users where balance may be claimable only after + * the SON object is deleted(plus a linear policy). + * When deleting a SON member the dormant_mode will change and the linear policy will became active. + * + * @note New funds may not be added to a dormant vesting balance. + */ + struct dormant_vesting_policy + { + /// dormant mode flag indicates if we are in dormant mode or linear policy. + bool dormant_mode = true; + + /// This is the time at which funds begin vesting. + fc::time_point_sec begin_timestamp; + /// No amount may be withdrawn before this many seconds of the vesting period have elapsed. + uint32_t vesting_cliff_seconds = 0; + /// Duration of the vesting period, in seconds. Must be greater than 0 and greater than vesting_cliff_seconds. + uint32_t vesting_duration_seconds = 0; + /// The total amount of asset to vest. + share_type begin_balance; + + asset get_allowed_withdraw(const vesting_policy_context& ctx)const; + bool is_deposit_allowed(const vesting_policy_context& ctx)const; + bool is_deposit_vested_allowed(const vesting_policy_context&)const { return false; } + bool is_withdraw_allowed(const vesting_policy_context& ctx)const; + void on_deposit(const vesting_policy_context& ctx); + void on_deposit_vested(const vesting_policy_context&) + { FC_THROW( "May not deposit vested into a linear vesting balance." ); } + void on_withdraw(const vesting_policy_context& ctx); + }; + typedef fc::static_variant< linear_vesting_policy, - cdd_vesting_policy - > vesting_policy; + cdd_vesting_policy, + dormant_vesting_policy + > vesting_policy; /** * Vesting balance object is a balance that is locked by the blockchain for a period of time. @@ -225,6 +259,14 @@ FC_REFLECT(graphene::chain::cdd_vesting_policy, (coin_seconds_earned_last_update) ) +FC_REFLECT(graphene::chain::dormant_vesting_policy, + (dormant_mode) + (begin_timestamp) + (vesting_cliff_seconds) + (vesting_duration_seconds) + (begin_balance) + ) + FC_REFLECT_TYPENAME( graphene::chain::vesting_policy ) FC_REFLECT_DERIVED(graphene::chain::vesting_balance_object, (graphene::db::object), diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index 8ac0cb24e..5f437caff 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -68,7 +69,20 @@ void_result delete_son_evaluator::do_evaluate(const son_delete_operation& op) void_result delete_son_evaluator::do_apply(const son_delete_operation& op) { try { const auto& idx = db().get_index_type().indices().get(); - db().remove(*idx.find(op.son_id)); + auto son = idx.find(op.son_id); + if(son != idx.end()) { + vesting_balance_object deposit = son->deposit(db()); + dormant_vesting_policy new_vesting_policy; + new_vesting_policy.dormant_mode = false; + new_vesting_policy.begin_timestamp = db().head_block_time(); + new_vesting_policy.vesting_cliff_seconds = db().get_global_properties().parameters.son_vesting_period(); + + db().modify(son->deposit(db()), [&new_vesting_policy](vesting_balance_object &vbo) { + vbo.policy = new_vesting_policy; + }); + + db().remove(*son); + } return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/chain/vesting_balance_evaluator.cpp b/libraries/chain/vesting_balance_evaluator.cpp index 0b6e192e0..fa6fb975e 100644 --- a/libraries/chain/vesting_balance_evaluator.cpp +++ b/libraries/chain/vesting_balance_evaluator.cpp @@ -45,7 +45,11 @@ void_result vesting_balance_create_evaluator::do_evaluate( const vesting_balance if(d.head_block_time() < HARDFORK_GPOS_TIME) // Todo: can be removed after gpos hf time pass FC_ASSERT( op.balance_type == vesting_balance_type::unspecified); + if(d.head_block_time() >= HARDFORK_SON_TIME && op.balance_type == vesting_balance_type::son) // Todo: hf check can be removed after pass + FC_ASSERT( op.amount.amount >= d.get_global_properties().parameters.son_vesting_amount() ); + return void_result(); + } FC_CAPTURE_AND_RETHROW( (op) ) } struct init_policy_visitor @@ -79,6 +83,17 @@ struct init_policy_visitor policy.coin_seconds_earned_last_update = now; p = policy; } + + void operator()( const dormant_vesting_policy_initializer& i )const + { + dormant_vesting_policy policy; + policy.dormant_mode = i.dormant; + policy.begin_timestamp = i.begin_timestamp; + policy.vesting_cliff_seconds = i.vesting_cliff_seconds; + policy.vesting_duration_seconds = i.vesting_duration_seconds; + policy.begin_balance = init_balance; + p = policy; + } }; object_id_type vesting_balance_create_evaluator::do_apply( const vesting_balance_create_operation& op ) @@ -105,6 +120,14 @@ object_id_type vesting_balance_create_evaluator::do_apply( const vesting_balance p.vesting_duration_seconds = gpo.parameters.gpos_subperiod(); obj.policy = p; } + if(op.balance_type == vesting_balance_type::son) + { + const auto &gpo = d.get_global_properties(); + // forcing son dormant policy + dormant_vesting_policy p; + p.dormant_mode = true; + obj.policy = p; + } else { op.policy.visit(init_policy_visitor(obj.policy, op.amount.amount, now)); } diff --git a/libraries/chain/vesting_balance_object.cpp b/libraries/chain/vesting_balance_object.cpp index 73448e04c..2463a78a1 100644 --- a/libraries/chain/vesting_balance_object.cpp +++ b/libraries/chain/vesting_balance_object.cpp @@ -157,6 +157,59 @@ bool cdd_vesting_policy::is_withdraw_allowed(const vesting_policy_context& ctx)c return (ctx.amount <= get_allowed_withdraw(ctx)); } +asset dormant_vesting_policy::get_allowed_withdraw( const vesting_policy_context& ctx )const +{ + share_type allowed_withdraw = 0; + + if( !dormant_mode && ctx.now > begin_timestamp) + { + const auto elapsed_seconds = (ctx.now - begin_timestamp).to_seconds(); + assert( elapsed_seconds > 0 ); + + if( elapsed_seconds >= vesting_cliff_seconds ) + { + share_type total_vested = 0; + if( elapsed_seconds < vesting_duration_seconds ) + { + total_vested = (fc::uint128_t( begin_balance.value ) * elapsed_seconds / vesting_duration_seconds).to_uint64(); + } + else + { + total_vested = begin_balance; + } + assert( total_vested >= 0 ); + + const share_type withdrawn_already = begin_balance - ctx.balance.amount; + assert( withdrawn_already >= 0 ); + + allowed_withdraw = total_vested - withdrawn_already; + assert( allowed_withdraw >= 0 ); + } + } + + return asset( allowed_withdraw, ctx.balance.asset_id ); +} + +void dormant_vesting_policy::on_deposit(const vesting_policy_context& ctx) +{ +} + +bool dormant_vesting_policy::is_deposit_allowed(const vesting_policy_context& ctx)const +{ + return (ctx.amount.asset_id == ctx.balance.asset_id) + && sum_below_max_shares(ctx.amount, ctx.balance); +} + +void dormant_vesting_policy::on_withdraw(const vesting_policy_context& ctx) +{ +} + +bool dormant_vesting_policy::is_withdraw_allowed(const vesting_policy_context& ctx)const +{ + return (ctx.amount.asset_id == ctx.balance.asset_id) + && (ctx.amount <= get_allowed_withdraw(ctx)); +} + #define VESTING_VISITOR(NAME, MAYBE_CONST) \ struct NAME ## _visitor \ { \ diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index b38b8dc1d..3596a146f 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -4,6 +4,7 @@ #include #include +#include using namespace graphene::chain; using namespace graphene::chain::test; @@ -12,9 +13,6 @@ BOOST_FIXTURE_TEST_SUITE( son_operation_tests, database_fixture ) BOOST_AUTO_TEST_CASE( create_son_test ) { generate_blocks(HARDFORK_SON_TIME); - while (db.head_block_time() <= HARDFORK_SON_TIME) { - generate_block(); - } generate_block(); set_expiration(db, trx); @@ -37,29 +35,50 @@ BOOST_AUTO_TEST_CASE( create_son_test ) { op.owner = alice_id; op.amount = asset(10); op.balance_type = vesting_balance_type::son; + trx.operations.push_back(op); + // amount in the son balance need to be at least 50 + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); + + op.amount = asset(50); + trx.clear(); trx.operations.push_back(op); - set_expiration(db, trx); + processed_transaction ptx = PUSH_TX(db, trx, ~0); - trx.clear(); + deposit = ptx.operation_results[0].get(); + + auto deposit_vesting = db.get(ptx.operation_results[0].get()); + + BOOST_CHECK_EQUAL(deposit(db).balance.amount.value, 50); + auto now = db.head_block_time(); + BOOST_CHECK_EQUAL(deposit(db).is_withdraw_allowed(now, asset(50)), false); // cant withdraw } - // create payment vesting - vesting_balance_id_type payment; + + generate_block(); + set_expiration(db, trx); + + // create payment normal vesting + vesting_balance_id_type payment ; { vesting_balance_create_operation op; op.creator = alice_id; op.owner = alice_id; - op.amount = asset(10); - op.balance_type = vesting_balance_type::son; + op.amount = asset(1); + op.balance_type = vesting_balance_type::unspecified; + + op.validate(); trx.operations.push_back(op); - set_expiration(db, trx); + trx.validate(); processed_transaction ptx = PUSH_TX(db, trx, ~0); trx.clear(); payment = ptx.operation_results[0].get(); } + generate_block(); + set_expiration(db, trx); + // alice became son { son_create_operation op; @@ -115,6 +134,9 @@ BOOST_AUTO_TEST_CASE( delete_son_test ) { INVOKE(create_son_test); GET_ACTOR(alice); + auto deposit_vesting = db.get(vesting_balance_id_type(0)); + BOOST_CHECK_EQUAL(deposit_vesting.policy.get().dormant_mode, true); // dormant while active + { son_delete_operation op; op.owner_account = alice_id; @@ -128,6 +150,20 @@ BOOST_AUTO_TEST_CASE( delete_son_test ) { const auto& idx = db.get_index_type().indices().get(); BOOST_REQUIRE( idx.empty() ); + + deposit_vesting = db.get(vesting_balance_id_type(0)); + BOOST_CHECK_EQUAL(deposit_vesting.policy.get().dormant_mode, false); // not sleeping anymore + + auto now = db.head_block_time(); + + BOOST_CHECK_EQUAL(deposit_vesting.is_withdraw_allowed(now, asset(50)), false); // but still cant withdraw + + generate_blocks(now + fc::seconds(db.get_global_properties().parameters.son_vesting_period())); + generate_block(); + + deposit_vesting = db.get(vesting_balance_id_type(0)); + now = db.head_block_time(); + BOOST_CHECK_EQUAL(deposit_vesting.is_withdraw_allowed(now, asset(50)), true); // after 2 days withdraw is allowed } BOOST_AUTO_TEST_CASE( update_delete_not_own ) { // fee payer needs to be the son object owner