From 517afc2d199112f87aa8b9478cf4c90aacda9478 Mon Sep 17 00:00:00 2001 From: satyakoneru Date: Wed, 23 Oct 2019 12:25:53 +0000 Subject: [PATCH] SON126 - Witness proposal tests and related fixes --- libraries/chain/db_getter.cpp | 11 + .../chain/include/graphene/chain/database.hpp | 1 + libraries/chain/son_evaluator.cpp | 7 +- tests/tests/son_operations_tests.cpp | 207 ++++++++++++++++++ 4 files changed, 225 insertions(+), 1 deletion(-) diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index 232a73ff..a23ff6de 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -183,6 +183,7 @@ fc::optional database::create_son_deregister_proposal(const son_id_ty { son_delete_operation son_dereg_op; son_dereg_op.payer = current_witness.witness_account; + son_dereg_op.son_id = son_id; proposal_create_operation proposal_op; proposal_op.fee_paying_account = current_witness.witness_account; @@ -245,4 +246,14 @@ void database::remove_son_proposal( const proposal_object& proposal ) } } FC_CAPTURE_AND_RETHROW( (proposal) ) } +bool database::is_son_dereg_valid( const son_id_type& son_id ) +{ + const auto& son_idx = get_index_type().indices().get< by_id >(); + auto son = son_idx.find( son_id ); + FC_ASSERT( son != son_idx.end() ); + bool ret = ( son->status == son_status::in_maintenance && + (head_block_time() - son->statistics(*this).last_down_timestamp >= fc::hours(SON_DEREGISTER_TIME))); + return ret; +} + } } diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index a368ce7a..1e989a21 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -285,6 +285,7 @@ namespace graphene { namespace chain { signed_transaction create_signed_transaction( const fc::ecc::private_key& signing_private_key, const operation& op ); void process_son_proposals( const witness_object& current_witness, const fc::ecc::private_key& private_key ); void remove_son_proposal( const proposal_object& proposal ); + bool is_son_dereg_valid( const son_id_type& son_id ); time_point_sec head_block_time()const; uint32_t head_block_num()const; diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index 92bc7af6..c54d1391 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -63,7 +64,11 @@ 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_account == op.owner_account); + // Get the current block witness signatory + witness_id_type wit_id = db().get_scheduled_witness(1); + const witness_object& current_witness = wit_id(db()); + // Either owner can remove or witness + FC_ASSERT(db().get(op.son_id).son_account == op.owner_account || (db().is_son_dereg_valid(op.son_id) && op.payer == current_witness.witness_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 3ec78fc3..34bb0b37 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include #include @@ -444,4 +446,209 @@ BOOST_AUTO_TEST_CASE( son_pay_test ) BOOST_CHECK( dpo.witness_budget.value == 0); }FC_LOG_AND_RETHROW() + } + +BOOST_AUTO_TEST_CASE( son_witness_proposal_test ) +{ + try + { + const dynamic_global_property_object& dpo = db.get_dynamic_global_properties(); + generate_blocks(HARDFORK_SON_TIME); + generate_block(); + generate_block(); + set_expiration(db, trx); + + ACTORS((alice)(bob)); + + upgrade_to_lifetime_member(alice); + upgrade_to_lifetime_member(bob); + + transfer( committee_account, alice_id, asset( 1000*GRAPHENE_BLOCKCHAIN_PRECISION ) ); + transfer( committee_account, bob_id, asset( 1000*GRAPHENE_BLOCKCHAIN_PRECISION ) ); + + set_expiration(db, trx); + generate_block(); + // Now create SONs + std::string test_url1 = "https://create_son_test1"; + std::string test_url2 = "https://create_son_test2"; + + // create deposit vesting + vesting_balance_id_type deposit1; + { + vesting_balance_create_operation op; + op.creator = alice_id; + op.owner = alice_id; + op.amount = asset(50*GRAPHENE_BLOCKCHAIN_PRECISION); + op.balance_type = vesting_balance_type::son; + op.policy = dormant_vesting_policy_initializer {}; + + trx.operations.push_back(op); + for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op); + set_expiration(db, trx); + processed_transaction ptx = PUSH_TX(db, trx, ~0); + trx.clear(); + deposit1 = ptx.operation_results[0].get(); + } + + // create payment vesting + vesting_balance_id_type payment1; + { + vesting_balance_create_operation op; + op.creator = alice_id; + op.owner = alice_id; + op.amount = asset(1*GRAPHENE_BLOCKCHAIN_PRECISION); + op.balance_type = vesting_balance_type::normal; + + trx.operations.push_back(op); + for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op); + set_expiration(db, trx); + processed_transaction ptx = PUSH_TX(db, trx, ~0); + trx.clear(); + payment1 = ptx.operation_results[0].get(); + } + + // create deposit vesting + vesting_balance_id_type deposit2; + { + vesting_balance_create_operation op; + op.creator = bob_id; + op.owner = bob_id; + op.amount = asset(50*GRAPHENE_BLOCKCHAIN_PRECISION); + op.balance_type = vesting_balance_type::son; + op.policy = dormant_vesting_policy_initializer {}; + + trx.operations.push_back(op); + for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op); + set_expiration(db, trx); + processed_transaction ptx = PUSH_TX(db, trx, ~0); + trx.clear(); + deposit2 = ptx.operation_results[0].get(); + } + + // create payment vesting + vesting_balance_id_type payment2; + { + vesting_balance_create_operation op; + op.creator = bob_id; + op.owner = bob_id; + op.amount = asset(1*GRAPHENE_BLOCKCHAIN_PRECISION); + op.balance_type = vesting_balance_type::normal; + + trx.operations.push_back(op); + for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op); + set_expiration(db, trx); + processed_transaction ptx = PUSH_TX(db, trx, ~0); + trx.clear(); + payment2 = ptx.operation_results[0].get(); + } + + // alice becomes son + { + son_create_operation op; + op.owner_account = alice_id; + op.url = test_url1; + op.deposit = deposit1; + op.pay_vb = payment1; + op.fee = asset(0); + op.signing_key = alice_public_key; + trx.operations.push_back(op); + for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + // bob becomes son + { + son_create_operation op; + op.owner_account = bob_id; + op.url = test_url2; + op.deposit = deposit2; + op.pay_vb = payment2; + op.fee = asset(0); + op.signing_key = bob_public_key; + trx.operations.push_back(op); + for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op); + sign(trx, bob_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + // Check if SONs are created properly + const auto& idx = db.get_index_type().indices().get(); + BOOST_REQUIRE( idx.size() == 2 ); + // Alice's SON + auto obj1 = idx.find( alice_id ); + BOOST_REQUIRE( obj1 != idx.end() ); + BOOST_CHECK( obj1->url == test_url1 ); + BOOST_CHECK( obj1->signing_key == alice_public_key ); + BOOST_CHECK( obj1->deposit.instance == deposit1.instance.value ); + BOOST_CHECK( obj1->pay_vb.instance == payment1.instance.value ); + // Bob's SON + auto obj2 = idx.find( bob_id ); + BOOST_REQUIRE( obj2 != idx.end() ); + BOOST_CHECK( obj2->url == test_url2 ); + BOOST_CHECK( obj2->signing_key == bob_public_key ); + BOOST_CHECK( obj2->deposit.instance == deposit2.instance.value ); + BOOST_CHECK( obj2->pay_vb.instance == payment2.instance.value ); + // Get the statistics object for the SONs + const auto& sidx = db.get_index_type().indices().get(); + BOOST_REQUIRE( sidx.size() == 2 ); + auto son_stats_obj1 = sidx.find( obj1->statistics ); + auto son_stats_obj2 = sidx.find( obj2->statistics ); + BOOST_REQUIRE( son_stats_obj1 != sidx.end() ); + BOOST_REQUIRE( son_stats_obj2 != sidx.end() ); + + + // Modify SON's status to in_maintenance + db.modify( *obj1, [&]( son_object& _s) + { + _s.status = son_status::in_maintenance; + }); + + // Modify the transaction signed statistics of Alice's SON + db.modify( *son_stats_obj1, [&]( son_statistics_object& _s) + { + _s.last_down_timestamp = fc::time_point_sec(db.head_block_time() - fc::hours(12)); + }); + + // Modify SON's status to in_maintenance + db.modify( *obj2, [&]( son_object& _s) + { + _s.status = son_status::in_maintenance; + }); + + // Modify the transaction signed statistics of Alice's SON + db.modify( *son_stats_obj2, [&]( son_statistics_object& _s) + { + _s.last_down_timestamp = fc::time_point_sec(db.head_block_time() - fc::hours(12)); + }); + + const auto& son_proposal_idx = db.get_index_type().indices().get(); + const auto& proposal_idx = db.get_index_type().indices().get(); + + BOOST_CHECK( son_proposal_idx.size() == 0 && proposal_idx.size() == 0 ); + + generate_block(); + witness_id_type proposal_initiator = dpo.current_witness; + + BOOST_CHECK( son_proposal_idx.size() == 2 && proposal_idx.size() == 2 ); + + for(size_t i = 0 ; i < 3 * db.get_global_properties().active_witnesses.size() ; i++ ) + { + generate_block(); + if( dpo.current_witness != proposal_initiator) + { + BOOST_CHECK( son_proposal_idx.size() == 2 && proposal_idx.size() == 2 ); + } + else + { + break; + } + } + BOOST_CHECK( son_proposal_idx.size() == 0 && proposal_idx.size() == 0 ); + BOOST_REQUIRE( idx.size() == 0 ); + } FC_LOG_AND_RETHROW() + } BOOST_AUTO_TEST_SUITE_END()