From fe08af0f1ef9e786011c467ffb09373d8dbb881a Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Mon, 17 Sep 2018 17:21:05 +0300 Subject: [PATCH 01/33] activenodes feature --- .gitignore | 1 + genesis.json | 11 + libraries/app/database_api.cpp | 28 ++ libraries/app/impacted.cpp | 9 + .../app/include/graphene/app/database_api.hpp | 25 ++ libraries/chain/CMakeLists.txt | 3 + libraries/chain/activenode_evaluator.cpp | 82 +++++ libraries/chain/db_activenode_schedule.cpp | 120 +++++++ libraries/chain/db_balance.cpp | 23 ++ libraries/chain/db_block.cpp | 3 + libraries/chain/db_init.cpp | 10 + libraries/chain/db_maint.cpp | 22 +- libraries/chain/db_notify.cpp | 17 + libraries/chain/db_update.cpp | 75 ++++- .../graphene/chain/activenode_evaluator.hpp | 24 ++ .../graphene/chain/activenode_object.hpp | 66 ++++ .../chain/activenode_schedule_object.hpp | 25 ++ .../chain/include/graphene/chain/config.hpp | 9 +- .../chain/include/graphene/chain/database.hpp | 45 +++ .../graphene/chain/global_property_object.hpp | 2 + .../graphene/chain/protocol/activenode.hpp | 76 +++++ .../graphene/chain/protocol/operations.hpp | 5 +- .../include/graphene/chain/protocol/types.hpp | 10 +- libraries/chain/protocol/activenode.cpp | 37 +++ libraries/plugins/CMakeLists.txt | 1 + libraries/plugins/activenode/CMakeLists.txt | 17 + libraries/plugins/activenode/activenode.cpp | 309 ++++++++++++++++++ .../graphene/activenode/activenode.hpp | 86 +++++ libraries/plugins/witness/witness.cpp | 5 + .../wallet/include/graphene/wallet/wallet.hpp | 11 + libraries/wallet/wallet.cpp | 71 +++- programs/witness_node/CMakeLists.txt | 2 +- programs/witness_node/main.cpp | 3 + tests/CMakeLists.txt | 4 +- 34 files changed, 1226 insertions(+), 11 deletions(-) create mode 100644 libraries/chain/activenode_evaluator.cpp create mode 100644 libraries/chain/db_activenode_schedule.cpp create mode 100644 libraries/chain/include/graphene/chain/activenode_evaluator.hpp create mode 100644 libraries/chain/include/graphene/chain/activenode_object.hpp create mode 100644 libraries/chain/include/graphene/chain/activenode_schedule_object.hpp create mode 100644 libraries/chain/include/graphene/chain/protocol/activenode.hpp create mode 100644 libraries/chain/protocol/activenode.cpp create mode 100644 libraries/plugins/activenode/CMakeLists.txt create mode 100644 libraries/plugins/activenode/activenode.cpp create mode 100644 libraries/plugins/activenode/include/graphene/activenode/activenode.hpp diff --git a/.gitignore b/.gitignore index bbe6965b..2fb89b09 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ CMakeCache.txt CMakeFiles Makefile +CMakeDoxyfile.in compile_commands.json moc_* *.moc diff --git a/genesis.json b/genesis.json index d1bb94d5..ab7014aa 100644 --- a/genesis.json +++ b/genesis.json @@ -245,6 +245,16 @@ ], [ 46, {} + ], + [ + 47, { + "fee": 1000000 + } + ], + [ + 48, { + "fee" : 0 + } ] ], "scale": 10000 @@ -270,6 +280,7 @@ "count_non_member_votes": true, "allow_non_member_whitelists": false, "witness_pay_per_block": 100000, + "activenode_pay_per_block": 110000, "worker_budget_per_day": "50000000000", "max_predicate_opcode": 1, "fee_liquidation_threshold": 10000000, diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 8b979690..3eb2e082 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -122,6 +122,10 @@ class database_api_impl : public std::enable_shared_from_this map lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const; uint64_t get_witness_count()const; + // Activenodes + fc::optional get_activenode_by_account(account_id_type account)const; + + // Committee members vector> get_committee_members(const vector& committee_member_ids)const; fc::optional get_committee_member_by_account(account_id_type account)const; @@ -1558,6 +1562,20 @@ vector> database_api_impl::get_witnesses(const vector database_api::get_activenode_by_account(account_id_type account)const +{ + return my->get_activenode_by_account( account ); +} + +fc::optional database_api_impl::get_activenode_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 {}; +} + fc::optional database_api::get_witness_by_account(account_id_type account)const { return my->get_witness_by_account( account ); @@ -1600,6 +1618,16 @@ map database_api_impl::lookup_witness_accounts(const st return witnesses_by_account_name; } +uint64_t database_api::get_activenode_count()const +{ + return my->get_activenode_count(); +} + +uint64_t database_api_impl::get_activenode_count()const +{ + return _db.get_index_type().indices().size(); +} + uint64_t database_api::get_witness_count()const { return my->get_witness_count(); diff --git a/libraries/app/impacted.cpp b/libraries/app/impacted.cpp index 5f2d4fdb..3e3a97ec 100644 --- a/libraries/app/impacted.cpp +++ b/libraries/app/impacted.cpp @@ -211,6 +211,15 @@ struct get_impacted_account_visitor _impacted.insert( op.account_id ); } + void operator()( const activenode_create_operation& op ) + { + _impacted.insert( op.activenode_account ); + } + + void operator()( const activenode_send_activity_operation& op ) + { + _impacted.insert( op.activenode_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 d7bbb9ee..a34afc2e 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -516,6 +516,27 @@ class database_api */ uint64_t get_witness_count()const; + + ///////////////// + // Activenodes // + ///////////////// + + vector> get_activenodes(const vector& witness_ids)const; + + + map lookup_activenode_accounts(const string& lower_bound_name, uint32_t limit)const; + + + /** + * @brief Get the activenode owned by a given account + * @param account The ID of the account whose activenode should be retrieved + * @return The activenode object, or null if the account does not have a activenode + */ + fc::optional get_activenode_by_account(account_id_type account)const; + + + uint64_t get_activenodes_count()const; + /////////////////////// // Committee members // /////////////////////// @@ -754,6 +775,10 @@ FC_API(graphene::app::database_api, (lookup_witness_accounts) (get_witness_count) + // Activenodes + (get_activenode_by_account) + + // Committee members (get_committee_members) (get_committee_member_by_account) diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 8443841e..992ae7f7 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -20,6 +20,7 @@ if( GRAPHENE_DISABLE_UNITY_BUILD ) db_market.cpp db_update.cpp db_witness_schedule.cpp + db_activenode_schedule.cpp db_notify.cpp ) message( STATUS "Graphene database unity build disabled" ) @@ -45,6 +46,7 @@ add_library( graphene_chain protocol/transfer.cpp protocol/committee_member.cpp protocol/witness.cpp + protocol/activenode.cpp protocol/market.cpp protocol/proposal.cpp protocol/withdraw_permission.cpp @@ -69,6 +71,7 @@ add_library( graphene_chain account_evaluator.cpp assert_evaluator.cpp witness_evaluator.cpp + activenode_evaluator.cpp committee_member_evaluator.cpp asset_evaluator.cpp transfer_evaluator.cpp diff --git a/libraries/chain/activenode_evaluator.cpp b/libraries/chain/activenode_evaluator.cpp new file mode 100644 index 00000000..ba5ce106 --- /dev/null +++ b/libraries/chain/activenode_evaluator.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include + + +namespace graphene { namespace chain { + +void_result activenode_create_evaluator::do_evaluate( const activenode_create_operation& op ) +{ try { + FC_ASSERT(db().get(op.activenode_account).is_lifetime_member()); + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +object_id_type activenode_create_evaluator::do_apply( const activenode_create_operation& op ) +{ try { + const auto& new_activenode_object = db().create( [&]( activenode_object& obj ){ + obj.activenode_account = op.activenode_account; + obj.is_enabled = true; + }); + return new_activenode_object.id; +} FC_CAPTURE_AND_RETHROW( (op) ) } + + +void_result activenode_activity_evaluator::do_evaluate( const activenode_send_activity_operation& op ) +{ try { + FC_ASSERT(db().get(op.activenode_account).is_lifetime_member()); + // here we validate that action is possible + const auto& anode_idx = db().get_index_type().indices().get(); + FC_ASSERT(anode_idx.find(op.activenode_account) != anode_idx.end(), "Account ${acc} is not a registered activenode", ("acc", op.activenode_account)); + FC_ASSERT(db().get(op.activenode).activenode_account == op.activenode_account); + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +object_id_type activenode_activity_evaluator::do_apply( const activenode_send_activity_operation& op ) +{ try { + + // DONT validate balance & remove + + // get timestamp from ... + fc::time_point now = fc::time_point::now(); + + // modify activenode with new data + + database& _db = db(); + _db.modify( + _db.get(op.activenode), + [&]( activenode_object& activenode_object ) + { + activenode_object.last_activity = op.timepoint; + activenode_object.endpoint = op.endpoint; + }); + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } +} } // graphene::chain diff --git a/libraries/chain/db_activenode_schedule.cpp b/libraries/chain/db_activenode_schedule.cpp new file mode 100644 index 00000000..143ebe00 --- /dev/null +++ b/libraries/chain/db_activenode_schedule.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +namespace graphene { namespace chain { + +using boost::container::flat_set; + +activenode_id_type database::get_scheduled_activenode( uint32_t slot_num )const +{ + const dynamic_global_property_object& dpo = get_dynamic_global_properties(); + const activenode_schedule_object& aso = activenode_schedule_id_type()(*this); + uint64_t current_aslot = dpo.current_aslot + slot_num; + return aso.current_shuffled_activenodes[ current_aslot % aso.current_shuffled_activenodes.size() ]; +} + +fc::time_point_sec database::get_activenode_slot_time(uint32_t slot_num)const +{ + if( slot_num == 0 ) + return fc::time_point_sec(); + //TODO: if head_block used - maybe we don't need it + auto interval = block_interval(); + const dynamic_global_property_object& dpo = get_dynamic_global_properties(); + + if( head_block_num() == 0 ) + { + // n.b. first block is at genesis_time plus one block interval + fc::time_point_sec genesis_time = dpo.time; + return genesis_time + slot_num * interval; + } + + int64_t head_block_abs_slot = head_block_time().sec_since_epoch() / interval; + fc::time_point_sec head_slot_time(head_block_abs_slot * interval); +// ilog("!#dbg database::get_activenode_slot_time slot_num=${slot_num} head_block_abs_slot=${head_block_abs_slot} head_slot_time=${head_slot_time}, return_val=${return_val}", ("slot_num", slot_num)("head_block_abs_slot",head_block_abs_slot)("head_slot_time", head_slot_time)("return_val", head_slot_time + (slot_num * interval))); + + const global_property_object& gpo = get_global_properties(); + + if( dpo.dynamic_flags & dynamic_global_property_object::maintenance_flag ) + slot_num += gpo.parameters.maintenance_skip_slots; + + // "slot 0" is head_slot_time + // "slot 1" is head_slot_time, + // plus maint interval if head block is a maint block + // plus block interval if head block is not a maint block + return head_slot_time + (slot_num * interval); +} + +uint32_t database::get_activenode_slot_at_time(fc::time_point_sec when)const +{ + fc::time_point_sec first_slot_time = get_activenode_slot_time( 1 ); +// ilog("!#dbg database::get_slot_at_time when=${when} first_slot_time=${first_slot_time} return_val=${return_val}", ("when", when)("first_slot_time", first_slot_time)("return_val", (when - first_slot_time).to_seconds() / block_interval() + 1)); + + if( when < first_slot_time ) + return 0; + return (when - first_slot_time).to_seconds() / block_interval() + 1; +} + +void database::update_activenode_schedule() +{ + const activenode_schedule_object& wso = activenode_schedule_id_type()(*this); + const global_property_object& gpo = get_global_properties(); + + if( head_block_num() % gpo.active_activenodes.size() == 0 ) + { + modify( wso, [&]( activenode_schedule_object& _wso ) + { + _wso.current_shuffled_activenodes.clear(); + _wso.current_shuffled_activenodes.reserve( gpo.active_activenodes.size() ); + + for( const activenode_id_type& w : gpo.active_activenodes ) + _wso.current_shuffled_activenodes.push_back( w ); + + auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32; + for( uint32_t i = 0; i < _wso.current_shuffled_activenodes.size(); ++i ) + { + /// High performance random generator + /// http://xorshift.di.unimi.it/ + uint64_t k = now_hi + uint64_t(i)*2685821657736338717ULL; + k ^= (k >> 12); + k ^= (k << 25); + k ^= (k >> 27); + k *= 2685821657736338717ULL; + + uint32_t jmax = _wso.current_shuffled_activenodes.size() - i; + uint32_t j = i + k%jmax; + std::swap( _wso.current_shuffled_activenodes[i], + _wso.current_shuffled_activenodes[j] ); + } + }); + } +} + +} } + + diff --git a/libraries/chain/db_balance.cpp b/libraries/chain/db_balance.cpp index a70f077b..09bed76a 100644 --- a/libraries/chain/db_balance.cpp +++ b/libraries/chain/db_balance.cpp @@ -186,4 +186,27 @@ void database::deposit_witness_pay(const witness_object& wit, share_type amount) return; } +void database::deposit_activenode_pay(const activenode_object& ano, share_type amount) +{ + if( amount == 0 ) + return; + + optional< vesting_balance_id_type > new_vbid = deposit_lazy_vesting( + ano.pay_vb, + amount, + get_global_properties().parameters.activenode_pay_vesting_seconds, + ano.activenode_account, + true ); + + if( new_vbid.valid() ) + { + modify( ano, [&]( activenode_object& _ano ) + { + _ano.pay_vb = *new_vbid; + } ); + } + + return; +} + } } diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index b571f887..679278a9 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -514,6 +514,7 @@ void database::_apply_block( const signed_block& next_block ) update_global_dynamic_data(next_block); update_signing_witness(signing_witness, next_block); + reward_activenode(next_block); update_last_irreversible_block(); // Are we at the maintenance interval? @@ -534,6 +535,8 @@ void database::_apply_block( const signed_block& next_block ) // to be called for header validation? update_maintenance_flag( maint_needed ); update_witness_schedule(); + update_activenode_schedule(); + if( !_node_property_object.debug_updates.empty() ) apply_debug_updates(); diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 85203e31..8471b79f 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -63,6 +63,7 @@ #include #include +#include #include #include @@ -218,6 +219,7 @@ void database::initialize_indexes() add_index< primary_index >(); add_index< primary_index< simple_index< fba_accumulator_object > > >(); + add_index< primary_index > >(); } void database::init_genesis(const genesis_state_type& genesis_state) @@ -663,6 +665,14 @@ void database::init_genesis(const genesis_state_type& genesis_state) wso.current_shuffled_witnesses.push_back( wid ); }); + // Create activenode scheduler + create([&]( activenode_schedule_object& aso ) + { + // TODO: should I + // for( const activenode_id_type& aid : get_global_properties().active_nodes ) + // aso.current_shuffled_activenodes.push_back( aid ); + }); + // Create FBA counters create([&]( fba_accumulator_object& acc ) { diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 0c461447..10546de9 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include namespace graphene { namespace chain { @@ -74,9 +75,6 @@ vector> database::sort bool database::witness_can_be_active(const witness_object& witness) const { - const account_balance_index& balance_index = get_index_type(); - auto range = balance_index.indices().get().equal_range(boost::make_tuple(witness.witness_account)); - auto& account = witness.witness_account(*this); const auto& stats = account.statistics(*this); share_type total_balance = stats.total_core_in_orders.value @@ -205,6 +203,23 @@ void database::pay_workers( share_type& budget ) } } +void database::update_current_activenodes() +{ try { + const global_property_object& gpo = get_global_properties(); + + const auto& anodes = get_index_type().indices(); + + modify(gpo, [&]( global_property_object& gp ){ + gp.current_activenodes.clear(); + gp.current_activenodes.reserve(anodes.size()); + std::transform(anodes.begin(), anodes.end(), + std::inserter(gp.current_activenodes, gp.current_activenodes.end()), + [](const activenode_object& anode) { + return anode.id; + }); + }); +} FC_CAPTURE_AND_RETHROW() } + void database::update_active_witnesses() { try { assert( _witness_count_histogram_buffer.size() > 0 ); @@ -918,6 +933,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g update_top_n_authorities(*this); update_active_witnesses(); + update_current_activenodes(); update_active_committee_members(); update_worker_votes(); diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 32f30481..14031a6e 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -199,6 +199,16 @@ struct get_impacted_account_visitor _impacted.insert( op.account_id ); } + void operator()( const activenode_create_operation& op ) + { + _impacted.insert( op.activenode_account ); + } + + void operator()( const activenode_send_activity_operation& op ) + { + _impacted.insert( op.activenode_account ); + } + }; static void operation_get_impacted_accounts( const operation& op, flat_set& result ) @@ -287,6 +297,11 @@ static void get_relevant_accounts( const object* obj, flat_set& } case balance_object_type:{ /** these are free from any accounts */ break; + } case activenode_object_type: { + const auto& aobj = dynamic_cast(obj); + FC_ASSERT( aobj != nullptr ); + accounts.insert( aobj->activenode_account ); + break; } } } @@ -350,6 +365,8 @@ static void get_relevant_accounts( const object* obj, flat_set& accounts.insert( aobj->bidder ); break; } + case impl_activenode_schedule_object_type: + break; } } } // end get_relevant_accounts( const object* obj, flat_set& accounts ) diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 5ffe89c1..494272a9 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -44,7 +44,8 @@ void database::update_global_dynamic_data( const signed_block& b ) { const dynamic_global_property_object& _dgp = dynamic_global_property_id_type(0)(*this); - + + // activenodes missed can be implemented in the same way uint32_t missed_blocks = get_slot_at_time( b.timestamp ); assert( missed_blocks != 0 ); missed_blocks--; @@ -120,6 +121,78 @@ void database::update_signing_witness(const witness_object& signing_witness, con _wit.last_confirmed_block_num = new_block.block_num(); } ); } +const activenode_id_type database::validate_activenode(const signed_block& new_block) { + + // get all activenodes who sent activity this time from the block + // new_block.transactions. operations + //or get all activenodes from db with time >= block_head_time... + fc::time_point_sec prev_block_time; + if (new_block.number == 0){ + return; + // n.b. first block is at genesis_time plus one block interval + // prev_block_time = dpo.time; + // return genesis_time + slot_num * interval; + } + + optional prev_block = fetch_block_by_number(new_block.number - 1); + FC_ASSERT(prev_block); + prev_block_time = prev_block->time; + const auto& idx = get_index_type().indices(); + bool found_activenode = false; + activenode_id_type activenode = GRAPHENE_NULL_ACTIVENODE; + std::vector= LLC_ACTIVENODE_MINIMAL_BALANCE); + if (!enough_balance) { + list_for_removal.push(act_object.id); + continue; + // should deactivate or delete?? + } + uint32_t slot_num = get_activenode_slot_at_time( next_block.timestamp ); + FC_ASSERT( slot_num > 0 ); // why + + //TODO: add processing of activenodes that has sent the activity on the slot without block (if/when witness misses the block) + + activenode_id_type scheduled_activenode = get_scheduled_activenode( slot_num ); + + if (act_object.id == scheduled_activenode) { + found = true; + activenode = scheduled_activenode; + } + + } + //removing activenodes that doesn't have money + for(auto& act_id : list_for_removal) + { + remove(act_id); + } + + if (activenode == GRAPHENE_NULL_ACTIVENODE) { + ilog("sheduled activenode ${node} didn't send activity this time", ("node", scheduled_activenode)); + } + + return activenode; +} + +void database::reward_activenode(const signed_block& new_block) { + const global_property_object& gpo = get_global_properties(); + const dynamic_global_property_object& dpo = get_dynamic_global_properties(); + uint64_t new_block_aslot = dpo.current_aslot + get_slot_at_time( new_block.timestamp ); + + activenode_id_type activenode_id = validate_activenode(new_block); + auto& sheduled_activenode = activenode_id(*this); + + deposit_activenode_pay( sheduled_activenode, gpo.parameters.activenode_pay_per_block ); +} void database::update_last_irreversible_block() { diff --git a/libraries/chain/include/graphene/chain/activenode_evaluator.hpp b/libraries/chain/include/graphene/chain/activenode_evaluator.hpp new file mode 100644 index 00000000..a9b64e44 --- /dev/null +++ b/libraries/chain/include/graphene/chain/activenode_evaluator.hpp @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include +namespace graphene { namespace chain { + + class activenode_create_evaluator : public evaluator + { + public: + typedef activenode_create_operation operation_type; + + void_result do_evaluate( const activenode_create_operation& o ); + object_id_type do_apply( const activenode_create_operation& o ); + }; + + class activenode_activity_evaluator : public evaluator + { + public: + typedef activenode_send_activity_operation operation_type; + + void_result do_evaluate( const activenode_send_activity_operation& o ); + object_id_type do_apply( const activenode_send_activity_operation& o ); + }; +} } // graphene::chain diff --git a/libraries/chain/include/graphene/chain/activenode_object.hpp b/libraries/chain/include/graphene/chain/activenode_object.hpp new file mode 100644 index 00000000..a8fbe803 --- /dev/null +++ b/libraries/chain/include/graphene/chain/activenode_object.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once +#include +#include +#include + +namespace graphene { namespace chain { + using namespace graphene::db; + + class activenode_object; + + class activenode_object : public abstract_object + { + public: + static const uint8_t space_id = protocol_ids; + static const uint8_t type_id = activenode_object_type; + + account_id_type activenode_account; + fc::time_point last_activity; + fc::ip::endpoint endpoint; + optional< vesting_balance_id_type > pay_vb; + bool is_enabled; + activenode_object() {} + }; + + struct by_account; + using activenode_multi_index_type = multi_index_container< + activenode_object, + indexed_by< + ordered_unique< tag, + member + >, + ordered_unique< tag, + member + > + > + >; + using activenode_index = generic_index; +} } // graphene::chain + +FC_REFLECT_DERIVED( graphene::chain::activenode_object, (graphene::db::object), + (activenode_account) + (pay_vb) + ) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/activenode_schedule_object.hpp b/libraries/chain/include/graphene/chain/activenode_schedule_object.hpp new file mode 100644 index 00000000..33e6d7c5 --- /dev/null +++ b/libraries/chain/include/graphene/chain/activenode_schedule_object.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include + +namespace graphene { namespace chain { + +class activenode_schedule_object; + +class activenode_schedule_object : public graphene::db::abstract_object +{ + public: + static const uint8_t space_id = implementation_ids; + static const uint8_t type_id = impl_activenode_schedule_object_type; + + vector< activenode_id_type > current_shuffled_activenodes; +}; + +} } + +FC_REFLECT_DERIVED( + graphene::chain::activenode_schedule_object, + (graphene::db::object), + (current_shuffled_activenodes) +) diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index ea922111..4e266cd9 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -137,6 +137,8 @@ #define GRAPHENE_DEFAULT_WITNESS_PAY_VESTING_SECONDS (60*60*24) #define GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY (GRAPHENE_BLOCKCHAIN_PRECISION * int64_t(500) * 1000 ) +#define GRAPHENE_DEFAULT_ACTIVENODE_PAY_PER_BLOCK int64_t(GRAPHENE_BLOCKCHAIN_PRECISION * double( 1.1) ) + #define GRAPHENE_DEFAULT_MINIMUM_FEEDS 7 #define GRAPHENE_MAX_INTEREST_APR uint16_t( 10000 ) @@ -167,8 +169,13 @@ /// Sentinel value used in the scheduler. #define GRAPHENE_NULL_WITNESS (graphene::chain::witness_id_type(0)) ///@} +/// Sentinel value used in the activenode_scheduler. +#define GRAPHENE_NULL_ACTIVENODE (graphene::chain::activenode_id_type(0)) +///@} #define GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET (asset_id_type(743)) #define GRAPHENE_MAX_NESTED_OBJECTS (200) -#define LLC_WITNESS_MINIMAL_BALANCE (100000 * GRAPHENE_BLOCKCHAIN_PRECISION) \ No newline at end of file +#define LLC_WITNESS_MINIMAL_BALANCE (100000 * GRAPHENE_BLOCKCHAIN_PRECISION) + +#define LLC_ACTIVENODE_MINIMAL_BALANCE (501 * GRAPHENE_BLOCKCHAIN_PRECISION) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 33c27f63..953b9e33 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -248,6 +248,46 @@ namespace graphene { namespace chain { void update_witness_schedule(); + //////////////////// db_activenode_schedule.cpp //////////////////// + + /** + * @brief Get the activenode scheduled for sending activity in a slot. + * + * slot_num always corresponds to a time in the future. + * + * If slot_num == 1, returns the next scheduled activenode. + * If slot_num == 2, returns the next scheduled activenode after + * 1 block gap. + * + * Use the get_slot_time() and get_slot_at_time() functions + * to convert between slot_num and timestamp. + * + * Passing slot_num == 0 returns GRAPHENE_NULL_ACTIVENODE + */ + activenode_id_type get_scheduled_activenode(uint32_t slot_num)const; + + /** + * Get the time at which the given slot occurs. + * + * If slot_num == 0, return time_point_sec(). + * + * If slot_num == N for N > 0, return the Nth next + * block-interval-aligned time greater than head_block_time(). + */ + fc::time_point_sec get_activenode_slot_time(uint32_t slot_num)const; + + /** + * Get the last slot which occurs AT or BEFORE the given time. + * + * The return value is the greatest value N such that + * get_slot_time( N ) <= when. + * + * If no such N exists, return 0. + */ + uint32_t get_activenode_slot_at_time(fc::time_point_sec when)const; + + void update_activenode_schedule(); + //////////////////// db_getter.cpp //////////////////// const chain_id_type& get_chain_id()const; @@ -326,6 +366,9 @@ namespace graphene { namespace chain { void deposit_cashback(const account_object& acct, share_type amount, bool require_vesting = true); // helper to handle witness pay void deposit_witness_pay(const witness_object& wit, share_type amount); + // helper to handle witness pay + void database::deposit_activenode_pay(const activenode_object& ano, share_type amount); + //////////////////// db_debug.cpp //////////////////// @@ -448,6 +491,7 @@ namespace graphene { namespace chain { //////////////////// db_update.cpp //////////////////// void update_global_dynamic_data( const signed_block& b ); void update_signing_witness(const witness_object& signing_witness, const signed_block& new_block); + void reward_activenode(const signed_block& new_block); void update_last_irreversible_block(); void clear_expired_transactions(); void clear_expired_proposals(); @@ -467,6 +511,7 @@ namespace graphene { namespace chain { void pay_workers( share_type& budget ); void perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props); void update_active_witnesses(); + void update_current_activenodes(); void update_active_committee_members(); void update_worker_votes(); void process_bids( const asset_bitasset_data_object& bad ); diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index 2c5a1f12..c9f3332d 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -51,6 +51,8 @@ namespace graphene { namespace chain { uint32_t next_available_vote_id = 0; vector active_committee_members; // updated once per maintenance interval flat_set active_witnesses; // updated once per maintenance interval + flat_set current_activenodes; // updated once per maintenance interval + // n.b. witness scheduling is done by witness_schedule object }; diff --git a/libraries/chain/include/graphene/chain/protocol/activenode.hpp b/libraries/chain/include/graphene/chain/protocol/activenode.hpp new file mode 100644 index 00000000..9b7148bb --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/activenode.hpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once +#include + +namespace graphene { namespace chain { + + /** + * @brief Create an activenode object, as a bid to hold a witness position on the network. + * @ingroup operations + * + * Accounts which wish to become witnesses may use this operation to create a witness object which stakeholders may + * vote on to approve its position as a witness. + */ + struct activenode_create_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 10 * GRAPHENE_BLOCKCHAIN_PRECISION; }; + + asset fee; + /// The account which owns the activenode. This account pays the fee for this operation. + account_id_type activenode_account; + + account_id_type fee_payer()const { return activenode_account; } + void validate()const; + }; + + + /** + * @brief Sending activity operation (I'm active) + * @ingroup operations + * + */ + struct activenode_send_activity_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 10 * GRAPHENE_BLOCKCHAIN_PRECISION; }; + + asset fee; + /// The account which owns the activenode. This account pays the fee for this operation. + account_id_type activenode_account; + activenode_id_type activenode; + fc::time_point timepoint; + fc::ip::endpoint endpoint; + + account_id_type fee_payer()const { return activenode_account; } + void validate()const; + }; + +} } // graphene::chain + +FC_REFLECT( graphene::chain::activenode_create_operation::fee_parameters_type, (fee) ) +FC_REFLECT( graphene::chain::activenode_create_operation, (fee)(activenode_account) ) + + +FC_REFLECT( graphene::chain::activenode_send_activity_operation::fee_parameters_type, (fee) ) +FC_REFLECT( graphene::chain::activenode_send_activity_operation, (fee)(activenode_account) ) diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index 3377a2f9..662bfb91 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -37,6 +37,7 @@ #include #include #include +#include #include namespace graphene { namespace chain { @@ -93,7 +94,9 @@ namespace graphene { namespace chain { asset_claim_fees_operation, fba_distribute_operation, // VIRTUAL bid_collateral_operation, - execute_bid_operation // VIRTUAL + execute_bid_operation, // VIRTUAL + activenode_create_operation, + activenode_send_activity_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 5e0c4a02..372713cc 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -141,6 +141,7 @@ namespace graphene { namespace chain { vesting_balance_object_type, worker_object_type, balance_object_type, + activenode_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; @@ -163,7 +164,8 @@ namespace graphene { namespace chain { impl_special_authority_object_type, impl_buyback_object_type, impl_fba_accumulator_object_type, - impl_collateral_bid_object_type + impl_collateral_bid_object_type, + impl_activenode_schedule_object_type }; //typedef fc::unsigned_int object_id_type; @@ -183,6 +185,7 @@ namespace graphene { namespace chain { class worker_object; class balance_object; class blinded_balance_object; + class activenode_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; @@ -198,6 +201,7 @@ namespace graphene { namespace chain { typedef object_id< protocol_ids, vesting_balance_object_type, vesting_balance_object> vesting_balance_id_type; typedef object_id< protocol_ids, worker_object_type, worker_object> worker_id_type; typedef object_id< protocol_ids, balance_object_type, balance_object> balance_id_type; + typedef object_id< protocol_ids, activenode_object_type, activenode_object> activenode_id_type; // implementation types class global_property_object; @@ -216,6 +220,7 @@ namespace graphene { namespace chain { class buyback_object; class fba_accumulator_object; class collateral_bid_object; + class activenode_schedule_object; typedef object_id< implementation_ids, impl_global_property_object_type, global_property_object> global_property_id_type; typedef object_id< implementation_ids, impl_dynamic_global_property_object_type, dynamic_global_property_object> dynamic_global_property_id_type; @@ -237,6 +242,7 @@ namespace graphene { namespace chain { typedef object_id< implementation_ids, impl_buyback_object_type, buyback_object > buyback_id_type; typedef object_id< implementation_ids, impl_fba_accumulator_object_type, fba_accumulator_object > fba_accumulator_id_type; typedef object_id< implementation_ids, impl_collateral_bid_object_type, collateral_bid_object > collateral_bid_id_type; + typedef object_id< implementation_ids, impl_activenode_schedule_object_type, activenode_schedule_object> activenode_schedule_id_type; typedef fc::array symbol_type; typedef fc::ripemd160 block_id_type; @@ -347,6 +353,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type, (vesting_balance_object_type) (worker_object_type) (balance_object_type) + (activenode_object_type) (OBJECT_TYPE_COUNT) ) FC_REFLECT_ENUM( graphene::chain::impl_object_type, @@ -368,6 +375,7 @@ FC_REFLECT_ENUM( graphene::chain::impl_object_type, (impl_buyback_object_type) (impl_fba_accumulator_object_type) (impl_collateral_bid_object_type) + (impl_activenode_schedule_object_type) ) FC_REFLECT_TYPENAME( graphene::chain::share_type ) diff --git a/libraries/chain/protocol/activenode.cpp b/libraries/chain/protocol/activenode.cpp new file mode 100644 index 00000000..1d93a753 --- /dev/null +++ b/libraries/chain/protocol/activenode.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +namespace graphene { namespace chain { + +void activenode_create_operation::validate() const +{ + FC_ASSERT(fee.amount >= 0); +} +void activenode_send_activity_operation::validate() const +{ + FC_ASSERT(fee.amount >= 0); +} + +} } // graphene::chain diff --git a/libraries/plugins/CMakeLists.txt b/libraries/plugins/CMakeLists.txt index caacb8bd..4d460a20 100644 --- a/libraries/plugins/CMakeLists.txt +++ b/libraries/plugins/CMakeLists.txt @@ -7,3 +7,4 @@ add_subdirectory( delayed_node ) add_subdirectory( debug_witness ) add_subdirectory( snapshot ) add_subdirectory( es_objects ) +add_subdirectory( activenode ) \ No newline at end of file diff --git a/libraries/plugins/activenode/CMakeLists.txt b/libraries/plugins/activenode/CMakeLists.txt new file mode 100644 index 00000000..8e1de7d0 --- /dev/null +++ b/libraries/plugins/activenode/CMakeLists.txt @@ -0,0 +1,17 @@ +file(GLOB HEADERS "include/graphene/activenode/*.hpp") + +add_library( graphene_activenode + activenode.cpp + ) + +target_link_libraries( graphene_activenode graphene_chain graphene_app ) +target_include_directories( graphene_activenode + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) + +install( TARGETS + graphene_activenode + + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) diff --git a/libraries/plugins/activenode/activenode.cpp b/libraries/plugins/activenode/activenode.cpp new file mode 100644 index 00000000..26b41862 --- /dev/null +++ b/libraries/plugins/activenode/activenode.cpp @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include +#include + +#include + +#include +#include + +#include + +using namespace graphene::activenode_plugin; +using std::string; +using std::vector; + +namespace bpo = boost::program_options; + +void activenode_plugin::plugin_set_program_options( + boost::program_options::options_description& command_line_options, + boost::program_options::options_description& config_file_options) +{ + auto default_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("nathan"))); + string activenode_id_example = fc::json::to_string(chain::activenode_id_type(5)); + command_line_options.add_options() + ("activenode-id,w", bpo::value>()->composing()->multitoken(), + ("ID of activenode controlled by this node (e.g. " + activenode_id_example + ", quotes are required").c_str()) + ("activenode-private-key", bpo::value>()->composing()->multitoken()-> + DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))), + "Tuple of [PublicKey, WIF private key] (for account that will get rewards for being an activenode)") + ; + config_file_options.add(command_line_options); +} + +std::string activenode_plugin::plugin_name()const +{ + return "activenode"; +} + +void activenode_plugin::plugin_initialize(const boost::program_options::variables_map& options) +{ try { + ilog("activenode plugin: plugin_initialize() begin"); + _options = &options; + _activenode = GRAPHENE_NULL_ACTIVENODE; + if (options.count("activenode-id")) + { + std::string activenode_id = options["activenode-id"].as(); + + _activenode = graphene::app::dejsonify(activenode_id); + } + + if( options.count("activenode-private-key") ) + { + const std::string key_id_to_wif_pair_string = options["activenode-private-key"].as(); + auto key_id_to_wif_pair = graphene::app::dejsonify >(key_id_to_wif_pair_string, 5); + ilog("Public Key: ${public}", ("public", key_id_to_wif_pair.first)); + fc::optional private_key = graphene::utilities::wif_to_key(key_id_to_wif_pair.second); + if (!private_key) + { + // the key isn't in WIF format; see if they are still passing the old native private key format. This is + // just here to ease the transition, can be removed soon + try + { + private_key = fc::variant(key_id_to_wif_pair.second, 2).as(1); + } + catch (const fc::exception&) + { + FC_THROW("Invalid WIF-format private key ${key_string}", ("key_string", key_id_to_wif_pair.second)); + } + } + _private_key = std::make_pair(key_id_to_wif_pair.first, *private_key); + } + ilog("activenode plugin: plugin_initialize() end"); +} FC_LOG_AND_RETHROW() } + +void activenode_plugin::plugin_startup() +{ try { + ilog("activenode plugin: plugin_startup() begin"); + + if( _activenode != GRAPHENE_NULL_ACTIVENODE) + { + ilog("Launching activity for an activenodes."); + schedule_activity_loop(); + } else + elog("No activenodes configured! Please add activenode IDs and private keys to configuration."); + ilog("activenode plugin: plugin_startup() end"); +} FC_CAPTURE_AND_RETHROW() } + +void activenode_plugin::plugin_shutdown() +{ + // nothing to do +} + +void activenode_plugin::schedule_activity_loop() +{ + //Schedule for the next second's tick regardless of chain state + // If we would wait less than 50ms, wait for the whole second. + fc::time_point now = fc::time_point::now(); + ilog("!activenode_plugin::schedule_activity_loop now=${now}", ("now", now)); + int64_t time_to_next_second = 1000000 - (now.time_since_epoch().count() % 1000000); + if( time_to_next_second < 50000 ) // we must sleep for at least 50ms + time_to_next_second += 1000000; + + fc::time_point next_wakeup( now + fc::microseconds( time_to_next_second ) ); + ilog("!activenode_plugin::schedule_activity_loop next_wakeup=${next_wakeup}", ("next_wakeup", next_wakeup)); + _activity_task = fc::schedule([this]{_activity_loop();}, + next_wakeup, "Node activity transaction"); +} + +activenode_condition::activenode_condition_enum activenode_plugin::activity_loop() +{ + activenode_condition::activenode_condition_enum result; + fc::limited_mutable_variant_object capture( GRAPHENE_MAX_NESTED_OBJECTS ); + try + { + chain::database& db = database(); + if (_activenode(db).is_enabled) + result = maybe_send_activity(capture); + } + catch( const fc::canceled_exception& ) + { + //We're trying to exit. Go ahead and let this one out. + throw; + } + catch( const fc::exception& e ) + { + elog("Got exception while sending activity:\n${e}", ("e", e.to_detail_string())); + result = activenode_condition::exception_perform_activity; + } + + switch( result ) + { + case activenode_condition_enum::performed_activity: + ilog("Sent activity #${n} with timestamp ${t} at time ${c}", (capture)); + break; + case activenode_condition_enum::not_synced: + ilog("Not sending activity because activity is disabled until we receive a recent block (see: --enable-stale-activity)"); + break; + case activenode_condition_enum::not_my_turn: + break; + case activenode_condition_enum::not_time_yet: + break; + case activenode_condition_enum::no_private_key: + ilog("Not sending activity because I don't have the private key for ${scheduled_key}", (capture) ); + break; + case activenode_condition_enum::lag: + elog("Not sending activity because node didn't wake up within 500ms of the slot time."); + break; + case activenode_condition_enum::exception_perform_activity: + elog( "exception sending activity" ); + break; + } + schedule_activity_loop(); + return result; +} + +//todo complete rewrite +activenode_condition::activenode_condition_enum +activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capture ) +{ + chain::database& db = database(); + fc::time_point now_fine = fc::time_point::now(); + fc::time_point_sec now = now_fine + fc::microseconds( 500000 ); + ilog("!activenode_plugin::maybe_send_activity now_fine=${now_fine} now=${now}", ("now_fine", now_fine)("now", now)); + + // If the next send activity opportunity is in the present or future, we're synced. + if( !_activity_enabled ) + { + // TODO: check if it is okay???!?!??! + // need special slots for sending activity + if( db.get_slot_time(1) >= now ) + _activity_enabled = true; + else + return activenode_condition::not_synced; + } + + // is anyone scheduled to produce now or one second in the future? + uint32_t slot = db.get_slot_at_time( now ); + ilog("!activenode_plugin::maybe_send_activitys slot=${slow} db.head_block_time()=${db_head_time}", ("slot", slot)("db_head_time", db.head_block_time())); + + if( slot == 0 ) + { + capture("next_time", db.get_slot_time(1)); + return activenode_condition_enum::not_time_yet; + } + + // + // this assert should not fail, because now <= db.head_block_time() + // should have resulted in slot == 0. + // + // if this assert triggers, there is a serious bug in get_slot_at_time() + // which would result in allowing a later block to have a timestamp + // less than or equal to the previous block + // + assert( now > db.head_block_time() ); + + graphene::chain::activenode_id_type scheduled_activenode = db.get_scheduled_activenode( slot ); + // we must control the witness scheduled to produce the next block. + if( scheduled_activenode == _activenode ) + { + capture("scheduled_activenode", scheduled_activenode); + return activenode_condition::not_my_turn; + } + + fc::time_point_sec scheduled_time = db.get_slot_time( slot ); + graphene::chain::public_key_type scheduled_key = scheduled_activenode( db ).signing_key; + + if( _private_key.first != scheduled_key ) + { + capture("scheduled_key", scheduled_key); + return activenode_condition::no_private_key; + } + + if( llabs((scheduled_time - now).count()) > fc::milliseconds( 500 ).count() ) + { + capture("scheduled_time", scheduled_time)("now", now); + return activenode_condition::lag; + } + + + +// auto block = db.generate_block( +// scheduled_time, +// scheduled_witness, +// private_key_itr->second, +// _activity_skip_flags +// ); +// capture("n", block.block_num())("t", block.timestamp)("c", now); +// fc::async( [this,block](){ p2p_node().broadcast(net::block_message(block)); } ); + + + + //todo here should send transaction, with spcial operation, + // with ip, ssl enabled status, timestamp, should also check if money is enough + + // account_object issuer_account = get_account( issuer ); + // FC_ASSERT(!find_asset(symbol).valid(), "Asset with that symbol already exists!"); + + // if doesn't have 501 LLC should downgrade here? + + + // asset_create_operation create_op; + // create_op.issuer = issuer_account.id; + // create_op.symbol = symbol; + // create_op.precision = precision; + // create_op.common_options = common; + // create_op.bitasset_opts = bitasset_opts; + +// auto& account = _activenode(db).activenode_account; +// const auto& stats = account.statistics(*this); + +// share_type total_activenode_balance = stats.total_core_in_orders.value +// + (account.cashback_vb.valid() ? (*account.cashback_vb)(*this).balance.amount.value: 0) + get_balance(account.get_id(), asset_id_type()).amount.value; + +// bool enough_balance = (total_activenode_balance >= LLC_ACTIVENODE_MINIMAL_BALANCE); +// if (!enough_balance) { + +// } + fc:variant_object network_info = app().p2p_node()->network_get_info(); + //fc::ip::endpoint + //fc::from_variant + //ip::endpoint::from_string + fc::ip::endpoint endpoint = ip::endpoint::from_string(network_info['listening_on'].as_string()); + //firewalled_state - uint8_t - unknown,firewalled, not firewalled + graphene::net::firewalled_state node_firewalled_state; + fc::from_variant(network_info['firewalled'], firewalled, 1); + // network_info['firewalled'] + FC_ASSERT(endpoint.is_public() && node_firewalled_state == graphene::net::firewalled::not_firewalled); + + activenode_send_activity_operation send_activity_operation; + // SHOULD??: send_act_op.timestamp + fc::time_point now = fc::time_point::now(); + send_activity_operation.timepoint = now; + send_activity_operation.endpoint = endpoint; + send_activity_operation.activenode = _activenode; + send_activity_operation.activenode_account = account; + + signed_transaction tx; + tx.operations.push_back( create_op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); + tx.validate(); + + sign_transaction( tx, broadcast ); + + return activenode_condition::performed_activity; +} diff --git a/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp b/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp new file mode 100644 index 00000000..536f91d4 --- /dev/null +++ b/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once + +#include +#include + +#include + +namespace graphene { namespace activenode_plugin { + +namespace activenode_condition +{ + enum activenode_condition_enum + { + performed_activity = 0, + not_synced = 1, + not_my_turn = 2, + not_time_yet = 3, + no_private_key = 4, + lag = 5, + exception_perform_activity = 6 + }; +} + +class activenode_plugin : public graphene::app::plugin { +public: + ~activenode_plugin() { + try { + if( _activity_task.valid() ) + _activity_task.cancel_and_wait(__FUNCTION__); + } catch(fc::canceled_exception&) { + //Expected exception. Move along. + } catch(fc::exception& e) { + edump((e.to_detail_string())); + } + } + + std::string plugin_name()const override; + + virtual void plugin_set_program_options( + boost::program_options::options_description &command_line_options, + boost::program_options::options_description &config_file_options + ) override; + + void set_activenode_plugin_enabled(bool allow) { _activenode_plugin_enabled = allow; } + + virtual void plugin_initialize( const boost::program_options::variables_map& options ) override; + virtual void plugin_startup() override; + virtual void plugin_shutdown() override; + +private: + void schedule_activity_loop(); + activenode_condition::activenode_condition_enum activity_loop(); + activenode_condition::activenode_condition_enum maybe_send_activity( fc::limited_mutable_variant_object& capture ); + + boost::program_options::variables_map _options; + bool _activenode_plugin_enabled = false; + + std::pair _private_key; + chain::activenode_id_type _activenode; + fc::future _activity_task; +}; + +} } //graphene::activenode_plugin diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index 29c6191b..8322b734 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -146,11 +146,13 @@ void witness_plugin::schedule_production_loop() //Schedule for the next second's tick regardless of chain state // If we would wait less than 50ms, wait for the whole second. fc::time_point now = fc::time_point::now(); +// ilog("!witness_plugin::schedule_production_loop now=${now}", ("now", now)); int64_t time_to_next_second = 1000000 - (now.time_since_epoch().count() % 1000000); if( time_to_next_second < 50000 ) // we must sleep for at least 50ms time_to_next_second += 1000000; fc::time_point next_wakeup( now + fc::microseconds( time_to_next_second ) ); +// ilog("!witness_plugin::schedule_production_loop next_wakeup=${next_wakeup}", ("next_wakeup", next_wakeup)); _block_production_task = fc::schedule([this]{block_production_loop();}, next_wakeup, "Witness Block Production"); @@ -213,6 +215,7 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb chain::database& db = database(); fc::time_point now_fine = fc::time_point::now(); fc::time_point_sec now = now_fine + fc::microseconds( 500000 ); +// ilog("!witness_plugin::maybe_produce_block now_fine=${now_fine} now=${now}", ("now_fine", now_fine)("now", now)); // If the next block production opportunity is in the present or future, we're synced. if( !_production_enabled ) @@ -225,6 +228,8 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb // is anyone scheduled to produce now or one second in the future? uint32_t slot = db.get_slot_at_time( now ); +// ilog("!witness_plugin::maybe_produce_block slot=${slow} db.head_block_time()=${db_head_time}", ("slot", slot)("db_head_time", db.head_block_time())); + if( slot == 0 ) { capture("next_time", db.get_slot_time(1)); diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 8ffb499d..0c4bceb8 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1259,6 +1259,8 @@ class wallet_api */ map list_witnesses(const string& lowerbound, uint32_t limit); + map list_activenodes(const string& lowerbound, uint32_t limit); + /** Lists all committee_members registered in the blockchain. * This returns a list of all account names that own committee_members, and the associated committee_member id, * sorted by name. This lists committee_members whether they are currently voted in or not. @@ -1280,6 +1282,9 @@ class wallet_api */ witness_object get_witness(string owner_account); + activenode_object get_activenodes(string owner_account); + + /** Returns information about the given committee_member. * @param owner_account the name or id of the committee_member account owner, or the id of the committee_member * @returns the information about the committee_member stored in the block chain @@ -1300,6 +1305,9 @@ class wallet_api string url, bool broadcast = false); + signed_transaction create_activenode(string owner_account, + bool broadcast /* = false */) + /** * Update a witness object owned by the given account. * @@ -1690,10 +1698,13 @@ FC_API( graphene::wallet::wallet_api, (whitelist_account) (create_committee_member) (get_witness) + (get_activenodes) (get_committee_member) (list_witnesses) + (list_activenodes) (list_committee_members) (create_witness) + (create_activenode) (update_witness) (create_worker) (update_worker_votes) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index b53f9741..50672750 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1123,7 +1123,6 @@ class wallet_api_impl return create_account_with_private_key(owner_privkey, account_name, registrar_account, referrer_account, broadcast, save_wallet); } FC_CAPTURE_AND_RETHROW( (account_name)(registrar_account)(referrer_account) ) } - signed_transaction create_asset(string issuer, string symbol, uint8_t precision, @@ -1427,6 +1426,41 @@ class wallet_api_impl FC_CAPTURE_AND_RETHROW( (owner_account) ) } + activenode_object get_activenode(string owner_account) + { + try + { + fc::optional activenode_id = maybe_id(owner_account); + if (activenode_id) + { + std::vector ids_to_get; + ids_to_get.push_back(*activenode_id); + std::vector> activenode_objects = _remote_db->get_activenodees(ids_to_get); + if (activenode_objects.front()) + return *activenode_objects.front(); + FC_THROW("No activenode is registered for id ${id}", ("id", owner_account)); + } + else + { + // then maybe it's the owner account + try + { + account_id_type owner_account_id = get_account_id(owner_account); + fc::optional activenode = _remote_db->get_activenode_by_account(owner_account_id); + if (activenode) + return *activenode; + else + FC_THROW("No activenode is registered for account ${account}", ("account", owner_account)); + } + catch (const fc::exception&) + { + FC_THROW("No account or activenode named ${account}", ("account", owner_account)); + } + } + } + FC_CAPTURE_AND_RETHROW( (owner_account) ) + } + committee_member_object get_committee_member(string owner_account) { try @@ -1490,6 +1524,25 @@ class wallet_api_impl return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (owner_account)(broadcast) ) } + signed_transaction create_activenode(string owner_account, + bool broadcast /* = false */) + { try { + account_object activenode_account = get_account(owner_account); + + activenode_create_operation activenode_create_op; + activenode_create_op.activenode_account = activenode_account.id; + + if (_remote_db->get_activenode_by_account(activenode_create_op.activenode_account)) + FC_THROW("Account ${owner_account} is already an activenode", ("owner_account", owner_account)); + + signed_transaction tx; + tx.operations.push_back( activenode_create_op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); + tx.validate(); + + return sign_transaction( tx, broadcast ); + } FC_CAPTURE_AND_RETHROW( (owner_account)(broadcast) ) } + signed_transaction update_witness(string witness_name, string url, string block_signing_key, @@ -3386,6 +3439,22 @@ map wallet_api::list_witnesses(const string& lowerbound, return my->_remote_db->lookup_witness_accounts(lowerbound, limit); } +map wallet_api::list_activenodes(const string& lowerbound, uint32_t limit) +{ + return my->_remote_db->lookup_activenode_accounts(lowerbound, limit); +} + +signed_transaction wallet_api::create_activenode(string owner_account, + bool broadcast /* = false */) +{ + return my->create_activenode(owner_account, broadcast); +} + +activenode_object wallet_api::get_activenodes(string owner_account) +{ + return my->get_activenodes(owner_account); +} + map wallet_api::list_committee_members(const string& lowerbound, uint32_t limit) { return my->_remote_db->lookup_committee_member_accounts(lowerbound, limit); diff --git a/programs/witness_node/CMakeLists.txt b/programs/witness_node/CMakeLists.txt index 4815879a..b1864be2 100644 --- a/programs/witness_node/CMakeLists.txt +++ b/programs/witness_node/CMakeLists.txt @@ -12,7 +12,7 @@ endif() # We have to link against graphene_debug_witness because deficiency in our API infrastructure doesn't allow plugins to be fully abstracted #246 target_link_libraries( witness_node -PRIVATE graphene_app graphene_delayed_node graphene_account_history graphene_elasticsearch graphene_market_history graphene_grouped_orders graphene_witness graphene_chain graphene_debug_witness graphene_egenesis_full graphene_snapshot graphene_es_objects fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) +PRIVATE graphene_app graphene_delayed_node graphene_account_history graphene_elasticsearch graphene_market_history graphene_grouped_orders graphene_witness graphene_activenode graphene_chain graphene_debug_witness graphene_egenesis_full graphene_snapshot graphene_es_objects fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS witness_node diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index 873c2bad..f5c01531 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -192,6 +193,8 @@ int main(int argc, char** argv) { bpo::variables_map options; auto witness_plug = node->register_plugin(); + auto activenode_plug = node->register_plugin(); + auto debug_witness_plug = node->register_plugin(); auto history_plug = node->register_plugin(); auto elasticsearch_plug = node->register_plugin(); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5b19d9d8..81aee8b7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,10 +23,10 @@ target_link_libraries( chain_bench graphene_chain graphene_app graphene_account_ file(GLOB APP_SOURCES "app/*.cpp") add_executable( app_test ${APP_SOURCES} ) -target_link_libraries( app_test graphene_app graphene_account_history graphene_net graphene_witness graphene_chain graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( app_test graphene_app graphene_account_history graphene_net graphene_witness graphene_activenode graphene_chain graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB CLI_SOURCES "cli/*.cpp") add_executable( cli_test ${CLI_SOURCES} ) -target_link_libraries( cli_test graphene_app graphene_wallet graphene_witness graphene_account_history graphene_net graphene_chain graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( cli_test graphene_app graphene_wallet graphene_witness graphene_activenode graphene_account_history graphene_net graphene_chain graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) add_subdirectory( generate_empty_blocks ) From 57906637db131fc224bbde2ea108f3ad031af6d7 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Tue, 16 Oct 2018 16:18:56 +0300 Subject: [PATCH 02/33] activenodes fixes --- libraries/app/database_api.cpp | 92 +++++++++++++++---- .../app/include/graphene/app/database_api.hpp | 8 +- libraries/chain/account_evaluator.cpp | 2 + libraries/chain/activenode_evaluator.cpp | 2 +- libraries/chain/database.cpp | 1 + libraries/chain/db_activenode_schedule.cpp | 6 +- libraries/chain/db_balance.cpp | 2 + libraries/chain/db_block.cpp | 1 + libraries/chain/db_debug.cpp | 1 + libraries/chain/db_init.cpp | 2 + libraries/chain/db_notify.cpp | 1 + libraries/chain/db_update.cpp | 28 +++--- .../graphene/chain/activenode_evaluator.hpp | 2 +- .../graphene/chain/activenode_object.hpp | 1 + .../chain/include/graphene/chain/config.hpp | 2 + .../chain/include/graphene/chain/database.hpp | 3 +- .../graphene/chain/protocol/activenode.hpp | 1 + .../chain/protocol/chain_parameters.hpp | 6 ++ libraries/plugins/activenode/activenode.cpp | 67 ++++++++------ .../graphene/activenode/activenode.hpp | 2 +- libraries/plugins/debug_witness/debug_api.cpp | 1 + .../wallet/include/graphene/wallet/wallet.hpp | 6 +- libraries/wallet/wallet.cpp | 12 +-- programs/build_helpers/member_enumerator.cpp | 1 + programs/js_operation_serializer/main.cpp | 1 + tests/common/database_fixture.cpp | 1 + 26 files changed, 171 insertions(+), 81 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 3eb2e082..f129cf8a 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -124,7 +124,9 @@ class database_api_impl : public std::enable_shared_from_this // Activenodes fc::optional get_activenode_by_account(account_id_type account)const; - + vector> get_activenodes(const vector& activenode_ids)const; + map lookup_activenode_accounts(const string& lower_bound_name, uint32_t limit)const; + uint64_t get_activenode_count()const; // Committee members vector> get_committee_members(const vector& committee_member_ids)const; @@ -1562,20 +1564,6 @@ vector> database_api_impl::get_witnesses(const vector database_api::get_activenode_by_account(account_id_type account)const -{ - return my->get_activenode_by_account( account ); -} - -fc::optional database_api_impl::get_activenode_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 {}; -} - fc::optional database_api::get_witness_by_account(account_id_type account)const { return my->get_witness_by_account( account ); @@ -1618,6 +1606,67 @@ map database_api_impl::lookup_witness_accounts(const st return witnesses_by_account_name; } +uint64_t database_api::get_witness_count()const +{ + return my->get_witness_count(); +} + +uint64_t database_api_impl::get_witness_count()const +{ + return _db.get_index_type().indices().size(); +} + +////////////////////////////////////////////////////////////////////// +// // +// Activenodes // +// // +////////////////////////////////////////////////////////////////////// + +vector> database_api::get_activenodes(const vector& activenode_ids)const +{ + return my->get_activenodes( activenode_ids ); +} + +vector> database_api_impl::get_activenodes(const vector& activenode_ids)const +{ + vector> result; result.reserve(activenode_ids.size()); + std::transform(activenode_ids.begin(), activenode_ids.end(), std::back_inserter(result), + [this](activenode_id_type id) -> optional { + if(auto o = _db.find(id)) + return *o; + return {}; + }); + return result; +} + +map database_api::lookup_activenode_accounts(const string& lower_bound_name, uint32_t limit)const +{ + return my->lookup_activenode_accounts( lower_bound_name, limit ); +} + +map database_api_impl::lookup_activenode_accounts(const string& lower_bound_name, uint32_t limit)const +{ + FC_ASSERT( limit <= 1000 ); + const auto& activenodes_by_id = _db.get_index_type().indices().get(); + + // we want to order activenodes by account name, but that name is in the account object + // so the activenode_index doesn't have a quick way to access it. + // get all the names and look them all up, sort them, then figure out what + // records to return. This could be optimized, but we expect the + // number of activenodes to be few and the frequency of calls to be rare + std::map activenodes_by_account_name; + for (const activenode_object& activenode : activenodes_by_id) + if (auto account_iter = _db.find(activenode.activenode_account)) + if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name + activenodes_by_account_name.insert(std::make_pair(account_iter->name, activenode.id)); + + auto end_iter = activenodes_by_account_name.begin(); + while (end_iter != activenodes_by_account_name.end() && limit--) + ++end_iter; + activenodes_by_account_name.erase(end_iter, activenodes_by_account_name.end()); + return activenodes_by_account_name; +} + uint64_t database_api::get_activenode_count()const { return my->get_activenode_count(); @@ -1628,16 +1677,19 @@ uint64_t database_api_impl::get_activenode_count()const return _db.get_index_type().indices().size(); } -uint64_t database_api::get_witness_count()const +fc::optional database_api::get_activenode_by_account(account_id_type account)const { - return my->get_witness_count(); + return my->get_activenode_by_account( account ); } -uint64_t database_api_impl::get_witness_count()const +fc::optional database_api_impl::get_activenode_by_account(account_id_type account) const { - return _db.get_index_type().indices().size(); + const auto& idx = _db.get_index_type().indices().get(); + auto itr = idx.find(account); + if( itr != idx.end() ) + return *itr; + return {}; } - ////////////////////////////////////////////////////////////////////// // // // Committee members // diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index a34afc2e..b92847a9 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -40,6 +40,7 @@ #include #include #include +#include #include @@ -521,7 +522,7 @@ class database_api // Activenodes // ///////////////// - vector> get_activenodes(const vector& witness_ids)const; + vector> get_activenodes(const vector& witness_ids)const; map lookup_activenode_accounts(const string& lower_bound_name, uint32_t limit)const; @@ -535,7 +536,7 @@ class database_api fc::optional get_activenode_by_account(account_id_type account)const; - uint64_t get_activenodes_count()const; + uint64_t get_activenode_count()const; /////////////////////// // Committee members // @@ -776,7 +777,10 @@ FC_API(graphene::app::database_api, (get_witness_count) // Activenodes + (get_activenodes) (get_activenode_by_account) + (lookup_activenode_accounts) + (get_activenode_count) // Committee members diff --git a/libraries/chain/account_evaluator.cpp b/libraries/chain/account_evaluator.cpp index 84334339..2bab2ef1 100644 --- a/libraries/chain/account_evaluator.cpp +++ b/libraries/chain/account_evaluator.cpp @@ -35,6 +35,8 @@ #include #include #include +#include + #include #include diff --git a/libraries/chain/activenode_evaluator.cpp b/libraries/chain/activenode_evaluator.cpp index ba5ce106..6edc9050 100644 --- a/libraries/chain/activenode_evaluator.cpp +++ b/libraries/chain/activenode_evaluator.cpp @@ -59,7 +59,7 @@ void_result activenode_activity_evaluator::do_evaluate( const activenode_send_ac return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } -object_id_type activenode_activity_evaluator::do_apply( const activenode_send_activity_operation& op ) +void_result activenode_activity_evaluator::do_apply( const activenode_send_activity_operation& op ) { try { // DONT validate balance & remove diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 2d02b184..e163515c 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -32,4 +32,5 @@ #include "db_market.cpp" #include "db_update.cpp" #include "db_witness_schedule.cpp" +#include "db_activenode_schedule.cpp" #include "db_notify.cpp" \ No newline at end of file diff --git a/libraries/chain/db_activenode_schedule.cpp b/libraries/chain/db_activenode_schedule.cpp index 143ebe00..0dc818d2 100644 --- a/libraries/chain/db_activenode_schedule.cpp +++ b/libraries/chain/db_activenode_schedule.cpp @@ -85,14 +85,14 @@ void database::update_activenode_schedule() const activenode_schedule_object& wso = activenode_schedule_id_type()(*this); const global_property_object& gpo = get_global_properties(); - if( head_block_num() % gpo.active_activenodes.size() == 0 ) + if( head_block_num() % gpo.current_activenodes.size() == 0 ) { modify( wso, [&]( activenode_schedule_object& _wso ) { _wso.current_shuffled_activenodes.clear(); - _wso.current_shuffled_activenodes.reserve( gpo.active_activenodes.size() ); + _wso.current_shuffled_activenodes.reserve( gpo.current_activenodes.size() ); - for( const activenode_id_type& w : gpo.active_activenodes ) + for( const activenode_id_type& w : gpo.current_activenodes ) _wso.current_shuffled_activenodes.push_back( w ); auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32; diff --git a/libraries/chain/db_balance.cpp b/libraries/chain/db_balance.cpp index 09bed76a..34493cd6 100644 --- a/libraries/chain/db_balance.cpp +++ b/libraries/chain/db_balance.cpp @@ -28,6 +28,8 @@ #include #include #include +#include + namespace graphene { namespace chain { diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 679278a9..e328cd6b 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/chain/db_debug.cpp b/libraries/chain/db_debug.cpp index 61376c22..29cd4523 100644 --- a/libraries/chain/db_debug.cpp +++ b/libraries/chain/db_debug.cpp @@ -29,6 +29,7 @@ #include #include #include +#include namespace graphene { namespace chain { diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 8471b79f..7dee566f 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -44,6 +44,8 @@ #include #include #include +#include + #include #include diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 14031a6e..090883e6 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 494272a9..381cd2b6 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -127,20 +128,21 @@ const activenode_id_type database::validate_activenode(const signed_block& new_b // new_block.transactions. operations //or get all activenodes from db with time >= block_head_time... fc::time_point_sec prev_block_time; - if (new_block.number == 0){ - return; + activenode_id_type activenode = GRAPHENE_NULL_ACTIVENODE; + + if (new_block.block_num() == 0){ + return activenode; // n.b. first block is at genesis_time plus one block interval // prev_block_time = dpo.time; // return genesis_time + slot_num * interval; } - optional prev_block = fetch_block_by_number(new_block.number - 1); + optional prev_block = fetch_block_by_number(new_block.block_num() - 1); FC_ASSERT(prev_block); - prev_block_time = prev_block->time; + prev_block_time = prev_block->timestamp; const auto& idx = get_index_type().indices(); bool found_activenode = false; - activenode_id_type activenode = GRAPHENE_NULL_ACTIVENODE; - std::vector list_for_removal; for( const activenode_object& act_object : idx ) { // if a.last_activity @@ -153,11 +155,11 @@ const activenode_id_type database::validate_activenode(const signed_block& new_b bool enough_balance = (total_balance >= LLC_ACTIVENODE_MINIMAL_BALANCE); if (!enough_balance) { - list_for_removal.push(act_object.id); + list_for_removal.push_back(act_object); continue; // should deactivate or delete?? } - uint32_t slot_num = get_activenode_slot_at_time( next_block.timestamp ); + uint32_t slot_num = get_activenode_slot_at_time( new_block.timestamp ); FC_ASSERT( slot_num > 0 ); // why //TODO: add processing of activenodes that has sent the activity on the slot without block (if/when witness misses the block) @@ -165,19 +167,19 @@ const activenode_id_type database::validate_activenode(const signed_block& new_b activenode_id_type scheduled_activenode = get_scheduled_activenode( slot_num ); if (act_object.id == scheduled_activenode) { - found = true; + found_activenode = true; activenode = scheduled_activenode; } - } + //removing activenodes that doesn't have money - for(auto& act_id : list_for_removal) + for(auto& account : list_for_removal) { - remove(act_id); + remove(account); } if (activenode == GRAPHENE_NULL_ACTIVENODE) { - ilog("sheduled activenode ${node} didn't send activity this time", ("node", scheduled_activenode)); + ilog("sheduled activenode ${node} didn't send activity this time", ("node", activenode)); } return activenode; diff --git a/libraries/chain/include/graphene/chain/activenode_evaluator.hpp b/libraries/chain/include/graphene/chain/activenode_evaluator.hpp index a9b64e44..4ee2c3f8 100644 --- a/libraries/chain/include/graphene/chain/activenode_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/activenode_evaluator.hpp @@ -19,6 +19,6 @@ namespace graphene { namespace chain { typedef activenode_send_activity_operation operation_type; void_result do_evaluate( const activenode_send_activity_operation& o ); - object_id_type do_apply( const activenode_send_activity_operation& o ); + void_result do_apply( const activenode_send_activity_operation& o ); }; } } // graphene::chain diff --git a/libraries/chain/include/graphene/chain/activenode_object.hpp b/libraries/chain/include/graphene/chain/activenode_object.hpp index a8fbe803..4ba8634d 100644 --- a/libraries/chain/include/graphene/chain/activenode_object.hpp +++ b/libraries/chain/include/graphene/chain/activenode_object.hpp @@ -39,6 +39,7 @@ namespace graphene { namespace chain { account_id_type activenode_account; fc::time_point last_activity; + fc::ip::endpoint endpoint; optional< vesting_balance_id_type > pay_vb; bool is_enabled; diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 4e266cd9..ac4a0c2f 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -135,6 +135,8 @@ #define GRAPHENE_DEFAULT_WITNESS_PAY_PER_BLOCK (GRAPHENE_BLOCKCHAIN_PRECISION * int64_t( 10) ) #define GRAPHENE_DEFAULT_WITNESS_PAY_VESTING_SECONDS (60*60*24) +#define GRAPHENE_DEFAULT_ACTIVENODE_PAY_VESTING_SECONDS (60*60*24) + #define GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY (GRAPHENE_BLOCKCHAIN_PRECISION * int64_t(500) * 1000 ) #define GRAPHENE_DEFAULT_ACTIVENODE_PAY_PER_BLOCK int64_t(GRAPHENE_BLOCKCHAIN_PRECISION * double( 1.1) ) diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 953b9e33..f526a1c9 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -367,7 +367,7 @@ namespace graphene { namespace chain { // helper to handle witness pay void deposit_witness_pay(const witness_object& wit, share_type amount); // helper to handle witness pay - void database::deposit_activenode_pay(const activenode_object& ano, share_type amount); + void deposit_activenode_pay(const activenode_object& ano, share_type amount); //////////////////// db_debug.cpp //////////////////// @@ -491,6 +491,7 @@ namespace graphene { namespace chain { //////////////////// db_update.cpp //////////////////// void update_global_dynamic_data( const signed_block& b ); void update_signing_witness(const witness_object& signing_witness, const signed_block& new_block); + const activenode_id_type validate_activenode(const signed_block& new_block); void reward_activenode(const signed_block& new_block); void update_last_irreversible_block(); void clear_expired_transactions(); diff --git a/libraries/chain/include/graphene/chain/protocol/activenode.hpp b/libraries/chain/include/graphene/chain/protocol/activenode.hpp index 9b7148bb..9b716637 100644 --- a/libraries/chain/include/graphene/chain/protocol/activenode.hpp +++ b/libraries/chain/include/graphene/chain/protocol/activenode.hpp @@ -23,6 +23,7 @@ */ #pragma once #include +#include namespace graphene { namespace chain { diff --git a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp index 695d9541..87bda97a 100644 --- a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp +++ b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp @@ -56,7 +56,12 @@ namespace graphene { namespace chain { bool count_non_member_votes = true; ///< set to false to restrict voting privlegages to member accounts bool allow_non_member_whitelists = false; ///< true if non-member accounts may set whitelists and blacklists; false otherwise share_type witness_pay_per_block = GRAPHENE_DEFAULT_WITNESS_PAY_PER_BLOCK; ///< CORE to be allocated to witnesses (per block) + + share_type activenode_pay_per_block = GRAPHENE_DEFAULT_ACTIVENODE_PAY_PER_BLOCK; ///< CORE to be allocated to witnesses (per block) + uint32_t witness_pay_vesting_seconds = GRAPHENE_DEFAULT_WITNESS_PAY_VESTING_SECONDS; ///< vesting_seconds parameter for witness VBO's + uint32_t activenode_pay_vesting_seconds = GRAPHENE_DEFAULT_ACTIVENODE_PAY_VESTING_SECONDS; ///< vesting_seconds parameter for witness VBO's + share_type worker_budget_per_day = GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY; ///< CORE to be allocated to workers (per day) uint16_t max_predicate_opcode = GRAPHENE_DEFAULT_MAX_ASSERT_OPCODE; ///< predicate_opcode must be less than this number share_type fee_liquidation_threshold = GRAPHENE_DEFAULT_FEE_LIQUIDATION_THRESHOLD; ///< value in CORE at which accumulated fees in blockchain-issued market assets should be liquidated @@ -94,6 +99,7 @@ FC_REFLECT( graphene::chain::chain_parameters, (count_non_member_votes) (allow_non_member_whitelists) (witness_pay_per_block) + (activenode_pay_per_block) (worker_budget_per_day) (max_predicate_opcode) (fee_liquidation_threshold) diff --git a/libraries/plugins/activenode/activenode.cpp b/libraries/plugins/activenode/activenode.cpp index 26b41862..6fbde082 100644 --- a/libraries/plugins/activenode/activenode.cpp +++ b/libraries/plugins/activenode/activenode.cpp @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include +#include #include #include @@ -69,7 +70,7 @@ void activenode_plugin::plugin_initialize(const boost::program_options::variable { std::string activenode_id = options["activenode-id"].as(); - _activenode = graphene::app::dejsonify(activenode_id); + _activenode = graphene::app::dejsonify(activenode_id, 5); } if( options.count("activenode-private-key") ) @@ -126,7 +127,7 @@ void activenode_plugin::schedule_activity_loop() fc::time_point next_wakeup( now + fc::microseconds( time_to_next_second ) ); ilog("!activenode_plugin::schedule_activity_loop next_wakeup=${next_wakeup}", ("next_wakeup", next_wakeup)); - _activity_task = fc::schedule([this]{_activity_loop();}, + _activity_task = fc::schedule([this]{activity_loop();}, next_wakeup, "Node activity transaction"); } @@ -153,23 +154,23 @@ activenode_condition::activenode_condition_enum activenode_plugin::activity_loop switch( result ) { - case activenode_condition_enum::performed_activity: + case activenode_condition::performed_activity: ilog("Sent activity #${n} with timestamp ${t} at time ${c}", (capture)); break; - case activenode_condition_enum::not_synced: + case activenode_condition::not_synced: ilog("Not sending activity because activity is disabled until we receive a recent block (see: --enable-stale-activity)"); break; - case activenode_condition_enum::not_my_turn: + case activenode_condition::not_my_turn: break; - case activenode_condition_enum::not_time_yet: + case activenode_condition::not_time_yet: break; - case activenode_condition_enum::no_private_key: + case activenode_condition::no_private_key: ilog("Not sending activity because I don't have the private key for ${scheduled_key}", (capture) ); break; - case activenode_condition_enum::lag: + case activenode_condition::lag: elog("Not sending activity because node didn't wake up within 500ms of the slot time."); break; - case activenode_condition_enum::exception_perform_activity: + case activenode_condition::exception_perform_activity: elog( "exception sending activity" ); break; } @@ -187,12 +188,12 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt ilog("!activenode_plugin::maybe_send_activity now_fine=${now_fine} now=${now}", ("now_fine", now_fine)("now", now)); // If the next send activity opportunity is in the present or future, we're synced. - if( !_activity_enabled ) + if( !_activenode_plugin_enabled ) { // TODO: check if it is okay???!?!??! // need special slots for sending activity - if( db.get_slot_time(1) >= now ) - _activity_enabled = true; + if( db.get_activenode_slot_time(1) >= now ) + _activenode_plugin_enabled = true; else return activenode_condition::not_synced; } @@ -204,7 +205,7 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt if( slot == 0 ) { capture("next_time", db.get_slot_time(1)); - return activenode_condition_enum::not_time_yet; + return activenode_condition::not_time_yet; } // @@ -226,13 +227,13 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt } fc::time_point_sec scheduled_time = db.get_slot_time( slot ); - graphene::chain::public_key_type scheduled_key = scheduled_activenode( db ).signing_key; +// graphene::chain::public_key_type scheduled_key = scheduled_activenode( db ).signing_key; - if( _private_key.first != scheduled_key ) - { - capture("scheduled_key", scheduled_key); - return activenode_condition::no_private_key; - } +// if( _private_key.first != scheduled_key ) +// { +// capture("scheduled_key", scheduled_key); +// return activenode_condition::no_private_key; +// } if( llabs((scheduled_time - now).count()) > fc::milliseconds( 500 ).count() ) { @@ -279,31 +280,37 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt // if (!enough_balance) { // } - fc:variant_object network_info = app().p2p_node()->network_get_info(); + fc::variant_object network_info = app().p2p_node()->network_get_info(); //fc::ip::endpoint //fc::from_variant //ip::endpoint::from_string - fc::ip::endpoint endpoint = ip::endpoint::from_string(network_info['listening_on'].as_string()); + fc::ip::endpoint endpoint = fc::ip::endpoint::from_string(network_info["listening_on"].as_string()); //firewalled_state - uint8_t - unknown,firewalled, not firewalled graphene::net::firewalled_state node_firewalled_state; - fc::from_variant(network_info['firewalled'], firewalled, 1); + fc::from_variant(network_info["firewalled"], node_firewalled_state, 1); // network_info['firewalled'] - FC_ASSERT(endpoint.is_public() && node_firewalled_state == graphene::net::firewalled::not_firewalled); + FC_ASSERT(endpoint.get_address().is_public_address() && node_firewalled_state == graphene::net::firewalled_state::not_firewalled); - activenode_send_activity_operation send_activity_operation; + chain::activenode_send_activity_operation send_activity_operation; // SHOULD??: send_act_op.timestamp - fc::time_point now = fc::time_point::now(); + now = fc::time_point::now(); send_activity_operation.timepoint = now; send_activity_operation.endpoint = endpoint; send_activity_operation.activenode = _activenode; - send_activity_operation.activenode_account = account; + send_activity_operation.activenode_account = _activenode(db).activenode_account; + + graphene::chain::signed_transaction tx; + tx.operations.push_back( send_activity_operation ); + + const graphene::chain::fee_schedule& fee_shed = db.current_fee_schedule(); + for( auto& op : tx.operations ) + fee_shed.set_fee(op); - signed_transaction tx; - tx.operations.push_back( create_op ); - set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); tx.validate(); - sign_transaction( tx, broadcast ); + tx.sign( _private_key.second, db.get_chain_id() ); + + fc::async( [this, tx](){ p2p_node().broadcast_transaction(tx); } ); return activenode_condition::performed_activity; } diff --git a/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp b/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp index 536f91d4..2f5b24bd 100644 --- a/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp +++ b/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp @@ -76,7 +76,7 @@ class activenode_plugin : public graphene::app::plugin { activenode_condition::activenode_condition_enum maybe_send_activity( fc::limited_mutable_variant_object& capture ); boost::program_options::variables_map _options; - bool _activenode_plugin_enabled = false; + bool _activenode_plugin_enabled = true; std::pair _private_key; chain::activenode_id_type _activenode; diff --git a/libraries/plugins/debug_witness/debug_api.cpp b/libraries/plugins/debug_witness/debug_api.cpp index 823755f5..65d6d669 100644 --- a/libraries/plugins/debug_witness/debug_api.cpp +++ b/libraries/plugins/debug_witness/debug_api.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 0c4bceb8..d48601a7 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1282,7 +1282,7 @@ class wallet_api */ witness_object get_witness(string owner_account); - activenode_object get_activenodes(string owner_account); + activenode_object get_activenode(string owner_account); /** Returns information about the given committee_member. @@ -1306,7 +1306,7 @@ class wallet_api bool broadcast = false); signed_transaction create_activenode(string owner_account, - bool broadcast /* = false */) + bool broadcast /* = false */); /** * Update a witness object owned by the given account. @@ -1698,7 +1698,7 @@ FC_API( graphene::wallet::wallet_api, (whitelist_account) (create_committee_member) (get_witness) - (get_activenodes) + (get_activenode) (get_committee_member) (list_witnesses) (list_activenodes) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 50672750..ba3aeaf9 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1435,7 +1435,7 @@ class wallet_api_impl { std::vector ids_to_get; ids_to_get.push_back(*activenode_id); - std::vector> activenode_objects = _remote_db->get_activenodees(ids_to_get); + std::vector> activenode_objects = _remote_db->get_activenodes(ids_to_get); if (activenode_objects.front()) return *activenode_objects.front(); FC_THROW("No activenode is registered for id ${id}", ("id", owner_account)); @@ -3450,11 +3450,6 @@ signed_transaction wallet_api::create_activenode(string owner_account, return my->create_activenode(owner_account, broadcast); } -activenode_object wallet_api::get_activenodes(string owner_account) -{ - return my->get_activenodes(owner_account); -} - map wallet_api::list_committee_members(const string& lowerbound, uint32_t limit) { return my->_remote_db->lookup_committee_member_accounts(lowerbound, limit); @@ -3465,6 +3460,11 @@ witness_object wallet_api::get_witness(string owner_account) return my->get_witness(owner_account); } +activenode_object wallet_api::get_activenode(string owner_account) +{ + return my->get_activenode(owner_account); +} + committee_member_object wallet_api::get_committee_member(string owner_account) { return my->get_committee_member(owner_account); diff --git a/programs/build_helpers/member_enumerator.cpp b/programs/build_helpers/member_enumerator.cpp index 4b12ce75..7df3d0ca 100644 --- a/programs/build_helpers/member_enumerator.cpp +++ b/programs/build_helpers/member_enumerator.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/programs/js_operation_serializer/main.cpp b/programs/js_operation_serializer/main.cpp index 61c1873e..a644f48d 100644 --- a/programs/js_operation_serializer/main.cpp +++ b/programs/js_operation_serializer/main.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index bac16f18..1423c9c8 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include From 31846f2d7642e3a4051431bb17f83328a2d690f0 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Thu, 18 Oct 2018 17:15:08 +0300 Subject: [PATCH 03/33] fix compilation issues --- libraries/chain/db_init.cpp | 2 ++ libraries/chain/db_maint.cpp | 2 ++ libraries/chain/db_update.cpp | 8 +++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 7dee566f..e547175c 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -192,6 +192,8 @@ void database::initialize_indexes() add_index< primary_index >(); add_index< primary_index >(); + add_index< primary_index >(); + add_index< primary_index >(); add_index< primary_index >(); diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 10546de9..4feefdf3 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -210,8 +210,10 @@ void database::update_current_activenodes() const auto& anodes = get_index_type().indices(); modify(gpo, [&]( global_property_object& gp ){ + gp.current_activenodes.clear(); gp.current_activenodes.reserve(anodes.size()); + std::transform(anodes.begin(), anodes.end(), std::inserter(gp.current_activenodes, gp.current_activenodes.end()), [](const activenode_object& anode) { diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 381cd2b6..1f255fa1 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -130,7 +130,10 @@ const activenode_id_type database::validate_activenode(const signed_block& new_b fc::time_point_sec prev_block_time; activenode_id_type activenode = GRAPHENE_NULL_ACTIVENODE; - if (new_block.block_num() == 0){ + if ( + new_block.block_num() == 0 + || new_block.block_num() == 1 //why we need it ??? + ){ return activenode; // n.b. first block is at genesis_time plus one block interval // prev_block_time = dpo.time; @@ -138,6 +141,7 @@ const activenode_id_type database::validate_activenode(const signed_block& new_b } optional prev_block = fetch_block_by_number(new_block.block_num() - 1); + FC_ASSERT(prev_block); prev_block_time = prev_block->timestamp; const auto& idx = get_index_type().indices(); @@ -191,6 +195,8 @@ void database::reward_activenode(const signed_block& new_block) { uint64_t new_block_aslot = dpo.current_aslot + get_slot_at_time( new_block.timestamp ); activenode_id_type activenode_id = validate_activenode(new_block); + if (activenode_id == GRAPHENE_NULL_ACTIVENODE) + return; auto& sheduled_activenode = activenode_id(*this); deposit_activenode_pay( sheduled_activenode, gpo.parameters.activenode_pay_per_block ); From 332e6e86608311f0519ed9fa54d407f4ca5be259 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Fri, 19 Oct 2018 18:33:01 +0300 Subject: [PATCH 04/33] activenodes fix all compilation issues --- libraries/chain/db_activenode_schedule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/db_activenode_schedule.cpp b/libraries/chain/db_activenode_schedule.cpp index 0dc818d2..a89a5662 100644 --- a/libraries/chain/db_activenode_schedule.cpp +++ b/libraries/chain/db_activenode_schedule.cpp @@ -85,7 +85,7 @@ void database::update_activenode_schedule() const activenode_schedule_object& wso = activenode_schedule_id_type()(*this); const global_property_object& gpo = get_global_properties(); - if( head_block_num() % gpo.current_activenodes.size() == 0 ) + if( gpo.current_activenodes.size() != 0 && head_block_num() % gpo.current_activenodes.size() == 0 ) { modify( wso, [&]( activenode_schedule_object& _wso ) { From 4bc7c283eff7eb8dc764ff7b1d89d79ebb0fd3aa Mon Sep 17 00:00:00 2001 From: "LocalCoin.is" <42545106+LocalCoinIS@users.noreply.github.com> Date: Thu, 25 Oct 2018 21:30:41 +0100 Subject: [PATCH 05/33] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d7e7a700..264956ab 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -BitShares Core +LocalCoin Core - MasterNodes ============== [Build Status](https://travis-ci.org/bitshares/bitshares-core/branches): From 927653b3b0eebcf59a05cbcb6e1cf4b5bc364a3f Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Fri, 2 Nov 2018 22:30:18 +0100 Subject: [PATCH 06/33] activenode --- libraries/chain/db_activenode_schedule.cpp | 11 +- libraries/chain/db_block.cpp | 2 +- libraries/chain/db_init.cpp | 4 + libraries/chain/db_maint.cpp | 3 + libraries/chain/db_update.cpp | 102 +++++----- libraries/chain/db_witness_schedule.cpp | 6 + .../graphene/chain/activenode_object.hpp | 4 +- .../chain/include/graphene/chain/config.hpp | 4 +- .../chain/include/graphene/chain/database.hpp | 4 +- libraries/plugins/activenode/activenode.cpp | 176 ++++++++---------- .../graphene/activenode/activenode.hpp | 7 +- libraries/plugins/witness/witness.cpp | 11 +- tests/gateis_manual_tests/activenode.scenario | 9 + tests/tests/activenodes_tests.cpp | 0 14 files changed, 185 insertions(+), 158 deletions(-) create mode 100644 tests/gateis_manual_tests/activenode.scenario create mode 100644 tests/tests/activenodes_tests.cpp diff --git a/libraries/chain/db_activenode_schedule.cpp b/libraries/chain/db_activenode_schedule.cpp index a89a5662..46968473 100644 --- a/libraries/chain/db_activenode_schedule.cpp +++ b/libraries/chain/db_activenode_schedule.cpp @@ -36,6 +36,8 @@ activenode_id_type database::get_scheduled_activenode( uint32_t slot_num )const const dynamic_global_property_object& dpo = get_dynamic_global_properties(); const activenode_schedule_object& aso = activenode_schedule_id_type()(*this); uint64_t current_aslot = dpo.current_aslot + slot_num; + FC_ASSERT(aso.current_shuffled_activenodes.size() > 0); + return aso.current_shuffled_activenodes[ current_aslot % aso.current_shuffled_activenodes.size() ]; } @@ -56,7 +58,7 @@ fc::time_point_sec database::get_activenode_slot_time(uint32_t slot_num)const int64_t head_block_abs_slot = head_block_time().sec_since_epoch() / interval; fc::time_point_sec head_slot_time(head_block_abs_slot * interval); -// ilog("!#dbg database::get_activenode_slot_time slot_num=${slot_num} head_block_abs_slot=${head_block_abs_slot} head_slot_time=${head_slot_time}, return_val=${return_val}", ("slot_num", slot_num)("head_block_abs_slot",head_block_abs_slot)("head_slot_time", head_slot_time)("return_val", head_slot_time + (slot_num * interval))); + // ilog("!#dbg database::get_activenode_slot_time slot_num=${slot_num} head_block_abs_slot=${head_block_abs_slot} head_slot_time=${head_slot_time}, return_val=${return_val}", ("slot_num", slot_num)("head_block_abs_slot",head_block_abs_slot)("head_slot_time", head_slot_time)("return_val", head_slot_time + (slot_num * interval))); const global_property_object& gpo = get_global_properties(); @@ -67,13 +69,16 @@ fc::time_point_sec database::get_activenode_slot_time(uint32_t slot_num)const // "slot 1" is head_slot_time, // plus maint interval if head block is a maint block // plus block interval if head block is not a maint block + // ilog("!ANODE get_activenode_slot_time head_block_time = ${hbt}, head_slot_time = ${hst}, hbt + slot*interval = ${hbtplus}", ("hbt", head_block_time().sec_since_epoch())("hst", head_slot_time.sec_since_epoch())("hbtplus", (head_slot_time + (slot_num * interval)).sec_since_epoch())); + + return head_slot_time + (slot_num * interval); } uint32_t database::get_activenode_slot_at_time(fc::time_point_sec when)const { - fc::time_point_sec first_slot_time = get_activenode_slot_time( 1 ); -// ilog("!#dbg database::get_slot_at_time when=${when} first_slot_time=${first_slot_time} return_val=${return_val}", ("when", when)("first_slot_time", first_slot_time)("return_val", (when - first_slot_time).to_seconds() / block_interval() + 1)); + fc::time_point_sec first_slot_time = get_activenode_slot_time( 0 ); + // ilog("!ANODE get_activenode_slot_at_time when = ${when}, first_slot_time = ${fst}", ("when", when.sec_since_epoch())("fst", first_slot_time.sec_since_epoch())); if( when < first_slot_time ) return 0; diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index e328cd6b..0825e30d 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -512,10 +512,10 @@ void database::_apply_block( const signed_block& next_block ) apply_transaction( trx, skip ); ++_current_trx_in_block; } + reward_activenode(next_block); update_global_dynamic_data(next_block); update_signing_witness(signing_witness, next_block); - reward_activenode(next_block); update_last_irreversible_block(); // Are we at the maintenance interval? diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index e547175c..a3d6a01e 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -63,6 +63,7 @@ #include #include #include +#include #include #include @@ -175,6 +176,9 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); + register_evaluator(); + } void database::initialize_indexes() diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 4feefdf3..462e0918 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -219,6 +219,9 @@ void database::update_current_activenodes() [](const activenode_object& anode) { return anode.id; }); + if (gp.current_activenodes.size() > 0) { + activenode_id_type aid = *(gp.current_activenodes.begin()); + } }); } FC_CAPTURE_AND_RETHROW() } diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 1f255fa1..2c9fd4e1 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -122,13 +122,35 @@ void database::update_signing_witness(const witness_object& signing_witness, con _wit.last_confirmed_block_num = new_block.block_num(); } ); } -const activenode_id_type database::validate_activenode(const signed_block& new_block) { + +share_type database::get_total_account_balance(const account_object& account) { + const auto& stats = account.statistics(*this); + share_type total_balance = stats.total_core_in_orders.value + + (account.cashback_vb.valid() ? (*account.cashback_vb)(*this).balance.amount.value: 0) + + get_balance(account.get_id(), asset_id_type()).amount.value; + return total_balance; +} + +//we can also disable instead +void database::clean_poor_activenodes() { + const auto& idx = get_index_type().indices(); + std::vector list_for_removal; + + for( const activenode_object& act_object : idx ) { + + //removing activenodes that doesn't have money + share_type total_balance = get_total_account_balance(act_object.activenode_account(*this)); + if (total_balance < LLC_ACTIVENODE_MINIMAL_BALANCE) + remove(act_object); + } +} + +const fc::optional database::validate_activenode(const signed_block& new_block) { // get all activenodes who sent activity this time from the block // new_block.transactions. operations //or get all activenodes from db with time >= block_head_time... - fc::time_point_sec prev_block_time; - activenode_id_type activenode = GRAPHENE_NULL_ACTIVENODE; + fc::optional activenode = optional< activenode_id_type >(); if ( new_block.block_num() == 0 @@ -143,47 +165,30 @@ const activenode_id_type database::validate_activenode(const signed_block& new_b optional prev_block = fetch_block_by_number(new_block.block_num() - 1); FC_ASSERT(prev_block); - prev_block_time = prev_block->timestamp; + fc::time_point_sec prev_block_time = prev_block->timestamp; + fc::time_point_sec new_block_time = new_block.timestamp; const auto& idx = get_index_type().indices(); - bool found_activenode = false; - std::vector list_for_removal; - for( const activenode_object& act_object : idx ) - { - // if a.last_activity - // check if activenode has enough money on balance - auto& account = act_object.activenode_account(*this); - const auto& stats = account.statistics(*this); - share_type total_balance = stats.total_core_in_orders.value - + (account.cashback_vb.valid() ? (*account.cashback_vb)(*this).balance.amount.value: 0) - + get_balance(account.get_id(), asset_id_type()).amount.value; - - bool enough_balance = (total_balance >= LLC_ACTIVENODE_MINIMAL_BALANCE); - if (!enough_balance) { - list_for_removal.push_back(act_object); - continue; - // should deactivate or delete?? - } - uint32_t slot_num = get_activenode_slot_at_time( new_block.timestamp ); - FC_ASSERT( slot_num > 0 ); // why - //TODO: add processing of activenodes that has sent the activity on the slot without block (if/when witness misses the block) + // remove activenodes that doesn't have enough money + clean_poor_activenodes(); + uint32_t slot_num = get_activenode_slot_at_time( prev_block_time ); - activenode_id_type scheduled_activenode = get_scheduled_activenode( slot_num ); + //TODO: add processing of activenodes that has sent the activity on the slot without block (if/when witness misses the block) - if (act_object.id == scheduled_activenode) { - found_activenode = true; - activenode = scheduled_activenode; + activenode_id_type scheduled_activenode = get_scheduled_activenode( slot_num ); + for( const activenode_object& act_object : idx ) + { + if (act_object.last_activity > fc::time_point(new_block_time)) { + int a = 0; + if ( act_object.id == object_id_type(scheduled_activenode)) { + activenode = scheduled_activenode; + break; + } } } - - //removing activenodes that doesn't have money - for(auto& account : list_for_removal) - { - remove(account); - } - if (activenode == GRAPHENE_NULL_ACTIVENODE) { - ilog("sheduled activenode ${node} didn't send activity this time", ("node", activenode)); + if (!activenode) { + ilog("sheduled activenode ${node} didn't send activity this time", ("node", scheduled_activenode)); } return activenode; @@ -192,14 +197,21 @@ const activenode_id_type database::validate_activenode(const signed_block& new_b void database::reward_activenode(const signed_block& new_block) { const global_property_object& gpo = get_global_properties(); const dynamic_global_property_object& dpo = get_dynamic_global_properties(); - uint64_t new_block_aslot = dpo.current_aslot + get_slot_at_time( new_block.timestamp ); - - activenode_id_type activenode_id = validate_activenode(new_block); - if (activenode_id == GRAPHENE_NULL_ACTIVENODE) - return; - auto& sheduled_activenode = activenode_id(*this); - - deposit_activenode_pay( sheduled_activenode, gpo.parameters.activenode_pay_per_block ); + //get current_activenodes - if empty - return + const auto& anodes = get_index_type().indices(); + // check scheduled + if (anodes.size() == 0) return; + const activenode_schedule_object& aso = activenode_schedule_id_type()(*this); + if (aso.current_shuffled_activenodes.size() == 0) { + return; + } + auto& activenode_id = validate_activenode(new_block); + if (!activenode_id) { + return; + } + auto& scheduled_activenode = (*activenode_id)(*this); + + deposit_activenode_pay( scheduled_activenode, gpo.parameters.activenode_pay_per_block ); } void database::update_last_irreversible_block() diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index 66db87ee..0cf231af 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -39,6 +39,7 @@ witness_id_type database::get_scheduled_witness( uint32_t slot_num )const return wso.current_shuffled_witnesses[ current_aslot % wso.current_shuffled_witnesses.size() ]; } +// returns the time of the next witness producal fc::time_point_sec database::get_slot_time(uint32_t slot_num)const { if( slot_num == 0 ) @@ -59,6 +60,7 @@ fc::time_point_sec database::get_slot_time(uint32_t slot_num)const const global_property_object& gpo = get_global_properties(); + // if maitenance - add several blocks (that are missed) if( dpo.dynamic_flags & dynamic_global_property_object::maintenance_flag ) slot_num += gpo.parameters.maintenance_skip_slots; @@ -66,12 +68,16 @@ fc::time_point_sec database::get_slot_time(uint32_t slot_num)const // "slot 1" is head_slot_time, // plus maint interval if head block is a maint block // plus block interval if head block is not a maint block + // ilog("!@#$ get_slot_time head_block_time = ${hbt}, head_slot_time = ${hst}, hbt + slot*interval = ${hbtplus}", ("hbt", head_block_time().sec_since_epoch())("hst", head_slot_time.sec_since_epoch())("hbtplus", (head_slot_time + (slot_num * interval)).sec_since_epoch())); + return head_slot_time + (slot_num * interval); } uint32_t database::get_slot_at_time(fc::time_point_sec when)const { fc::time_point_sec first_slot_time = get_slot_time( 1 ); + // ilog("!@#$ get_slot_at_time when = ${when}, first_slot_time = ${fst}", ("when", when.sec_since_epoch())("fst", first_slot_time.sec_since_epoch())); + if( when < first_slot_time ) return 0; return (when - first_slot_time).to_seconds() / block_interval() + 1; diff --git a/libraries/chain/include/graphene/chain/activenode_object.hpp b/libraries/chain/include/graphene/chain/activenode_object.hpp index 4ba8634d..7f0c804a 100644 --- a/libraries/chain/include/graphene/chain/activenode_object.hpp +++ b/libraries/chain/include/graphene/chain/activenode_object.hpp @@ -28,7 +28,6 @@ namespace graphene { namespace chain { using namespace graphene::db; - class activenode_object; class activenode_object : public abstract_object @@ -63,5 +62,8 @@ namespace graphene { namespace chain { FC_REFLECT_DERIVED( graphene::chain::activenode_object, (graphene::db::object), (activenode_account) + (last_activity) + (endpoint) (pay_vb) + (is_enabled) ) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index ac4a0c2f..a736a2b9 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -171,9 +171,7 @@ /// Sentinel value used in the scheduler. #define GRAPHENE_NULL_WITNESS (graphene::chain::witness_id_type(0)) ///@} -/// Sentinel value used in the activenode_scheduler. -#define GRAPHENE_NULL_ACTIVENODE (graphene::chain::activenode_id_type(0)) -///@} + #define GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET (asset_id_type(743)) diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index f526a1c9..34b5ef4a 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -491,7 +491,9 @@ namespace graphene { namespace chain { //////////////////// db_update.cpp //////////////////// void update_global_dynamic_data( const signed_block& b ); void update_signing_witness(const witness_object& signing_witness, const signed_block& new_block); - const activenode_id_type validate_activenode(const signed_block& new_block); + const optional validate_activenode(const signed_block& new_block); + void clean_poor_activenodes(); + share_type get_total_account_balance(const account_object& account); void reward_activenode(const signed_block& new_block); void update_last_irreversible_block(); void clear_expired_transactions(); diff --git a/libraries/plugins/activenode/activenode.cpp b/libraries/plugins/activenode/activenode.cpp index 6fbde082..eac17607 100644 --- a/libraries/plugins/activenode/activenode.cpp +++ b/libraries/plugins/activenode/activenode.cpp @@ -45,10 +45,9 @@ void activenode_plugin::plugin_set_program_options( boost::program_options::options_description& config_file_options) { auto default_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("nathan"))); - string activenode_id_example = fc::json::to_string(chain::activenode_id_type(5)); command_line_options.add_options() - ("activenode-id,w", bpo::value>()->composing()->multitoken(), - ("ID of activenode controlled by this node (e.g. " + activenode_id_example + ", quotes are required").c_str()) + ("activenode-account", bpo::value()->composing()->multitoken(), + "Name of account that is an activenode") ("activenode-private-key", bpo::value>()->composing()->multitoken()-> DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))), "Tuple of [PublicKey, WIF private key] (for account that will get rewards for being an activenode)") @@ -65,34 +64,33 @@ void activenode_plugin::plugin_initialize(const boost::program_options::variable { try { ilog("activenode plugin: plugin_initialize() begin"); _options = &options; - _activenode = GRAPHENE_NULL_ACTIVENODE; - if (options.count("activenode-id")) - { - std::string activenode_id = options["activenode-id"].as(); - - _activenode = graphene::app::dejsonify(activenode_id, 5); + chain::database& db = database(); + if (options.count("activenode-account")) { + _activenode_account_name = options["activenode-account"].as(); } - if( options.count("activenode-private-key") ) { - const std::string key_id_to_wif_pair_string = options["activenode-private-key"].as(); - auto key_id_to_wif_pair = graphene::app::dejsonify >(key_id_to_wif_pair_string, 5); - ilog("Public Key: ${public}", ("public", key_id_to_wif_pair.first)); - fc::optional private_key = graphene::utilities::wif_to_key(key_id_to_wif_pair.second); - if (!private_key) + const std::vector key_id_to_wif_pair_strings = options["activenode-private-key"].as>(); + for (const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings) { - // the key isn't in WIF format; see if they are still passing the old native private key format. This is - // just here to ease the transition, can be removed soon - try - { - private_key = fc::variant(key_id_to_wif_pair.second, 2).as(1); - } - catch (const fc::exception&) + auto key_id_to_wif_pair = graphene::app::dejsonify >(key_id_to_wif_pair_string, GRAPHENE_MAX_NESTED_OBJECTS); + idump((key_id_to_wif_pair)); + fc::optional private_key = graphene::utilities::wif_to_key(key_id_to_wif_pair.second); + if (!private_key) { - FC_THROW("Invalid WIF-format private key ${key_string}", ("key_string", key_id_to_wif_pair.second)); + // the key isn't in WIF format; see if they are still passing the old native private key format. This is + // just here to ease the transition, can be removed soon + try + { + private_key = fc::variant( key_id_to_wif_pair.second, GRAPHENE_MAX_NESTED_OBJECTS ).as( GRAPHENE_MAX_NESTED_OBJECTS ); + } + catch (const fc::exception&) + { + FC_THROW("Invalid WIF-format private key ${key_string}", ("key_string", key_id_to_wif_pair.second)); + } } + _private_key = std::make_pair(key_id_to_wif_pair.first, *private_key); } - _private_key = std::make_pair(key_id_to_wif_pair.first, *private_key); } ilog("activenode plugin: plugin_initialize() end"); } FC_LOG_AND_RETHROW() } @@ -100,13 +98,27 @@ void activenode_plugin::plugin_initialize(const boost::program_options::variable void activenode_plugin::plugin_startup() { try { ilog("activenode plugin: plugin_startup() begin"); + chain::database& db = database(); - if( _activenode != GRAPHENE_NULL_ACTIVENODE) + const auto& account_idx = db.get_index_type().indices().get(); + const auto anode_account_itr = account_idx.find(_activenode_account_name); + if (anode_account_itr != account_idx.end()) { + // get activenode from account + const auto& anode_idx = db.get_index_type().indices().get(); + const account_object& acc_obj = *anode_account_itr; + const auto& anode_itr = anode_idx.find(acc_obj.id); + if (anode_itr != anode_idx.end()) { + _activenode = anode_itr->id; + } else { + ilog("Account ${acc} is not a registered activenode", ("acc", _activenode_account_name)); + } + } + if (_activenode) { ilog("Launching activity for an activenodes."); schedule_activity_loop(); } else - elog("No activenodes configured! Please add activenode IDs and private keys to configuration."); + elog("No activenodes configured! Please add activenode account and private key to configuration or register an activenode"); ilog("activenode plugin: plugin_startup() end"); } FC_CAPTURE_AND_RETHROW() } @@ -120,13 +132,13 @@ void activenode_plugin::schedule_activity_loop() //Schedule for the next second's tick regardless of chain state // If we would wait less than 50ms, wait for the whole second. fc::time_point now = fc::time_point::now(); - ilog("!activenode_plugin::schedule_activity_loop now=${now}", ("now", now)); + // ilog("!activenode_plugin::schedule_activity_loop now=${now}", ("now", now)); int64_t time_to_next_second = 1000000 - (now.time_since_epoch().count() % 1000000); if( time_to_next_second < 50000 ) // we must sleep for at least 50ms time_to_next_second += 1000000; fc::time_point next_wakeup( now + fc::microseconds( time_to_next_second ) ); - ilog("!activenode_plugin::schedule_activity_loop next_wakeup=${next_wakeup}", ("next_wakeup", next_wakeup)); + // ilog("!ANODE schedule_activity_loop now = ${now}, time_to_next_second = ${ttns}, nextwakeup = ${nwakeup}", ("now", now.time_since_epoch())("ttns", time_to_next_second)("nwakeup", next_wakeup.time_since_epoch())); _activity_task = fc::schedule([this]{activity_loop();}, next_wakeup, "Node activity transaction"); } @@ -138,8 +150,10 @@ activenode_condition::activenode_condition_enum activenode_plugin::activity_loop try { chain::database& db = database(); - if (_activenode(db).is_enabled) + if ((*_activenode)(db).is_enabled) result = maybe_send_activity(capture); + else + result = activenode_condition::exception_perform_activity; } catch( const fc::canceled_exception& ) { @@ -155,20 +169,22 @@ activenode_condition::activenode_condition_enum activenode_plugin::activity_loop switch( result ) { case activenode_condition::performed_activity: - ilog("Sent activity #${n} with timestamp ${t} at time ${c}", (capture)); + ilog("Sent activity from anode ${activenode}, endpoint ${endpoint} with timestamp ${timestamp}", (capture)); break; case activenode_condition::not_synced: ilog("Not sending activity because activity is disabled until we receive a recent block (see: --enable-stale-activity)"); break; case activenode_condition::not_my_turn: + ilog("not_my_turn ${scheduled_activenode}", (capture)); break; case activenode_condition::not_time_yet: + ilog("not_time_yet ${next_time}", (capture)); break; case activenode_condition::no_private_key: ilog("Not sending activity because I don't have the private key for ${scheduled_key}", (capture) ); break; case activenode_condition::lag: - elog("Not sending activity because node didn't wake up within 500ms of the slot time."); + elog("Not sending activity because node didn't wake up within 500ms of the slot time. scheduled=${scheduled_time} now=${now}", (capture)); break; case activenode_condition::exception_perform_activity: elog( "exception sending activity" ); @@ -184,8 +200,8 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt { chain::database& db = database(); fc::time_point now_fine = fc::time_point::now(); - fc::time_point_sec now = now_fine + fc::microseconds( 500000 ); - ilog("!activenode_plugin::maybe_send_activity now_fine=${now_fine} now=${now}", ("now_fine", now_fine)("now", now)); + fc::time_point_sec now = now_fine; + // ilog("!activenode_plugin::maybe_send_activity now_fine=${now_fine} now=${now}", ("now_fine", now_fine)("now", now)); // If the next send activity opportunity is in the present or future, we're synced. if( !_activenode_plugin_enabled ) @@ -199,15 +215,17 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt } // is anyone scheduled to produce now or one second in the future? - uint32_t slot = db.get_slot_at_time( now ); - ilog("!activenode_plugin::maybe_send_activitys slot=${slow} db.head_block_time()=${db_head_time}", ("slot", slot)("db_head_time", db.head_block_time())); + + //always zero + // ilog("!ANODE maybe_send_activity now_fine = ${now_fine}, now = ${now}", ("now_fine", now_fine.time_since_epoch())("now", now.sec_since_epoch())); + uint32_t slot = db.get_activenode_slot_at_time( now ); + // ilog("!ANODE maybe_send_activity slot = ${slot}", ("slot", slot)); if( slot == 0 ) { capture("next_time", db.get_slot_time(1)); return activenode_condition::not_time_yet; } - // // this assert should not fail, because now <= db.head_block_time() // should have resulted in slot == 0. @@ -216,88 +234,36 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt // which would result in allowing a later block to have a timestamp // less than or equal to the previous block // - assert( now > db.head_block_time() ); graphene::chain::activenode_id_type scheduled_activenode = db.get_scheduled_activenode( slot ); - // we must control the witness scheduled to produce the next block. - if( scheduled_activenode == _activenode ) + + if( scheduled_activenode != *_activenode ) { capture("scheduled_activenode", scheduled_activenode); return activenode_condition::not_my_turn; } fc::time_point_sec scheduled_time = db.get_slot_time( slot ); -// graphene::chain::public_key_type scheduled_key = scheduled_activenode( db ).signing_key; + // TODO: check if we need to change it + // if( llabs((scheduled_time - now).count()) > fc::milliseconds( 500 ).count() ) + // { + // capture("scheduled_time", scheduled_time)("now", now); + // return activenode_condition::lag; + // } -// if( _private_key.first != scheduled_key ) -// { -// capture("scheduled_key", scheduled_key); -// return activenode_condition::no_private_key; -// } - - if( llabs((scheduled_time - now).count()) > fc::milliseconds( 500 ).count() ) - { - capture("scheduled_time", scheduled_time)("now", now); - return activenode_condition::lag; - } - - - -// auto block = db.generate_block( -// scheduled_time, -// scheduled_witness, -// private_key_itr->second, -// _activity_skip_flags -// ); -// capture("n", block.block_num())("t", block.timestamp)("c", now); -// fc::async( [this,block](){ p2p_node().broadcast(net::block_message(block)); } ); - - - - //todo here should send transaction, with spcial operation, - // with ip, ssl enabled status, timestamp, should also check if money is enough - - // account_object issuer_account = get_account( issuer ); - // FC_ASSERT(!find_asset(symbol).valid(), "Asset with that symbol already exists!"); - - // if doesn't have 501 LLC should downgrade here? - - - // asset_create_operation create_op; - // create_op.issuer = issuer_account.id; - // create_op.symbol = symbol; - // create_op.precision = precision; - // create_op.common_options = common; - // create_op.bitasset_opts = bitasset_opts; - -// auto& account = _activenode(db).activenode_account; -// const auto& stats = account.statistics(*this); - -// share_type total_activenode_balance = stats.total_core_in_orders.value -// + (account.cashback_vb.valid() ? (*account.cashback_vb)(*this).balance.amount.value: 0) + get_balance(account.get_id(), asset_id_type()).amount.value; - -// bool enough_balance = (total_activenode_balance >= LLC_ACTIVENODE_MINIMAL_BALANCE); -// if (!enough_balance) { - -// } fc::variant_object network_info = app().p2p_node()->network_get_info(); - //fc::ip::endpoint - //fc::from_variant - //ip::endpoint::from_string + fc::ip::endpoint endpoint = fc::ip::endpoint::from_string(network_info["listening_on"].as_string()); - //firewalled_state - uint8_t - unknown,firewalled, not firewalled graphene::net::firewalled_state node_firewalled_state; fc::from_variant(network_info["firewalled"], node_firewalled_state, 1); - // network_info['firewalled'] - FC_ASSERT(endpoint.get_address().is_public_address() && node_firewalled_state == graphene::net::firewalled_state::not_firewalled); + FC_ASSERT(endpoint.get_address().is_public_address() && node_firewalled_state != graphene::net::firewalled_state::firewalled); chain::activenode_send_activity_operation send_activity_operation; - // SHOULD??: send_act_op.timestamp now = fc::time_point::now(); send_activity_operation.timepoint = now; send_activity_operation.endpoint = endpoint; - send_activity_operation.activenode = _activenode; - send_activity_operation.activenode_account = _activenode(db).activenode_account; + send_activity_operation.activenode = *_activenode; + send_activity_operation.activenode_account = (*_activenode)(db).activenode_account; graphene::chain::signed_transaction tx; tx.operations.push_back( send_activity_operation ); @@ -307,10 +273,18 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt fee_shed.set_fee(op); tx.validate(); + auto dyn_props = db.get_dynamic_global_properties(); + tx.set_reference_block( dyn_props.head_block_id ); + tx.set_expiration( dyn_props.time + fc::seconds(30) ); tx.sign( _private_key.second, db.get_chain_id() ); - fc::async( [this, tx](){ p2p_node().broadcast_transaction(tx); } ); + fc::async( [this, tx](){ + if( app().p2p_node() != nullptr ) + app().p2p_node()->broadcast_transaction(tx); + } ); + + capture("timestamp", now)("endpoint", endpoint)("activenode", *_activenode); return activenode_condition::performed_activity; } diff --git a/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp b/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp index 2f5b24bd..5ad25bdf 100644 --- a/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp +++ b/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp @@ -27,9 +27,11 @@ #include #include +#include namespace graphene { namespace activenode_plugin { - +using namespace fc; +using namespace chain; namespace activenode_condition { enum activenode_condition_enum @@ -79,7 +81,8 @@ class activenode_plugin : public graphene::app::plugin { bool _activenode_plugin_enabled = true; std::pair _private_key; - chain::activenode_id_type _activenode; + optional _activenode = optional(); + std::string _activenode_account_name; fc::future _activity_task; }; diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index 8322b734..74579df7 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -147,11 +147,17 @@ void witness_plugin::schedule_production_loop() // If we would wait less than 50ms, wait for the whole second. fc::time_point now = fc::time_point::now(); // ilog("!witness_plugin::schedule_production_loop now=${now}", ("now", now)); + + //in microseconds int64_t time_to_next_second = 1000000 - (now.time_since_epoch().count() % 1000000); + // next second in less than 50ms, we'll wait for the next one if( time_to_next_second < 50000 ) // we must sleep for at least 50ms time_to_next_second += 1000000; fc::time_point next_wakeup( now + fc::microseconds( time_to_next_second ) ); + + // ilog("!@#$ schedule_production_loop now = ${now}, time_to_next_second = ${ttns}, nextwakeup = ${nwakeup}", ("now", now.time_since_epoch())("ttns", time_to_next_second)("nwakeup", next_wakeup.time_since_epoch())); + // ilog("!witness_plugin::schedule_production_loop next_wakeup=${next_wakeup}", ("next_wakeup", next_wakeup)); _block_production_task = fc::schedule([this]{block_production_loop();}, @@ -214,7 +220,7 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb { chain::database& db = database(); fc::time_point now_fine = fc::time_point::now(); - fc::time_point_sec now = now_fine + fc::microseconds( 500000 ); + fc::time_point_sec now = now_fine; // ilog("!witness_plugin::maybe_produce_block now_fine=${now_fine} now=${now}", ("now_fine", now_fine)("now", now)); // If the next block production opportunity is in the present or future, we're synced. @@ -227,7 +233,10 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb } // is anyone scheduled to produce now or one second in the future? + // ilog("!@#$ maybe_produce_block now_fine = ${now_fine}, now = ${now}", ("now_fine", now_fine.time_since_epoch())("now", now.sec_since_epoch())); uint32_t slot = db.get_slot_at_time( now ); + // ilog("!@#$ maybe_produce_block slot = ${slot}", ("slot", slot)); + // ilog("!witness_plugin::maybe_produce_block slot=${slow} db.head_block_time()=${db_head_time}", ("slot", slot)("db_head_time", db.head_block_time())); if( slot == 0 ) diff --git a/tests/gateis_manual_tests/activenode.scenario b/tests/gateis_manual_tests/activenode.scenario new file mode 100644 index 00000000..f0b76e2f --- /dev/null +++ b/tests/gateis_manual_tests/activenode.scenario @@ -0,0 +1,9 @@ +# we can become activenode + +# we send send_activity operation and operation is included in block + +# AN gets reward + +# if AN doesn't have 501 LLC - we delete account + +# we can get AN info \ No newline at end of file diff --git a/tests/tests/activenodes_tests.cpp b/tests/tests/activenodes_tests.cpp new file mode 100644 index 00000000..e69de29b From ef51a21ebbbcdbc9fcc7fc02bf70d662eda26cc7 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Tue, 6 Nov 2018 18:37:14 +0100 Subject: [PATCH 07/33] finish witness issues --- libraries/chain/db_init.cpp | 1 + libraries/chain/db_update.cpp | 26 ++++++++++++++----- .../graphene/chain/protocol/witness.hpp | 1 + libraries/chain/witness_evaluator.cpp | 11 ++++++++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 85203e31..b3a78071 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -615,6 +615,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) std::for_each(genesis_state.initial_witness_candidates.begin(), genesis_state.initial_witness_candidates.end(), [&](const genesis_state_type::initial_witness_type& witness) { witness_create_operation op; + op.initial = true; op.witness_account = get_account_id(witness.owner_name); op.block_signing_key = witness.block_signing_key; apply_operation(genesis_eval_state, op); diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 5ffe89c1..024bb21a 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -105,14 +105,28 @@ void database::update_signing_witness(const witness_object& signing_witness, con const dynamic_global_property_object& dpo = get_dynamic_global_properties(); uint64_t new_block_aslot = dpo.current_aslot + get_slot_at_time( new_block.timestamp ); - share_type witness_pay = std::min( gpo.parameters.witness_pay_per_block, dpo.witness_budget ); + const account_balance_index& balance_index = get_index_type(); + auto range = balance_index.indices().get().equal_range(boost::make_tuple(signing_witness.witness_account)); - modify( dpo, [&]( dynamic_global_property_object& _dpo ) - { - _dpo.witness_budget -= witness_pay; - } ); + auto& account = signing_witness.witness_account(*this); + const auto& stats = account.statistics(*this); + share_type total_balance = stats.total_core_in_orders.value + + (account.cashback_vb.valid() ? (*account.cashback_vb)(*this).balance.amount.value: 0) + + get_balance(account.get_id(), asset_id_type()).amount.value; + + bool enough_balance = (total_balance >= LLC_WITNESS_MINIMAL_BALANCE); + + if (enough_balance) { + ilog("update_signing_witness enough_balance"); + share_type witness_pay = std::min( gpo.parameters.witness_pay_per_block, dpo.witness_budget ); + + modify( dpo, [&]( dynamic_global_property_object& _dpo ) + { + _dpo.witness_budget -= witness_pay; + } ); - deposit_witness_pay( signing_witness, witness_pay ); + deposit_witness_pay( signing_witness, witness_pay ); + } modify( signing_witness, [&]( witness_object& _wit ) { diff --git a/libraries/chain/include/graphene/chain/protocol/witness.hpp b/libraries/chain/include/graphene/chain/protocol/witness.hpp index 5eb75f9b..8b61a7ff 100644 --- a/libraries/chain/include/graphene/chain/protocol/witness.hpp +++ b/libraries/chain/include/graphene/chain/protocol/witness.hpp @@ -42,6 +42,7 @@ namespace graphene { namespace chain { account_id_type witness_account; string url; public_key_type block_signing_key; + bool initial = false; account_id_type fee_payer()const { return witness_account; } void validate()const; diff --git a/libraries/chain/witness_evaluator.cpp b/libraries/chain/witness_evaluator.cpp index 93785bdc..0ed3af82 100644 --- a/libraries/chain/witness_evaluator.cpp +++ b/libraries/chain/witness_evaluator.cpp @@ -27,12 +27,23 @@ #include #include #include +#include + namespace graphene { namespace chain { void_result witness_create_evaluator::do_evaluate( const witness_create_operation& op ) { try { FC_ASSERT(db().get(op.witness_account).is_lifetime_member()); + if (!op.initial) { + auto& account = op.witness_account(db()); + const auto& stats = account.statistics(db()); + share_type total_balance = stats.total_core_in_orders.value + + (account.cashback_vb.valid() ? ((*account.cashback_vb)(db())).balance.amount.value: 0) + + db().get_balance(account.get_id(), asset_id_type()).amount.value; + + FC_ASSERT(total_balance >= LLC_WITNESS_MINIMAL_BALANCE); + } return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } From 6d12d54299ed97aa21a78075be998b6dd493739f Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Sun, 18 Nov 2018 19:43:27 +0200 Subject: [PATCH 08/33] finish activenode logic --- libraries/app/application.cpp | 1 - libraries/chain/db_activenode_schedule.cpp | 7 +- libraries/chain/db_block.cpp | 1 + libraries/chain/db_update.cpp | 10 +-- .../chain/include/graphene/chain/config.hpp | 2 +- .../chain/include/graphene/chain/database.hpp | 2 +- libraries/plugins/activenode/activenode.cpp | 74 ++++++++++++++----- .../graphene/activenode/activenode.hpp | 4 +- libraries/plugins/es_objects/es_objects.cpp | 4 +- startup_cli_wallet_testnet.txt | 4 +- tests/gateis_manual_tests/activenode.scenario | 8 +- 11 files changed, 79 insertions(+), 38 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 67530898..b9101a23 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -542,7 +542,6 @@ void application_impl::handle_transaction(const graphene::net::trx_message& tran last_call = now; trx_count = 0; } - _chain_db->push_transaction( transaction_message.trx ); } FC_CAPTURE_AND_RETHROW( (transaction_message) ) } diff --git a/libraries/chain/db_activenode_schedule.cpp b/libraries/chain/db_activenode_schedule.cpp index 46968473..855be57c 100644 --- a/libraries/chain/db_activenode_schedule.cpp +++ b/libraries/chain/db_activenode_schedule.cpp @@ -31,12 +31,15 @@ namespace graphene { namespace chain { using boost::container::flat_set; -activenode_id_type database::get_scheduled_activenode( uint32_t slot_num )const +fc::optional database::get_scheduled_activenode( uint32_t slot_num )const { const dynamic_global_property_object& dpo = get_dynamic_global_properties(); const activenode_schedule_object& aso = activenode_schedule_id_type()(*this); uint64_t current_aslot = dpo.current_aslot + slot_num; - FC_ASSERT(aso.current_shuffled_activenodes.size() > 0); + + if (aso.current_shuffled_activenodes.size() == 0) { + return fc::optional(); + } return aso.current_shuffled_activenodes[ current_aslot % aso.current_shuffled_activenodes.size() ]; } diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 0825e30d..86ca25f4 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -231,6 +231,7 @@ processed_transaction database::_push_transaction( const signed_transaction& trx { // If this is the first transaction pushed after applying a block, start a new undo session. // This allows us to quickly rewind to the clean state of the head block, in case a new block arrives. + if( !_pending_tx_session.valid() ) _pending_tx_session = _undo_db.start_undo_session(); diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 2c9fd4e1..b4e296a1 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -175,22 +175,18 @@ const fc::optional database::validate_activenode(const signe //TODO: add processing of activenodes that has sent the activity on the slot without block (if/when witness misses the block) - activenode_id_type scheduled_activenode = get_scheduled_activenode( slot_num ); + fc::optional scheduled_activenode = get_scheduled_activenode( slot_num ); for( const activenode_object& act_object : idx ) { - if (act_object.last_activity > fc::time_point(new_block_time)) { + if (act_object.last_activity == fc::time_point(prev_block_time)) { int a = 0; - if ( act_object.id == object_id_type(scheduled_activenode)) { + if ( act_object.id == object_id_type(*scheduled_activenode)) { activenode = scheduled_activenode; break; } } } - if (!activenode) { - ilog("sheduled activenode ${node} didn't send activity this time", ("node", scheduled_activenode)); - } - return activenode; } diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index a736a2b9..63c12206 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -47,7 +47,7 @@ #define GRAPHENE_DEFAULT_MAX_TRANSACTION_SIZE 2048 #define GRAPHENE_DEFAULT_MAX_BLOCK_SIZE (2*1000*1000) /* < 2 MiB (less than MAX_MESSAGE_SIZE in graphene/net/config.hpp) */ #define GRAPHENE_DEFAULT_MAX_TIME_UNTIL_EXPIRATION (60*60*24) // seconds, aka: 1 day -#define GRAPHENE_DEFAULT_MAINTENANCE_INTERVAL (60*60*24) // seconds, aka: 1 day +#define GRAPHENE_DEFAULT_MAINTENANCE_INTERVAL (60*60*24) // seconds, aka: 1 day #define GRAPHENE_DEFAULT_MAINTENANCE_SKIP_SLOTS 3 // number of slots to skip for maintenance interval #define GRAPHENE_MIN_UNDO_HISTORY 10 diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 34b5ef4a..c509e47c 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -264,7 +264,7 @@ namespace graphene { namespace chain { * * Passing slot_num == 0 returns GRAPHENE_NULL_ACTIVENODE */ - activenode_id_type get_scheduled_activenode(uint32_t slot_num)const; + fc::optional get_scheduled_activenode(uint32_t slot_num)const; /** * Get the time at which the given slot occurs. diff --git a/libraries/plugins/activenode/activenode.cpp b/libraries/plugins/activenode/activenode.cpp index eac17607..d9f2b4e5 100644 --- a/libraries/plugins/activenode/activenode.cpp +++ b/libraries/plugins/activenode/activenode.cpp @@ -23,6 +23,7 @@ */ #include #include +#include #include #include @@ -33,6 +34,8 @@ #include #include +#include + using namespace graphene::activenode_plugin; using std::string; @@ -65,8 +68,11 @@ void activenode_plugin::plugin_initialize(const boost::program_options::variable ilog("activenode plugin: plugin_initialize() begin"); _options = &options; chain::database& db = database(); + if (options.count("activenode-account")) { _activenode_account_name = options["activenode-account"].as(); + } else { + elog("activenode-account field is empty! Please add activenode account to configuration"); } if( options.count("activenode-private-key") ) { @@ -91,6 +97,8 @@ void activenode_plugin::plugin_initialize(const boost::program_options::variable } _private_key = std::make_pair(key_id_to_wif_pair.first, *private_key); } + } else { + elog("activenode-private-key field is empty! Please add activenode private key to configuration"); } ilog("activenode plugin: plugin_initialize() end"); } FC_LOG_AND_RETHROW() } @@ -99,7 +107,6 @@ void activenode_plugin::plugin_startup() { try { ilog("activenode plugin: plugin_startup() begin"); chain::database& db = database(); - const auto& account_idx = db.get_index_type().indices().get(); const auto anode_account_itr = account_idx.find(_activenode_account_name); if (anode_account_itr != account_idx.end()) { @@ -110,7 +117,20 @@ void activenode_plugin::plugin_startup() if (anode_itr != anode_idx.end()) { _activenode = anode_itr->id; } else { - ilog("Account ${acc} is not a registered activenode", ("acc", _activenode_account_name)); + database().new_objects.connect([&]( const vector& ids, const flat_set& impacted_accounts ){ + const auto impacted_account = impacted_accounts.find(acc_obj.id); + if (impacted_account != impacted_accounts.end()) { + // check if we have corresponding activenode + const auto& anode_idx = db.get_index_type().indices().get(); + const auto& acc_obj = *impacted_account; + const auto& anode_itr = anode_idx.find(acc_obj); + if (anode_itr != anode_idx.end() && std::find(ids.begin(), ids.end(), anode_itr->id) != ids.end()) { + _activenode = anode_itr->id; + schedule_activity_loop(); + } + } + }); + ilog("Account ${acc} is not a registered activenode, can't start sending activity", ("acc", _activenode_account_name)); } } if (_activenode) @@ -150,10 +170,17 @@ activenode_condition::activenode_condition_enum activenode_plugin::activity_loop try { chain::database& db = database(); - if ((*_activenode)(db).is_enabled) - result = maybe_send_activity(capture); - else - result = activenode_condition::exception_perform_activity; + + auto maybe_found = db.find(*_activenode); + if ( maybe_found == nullptr ) { + _activenode.reset(); + result = activenode_condition::deleted; + } else { + if ((*_activenode)(db).is_enabled) + result = maybe_send_activity(capture); + else + result = activenode_condition::exception_perform_activity; + } } catch( const fc::canceled_exception& ) { @@ -175,10 +202,10 @@ activenode_condition::activenode_condition_enum activenode_plugin::activity_loop ilog("Not sending activity because activity is disabled until we receive a recent block (see: --enable-stale-activity)"); break; case activenode_condition::not_my_turn: - ilog("not_my_turn ${scheduled_activenode}", (capture)); break; + case activenode_condition::deleted: + return result; case activenode_condition::not_time_yet: - ilog("not_time_yet ${next_time}", (capture)); break; case activenode_condition::no_private_key: ilog("Not sending activity because I don't have the private key for ${scheduled_key}", (capture) ); @@ -186,6 +213,9 @@ activenode_condition::activenode_condition_enum activenode_plugin::activity_loop case activenode_condition::lag: elog("Not sending activity because node didn't wake up within 500ms of the slot time. scheduled=${scheduled_time} now=${now}", (capture)); break; + case activenode_condition::no_scheduled_activenodes: + ilog("No scheduled activenodes"); + break; case activenode_condition::exception_perform_activity: elog( "exception sending activity" ); break; @@ -199,6 +229,12 @@ activenode_condition::activenode_condition_enum activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capture ) { chain::database& db = database(); + + const dynamic_global_property_object& dpo = db.get_dynamic_global_properties(); + + if( dpo.dynamic_flags & dynamic_global_property_object::maintenance_flag ) + return activenode_condition::not_time_yet; + fc::time_point now_fine = fc::time_point::now(); fc::time_point_sec now = now_fine; // ilog("!activenode_plugin::maybe_send_activity now_fine=${now_fine} now=${now}", ("now_fine", now_fine)("now", now)); @@ -223,7 +259,7 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt if( slot == 0 ) { - capture("next_time", db.get_slot_time(1)); + capture("next_time", db.get_activenode_slot_time(1)); return activenode_condition::not_time_yet; } // @@ -235,11 +271,13 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt // less than or equal to the previous block // - graphene::chain::activenode_id_type scheduled_activenode = db.get_scheduled_activenode( slot ); - - if( scheduled_activenode != *_activenode ) + fc::optional scheduled_activenode = db.get_scheduled_activenode( slot ); + if (!scheduled_activenode) { + return activenode_condition::no_scheduled_activenodes; + } + if( *scheduled_activenode != *_activenode ) { - capture("scheduled_activenode", scheduled_activenode); + capture("scheduled_activenode", *scheduled_activenode); return activenode_condition::not_my_turn; } @@ -278,11 +316,13 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt tx.set_expiration( dyn_props.time + fc::seconds(30) ); tx.sign( _private_key.second, db.get_chain_id() ); + ilog("maybe_send_activity"); + app().chain_database()->push_transaction(tx); - fc::async( [this, tx](){ - if( app().p2p_node() != nullptr ) - app().p2p_node()->broadcast_transaction(tx); - } ); + // fc::async( [this, tx](){ + // if( app().p2p_node() != nullptr ) + // app().p2p_node()->broadcast_transaction(tx); + // } ); capture("timestamp", now)("endpoint", endpoint)("activenode", *_activenode); diff --git a/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp b/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp index 5ad25bdf..159067b5 100644 --- a/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp +++ b/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp @@ -42,7 +42,9 @@ namespace activenode_condition not_time_yet = 3, no_private_key = 4, lag = 5, - exception_perform_activity = 6 + no_scheduled_activenodes = 6, + deleted = 7, + exception_perform_activity = 8 }; } diff --git a/libraries/plugins/es_objects/es_objects.cpp b/libraries/plugins/es_objects/es_objects.cpp index 586cb1e2..6de81eb5 100644 --- a/libraries/plugins/es_objects/es_objects.cpp +++ b/libraries/plugins/es_objects/es_objects.cpp @@ -347,9 +347,7 @@ void es_objects_plugin::plugin_set_program_options( ("es-objects-assets", boost::program_options::value(), "Store asset objects") ("es-objects-balances", boost::program_options::value(), "Store balances objects") ("es-objects-limit-orders", boost::program_options::value(), "Store limit order objects") - ("es-objects-asset-bitasset", boost::program_options::value(), "Store feed data") - - ; + ("es-objects-asset-bitasset", boost::program_options::value(), "Store feed data"); cfg.add(cli); } diff --git a/startup_cli_wallet_testnet.txt b/startup_cli_wallet_testnet.txt index 4c17265d..7cb8ceaf 100644 --- a/startup_cli_wallet_testnet.txt +++ b/startup_cli_wallet_testnet.txt @@ -26,4 +26,6 @@ import_key localcoin-feed "5JjKPDzqw9DWPPhatkM7jo3PBoAMYDnUrCcLJQXYdw9eHRLad6k" import_balance localcoin-feed ["5JjKPDzqw9DWPPhatkM7jo3PBoAMYDnUrCcLJQXYdw9eHRLad6k"] true true import_key llc-igorbiliba "5KAPZxRBf3pQTHSNVEQUyH4gncUu82TMT3mFXTr9G3wpFNAu8Zn" true -import_balance llc-igorbiliba ["5KAPZxRBf3pQTHSNVEQUyH4gncUu82TMT3mFXTr9G3wpFNAu8Zn"] true true \ No newline at end of file +import_balance llc-igorbiliba ["5KAPZxRBf3pQTHSNVEQUyH4gncUu82TMT3mFXTr9G3wpFNAu8Zn"] true true + +create_activenode localcoin-ico true \ No newline at end of file diff --git a/tests/gateis_manual_tests/activenode.scenario b/tests/gateis_manual_tests/activenode.scenario index f0b76e2f..1f660c79 100644 --- a/tests/gateis_manual_tests/activenode.scenario +++ b/tests/gateis_manual_tests/activenode.scenario @@ -1,9 +1,9 @@ -# we can become activenode +# we can become activenode + -# we send send_activity operation and operation is included in block +# we send send_activity operation and operation is included in block + -# AN gets reward +# AN gets reward + # if AN doesn't have 501 LLC - we delete account -# we can get AN info \ No newline at end of file +# we can get AN info + \ No newline at end of file From 79eb275e0d73bb57e33c05d39cf92e122e6300be Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Tue, 20 Nov 2018 14:54:38 +0200 Subject: [PATCH 09/33] update activenode minimal balance requirements --- genesis.json | 2 +- libraries/chain/activenode_evaluator.cpp | 9 ++++++++- libraries/chain/db_update.cpp | 2 +- libraries/chain/include/graphene/chain/config.hpp | 3 ++- libraries/chain/include/graphene/chain/database.hpp | 3 ++- startup_cli_wallet_testnet.txt | 3 --- tests/gateis_manual_tests/activenode.scenario | 5 ++++- 7 files changed, 18 insertions(+), 9 deletions(-) diff --git a/genesis.json b/genesis.json index ab7014aa..801c7859 100644 --- a/genesis.json +++ b/genesis.json @@ -253,7 +253,7 @@ ], [ 48, { - "fee" : 0 + "fee" : 100000 } ] ], diff --git a/libraries/chain/activenode_evaluator.cpp b/libraries/chain/activenode_evaluator.cpp index 6edc9050..0b07f84b 100644 --- a/libraries/chain/activenode_evaluator.cpp +++ b/libraries/chain/activenode_evaluator.cpp @@ -28,13 +28,20 @@ #include #include #include +#include namespace graphene { namespace chain { void_result activenode_create_evaluator::do_evaluate( const activenode_create_operation& op ) { try { - FC_ASSERT(db().get(op.activenode_account).is_lifetime_member()); + + database& d = db(); + auto& account_obj = d.get(op.activenode_account); + FC_ASSERT(d.get(op.activenode_account).is_lifetime_member()); + + share_type total_balance = d.get_total_account_balance(account_obj); + FC_ASSERT(total_balance >= LLC_ACTIVENODE_MINIMAL_BALANCE_CREATE); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index b4e296a1..db195c5e 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -140,7 +140,7 @@ void database::clean_poor_activenodes() { //removing activenodes that doesn't have money share_type total_balance = get_total_account_balance(act_object.activenode_account(*this)); - if (total_balance < LLC_ACTIVENODE_MINIMAL_BALANCE) + if (total_balance < LLC_ACTIVENODE_MINIMAL_BALANCE_AFTER_SEND) remove(act_object); } } diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 63c12206..7265d6e5 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -178,4 +178,5 @@ #define GRAPHENE_MAX_NESTED_OBJECTS (200) #define LLC_WITNESS_MINIMAL_BALANCE (100000 * GRAPHENE_BLOCKCHAIN_PRECISION) -#define LLC_ACTIVENODE_MINIMAL_BALANCE (501 * GRAPHENE_BLOCKCHAIN_PRECISION) \ No newline at end of file +#define LLC_ACTIVENODE_MINIMAL_BALANCE_AFTER_SEND (500 * GRAPHENE_BLOCKCHAIN_PRECISION) +#define LLC_ACTIVENODE_MINIMAL_BALANCE_CREATE (511 * GRAPHENE_BLOCKCHAIN_PRECISION) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index c509e47c..bb6080da 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -476,6 +476,8 @@ namespace graphene { namespace chain { void apply_block( const signed_block& next_block, uint32_t skip = skip_nothing ); processed_transaction apply_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing ); operation_result apply_operation( transaction_evaluation_state& eval_state, const operation& op ); + share_type get_total_account_balance(const account_object& account); + private: void _apply_block( const signed_block& next_block ); processed_transaction _apply_transaction( const signed_transaction& trx ); @@ -493,7 +495,6 @@ namespace graphene { namespace chain { void update_signing_witness(const witness_object& signing_witness, const signed_block& new_block); const optional validate_activenode(const signed_block& new_block); void clean_poor_activenodes(); - share_type get_total_account_balance(const account_object& account); void reward_activenode(const signed_block& new_block); void update_last_irreversible_block(); void clear_expired_transactions(); diff --git a/startup_cli_wallet_testnet.txt b/startup_cli_wallet_testnet.txt index 7cb8ceaf..5834915d 100644 --- a/startup_cli_wallet_testnet.txt +++ b/startup_cli_wallet_testnet.txt @@ -25,7 +25,4 @@ import_balance localcoin-otc ["5Hz2oKGJKbmDC5Bp7ARFHdS8tFL2o4wm8DybFtmr3w97pAX4K import_key localcoin-feed "5JjKPDzqw9DWPPhatkM7jo3PBoAMYDnUrCcLJQXYdw9eHRLad6k" true import_balance localcoin-feed ["5JjKPDzqw9DWPPhatkM7jo3PBoAMYDnUrCcLJQXYdw9eHRLad6k"] true true -import_key llc-igorbiliba "5KAPZxRBf3pQTHSNVEQUyH4gncUu82TMT3mFXTr9G3wpFNAu8Zn" true -import_balance llc-igorbiliba ["5KAPZxRBf3pQTHSNVEQUyH4gncUu82TMT3mFXTr9G3wpFNAu8Zn"] true true - create_activenode localcoin-ico true \ No newline at end of file diff --git a/tests/gateis_manual_tests/activenode.scenario b/tests/gateis_manual_tests/activenode.scenario index 1f660c79..1f232c70 100644 --- a/tests/gateis_manual_tests/activenode.scenario +++ b/tests/gateis_manual_tests/activenode.scenario @@ -1,9 +1,12 @@ # we can become activenode + +# we can become activenode with only 511 LLC + +# we can't become activenode with 510 LLC + # we send send_activity operation and operation is included in block + # AN gets reward + -# if AN doesn't have 501 LLC - we delete account +# first we send activity, then we delete nodes and give out rewards + +# if AN doesn't have 500 LLC after sending activity - we delete account + # we can get AN info + \ No newline at end of file From 2c40d304f165e003600a7073aa39b5facb737792 Mon Sep 17 00:00:00 2001 From: Nineseven Date: Fri, 23 Nov 2018 18:49:27 +0300 Subject: [PATCH 10/33] Update main.cpp --- programs/witness_node/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index f5c01531..f0e90b5c 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -266,7 +266,7 @@ int main(int argc, char** argv) { exit_promise->set_value(signal); }, SIGTERM); - ilog("Started BitShares node on a chain with ${h} blocks.", ("h", node->chain_database()->head_block_num())); + ilog("Started LocalCoin node on a chain with ${h} blocks.", ("h", node->chain_database()->head_block_num())); ilog("Chain ID is ${id}", ("id", node->chain_database()->get_chain_id()) ); int signal = exit_promise->wait(); From 59094113e81a37e74a36688d6bb40d8f936dfd2e Mon Sep 17 00:00:00 2001 From: Nineseven Date: Fri, 23 Nov 2018 18:59:46 +0300 Subject: [PATCH 11/33] Add seeds --- libraries/app/application.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index b9101a23..a226e111 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -117,7 +117,7 @@ namespace graphene { namespace app { namespace detail { void application_impl::reset_p2p_node(const fc::path& data_dir) { try { - _p2p_network = std::make_shared("BitShares Reference Implementation"); + _p2p_network = std::make_shared("LocalCoin Reference Implementation"); _p2p_network->load_configuration(data_dir / "p2p"); _p2p_network->set_node_delegate(this); @@ -164,8 +164,9 @@ void application_impl::reset_p2p_node(const fc::path& data_dir) else { // https://bitsharestalk.org/index.php/topic,23715.0.html - vector seeds = { - }; + vector seeds = { + "moscow.localcoin.is:11010" // Moscow (Russia) + }; for( const string& endpoint_string : seeds ) { try { From 896f15d32199da50b82807c2909cbcc32e30f2f5 Mon Sep 17 00:00:00 2001 From: "LocalCoin.is" <42545106+LocalCoinIS@users.noreply.github.com> Date: Mon, 26 Nov 2018 20:35:33 +0300 Subject: [PATCH 12/33] Create 700.hf --- libraries/chain/hardfork.d/700.hf | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 libraries/chain/hardfork.d/700.hf diff --git a/libraries/chain/hardfork.d/700.hf b/libraries/chain/hardfork.d/700.hf new file mode 100644 index 00000000..c12cc6ce --- /dev/null +++ b/libraries/chain/hardfork.d/700.hf @@ -0,0 +1,4 @@ +// #700 Masternode update +#ifndef HARDFORK_700_TIME +#define HARDFORK_700_TIME (fc::time_point_sec( 1543253000 )) +#endif From 6904bd43f625577dae93bbb489787959dfcc43b5 Mon Sep 17 00:00:00 2001 From: "LocalCoin.is" <42545106+LocalCoinIS@users.noreply.github.com> Date: Mon, 26 Nov 2018 23:15:31 +0300 Subject: [PATCH 13/33] Update config.hpp --- libraries/chain/include/graphene/chain/config.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 7265d6e5..2011ee1c 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -148,7 +148,7 @@ #define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4 #define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3 -#define GRAPHENE_CURRENT_DB_VERSION "BTS2.13" +#define GRAPHENE_CURRENT_DB_VERSION "BTS2.14" #define GRAPHENE_IRREVERSIBLE_THRESHOLD (70 * GRAPHENE_1_PERCENT) @@ -179,4 +179,4 @@ #define LLC_WITNESS_MINIMAL_BALANCE (100000 * GRAPHENE_BLOCKCHAIN_PRECISION) #define LLC_ACTIVENODE_MINIMAL_BALANCE_AFTER_SEND (500 * GRAPHENE_BLOCKCHAIN_PRECISION) -#define LLC_ACTIVENODE_MINIMAL_BALANCE_CREATE (511 * GRAPHENE_BLOCKCHAIN_PRECISION) \ No newline at end of file +#define LLC_ACTIVENODE_MINIMAL_BALANCE_CREATE (511 * GRAPHENE_BLOCKCHAIN_PRECISION) From da7ce4a9f52088eaf391da53b941afd0756a1349 Mon Sep 17 00:00:00 2001 From: Nineseven Date: Tue, 27 Nov 2018 17:59:34 +0300 Subject: [PATCH 14/33] Cmake add CURL --- CMakeLists.txt | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e91e80b..ba8d3643 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,11 @@ -# Defines BitShares library target. -project( BitShares ) +# Defines LocalCoin library target. +project( LocalCoin ) cmake_minimum_required( VERSION 2.8.12 ) -set( BLOCKCHAIN_NAME "BitShares" ) +set( BLOCKCHAIN_NAME "LocalCoin" ) set( CLI_CLIENT_EXECUTABLE_NAME graphene_client ) -set( GUI_CLIENT_EXECUTABLE_NAME BitShares ) +set( GUI_CLIENT_EXECUTABLE_NAME LocalCoin ) set( CUSTOM_URL_SCHEME "gcs" ) set( INSTALLER_APP_ID "68ad7005-8eee-49c9-95ce-9eed97e5b347" ) @@ -71,7 +71,7 @@ ENDIF() if( WIN32 ) - message( STATUS "Configuring BitShares on WIN32") + message( STATUS "Configuring LocalCoin on WIN32") set( DB_VERSION 60 ) set( BDB_STATIC_LIBS 1 ) @@ -102,15 +102,25 @@ if( WIN32 ) SET(TCL_LIBS "${TCL_LIBS}${TCL_LIB_PATH}/${TCL_LIB_NAME}g${TCL_LIB_EXT}") SET(TCL_LIBRARY ${TCL_LIBS}) + add_definitions( -DCURL_STATICLIB ) + + SET(CURL_ROOT $ENV{PROGRAMFILES}/Curl) + SET(CURL_LIBRARY ${CURL_ROOT}/lib) + SET(CURL_INCLUDE_DIR ${CURL_ROOT}/include) + find_package( CURL ) + + include_directories( ${CURL_INCLUDE_DIRS} ) + link_directories( ${CURL_LIBRARIES} ) + else( WIN32 ) # Apple AND Linux if( APPLE ) # Apple Specific Options Here - message( STATUS "Configuring BitShares on OS X" ) + message( STATUS "Configuring LocalCoin on OS X" ) set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -stdlib=libc++ -Wall" ) else( APPLE ) # Linux Specific Options Here - message( STATUS "Configuring BitShares on Linux" ) + message( STATUS "Configuring LocalCoin on Linux" ) set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -Wall" ) set( rt_library rt ) set( pthread_library pthread) @@ -144,7 +154,7 @@ else( WIN32 ) # Apple AND Linux endif( WIN32 ) -set(ENABLE_COVERAGE_TESTING FALSE CACHE BOOL "Build BitShares for code coverage analysis") +set(ENABLE_COVERAGE_TESTING FALSE CACHE BOOL "Build LocalCoin for code coverage analysis") if(ENABLE_COVERAGE_TESTING) SET(CMAKE_CXX_FLAGS "--coverage ${CMAKE_CXX_FLAGS}") @@ -174,18 +184,18 @@ set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}") set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") -set(CPACK_PACKAGE_DESCRIPTION "A client for the BitShares network") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A client for the BitShares network") +set(CPACK_PACKAGE_DESCRIPTION "A client for the LocalCoin network") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A client for the LocalCoin network") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.md") -set(CPACK_PACKAGE_INSTALL_DIRECTORY "BitShares ${CPACK_PACKAGE_VERSION}") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "LocalCoin ${CPACK_PACKAGE_VERSION}") if(WIN32) SET(CPACK_GENERATOR "ZIP;NSIS") - set(CPACK_PACKAGE_NAME "BitShares") # override above + set(CPACK_PACKAGE_NAME "LocalCoin") # override above set(CPACK_NSIS_EXECUTABLES_DIRECTORY .) - set(CPACK_NSIS_PACKAGE_NAME "BitShares v${CPACK_PACKAGE_VERSION}") + set(CPACK_NSIS_PACKAGE_NAME "LocalCoin v${CPACK_PACKAGE_VERSION}") set(CPACK_NSIS_DISPLAY_NAME "${CPACK_NSIS_PACKAGE_NAME}") - set(CPACK_NSIS_DEFINES " !define MUI_STARTMENUPAGE_DEFAULTFOLDER \\\"BitShares\\\"") + set(CPACK_NSIS_DEFINES " !define MUI_STARTMENUPAGE_DEFAULTFOLDER \\\"LocalCoin\\\"") # it seems like windows zip files usually don't have a single directory inside them, unix tgz frequently do SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0) From 1273ea2568800e815b878065f3e125b719586ebf Mon Sep 17 00:00:00 2001 From: Nineseven Date: Tue, 27 Nov 2018 23:37:37 +0300 Subject: [PATCH 15/33] Update Readme, delete testnet --- .gitmodules | 4 +- README.md | 28 +- test-config.ini | 163 --- test-genesis.json | 2013 -------------------------- testnet-shared-accounts.txt | 556 ------- testnet-shared-balances.txt | 41 - testnet-shared-committee-members.txt | 204 --- testnet-shared-private-keys.txt | 10 - testnet-shared-vesting-balances.txt | 71 - testnet-shared-witnesses.txt | 304 ---- 10 files changed, 5 insertions(+), 3389 deletions(-) delete mode 100644 test-config.ini delete mode 100644 test-genesis.json delete mode 100644 testnet-shared-accounts.txt delete mode 100644 testnet-shared-balances.txt delete mode 100644 testnet-shared-committee-members.txt delete mode 100644 testnet-shared-private-keys.txt delete mode 100644 testnet-shared-vesting-balances.txt delete mode 100644 testnet-shared-witnesses.txt diff --git a/.gitmodules b/.gitmodules index e83f6f24..df92143c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,8 +1,8 @@ [submodule "docs"] path = docs - url = https://github.com/bitshares/bitshares-core.wiki.git + url = https://github.com/LocalCoinIS/LocalCoin-core.wiki.git ignore = dirty [submodule "libraries/fc"] path = libraries/fc - url = https://github.com/bitshares/bitshares-fc.git + url = https://github.com/LocalCoinIS/bitshares-fc.git ignore = dirty diff --git a/README.md b/README.md index d66400a0..b01f7171 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,6 @@ -<<<<<<< HEAD LocalCoin Core - MasterNodes -======= -LocalCoin Core ->>>>>>> master ============== -[Build Status](https://travis-ci.org/LocalCoinIS/LocalCoin-core/branches): - -`master` | `develop` | `hardfork` | `testnet` | `localcoin-fc` - --- | --- | --- | --- | --- - [![](https://travis-ci.org/LocalCoinIS/LocalCoin-core.svg?branch=master)](https://travis-ci.org/LocalCoinIS/LocalCoin-core) | [![](https://travis-ci.org/LocalCoinIS/LocalCoin-core.svg?branch=develop)](https://travis-ci.org/LocalCoinIS/LocalCoin-core) | [![](https://travis-ci.org/LocalCoinIS/LocalCoin-core.svg?branch=hardfork)](https://travis-ci.org/LocalCoinIS/LocalCoin-core) | [![](https://travis-ci.org/LocalCoinIS/LocalCoin-core.svg?branch=testnet)](https://travis-ci.org/LocalCoinIS/LocalCoin-core) | [![](https://travis-ci.org/LocalCoinIS/LocalCoin-fc.svg?branch=master)](https://travis-ci.org/LocalCoinIS/LocalCoin-fc) - - * [Getting Started](#getting-started) * [Support](#support) * [Using the API](#using-the-api) @@ -22,7 +11,7 @@ LocalCoin Core LocalCoin Core is the LocalCoin blockchain implementation and command-line interface. The web wallet is [LocalCoin UI](https://github.com/LocalCoinIS/LocalCoin-ui). -Visit [localcoin.org](https://localcoin.org/) to learn about LocalCoin and join the community at [localcoinTalk.org](https://localcointalk.org/). +Visit [localcoin.org](https://localcoin.is/) to learn about LocalCoin. **NOTE:** The official LocalCoin git repository location, default branch, and submodule remotes were recently changed. Existing repositories can be updated with the following steps: @@ -37,7 +26,7 @@ repositories can be updated with the following steps: Getting Started --------------- Build instructions and additional documentation are available in the -[wiki](https://github.com/LocalCoinIS/LocalCoin-core/wiki). +[wiki](https://dev.localcoin.is). We recommend building on Ubuntu 16.04 LTS, and the build dependencies may be installed with: @@ -92,14 +81,10 @@ Use `help` to see all available wallet commands. Source definition and listing o Support ------- -Technical support is available in the [localcoinTalk technical support subforum](https://localcointalk.org/index.php?board=45.0). - LocalCoin Core bugs can be reported directly to the [issue tracker](https://github.com/LocalCoinIS/LocalCoin-core/issues). LocalCoin UI bugs should be reported to the [UI issue tracker](https://github.com/LocalCoinIS/LocalCoin-ui/issues) -Up to date online Doxygen documentation can be found at [Doxygen](https://localcoin.org/doxygen/hierarchy.html) - Using the API ------------- @@ -164,13 +149,6 @@ With the above configuration, here is an example of how to call `add_node` from Note, the call to `network_node` is necessary to obtain the correct API identifier for the network API. It is not guaranteed that the network API identifier will always be `2`. -Since the `network_node` API requires login, it is only accessible over the websocket RPC. Our `doxygen` documentation contains the most up-to-date information -about API's for the [witness node](https://localcoin.github.io/doxygen/namespacegraphene_1_1app.html) and the -[wallet](https://localcoin.github.io/doxygen/classgraphene_1_1wallet_1_1wallet__api.html). -If you want information which is not available from an API, it might be available -from the [database](https://localcoin.github.io/doxygen/classgraphene_1_1chain_1_1database.html); -it is fairly simple to write API methods to expose database methods. - FAQ --- @@ -211,7 +189,7 @@ FAQ The second number specifies the *type*. The type of the object determines what fields it has. For a complete list of type ID's, see `enum object_type` and `enum impl_object_type` in - [types.hpp](https://github.com/LocalCoinIS/LocalCoin-2/blob/localcoin/libraries/chain/include/graphene/chain/protocol/types.hpp). + [types.hpp](https://github.com/LocalCoinIS/LocalCoin-core/blob/master/libraries/chain/include/graphene/chain/protocol/types.hpp). The third number specifies the *instance*. The instance of the object is different for each individual object. diff --git a/test-config.ini b/test-config.ini deleted file mode 100644 index 2f98e043..00000000 --- a/test-config.ini +++ /dev/null @@ -1,163 +0,0 @@ -# Endpoint for P2P node to listen on -p2p-endpoint = 0.0.0.0:11010 - -# P2P nodes to connect to on startup (may specify multiple times) -# seed-node = - -# JSON array of P2P nodes to connect to on startup -seed-nodes = [] - -# Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints. -# checkpoint = - -# Endpoint for websocket RPC to listen on -rpc-endpoint = 0.0.0.0:8090 - -# Endpoint for TLS websocket RPC to listen on -# rpc-tls-endpoint = - -# The TLS certificate file for this server -# server-pem = - -# Password for this certificate -# server-pem-password = - -# File to read Genesis State from -genesis-json = genesis.json - -# Block signing key to use for init witnesses, overrides genesis file -# dbg-init-key = - -# JSON file specifying API permissions -# api-access = - -# Space-separated list of plugins to activate -# plugins = - -# Enable block production, even if the chain is stale. -enable-stale-production = true - -# Percent of witnesses (0-99) that must be participating in order to produce blocks -required-participation = false - -# ID of witness controlled by this node (e.g. "1.6.5", quotes are required, may specify multiple times) -witness-id = "1.6.1" -witness-id = "1.6.2" -witness-id = "1.6.3" -witness-id = "1.6.4" -witness-id = "1.6.5" -witness-id = "1.6.6" -witness-id = "1.6.7" -witness-id = "1.6.8" - -# Tuple of [PublicKey, WIF private key] (may specify multiple times) -private-key = ["LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"] - -# Tuple of [PublicKey, WIF private key] (may specify multiple times) -debug-private-key = ["LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"] - -# Account ID to track history for (may specify multiple times) -# track-account = - -# Keep only those operations in memory that are related to account history tracking -partial-operations = 1 - -# Maximum number of operations per account will be kept in memory -max-ops-per-account = 1000 - -# Elastic Search database node url -# elasticsearch-node-url = - -# Number of bulk documents to index on replay(5000) -# elasticsearch-bulk-replay = - -# Number of bulk documents to index on a syncronied chain(10) -# elasticsearch-bulk-sync = - -# Log bulk events to database -# elasticsearch-logs = - -# Use visitor to index additional data(slows down the replay) -# elasticsearch-visitor = - -# Track market history by grouping orders into buckets of equal size measured in seconds specified as a JSON array of numbers -bucket-size = [60,300,900,1800,3600,14400,86400] - -# How far back in time to track history for each bucket size, measured in the number of buckets (default: 1000) -history-per-size = 1000 - -# Will only store this amount of matched orders for each market in order history for querying, or those meet the other option, which has more data (default: 1000) -max-order-his-records-per-market = 1000 - -# Will only store matched orders in last X seconds for each market in order history for querying, or those meet the other option, which has more data (default: 259200 (3 days)) -max-order-his-seconds-per-market = 259200 - -# RPC endpoint of a trusted validating node (required) -# trusted-node = - -# Block number after which to do a snapshot -# snapshot-at-block = - -# Block time (ISO format) after which to do a snapshot -# snapshot-at-time = - -# Pathname of JSON file where to store the snapshot -# snapshot-to = - -# Elasticsearch node url -# es-objects-elasticsearch-url = - -# Log bulk events to database -# es-objects-logs = - -# Number of bulk documents to index on replay(5000) -# es-objects-bulk-replay = - -# Number of bulk documents to index on a syncronied chain(10) -# es-objects-bulk-sync = - -# Store proposal objects -# es-objects-proposals = - -# Store account objects -# es-objects-accounts = - -# Store asset objects -# es-objects-assets = - -# Store balances objects -# es-objects-balances = - -# Store limit order objects -# es-objects-limit-orders = - -# Store feed data -# es-objects-asset-bitasset = - -# Group orders by percentage increase on price. Specify a JSON array of numbers here, each number is a group, number 1 means 0.01%. -tracked-groups = [10,100] - -# declare an appender named "stderr" that writes messages to the console -[log.console_appender.stderr] -stream=std_error - -# declare an appender named "p2p" that writes messages to p2p.log -[log.file_appender.p2p] -# filename can be absolute or relative to this config file -filename=logs/p2p/p2p.log -# Rotate log every ? minutes, if leave out default to 60 -rotation_interval=60 -# how long will logs be kept (in days), if leave out default to 7 -rotation_limit=7 - -# route any messages logged to the default logger to the "stderr" logger we -# declared above, if they are info level are higher -[logger.default] -level=info -appenders=stderr - -# route messages sent to the "p2p" logger to the p2p appender declared above -[logger.p2p] -level=info -appenders=p2p - diff --git a/test-genesis.json b/test-genesis.json deleted file mode 100644 index 1e5e3d21..00000000 --- a/test-genesis.json +++ /dev/null @@ -1,2013 +0,0 @@ -{ - "initial_timestamp": "2018-05-15T10:23:20", - "max_core_supply": "360000000000000", - "initial_parameters": { - "current_fees": { - "parameters": [ - [ - 0, { - "fee": 2000000, - "price_per_kbyte": 1000000 - } - ], - [ - 1, { - "fee": 500000 - } - ], - [ - 2, { - "fee": 0 - } - ], - [ - 3, { - "fee": 2000000 - } - ], - [ - 4, {} - ], - [ - 5, { - "basic_fee": 500000, - "premium_fee": 200000000, - "price_per_kbyte": 100000 - } - ], - [ - 6, { - "fee": 2000000, - "price_per_kbyte": 100000 - } - ], - [ - 7, { - "fee": 300000 - } - ], - [ - 8, { - "membership_annual_fee": 200000000, - "membership_lifetime_fee": 1000000000 - } - ], - [ - 9, { - "fee": 50000000 - } - ], - [ - 10, { - "symbol3": "50000000000", - "symbol4": "30000000000", - "long_symbol": 500000000, - "price_per_kbyte": 10 - } - ], - [ - 11, { - "fee": 50000000, - "price_per_kbyte": 10 - } - ], - [ - 12, { - "fee": 50000000 - } - ], - [ - 13, { - "fee": 50000000 - } - ], - [ - 14, { - "fee": 2000000, - "price_per_kbyte": 100000 - } - ], - [ - 15, { - "fee": 2000000 - } - ], - [ - 16, { - "fee": 100000 - } - ], - [ - 17, { - "fee": 10000000 - } - ], - [ - 18, { - "fee": 50000000 - } - ], - [ - 19, { - "fee": 100000 - } - ], - [ - 20, { - "fee": 500000000 - } - ], - [ - 21, { - "fee": 2000000 - } - ], - [ - 22, { - "fee": 2000000, - "price_per_kbyte": 10 - } - ], - [ - 23, { - "fee": 2000000, - "price_per_kbyte": 10 - } - ], - [ - 24, { - "fee": 100000 - } - ], - [ - 25, { - "fee": 100000 - } - ], - [ - 26, { - "fee": 100000 - } - ], - [ - 27, { - "fee": 2000000, - "price_per_kbyte": 10 - } - ], - [ - 28, { - "fee": 0 - } - ], - [ - 29, { - "fee": 500000000 - } - ], - [ - 30, { - "fee": 2000000 - } - ], - [ - 31, { - "fee": 100000 - } - ], - [ - 32, { - "fee": 100000 - } - ], - [ - 33, { - "fee": 2000000 - } - ], - [ - 34, { - "fee": 500000000 - } - ], - [ - 35, { - "fee": 100000, - "price_per_kbyte": 10 - } - ], - [ - 36, { - "fee": 100000 - } - ], - [ - 37, {} - ], - [ - 38, { - "fee": 2000000, - "price_per_kbyte": 10 - } - ], - [ - 39, { - "fee": 500000, - "price_per_output": 500000 - } - ], - [ - 40, { - "fee": 500000, - "price_per_output": 500000 - } - ], - [ - 41, { - "fee": 500000 - } - ], - [ - 42, {} - ], - [ - 43, { - "fee": 2000000 - } - ], - [ - 44, {} - ], - [ - 45, { - "fee": 2000000 - } - ], - [ - 46, {} - ] - ], - "scale": 10000 - }, - "block_interval": 3, - "maintenance_interval": 86400, - "maintenance_skip_slots": 3, - "committee_proposal_review_period": 1209600, - "maximum_transaction_size": 2048, - "maximum_block_size": 2000000, - "maximum_time_until_expiration": 86400, - "maximum_proposal_lifetime": 2419200, - "maximum_asset_whitelist_authorities": 10, - "maximum_asset_feed_publishers": 10, - "maximum_witness_count": 1001, - "maximum_committee_count": 1001, - "maximum_authority_membership": 10, - "reserve_percent_of_fee": 2000, - "network_percent_of_fee": 2000, - "lifetime_referrer_percent_of_fee": 3000, - "cashback_vesting_period_seconds": 31536000, - "cashback_vesting_threshold": 10000000, - "count_non_member_votes": true, - "allow_non_member_whitelists": false, - "witness_pay_per_block": 100000, - "worker_budget_per_day": "50000000000", - "max_predicate_opcode": 1, - "fee_liquidation_threshold": 10000000, - "accounts_per_fee_scale": 1000, - "account_fee_scale_bitshifts": 4, - "max_authority_depth": 2, - "extensions": [] - }, - "initial_accounts": [{ - "name": "notteler", - "owner_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - }, { - "name": "germut", - "owner_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - }, { - "name": "localcoin-ico", - "owner_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - }, { - "name": "localcoin", - "owner_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - }, { - "name": "localcoin-wallet", - "owner_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - }, { - "name": "localcoin-fiat", - "owner_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - }, { - "name": "localcoin-otc", - "owner_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - }, { - "name": "localcoin-feed", - "owner_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - }], - "initial_assets": [{ - "symbol": "USD", - "issuer_name": "localcoin-fiat", - "description": "US dollar", - "precision": 4 - }, { - "symbol": "EUR", - "issuer_name": "localcoin-fiat", - "description": "Euro", - "precision": 4 - }, { - "symbol": "GBP", - "issuer_name": "localcoin-fiat", - "description": "Pound sterling", - "precision": 4 - }, { - "symbol": "RUB", - "issuer_name": "localcoin-fiat", - "description": "Russian rouble", - "precision": 4 - }, { - "symbol": "CNY", - "issuer_name": "localcoin-fiat", - "description": "Chinese yuan renminbi", - "precision": 4 - }, - { - "description": "1 bitcoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BTC" - }, - { - "description": "1 ethereum", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ETH" - }, - - { - "description": "1 bitcoin cash", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BCH" - }, - - { - "description": "1 litecoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "LTC" - }, - - - { - "description": "1 ripple", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XRP" - }, - - { - "description": "1 qtum", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "QTUM" - }, - - { - "description": "1 huobi token", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "HT" - }, - - { - "description": "1 ethereum classic", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ETC" - }, - - { - "description": "1 NEO", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NEO" - }, - - - { - "description": "1 cardano", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ADA" - }, - - { - "description": "1 zcash", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ZEC" - }, - { - "description": "1 stellar", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XLM" - }, - { - "description": "1 IOTA", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "MIOTA" - }, - - { - "description": "1 monero", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XMR" - }, - { - "description": "1 dash", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DASH" - }, - { - "description": "1 nem", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XEM" - }, - - { - "description": "1 bytecoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BCN" - }, - - - { - "description": "1 lisk", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "LSK" - }, - { - "description": "1 bitcoin gold", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BTG" - }, - { - "description": "1 decred", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DCR" - }, - { - "description": "1 verge", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XVG" - }, - { - "description": "1 steem", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "STEEM" - }, - { - "description": "1 nano", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NANO" - }, - { - "description": "1 bitshares", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BTS" - }, - { - "description": "1 wanchain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "WAN" - }, - { - "description": "1 hshare", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "HSR" - }, - { - "description": "1 Waves", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "WAVES" - }, - { - "description": "1 Achain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ACT" - }, - { - "description": "1 Groestlcoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "GRS" - }, - { - "description": "1 dogecoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DOGE" - }, - { - "description": "1 waykichain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "WICC" - }, - { - "description": "1 GXChain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "GXS" - }, - { - "description": "1 cloakcoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "CLOAK" - }, - { - "description": "1 stratis", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "STRAT" - }, - { - "description": "1 neblio", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NEBL" - }, - { - "description": "1 siacoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SC" - }, - { - "description": "1 elastos", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ELA" - }, - { - "description": "1 navcoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NAV" - }, - { - "description": "1 asch", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XAS" - }, - { - "description": "1 Metaverse ETP", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ETP" - }, - { - "description": "1 digibyte", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DGB" - }, - { - "description": "1 reddcoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "RDD" - }, - { - "description": "1 poa network", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "POA" - }, - { - "description": "1 nxt", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NXT" - }, - { - "description": "1 syscoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SYS" - }, - { - "description": "1 pivx", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "PIVX" - }, - { - "description": "1 Pura", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "PURA" - }, - { - "description": "1 DECENT", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DCT" - }, - { - "description": "1 nexus", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NXS" - }, - { - "description": "1 primecoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XPM" - }, - { - "description": "1 komodo", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "KMD" - }, - { - "description": "1 DigitalNote", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XDN" - }, - { - "description": "1 ZenCash", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ZEN" - }, - { - "description": "1 Ardor", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ARDR" - }, - { - "description": "1 vertcoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "VTC" - }, - { - "description": "1 bitcoin diamond", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BCD" - }, - { - "description": "1 cryptonex", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "CNX" - }, - { - "description": "1 ZCoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XZC" - }, - { - "description": "1 Steem Dollars", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SBD" - }, - { - "description": "1 Factom", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "FCT" - }, - { - "description": "1 LinkEye", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "LET" - }, - { - "description": "1 Viacoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "VIA" - }, - { - "description": "1 Particl", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "PART" - }, - { - "description": "1 Emercoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "EMC" - }, - { - "description": "1 Ark", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ARK" - }, - { - "description": "1 Experience points", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XP" - }, - { - "description": "1 Skycoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SKY" - }, - { - "description": "1 ZClassic", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ZCL" - }, - { - "description": "1 MonaCoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "MONA" - }, - { - "description": "1 SelfSell", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SSC" - }, - { - "description": "1 Ubiq", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "UBQ" - }, - { - "description": "1 BitCoin Private", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BTCP" - }, - { - "description": "1 BitCore", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BTX" - }, - { - "description": "1 Electroneum", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ETN" - }, - { - "description": "1 Electra", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ECA" - }, - { - "description": "1 Einsteinium", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "EMC2" - }, - { - "description": "1 Salus", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SLS" - }, - { - "description": "1 TokenPay", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "TPAY" - }, - { - "description": "1 Ravencoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "RVN" - }, - { - "description": "1 GameCredits", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "GAME" - }, - { - "description": "1 ION", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ION" - }, - { - "description": "1 Peercoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "PPC" - }, - { - "description": "1 BOSCoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BOS" - }, - { - "description": "1 LBRY Credits", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "LBC" - }, - { - "description": "1 Litecoin Cash", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "LCC" - }, - { - "description": "1 Zoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ZOI" - }, - { - "description": "1 WhiteCoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XWC" - }, - { - "description": "1 BitCoin Dark", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BTCD" - }, - { - "description": "1 Burst", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BURST" - }, - { - "description": "1 Byteball Bytes", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "GBYTE" - }, - { - "description": "1 HTMLCOIN", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "HTML" - }, - { - "description": "1 BitBay", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BAY" - }, - { - "description": "1 Counterparty", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XCP" - }, - { - "description": "1 Namecoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NMC" - }, - { - "description": "1 Blocknet", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BLOCK" - }, - { - "description": "1 SmartCash", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SMART" - }, - { - "description": "1 Feathercoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "FTC" - }, - { - "description": "1 Gulden", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NLG" - }, - { - "description": "1 MinexCoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "MNX" - }, - - - - - { - "description": "1 Tether", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "USDT" - }, - { - "description": "1 EOS", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "EOS" - }, - { - "description": "1 TRON", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "TRX" - }, - { - "description": "1 True Chain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "TRUE" - }, - { - "description": "1 0x", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ZRX" - }, - { - "description": "1 Bibox Token", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BIX" - }, - { - "description": "1 Ontology", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ONT" - }, - { - "description": "1 CyberMiles", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "CMT" - }, - { - "description": "1 Zilliqa", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ZIL" - }, - { - "description": "1 IOSToken", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "IOST" - }, - { - "description": "1 VeChain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "VEN" - }, - { - "description": "1 Cortex", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "CTXC" - }, - { - "description": "1 Binance Coin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BNB" - }, - { - "description": "1 Bytom", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BTM" - }, - { - "description": "1 aelf", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ELF" - }, - { - "description": "1 OmiseGO", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "OMG" - }, - { - "description": "1 Nebulas", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NAS" - }, - { - "description": "1 ICON", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ICX" - }, - { - "description": "1 Status", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SNT" - }, - { - "description": "1 Storm", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "STORM" - }, - { - "description": "1 Populous", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "PPT" - }, - { - "description": "1 Aeternity", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "AE" - }, - { - "description": "1 Loopring", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "LRC" - }, - { - "description": "1 Mithril", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "MITH" - }, - { - "description": "1 Nexo", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NEXO" - }, - { - "description": "1 Monaco", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "MCO" - }, - { - "description": "1 Arcblock", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ABT" - }, - { - "description": "1 Golem", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "GNT" - }, - { - "description": "1 Kyber Network", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "KNC" - }, - { - "description": "1 IHT Real Estate Protocol", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "IHT" - }, - { - "description": "1 All Sports", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SOC" - }, - { - "description": "1 Time New Bank", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "TNB" - }, - { - "description": "1 Bancor", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BNT" - }, - { - "description": "1 eosDAC", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "EOSDAC" - }, - { - "description": "1 Nucleus Vision", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NCASH" - }, - { - "description": "1 Theta Token", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "THETA" - }, - { - "description": "1 Loom Network", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "LOOM" - }, - { - "description": "1 Civic", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "CVC" - }, - { - "description": "1 Gifto", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "GTO" - }, - { - "description": "1 Enigma", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ENG" - }, - { - "description": "1 Game.com", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "GTC" - }, - { - "description": "1 Fusion", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "FSN" - }, - { - "description": "1 Basic Attention Token", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BAT" - }, - { - "description": "1 Power Ledger", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "POWR" - }, - { - "description": "1 Waltonchain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "WTC" - }, - { - "description": "1 FunFair", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "FUN" - }, - { - "description": "1 TenX", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "PAY" - }, - { - "description": "1 Storj", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "STORJ" - }, - { - "description": "1 Nuls", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "NULS" - }, - { - "description": "1 Polymath", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "POLY" - }, - { - "description": "1 Ethos", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ETHOS" - }, - { - "description": "1 High Performance Blockchain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "HPB" - }, - { - "description": "1 Augur", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "REP" - }, - { - "description": "1 Ink", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "INK" - }, - { - "description": "1 Ruff", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "RUFF" - }, - { - "description": "1 Gas", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "GAS" - }, - { - "description": "1 SALT", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SALT" - }, - { - "description": "1 Substratum", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SUB" - }, - { - "description": "1 Bluzelle", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BLZ" - }, - { - "description": "1 Decentraland", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "MANA" - }, - { - "description": "1 Aion", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "AION" - }, - { - "description": "1 Bottos", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BTO" - }, - { - "description": "1 Holo", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "HOT" - }, - { - "description": "1 Credits", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "CS" - }, - { - "description": "1 DeepBrain Chain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DBC" - }, - { - "description": "1 Quantstamp", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "QSP" - }, - { - "description": "1 BnkToTheFuture", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "BFT" - }, - { - "description": "1 Enjin Coin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ENJ" - }, - { - "description": "1 MaidSafeCoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SAFE" - }, - { - "description": "1 WAX", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "WAX" - }, - { - "description": "1 iExec RLC", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "RLC" - }, - { - "description": "1 Dent", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DENT" - }, - { - "description": "1 Dragonchain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DRGN" - }, - { - "description": "1 SmartMesh", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SMT" - }, - { - "description": "1 Matrix AI Network", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "MAN" - }, - { - "description": "1 Delphy", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DPY" - }, - { - "description": "1 Revain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "R" - }, - { - "description": "1 DigixDAO", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DGD" - }, - { - "description": "1 QASH", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "QASH" - }, - { - "description": "1 Crypterium", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "CRPT" - }, - { - "description": "1 SONM", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SNM" - }, - { - "description": "1 Request Network", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "REQ" - }, - { - "description": "1 Ignis", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "IGNIS" - }, - { - "description": "1 Scry.info", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DDD" - }, - { - "description": "1 ChainLink", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "LINK" - }, - { - "description": "1 Veritaseum", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "VERI" - }, - { - "description": "1 Maker", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "MKR" - }, - { - "description": "1 Kin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "KIN" - }, - { - "description": "1 Cindicator", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "CND" - }, - { - "description": "1 MediBloc", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "MED" - }, - { - "description": "1 SophiaTX", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "SPHTX" - }, - { - "description": "1 Gnosis", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "GNO" - }, - { - "description": "1 RChain", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "RHOC" - }, - { - "description": "1 Iconomi", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ICN" - }, - { - "description": "1 Mixin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "XIN" - }, - { - "description": "1 Aragon", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "ANT" - }, - { - "description": "1 Dentacoin", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "DCN" - }, - { - "description": "1 Centrality", - "is_bitasset": true, - "issuer_name": "localcoin-wallet", - "max_supply": "1000000000000000", - "precision": 8, - "symbol": "CENNZ" - } - ], - - "initial_balances": [{ - "owner": "LLCJBqPxC8R6H4KdRPSxbs999XyobsZXTyPa", - "asset_symbol": "LLC", - "amount": "80000000000000" - }, - { - "owner": "LLCHnjug7KJG84jg8qoG5SVa9XDqfDm8cBkx", - "asset_symbol": "LLC", - "amount": "20000000000000" - }, - { - "owner": "LLC6f3FN251kWo8gQKrTwtSb1R8Tvt6w2B3H", - "asset_symbol": "LLC", - "amount": "10000000000000" - } - ], - "initial_vesting_balances": [], - "initial_active_witnesses": 8, - "initial_witness_candidates": [{ - "owner_name": "notteler", - "block_signing_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - }, { - "owner_name": "germut", - "block_signing_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - }, { - "owner_name": "localcoin-ico", - "block_signing_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - }, { - "owner_name": "localcoin", - "block_signing_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - }, { - "owner_name": "localcoin-wallet", - "block_signing_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - }, { - "owner_name": "localcoin-fiat", - "block_signing_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - }, { - "owner_name": "localcoin-otc", - "block_signing_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - }, { - "owner_name": "localcoin-feed", - "block_signing_key": "LLC6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - }], - "initial_committee_candidates": [{ - "owner_name": "notteler" - }, { - "owner_name": "germut" - }, { - "owner_name": "localcoin-ico" - }, { - "owner_name": "localcoin" - }, { - "owner_name": "localcoin-wallet" - }, { - "owner_name": "localcoin-fiat" - }, { - "owner_name": "localcoin-otc" - }, { - "owner_name": "localcoin-feed" - }], - "initial_worker_candidates": [], - "initial_chain_id": "aa34045518f1469a28fa4578240d5f039afa9959c0b95ce3b39674efa691fb21", - "immutable_parameters": { - "min_committee_member_count": 7, - "min_witness_count": 7, - "num_special_accounts": 0, - "num_special_assets": 0 - } -} \ No newline at end of file diff --git a/testnet-shared-accounts.txt b/testnet-shared-accounts.txt deleted file mode 100644 index 99392365..00000000 --- a/testnet-shared-accounts.txt +++ /dev/null @@ -1,556 +0,0 @@ - "initial_accounts": [{ - "name": "init0", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init1", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init2", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init3", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init4", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init5", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init6", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init7", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init8", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init9", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init10", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init11", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init12", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init13", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init14", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init15", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init16", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init17", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init18", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init19", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init20", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init21", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init22", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init23", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init24", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init25", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init26", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init27", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init28", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init29", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init30", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init31", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init32", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init33", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init34", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init35", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init36", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init37", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init38", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init39", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init40", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init41", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init42", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init43", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init44", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init45", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init46", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init47", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init48", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init49", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init50", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init51", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init52", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init53", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init54", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init55", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init56", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init57", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init58", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init59", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init60", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init61", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init62", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init63", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init64", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init65", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init66", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init67", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init68", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init69", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init70", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init71", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init72", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init73", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init74", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init75", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init76", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init77", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init78", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init79", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init80", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init81", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init82", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init83", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init84", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init85", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init86", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init87", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init88", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init89", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init90", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init91", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init92", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init93", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init94", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init95", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init96", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init97", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init98", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init99", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "init100", - "owner_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "active_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "is_lifetime_member": true - },{ - "name": "dummy0", - "owner_key": "BTS6qkMe8pHmQ4zUetLV1bbVKoQJYTNb1fSUbkQzuzpscYhonWpgk", - "active_key": "BTS6qkMe8pHmQ4zUetLV1bbVKoQJYTNb1fSUbkQzuzpscYhonWpgk", - "is_lifetime_member": true - },{ - "name": "dummy1", - "owner_key": "BTS7wXsTzBBR2QEetjrgxcSmN7Kuzey3RAzQWNNHwbPQsKYxkP6fp", - "active_key": "BTS7wXsTzBBR2QEetjrgxcSmN7Kuzey3RAzQWNNHwbPQsKYxkP6fp", - "is_lifetime_member": true - },{ - "name": "dummy2", - "owner_key": "BTS7rzifzfJxS8RWhev9aU8HDYoJi1EGwJRHG9B2fJKxnZAiF2Rsh", - "active_key": "BTS7rzifzfJxS8RWhev9aU8HDYoJi1EGwJRHG9B2fJKxnZAiF2Rsh", - "is_lifetime_member": true - },{ - "name": "dummy3", - "owner_key": "BTS6QZdcwFEFMtHsfW27YBGTv9KLaLTvgx5wgGrPHeUxDTrYEQJ2d", - "active_key": "BTS6QZdcwFEFMtHsfW27YBGTv9KLaLTvgx5wgGrPHeUxDTrYEQJ2d", - "is_lifetime_member": true - },{ - "name": "dummy4", - "owner_key": "BTS7q5MqhSP2a6CRTWaJk77ZcGdpnv14JbT4cVzbXaoAsWJoCxFJG", - "active_key": "BTS7q5MqhSP2a6CRTWaJk77ZcGdpnv14JbT4cVzbXaoAsWJoCxFJG", - "is_lifetime_member": true - },{ - "name": "dummy5", - "owner_key": "BTS5sRXxgDCnteHLUS623xtxJM5WKKVygwDMzEso6LigwxvprJqBA", - "active_key": "BTS5sRXxgDCnteHLUS623xtxJM5WKKVygwDMzEso6LigwxvprJqBA", - "is_lifetime_member": true - },{ - "name": "dummy6", - "owner_key": "BTS5V4HEQJbVbMjUWASeknQ42NT3NP9bZaygt83XMuvy6v4QMJuSP", - "active_key": "BTS5V4HEQJbVbMjUWASeknQ42NT3NP9bZaygt83XMuvy6v4QMJuSP", - "is_lifetime_member": true - },{ - "name": "dummy7", - "owner_key": "BTS86ukuPAufzKouerZf1dCxjVSmxQPA5kLwvnYEjn9GRqi5qXBop", - "active_key": "BTS86ukuPAufzKouerZf1dCxjVSmxQPA5kLwvnYEjn9GRqi5qXBop", - "is_lifetime_member": true - },{ - "name": "dummy8", - "owner_key": "BTS7Sdg3kQuz2pPT8mA8Yr3mkBe7zr6293mnBmoR36z9xxtRdiMmJ", - "active_key": "BTS7Sdg3kQuz2pPT8mA8Yr3mkBe7zr6293mnBmoR36z9xxtRdiMmJ", - "is_lifetime_member": true - },{ - "name": "dummy9", - "owner_key": "BTS5WCj1mMiiqEE4QRs7xhaFfSaiFroejUp3GuZE9wvfue9nxhPPn", - "active_key": "BTS5WCj1mMiiqEE4QRs7xhaFfSaiFroejUp3GuZE9wvfue9nxhPPn", - "is_lifetime_member": true - },{ diff --git a/testnet-shared-balances.txt b/testnet-shared-balances.txt deleted file mode 100644 index dc9061fa..00000000 --- a/testnet-shared-balances.txt +++ /dev/null @@ -1,41 +0,0 @@ - "initial_balances": [{ - "owner": "BTSHYhQcrjVg5kBzCoeeD38eQdncCC5pBgee", - "asset_symbol": "CORE", - "amount": 100000000000 - },{ - "owner": "BTSPgQZg5929ht1NBdEvsGKqoQ7buRu3nKf4", - "asset_symbol": "CORE", - "amount": 100000000000 - },{ - "owner": "BTSC9zrLXSAPUQaVmQPk1S9dMqSzT7jPqYU7", - "asset_symbol": "CORE", - "amount": 100000000000 - },{ - "owner": "BTS93aQPtbbkXwaSjtHaREsNVcCvbfHo93aZ", - "asset_symbol": "CORE", - "amount": 100000000000 - },{ - "owner": "BTS6RM4UfsYFPDuhbmgkvDS9ip8Kvqundvyk", - "asset_symbol": "CORE", - "amount": 100000000000 - },{ - "owner": "BTSNVkZXdqWWSzqHVxvfetMe347is6kEkC4K", - "asset_symbol": "CORE", - "amount": 100000000000 - },{ - "owner": "BTS5GHzWZ64Luoajqsz6JGjTKVMgWYkGV9SQ", - "asset_symbol": "CORE", - "amount": 100000000000 - },{ - "owner": "BTSDCVRFez92bW9doRLjnFCKLJnpM58mgmMb", - "asset_symbol": "CORE", - "amount": 100000000000 - },{ - "owner": "BTS5CCdX3JYLBptYMuCjbsezqGYzN9vG9JCu", - "asset_symbol": "CORE", - "amount": 100000000000 - },{ - "owner": "BTSEQ3yQdr3EMDL2eRqGiceMCpoanaW16Puw", - "asset_symbol": "CORE", - "amount": 100000000000 - },{ diff --git a/testnet-shared-committee-members.txt b/testnet-shared-committee-members.txt deleted file mode 100644 index 7d7ae11b..00000000 --- a/testnet-shared-committee-members.txt +++ /dev/null @@ -1,204 +0,0 @@ - "initial_committee_candidates": [{ - "owner_name": "init0" - },{ - "owner_name": "init1" - },{ - "owner_name": "init2" - },{ - "owner_name": "init3" - },{ - "owner_name": "init4" - },{ - "owner_name": "init5" - },{ - "owner_name": "init6" - },{ - "owner_name": "init7" - },{ - "owner_name": "init8" - },{ - "owner_name": "init9" - },{ - "owner_name": "init10" - },{ - "owner_name": "init11" - },{ - "owner_name": "init12" - },{ - "owner_name": "init13" - },{ - "owner_name": "init14" - },{ - "owner_name": "init15" - },{ - "owner_name": "init16" - },{ - "owner_name": "init17" - },{ - "owner_name": "init18" - },{ - "owner_name": "init19" - },{ - "owner_name": "init20" - },{ - "owner_name": "init21" - },{ - "owner_name": "init22" - },{ - "owner_name": "init23" - },{ - "owner_name": "init24" - },{ - "owner_name": "init25" - },{ - "owner_name": "init26" - },{ - "owner_name": "init27" - },{ - "owner_name": "init28" - },{ - "owner_name": "init29" - },{ - "owner_name": "init30" - },{ - "owner_name": "init31" - },{ - "owner_name": "init32" - },{ - "owner_name": "init33" - },{ - "owner_name": "init34" - },{ - "owner_name": "init35" - },{ - "owner_name": "init36" - },{ - "owner_name": "init37" - },{ - "owner_name": "init38" - },{ - "owner_name": "init39" - },{ - "owner_name": "init40" - },{ - "owner_name": "init41" - },{ - "owner_name": "init42" - },{ - "owner_name": "init43" - },{ - "owner_name": "init44" - },{ - "owner_name": "init45" - },{ - "owner_name": "init46" - },{ - "owner_name": "init47" - },{ - "owner_name": "init48" - },{ - "owner_name": "init49" - },{ - "owner_name": "init50" - },{ - "owner_name": "init51" - },{ - "owner_name": "init52" - },{ - "owner_name": "init53" - },{ - "owner_name": "init54" - },{ - "owner_name": "init55" - },{ - "owner_name": "init56" - },{ - "owner_name": "init57" - },{ - "owner_name": "init58" - },{ - "owner_name": "init59" - },{ - "owner_name": "init60" - },{ - "owner_name": "init61" - },{ - "owner_name": "init62" - },{ - "owner_name": "init63" - },{ - "owner_name": "init64" - },{ - "owner_name": "init65" - },{ - "owner_name": "init66" - },{ - "owner_name": "init67" - },{ - "owner_name": "init68" - },{ - "owner_name": "init69" - },{ - "owner_name": "init70" - },{ - "owner_name": "init71" - },{ - "owner_name": "init72" - },{ - "owner_name": "init73" - },{ - "owner_name": "init74" - },{ - "owner_name": "init75" - },{ - "owner_name": "init76" - },{ - "owner_name": "init77" - },{ - "owner_name": "init78" - },{ - "owner_name": "init79" - },{ - "owner_name": "init80" - },{ - "owner_name": "init81" - },{ - "owner_name": "init82" - },{ - "owner_name": "init83" - },{ - "owner_name": "init84" - },{ - "owner_name": "init85" - },{ - "owner_name": "init86" - },{ - "owner_name": "init87" - },{ - "owner_name": "init88" - },{ - "owner_name": "init89" - },{ - "owner_name": "init90" - },{ - "owner_name": "init91" - },{ - "owner_name": "init92" - },{ - "owner_name": "init93" - },{ - "owner_name": "init94" - },{ - "owner_name": "init95" - },{ - "owner_name": "init96" - },{ - "owner_name": "init97" - },{ - "owner_name": "init98" - },{ - "owner_name": "init99" - },{ - "owner_name": "init100" - } - ], diff --git a/testnet-shared-private-keys.txt b/testnet-shared-private-keys.txt deleted file mode 100644 index e2a8d7dd..00000000 --- a/testnet-shared-private-keys.txt +++ /dev/null @@ -1,10 +0,0 @@ -5KCNDLVGqvX8p3GcMFun9sMe6XbMvycVTm4bGrkB5aZGWCbAAtr -5HvFQ1bcAWk8H1A2qXj1AqSNp93GUAb6b2w5TVfLb1jWL6yNF3f -5JSxv2kgaBSm9nGseRNhLhgEKTBmoKJ5CkgLbbk5RW4RBCNsLJC -5K5E2TQtrodDFzsqPq3oVFi9rVX15AN8sLE3iTHfVsX1b49y49J -5HxC3fwN7VDZXKVkbbX3SzCczh18Fetx8TXBfJ3z3ovDUSPKvVd -5KSr4w978PDanQDYtftarcfJVvGe4wedYb1sYbdH6HNpi15heRa -5Kan4si6qWvDVpZuqug4c6KQH4zkvDhwspaGQiFKYniJv6qji6t -5KcZri5DDsMcDp1DjNeMkZSijkWurPoAoR7gBKTnnetNQ9CpXoJ -5K5TRZyEhC6GPgi57t5FhiSMRGVTHEbwXngbBEtCA41gM8LPFhF -5KXVG4oP4Vj3RawRpta79UFAg7pWp17FGf4DnrKfkr69ELytDMv diff --git a/testnet-shared-vesting-balances.txt b/testnet-shared-vesting-balances.txt deleted file mode 100644 index 1dd00230..00000000 --- a/testnet-shared-vesting-balances.txt +++ /dev/null @@ -1,71 +0,0 @@ - "initial_vesting_balances": [{ - "owner": "BTSHYhQcrjVg5kBzCoeeD38eQdncCC5pBgee", - "asset_symbol": "BTS", - "amount": 50000000000, - "begin_timestamp": "2014-11-06T00:00:00", - "vesting_duration_seconds": 63072000, - "begin_balance": 50000000000 - },{ - "owner": "BTSPgQZg5929ht1NBdEvsGKqoQ7buRu3nKf4", - "asset_symbol": "BTS", - "amount": 50000000000, - "begin_timestamp": "2014-11-06T00:00:00", - "vesting_duration_seconds": 63072000, - "begin_balance": 50000000000 - },{ - "owner": "BTSC9zrLXSAPUQaVmQPk1S9dMqSzT7jPqYU7", - "asset_symbol": "BTS", - "amount": 50000000000, - "begin_timestamp": "2014-11-06T00:00:00", - "vesting_duration_seconds": 63072000, - "begin_balance": 50000000000 - },{ - "owner": "BTS93aQPtbbkXwaSjtHaREsNVcCvbfHo93aZ", - "asset_symbol": "BTS", - "amount": 50000000000, - "begin_timestamp": "2014-11-06T00:00:00", - "vesting_duration_seconds": 63072000, - "begin_balance": 50000000000 - },{ - "owner": "BTS6RM4UfsYFPDuhbmgkvDS9ip8Kvqundvyk", - "asset_symbol": "BTS", - "amount": 50000000000, - "begin_timestamp": "2014-11-06T00:00:00", - "vesting_duration_seconds": 63072000, - "begin_balance": 50000000000 - },{ - "owner": "BTSNVkZXdqWWSzqHVxvfetMe347is6kEkC4K", - "asset_symbol": "BTS", - "amount": 50000000000, - "begin_timestamp": "2014-11-06T00:00:00", - "vesting_duration_seconds": 63072000, - "begin_balance": 50000000000 - },{ - "owner": "BTS5GHzWZ64Luoajqsz6JGjTKVMgWYkGV9SQ", - "asset_symbol": "BTS", - "amount": 50000000000, - "begin_timestamp": "2014-11-06T00:00:00", - "vesting_duration_seconds": 63072000, - "begin_balance": 50000000000 - },{ - "owner": "BTSDCVRFez92bW9doRLjnFCKLJnpM58mgmMb", - "asset_symbol": "BTS", - "amount": 50000000000, - "begin_timestamp": "2014-11-06T00:00:00", - "vesting_duration_seconds": 63072000, - "begin_balance": 50000000000 - },{ - "owner": "BTS5CCdX3JYLBptYMuCjbsezqGYzN9vG9JCu", - "asset_symbol": "BTS", - "amount": 50000000000, - "begin_timestamp": "2014-11-06T00:00:00", - "vesting_duration_seconds": 63072000, - "begin_balance": 50000000000 - },{ - "owner": "BTSEQ3yQdr3EMDL2eRqGiceMCpoanaW16Puw", - "asset_symbol": "BTS", - "amount": 50000000000, - "begin_timestamp": "2014-11-06T00:00:00", - "vesting_duration_seconds": 63072000, - "begin_balance": 50000000000 - },{ diff --git a/testnet-shared-witnesses.txt b/testnet-shared-witnesses.txt deleted file mode 100644 index c09b1329..00000000 --- a/testnet-shared-witnesses.txt +++ /dev/null @@ -1,304 +0,0 @@ - "initial_witness_candidates": [{ - "owner_name": "init0", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init1", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init2", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init3", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init4", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init5", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init6", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init7", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init8", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init9", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init10", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init11", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init12", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init13", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init14", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init15", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init16", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init17", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init18", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init19", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init20", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init21", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init22", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init23", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init24", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init25", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init26", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init27", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init28", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init29", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init30", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init31", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init32", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init33", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init34", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init35", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init36", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init37", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init38", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init39", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init40", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init41", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init42", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init43", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init44", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init45", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init46", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init47", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init48", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init49", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init50", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init51", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init52", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init53", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init54", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init55", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init56", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init57", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init58", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init59", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init60", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init61", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init62", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init63", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init64", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init65", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init66", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init67", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init68", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init69", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init70", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init71", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init72", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init73", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init74", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init75", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init76", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init77", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init78", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init79", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init80", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init81", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init82", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init83", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init84", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init85", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init86", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init87", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init88", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init89", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init90", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init91", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init92", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init93", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init94", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init95", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init96", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init97", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init98", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init99", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ - "owner_name": "init100", - "block_signing_key": "GPH6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - },{ From 5dea4b1770259ed3d4517dea97858b31fbbfad45 Mon Sep 17 00:00:00 2001 From: Nineseven Date: Tue, 27 Nov 2018 23:51:40 +0300 Subject: [PATCH 16/33] Submodule update --- docs | 2 +- libraries/fc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs b/docs index bd792d02..008cd676 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit bd792d02c70e7686da2b27197eba4fd6df30477c +Subproject commit 008cd676579efd28083e35eaff49b1b6437144d9 diff --git a/libraries/fc b/libraries/fc index 51688042..0468884e 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 51688042b0b9f99f03224f54fb937fe024fe5ced +Subproject commit 0468884ea675afe3a16ffc61371672fecf6e7dde From c4e2e2716ae8d269e9d806e589d28a9ebf329757 Mon Sep 17 00:00:00 2001 From: Nineseven Date: Thu, 29 Nov 2018 14:33:06 +0300 Subject: [PATCH 17/33] fc lib update --- libraries/fc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fc b/libraries/fc index 0468884e..51688042 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 0468884ea675afe3a16ffc61371672fecf6e7dde +Subproject commit 51688042b0b9f99f03224f54fb937fe024fe5ced From fae588e6f0a8b7f2bd870730b31660c2aeacb754 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Thu, 29 Nov 2018 16:29:15 +0300 Subject: [PATCH 18/33] cleanup code from comments --- libraries/chain/db_activenode_schedule.cpp | 9 --------- libraries/chain/db_maint.cpp | 1 - libraries/chain/db_update.cpp | 1 - libraries/chain/db_witness_schedule.cpp | 2 -- libraries/net/stcp_socket.cpp | 1 - libraries/plugins/activenode/activenode.cpp | 5 ----- .../plugins/elasticsearch/elasticsearch_plugin.cpp | 1 - .../plugins/market_history/market_history_plugin.cpp | 1 - libraries/plugins/witness/witness.cpp | 10 ---------- 9 files changed, 31 deletions(-) diff --git a/libraries/chain/db_activenode_schedule.cpp b/libraries/chain/db_activenode_schedule.cpp index 855be57c..b2638691 100644 --- a/libraries/chain/db_activenode_schedule.cpp +++ b/libraries/chain/db_activenode_schedule.cpp @@ -61,27 +61,18 @@ fc::time_point_sec database::get_activenode_slot_time(uint32_t slot_num)const int64_t head_block_abs_slot = head_block_time().sec_since_epoch() / interval; fc::time_point_sec head_slot_time(head_block_abs_slot * interval); - // ilog("!#dbg database::get_activenode_slot_time slot_num=${slot_num} head_block_abs_slot=${head_block_abs_slot} head_slot_time=${head_slot_time}, return_val=${return_val}", ("slot_num", slot_num)("head_block_abs_slot",head_block_abs_slot)("head_slot_time", head_slot_time)("return_val", head_slot_time + (slot_num * interval))); const global_property_object& gpo = get_global_properties(); if( dpo.dynamic_flags & dynamic_global_property_object::maintenance_flag ) slot_num += gpo.parameters.maintenance_skip_slots; - // "slot 0" is head_slot_time - // "slot 1" is head_slot_time, - // plus maint interval if head block is a maint block - // plus block interval if head block is not a maint block - // ilog("!ANODE get_activenode_slot_time head_block_time = ${hbt}, head_slot_time = ${hst}, hbt + slot*interval = ${hbtplus}", ("hbt", head_block_time().sec_since_epoch())("hst", head_slot_time.sec_since_epoch())("hbtplus", (head_slot_time + (slot_num * interval)).sec_since_epoch())); - - return head_slot_time + (slot_num * interval); } uint32_t database::get_activenode_slot_at_time(fc::time_point_sec when)const { fc::time_point_sec first_slot_time = get_activenode_slot_time( 0 ); - // ilog("!ANODE get_activenode_slot_at_time when = ${when}, first_slot_time = ${fst}", ("when", when.sec_since_epoch())("fst", first_slot_time.sec_since_epoch())); if( when < first_slot_time ) return 0; diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 462e0918..93d2bd4c 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -194,7 +194,6 @@ void database::pay_workers( share_type& budget ) } share_type actual_pay = std::min(budget, requested_pay); - //ilog(" ==> Paying ${a} to worker ${w}", ("w", active_worker.id)("a", actual_pay)); modify(active_worker, [&](worker_object& w) { w.worker.visit(worker_pay_visitor(actual_pay, *this)); }); diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index c1121d96..6616e712 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -119,7 +119,6 @@ void database::update_signing_witness(const witness_object& signing_witness, con bool enough_balance = (total_balance >= LLC_WITNESS_MINIMAL_BALANCE); if (enough_balance) { - ilog("update_signing_witness enough_balance"); share_type witness_pay = std::min( gpo.parameters.witness_pay_per_block, dpo.witness_budget ); modify( dpo, [&]( dynamic_global_property_object& _dpo ) diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index 0cf231af..b95392b2 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -68,7 +68,6 @@ fc::time_point_sec database::get_slot_time(uint32_t slot_num)const // "slot 1" is head_slot_time, // plus maint interval if head block is a maint block // plus block interval if head block is not a maint block - // ilog("!@#$ get_slot_time head_block_time = ${hbt}, head_slot_time = ${hst}, hbt + slot*interval = ${hbtplus}", ("hbt", head_block_time().sec_since_epoch())("hst", head_slot_time.sec_since_epoch())("hbtplus", (head_slot_time + (slot_num * interval)).sec_since_epoch())); return head_slot_time + (slot_num * interval); } @@ -76,7 +75,6 @@ fc::time_point_sec database::get_slot_time(uint32_t slot_num)const uint32_t database::get_slot_at_time(fc::time_point_sec when)const { fc::time_point_sec first_slot_time = get_slot_time( 1 ); - // ilog("!@#$ get_slot_at_time when = ${when}, first_slot_time = ${fst}", ("when", when.sec_since_epoch())("fst", first_slot_time.sec_since_epoch())); if( when < first_slot_time ) return 0; diff --git a/libraries/net/stcp_socket.cpp b/libraries/net/stcp_socket.cpp index 7a483f08..a7c6bf20 100644 --- a/libraries/net/stcp_socket.cpp +++ b/libraries/net/stcp_socket.cpp @@ -61,7 +61,6 @@ void stcp_socket::do_key_exchange() memcpy((char*)&rpub, serialized_key_buffer.get(), sizeof(fc::ecc::public_key_data)); _shared_secret = _priv_key.get_shared_secret( rpub ); -// ilog("shared secret ${s}", ("s", shared_secret) ); _send_aes.init( fc::sha256::hash( (char*)&_shared_secret, sizeof(_shared_secret) ), fc::city_hash_crc_128((char*)&_shared_secret,sizeof(_shared_secret) ) ); _recv_aes.init( fc::sha256::hash( (char*)&_shared_secret, sizeof(_shared_secret) ), diff --git a/libraries/plugins/activenode/activenode.cpp b/libraries/plugins/activenode/activenode.cpp index d9f2b4e5..3a2b2322 100644 --- a/libraries/plugins/activenode/activenode.cpp +++ b/libraries/plugins/activenode/activenode.cpp @@ -152,13 +152,11 @@ void activenode_plugin::schedule_activity_loop() //Schedule for the next second's tick regardless of chain state // If we would wait less than 50ms, wait for the whole second. fc::time_point now = fc::time_point::now(); - // ilog("!activenode_plugin::schedule_activity_loop now=${now}", ("now", now)); int64_t time_to_next_second = 1000000 - (now.time_since_epoch().count() % 1000000); if( time_to_next_second < 50000 ) // we must sleep for at least 50ms time_to_next_second += 1000000; fc::time_point next_wakeup( now + fc::microseconds( time_to_next_second ) ); - // ilog("!ANODE schedule_activity_loop now = ${now}, time_to_next_second = ${ttns}, nextwakeup = ${nwakeup}", ("now", now.time_since_epoch())("ttns", time_to_next_second)("nwakeup", next_wakeup.time_since_epoch())); _activity_task = fc::schedule([this]{activity_loop();}, next_wakeup, "Node activity transaction"); } @@ -237,7 +235,6 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt fc::time_point now_fine = fc::time_point::now(); fc::time_point_sec now = now_fine; - // ilog("!activenode_plugin::maybe_send_activity now_fine=${now_fine} now=${now}", ("now_fine", now_fine)("now", now)); // If the next send activity opportunity is in the present or future, we're synced. if( !_activenode_plugin_enabled ) @@ -253,9 +250,7 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt // is anyone scheduled to produce now or one second in the future? //always zero - // ilog("!ANODE maybe_send_activity now_fine = ${now_fine}, now = ${now}", ("now_fine", now_fine.time_since_epoch())("now", now.sec_since_epoch())); uint32_t slot = db.get_activenode_slot_at_time( now ); - // ilog("!ANODE maybe_send_activity slot = ${slot}", ("slot", slot)); if( slot == 0 ) { diff --git a/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp index 2398fc7b..98cba0e6 100644 --- a/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp +++ b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp @@ -317,7 +317,6 @@ void elasticsearch_plugin_impl::sendBulk(std::string _elasticsearch_node_url, bo curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &readBuffer_logs); curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1"); //curl_easy_setopt(curl, CURLOPT_VERBOSE, true); - //ilog("log here curl: ${output}", ("output", readBuffer_logs)); curl_easy_perform(curl); http_code = 0; diff --git a/libraries/plugins/market_history/market_history_plugin.cpp b/libraries/plugins/market_history/market_history_plugin.cpp index 3f3277e4..71248492 100644 --- a/libraries/plugins/market_history/market_history_plugin.cpp +++ b/libraries/plugins/market_history/market_history_plugin.cpp @@ -83,7 +83,6 @@ struct operation_process_fill_order void operator()( const fill_order_operation& o )const { - //ilog( "processing ${o}", ("o",o) ); auto& db = _plugin.database(); const auto& order_his_idx = db.get_index_type().indices(); const auto& history_idx = order_his_idx.get(); diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index 74579df7..78b9bdd5 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -146,7 +146,6 @@ void witness_plugin::schedule_production_loop() //Schedule for the next second's tick regardless of chain state // If we would wait less than 50ms, wait for the whole second. fc::time_point now = fc::time_point::now(); -// ilog("!witness_plugin::schedule_production_loop now=${now}", ("now", now)); //in microseconds int64_t time_to_next_second = 1000000 - (now.time_since_epoch().count() % 1000000); @@ -156,10 +155,6 @@ void witness_plugin::schedule_production_loop() fc::time_point next_wakeup( now + fc::microseconds( time_to_next_second ) ); - // ilog("!@#$ schedule_production_loop now = ${now}, time_to_next_second = ${ttns}, nextwakeup = ${nwakeup}", ("now", now.time_since_epoch())("ttns", time_to_next_second)("nwakeup", next_wakeup.time_since_epoch())); - -// ilog("!witness_plugin::schedule_production_loop next_wakeup=${next_wakeup}", ("next_wakeup", next_wakeup)); - _block_production_task = fc::schedule([this]{block_production_loop();}, next_wakeup, "Witness Block Production"); } @@ -221,7 +216,6 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb chain::database& db = database(); fc::time_point now_fine = fc::time_point::now(); fc::time_point_sec now = now_fine; -// ilog("!witness_plugin::maybe_produce_block now_fine=${now_fine} now=${now}", ("now_fine", now_fine)("now", now)); // If the next block production opportunity is in the present or future, we're synced. if( !_production_enabled ) @@ -233,11 +227,7 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb } // is anyone scheduled to produce now or one second in the future? - // ilog("!@#$ maybe_produce_block now_fine = ${now_fine}, now = ${now}", ("now_fine", now_fine.time_since_epoch())("now", now.sec_since_epoch())); uint32_t slot = db.get_slot_at_time( now ); - // ilog("!@#$ maybe_produce_block slot = ${slot}", ("slot", slot)); - -// ilog("!witness_plugin::maybe_produce_block slot=${slow} db.head_block_time()=${db_head_time}", ("slot", slot)("db_head_time", db.head_block_time())); if( slot == 0 ) { From 733f8ee7241397e61e9b9dace17ca6df6a3b3d4f Mon Sep 17 00:00:00 2001 From: "LocalCoin.is" <42545106+LocalCoinIS@users.noreply.github.com> Date: Fri, 30 Nov 2018 16:20:24 +0300 Subject: [PATCH 19/33] Update to 1500ms --- libraries/plugins/witness/witness.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index 78b9bdd5..1274c4fa 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -197,7 +197,7 @@ block_production_condition::block_production_condition_enum witness_plugin::bloc elog("Not producing block because node appears to be on a minority fork with only ${pct}% witness participation", (capture) ); break; case block_production_condition::lag: - elog("Not producing block because node didn't wake up within 500ms of the slot time."); + elog("Not producing block because node didn't wake up within 1500ms of the slot time."); break; case block_production_condition::consecutive: elog("Not producing block because the last block was generated by the same witness.\nThis node is probably disconnected from the network so block production has been disabled.\nDisable this check with --allow-consecutive option."); @@ -270,7 +270,7 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb return block_production_condition::low_participation; } - if( llabs((scheduled_time - now).count()) > fc::milliseconds( 500 ).count() ) + if( llabs((scheduled_time - now).count()) > fc::milliseconds( 1500 ).count() ) { capture("scheduled_time", scheduled_time)("now", now); return block_production_condition::lag; From 039b6434265980ca5f7e6c90e02e5bd7b8113a1d Mon Sep 17 00:00:00 2001 From: Nineseven Date: Fri, 30 Nov 2018 18:18:40 +0300 Subject: [PATCH 20/33] Update CMakeLists.txt --- CMakeLists.txt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba8d3643..11a00e6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,15 +102,9 @@ if( WIN32 ) SET(TCL_LIBS "${TCL_LIBS}${TCL_LIB_PATH}/${TCL_LIB_NAME}g${TCL_LIB_EXT}") SET(TCL_LIBRARY ${TCL_LIBS}) - add_definitions( -DCURL_STATICLIB ) - - SET(CURL_ROOT $ENV{PROGRAMFILES}/Curl) - SET(CURL_LIBRARY ${CURL_ROOT}/lib) - SET(CURL_INCLUDE_DIR ${CURL_ROOT}/include) - find_package( CURL ) - - include_directories( ${CURL_INCLUDE_DIRS} ) - link_directories( ${CURL_LIBRARIES} ) + find_package( CURL ) + include_directories( ${CURL_INCLUDE_DIRS} ) + link_directories( ${CURL_LIBRARIES} ) else( WIN32 ) # Apple AND Linux From 8626cf7c33fe02bec58fd583ebd2d5302ac31b48 Mon Sep 17 00:00:00 2001 From: Nineseven Date: Fri, 30 Nov 2018 18:47:06 +0300 Subject: [PATCH 21/33] add staticcurl --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11a00e6b..d84f3f32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,7 @@ if( WIN32 ) SET(TCL_LIBRARY ${TCL_LIBS}) find_package( CURL ) + set(CURL_STATICLIB ON) include_directories( ${CURL_INCLUDE_DIRS} ) link_directories( ${CURL_LIBRARIES} ) From 743e69b79031d9224ec3bdf1132ec5d83b1fc2df Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Wed, 12 Dec 2018 13:47:01 +0300 Subject: [PATCH 22/33] Add current_activenodes to global_property_object reflexion; fix activenode_send_activity_operation reflexion; make activenode plugin messages debug level --- .../include/graphene/chain/global_property_object.hpp | 1 + .../chain/include/graphene/chain/protocol/activenode.hpp | 2 +- libraries/plugins/activenode/activenode.cpp | 9 ++------- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index c9f3332d..abb1da9b 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -148,4 +148,5 @@ FC_REFLECT_DERIVED( graphene::chain::global_property_object, (graphene::db::obje (next_available_vote_id) (active_committee_members) (active_witnesses) + (current_activenodes) ) diff --git a/libraries/chain/include/graphene/chain/protocol/activenode.hpp b/libraries/chain/include/graphene/chain/protocol/activenode.hpp index 9b716637..5eb40de1 100644 --- a/libraries/chain/include/graphene/chain/protocol/activenode.hpp +++ b/libraries/chain/include/graphene/chain/protocol/activenode.hpp @@ -74,4 +74,4 @@ FC_REFLECT( graphene::chain::activenode_create_operation, (fee)(activenode_accou FC_REFLECT( graphene::chain::activenode_send_activity_operation::fee_parameters_type, (fee) ) -FC_REFLECT( graphene::chain::activenode_send_activity_operation, (fee)(activenode_account) ) +FC_REFLECT( graphene::chain::activenode_send_activity_operation, (fee)(activenode_account)(activenode)(timepoint)(endpoint) ) diff --git a/libraries/plugins/activenode/activenode.cpp b/libraries/plugins/activenode/activenode.cpp index 3a2b2322..1121aa83 100644 --- a/libraries/plugins/activenode/activenode.cpp +++ b/libraries/plugins/activenode/activenode.cpp @@ -212,7 +212,7 @@ activenode_condition::activenode_condition_enum activenode_plugin::activity_loop elog("Not sending activity because node didn't wake up within 500ms of the slot time. scheduled=${scheduled_time} now=${now}", (capture)); break; case activenode_condition::no_scheduled_activenodes: - ilog("No scheduled activenodes"); + dlog("No scheduled activenodes"); break; case activenode_condition::exception_perform_activity: elog( "exception sending activity" ); @@ -311,14 +311,9 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt tx.set_expiration( dyn_props.time + fc::seconds(30) ); tx.sign( _private_key.second, db.get_chain_id() ); - ilog("maybe_send_activity"); + dlog("maybe_send_activity"); app().chain_database()->push_transaction(tx); - // fc::async( [this, tx](){ - // if( app().p2p_node() != nullptr ) - // app().p2p_node()->broadcast_transaction(tx); - // } ); - capture("timestamp", now)("endpoint", endpoint)("activenode", *_activenode); return activenode_condition::performed_activity; From 9e4b039518682d8a278fe5aafad72bf6fb2e5f88 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Mon, 17 Dec 2018 13:53:47 +0300 Subject: [PATCH 23/33] vesting fixes. Now activenode gets reward each time for each block slot (even if witness missed block in that slot) --- libraries/chain/activenode_evaluator.cpp | 21 +++--- libraries/chain/db_maint.cpp | 3 - libraries/chain/db_update.cpp | 73 +++++++++++-------- .../graphene/chain/activenode_object.hpp | 7 +- .../chain/include/graphene/chain/database.hpp | 2 +- libraries/plugins/activenode/activenode.cpp | 7 +- 6 files changed, 66 insertions(+), 47 deletions(-) diff --git a/libraries/chain/activenode_evaluator.cpp b/libraries/chain/activenode_evaluator.cpp index 0b07f84b..8b34c342 100644 --- a/libraries/chain/activenode_evaluator.cpp +++ b/libraries/chain/activenode_evaluator.cpp @@ -41,7 +41,11 @@ void_result activenode_create_evaluator::do_evaluate( const activenode_create_op FC_ASSERT(d.get(op.activenode_account).is_lifetime_member()); share_type total_balance = d.get_total_account_balance(account_obj); - FC_ASSERT(total_balance >= LLC_ACTIVENODE_MINIMAL_BALANCE_CREATE); + FC_ASSERT(total_balance >= LLC_ACTIVENODE_MINIMAL_BALANCE_CREATE, "Insufficient Balance: ${a}'s balance of ${b} is less than minimal activenode balance required ${r}", + ("a",account_obj.name) + ("b",d.to_pretty_string(asset(total_balance))) + ("r",d.to_pretty_string(asset(LLC_ACTIVENODE_MINIMAL_BALANCE_CREATE)))); + return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -68,20 +72,17 @@ void_result activenode_activity_evaluator::do_evaluate( const activenode_send_ac void_result activenode_activity_evaluator::do_apply( const activenode_send_activity_operation& op ) { try { - - // DONT validate balance & remove - - // get timestamp from ... - fc::time_point now = fc::time_point::now(); - - // modify activenode with new data - database& _db = db(); _db.modify( _db.get(op.activenode), [&]( activenode_object& activenode_object ) { - activenode_object.last_activity = op.timepoint; + // if head_block_time == op.timepoint --> remove all old activities + if (_db.head_block_time() == fc::time_point_sec(op.timepoint)) { + activenode_object.activity_since_last_block.clear(); + } + + activenode_object.activity_since_last_block.push_back(op.timepoint); activenode_object.endpoint = op.endpoint; }); return void_result(); diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 93d2bd4c..1306da95 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -218,9 +218,6 @@ void database::update_current_activenodes() [](const activenode_object& anode) { return anode.id; }); - if (gp.current_activenodes.size() > 0) { - activenode_id_type aid = *(gp.current_activenodes.begin()); - } }); } FC_CAPTURE_AND_RETHROW() } diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 6616e712..8b42e816 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -38,6 +38,7 @@ #include #include +#include namespace graphene { namespace chain { @@ -107,9 +108,6 @@ void database::update_signing_witness(const witness_object& signing_witness, con const dynamic_global_property_object& dpo = get_dynamic_global_properties(); uint64_t new_block_aslot = dpo.current_aslot + get_slot_at_time( new_block.timestamp ); - const account_balance_index& balance_index = get_index_type(); - auto range = balance_index.indices().get().equal_range(boost::make_tuple(signing_witness.witness_account)); - auto& account = signing_witness.witness_account(*this); const auto& stats = account.statistics(*this); share_type total_balance = stats.total_core_in_orders.value @@ -158,18 +156,13 @@ void database::clean_poor_activenodes() { } } -const fc::optional database::validate_activenode(const signed_block& new_block) { - - // get all activenodes who sent activity this time from the block - // new_block.transactions. operations - //or get all activenodes from db with time >= block_head_time... - fc::optional activenode = optional< activenode_id_type >(); - +const vector database::validate_activenode(const signed_block& new_block) { + vector nodes_to_reward; if ( new_block.block_num() == 0 || new_block.block_num() == 1 //why we need it ??? ){ - return activenode; + return nodes_to_reward; // n.b. first block is at genesis_time plus one block interval // prev_block_time = dpo.time; // return genesis_time + slot_num * interval; @@ -178,34 +171,52 @@ const fc::optional database::validate_activenode(const signe optional prev_block = fetch_block_by_number(new_block.block_num() - 1); FC_ASSERT(prev_block); - fc::time_point_sec prev_block_time = prev_block->timestamp; - fc::time_point_sec new_block_time = new_block.timestamp; + fc::time_point prev_block_time = fc::time_point(prev_block->timestamp); const auto& idx = get_index_type().indices(); - // remove activenodes that doesn't have enough money + // removing activenodes that doesn't have enough money clean_poor_activenodes(); - uint32_t slot_num = get_activenode_slot_at_time( prev_block_time ); - //TODO: add processing of activenodes that has sent the activity on the slot without block (if/when witness misses the block) - fc::optional scheduled_activenode = get_scheduled_activenode( slot_num ); - for( const activenode_object& act_object : idx ) - { - if (act_object.last_activity == fc::time_point(prev_block_time)) { - int a = 0; - if ( act_object.id == object_id_type(*scheduled_activenode)) { - activenode = scheduled_activenode; + fc::time_point new_block_time = fc::time_point(new_block.timestamp); + for (fc::time_point tp = prev_block_time; tp < new_block_time; tp+=fc::seconds(1)) { + + + uint32_t slot_num = get_activenode_slot_at_time( tp ); + + fc::optional scheduled_activenode = get_scheduled_activenode( slot_num ); + + if (!scheduled_activenode) { + // no scheduled activenodes + continue; + } + + // dlog("validate_activenode: scheduled node ${scheduled_node} prev_block_time ${prev_block_time}", + // ("scheduled_node", *scheduled_activenode) + // ("prev_block_time", prev_block_time)); + + for( const activenode_object& act_object : idx ) + { + if (act_object.id != object_id_type(*scheduled_activenode)) + continue; + + auto activity_it = std::find(act_object.activity_since_last_block.begin(), + act_object.activity_since_last_block.end(), + tp); + if (activity_it != act_object.activity_since_last_block.end()) { + elog("nodes_to_reward push: for time ${time} ${act_id} was scheduled", ("time", tp)("act_id",act_object.id)); + + nodes_to_reward.push_back(act_object.id); break; } } } - return activenode; + return nodes_to_reward; } void database::reward_activenode(const signed_block& new_block) { const global_property_object& gpo = get_global_properties(); - const dynamic_global_property_object& dpo = get_dynamic_global_properties(); //get current_activenodes - if empty - return const auto& anodes = get_index_type().indices(); // check scheduled @@ -214,13 +225,17 @@ void database::reward_activenode(const signed_block& new_block) { if (aso.current_shuffled_activenodes.size() == 0) { return; } - auto& activenode_id = validate_activenode(new_block); - if (!activenode_id) { + vector activenodes_ids = validate_activenode(new_block); + if (activenodes_ids.empty()) { + ilog("no activenodes to reward"); return; } - auto& scheduled_activenode = (*activenode_id)(*this); + for (auto& an_id : activenodes_ids) { + auto& scheduled_activenode = an_id(*this); + ilog("deposit_activenode_pay ${an_id}", ("an_id", an_id)); - deposit_activenode_pay( scheduled_activenode, gpo.parameters.activenode_pay_per_block ); + deposit_activenode_pay( scheduled_activenode, gpo.parameters.activenode_pay_per_block ); + } } void database::update_last_irreversible_block() diff --git a/libraries/chain/include/graphene/chain/activenode_object.hpp b/libraries/chain/include/graphene/chain/activenode_object.hpp index 7f0c804a..ad6cc9f4 100644 --- a/libraries/chain/include/graphene/chain/activenode_object.hpp +++ b/libraries/chain/include/graphene/chain/activenode_object.hpp @@ -25,6 +25,8 @@ #include #include #include +#include + namespace graphene { namespace chain { using namespace graphene::db; @@ -37,7 +39,8 @@ namespace graphene { namespace chain { static const uint8_t type_id = activenode_object_type; account_id_type activenode_account; - fc::time_point last_activity; + vector activity_since_last_block; + // fc::time_point last_activity; fc::ip::endpoint endpoint; optional< vesting_balance_id_type > pay_vb; @@ -62,7 +65,7 @@ namespace graphene { namespace chain { FC_REFLECT_DERIVED( graphene::chain::activenode_object, (graphene::db::object), (activenode_account) - (last_activity) + (activity_since_last_block) (endpoint) (pay_vb) (is_enabled) diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index bb6080da..fbe8e4cd 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -493,7 +493,7 @@ namespace graphene { namespace chain { //////////////////// db_update.cpp //////////////////// void update_global_dynamic_data( const signed_block& b ); void update_signing_witness(const witness_object& signing_witness, const signed_block& new_block); - const optional validate_activenode(const signed_block& new_block); + const vector validate_activenode(const signed_block& new_block); void clean_poor_activenodes(); void reward_activenode(const signed_block& new_block); void update_last_irreversible_block(); diff --git a/libraries/plugins/activenode/activenode.cpp b/libraries/plugins/activenode/activenode.cpp index 1121aa83..54994336 100644 --- a/libraries/plugins/activenode/activenode.cpp +++ b/libraries/plugins/activenode/activenode.cpp @@ -67,8 +67,6 @@ void activenode_plugin::plugin_initialize(const boost::program_options::variable { try { ilog("activenode plugin: plugin_initialize() begin"); _options = &options; - chain::database& db = database(); - if (options.count("activenode-account")) { _activenode_account_name = options["activenode-account"].as(); } else { @@ -290,6 +288,11 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt graphene::net::firewalled_state node_firewalled_state; fc::from_variant(network_info["firewalled"], node_firewalled_state, 1); FC_ASSERT(endpoint.get_address().is_public_address() && node_firewalled_state != graphene::net::firewalled_state::firewalled); + // FC_ASSERT(endpoint.get_address().is_public_address()); + if (!endpoint.get_address().is_public_address()) + elog("ERROR: node's ip is local ${endpoint}", ("endpoint", endpoint.get_address())); + if (node_firewalled_state == graphene::net::firewalled_state::firewalled) + elog("ERROR: node is firewalled ${endpoint}", ("endpoint", endpoint.get_address())); chain::activenode_send_activity_operation send_activity_operation; now = fc::time_point::now(); From d9b8acf672b977a9050b69037bb4a370e18b5c51 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Mon, 24 Dec 2018 21:48:02 +0300 Subject: [PATCH 24/33] Activenode fixes --- libraries/app/application.cpp | 3 + libraries/chain/activenode_evaluator.cpp | 7 +- libraries/chain/db_activenode_schedule.cpp | 72 +++---- libraries/chain/db_block.cpp | 5 +- libraries/chain/db_maint.cpp | 1 + libraries/chain/db_notify.cpp | 5 + libraries/chain/db_update.cpp | 90 ++------- .../graphene/chain/activenode_object.hpp | 5 +- .../chain/include/graphene/chain/database.hpp | 44 +---- .../graphene/chain/global_property_object.hpp | 3 + .../graphene/chain/protocol/activenode.hpp | 2 +- libraries/plugins/activenode/activenode.cpp | 175 ++++++------------ .../graphene/activenode/activenode.hpp | 8 +- libraries/plugins/witness/witness.cpp | 6 +- 14 files changed, 134 insertions(+), 292 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index a226e111..5d3ff516 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -501,6 +501,9 @@ bool application_impl::handle_block(const graphene::net::block_message& blk_msg, // the block was accepted, so we now know all of the transactions contained in the block if (!sync_mode) { + _chain_db->notify_new_block_applied( blk_msg.block ); //emit + + // if we're not in sync mode, there's a chance we will be seeing some transactions // included in blocks before we see the free-floating transaction itself. If that // happens, there's no reason to fetch the transactions, so construct a list of the diff --git a/libraries/chain/activenode_evaluator.cpp b/libraries/chain/activenode_evaluator.cpp index 8b34c342..ead0c6a2 100644 --- a/libraries/chain/activenode_evaluator.cpp +++ b/libraries/chain/activenode_evaluator.cpp @@ -77,12 +77,7 @@ void_result activenode_activity_evaluator::do_apply( const activenode_send_activ _db.get(op.activenode), [&]( activenode_object& activenode_object ) { - // if head_block_time == op.timepoint --> remove all old activities - if (_db.head_block_time() == fc::time_point_sec(op.timepoint)) { - activenode_object.activity_since_last_block.clear(); - } - - activenode_object.activity_since_last_block.push_back(op.timepoint); + activenode_object.last_activity = op.timepoint; activenode_object.endpoint = op.endpoint; }); return void_result(); diff --git a/libraries/chain/db_activenode_schedule.cpp b/libraries/chain/db_activenode_schedule.cpp index b2638691..0ce0c6bf 100644 --- a/libraries/chain/db_activenode_schedule.cpp +++ b/libraries/chain/db_activenode_schedule.cpp @@ -31,71 +31,41 @@ namespace graphene { namespace chain { using boost::container::flat_set; -fc::optional database::get_scheduled_activenode( uint32_t slot_num )const + +fc::optional database::get_scheduled_activenode(uint32_t block_num)const { + fc::optional scheduled_node(); + const global_property_object& gpo = get_global_properties(); const dynamic_global_property_object& dpo = get_dynamic_global_properties(); const activenode_schedule_object& aso = activenode_schedule_id_type()(*this); - uint64_t current_aslot = dpo.current_aslot + slot_num; - - if (aso.current_shuffled_activenodes.size() == 0) { + if (head_block_num() == 0) { //GENESIS return fc::optional(); } + if (aso.current_shuffled_activenodes.size() == 0) + return fc::optional(); - return aso.current_shuffled_activenodes[ current_aslot % aso.current_shuffled_activenodes.size() ]; -} - -fc::time_point_sec database::get_activenode_slot_time(uint32_t slot_num)const -{ - if( slot_num == 0 ) - return fc::time_point_sec(); - //TODO: if head_block used - maybe we don't need it - auto interval = block_interval(); - const dynamic_global_property_object& dpo = get_dynamic_global_properties(); - - if( head_block_num() == 0 ) - { - // n.b. first block is at genesis_time plus one block interval - fc::time_point_sec genesis_time = dpo.time; - return genesis_time + slot_num * interval; - } - - int64_t head_block_abs_slot = head_block_time().sec_since_epoch() / interval; - fc::time_point_sec head_slot_time(head_block_abs_slot * interval); - - const global_property_object& gpo = get_global_properties(); - - if( dpo.dynamic_flags & dynamic_global_property_object::maintenance_flag ) - slot_num += gpo.parameters.maintenance_skip_slots; - - return head_slot_time + (slot_num * interval); -} - -uint32_t database::get_activenode_slot_at_time(fc::time_point_sec when)const -{ - fc::time_point_sec first_slot_time = get_activenode_slot_time( 0 ); - - if( when < first_slot_time ) - return 0; - return (when - first_slot_time).to_seconds() / block_interval() + 1; + FC_ASSERT(block_num == head_block_num() || block_num == head_block_num() - 1); + return aso.current_shuffled_activenodes[block_num - dpo.last_scheduling_block_num]; } void database::update_activenode_schedule() { - const activenode_schedule_object& wso = activenode_schedule_id_type()(*this); + const activenode_schedule_object& aso = activenode_schedule_id_type()(*this); const global_property_object& gpo = get_global_properties(); + const dynamic_global_property_object& dpo = get_dynamic_global_properties(); if( gpo.current_activenodes.size() != 0 && head_block_num() % gpo.current_activenodes.size() == 0 ) { - modify( wso, [&]( activenode_schedule_object& _wso ) + modify( aso, [&]( activenode_schedule_object& _aso ) { - _wso.current_shuffled_activenodes.clear(); - _wso.current_shuffled_activenodes.reserve( gpo.current_activenodes.size() ); + _aso.current_shuffled_activenodes.clear(); + _aso.current_shuffled_activenodes.reserve( gpo.current_activenodes.size() ); for( const activenode_id_type& w : gpo.current_activenodes ) - _wso.current_shuffled_activenodes.push_back( w ); + _aso.current_shuffled_activenodes.push_back( w ); auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32; - for( uint32_t i = 0; i < _wso.current_shuffled_activenodes.size(); ++i ) + for( uint32_t i = 0; i < _aso.current_shuffled_activenodes.size(); ++i ) { /// High performance random generator /// http://xorshift.di.unimi.it/ @@ -105,12 +75,16 @@ void database::update_activenode_schedule() k ^= (k >> 27); k *= 2685821657736338717ULL; - uint32_t jmax = _wso.current_shuffled_activenodes.size() - i; + uint32_t jmax = _aso.current_shuffled_activenodes.size() - i; uint32_t j = i + k%jmax; - std::swap( _wso.current_shuffled_activenodes[i], - _wso.current_shuffled_activenodes[j] ); + std::swap( _aso.current_shuffled_activenodes[i], + _aso.current_shuffled_activenodes[j] ); } }); + modify( dpo, [&]( dynamic_global_property_object& _dpo ) + { + _dpo.last_scheduling_block_num = head_block_num(); + } ); } } diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 86ca25f4..0a1fadce 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -513,9 +513,11 @@ void database::_apply_block( const signed_block& next_block ) apply_transaction( trx, skip ); ++_current_trx_in_block; } - reward_activenode(next_block); update_global_dynamic_data(next_block); + + reward_activenode(next_block); + update_signing_witness(signing_witness, next_block); update_last_irreversible_block(); @@ -538,6 +540,7 @@ void database::_apply_block( const signed_block& next_block ) update_maintenance_flag( maint_needed ); update_witness_schedule(); update_activenode_schedule(); + clean_poor_activenodes(); if( !_node_property_object.debug_updates.empty() ) apply_debug_updates(); diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 1306da95..d980ff9b 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -836,6 +836,7 @@ void database::process_bids( const asset_bitasset_data_object& bad ) void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props) { + dlog("chain_maintenance"); const auto& gpo = get_global_properties(); distribute_fba_balances(*this); diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 090883e6..c022ae33 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -379,6 +379,11 @@ void database::notify_applied_block( const signed_block& block ) GRAPHENE_TRY_NOTIFY( applied_block, block ) } +void database::notify_new_block_applied( const signed_block& block ) +{ + GRAPHENE_TRY_NOTIFY( new_block_applied, block ) +} + void database::notify_on_pending_transaction( const signed_transaction& tx ) { GRAPHENE_TRY_NOTIFY( on_pending_transaction, tx ) diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 8b42e816..18447a99 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -148,93 +148,41 @@ void database::clean_poor_activenodes() { std::vector list_for_removal; for( const activenode_object& act_object : idx ) { - - //removing activenodes that doesn't have money + //removing activenodes that doesn't have money share_type total_balance = get_total_account_balance(act_object.activenode_account(*this)); - if (total_balance < LLC_ACTIVENODE_MINIMAL_BALANCE_AFTER_SEND) + if (total_balance < LLC_ACTIVENODE_MINIMAL_BALANCE_AFTER_SEND) { + dlog("activenode ${node} was deleted", ("node", act_object.id)); remove(act_object); - } -} - -const vector database::validate_activenode(const signed_block& new_block) { - vector nodes_to_reward; - if ( - new_block.block_num() == 0 - || new_block.block_num() == 1 //why we need it ??? - ){ - return nodes_to_reward; - // n.b. first block is at genesis_time plus one block interval - // prev_block_time = dpo.time; - // return genesis_time + slot_num * interval; - } - - optional prev_block = fetch_block_by_number(new_block.block_num() - 1); - - FC_ASSERT(prev_block); - fc::time_point prev_block_time = fc::time_point(prev_block->timestamp); - const auto& idx = get_index_type().indices(); - - // removing activenodes that doesn't have enough money - clean_poor_activenodes(); - - - fc::time_point new_block_time = fc::time_point(new_block.timestamp); - for (fc::time_point tp = prev_block_time; tp < new_block_time; tp+=fc::seconds(1)) { - - - uint32_t slot_num = get_activenode_slot_at_time( tp ); - - fc::optional scheduled_activenode = get_scheduled_activenode( slot_num ); - - if (!scheduled_activenode) { - // no scheduled activenodes - continue; - } - - // dlog("validate_activenode: scheduled node ${scheduled_node} prev_block_time ${prev_block_time}", - // ("scheduled_node", *scheduled_activenode) - // ("prev_block_time", prev_block_time)); - - for( const activenode_object& act_object : idx ) - { - if (act_object.id != object_id_type(*scheduled_activenode)) - continue; - - auto activity_it = std::find(act_object.activity_since_last_block.begin(), - act_object.activity_since_last_block.end(), - tp); - if (activity_it != act_object.activity_since_last_block.end()) { - elog("nodes_to_reward push: for time ${time} ${act_id} was scheduled", ("time", tp)("act_id",act_object.id)); - - nodes_to_reward.push_back(act_object.id); - break; - } } } - - return nodes_to_reward; } + void database::reward_activenode(const signed_block& new_block) { const global_property_object& gpo = get_global_properties(); - //get current_activenodes - if empty - return const auto& anodes = get_index_type().indices(); + // check scheduled if (anodes.size() == 0) return; + if (head_block_num() == 0 || head_block_num() == 1) return; //GENESIS + const activenode_schedule_object& aso = activenode_schedule_id_type()(*this); if (aso.current_shuffled_activenodes.size() == 0) { return; } - vector activenodes_ids = validate_activenode(new_block); - if (activenodes_ids.empty()) { - ilog("no activenodes to reward"); - return; - } - for (auto& an_id : activenodes_ids) { - auto& scheduled_activenode = an_id(*this); - ilog("deposit_activenode_pay ${an_id}", ("an_id", an_id)); + fc::optional scheduled_activenode = get_scheduled_activenode(head_block_num() - 1); + if (!scheduled_activenode) + return; - deposit_activenode_pay( scheduled_activenode, gpo.parameters.activenode_pay_per_block ); + if (find(*scheduled_activenode) == nullptr ) { + // was deleted + return; + } + auto& activenode_object = (*scheduled_activenode)(*this); + signed_block prev_block = *fetch_block_by_number(new_block.block_num() - 1); + fc::time_point_sec prev_block_time = prev_block.timestamp; + if (activenode_object.last_activity == prev_block_time) { + deposit_activenode_pay( activenode_object, gpo.parameters.activenode_pay_per_block ); } } diff --git a/libraries/chain/include/graphene/chain/activenode_object.hpp b/libraries/chain/include/graphene/chain/activenode_object.hpp index ad6cc9f4..55395e68 100644 --- a/libraries/chain/include/graphene/chain/activenode_object.hpp +++ b/libraries/chain/include/graphene/chain/activenode_object.hpp @@ -39,8 +39,7 @@ namespace graphene { namespace chain { static const uint8_t type_id = activenode_object_type; account_id_type activenode_account; - vector activity_since_last_block; - // fc::time_point last_activity; + fc::time_point_sec last_activity; fc::ip::endpoint endpoint; optional< vesting_balance_id_type > pay_vb; @@ -65,7 +64,7 @@ namespace graphene { namespace chain { FC_REFLECT_DERIVED( graphene::chain::activenode_object, (graphene::db::object), (activenode_account) - (activity_since_last_block) + (last_activity) (endpoint) (pay_vb) (is_enabled) diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index fbe8e4cd..66c7b4bc 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -185,6 +185,10 @@ namespace graphene { namespace chain { */ fc::signal applied_block; + /** + */ + fc::signal new_block_applied; + /** * This signal is emitted any time a new transaction is added to the pending * block state. @@ -249,42 +253,7 @@ namespace graphene { namespace chain { void update_witness_schedule(); //////////////////// db_activenode_schedule.cpp //////////////////// - - /** - * @brief Get the activenode scheduled for sending activity in a slot. - * - * slot_num always corresponds to a time in the future. - * - * If slot_num == 1, returns the next scheduled activenode. - * If slot_num == 2, returns the next scheduled activenode after - * 1 block gap. - * - * Use the get_slot_time() and get_slot_at_time() functions - * to convert between slot_num and timestamp. - * - * Passing slot_num == 0 returns GRAPHENE_NULL_ACTIVENODE - */ - fc::optional get_scheduled_activenode(uint32_t slot_num)const; - - /** - * Get the time at which the given slot occurs. - * - * If slot_num == 0, return time_point_sec(). - * - * If slot_num == N for N > 0, return the Nth next - * block-interval-aligned time greater than head_block_time(). - */ - fc::time_point_sec get_activenode_slot_time(uint32_t slot_num)const; - - /** - * Get the last slot which occurs AT or BEFORE the given time. - * - * The return value is the greatest value N such that - * get_slot_time( N ) <= when. - * - * If no such N exists, return 0. - */ - uint32_t get_activenode_slot_at_time(fc::time_point_sec when)const; + fc::optional get_scheduled_activenode(uint32_t block_num)const; void update_activenode_schedule(); @@ -449,6 +418,8 @@ namespace graphene { namespace chain { * can be reapplied at the proper time */ std::deque< signed_transaction > _popped_tx; + void notify_new_block_applied( const signed_block& block ); + /** * @} */ @@ -493,7 +464,6 @@ namespace graphene { namespace chain { //////////////////// db_update.cpp //////////////////// void update_global_dynamic_data( const signed_block& b ); void update_signing_witness(const witness_object& signing_witness, const signed_block& new_block); - const vector validate_activenode(const signed_block& new_block); void clean_poor_activenodes(); void reward_activenode(const signed_block& new_block); void update_last_irreversible_block(); diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index abb1da9b..d677372e 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -110,6 +110,8 @@ namespace graphene { namespace chain { uint32_t last_irreversible_block_num = 0; + uint32_t last_scheduling_block_num = 0; + enum dynamic_flag_bits { /** @@ -140,6 +142,7 @@ FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene:: (recent_slots_filled) (dynamic_flags) (last_irreversible_block_num) + (last_scheduling_block_num) ) FC_REFLECT_DERIVED( graphene::chain::global_property_object, (graphene::db::object), diff --git a/libraries/chain/include/graphene/chain/protocol/activenode.hpp b/libraries/chain/include/graphene/chain/protocol/activenode.hpp index 5eb40de1..d1d19057 100644 --- a/libraries/chain/include/graphene/chain/protocol/activenode.hpp +++ b/libraries/chain/include/graphene/chain/protocol/activenode.hpp @@ -60,7 +60,7 @@ namespace graphene { namespace chain { /// The account which owns the activenode. This account pays the fee for this operation. account_id_type activenode_account; activenode_id_type activenode; - fc::time_point timepoint; + fc::time_point_sec timepoint; fc::ip::endpoint endpoint; account_id_type fee_payer()const { return activenode_account; } diff --git a/libraries/plugins/activenode/activenode.cpp b/libraries/plugins/activenode/activenode.cpp index 54994336..87da5220 100644 --- a/libraries/plugins/activenode/activenode.cpp +++ b/libraries/plugins/activenode/activenode.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,6 @@ #include #include - using namespace graphene::activenode_plugin; using std::string; using std::vector; @@ -108,35 +108,12 @@ void activenode_plugin::plugin_startup() const auto& account_idx = db.get_index_type().indices().get(); const auto anode_account_itr = account_idx.find(_activenode_account_name); if (anode_account_itr != account_idx.end()) { - // get activenode from account - const auto& anode_idx = db.get_index_type().indices().get(); - const account_object& acc_obj = *anode_account_itr; - const auto& anode_itr = anode_idx.find(acc_obj.id); - if (anode_itr != anode_idx.end()) { - _activenode = anode_itr->id; - } else { - database().new_objects.connect([&]( const vector& ids, const flat_set& impacted_accounts ){ - const auto impacted_account = impacted_accounts.find(acc_obj.id); - if (impacted_account != impacted_accounts.end()) { - // check if we have corresponding activenode - const auto& anode_idx = db.get_index_type().indices().get(); - const auto& acc_obj = *impacted_account; - const auto& anode_itr = anode_idx.find(acc_obj); - if (anode_itr != anode_idx.end() && std::find(ids.begin(), ids.end(), anode_itr->id) != ids.end()) { - _activenode = anode_itr->id; - schedule_activity_loop(); - } - } - }); - ilog("Account ${acc} is not a registered activenode, can't start sending activity", ("acc", _activenode_account_name)); - } + _activenode_account_id = anode_account_itr->id; + db.new_block_applied.connect( [&]( const signed_block& b){ on_new_block_applied(b); } ); + } + else { + elog("activenode plugin: invalid activenode-account provided - no activenode associated with account with name ${activenode_account}", ("activenode_account", _activenode_account_name)); } - if (_activenode) - { - ilog("Launching activity for an activenodes."); - schedule_activity_loop(); - } else - elog("No activenodes configured! Please add activenode account and private key to configuration or register an activenode"); ilog("activenode plugin: plugin_startup() end"); } FC_CAPTURE_AND_RETHROW() } @@ -145,38 +122,43 @@ void activenode_plugin::plugin_shutdown() // nothing to do } -void activenode_plugin::schedule_activity_loop() +void activenode_plugin::on_new_block_applied(const signed_block& new_block) { - //Schedule for the next second's tick regardless of chain state - // If we would wait less than 50ms, wait for the whole second. - fc::time_point now = fc::time_point::now(); - int64_t time_to_next_second = 1000000 - (now.time_since_epoch().count() % 1000000); - if( time_to_next_second < 50000 ) // we must sleep for at least 50ms - time_to_next_second += 1000000; + chain::database& db = database(); - fc::time_point next_wakeup( now + fc::microseconds( time_to_next_second ) ); - _activity_task = fc::schedule([this]{activity_loop();}, - next_wakeup, "Node activity transaction"); -} + // check if still exists + if (_activenode){ + if ( db.find(*_activenode) == nullptr ) { + ilog("RESET DELETED ACTIVENODE"); + _activenode.reset(); + } + } -activenode_condition::activenode_condition_enum activenode_plugin::activity_loop() -{ - activenode_condition::activenode_condition_enum result; + if (!_activenode) { + // get activenode from account + const auto& anode_idx = db.get_index_type().indices().get(); + const auto& anode_itr = anode_idx.find(_activenode_account_id); + if (anode_itr != anode_idx.end()) { + _activenode = anode_itr->id; + } + else { + // didn't find any node for account + return; + } + } + + // if we are scheduled - send activity + + fc::optional scheduled_activenode = db.get_scheduled_activenode(db.head_block_num()); fc::limited_mutable_variant_object capture( GRAPHENE_MAX_NESTED_OBJECTS ); + activenode_condition::activenode_condition_enum result; + + if (_activenode != scheduled_activenode) + return; + try { - chain::database& db = database(); - - auto maybe_found = db.find(*_activenode); - if ( maybe_found == nullptr ) { - _activenode.reset(); - result = activenode_condition::deleted; - } else { - if ((*_activenode)(db).is_enabled) - result = maybe_send_activity(capture); - else - result = activenode_condition::exception_perform_activity; - } + result = send_activity(capture); } catch( const fc::canceled_exception& ) { @@ -188,7 +170,6 @@ activenode_condition::activenode_condition_enum activenode_plugin::activity_loop elog("Got exception while sending activity:\n${e}", ("e", e.to_detail_string())); result = activenode_condition::exception_perform_activity; } - switch( result ) { case activenode_condition::performed_activity: @@ -200,7 +181,7 @@ activenode_condition::activenode_condition_enum activenode_plugin::activity_loop case activenode_condition::not_my_turn: break; case activenode_condition::deleted: - return result; + return; case activenode_condition::not_time_yet: break; case activenode_condition::no_private_key: @@ -212,90 +193,39 @@ activenode_condition::activenode_condition_enum activenode_plugin::activity_loop case activenode_condition::no_scheduled_activenodes: dlog("No scheduled activenodes"); break; + case activenode_condition::not_sending: + break; case activenode_condition::exception_perform_activity: elog( "exception sending activity" ); break; } - schedule_activity_loop(); - return result; } -//todo complete rewrite activenode_condition::activenode_condition_enum -activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capture ) +activenode_plugin::send_activity( fc::limited_mutable_variant_object& capture ) { chain::database& db = database(); const dynamic_global_property_object& dpo = db.get_dynamic_global_properties(); - if( dpo.dynamic_flags & dynamic_global_property_object::maintenance_flag ) - return activenode_condition::not_time_yet; - - fc::time_point now_fine = fc::time_point::now(); - fc::time_point_sec now = now_fine; - - // If the next send activity opportunity is in the present or future, we're synced. - if( !_activenode_plugin_enabled ) - { - // TODO: check if it is okay???!?!??! - // need special slots for sending activity - if( db.get_activenode_slot_time(1) >= now ) - _activenode_plugin_enabled = true; - else - return activenode_condition::not_synced; - } - - // is anyone scheduled to produce now or one second in the future? - - //always zero - uint32_t slot = db.get_activenode_slot_at_time( now ); - - if( slot == 0 ) - { - capture("next_time", db.get_activenode_slot_time(1)); - return activenode_condition::not_time_yet; - } - // - // this assert should not fail, because now <= db.head_block_time() - // should have resulted in slot == 0. - // - // if this assert triggers, there is a serious bug in get_slot_at_time() - // which would result in allowing a later block to have a timestamp - // less than or equal to the previous block - // - - fc::optional scheduled_activenode = db.get_scheduled_activenode( slot ); - if (!scheduled_activenode) { - return activenode_condition::no_scheduled_activenodes; - } - if( *scheduled_activenode != *_activenode ) - { - capture("scheduled_activenode", *scheduled_activenode); - return activenode_condition::not_my_turn; - } - - fc::time_point_sec scheduled_time = db.get_slot_time( slot ); - // TODO: check if we need to change it - // if( llabs((scheduled_time - now).count()) > fc::milliseconds( 500 ).count() ) - // { - // capture("scheduled_time", scheduled_time)("now", now); - // return activenode_condition::lag; - // } - fc::variant_object network_info = app().p2p_node()->network_get_info(); fc::ip::endpoint endpoint = fc::ip::endpoint::from_string(network_info["listening_on"].as_string()); graphene::net::firewalled_state node_firewalled_state; fc::from_variant(network_info["firewalled"], node_firewalled_state, 1); - FC_ASSERT(endpoint.get_address().is_public_address() && node_firewalled_state != graphene::net::firewalled_state::firewalled); - // FC_ASSERT(endpoint.get_address().is_public_address()); - if (!endpoint.get_address().is_public_address()) + + if (!endpoint.get_address().is_public_address() || endpoint.get_address() == fc::ip::address("127.0.0.1")) { elog("ERROR: node's ip is local ${endpoint}", ("endpoint", endpoint.get_address())); - if (node_firewalled_state == graphene::net::firewalled_state::firewalled) + return activenode_condition::not_sending; + } + + if (node_firewalled_state == graphene::net::firewalled_state::firewalled) { elog("ERROR: node is firewalled ${endpoint}", ("endpoint", endpoint.get_address())); + return activenode_condition::not_sending; + } chain::activenode_send_activity_operation send_activity_operation; - now = fc::time_point::now(); + fc::time_point_sec now = fc::time_point::now(); send_activity_operation.timepoint = now; send_activity_operation.endpoint = endpoint; send_activity_operation.activenode = *_activenode; @@ -314,10 +244,11 @@ activenode_plugin::maybe_send_activity( fc::limited_mutable_variant_object& capt tx.set_expiration( dyn_props.time + fc::seconds(30) ); tx.sign( _private_key.second, db.get_chain_id() ); - dlog("maybe_send_activity"); app().chain_database()->push_transaction(tx); + if( app().p2p_node() != nullptr ) + app().p2p_node()->broadcast_transaction(tx); capture("timestamp", now)("endpoint", endpoint)("activenode", *_activenode); return activenode_condition::performed_activity; -} +} \ No newline at end of file diff --git a/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp b/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp index 159067b5..77355e54 100644 --- a/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp +++ b/libraries/plugins/activenode/include/graphene/activenode/activenode.hpp @@ -44,7 +44,8 @@ namespace activenode_condition lag = 5, no_scheduled_activenodes = 6, deleted = 7, - exception_perform_activity = 8 + not_sending = 8, + exception_perform_activity = 9 }; } @@ -76,15 +77,20 @@ class activenode_plugin : public graphene::app::plugin { private: void schedule_activity_loop(); + void on_new_block_applied(const signed_block& new_block); + activenode_condition::activenode_condition_enum activity_loop(); activenode_condition::activenode_condition_enum maybe_send_activity( fc::limited_mutable_variant_object& capture ); + activenode_condition::activenode_condition_enum send_activity( fc::limited_mutable_variant_object& capture ); + boost::program_options::variables_map _options; bool _activenode_plugin_enabled = true; std::pair _private_key; optional _activenode = optional(); std::string _activenode_account_name; + chain::account_id_type _activenode_account_id; fc::future _activity_task; }; diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index 1274c4fa..557bb4be 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -283,7 +283,11 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb _production_skip_flags ); capture("n", block.block_num())("t", block.timestamp)("c", now); - fc::async( [this,block](){ p2p_node().broadcast(net::block_message(block)); } ); + fc::async( [this,block](){ + p2p_node().broadcast(net::block_message(block)); + database().notify_new_block_applied( block ); //emit + + } ); return block_production_condition::produced; } From c59c4f7c15ef8ecb5c4ac936849229f549e702fa Mon Sep 17 00:00:00 2001 From: Nineseven Date: Wed, 26 Dec 2018 13:07:40 +0300 Subject: [PATCH 25/33] cmake update --- CMakeLists.txt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba8d3643..3f725ced 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,13 +102,8 @@ if( WIN32 ) SET(TCL_LIBS "${TCL_LIBS}${TCL_LIB_PATH}/${TCL_LIB_NAME}g${TCL_LIB_EXT}") SET(TCL_LIBRARY ${TCL_LIBS}) - add_definitions( -DCURL_STATICLIB ) - - SET(CURL_ROOT $ENV{PROGRAMFILES}/Curl) - SET(CURL_LIBRARY ${CURL_ROOT}/lib) - SET(CURL_INCLUDE_DIR ${CURL_ROOT}/include) find_package( CURL ) - + set(CURL_STATICLIB ON) include_directories( ${CURL_INCLUDE_DIRS} ) link_directories( ${CURL_LIBRARIES} ) From bbae4ae4efbfaece57dc297769d5221884cdb086 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Thu, 27 Dec 2018 17:02:34 +0300 Subject: [PATCH 26/33] Enable default activenode; calculate activenode balance intelligently --- genesis.json | 2 +- libraries/app/application.cpp | 1 + libraries/chain/db_update.cpp | 7 ++++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/genesis.json b/genesis.json index e0a7a6bf..edee7b20 100644 --- a/genesis.json +++ b/genesis.json @@ -279,7 +279,7 @@ "cashback_vesting_threshold": 10000000, "count_non_member_votes": true, "allow_non_member_whitelists": false, - "activenode_pay_per_block": 110000, + "activenode_pay_per_block": 6500, "witness_pay_per_block": 65000, "worker_budget_per_day": "30000000000", "max_predicate_opcode": 1, diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 5d3ff516..1fec3e0d 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -979,6 +979,7 @@ void application::initialize(const fc::path& data_dir, const boost::program_opti else { wanted.push_back("witness"); + wanted.push_back("activenode"); wanted.push_back("account_history"); wanted.push_back("market_history"); wanted.push_back("grouped_orders"); diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 18447a99..ca838818 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -182,7 +182,12 @@ void database::reward_activenode(const signed_block& new_block) { signed_block prev_block = *fetch_block_by_number(new_block.block_num() - 1); fc::time_point_sec prev_block_time = prev_block.timestamp; if (activenode_object.last_activity == prev_block_time) { - deposit_activenode_pay( activenode_object, gpo.parameters.activenode_pay_per_block ); + + chain::activenode_send_activity_operation send_activity_operation; + + share_type fee = current_fee_schedule().calculate_fee( send_activity_operation ).amount; + share_type to_deposit = fee.value * 0.2 + gpo.parameters.activenode_pay_per_block; + deposit_activenode_pay( activenode_object, to_deposit ); } } From 4287c6c12262ad2d2f693ab56fa3757d148b6607 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Fri, 4 Jan 2019 18:28:48 +0300 Subject: [PATCH 27/33] make activenodes that miss inactive --- libraries/chain/db_activenode_schedule.cpp | 4 +- libraries/chain/db_maint.cpp | 115 +++++++++++++++++- libraries/chain/db_update.cpp | 10 +- .../graphene/chain/activenode_object.hpp | 6 + .../chain/include/graphene/chain/config.hpp | 1 + .../chain/include/graphene/chain/database.hpp | 3 + .../graphene/chain/global_property_object.hpp | 5 +- libraries/plugins/activenode/activenode.cpp | 24 ++-- 8 files changed, 147 insertions(+), 21 deletions(-) diff --git a/libraries/chain/db_activenode_schedule.cpp b/libraries/chain/db_activenode_schedule.cpp index 0ce0c6bf..df9fa75b 100644 --- a/libraries/chain/db_activenode_schedule.cpp +++ b/libraries/chain/db_activenode_schedule.cpp @@ -45,7 +45,7 @@ fc::optional database::get_scheduled_activenode(uint32_t blo return fc::optional(); FC_ASSERT(block_num == head_block_num() || block_num == head_block_num() - 1); - return aso.current_shuffled_activenodes[block_num - dpo.last_scheduling_block_num]; + return aso.current_shuffled_activenodes[block_num - dpo.current_scheduling_block_num]; } void database::update_activenode_schedule() @@ -83,7 +83,7 @@ void database::update_activenode_schedule() }); modify( dpo, [&]( dynamic_global_property_object& _dpo ) { - _dpo.last_scheduling_block_num = head_block_num(); + _dpo.current_scheduling_block_num = head_block_num(); } ); } } diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index d980ff9b..c758ab0b 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -202,23 +202,123 @@ void database::pay_workers( share_type& budget ) } } +void database::burn_account_coins(account_id_type account, asset amount) { + + const asset_dynamic_data_object& core = + asset_id_type(0)(*this).dynamic_asset_data_id(*this); + + wlog("before reduce supply ${supply} and account ${acc} by ${amount}",("supply", core.current_supply)("acc", account)("amount", amount.amount) ); + + + modify(core, [&]( asset_dynamic_data_object& _core ) + { + _core.current_supply = _core.current_supply - amount.amount; + }); + + adjust_balance( account, -amount ); + wlog("reduced current supply ${supply} and account ${acc} by ${amount}",("supply", core.current_supply)("acc", account)("amount", amount.amount) ); +} + void database::update_current_activenodes() { try { const global_property_object& gpo = get_global_properties(); + const dynamic_global_property_object& dpo = get_dynamic_global_properties(); const auto& anodes = get_index_type().indices(); + uint32_t blocks_since_maintenance = head_block_num() - dpo.previous_maintenance_block_num; + dlog("blocks_since_maintenance ${blocks}", ("blocks", blocks_since_maintenance)); + uint32_t min_blocks_per_node = 0; + if (gpo.current_activenodes.size()) + min_blocks_per_node = blocks_since_maintenance / gpo.current_activenodes.size() / 2; + + if (gpo.current_activenodes.size() > blocks_since_maintenance /2) { + wlog("Not every node will get reward - there is more than blocks_since_maintenance/2 activenodes (${nodes}/${blocks}", ("nodes", gpo.current_activenodes.size())("blocks", blocks_since_maintenance /2)); + } + + std::vector new_activenodes; + + for( const activenode_object& anode : anodes ) { + ilog("list nodes ${node}", ("node", anode.id)); + // node is still having penalty + if (anode.penalty_left > 0) { + + modify(anode, [&]( activenode_object& anode_obj ){ + anode_obj.penalty_left--; + }); + + if (anode.penalty_left != 0) { + dlog("node ${node} penalty ${penalty}", ("node", anode.id)("penalty", anode.penalty_left)); + continue; + } + share_type account_balance = get_balance(anode.activenode_account, asset_id_type()).amount.value; + chain::activenode_create_operation create_op; + + asset create_anode_fee = current_fee_schedule().calculate_fee( create_op ); + if (account_balance < LLC_ACTIVENODE_MINIMAL_BALANCE_AFTER_SEND + create_anode_fee.amount) { + // если balance < min_balance + create_anode.fee, то не возвращаем к жизни, т.к. сразу удалим + continue; + } + wlog("fine node ${node} coins ${amount} for returning to active", ("node", anode.id)("amount", create_anode_fee)); + burn_account_coins(anode.activenode_account, create_anode_fee); + new_activenodes.push_back(anode.id); + } + else { + elog("node ${node} activity ${sent}/${min_blocks}", ("node", anode.id)("sent", anode.activities_sent)("min_blocks", min_blocks_per_node)); + uint32_t activities_num = anode.activities_sent; + if (anode.activities_sent >= min_blocks_per_node) { + new_activenodes.push_back(anode.id); + modify(anode, [&]( activenode_object& anode_obj ){ + anode_obj.activities_sent = 0; + }); + continue; + } + + // if node didn't exist and it is here - we should add it + if (anode.is_new) { + new_activenodes.push_back(anode.id); + modify(anode, [&]( activenode_object& anode_obj ){ + anode_obj.is_new = false; + }); + continue; + } + + modify(anode, [&]( activenode_object& anode_obj ){ + anode_obj.activities_sent = 0; + }); + + if (anode.max_penalty == LLC_ACTIVENODE_MAX_MISS_PENALTY) { + elog("removing inactive node ${anode}", ("anode", anode.id)); + remove(anode); + continue; + } + modify(anode, [&]( activenode_object& anode_obj ){ + if (!anode_obj.max_penalty) { + anode_obj.max_penalty = 1; + } + else + anode_obj.max_penalty *= 2; + anode_obj.penalty_left = anode_obj.max_penalty; + }); + dlog("update node ${node} penalty to ${penalty}", ("node", anode.id)("penalty", anode.penalty_left)); + } + } + modify(gpo, [&]( global_property_object& gp ){ gp.current_activenodes.clear(); - gp.current_activenodes.reserve(anodes.size()); + gp.current_activenodes.reserve(new_activenodes.size()); - std::transform(anodes.begin(), anodes.end(), + std::transform(new_activenodes.begin(), new_activenodes.end(), std::inserter(gp.current_activenodes, gp.current_activenodes.end()), - [](const activenode_object& anode) { - return anode.id; + [](const activenode_id_type& anode_id) { + return anode_id; }); }); + + for (auto& node: gpo.current_activenodes) { + ilog("update_current_activenodes node: ${node}", ("node", node)); + } } FC_CAPTURE_AND_RETHROW() } void database::update_active_witnesses() @@ -838,6 +938,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g { dlog("chain_maintenance"); const auto& gpo = get_global_properties(); + const auto& dpo = get_dynamic_global_properties(); distribute_fba_balances(*this); create_buyback_orders(*this); @@ -935,7 +1036,13 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g update_top_n_authorities(*this); update_active_witnesses(); + //here we need to calc how many blocks each activenode has missed and throw them away if < 50% + // but if there more than blocks_in_interval/2 activenodes, then not every node will be granted with at least 2 blocks update_current_activenodes(); + modify( dpo, [&]( dynamic_global_property_object& _dpo ) + { + _dpo.previous_maintenance_block_num = head_block_num(); + } ); update_active_committee_members(); update_worker_votes(); diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index ca838818..37f38e29 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -178,16 +178,20 @@ void database::reward_activenode(const signed_block& new_block) { // was deleted return; } - auto& activenode_object = (*scheduled_activenode)(*this); + auto& activenode = (*scheduled_activenode)(*this); signed_block prev_block = *fetch_block_by_number(new_block.block_num() - 1); fc::time_point_sec prev_block_time = prev_block.timestamp; - if (activenode_object.last_activity == prev_block_time) { + if (activenode.last_activity == prev_block_time) { + modify( activenode, [&]( activenode_object& _ano ) + { + _ano.activities_sent++; + } ); chain::activenode_send_activity_operation send_activity_operation; share_type fee = current_fee_schedule().calculate_fee( send_activity_operation ).amount; share_type to_deposit = fee.value * 0.2 + gpo.parameters.activenode_pay_per_block; - deposit_activenode_pay( activenode_object, to_deposit ); + deposit_activenode_pay( activenode, to_deposit ); } } diff --git a/libraries/chain/include/graphene/chain/activenode_object.hpp b/libraries/chain/include/graphene/chain/activenode_object.hpp index 55395e68..065e0d24 100644 --- a/libraries/chain/include/graphene/chain/activenode_object.hpp +++ b/libraries/chain/include/graphene/chain/activenode_object.hpp @@ -40,6 +40,12 @@ namespace graphene { namespace chain { account_id_type activenode_account; fc::time_point_sec last_activity; + + uint32_t activities_sent = 0; + uint8_t penalty_left = 0; + uint8_t max_penalty = 0; + + bool is_new = true; fc::ip::endpoint endpoint; optional< vesting_balance_id_type > pay_vb; diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 2011ee1c..a7397daa 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -180,3 +180,4 @@ #define LLC_ACTIVENODE_MINIMAL_BALANCE_AFTER_SEND (500 * GRAPHENE_BLOCKCHAIN_PRECISION) #define LLC_ACTIVENODE_MINIMAL_BALANCE_CREATE (511 * GRAPHENE_BLOCKCHAIN_PRECISION) +#define LLC_ACTIVENODE_MAX_MISS_PENALTY (8) diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 66c7b4bc..48045895 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -492,6 +492,9 @@ namespace graphene { namespace chain { template void perform_account_maintenance(std::tuple helpers); + + void burn_account_coins(account_id_type account, asset amount); + ///@} ///@} diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index d677372e..4a55e943 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -110,7 +110,8 @@ namespace graphene { namespace chain { uint32_t last_irreversible_block_num = 0; - uint32_t last_scheduling_block_num = 0; + uint32_t current_scheduling_block_num = 0; + uint32_t previous_maintenance_block_num = 0; enum dynamic_flag_bits { @@ -142,7 +143,7 @@ FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene:: (recent_slots_filled) (dynamic_flags) (last_irreversible_block_num) - (last_scheduling_block_num) + (current_scheduling_block_num) ) FC_REFLECT_DERIVED( graphene::chain::global_property_object, (graphene::db::object), diff --git a/libraries/plugins/activenode/activenode.cpp b/libraries/plugins/activenode/activenode.cpp index 87da5220..78a769d3 100644 --- a/libraries/plugins/activenode/activenode.cpp +++ b/libraries/plugins/activenode/activenode.cpp @@ -104,15 +104,17 @@ void activenode_plugin::plugin_initialize(const boost::program_options::variable void activenode_plugin::plugin_startup() { try { ilog("activenode plugin: plugin_startup() begin"); - chain::database& db = database(); - const auto& account_idx = db.get_index_type().indices().get(); - const auto anode_account_itr = account_idx.find(_activenode_account_name); - if (anode_account_itr != account_idx.end()) { - _activenode_account_id = anode_account_itr->id; - db.new_block_applied.connect( [&]( const signed_block& b){ on_new_block_applied(b); } ); - } - else { - elog("activenode plugin: invalid activenode-account provided - no activenode associated with account with name ${activenode_account}", ("activenode_account", _activenode_account_name)); + if (_activenode_account_name.size()) { + chain::database& db = database(); + const auto& account_idx = db.get_index_type().indices().get(); + const auto anode_account_itr = account_idx.find(_activenode_account_name); + if (anode_account_itr != account_idx.end()) { + _activenode_account_id = anode_account_itr->id; + db.new_block_applied.connect( [&]( const signed_block& b){ on_new_block_applied(b); } ); + } + else { + elog("activenode plugin: invalid activenode-account provided - no activenode associated with account with name ${activenode_account}", ("activenode_account", _activenode_account_name)); + } } ilog("activenode plugin: plugin_startup() end"); } FC_CAPTURE_AND_RETHROW() } @@ -155,7 +157,9 @@ void activenode_plugin::on_new_block_applied(const signed_block& new_block) if (_activenode != scheduled_activenode) return; - + if ((*_activenode)(db).last_activity == fc::time_point::now()) + //double block appied + return; try { result = send_activity(capture); From 537ad702f20687a6bb8f8387fe401080c5ae9041 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Thu, 10 Jan 2019 18:22:04 +0300 Subject: [PATCH 28/33] remove logs --- libraries/chain/db_maint.cpp | 15 --------------- libraries/chain/db_update.cpp | 1 - 2 files changed, 16 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index c758ab0b..0eae3b33 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -207,16 +207,12 @@ void database::burn_account_coins(account_id_type account, asset amount) { const asset_dynamic_data_object& core = asset_id_type(0)(*this).dynamic_asset_data_id(*this); - wlog("before reduce supply ${supply} and account ${acc} by ${amount}",("supply", core.current_supply)("acc", account)("amount", amount.amount) ); - - modify(core, [&]( asset_dynamic_data_object& _core ) { _core.current_supply = _core.current_supply - amount.amount; }); adjust_balance( account, -amount ); - wlog("reduced current supply ${supply} and account ${acc} by ${amount}",("supply", core.current_supply)("acc", account)("amount", amount.amount) ); } void database::update_current_activenodes() @@ -227,7 +223,6 @@ void database::update_current_activenodes() const auto& anodes = get_index_type().indices(); uint32_t blocks_since_maintenance = head_block_num() - dpo.previous_maintenance_block_num; - dlog("blocks_since_maintenance ${blocks}", ("blocks", blocks_since_maintenance)); uint32_t min_blocks_per_node = 0; if (gpo.current_activenodes.size()) min_blocks_per_node = blocks_since_maintenance / gpo.current_activenodes.size() / 2; @@ -239,7 +234,6 @@ void database::update_current_activenodes() std::vector new_activenodes; for( const activenode_object& anode : anodes ) { - ilog("list nodes ${node}", ("node", anode.id)); // node is still having penalty if (anode.penalty_left > 0) { @@ -248,7 +242,6 @@ void database::update_current_activenodes() }); if (anode.penalty_left != 0) { - dlog("node ${node} penalty ${penalty}", ("node", anode.id)("penalty", anode.penalty_left)); continue; } share_type account_balance = get_balance(anode.activenode_account, asset_id_type()).amount.value; @@ -259,12 +252,10 @@ void database::update_current_activenodes() // если balance < min_balance + create_anode.fee, то не возвращаем к жизни, т.к. сразу удалим continue; } - wlog("fine node ${node} coins ${amount} for returning to active", ("node", anode.id)("amount", create_anode_fee)); burn_account_coins(anode.activenode_account, create_anode_fee); new_activenodes.push_back(anode.id); } else { - elog("node ${node} activity ${sent}/${min_blocks}", ("node", anode.id)("sent", anode.activities_sent)("min_blocks", min_blocks_per_node)); uint32_t activities_num = anode.activities_sent; if (anode.activities_sent >= min_blocks_per_node) { new_activenodes.push_back(anode.id); @@ -288,7 +279,6 @@ void database::update_current_activenodes() }); if (anode.max_penalty == LLC_ACTIVENODE_MAX_MISS_PENALTY) { - elog("removing inactive node ${anode}", ("anode", anode.id)); remove(anode); continue; } @@ -300,7 +290,6 @@ void database::update_current_activenodes() anode_obj.max_penalty *= 2; anode_obj.penalty_left = anode_obj.max_penalty; }); - dlog("update node ${node} penalty to ${penalty}", ("node", anode.id)("penalty", anode.penalty_left)); } } @@ -315,10 +304,6 @@ void database::update_current_activenodes() return anode_id; }); }); - - for (auto& node: gpo.current_activenodes) { - ilog("update_current_activenodes node: ${node}", ("node", node)); - } } FC_CAPTURE_AND_RETHROW() } void database::update_active_witnesses() diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 37f38e29..d2d3db6f 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -151,7 +151,6 @@ void database::clean_poor_activenodes() { //removing activenodes that doesn't have money share_type total_balance = get_total_account_balance(act_object.activenode_account(*this)); if (total_balance < LLC_ACTIVENODE_MINIMAL_BALANCE_AFTER_SEND) { - dlog("activenode ${node} was deleted", ("node", act_object.id)); remove(act_object); } } From 27dc1cdff20a2c438f834f2d43b98ded62bf7883 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Thu, 10 Jan 2019 20:39:33 +0300 Subject: [PATCH 29/33] null commitions for system accounts --- libraries/chain/account_object.cpp | 5 ++++- libraries/chain/db_init.cpp | 6 ++++++ libraries/chain/db_market.cpp | 2 +- libraries/chain/evaluator.cpp | 2 +- libraries/chain/include/graphene/chain/account_object.hpp | 5 ++++- libraries/chain/include/graphene/chain/genesis_state.hpp | 3 ++- 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/libraries/chain/account_object.cpp b/libraries/chain/account_object.cpp index 90d97692..b1ec4746 100644 --- a/libraries/chain/account_object.cpp +++ b/libraries/chain/account_object.cpp @@ -102,8 +102,11 @@ void account_statistics_object::process_fees(const account_object& a, database& } } -void account_statistics_object::pay_fee( share_type core_fee, share_type cashback_vesting_threshold ) +void account_statistics_object::pay_fee( share_type core_fee, share_type cashback_vesting_threshold, database& d) { + if (owner(d).is_system_account) { + return; + } if( core_fee > cashback_vesting_threshold ) pending_fees += core_fee; else diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 32a49b72..430f3cd0 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -435,6 +435,12 @@ void database::init_genesis(const genesis_state_type& genesis_state) } account_id_type account_id(apply_operation(genesis_eval_state, cop).get()); + if( account.is_system_account ) + { + modify( account_id(*this), [&]( account_object& a ) { + a.is_system_account = true; + }); + } if( account.is_lifetime_member ) { account_upgrade_operation op; diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index ef811c03..8d2b1acd 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -402,7 +402,7 @@ bool database::fill_order( const limit_order_object& order, const asset& pays, c { modify( seller.statistics(*this), [&]( account_statistics_object& statistics ) { - statistics.pay_fee( order.deferred_fee, get_global_properties().parameters.cashback_vesting_threshold ); + statistics.pay_fee( order.deferred_fee, get_global_properties().parameters.cashback_vesting_threshold, *this); } ); } diff --git a/libraries/chain/evaluator.cpp b/libraries/chain/evaluator.cpp index a4127c25..efa42ab0 100644 --- a/libraries/chain/evaluator.cpp +++ b/libraries/chain/evaluator.cpp @@ -99,7 +99,7 @@ database& generic_evaluator::db()const { return trx_state->db(); } /// TODO: db().pay_fee( account_id, core_fee ); d.modify(*fee_paying_account_statistics, [&](account_statistics_object& s) { - s.pay_fee( core_fee_paid, d.get_global_properties().parameters.cashback_vesting_threshold ); + s.pay_fee( core_fee_paid, d.get_global_properties().parameters.cashback_vesting_threshold, db()); }); } } FC_CAPTURE_AND_RETHROW() } diff --git a/libraries/chain/include/graphene/chain/account_object.hpp b/libraries/chain/include/graphene/chain/account_object.hpp index 522cb7bc..e3ac5f97 100644 --- a/libraries/chain/include/graphene/chain/account_object.hpp +++ b/libraries/chain/include/graphene/chain/account_object.hpp @@ -88,7 +88,7 @@ namespace graphene { namespace chain { /** * Core fees are paid into the account_statistics_object by this method */ - void pay_fee( share_type core_fee, share_type cashback_vesting_threshold ); + void pay_fee( share_type core_fee, share_type cashback_vesting_threshold, database& d ); }; /** @@ -144,6 +144,8 @@ namespace graphene { namespace chain { /// The lifetime member at the top of the referral tree. Receives a percentage of referral rewards. account_id_type lifetime_referrer; + bool is_system_account = false; + /// Percentage of fee which should go to network. uint16_t network_fee_percentage = GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; /// Percentage of fee which should go to lifetime referrer. @@ -379,6 +381,7 @@ FC_REFLECT_DERIVED( graphene::chain::account_object, (owner_special_authority)(active_special_authority) (top_n_control_flags) (allowed_assets) + (is_system_account) ) FC_REFLECT_DERIVED( graphene::chain::account_balance_object, diff --git a/libraries/chain/include/graphene/chain/genesis_state.hpp b/libraries/chain/include/graphene/chain/genesis_state.hpp index df87d179..0e52dbd9 100644 --- a/libraries/chain/include/graphene/chain/genesis_state.hpp +++ b/libraries/chain/include/graphene/chain/genesis_state.hpp @@ -51,6 +51,7 @@ struct genesis_state_type { public_key_type owner_key; public_key_type active_key; bool is_lifetime_member = false; + bool is_system_account = false; }; struct initial_asset_type { struct initial_collateral_position { @@ -127,7 +128,7 @@ struct genesis_state_type { } } // namespace graphene::chain -FC_REFLECT(graphene::chain::genesis_state_type::initial_account_type, (name)(owner_key)(active_key)(is_lifetime_member)) +FC_REFLECT(graphene::chain::genesis_state_type::initial_account_type, (name)(owner_key)(active_key)(is_lifetime_member)(is_system_account)) FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type, (symbol)(issuer_name)(description)(precision)(max_supply)(accumulated_fees)(is_bitasset)(collateral_records)) From 001edae1f30b94ad46af4b1e44c8c0aedd6d672f Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Fri, 11 Jan 2019 15:49:51 +0300 Subject: [PATCH 30/33] Fix null comissions --- libraries/chain/include/graphene/chain/evaluator.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/graphene/chain/evaluator.hpp b/libraries/chain/include/graphene/chain/evaluator.hpp index af90517e..46c3cd23 100644 --- a/libraries/chain/include/graphene/chain/evaluator.hpp +++ b/libraries/chain/include/graphene/chain/evaluator.hpp @@ -168,8 +168,8 @@ namespace graphene { namespace chain { pay_fee(); auto result = eval->do_apply(op); - - db_adjust_balance(op.fee_payer(), -fee_from_account); + if (!op.fee_payer()(db()).is_system_account) + db_adjust_balance(op.fee_payer(), -fee_from_account); return result; } From d9b19926c91a8df67bc3155e9f6e6f044c624441 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Fri, 11 Jan 2019 19:32:07 +0300 Subject: [PATCH 31/33] =?UTF-8?q?Reflect=20new=20values=20of=20activenode?= =?UTF-8?q?=5Fobject=20(activities=5Fsent,=20penalty=5Fleft,=20max=5Fpenal?= =?UTF-8?q?ty,=20is=5Fnew).=E2=80=A8And=20remove=20is=5Fenabled=20from=20a?= =?UTF-8?q?ctivenode=5Fobject=20as=20we=20don=E2=80=99t=20use=20it=20anymo?= =?UTF-8?q?re?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libraries/chain/activenode_evaluator.cpp | 1 - .../include/graphene/chain/activenode_object.hpp | 14 ++++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/chain/activenode_evaluator.cpp b/libraries/chain/activenode_evaluator.cpp index ead0c6a2..2b7967f1 100644 --- a/libraries/chain/activenode_evaluator.cpp +++ b/libraries/chain/activenode_evaluator.cpp @@ -53,7 +53,6 @@ object_id_type activenode_create_evaluator::do_apply( const activenode_create_op { try { const auto& new_activenode_object = db().create( [&]( activenode_object& obj ){ obj.activenode_account = op.activenode_account; - obj.is_enabled = true; }); return new_activenode_object.id; } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/chain/include/graphene/chain/activenode_object.hpp b/libraries/chain/include/graphene/chain/activenode_object.hpp index 065e0d24..ea4120da 100644 --- a/libraries/chain/include/graphene/chain/activenode_object.hpp +++ b/libraries/chain/include/graphene/chain/activenode_object.hpp @@ -41,15 +41,14 @@ namespace graphene { namespace chain { account_id_type activenode_account; fc::time_point_sec last_activity; - uint32_t activities_sent = 0; - uint8_t penalty_left = 0; - uint8_t max_penalty = 0; + uint32_t activities_sent = 0; // amount of activities sent in this interval + uint8_t penalty_left = 0; // how many maintenance intervals do we need to wait before we'll become active + uint8_t max_penalty = 0; // max penalty that we've got - bool is_new = true; + bool is_new = true; // have the activenode already participated in scheduling fc::ip::endpoint endpoint; optional< vesting_balance_id_type > pay_vb; - bool is_enabled; activenode_object() {} }; @@ -73,5 +72,8 @@ FC_REFLECT_DERIVED( graphene::chain::activenode_object, (graphene::db::object), (last_activity) (endpoint) (pay_vb) - (is_enabled) + (activities_sent) + (penalty_left) + (max_penalty) + (is_new) ) \ No newline at end of file From 6b44455827bb86f8cec0930b996f347e86f59f76 Mon Sep 17 00:00:00 2001 From: Nikita Kunevich Date: Thu, 17 Jan 2019 13:22:04 +0300 Subject: [PATCH 32/33] fix deactivate activenodes --- libraries/chain/activenode_evaluator.cpp | 2 +- libraries/chain/db_activenode_schedule.cpp | 3 ++- libraries/chain/db_maint.cpp | 5 +++++ .../chain/include/graphene/chain/global_property_object.hpp | 1 + libraries/plugins/activenode/activenode.cpp | 2 +- 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/chain/activenode_evaluator.cpp b/libraries/chain/activenode_evaluator.cpp index 2b7967f1..4e49ff78 100644 --- a/libraries/chain/activenode_evaluator.cpp +++ b/libraries/chain/activenode_evaluator.cpp @@ -76,7 +76,7 @@ void_result activenode_activity_evaluator::do_apply( const activenode_send_activ _db.get(op.activenode), [&]( activenode_object& activenode_object ) { - activenode_object.last_activity = op.timepoint; + activenode_object.last_activity = db().head_block_time(); activenode_object.endpoint = op.endpoint; }); return void_result(); diff --git a/libraries/chain/db_activenode_schedule.cpp b/libraries/chain/db_activenode_schedule.cpp index df9fa75b..0ccb5b4e 100644 --- a/libraries/chain/db_activenode_schedule.cpp +++ b/libraries/chain/db_activenode_schedule.cpp @@ -54,7 +54,8 @@ void database::update_activenode_schedule() const global_property_object& gpo = get_global_properties(); const dynamic_global_property_object& dpo = get_dynamic_global_properties(); - if( gpo.current_activenodes.size() != 0 && head_block_num() % gpo.current_activenodes.size() == 0 ) + if ( dpo.dynamic_flags & dynamic_global_property_object::maintenance_flag || + (gpo.current_activenodes.size() != 0 && head_block_num() % gpo.current_activenodes.size() == 0) ) { modify( aso, [&]( activenode_schedule_object& _aso ) { diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 0eae3b33..ed7f34c7 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -261,6 +261,10 @@ void database::update_current_activenodes() new_activenodes.push_back(anode.id); modify(anode, [&]( activenode_object& anode_obj ){ anode_obj.activities_sent = 0; + //for cases when min_blocks_per_node = 0 (can happen because of integer division) + if (anode.is_new) { + anode_obj.is_new = false; + } }); continue; } @@ -270,6 +274,7 @@ void database::update_current_activenodes() new_activenodes.push_back(anode.id); modify(anode, [&]( activenode_object& anode_obj ){ anode_obj.is_new = false; + anode_obj.activities_sent = 0; }); continue; } diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index 4a55e943..4ad27e85 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -144,6 +144,7 @@ FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene:: (dynamic_flags) (last_irreversible_block_num) (current_scheduling_block_num) + (previous_maintenance_block_num) ) FC_REFLECT_DERIVED( graphene::chain::global_property_object, (graphene::db::object), diff --git a/libraries/plugins/activenode/activenode.cpp b/libraries/plugins/activenode/activenode.cpp index 78a769d3..5923dec2 100644 --- a/libraries/plugins/activenode/activenode.cpp +++ b/libraries/plugins/activenode/activenode.cpp @@ -229,7 +229,7 @@ activenode_plugin::send_activity( fc::limited_mutable_variant_object& capture ) } chain::activenode_send_activity_operation send_activity_operation; - fc::time_point_sec now = fc::time_point::now(); + fc::time_point_sec now = db.head_block_time(); send_activity_operation.timepoint = now; send_activity_operation.endpoint = endpoint; send_activity_operation.activenode = *_activenode; From 39a6ae2f9434813f3350e74b77bcc6e12836f8de Mon Sep 17 00:00:00 2001 From: "LocalCoin.is" <42545106+LocalCoinIS@users.noreply.github.com> Date: Tue, 12 Feb 2019 10:38:50 +0300 Subject: [PATCH 33/33] Update default seed-list --- libraries/app/application.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 1fec3e0d..d8ff8363 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -166,6 +166,8 @@ void application_impl::reset_p2p_node(const fc::path& data_dir) // https://bitsharestalk.org/index.php/topic,23715.0.html vector seeds = { "moscow.localcoin.is:11010" // Moscow (Russia) + "ru.localcoin.is:11010" // Russia + "helsinki.localcoin.is:11010" // Helsinki (Finland) }; for( const string& endpoint_string : seeds ) {