Merge branch 'feature/SONs-base' into feature/SON-158
This commit is contained in:
commit
a08905e22b
18 changed files with 614 additions and 51 deletions
|
|
@ -350,6 +350,7 @@ processed_transaction database::push_proposal(const proposal_object& proposal)
|
|||
auto session = _undo_db.start_undo_session(true);
|
||||
for( auto& op : proposal.proposed_transaction.operations )
|
||||
eval_state.operation_results.emplace_back(apply_operation(eval_state, op));
|
||||
remove_son_proposal(proposal);
|
||||
remove(proposal);
|
||||
session.merge();
|
||||
} catch ( const fc::exception& e ) {
|
||||
|
|
@ -426,6 +427,34 @@ signed_block database::_generate_block(
|
|||
_pending_tx_session.reset();
|
||||
_pending_tx_session = _undo_db.start_undo_session();
|
||||
|
||||
if( head_block_time() > HARDFORK_SON_TIME )
|
||||
{
|
||||
// Approve proposals raised by me in previous schedule or before
|
||||
process_son_proposals( witness_obj, block_signing_private_key );
|
||||
// Check for new SON Deregistration Proposals to be raised
|
||||
std::set<son_id_type> sons_to_be_dereg = get_sons_to_be_deregistered();
|
||||
if(sons_to_be_dereg.size() > 0)
|
||||
{
|
||||
// We shouldn't raise proposals for the SONs for which a de-reg
|
||||
// proposal is already raised.
|
||||
std::set<son_id_type> sons_being_dereg = get_sons_being_deregistered();
|
||||
for( auto& son : sons_to_be_dereg)
|
||||
{
|
||||
// New SON to be deregistered
|
||||
if(sons_being_dereg.find(son) == sons_being_dereg.end())
|
||||
{
|
||||
// Creating the de-reg proposal
|
||||
auto op = create_son_deregister_proposal(son, witness_obj);
|
||||
if(op.valid())
|
||||
{
|
||||
// Signing and pushing into the txs to be included in the block
|
||||
_pending_tx.insert( _pending_tx.begin(), create_signed_transaction( block_signing_private_key, *op ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t postponed_tx_count = 0;
|
||||
// pop pending state (reset to head block state)
|
||||
for( const processed_transaction& tx : _pending_tx )
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@
|
|||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/chain_property_object.hpp>
|
||||
#include <graphene/chain/global_property_object.hpp>
|
||||
|
||||
#include <graphene/chain/son_object.hpp>
|
||||
#include <graphene/chain/son_proposal_object.hpp>
|
||||
#include <fc/smart_ref_impl.hpp>
|
||||
|
||||
#include <ctime>
|
||||
|
|
@ -141,4 +142,118 @@ const std::vector<uint32_t> database::get_winner_numbers( asset_id_type for_asse
|
|||
return result;
|
||||
}
|
||||
|
||||
std::set<son_id_type> database::get_sons_being_deregistered()
|
||||
{
|
||||
std::set<son_id_type> ret;
|
||||
const auto& son_proposal_idx = get_index_type<son_proposal_index>().indices().get< by_id >();
|
||||
|
||||
for( auto& son_proposal : son_proposal_idx )
|
||||
{
|
||||
if(son_proposal.proposal_type == son_proposal_type::son_deregister_proposal)
|
||||
{
|
||||
ret.insert(son_proposal.son_id);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::set<son_id_type> database::get_sons_to_be_deregistered()
|
||||
{
|
||||
std::set<son_id_type> ret;
|
||||
const auto& son_idx = get_index_type<son_index>().indices().get< by_id >();
|
||||
|
||||
for( auto& son : son_idx )
|
||||
{
|
||||
if(son.status == son_status::in_maintenance)
|
||||
{
|
||||
auto stats = son.statistics(*this);
|
||||
// TODO : We need to add a function that returns if we can deregister SON
|
||||
// i.e. with introduction of PW code, we have to make a decision if the SON
|
||||
// is needed for release of funds from the PW
|
||||
if(head_block_time() - stats.last_down_timestamp >= fc::hours(SON_DEREGISTER_TIME))
|
||||
{
|
||||
ret.insert(son.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
fc::optional<operation> database::create_son_deregister_proposal(const son_id_type& son_id, const witness_object& current_witness )
|
||||
{
|
||||
son_delete_operation son_dereg_op;
|
||||
son_dereg_op.payer = current_witness.witness_account;
|
||||
son_dereg_op.son_id = son_id;
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = current_witness.witness_account;
|
||||
proposal_op.proposed_ops.push_back( op_wrapper( son_dereg_op ) );
|
||||
uint32_t lifetime = ( get_global_properties().parameters.block_interval * get_global_properties().active_witnesses.size() ) * 3;
|
||||
proposal_op.expiration_time = time_point_sec( head_block_time().sec_since_epoch() + lifetime );
|
||||
return proposal_op;
|
||||
}
|
||||
|
||||
signed_transaction database::create_signed_transaction( const fc::ecc::private_key& signing_private_key, const operation& op )
|
||||
{
|
||||
signed_transaction processed_trx;
|
||||
auto dyn_props = get_dynamic_global_properties();
|
||||
processed_trx.set_reference_block( dyn_props.head_block_id );
|
||||
processed_trx.set_expiration( head_block_time() + get_global_properties().parameters.maximum_time_until_expiration );
|
||||
processed_trx.operations.push_back( op );
|
||||
current_fee_schedule().set_fee( processed_trx.operations.back() );
|
||||
|
||||
processed_trx.sign( signing_private_key, get_chain_id() );
|
||||
|
||||
return processed_trx;
|
||||
}
|
||||
|
||||
void database::process_son_proposals( const witness_object& current_witness, const fc::ecc::private_key& private_key )
|
||||
{
|
||||
const auto& son_proposal_idx = get_index_type<son_proposal_index>().indices().get< by_id >();
|
||||
const auto& proposal_idx = get_index_type<proposal_index>().indices().get< by_id >();
|
||||
|
||||
auto approve_proposal = [ & ]( const proposal_id_type& id )
|
||||
{
|
||||
proposal_update_operation puo;
|
||||
puo.fee_paying_account = current_witness.witness_account;
|
||||
puo.proposal = id;
|
||||
puo.active_approvals_to_add = { current_witness.witness_account };
|
||||
_pending_tx.insert( _pending_tx.begin(), create_signed_transaction( private_key, puo ) );
|
||||
};
|
||||
|
||||
for( auto& son_proposal : son_proposal_idx )
|
||||
{
|
||||
const auto& proposal = proposal_idx.find( son_proposal.proposal_id );
|
||||
FC_ASSERT( proposal != proposal_idx.end() );
|
||||
if( proposal->proposer == current_witness.witness_account)
|
||||
{
|
||||
approve_proposal( proposal->id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void database::remove_son_proposal( const proposal_object& proposal )
|
||||
{ try {
|
||||
if( proposal.proposed_transaction.operations.size() == 1 &&
|
||||
( proposal.proposed_transaction.operations.back().which() == operation::tag<son_delete_operation>::value) )
|
||||
{
|
||||
const auto& son_proposal_idx = get_index_type<son_proposal_index>().indices().get<by_proposal>();
|
||||
auto son_proposal_itr = son_proposal_idx.find( proposal.id );
|
||||
if( son_proposal_itr == son_proposal_idx.end() ) {
|
||||
return;
|
||||
}
|
||||
remove( *son_proposal_itr );
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW( (proposal) ) }
|
||||
|
||||
bool database::is_son_dereg_valid( const son_id_type& son_id )
|
||||
{
|
||||
const auto& son_idx = get_index_type<son_index>().indices().get< by_id >();
|
||||
auto son = son_idx.find( son_id );
|
||||
FC_ASSERT( son != son_idx.end() );
|
||||
bool ret = ( son->status == son_status::in_maintenance &&
|
||||
(head_block_time() - son->statistics(*this).last_down_timestamp >= fc::hours(SON_DEREGISTER_TIME)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
#include <graphene/chain/betting_market_object.hpp>
|
||||
#include <graphene/chain/global_betting_statistics_object.hpp>
|
||||
#include <graphene/chain/son_object.hpp>
|
||||
#include <graphene/chain/son_proposal_object.hpp>
|
||||
|
||||
#include <graphene/chain/account_evaluator.hpp>
|
||||
#include <graphene/chain/asset_evaluator.hpp>
|
||||
|
|
@ -262,7 +263,7 @@ void database::initialize_indexes()
|
|||
acnt_index->add_secondary_index<account_referrer_index>();
|
||||
|
||||
add_index< primary_index<committee_member_index, 8> >(); // 256 members per chunk
|
||||
add_index< primary_index<son_index, 8> >(); // 256 sons per chunk
|
||||
add_index< primary_index<son_index> >();
|
||||
add_index< primary_index<witness_index, 10> >(); // 1024 witnesses per chunk
|
||||
add_index< primary_index<limit_order_index > >();
|
||||
add_index< primary_index<call_order_index > >();
|
||||
|
|
@ -288,6 +289,7 @@ void database::initialize_indexes()
|
|||
tournament_details_idx->add_secondary_index<tournament_players_index>();
|
||||
add_index< primary_index<match_index> >();
|
||||
add_index< primary_index<game_index> >();
|
||||
add_index< primary_index<son_proposal_index> >();
|
||||
|
||||
//Implementation object indexes
|
||||
add_index< primary_index<transaction_index > >();
|
||||
|
|
|
|||
|
|
@ -233,7 +233,8 @@
|
|||
#define TOURNAMENT_MAX_START_DELAY (60*60*24*7) // 1 week
|
||||
#define MIN_SON_MEMBER_COUNT 15
|
||||
#define SON_VESTING_AMOUNT (50*GRAPHENE_BLOCKCHAIN_PRECISION) // 50 PPY
|
||||
#define SON_VESTING_PERIOD (60*60*24*30) // 2 days
|
||||
#define SON_VESTING_PERIOD (60*60*24*2) // 2 days
|
||||
#define SON_DEREGISTER_TIME (12) // 12 Hours
|
||||
#define MIN_SON_PAY_DAILY_MAX (GRAPHENE_BLOCKCHAIN_PRECISION * int64_t(200))
|
||||
#define SWEEPS_DEFAULT_DISTRIBUTION_PERCENTAGE (2*GRAPHENE_1_PERCENT)
|
||||
#define SWEEPS_DEFAULT_DISTRIBUTION_ASSET (graphene::chain::asset_id_type(0))
|
||||
|
|
|
|||
|
|
@ -279,6 +279,13 @@ namespace graphene { namespace chain {
|
|||
const std::vector<uint32_t> get_winner_numbers( asset_id_type for_asset, uint32_t count_members, uint8_t count_winners ) const;
|
||||
std::vector<uint32_t> get_seeds( asset_id_type for_asset, uint8_t count_winners )const;
|
||||
uint64_t get_random_bits( uint64_t bound );
|
||||
std::set<son_id_type> get_sons_being_deregistered();
|
||||
std::set<son_id_type> get_sons_to_be_deregistered();
|
||||
fc::optional<operation> create_son_deregister_proposal(const son_id_type& son_id, const witness_object& current_witness );
|
||||
signed_transaction create_signed_transaction( const fc::ecc::private_key& signing_private_key, const operation& op );
|
||||
void process_son_proposals( const witness_object& current_witness, const fc::ecc::private_key& private_key );
|
||||
void remove_son_proposal( const proposal_object& proposal );
|
||||
bool is_son_dereg_valid( const son_id_type& son_id );
|
||||
|
||||
time_point_sec head_block_time()const;
|
||||
uint32_t head_block_num()const;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,21 @@
|
|||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class son_hardfork_visitor
|
||||
{
|
||||
public:
|
||||
typedef void result_type;
|
||||
database& db;
|
||||
proposal_id_type prop_id;
|
||||
|
||||
son_hardfork_visitor( database& _db, const proposal_id_type& _prop_id ) : db( _db ), prop_id( _prop_id ) {}
|
||||
|
||||
template<typename T>
|
||||
void operator()( const T &v ) const {}
|
||||
|
||||
void operator()( const son_delete_operation &v );
|
||||
};
|
||||
|
||||
class proposal_create_evaluator : public evaluator<proposal_create_evaluator>
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -40,9 +40,10 @@ namespace graphene { namespace chain {
|
|||
|
||||
asset fee;
|
||||
son_id_type son_id;
|
||||
account_id_type payer;
|
||||
account_id_type owner_account;
|
||||
|
||||
account_id_type fee_payer()const { return owner_account; }
|
||||
account_id_type fee_payer()const { return payer; }
|
||||
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
|
||||
};
|
||||
|
||||
|
|
@ -57,4 +58,4 @@ FC_REFLECT(graphene::chain::son_update_operation, (fee)(son_id)(owner_account)(n
|
|||
(new_signing_key)(new_pay_vb) )
|
||||
|
||||
FC_REFLECT(graphene::chain::son_delete_operation::fee_parameters_type, (fee) )
|
||||
FC_REFLECT(graphene::chain::son_delete_operation, (fee)(son_id)(owner_account) )
|
||||
FC_REFLECT(graphene::chain::son_delete_operation, (fee)(son_id)(payer)(owner_account) )
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ namespace graphene { namespace chain {
|
|||
betting_market_object_type,
|
||||
bet_object_type,
|
||||
son_object_type,
|
||||
son_proposal_object_type,
|
||||
OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types
|
||||
};
|
||||
|
||||
|
|
@ -207,6 +208,7 @@ namespace graphene { namespace chain {
|
|||
class betting_market_object;
|
||||
class bet_object;
|
||||
class son_object;
|
||||
class son_proposal_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;
|
||||
|
|
@ -234,6 +236,7 @@ namespace graphene { namespace chain {
|
|||
typedef object_id< protocol_ids, betting_market_object_type, betting_market_object> betting_market_id_type;
|
||||
typedef object_id< protocol_ids, bet_object_type, bet_object> bet_id_type;
|
||||
typedef object_id< protocol_ids, son_object_type, son_object> son_id_type;
|
||||
typedef object_id< protocol_ids, son_proposal_object_type, son_proposal_object> son_proposal_id_type;
|
||||
|
||||
// implementation types
|
||||
class global_property_object;
|
||||
|
|
@ -417,6 +420,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type,
|
|||
(betting_market_object_type)
|
||||
(bet_object_type)
|
||||
(son_object_type)
|
||||
(son_proposal_object_type)
|
||||
(OBJECT_TYPE_COUNT)
|
||||
)
|
||||
FC_REFLECT_ENUM( graphene::chain::impl_object_type,
|
||||
|
|
@ -488,6 +492,7 @@ FC_REFLECT_TYPENAME( graphene::chain::betting_market_position_id_type )
|
|||
FC_REFLECT_TYPENAME( graphene::chain::global_betting_statistics_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::tournament_details_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::son_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::son_proposal_id_type )
|
||||
|
||||
|
||||
FC_REFLECT( graphene::chain::void_t, )
|
||||
|
|
|
|||
|
|
@ -6,6 +6,12 @@
|
|||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
|
||||
enum class son_status
|
||||
{
|
||||
inactive,
|
||||
active,
|
||||
in_maintenance
|
||||
};
|
||||
/**
|
||||
* @class son_statistics_object
|
||||
* @ingroup object
|
||||
|
|
@ -23,6 +29,10 @@ namespace graphene { namespace chain {
|
|||
son_id_type owner;
|
||||
// Transactions signed since the last son payouts
|
||||
uint64_t txs_signed = 0;
|
||||
// Total Downtime barring the current down time in seconds, used for stats to present to user
|
||||
uint64_t total_downtime = 0;
|
||||
// Down timestamp, if son status is in_maintenance use this
|
||||
fc::time_point_sec last_down_timestamp;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -44,6 +54,7 @@ namespace graphene { namespace chain {
|
|||
public_key_type signing_key;
|
||||
vesting_balance_id_type pay_vb;
|
||||
son_statistics_id_type statistics;
|
||||
son_status status = son_status::inactive;
|
||||
|
||||
void pay_son_fee(share_type pay, database& db);
|
||||
};
|
||||
|
|
@ -76,6 +87,8 @@ namespace graphene { namespace chain {
|
|||
using son_stats_index = generic_index<son_statistics_object, son_stats_multi_index_type>;
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT_ENUM(graphene::chain::son_status, (inactive)(active)(in_maintenance) )
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::son_object, (graphene::db::object),
|
||||
(son_account)(vote_id)(total_votes)(url)(deposit)(signing_key)(pay_vb) )
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <graphene/chain/protocol/types.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
enum class son_proposal_type
|
||||
{
|
||||
son_deregister_proposal
|
||||
};
|
||||
|
||||
class son_proposal_object : public abstract_object<son_proposal_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = son_proposal_object_type;
|
||||
|
||||
son_proposal_id_type get_id()const { return id; }
|
||||
|
||||
proposal_id_type proposal_id;
|
||||
son_id_type son_id;
|
||||
son_proposal_type proposal_type;
|
||||
};
|
||||
|
||||
struct by_proposal;
|
||||
using son_proposal_multi_index_container = multi_index_container<
|
||||
son_proposal_object,
|
||||
indexed_by<
|
||||
ordered_unique< tag< by_id >, member< object, object_id_type, &object::id > >,
|
||||
ordered_unique< tag< by_proposal >, member< son_proposal_object, proposal_id_type, &son_proposal_object::proposal_id > >
|
||||
>
|
||||
>;
|
||||
using son_proposal_index = generic_index<son_proposal_object, son_proposal_multi_index_container>;
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT_ENUM(graphene::chain::son_proposal_type, (son_deregister_proposal) )
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::son_proposal_object, (graphene::chain::object), (proposal_id)(son_id)(proposal_type) )
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
#include <graphene/chain/proposal_evaluator.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/son_proposal_object.hpp>
|
||||
#include <graphene/chain/protocol/account.hpp>
|
||||
#include <graphene/chain/protocol/fee_schedule.hpp>
|
||||
#include <graphene/chain/protocol/tournament.hpp>
|
||||
|
|
@ -154,6 +155,15 @@ struct proposal_operation_hardfork_visitor
|
|||
}
|
||||
};
|
||||
|
||||
void son_hardfork_visitor::operator()( const son_delete_operation &v )
|
||||
{
|
||||
db.create<son_proposal_object>([&]( son_proposal_object& son_prop ) {
|
||||
son_prop.proposal_type = son_proposal_type::son_deregister_proposal;
|
||||
son_prop.proposal_id = prop_id;
|
||||
son_prop.son_id = v.son_id;
|
||||
});
|
||||
}
|
||||
|
||||
void_result proposal_create_evaluator::do_evaluate(const proposal_create_operation& o)
|
||||
{ try {
|
||||
const database& d = db();
|
||||
|
|
@ -232,6 +242,12 @@ object_id_type proposal_create_evaluator::do_apply(const proposal_create_operati
|
|||
std::inserter(proposal.required_active_approvals, proposal.required_active_approvals.begin()));
|
||||
});
|
||||
|
||||
son_hardfork_visitor son_vtor(d, proposal.id);
|
||||
for(auto& op: o.proposed_ops)
|
||||
{
|
||||
op.op.visit(son_vtor);
|
||||
}
|
||||
|
||||
return proposal.id;
|
||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||
|
||||
|
|
|
|||
|
|
@ -171,15 +171,22 @@ void account_options::validate() const
|
|||
{
|
||||
auto needed_witnesses = num_witness;
|
||||
auto needed_committee = num_committee;
|
||||
auto needed_sons = num_son;
|
||||
|
||||
for( vote_id_type id : votes )
|
||||
if( id.type() == vote_id_type::witness && needed_witnesses )
|
||||
--needed_witnesses;
|
||||
else if ( id.type() == vote_id_type::committee && needed_committee )
|
||||
--needed_committee;
|
||||
else if ( id.type() == vote_id_type::son && needed_sons )
|
||||
--needed_sons;
|
||||
|
||||
FC_ASSERT( needed_witnesses == 0 && needed_committee == 0,
|
||||
"May not specify fewer witnesses or committee members than the number voted for.");
|
||||
FC_ASSERT( needed_witnesses == 0,
|
||||
"May not specify fewer witnesses than the number voted for.");
|
||||
FC_ASSERT( needed_committee == 0,
|
||||
"May not specify fewer committee members than the number voted for.");
|
||||
FC_ASSERT( needed_sons == 0,
|
||||
"May not specify fewer SONs than the number voted for.");
|
||||
}
|
||||
|
||||
void affiliate_reward_distribution::validate() const
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/son_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
#include <graphene/chain/vesting_balance_object.hpp>
|
||||
|
||||
|
|
@ -63,7 +64,11 @@ object_id_type update_son_evaluator::do_apply(const son_update_operation& op)
|
|||
void_result delete_son_evaluator::do_evaluate(const son_delete_operation& op)
|
||||
{ try {
|
||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON_HARDFORK"); // can be removed after HF date pass
|
||||
FC_ASSERT(db().get(op.son_id).son_account == op.owner_account);
|
||||
// Get the current block witness signatory
|
||||
witness_id_type wit_id = db().get_scheduled_witness(1);
|
||||
const witness_object& current_witness = wit_id(db());
|
||||
// Either owner can remove or witness
|
||||
FC_ASSERT(db().get(op.son_id).son_account == op.owner_account || (db().is_son_dereg_valid(op.son_id) && op.payer == current_witness.witness_account));
|
||||
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
||||
FC_ASSERT( idx.find(op.son_id) != idx.end() );
|
||||
return void_result();
|
||||
|
|
|
|||
|
|
@ -402,15 +402,6 @@ namespace graphene { namespace db {
|
|||
DerivedIndex::remove(obj);
|
||||
}
|
||||
|
||||
virtual const object& insert( object&& obj )override
|
||||
{
|
||||
const auto& res = DerivedIndex::insert(std::move(obj));
|
||||
for( const auto& item : _sindex )
|
||||
item->object_inserted( res );
|
||||
on_add(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
virtual void modify( const object& obj, const std::function<void(object&)>& m )override
|
||||
{
|
||||
save_undo( obj );
|
||||
|
|
|
|||
|
|
@ -1340,8 +1340,6 @@ class wallet_api
|
|||
* An account can have at most one witness object.
|
||||
*
|
||||
* @param owner_account the name or id of the account which is creating the witness
|
||||
* @param url a URL to include in the witness record in the blockchain. Clients may
|
||||
* display this when showing a list of witnesses. May be blank.
|
||||
* @param broadcast true to broadcast the transaction on the network
|
||||
* @returns the signed transaction registering a witness
|
||||
*/
|
||||
|
|
@ -1363,6 +1361,13 @@ class wallet_api
|
|||
*/
|
||||
map<string, son_id_type> list_sons(const string& lowerbound, uint32_t limit);
|
||||
|
||||
/** Lists active at the moment SONs.
|
||||
* This returns a list of all account names that own active SON, and the associated SON id,
|
||||
* sorted by name.
|
||||
* @returns a list of active SONs mapping SON names to SON ids
|
||||
*/
|
||||
map<string, son_id_type> list_active_sons();
|
||||
|
||||
/** Creates a witness object owned by the given account.
|
||||
*
|
||||
* An account can have at most one witness object.
|
||||
|
|
@ -1429,15 +1434,17 @@ class wallet_api
|
|||
|
||||
/** Creates a vesting deposit owned by the given account.
|
||||
*
|
||||
* @param owner_account the name or id of the account
|
||||
* @param amount the amount to deposit
|
||||
* @param owner_account vesting balance owner and creator (the name or id)
|
||||
* @param amount amount to vest
|
||||
* @param asset_symbol the symbol of the asset to vest
|
||||
* @param vesting_type "normal", "gpos" or "son"
|
||||
* @param broadcast true to broadcast the transaction on the network
|
||||
* @returns the signed transaction registering a vesting object
|
||||
*/
|
||||
signed_transaction create_vesting(string owner_account,
|
||||
signed_transaction create_vesting_balance(string owner_account,
|
||||
string amount,
|
||||
string vesting_type,
|
||||
string asset_symbol,
|
||||
vesting_balance_type vesting_type,
|
||||
bool broadcast = false);
|
||||
|
||||
/**
|
||||
|
|
@ -2118,7 +2125,7 @@ FC_API( graphene::wallet::wallet_api,
|
|||
(update_witness)
|
||||
(create_worker)
|
||||
(update_worker_votes)
|
||||
(create_vesting)
|
||||
(create_vesting_balance)
|
||||
(get_vesting_balances)
|
||||
(withdraw_vesting)
|
||||
(vote_for_committee_member)
|
||||
|
|
|
|||
|
|
@ -1922,6 +1922,7 @@ public:
|
|||
son_delete_operation son_delete_op;
|
||||
son_delete_op.son_id = son.id;
|
||||
son_delete_op.owner_account = son.son_account;
|
||||
son_delete_op.payer = son.son_account;
|
||||
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back( son_delete_op );
|
||||
|
|
@ -1931,6 +1932,28 @@ public:
|
|||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (owner_account)(broadcast) ) }
|
||||
|
||||
map<string, son_id_type> list_active_sons()
|
||||
{ try {
|
||||
global_property_object gpo = get_global_properties();
|
||||
std::vector<fc::optional<son_object>> son_objects = _remote_db->get_sons(gpo.active_sons);
|
||||
vector<account_id_type> owners;
|
||||
owners.resize(son_objects.size());
|
||||
std::transform(son_objects.begin(), son_objects.end(), owners.begin(),
|
||||
[](const fc::optional<son_object>& obj) {
|
||||
FC_ASSERT(obj, "Invalid active SONs list in global properties.");
|
||||
return obj->son_account;
|
||||
});
|
||||
vector<fc::optional<account_object>> accs = _remote_db->get_accounts(owners);
|
||||
map<string, son_id_type> result;
|
||||
std::transform(accs.begin(), accs.end(), gpo.active_sons.begin(),
|
||||
std::inserter(result, result.end()),
|
||||
[](fc::optional<account_object>& acct, son_id_type& sid) {
|
||||
FC_ASSERT(acct, "Invalid active SONs list in global properties.");
|
||||
return std::make_pair<string, son_id_type>(string(acct->name), std::move(sid));
|
||||
});
|
||||
return result;
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
signed_transaction create_witness(string owner_account,
|
||||
string url,
|
||||
bool broadcast /* = false */)
|
||||
|
|
@ -2106,27 +2129,21 @@ public:
|
|||
return sign_transaction( tx, broadcast );
|
||||
}
|
||||
|
||||
signed_transaction create_vesting(string owner_account,
|
||||
signed_transaction create_vesting_balance(string owner_account,
|
||||
string amount,
|
||||
string vesting_type,
|
||||
string asset_symbol,
|
||||
vesting_balance_type vesting_type,
|
||||
bool broadcast /* = false */)
|
||||
{ try {
|
||||
account_object son_account = get_account(owner_account);
|
||||
fc::optional<asset_object> asset_obj = get_asset(asset_symbol);
|
||||
FC_ASSERT(asset_obj, "Invalid asset symbol {asst}", ("asst", asset_symbol));
|
||||
|
||||
vesting_balance_create_operation op;
|
||||
op.creator = son_account.get_id();
|
||||
op.owner = son_account.get_id();
|
||||
op.amount = asset_object().amount_from_string(amount);
|
||||
if (vesting_type == "normal")
|
||||
op.balance_type = vesting_balance_type::normal;
|
||||
else if (vesting_type == "gpos")
|
||||
op.balance_type = vesting_balance_type::gpos;
|
||||
else if (vesting_type == "son")
|
||||
op.balance_type = vesting_balance_type::son;
|
||||
else
|
||||
{
|
||||
FC_ASSERT( false, "unknown vesting type value ${vt}", ("vt", vesting_type) );
|
||||
}
|
||||
op.amount = asset_obj->amount_from_string(amount);
|
||||
op.balance_type = vesting_type;
|
||||
if (op.balance_type == vesting_balance_type::son)
|
||||
op.policy = dormant_vesting_policy_initializer {};
|
||||
|
||||
|
|
@ -2271,26 +2288,27 @@ public:
|
|||
uint16_t desired_number_of_sons,
|
||||
bool broadcast /* = false */)
|
||||
{ try {
|
||||
FC_ASSERT(sons_to_approve.size() || sons_to_reject.size(), "Both accepted and rejected lists can't be empty simultaneously");
|
||||
account_object voting_account_object = get_account(voting_account);
|
||||
for (const std::string& son : sons_to_approve)
|
||||
{
|
||||
account_id_type son_owner_account_id = get_account_id(son);
|
||||
fc::optional<son_object> son_obj = _remote_db->get_son_by_account(son_owner_account_id);
|
||||
if (!son_obj)
|
||||
FC_THROW("Account ${son} is not registered as a witness", ("son", son));
|
||||
FC_THROW("Account ${son} is not registered as a SON", ("son", son));
|
||||
auto insert_result = voting_account_object.options.votes.insert(son_obj->vote_id);
|
||||
if (!insert_result.second)
|
||||
FC_THROW("Account ${account} was already voting for son ${son}", ("account", voting_account)("son", son));
|
||||
FC_THROW("Account ${account} was already voting for SON ${son}", ("account", voting_account)("son", son));
|
||||
}
|
||||
for (const std::string& son : sons_to_reject)
|
||||
{
|
||||
account_id_type son_owner_account_id = get_account_id(son);
|
||||
fc::optional<son_object> son_obj = _remote_db->get_son_by_account(son_owner_account_id);
|
||||
if (!son_obj)
|
||||
FC_THROW("Account ${son} is not registered as a son", ("son", son));
|
||||
FC_THROW("Account ${son} is not registered as a SON", ("son", son));
|
||||
unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->vote_id);
|
||||
if (!votes_removed)
|
||||
FC_THROW("Account ${account} is already not voting for son ${son}", ("account", voting_account)("son", son));
|
||||
FC_THROW("Account ${account} is already not voting for SON ${son}", ("account", voting_account)("son", son));
|
||||
}
|
||||
voting_account_object.options.num_son = desired_number_of_sons;
|
||||
|
||||
|
|
@ -4270,12 +4288,13 @@ committee_member_object wallet_api::get_committee_member(string owner_account)
|
|||
return my->get_committee_member(owner_account);
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::create_vesting(string owner_account,
|
||||
signed_transaction wallet_api::create_vesting_balance(string owner_account,
|
||||
string amount,
|
||||
string vesting_type,
|
||||
string asset_symbol,
|
||||
vesting_balance_type vesting_type,
|
||||
bool broadcast /* = false */)
|
||||
{
|
||||
return my->create_vesting(owner_account, amount, vesting_type, broadcast);
|
||||
return my->create_vesting_balance(owner_account, amount, asset_symbol, vesting_type, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::create_son(string owner_account,
|
||||
|
|
@ -4306,6 +4325,11 @@ map<string, son_id_type> wallet_api::list_sons(const string& lowerbound, uint32_
|
|||
return my->_remote_db->lookup_son_accounts(lowerbound, limit);
|
||||
}
|
||||
|
||||
map<string, son_id_type> wallet_api::list_active_sons()
|
||||
{
|
||||
return my->list_active_sons();
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::create_witness(string owner_account,
|
||||
string url,
|
||||
bool broadcast /* = false */)
|
||||
|
|
|
|||
|
|
@ -78,11 +78,12 @@ public:
|
|||
BOOST_CHECK(fixture_.generate_block());
|
||||
|
||||
// create deposit vesting
|
||||
fixture_.con.wallet_api_ptr->create_vesting(account_name, "50000000", "son", true);
|
||||
fixture_.con.wallet_api_ptr->create_vesting_balance(account_name,
|
||||
"50", "1.3.0", vesting_balance_type::son, true);
|
||||
BOOST_CHECK(fixture_.generate_block());
|
||||
|
||||
// create pay_vb vesting
|
||||
fixture_.con.wallet_api_ptr->create_vesting(account_name, "1000000", "normal", true);
|
||||
fixture_.con.wallet_api_ptr->create_vesting_balance(account_name, "1", "1.3.0", vesting_balance_type::normal, true);
|
||||
BOOST_CHECK(fixture_.generate_block());
|
||||
|
||||
// check deposits are here
|
||||
|
|
@ -392,7 +393,7 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
accepted.push_back("son1account");
|
||||
accepted.push_back("son2account");
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 15, true);
|
||||
rejected, 2, true);
|
||||
BOOST_CHECK(generate_block());
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
|
|
@ -412,7 +413,7 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
rejected.clear();
|
||||
rejected.push_back("son1account");
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 15, true);
|
||||
rejected, 1, true);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify the votes
|
||||
|
|
@ -431,7 +432,7 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
rejected.clear();
|
||||
rejected.push_back("son1accnt");
|
||||
BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 15, true), fc::exception);
|
||||
rejected, 1, true), fc::exception);
|
||||
BOOST_CHECK(generate_block());
|
||||
|
||||
// Verify the votes
|
||||
|
|
@ -449,7 +450,7 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
rejected.clear();
|
||||
rejected.push_back("son2account");
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 15, true);
|
||||
rejected, 0, true);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify the votes
|
||||
|
|
@ -468,7 +469,24 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
rejected.push_back("son1accnt");
|
||||
accepted.push_back("son1accnt");
|
||||
BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 15, true), fc::exception);
|
||||
rejected, 1, true), fc::exception);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify the votes
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_end_votes = son1_obj.total_votes;
|
||||
BOOST_CHECK(son1_end_votes == son1_start_votes);
|
||||
son1_start_votes = son1_end_votes;
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
son2_end_votes = son2_obj.total_votes;
|
||||
BOOST_CHECK(son2_end_votes == son2_start_votes);
|
||||
son2_start_votes = son2_end_votes;
|
||||
|
||||
// Try to accept and reject empty lists
|
||||
accepted.clear();
|
||||
rejected.clear();
|
||||
BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 1, true), fc::exception);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify the votes
|
||||
|
|
@ -512,6 +530,62 @@ BOOST_AUTO_TEST_CASE( related_functions )
|
|||
BOOST_TEST_MESSAGE("SON-related functions cli wallet tests end");
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture )
|
||||
{
|
||||
BOOST_TEST_MESSAGE("SON cli wallet tests for list_active_sons begin");
|
||||
try
|
||||
{
|
||||
son_test_helper sth(*this);
|
||||
|
||||
signed_transaction vote_tx;
|
||||
global_property_object gpo;
|
||||
|
||||
gpo = con.wallet_api_ptr->get_global_properties();
|
||||
unsigned int son_number = gpo.parameters.maximum_son_count;
|
||||
|
||||
// create son accounts
|
||||
for(unsigned int i = 0; i < son_number + 1; i++)
|
||||
{
|
||||
sth.create_son("sonaccount" + fc::to_pretty_string(i),
|
||||
"http://son" + fc::to_pretty_string(i), false);
|
||||
}
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
BOOST_TEST_MESSAGE("Voting for SONs");
|
||||
for(unsigned int i = 1; i < son_number + 1; i++)
|
||||
{
|
||||
std::string name = "sonaccount" + fc::to_pretty_string(i);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name, name, true, true);
|
||||
}
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
for(unsigned int i = 1; i < son_number; i++)
|
||||
{
|
||||
std::string name1 = "sonaccount" + fc::to_pretty_string(i);
|
||||
std::string name2 = "sonaccount" + fc::to_pretty_string(i + 1);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, true, true);
|
||||
}
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
gpo = con.wallet_api_ptr->get_global_properties();
|
||||
BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size());
|
||||
|
||||
BOOST_CHECK(gpo.active_sons.size() == son_number);
|
||||
|
||||
map<string, son_id_type> active_sons = con.wallet_api_ptr->list_active_sons();
|
||||
BOOST_CHECK(active_sons.size() == son_number);
|
||||
for(unsigned int i = 1; i < son_number + 1; i++)
|
||||
{
|
||||
std::string name = "sonaccount" + fc::to_pretty_string(i);
|
||||
BOOST_CHECK(active_sons.find(name) != active_sons.end());
|
||||
}
|
||||
|
||||
} catch( fc::exception& e ) {
|
||||
BOOST_TEST_MESSAGE("SON cli wallet tests exception");
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
BOOST_TEST_MESSAGE("SON cli wallet tests for list_active_sons end");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
#include <graphene/chain/son_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/son_proposal_object.hpp>
|
||||
#include <graphene/chain/son_evaluator.hpp>
|
||||
#include <graphene/chain/vesting_balance_object.hpp>
|
||||
|
||||
|
|
@ -142,6 +144,7 @@ try {
|
|||
son_delete_operation op;
|
||||
op.owner_account = alice_id;
|
||||
op.son_id = son_id_type(0);
|
||||
op.payer = alice_id;
|
||||
|
||||
trx.operations.push_back(op);
|
||||
sign(trx, alice_private_key);
|
||||
|
|
@ -205,6 +208,7 @@ try {
|
|||
son_delete_operation op;
|
||||
op.owner_account = bob_id;
|
||||
op.son_id = son_id_type(0);
|
||||
op.payer = bob_id;
|
||||
|
||||
trx.operations.push_back(op);
|
||||
sign(trx, bob_private_key);
|
||||
|
|
@ -442,4 +446,210 @@ BOOST_AUTO_TEST_CASE( son_pay_test )
|
|||
BOOST_CHECK( dpo.witness_budget.value == 0);
|
||||
}FC_LOG_AND_RETHROW()
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( son_witness_proposal_test )
|
||||
{
|
||||
try
|
||||
{
|
||||
const dynamic_global_property_object& dpo = db.get_dynamic_global_properties();
|
||||
generate_blocks(HARDFORK_SON_TIME);
|
||||
generate_block();
|
||||
generate_block();
|
||||
set_expiration(db, trx);
|
||||
|
||||
ACTORS((alice)(bob));
|
||||
|
||||
upgrade_to_lifetime_member(alice);
|
||||
upgrade_to_lifetime_member(bob);
|
||||
|
||||
transfer( committee_account, alice_id, asset( 1000*GRAPHENE_BLOCKCHAIN_PRECISION ) );
|
||||
transfer( committee_account, bob_id, asset( 1000*GRAPHENE_BLOCKCHAIN_PRECISION ) );
|
||||
|
||||
set_expiration(db, trx);
|
||||
generate_block();
|
||||
// Now create SONs
|
||||
std::string test_url1 = "https://create_son_test1";
|
||||
std::string test_url2 = "https://create_son_test2";
|
||||
|
||||
// create deposit vesting
|
||||
vesting_balance_id_type deposit1;
|
||||
{
|
||||
vesting_balance_create_operation op;
|
||||
op.creator = alice_id;
|
||||
op.owner = alice_id;
|
||||
op.amount = asset(50*GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||
op.balance_type = vesting_balance_type::son;
|
||||
op.policy = dormant_vesting_policy_initializer {};
|
||||
|
||||
trx.operations.push_back(op);
|
||||
for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op);
|
||||
set_expiration(db, trx);
|
||||
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||
trx.clear();
|
||||
deposit1 = ptx.operation_results[0].get<object_id_type>();
|
||||
}
|
||||
|
||||
// create payment vesting
|
||||
vesting_balance_id_type payment1;
|
||||
{
|
||||
vesting_balance_create_operation op;
|
||||
op.creator = alice_id;
|
||||
op.owner = alice_id;
|
||||
op.amount = asset(1*GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||
op.balance_type = vesting_balance_type::normal;
|
||||
|
||||
trx.operations.push_back(op);
|
||||
for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op);
|
||||
set_expiration(db, trx);
|
||||
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||
trx.clear();
|
||||
payment1 = ptx.operation_results[0].get<object_id_type>();
|
||||
}
|
||||
|
||||
// create deposit vesting
|
||||
vesting_balance_id_type deposit2;
|
||||
{
|
||||
vesting_balance_create_operation op;
|
||||
op.creator = bob_id;
|
||||
op.owner = bob_id;
|
||||
op.amount = asset(50*GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||
op.balance_type = vesting_balance_type::son;
|
||||
op.policy = dormant_vesting_policy_initializer {};
|
||||
|
||||
trx.operations.push_back(op);
|
||||
for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op);
|
||||
set_expiration(db, trx);
|
||||
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||
trx.clear();
|
||||
deposit2 = ptx.operation_results[0].get<object_id_type>();
|
||||
}
|
||||
|
||||
// create payment vesting
|
||||
vesting_balance_id_type payment2;
|
||||
{
|
||||
vesting_balance_create_operation op;
|
||||
op.creator = bob_id;
|
||||
op.owner = bob_id;
|
||||
op.amount = asset(1*GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||
op.balance_type = vesting_balance_type::normal;
|
||||
|
||||
trx.operations.push_back(op);
|
||||
for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op);
|
||||
set_expiration(db, trx);
|
||||
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||
trx.clear();
|
||||
payment2 = ptx.operation_results[0].get<object_id_type>();
|
||||
}
|
||||
|
||||
// alice becomes son
|
||||
{
|
||||
son_create_operation op;
|
||||
op.owner_account = alice_id;
|
||||
op.url = test_url1;
|
||||
op.deposit = deposit1;
|
||||
op.pay_vb = payment1;
|
||||
op.fee = asset(0);
|
||||
op.signing_key = alice_public_key;
|
||||
trx.operations.push_back(op);
|
||||
for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op);
|
||||
sign(trx, alice_private_key);
|
||||
PUSH_TX(db, trx, ~0);
|
||||
trx.clear();
|
||||
}
|
||||
|
||||
// bob becomes son
|
||||
{
|
||||
son_create_operation op;
|
||||
op.owner_account = bob_id;
|
||||
op.url = test_url2;
|
||||
op.deposit = deposit2;
|
||||
op.pay_vb = payment2;
|
||||
op.fee = asset(0);
|
||||
op.signing_key = bob_public_key;
|
||||
trx.operations.push_back(op);
|
||||
for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op);
|
||||
sign(trx, bob_private_key);
|
||||
PUSH_TX(db, trx, ~0);
|
||||
trx.clear();
|
||||
}
|
||||
|
||||
generate_block();
|
||||
// Check if SONs are created properly
|
||||
const auto& idx = db.get_index_type<son_index>().indices().get<by_account>();
|
||||
BOOST_REQUIRE( idx.size() == 2 );
|
||||
// Alice's SON
|
||||
auto obj1 = idx.find( alice_id );
|
||||
BOOST_REQUIRE( obj1 != idx.end() );
|
||||
BOOST_CHECK( obj1->url == test_url1 );
|
||||
BOOST_CHECK( obj1->signing_key == alice_public_key );
|
||||
BOOST_CHECK( obj1->deposit.instance == deposit1.instance.value );
|
||||
BOOST_CHECK( obj1->pay_vb.instance == payment1.instance.value );
|
||||
// Bob's SON
|
||||
auto obj2 = idx.find( bob_id );
|
||||
BOOST_REQUIRE( obj2 != idx.end() );
|
||||
BOOST_CHECK( obj2->url == test_url2 );
|
||||
BOOST_CHECK( obj2->signing_key == bob_public_key );
|
||||
BOOST_CHECK( obj2->deposit.instance == deposit2.instance.value );
|
||||
BOOST_CHECK( obj2->pay_vb.instance == payment2.instance.value );
|
||||
// Get the statistics object for the SONs
|
||||
const auto& sidx = db.get_index_type<son_stats_index>().indices().get<by_id>();
|
||||
BOOST_REQUIRE( sidx.size() == 2 );
|
||||
auto son_stats_obj1 = sidx.find( obj1->statistics );
|
||||
auto son_stats_obj2 = sidx.find( obj2->statistics );
|
||||
BOOST_REQUIRE( son_stats_obj1 != sidx.end() );
|
||||
BOOST_REQUIRE( son_stats_obj2 != sidx.end() );
|
||||
|
||||
|
||||
// Modify SON's status to in_maintenance
|
||||
db.modify( *obj1, [&]( son_object& _s)
|
||||
{
|
||||
_s.status = son_status::in_maintenance;
|
||||
});
|
||||
|
||||
// Modify the Alice's SON down timestamp to now-12 hours
|
||||
db.modify( *son_stats_obj1, [&]( son_statistics_object& _s)
|
||||
{
|
||||
_s.last_down_timestamp = fc::time_point_sec(db.head_block_time() - fc::hours(12));
|
||||
});
|
||||
|
||||
// Modify SON's status to in_maintenance
|
||||
db.modify( *obj2, [&]( son_object& _s)
|
||||
{
|
||||
_s.status = son_status::in_maintenance;
|
||||
});
|
||||
|
||||
// Modify the Bob's SON down timestamp to now-12 hours
|
||||
db.modify( *son_stats_obj2, [&]( son_statistics_object& _s)
|
||||
{
|
||||
_s.last_down_timestamp = fc::time_point_sec(db.head_block_time() - fc::hours(12));
|
||||
});
|
||||
|
||||
const auto& son_proposal_idx = db.get_index_type<son_proposal_index>().indices().get<by_id>();
|
||||
const auto& proposal_idx = db.get_index_type<proposal_index>().indices().get<by_id>();
|
||||
|
||||
BOOST_CHECK( son_proposal_idx.size() == 0 && proposal_idx.size() == 0 );
|
||||
|
||||
generate_block();
|
||||
witness_id_type proposal_initiator = dpo.current_witness;
|
||||
|
||||
BOOST_CHECK( son_proposal_idx.size() == 2 && proposal_idx.size() == 2 );
|
||||
|
||||
for(size_t i = 0 ; i < 3 * db.get_global_properties().active_witnesses.size() ; i++ )
|
||||
{
|
||||
generate_block();
|
||||
if( dpo.current_witness != proposal_initiator)
|
||||
{
|
||||
BOOST_CHECK( son_proposal_idx.size() == 2 && proposal_idx.size() == 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
BOOST_CHECK( son_proposal_idx.size() == 0 && proposal_idx.size() == 0 );
|
||||
BOOST_REQUIRE( idx.size() == 0 );
|
||||
generate_block();
|
||||
} FC_LOG_AND_RETHROW()
|
||||
|
||||
} BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
|||
Loading…
Reference in a new issue