Progress #31: Initial work on new cashback system
Lots still to do. There's no longer a way to upgrade an account, genesis can't evaluate, and who knows how many tests are failing... But it builds!
This commit is contained in:
parent
fa26e39e10
commit
ed7d485df3
21 changed files with 337 additions and 278 deletions
|
|
@ -24,22 +24,13 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
void_result account_create_evaluator::do_evaluate( const account_create_operation& op )
|
void_result account_create_evaluator::do_evaluate( const account_create_operation& op )
|
||||||
{ try {
|
{ try {
|
||||||
FC_ASSERT( db().find_object(op.voting_account) );
|
database& d = db();
|
||||||
FC_ASSERT( is_relative(op.memo_key) || db().find_object(op.memo_key) );
|
FC_ASSERT( d.find_object(op.voting_account) );
|
||||||
|
FC_ASSERT( is_relative(op.memo_key) || d.find_object(op.memo_key) );
|
||||||
|
FC_ASSERT( fee_paying_account->is_lifetime_member() );
|
||||||
|
FC_ASSERT( op.referrer(d).is_member(d.head_block_time()) );
|
||||||
|
|
||||||
if( fee_paying_account->is_prime() )
|
const auto& global_props = d.get_global_properties();
|
||||||
{
|
|
||||||
FC_ASSERT( op.referrer(db()).is_prime() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FC_ASSERT( op.referrer == fee_paying_account->referrer );
|
|
||||||
FC_ASSERT( op.referrer_percent == fee_paying_account->referrer_percent, "",
|
|
||||||
("op",op)
|
|
||||||
("fee_paying_account->referral_percent",fee_paying_account->referrer_percent) );
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& global_props = db().get_global_properties();
|
|
||||||
uint32_t max_vote_id = global_props.next_available_vote_id;
|
uint32_t max_vote_id = global_props.next_available_vote_id;
|
||||||
const auto& chain_params = global_props.parameters;
|
const auto& chain_params = global_props.parameters;
|
||||||
FC_ASSERT( op.num_witness <= chain_params.maximum_witness_count );
|
FC_ASSERT( op.num_witness <= chain_params.maximum_witness_count );
|
||||||
|
|
@ -48,11 +39,11 @@ void_result account_create_evaluator::do_evaluate( const account_create_operatio
|
||||||
FC_ASSERT( op.active.auths.size() <= chain_params.maximum_authority_membership );
|
FC_ASSERT( op.active.auths.size() <= chain_params.maximum_authority_membership );
|
||||||
for( auto id : op.owner.auths )
|
for( auto id : op.owner.auths )
|
||||||
{
|
{
|
||||||
FC_ASSERT( is_relative(id.first) || db().find<object>(id.first) );
|
FC_ASSERT( is_relative(id.first) || d.find_object(id.first) );
|
||||||
}
|
}
|
||||||
for( auto id : op.active.auths )
|
for( auto id : op.active.auths )
|
||||||
{
|
{
|
||||||
FC_ASSERT( is_relative(id.first) || db().find<object>(id.first) );
|
FC_ASSERT( is_relative(id.first) || d.find_object(id.first) );
|
||||||
}
|
}
|
||||||
safe<uint32_t> counts[vote_id_type::VOTE_TYPE_COUNT];
|
safe<uint32_t> counts[vote_id_type::VOTE_TYPE_COUNT];
|
||||||
for( auto id : op.vote )
|
for( auto id : op.vote )
|
||||||
|
|
@ -67,7 +58,7 @@ void_result account_create_evaluator::do_evaluate( const account_create_operatio
|
||||||
"",
|
"",
|
||||||
("count", counts[vote_id_type::committee])("num", op.num_committee));
|
("count", counts[vote_id_type::committee])("num", op.num_committee));
|
||||||
|
|
||||||
auto& acnt_indx = db().get_index_type<account_index>();
|
auto& acnt_indx = d.get_index_type<account_index>();
|
||||||
if( op.name.size() )
|
if( op.name.size() )
|
||||||
{
|
{
|
||||||
auto current_account_itr = acnt_indx.indices().get<by_name>().find( op.name );
|
auto current_account_itr = acnt_indx.indices().get<by_name>().find( op.name );
|
||||||
|
|
@ -76,7 +67,7 @@ void_result account_create_evaluator::do_evaluate( const account_create_operatio
|
||||||
|
|
||||||
// TODO: this check can be removed after GRAPHENE_LEGACY_NAME_IMPORT_PERIOD
|
// TODO: this check can be removed after GRAPHENE_LEGACY_NAME_IMPORT_PERIOD
|
||||||
// legacy account check
|
// legacy account check
|
||||||
if( db().get_dynamic_global_properties().head_block_number < GRAPHENE_LEGACY_NAME_IMPORT_PERIOD )
|
if( d.get_dynamic_global_properties().head_block_number < GRAPHENE_LEGACY_NAME_IMPORT_PERIOD )
|
||||||
{
|
{
|
||||||
auto legacy_account_itr = acnt_indx.indices().get<by_name>().find( "bts-"+op.name );
|
auto legacy_account_itr = acnt_indx.indices().get<by_name>().find( "bts-"+op.name );
|
||||||
if( legacy_account_itr != acnt_indx.indices().get<by_name>().end() )
|
if( legacy_account_itr != acnt_indx.indices().get<by_name>().end() )
|
||||||
|
|
@ -109,18 +100,15 @@ object_id_type account_create_evaluator::do_apply( const account_create_operatio
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto& new_acnt_object = db().create<account_object>( [&]( account_object& obj ){
|
const auto& new_acnt_object = db().create<account_object>( [&]( account_object& obj ){
|
||||||
if( fee_paying_account->is_prime() )
|
obj.registrar = o.registrar;
|
||||||
{
|
obj.referrer = o.referrer;
|
||||||
obj.registrar = o.registrar;
|
obj.lifetime_referrer = o.referrer(db()).lifetime_referrer;
|
||||||
obj.referrer = o.referrer;
|
|
||||||
obj.referrer_percent = o.referrer_percent;
|
auto& params = db().get_global_properties().parameters;
|
||||||
}
|
obj.network_fee_percentage = params.network_percent_of_fee;
|
||||||
else
|
obj.lifetime_referrer_fee_percentage = params.lifetime_referrer_percent_of_fee;
|
||||||
{
|
obj.referrer_rewards_percentage = o.referrer_percent;
|
||||||
obj.registrar = fee_paying_account->registrar;
|
|
||||||
obj.referrer = fee_paying_account->referrer;
|
|
||||||
obj.referrer_percent = fee_paying_account->referrer_percent;
|
|
||||||
}
|
|
||||||
obj.name = o.name;
|
obj.name = o.name;
|
||||||
obj.owner = owner;
|
obj.owner = owner;
|
||||||
obj.active = active;
|
obj.active = active;
|
||||||
|
|
@ -138,7 +126,7 @@ object_id_type account_create_evaluator::do_apply( const account_create_operatio
|
||||||
|
|
||||||
void_result account_update_evaluator::do_evaluate( const account_update_operation& o )
|
void_result account_update_evaluator::do_evaluate( const account_update_operation& o )
|
||||||
{
|
{
|
||||||
database& d = db();
|
database& d = db();
|
||||||
|
|
||||||
FC_ASSERT( !o.memo_key || is_relative(*o.memo_key) || db().find_object(*o.memo_key) );
|
FC_ASSERT( !o.memo_key || is_relative(*o.memo_key) || db().find_object(*o.memo_key) );
|
||||||
|
|
||||||
|
|
@ -163,7 +151,6 @@ void_result account_update_evaluator::do_evaluate( const account_update_operatio
|
||||||
}
|
}
|
||||||
|
|
||||||
acnt = &o.account(d);
|
acnt = &o.account(d);
|
||||||
if( o.upgrade_to_prime ) FC_ASSERT( !acnt->is_prime() );
|
|
||||||
|
|
||||||
if( o.vote )
|
if( o.vote )
|
||||||
{
|
{
|
||||||
|
|
@ -184,11 +171,6 @@ void_result account_update_evaluator::do_apply( const account_update_operation&
|
||||||
if( o.voting_account ) a.voting_account = *o.voting_account;
|
if( o.voting_account ) a.voting_account = *o.voting_account;
|
||||||
if( o.memo_key ) a.memo_key = *o.memo_key;
|
if( o.memo_key ) a.memo_key = *o.memo_key;
|
||||||
if( o.vote ) a.votes = *o.vote;
|
if( o.vote ) a.votes = *o.vote;
|
||||||
if( o.upgrade_to_prime )
|
|
||||||
{
|
|
||||||
a.referrer_percent = 100;
|
|
||||||
a.referrer = a.id;
|
|
||||||
}
|
|
||||||
a.num_witness = o.num_witness;
|
a.num_witness = o.num_witness;
|
||||||
a.num_committee = o.num_committee;
|
a.num_committee = o.num_committee;
|
||||||
});
|
});
|
||||||
|
|
@ -200,8 +182,8 @@ void_result account_whitelist_evaluator::do_evaluate(const account_whitelist_ope
|
||||||
database& d = db();
|
database& d = db();
|
||||||
|
|
||||||
listed_account = &o.account_to_list(d);
|
listed_account = &o.account_to_list(d);
|
||||||
if( !d.get_global_properties().parameters.allow_non_prime_whitelists )
|
if( !d.get_global_properties().parameters.allow_non_member_whitelists )
|
||||||
FC_ASSERT(listed_account->is_prime());
|
FC_ASSERT(o.authorizing_account(d).is_lifetime_member());
|
||||||
|
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||||
|
|
|
||||||
|
|
@ -174,74 +174,6 @@ void database::update_active_delegates()
|
||||||
});
|
});
|
||||||
} FC_CAPTURE_AND_RETHROW() }
|
} FC_CAPTURE_AND_RETHROW() }
|
||||||
|
|
||||||
void database::update_vote_totals(const global_property_object& props)
|
|
||||||
{ try {
|
|
||||||
_vote_tally_buffer.resize(props.next_available_vote_id);
|
|
||||||
_witness_count_histogram_buffer.resize(props.parameters.maximum_witness_count / 2 + 1);
|
|
||||||
_committee_count_histogram_buffer.resize(props.parameters.maximum_committee_count / 2 + 1);
|
|
||||||
|
|
||||||
const account_index& account_idx = get_index_type<account_index>();
|
|
||||||
_total_voting_stake = 0;
|
|
||||||
|
|
||||||
bool count_non_prime_votes = props.parameters.count_non_prime_votes;
|
|
||||||
auto timestamp = fc::time_point::now();
|
|
||||||
for( const account_object& stake_account : account_idx.indices() )
|
|
||||||
{
|
|
||||||
if( count_non_prime_votes || stake_account.is_prime() )
|
|
||||||
{
|
|
||||||
// There may be a difference between the account whose stake is voting and the one specifying opinions.
|
|
||||||
// Usually they're the same, but if the stake account has specified a voting_account, that account is the one
|
|
||||||
// specifying the opinions.
|
|
||||||
const account_object& opinion_account =
|
|
||||||
(stake_account.voting_account == account_id_type())? stake_account
|
|
||||||
: get(stake_account.voting_account);
|
|
||||||
|
|
||||||
const auto& stats = stake_account.statistics(*this);
|
|
||||||
uint64_t voting_stake = stats.total_core_in_orders.value
|
|
||||||
+ (stake_account.cashback_vb.valid() ? (*stake_account.cashback_vb)(*this).balance.amount.value: 0)
|
|
||||||
+ get_balance(stake_account.get_id(), asset_id_type()).amount.value;
|
|
||||||
|
|
||||||
for( vote_id_type id : opinion_account.votes )
|
|
||||||
{
|
|
||||||
uint32_t offset = id.instance();
|
|
||||||
// if they somehow managed to specify an illegal offset, ignore it.
|
|
||||||
if( offset < _vote_tally_buffer.size() )
|
|
||||||
_vote_tally_buffer[ offset ] += voting_stake;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( opinion_account.num_witness <= props.parameters.maximum_witness_count )
|
|
||||||
{
|
|
||||||
uint16_t offset = std::min(size_t(opinion_account.num_witness/2),
|
|
||||||
_witness_count_histogram_buffer.size() - 1);
|
|
||||||
//
|
|
||||||
// votes for a number greater than maximum_witness_count
|
|
||||||
// are turned into votes for maximum_witness_count.
|
|
||||||
//
|
|
||||||
// in particular, this takes care of the case where a
|
|
||||||
// member was voting for a high number, then the
|
|
||||||
// parameter was lowered.
|
|
||||||
//
|
|
||||||
_witness_count_histogram_buffer[ offset ] += voting_stake;
|
|
||||||
}
|
|
||||||
if( opinion_account.num_committee <= props.parameters.maximum_committee_count )
|
|
||||||
{
|
|
||||||
uint16_t offset = std::min(size_t(opinion_account.num_committee/2),
|
|
||||||
_committee_count_histogram_buffer.size() - 1);
|
|
||||||
//
|
|
||||||
// votes for a number greater than maximum_committee_count
|
|
||||||
// are turned into votes for maximum_committee_count.
|
|
||||||
//
|
|
||||||
// same rationale as for witnesses
|
|
||||||
//
|
|
||||||
_committee_count_histogram_buffer[ offset ] += voting_stake;
|
|
||||||
}
|
|
||||||
|
|
||||||
_total_voting_stake += voting_stake;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ilog("Tallied votes in ${time} milliseconds.", ("time", (fc::time_point::now() - timestamp).count() / 1000.0));
|
|
||||||
} FC_CAPTURE_AND_RETHROW() }
|
|
||||||
|
|
||||||
share_type database::get_max_budget( fc::time_point_sec now )const
|
share_type database::get_max_budget( fc::time_point_sec now )const
|
||||||
{
|
{
|
||||||
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
||||||
|
|
@ -352,7 +284,154 @@ void database::process_budget()
|
||||||
|
|
||||||
void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props)
|
void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props)
|
||||||
{
|
{
|
||||||
update_vote_totals(global_props);
|
const auto& gpo = get_global_properties();
|
||||||
|
|
||||||
|
struct vote_tally_helper {
|
||||||
|
database& d;
|
||||||
|
const global_property_object& props;
|
||||||
|
|
||||||
|
vote_tally_helper(database& d, const global_property_object& gpo)
|
||||||
|
: d(d), props(gpo)
|
||||||
|
{
|
||||||
|
d._vote_tally_buffer.resize(props.next_available_vote_id);
|
||||||
|
d._witness_count_histogram_buffer.resize(props.parameters.maximum_witness_count / 2 + 1);
|
||||||
|
d._committee_count_histogram_buffer.resize(props.parameters.maximum_committee_count / 2 + 1);
|
||||||
|
d._total_voting_stake = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const account_object& stake_account) {
|
||||||
|
if( props.parameters.count_non_member_votes || stake_account.is_member(d.head_block_time()) )
|
||||||
|
{
|
||||||
|
// There may be a difference between the account whose stake is voting and the one specifying opinions.
|
||||||
|
// Usually they're the same, but if the stake account has specified a voting_account, that account is the one
|
||||||
|
// specifying the opinions.
|
||||||
|
const account_object& opinion_account =
|
||||||
|
(stake_account.voting_account == account_id_type())? stake_account
|
||||||
|
: d.get(stake_account.voting_account);
|
||||||
|
|
||||||
|
const auto& stats = stake_account.statistics(d);
|
||||||
|
uint64_t voting_stake = stats.total_core_in_orders.value
|
||||||
|
+ (stake_account.cashback_vb.valid() ? (*stake_account.cashback_vb)(d).balance.amount.value: 0)
|
||||||
|
+ d.get_balance(stake_account.get_id(), asset_id_type()).amount.value;
|
||||||
|
|
||||||
|
for( vote_id_type id : opinion_account.votes )
|
||||||
|
{
|
||||||
|
uint32_t offset = id.instance();
|
||||||
|
// if they somehow managed to specify an illegal offset, ignore it.
|
||||||
|
if( offset < d._vote_tally_buffer.size() )
|
||||||
|
d._vote_tally_buffer[ offset ] += voting_stake;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( opinion_account.num_witness <= props.parameters.maximum_witness_count )
|
||||||
|
{
|
||||||
|
uint16_t offset = std::min(size_t(opinion_account.num_witness/2),
|
||||||
|
d._witness_count_histogram_buffer.size() - 1);
|
||||||
|
// votes for a number greater than maximum_witness_count
|
||||||
|
// are turned into votes for maximum_witness_count.
|
||||||
|
//
|
||||||
|
// in particular, this takes care of the case where a
|
||||||
|
// member was voting for a high number, then the
|
||||||
|
// parameter was lowered.
|
||||||
|
d._witness_count_histogram_buffer[ offset ] += voting_stake;
|
||||||
|
}
|
||||||
|
if( opinion_account.num_committee <= props.parameters.maximum_committee_count )
|
||||||
|
{
|
||||||
|
uint16_t offset = std::min(size_t(opinion_account.num_committee/2),
|
||||||
|
d._committee_count_histogram_buffer.size() - 1);
|
||||||
|
// votes for a number greater than maximum_committee_count
|
||||||
|
// are turned into votes for maximum_committee_count.
|
||||||
|
//
|
||||||
|
// same rationale as for witnesses
|
||||||
|
d._committee_count_histogram_buffer[ offset ] += voting_stake;
|
||||||
|
}
|
||||||
|
|
||||||
|
d._total_voting_stake += voting_stake;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} tally_helper(*this, gpo);
|
||||||
|
struct process_fees_helper {
|
||||||
|
database& d;
|
||||||
|
const global_property_object& props;
|
||||||
|
|
||||||
|
process_fees_helper(database& d, const global_property_object& gpo)
|
||||||
|
: d(d), props(gpo) {}
|
||||||
|
|
||||||
|
void operator()(const account_object& a) {
|
||||||
|
const account_statistics_object& stats = a.statistics(d);
|
||||||
|
|
||||||
|
auto cut_fee = [](share_type a, uint16_t p) -> share_type
|
||||||
|
{
|
||||||
|
fc::uint128 r(a.value);
|
||||||
|
r *= p;
|
||||||
|
r /= GRAPHENE_100_PERCENT;
|
||||||
|
return r.to_uint64();
|
||||||
|
};
|
||||||
|
|
||||||
|
if( stats.pending_fees > 0 )
|
||||||
|
{
|
||||||
|
share_type core_fee_subtotal(stats.pending_fees);
|
||||||
|
share_type bulk_cashback = share_type(0);
|
||||||
|
if( stats.lifetime_fees_paid > props.parameters.bulk_discount_threshold_min &&
|
||||||
|
a.is_member(d.head_block_time()) )
|
||||||
|
{
|
||||||
|
uint64_t bulk_discount_percent = 0;
|
||||||
|
if( stats.lifetime_fees_paid >= props.parameters.bulk_discount_threshold_max )
|
||||||
|
bulk_discount_percent = props.parameters.max_bulk_discount_percent_of_fee;
|
||||||
|
else if(props.parameters.bulk_discount_threshold_max.value !=
|
||||||
|
props.parameters.bulk_discount_threshold_min.value)
|
||||||
|
{
|
||||||
|
bulk_discount_percent =
|
||||||
|
(props.parameters.max_bulk_discount_percent_of_fee *
|
||||||
|
(stats.lifetime_fees_paid.value -
|
||||||
|
props.parameters.bulk_discount_threshold_min.value)) /
|
||||||
|
(props.parameters.bulk_discount_threshold_max.value -
|
||||||
|
props.parameters.bulk_discount_threshold_min.value);
|
||||||
|
}
|
||||||
|
assert( bulk_discount_percent <= GRAPHENE_100_PERCENT );
|
||||||
|
assert( bulk_discount_percent >= 0 );
|
||||||
|
|
||||||
|
bulk_cashback = cut_fee(core_fee_subtotal, bulk_discount_percent);
|
||||||
|
assert( bulk_cashback <= core_fee_subtotal );
|
||||||
|
}
|
||||||
|
|
||||||
|
share_type core_fee_total = core_fee_subtotal - bulk_cashback;
|
||||||
|
share_type network_cut = cut_fee(core_fee_total, a.network_fee_percentage);
|
||||||
|
assert( network_cut <= core_fee_total );
|
||||||
|
share_type burned = cut_fee(network_cut, props.parameters.burn_percent_of_fee);
|
||||||
|
share_type accumulated = network_cut - burned;
|
||||||
|
assert( accumulated + burned == network_cut );
|
||||||
|
share_type referral = core_fee_total - network_cut;
|
||||||
|
|
||||||
|
d.modify(dynamic_asset_data_id_type()(d), [burned,accumulated](asset_dynamic_data_object& d) {
|
||||||
|
d.accumulated_fees += accumulated + burned;
|
||||||
|
});
|
||||||
|
|
||||||
|
d.modify(a.statistics(d), [core_fee_total](account_statistics_object& s) {
|
||||||
|
s.lifetime_fees_paid += core_fee_total;
|
||||||
|
s.pending_fees = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
d.deposit_cashback( a, bulk_cashback );
|
||||||
|
|
||||||
|
assert( referral + bulk_cashback + accumulated + burned == core_fee_subtotal );
|
||||||
|
|
||||||
|
// Potential optimization: Skip some of this math and object lookups by special casing on the account type.
|
||||||
|
// For example, if the account is a lifetime member, we can skip all this and just deposit the referral to
|
||||||
|
// it directly.
|
||||||
|
share_type lifetime_cut = cut_fee(referral, a.lifetime_referrer_fee_percentage);
|
||||||
|
share_type referrer_cut = cut_fee(referral, a.referrer_rewards_percentage);
|
||||||
|
share_type registrar_cut = referral - lifetime_cut = referrer_cut;
|
||||||
|
|
||||||
|
d.deposit_cashback(d.get(a.lifetime_referrer), lifetime_cut);
|
||||||
|
d.deposit_cashback(d.get(a.referrer), referrer_cut);
|
||||||
|
d.deposit_cashback(d.get(a.registrar), registrar_cut);
|
||||||
|
|
||||||
|
assert( lifetime_cut + referrer_cut + registrar_cut == referral );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} fees_helper(*this, gpo);
|
||||||
|
|
||||||
|
perform_account_maintenance(std::tie(tally_helper, fees_helper));
|
||||||
|
|
||||||
struct clear_canary {
|
struct clear_canary {
|
||||||
clear_canary(vector<uint64_t>& target): target(target){}
|
clear_canary(vector<uint64_t>& target): target(target){}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
object_id_type delegate_create_evaluator::do_evaluate( const delegate_create_operation& op )
|
object_id_type delegate_create_evaluator::do_evaluate( const delegate_create_operation& op )
|
||||||
{
|
{
|
||||||
FC_ASSERT(db().get(op.delegate_account).is_prime());
|
FC_ASSERT(db().get(op.delegate_account).is_lifetime_member());
|
||||||
return object_id_type();
|
return object_id_type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,55 +61,14 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
void generic_evaluator::pay_fee()
|
void generic_evaluator::pay_fee()
|
||||||
{ try {
|
{ try {
|
||||||
asset core_fee_subtotal(core_fee_paid);
|
|
||||||
const auto& gp = db().get_global_properties();
|
|
||||||
share_type bulk_cashback = share_type(0);
|
|
||||||
if( fee_paying_account_statistics->lifetime_fees_paid > gp.parameters.bulk_discount_threshold_min &&
|
|
||||||
fee_paying_account->is_prime() )
|
|
||||||
{
|
|
||||||
uint64_t bulk_discount_percent = 0;
|
|
||||||
if( fee_paying_account_statistics->lifetime_fees_paid > gp.parameters.bulk_discount_threshold_max )
|
|
||||||
bulk_discount_percent = gp.parameters.max_bulk_discount_percent_of_fee;
|
|
||||||
else if(gp.parameters.bulk_discount_threshold_max.value - gp.parameters.bulk_discount_threshold_min.value != 0)
|
|
||||||
{
|
|
||||||
bulk_discount_percent =
|
|
||||||
(gp.parameters.max_bulk_discount_percent_of_fee *
|
|
||||||
(fee_paying_account_statistics->lifetime_fees_paid.value -
|
|
||||||
gp.parameters.bulk_discount_threshold_min.value)) /
|
|
||||||
(gp.parameters.bulk_discount_threshold_max.value - gp.parameters.bulk_discount_threshold_min.value);
|
|
||||||
}
|
|
||||||
assert( bulk_discount_percent <= GRAPHENE_100_PERCENT );
|
|
||||||
assert( bulk_discount_percent >= 0 );
|
|
||||||
|
|
||||||
bulk_cashback = (core_fee_subtotal.amount.value * bulk_discount_percent) / GRAPHENE_100_PERCENT;
|
|
||||||
assert( bulk_cashback <= core_fee_subtotal.amount );
|
|
||||||
}
|
|
||||||
|
|
||||||
share_type core_fee_total = core_fee_subtotal.amount - bulk_cashback;
|
|
||||||
share_type accumulated = (core_fee_total.value * gp.parameters.witness_percent_of_fee)/GRAPHENE_100_PERCENT;
|
|
||||||
share_type burned = (core_fee_total.value * gp.parameters.burn_percent_of_fee)/GRAPHENE_100_PERCENT;
|
|
||||||
share_type referral = core_fee_total.value - accumulated - burned;
|
|
||||||
auto& d = db();
|
|
||||||
|
|
||||||
assert( accumulated + burned <= core_fee_total );
|
|
||||||
|
|
||||||
if( fee_asset->get_id() != asset_id_type() )
|
if( fee_asset->get_id() != asset_id_type() )
|
||||||
d.modify(*fee_asset_dyn_data, [this](asset_dynamic_data_object& d) {
|
db().modify(*fee_asset_dyn_data, [this](asset_dynamic_data_object& d) {
|
||||||
d.accumulated_fees += fee_from_account.amount;
|
d.accumulated_fees += fee_from_account.amount;
|
||||||
d.fee_pool -= core_fee_paid;
|
d.fee_pool -= core_fee_paid;
|
||||||
});
|
});
|
||||||
d.modify(dynamic_asset_data_id_type()(d), [burned,accumulated](asset_dynamic_data_object& d) {
|
db().modify(*fee_paying_account_statistics, [&](account_statistics_object& s) {
|
||||||
d.accumulated_fees += accumulated + burned;
|
s.pending_fees += core_fee_paid;
|
||||||
});
|
});
|
||||||
|
|
||||||
d.modify(fee_paying_account->statistics(d), [core_fee_total](account_statistics_object& s) {
|
|
||||||
s.lifetime_fees_paid += core_fee_total;
|
|
||||||
});
|
|
||||||
|
|
||||||
d.deposit_cashback( fee_paying_account->referrer(d), referral );
|
|
||||||
d.deposit_cashback( *fee_paying_account, bulk_cashback );
|
|
||||||
|
|
||||||
assert( referral + bulk_cashback + accumulated + burned == core_fee_subtotal.amount );
|
|
||||||
} FC_CAPTURE_AND_RETHROW() }
|
} FC_CAPTURE_AND_RETHROW() }
|
||||||
|
|
||||||
bool generic_evaluator::verify_authority( const account_object& a, authority::classification c )
|
bool generic_evaluator::verify_authority( const account_object& a, authority::classification c )
|
||||||
|
|
|
||||||
|
|
@ -39,32 +39,34 @@ namespace graphene { namespace chain {
|
||||||
static const uint8_t type_id = impl_account_statistics_object_type;
|
static const uint8_t type_id = impl_account_statistics_object_type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep the most recent operation as a root pointer to
|
* Keep the most recent operation as a root pointer to a linked list of the transaction history. This field is
|
||||||
* a linked list of the transaction history. This field is
|
* not required by core validation and could in theory be made an annotation on the account object, but
|
||||||
* not required by core validation and could in theory be
|
* because transaction history is so common and this object is already cached in the undo buffer (because it
|
||||||
* made an annotation on the account object, but because
|
* likely affected the balances of this account) it is convienent to simply track this data here. Account
|
||||||
* transaction history is so common and this object is already
|
* balance objects don't currenty inherit from annotated object.
|
||||||
* cached in the undo buffer (because it likely affected the
|
|
||||||
* balances of this account) it is convienent to simply
|
|
||||||
* track this data here. Account balance objects don't currenty
|
|
||||||
* inherit from annotated object.
|
|
||||||
*/
|
*/
|
||||||
account_transaction_history_id_type most_recent_op;
|
account_transaction_history_id_type most_recent_op;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When calculating votes it is necessary to know how much is
|
* When calculating votes it is necessary to know how much is stored in orders (and thus unavailable for
|
||||||
* stored in orders (and thus unavailable for transfers). Rather
|
* transfers). Rather than maintaining an index of [asset,owner,order_id] we will simply maintain the running
|
||||||
* than maintaining an index of [asset,owner,order_id] we will
|
* total here and update it every time an order is created or modified.
|
||||||
* simply maintain the running total here and update it every
|
|
||||||
* time an order is created or modified.
|
|
||||||
*/
|
*/
|
||||||
share_type total_core_in_orders;
|
share_type total_core_in_orders;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks the total fees paid by this account for the purpose
|
* Tracks the total fees paid by this account for the purpose of calculating bulk discounts.
|
||||||
* of calculating bulk discounts.
|
|
||||||
*/
|
*/
|
||||||
share_type lifetime_fees_paid;
|
share_type lifetime_fees_paid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks the fees paid by this account which have not been disseminated to the various parties that receive
|
||||||
|
* them yet (registrar, referrer, lifetime referrer, network, etc). This is used as an optimization to avoid
|
||||||
|
* doing massive amounts of uint128 math on each and every operation.
|
||||||
|
*
|
||||||
|
* These fees will be paid out and this counter will reset during the maintenance interval.
|
||||||
|
*/
|
||||||
|
share_type pending_fees;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -102,53 +104,54 @@ namespace graphene { namespace chain {
|
||||||
public:
|
public:
|
||||||
static const uint8_t space_id = protocol_ids;
|
static const uint8_t space_id = protocol_ids;
|
||||||
static const uint8_t type_id = account_object_type;
|
static const uint8_t type_id = account_object_type;
|
||||||
/**
|
|
||||||
* The account that paid the fee to register this account, this account is
|
|
||||||
* known as the primary referrer and is entitled to a percent of transaction
|
|
||||||
* fees.
|
|
||||||
*/
|
|
||||||
account_id_type registrar;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The registrar may be a faucet with its own revenue sharing model that allows
|
* The time at which this account's membership expires.
|
||||||
* users to refer each other.
|
* If set to any time in the past, the account is a basic account.
|
||||||
|
* If set to time_point_sec::maximum(), the account is a lifetime member.
|
||||||
|
* If set to any time not in the past less than time_point_sec::maximum(), the account is an annual member.
|
||||||
|
*
|
||||||
|
* See @ref is_lifetime_member, @ref is_basic_account, @ref is_annual_member, and @ref is_member
|
||||||
*/
|
*/
|
||||||
account_id_type referrer;
|
time_point_sec membership_expiration_date;
|
||||||
|
|
||||||
/**
|
///The account that paid the fee to register this account. Receives a percentage of referral rewards.
|
||||||
* Any referral fees not paid to referrer are paid to registrar
|
account_id_type registrar;
|
||||||
*/
|
/// The account credited as referring this account. Receives a percentage of referral rewards.
|
||||||
uint8_t referrer_percent = 0;
|
account_id_type referrer;
|
||||||
|
/// The lifetime member at the top of the referral tree. Receives a percentage of referral rewards.
|
||||||
|
account_id_type lifetime_referrer;
|
||||||
|
|
||||||
|
/// Percentage of fee which should go to network.
|
||||||
|
uint16_t network_fee_percentage;
|
||||||
|
/// Percentage of fee which should go to lifetime referrer.
|
||||||
|
uint16_t lifetime_referrer_fee_percentage = 0;
|
||||||
|
/// Percentage of referral rewards (leftover fee after paying network and lifetime referrer) which should go
|
||||||
|
/// to referrer. The remainder of referral rewards goes to the registrar.
|
||||||
|
uint16_t referrer_rewards_percentage = 0;
|
||||||
|
|
||||||
/// The account's name. This name must be unique among all account names on the graph. The name may be empty.
|
/// The account's name. This name must be unique among all account names on the graph. May not be empty.
|
||||||
string name;
|
string name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The owner authority represents absolute control over the account. Usually the keys in this authority will
|
* The owner authority represents absolute control over the account. Usually the keys in this authority will
|
||||||
* be kept in cold storage, as they should not be needed very often and compromise of these keys constitutes
|
* be kept in cold storage, as they should not be needed very often and compromise of these keys constitutes
|
||||||
* complete and irrevocable loss of the account. Generally the only time the owner authority is required is to
|
* complete and irrevocable loss of the account. Generally the only time the owner authority is required is to
|
||||||
* update the active authority.
|
* update the active authority.
|
||||||
*/
|
*/
|
||||||
authority owner;
|
authority owner;
|
||||||
|
|
||||||
/// The owner authority contains the hot keys of the account. This authority has control over nearly all
|
/// The owner authority contains the hot keys of the account. This authority has control over nearly all
|
||||||
/// operations the account may perform.
|
/// operations the account may perform.
|
||||||
authority active;
|
authority active;
|
||||||
|
|
||||||
/// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non-
|
/// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non-
|
||||||
/// validated account activities. This field is here to prevent confusion if the active authority has zero or
|
/// validated account activities. This field is here to prevent confusion if the active authority has zero or
|
||||||
/// multiple keys in it.
|
/// multiple keys in it.
|
||||||
key_id_type memo_key;
|
key_id_type memo_key;
|
||||||
|
|
||||||
/// If this field is set to an account ID other than 0, this account's votes will be ignored and its stake
|
/// If this field is set to an account ID other than 0, this account's votes will be ignored and its stake
|
||||||
/// will be counted as voting for the referenced account's selected votes instead.
|
/// will be counted as voting for the referenced account's selected votes instead.
|
||||||
account_id_type voting_account;
|
account_id_type voting_account;
|
||||||
|
|
||||||
|
|
||||||
uint16_t num_witness = 0;
|
|
||||||
uint16_t num_committee = 0;
|
|
||||||
|
|
||||||
|
uint16_t num_witness = 0;
|
||||||
|
uint16_t num_committee = 0;
|
||||||
/// This is the list of vote IDs this account votes for. The weight of these votes is determined by this
|
/// This is the list of vote IDs this account votes for. The weight of these votes is determined by this
|
||||||
/// account's balance of core asset.
|
/// account's balance of core asset.
|
||||||
flat_set<vote_id_type> votes;
|
flat_set<vote_id_type> votes;
|
||||||
|
|
@ -163,7 +166,7 @@ namespace graphene { namespace chain {
|
||||||
* account cannot update this set, except by transferring ownership of the account, which will clear it. Other
|
* account cannot update this set, except by transferring ownership of the account, which will clear it. Other
|
||||||
* accounts may add or remove their IDs from this set.
|
* accounts may add or remove their IDs from this set.
|
||||||
*/
|
*/
|
||||||
flat_set<account_id_type> whitelisting_accounts;
|
flat_set<account_id_type> whitelisting_accounts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a set of all accounts which have 'blacklisted' this account. Blacklisting is only used in core
|
* This is a set of all accounts which have 'blacklisted' this account. Blacklisting is only used in core
|
||||||
|
|
@ -171,20 +174,34 @@ namespace graphene { namespace chain {
|
||||||
* account cannot update this set, and it will be preserved even if the account is transferred. Other accounts
|
* account cannot update this set, and it will be preserved even if the account is transferred. Other accounts
|
||||||
* may add or remove their IDs from this set.
|
* may add or remove their IDs from this set.
|
||||||
*/
|
*/
|
||||||
flat_set<account_id_type> blacklisting_accounts;
|
flat_set<account_id_type> blacklisting_accounts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vesting balance which receives cashback_reward deposits.
|
* Vesting balance which receives cashback_reward deposits.
|
||||||
*/
|
*/
|
||||||
optional<vesting_balance_id_type> cashback_vb;
|
optional<vesting_balance_id_type> cashback_vb;
|
||||||
|
|
||||||
/**
|
/// @return true if this is a lifetime member account; false otherwise.
|
||||||
* @return true if this is a prime account, false otherwise.
|
bool is_lifetime_member()const
|
||||||
*/
|
|
||||||
bool is_prime()const
|
|
||||||
{
|
{
|
||||||
return get_id() == referrer;
|
return get_id() == referrer;
|
||||||
}
|
}
|
||||||
|
/// @return true if this is a basic account; false otherwise.
|
||||||
|
bool is_basic_account(time_point_sec now)const
|
||||||
|
{
|
||||||
|
return now > membership_expiration_date;
|
||||||
|
}
|
||||||
|
/// @return true if the account is an unexpired annual member; false otherwise.
|
||||||
|
/// @note This method will return false for lifetime members.
|
||||||
|
bool is_annual_member(time_point_sec now)const
|
||||||
|
{
|
||||||
|
return !is_lifetime_member() && !is_basic_account(now);
|
||||||
|
}
|
||||||
|
/// @return true if the account is an annual or lifetime member; false otherwise.
|
||||||
|
bool is_member(time_point_sec now)const
|
||||||
|
{
|
||||||
|
return !is_basic_account(now);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if this account is whitelisted and not blacklisted to transact in the provided asset; false
|
* @return true if this account is whitelisted and not blacklisted to transact in the provided asset; false
|
||||||
|
|
@ -253,9 +270,12 @@ namespace graphene { namespace chain {
|
||||||
typedef generic_index<account_object, account_object_multi_index_type> account_index;
|
typedef generic_index<account_object, account_object_multi_index_type> account_index;
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
FC_REFLECT_DERIVED( graphene::chain::account_object,
|
FC_REFLECT_DERIVED( graphene::chain::account_object,
|
||||||
(graphene::db::annotated_object<graphene::chain::account_object>),
|
(graphene::db::annotated_object<graphene::chain::account_object>),
|
||||||
(registrar)(referrer)(referrer_percent)(name)(owner)(active)(memo_key)(voting_account)(num_witness)(num_committee)(votes)
|
(membership_expiration_date)(registrar)(referrer)(lifetime_referrer)
|
||||||
|
(network_fee_percentage)(lifetime_referrer_fee_percentage)(referrer_rewards_percentage)
|
||||||
|
(name)(owner)(active)(memo_key)(voting_account)(num_witness)(num_committee)(votes)
|
||||||
(statistics)(whitelisting_accounts)(blacklisting_accounts)(cashback_vb) )
|
(statistics)(whitelisting_accounts)(blacklisting_accounts)(cashback_vb) )
|
||||||
|
|
||||||
FC_REFLECT_DERIVED( graphene::chain::account_balance_object,
|
FC_REFLECT_DERIVED( graphene::chain::account_balance_object,
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@
|
||||||
#define GRAPHENE_DEFAULT_TRANSFER_FEE (1*GRAPHENE_BLOCKCHAIN_PRECISION)
|
#define GRAPHENE_DEFAULT_TRANSFER_FEE (1*GRAPHENE_BLOCKCHAIN_PRECISION)
|
||||||
#define GRAPHENE_MAX_INSTANCE_ID (uint64_t(-1)>>16)
|
#define GRAPHENE_MAX_INSTANCE_ID (uint64_t(-1)>>16)
|
||||||
#define GRAPHENE_100_PERCENT 10000
|
#define GRAPHENE_100_PERCENT 10000
|
||||||
|
#define GRAPHENE_1_PERCENT (GRAPHENE_100_PERCENT/100)
|
||||||
/** NOTE: making this a power of 2 (say 2^15) would greatly accelerate fee calcs */
|
/** NOTE: making this a power of 2 (say 2^15) would greatly accelerate fee calcs */
|
||||||
#define GRAPHENE_MAX_MARKET_FEE_PERCENT GRAPHENE_100_PERCENT
|
#define GRAPHENE_MAX_MARKET_FEE_PERCENT GRAPHENE_100_PERCENT
|
||||||
#define GRAPHENE_DEFAULT_FORCE_SETTLEMENT_DELAY (60*60*24) ///< 1 day
|
#define GRAPHENE_DEFAULT_FORCE_SETTLEMENT_DELAY (60*60*24) ///< 1 day
|
||||||
|
|
@ -72,12 +73,14 @@
|
||||||
#define GRAPHENE_DEFAULT_MAX_COMMITTEE (1001) // SHOULD BE ODD
|
#define GRAPHENE_DEFAULT_MAX_COMMITTEE (1001) // SHOULD BE ODD
|
||||||
#define GRAPHENE_DEFAULT_MAX_PROPOSAL_LIFETIME_SEC (60*60*24*7*4) // Four weeks
|
#define GRAPHENE_DEFAULT_MAX_PROPOSAL_LIFETIME_SEC (60*60*24*7*4) // Four weeks
|
||||||
#define GRAPHENE_DEFAULT_GENESIS_PROPOSAL_REVIEW_PERIOD_SEC (60*60*24*7*2) // Two weeks
|
#define GRAPHENE_DEFAULT_GENESIS_PROPOSAL_REVIEW_PERIOD_SEC (60*60*24*7*2) // Two weeks
|
||||||
#define GRAPHENE_DEFAULT_WITNESS_PERCENT (10000/100) // 1%
|
#define GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE (20*GRAPHENE_1_PERCENT)
|
||||||
#define GRAPHENE_DEFAULT_MAX_BULK_DISCOUNT_PERCENT (10000/2) // 50%
|
#define GRAPHENE_DEFAULT_LIFETIME_REFERRER_PERCENT_OF_FEE (30*GRAPHENE_1_PERCENT)
|
||||||
|
#define GRAPHENE_DEFAULT_MAX_BULK_DISCOUNT_PERCENT (50*GRAPHENE_1_PERCENT)
|
||||||
#define GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN ( GRAPHENE_BLOCKCHAIN_PRECISION*int64_t(1000) )
|
#define GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN ( GRAPHENE_BLOCKCHAIN_PRECISION*int64_t(1000) )
|
||||||
#define GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX ( GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN*int64_t(100) )
|
#define GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX ( GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN*int64_t(100) )
|
||||||
#define GRAPHENE_DEFAULT_CASHBACK_VESTING_PERIOD_SEC (60*60*24*365) ///< 1 year
|
#define GRAPHENE_DEFAULT_CASHBACK_VESTING_PERIOD_SEC (60*60*24*365) ///< 1 year
|
||||||
#define GRAPHENE_DEFAULT_BURN_PERCENT_OF_FEE (10000/5) // 20%
|
#define GRAPHENE_DEFAULT_CASHBACK_VESTING_THRESHOLD (GRAPHENE_BLOCKCHAIN_PRECISION*int64_t(100))
|
||||||
|
#define GRAPHENE_DEFAULT_BURN_PERCENT_OF_FEE (20*GRAPHENE_1_PERCENT)
|
||||||
#define GRAPHENE_DEFAULT_WITNESS_PAY_PERCENT_OF_ACCUMULATED ( 1728000) /// gives a half life of 1 year assuming 1 second blocks
|
#define GRAPHENE_DEFAULT_WITNESS_PAY_PERCENT_OF_ACCUMULATED ( 1728000) /// gives a half life of 1 year assuming 1 second blocks
|
||||||
#define GRAPHENE_WITNESS_PAY_PERCENT_PRECISION (1000000000)
|
#define GRAPHENE_WITNESS_PAY_PERCENT_PRECISION (1000000000)
|
||||||
#define GRAPHENE_GENESIS_TIMESTAMP (1431700000) /// Should be divisible by GRAPHENE_DEFAULT_BLOCK_INTERVAL
|
#define GRAPHENE_GENESIS_TIMESTAMP (1431700000) /// Should be divisible by GRAPHENE_DEFAULT_BLOCK_INTERVAL
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include <graphene/chain/block.hpp>
|
#include <graphene/chain/block.hpp>
|
||||||
#include <graphene/chain/asset.hpp>
|
#include <graphene/chain/asset.hpp>
|
||||||
#include <graphene/chain/global_property_object.hpp>
|
#include <graphene/chain/global_property_object.hpp>
|
||||||
|
#include <graphene/chain/account_object.hpp>
|
||||||
#include <graphene/chain/asset_object.hpp>
|
#include <graphene/chain/asset_object.hpp>
|
||||||
#include <graphene/chain/fork_database.hpp>
|
#include <graphene/chain/fork_database.hpp>
|
||||||
|
|
||||||
|
|
@ -357,7 +358,9 @@ namespace graphene { namespace chain {
|
||||||
void perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props);
|
void perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props);
|
||||||
void update_active_witnesses();
|
void update_active_witnesses();
|
||||||
void update_active_delegates();
|
void update_active_delegates();
|
||||||
void update_vote_totals(const global_property_object& props);
|
|
||||||
|
template<class... Types>
|
||||||
|
void perform_account_maintenance(std::tuple<Types...> helpers);
|
||||||
///@}
|
///@}
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
|
|
@ -394,4 +397,29 @@ namespace graphene { namespace chain {
|
||||||
uint64_t _total_voting_stake;
|
uint64_t _total_voting_stake;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template<int... Is>
|
||||||
|
struct seq { };
|
||||||
|
|
||||||
|
template<int N, int... Is>
|
||||||
|
struct gen_seq : gen_seq<N - 1, N - 1, Is...> { };
|
||||||
|
|
||||||
|
template<int... Is>
|
||||||
|
struct gen_seq<0, Is...> : seq<Is...> { };
|
||||||
|
|
||||||
|
template<typename T, int... Is>
|
||||||
|
void for_each(T&& t, const account_object& a, seq<Is...>)
|
||||||
|
{
|
||||||
|
auto l = { (std::get<Is>(t)(a), 0)... };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<class... Types>
|
||||||
|
void database::perform_account_maintenance(std::tuple<Types...> helpers)
|
||||||
|
{
|
||||||
|
const auto& idx = get_index_type<account_index>().indices();
|
||||||
|
for( const account_object& a : idx )
|
||||||
|
detail::for_each(helpers, a, detail::gen_seq<sizeof...(Types)>());
|
||||||
|
}
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
/* Copyright (C) Cryptonomex, Inc - All Rights Reserved
|
/* Copyright (C) Cryptonomex, Inc - All Rights Reserved
|
||||||
*
|
*
|
||||||
* All modifications become property of Cryptonomex, Inc.
|
* All modifications become property of Cryptonomex, Inc.
|
||||||
*
|
*
|
||||||
|
|
@ -125,14 +125,13 @@ namespace graphene { namespace chain {
|
||||||
struct account_create_operation
|
struct account_create_operation
|
||||||
{
|
{
|
||||||
asset fee;
|
asset fee;
|
||||||
|
/// This account pays the fee. Must be a lifetime member.
|
||||||
account_id_type registrar;
|
account_id_type registrar;
|
||||||
|
|
||||||
/**
|
/// This account receives a portion of the fee split between registrar and referrer. Must be a member.
|
||||||
* If fee_paying_account->is_prime then referrer can be
|
|
||||||
* any other account that is also prime. Otherwise referrer must
|
|
||||||
* equal fee_paying_account->referrer.
|
|
||||||
*/
|
|
||||||
account_id_type referrer;
|
account_id_type referrer;
|
||||||
|
/// Of the fee split between registrar and referrer, this percentage goes to the referrer. The rest goes to the
|
||||||
|
/// registrar.
|
||||||
uint8_t referrer_percent = 0;
|
uint8_t referrer_percent = 0;
|
||||||
|
|
||||||
string name;
|
string name;
|
||||||
|
|
@ -214,12 +213,6 @@ namespace graphene { namespace chain {
|
||||||
uint16_t num_witness = 0;
|
uint16_t num_witness = 0;
|
||||||
uint16_t num_committee = 0;
|
uint16_t num_committee = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* If set to true, upgrades the account to a prime account by setting the account's referrer to itself. This may
|
|
||||||
* only be set to true when the account being modified is not already a prime account.
|
|
||||||
*/
|
|
||||||
bool upgrade_to_prime = false;
|
|
||||||
|
|
||||||
account_id_type fee_payer()const { return account; }
|
account_id_type fee_payer()const { return account; }
|
||||||
void get_required_auth(flat_set<account_id_type>& active_auth_set , flat_set<account_id_type>& owner_auth_set)const;
|
void get_required_auth(flat_set<account_id_type>& active_auth_set , flat_set<account_id_type>& owner_auth_set)const;
|
||||||
void validate()const;
|
void validate()const;
|
||||||
|
|
@ -1089,13 +1082,13 @@ namespace graphene { namespace chain {
|
||||||
* authorizing account. This operation is primarily useful for scheduling recurring payments.
|
* authorizing account. This operation is primarily useful for scheduling recurring payments.
|
||||||
*
|
*
|
||||||
* Withdrawal permissions define withdrawal periods, which is a span of time during which the authorized account may
|
* Withdrawal permissions define withdrawal periods, which is a span of time during which the authorized account may
|
||||||
* make a withdrawal. Any number of withdraws may be made so long as the total amount withdrawn is less than the limit
|
* make a withdrawal. Any number of withdrawals may be made so long as the total amount withdrawn per period does
|
||||||
* for any given period.
|
* not exceed the limit for any given period.
|
||||||
*
|
*
|
||||||
* Withdrawal permissions authorize only a specific pairing, i.e. a permission only authorizes one specified
|
* Withdrawal permissions authorize only a specific pairing, i.e. a permission only authorizes one specified
|
||||||
* authorized account to withdraw from one specified authorizing account. Withdrawals are limited and may not exceet
|
* authorized account to withdraw from one specified authorizing account. Withdrawals are limited and may not exceet
|
||||||
* the withdrawal limit. The withdrawal must be made in the same asset as the limit; attempts with withdraw any other
|
* the withdrawal limit. The withdrawal must be made in the same asset as the limit; attempts with withdraw any
|
||||||
* asset type will be rejected.
|
* other asset type will be rejected.
|
||||||
*
|
*
|
||||||
* The fee for this operation is paid by withdraw_from_account, and this account is required to authorize this
|
* The fee for this operation is paid by withdraw_from_account, and this account is required to authorize this
|
||||||
* operation.
|
* operation.
|
||||||
|
|
@ -1748,7 +1741,7 @@ FC_REFLECT( graphene::chain::account_create_operation,
|
||||||
|
|
||||||
FC_REFLECT_TYPENAME( fc::flat_set<graphene::chain::vote_id_type> )
|
FC_REFLECT_TYPENAME( fc::flat_set<graphene::chain::vote_id_type> )
|
||||||
FC_REFLECT( graphene::chain::account_update_operation,
|
FC_REFLECT( graphene::chain::account_update_operation,
|
||||||
(fee)(account)(owner)(active)(voting_account)(memo_key)(num_witness)(num_committee)(vote)(upgrade_to_prime)
|
(fee)(account)(owner)(active)(voting_account)(memo_key)(num_witness)(num_committee)(vote)
|
||||||
)
|
)
|
||||||
|
|
||||||
FC_REFLECT_TYPENAME( graphene::chain::account_whitelist_operation::account_listing)
|
FC_REFLECT_TYPENAME( graphene::chain::account_whitelist_operation::account_listing)
|
||||||
|
|
|
||||||
|
|
@ -460,23 +460,26 @@ namespace graphene { namespace chain {
|
||||||
uint16_t maximum_witness_count = GRAPHENE_DEFAULT_MAX_WITNESSES; ///< maximum number of active witnesses
|
uint16_t maximum_witness_count = GRAPHENE_DEFAULT_MAX_WITNESSES; ///< maximum number of active witnesses
|
||||||
uint16_t maximum_committee_count = GRAPHENE_DEFAULT_MAX_COMMITTEE; ///< maximum number of active delegates
|
uint16_t maximum_committee_count = GRAPHENE_DEFAULT_MAX_COMMITTEE; ///< maximum number of active delegates
|
||||||
uint16_t maximum_authority_membership = GRAPHENE_DEFAULT_MAX_AUTHORITY_MEMBERSHIP; ///< largest number of keys/accounts an authority can have
|
uint16_t maximum_authority_membership = GRAPHENE_DEFAULT_MAX_AUTHORITY_MEMBERSHIP; ///< largest number of keys/accounts an authority can have
|
||||||
uint16_t burn_percent_of_fee = GRAPHENE_DEFAULT_BURN_PERCENT_OF_FEE; ///< the percentage of every fee that is taken out of circulation
|
uint16_t burn_percent_of_fee = GRAPHENE_DEFAULT_BURN_PERCENT_OF_FEE; ///< the percentage of the network's allocation of a fee that is taken out of circulation
|
||||||
uint16_t witness_percent_of_fee = GRAPHENE_DEFAULT_WITNESS_PERCENT; ///< percent of revenue paid to witnesses
|
uint16_t network_percent_of_fee = GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; ///< percent of transaction fees paid to network
|
||||||
|
uint16_t lifetime_referrer_percent_of_fee = GRAPHENE_DEFAULT_LIFETIME_REFERRER_PERCENT_OF_FEE; ///< percent of transaction fees paid to network
|
||||||
uint32_t cashback_vesting_period_seconds = GRAPHENE_DEFAULT_CASHBACK_VESTING_PERIOD_SEC; ///< time after cashback rewards are accrued before they become liquid
|
uint32_t cashback_vesting_period_seconds = GRAPHENE_DEFAULT_CASHBACK_VESTING_PERIOD_SEC; ///< time after cashback rewards are accrued before they become liquid
|
||||||
|
share_type cashback_vesting_threshold = GRAPHENE_DEFAULT_CASHBACK_VESTING_THRESHOLD; ///< the maximum cashback that can be received without vesting
|
||||||
uint16_t max_bulk_discount_percent_of_fee = GRAPHENE_DEFAULT_MAX_BULK_DISCOUNT_PERCENT; ///< the maximum percentage discount for bulk discounts
|
uint16_t max_bulk_discount_percent_of_fee = GRAPHENE_DEFAULT_MAX_BULK_DISCOUNT_PERCENT; ///< the maximum percentage discount for bulk discounts
|
||||||
share_type bulk_discount_threshold_min = GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN; ///< the minimum amount of fees paid to qualify for bulk discounts
|
share_type bulk_discount_threshold_min = GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN; ///< the minimum amount of fees paid to qualify for bulk discounts
|
||||||
share_type bulk_discount_threshold_max = GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX; ///< the amount of fees paid to qualify for the max bulk discount percent
|
share_type bulk_discount_threshold_max = GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX; ///< the amount of fees paid to qualify for the max bulk discount percent
|
||||||
bool count_non_prime_votes = true; ///< set to false to restrict voting privlegages to prime accounts
|
bool count_non_member_votes = true; ///< set to false to restrict voting privlegages to member accounts
|
||||||
bool allow_non_prime_whitelists = false; ///< true if non-prime accounts may set whitelists and blacklists; false otherwise
|
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 witness_pay_per_block = GRAPHENE_DEFAULT_WITNESS_PAY_PER_BLOCK; ///< CORE to be allocated to witnesses (per block)
|
||||||
share_type worker_budget_per_day = GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY; ///< CORE to be allocated to workers (per day)
|
share_type worker_budget_per_day = GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY; ///< CORE to be allocated to workers (per day)
|
||||||
|
|
||||||
void validate()const
|
void validate()const
|
||||||
{
|
{
|
||||||
FC_ASSERT( witness_percent_of_fee <= GRAPHENE_100_PERCENT );
|
|
||||||
FC_ASSERT( burn_percent_of_fee <= GRAPHENE_100_PERCENT );
|
FC_ASSERT( burn_percent_of_fee <= GRAPHENE_100_PERCENT );
|
||||||
|
FC_ASSERT( network_percent_of_fee <= GRAPHENE_100_PERCENT );
|
||||||
FC_ASSERT( max_bulk_discount_percent_of_fee <= GRAPHENE_100_PERCENT );
|
FC_ASSERT( max_bulk_discount_percent_of_fee <= GRAPHENE_100_PERCENT );
|
||||||
FC_ASSERT( burn_percent_of_fee + witness_percent_of_fee <= GRAPHENE_100_PERCENT );
|
FC_ASSERT( lifetime_referrer_percent_of_fee <= GRAPHENE_100_PERCENT );
|
||||||
|
FC_ASSERT( network_percent_of_fee + lifetime_referrer_percent_of_fee <= GRAPHENE_100_PERCENT );
|
||||||
FC_ASSERT( bulk_discount_threshold_min <= bulk_discount_threshold_max );
|
FC_ASSERT( bulk_discount_threshold_min <= bulk_discount_threshold_max );
|
||||||
FC_ASSERT( bulk_discount_threshold_min > 0 );
|
FC_ASSERT( bulk_discount_threshold_min > 0 );
|
||||||
|
|
||||||
|
|
@ -656,13 +659,15 @@ FC_REFLECT( graphene::chain::chain_parameters,
|
||||||
(maximum_asset_feed_publishers)
|
(maximum_asset_feed_publishers)
|
||||||
(maximum_authority_membership)
|
(maximum_authority_membership)
|
||||||
(burn_percent_of_fee)
|
(burn_percent_of_fee)
|
||||||
(witness_percent_of_fee)
|
(network_percent_of_fee)
|
||||||
|
(lifetime_referrer_percent_of_fee)
|
||||||
(max_bulk_discount_percent_of_fee)
|
(max_bulk_discount_percent_of_fee)
|
||||||
(cashback_vesting_period_seconds)
|
(cashback_vesting_period_seconds)
|
||||||
|
(cashback_vesting_threshold)
|
||||||
(bulk_discount_threshold_min)
|
(bulk_discount_threshold_min)
|
||||||
(bulk_discount_threshold_max)
|
(bulk_discount_threshold_max)
|
||||||
(count_non_prime_votes)
|
(count_non_member_votes)
|
||||||
(allow_non_prime_whitelists)
|
(allow_non_member_whitelists)
|
||||||
(witness_pay_per_block)
|
(witness_pay_per_block)
|
||||||
(worker_budget_per_day)
|
(worker_budget_per_day)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,9 @@ namespace graphene { namespace chain {
|
||||||
*
|
*
|
||||||
* The primary purpose of this object is to enable recurring payments on the blockchain. An account which wishes to
|
* The primary purpose of this object is to enable recurring payments on the blockchain. An account which wishes to
|
||||||
* process a recurring payment may use a @ref withdraw_permission_claim_operation to reference an object of this type
|
* process a recurring payment may use a @ref withdraw_permission_claim_operation to reference an object of this type
|
||||||
* and withdraw up to @ref withdrawal_limit from @ref withdraw_from_account. Only @ref authorized_account may do this.
|
* and withdraw up to @ref withdrawal_limit from @ref withdraw_from_account. Only @ref authorized_account may do
|
||||||
* Any number of withdraws may be made so long as the total amount withdrawn is less than the limit for any given
|
* this. Any number of withdrawals may be made so long as the total amount withdrawn per period does not exceed the
|
||||||
* period.
|
* limit for any given period.
|
||||||
*/
|
*/
|
||||||
class withdraw_permission_object : public graphene::db::abstract_object<withdraw_permission_object>
|
class withdraw_permission_object : public graphene::db::abstract_object<withdraw_permission_object>
|
||||||
{
|
{
|
||||||
|
|
@ -54,14 +54,14 @@ namespace graphene { namespace chain {
|
||||||
/// tracks the total amount
|
/// tracks the total amount
|
||||||
share_type claimed_this_period;
|
share_type claimed_this_period;
|
||||||
/// True if the permission may still be claimed for this period; false if it has already been used
|
/// True if the permission may still be claimed for this period; false if it has already been used
|
||||||
asset available_this_period( fc::time_point_sec current_time )const
|
asset available_this_period( fc::time_point_sec current_time )const
|
||||||
{
|
{
|
||||||
if( current_time >= period_start_time + withdrawal_period_sec )
|
if( current_time >= period_start_time + withdrawal_period_sec )
|
||||||
return withdrawal_limit;
|
return withdrawal_limit;
|
||||||
return asset(
|
return asset(
|
||||||
( withdrawal_limit.amount > claimed_this_period )
|
( withdrawal_limit.amount > claimed_this_period )
|
||||||
? withdrawal_limit.amount - claimed_this_period
|
? withdrawal_limit.amount - claimed_this_period
|
||||||
: 0, withdrawal_limit.asset_id );
|
: 0, withdrawal_limit.asset_id );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,6 @@ share_type account_create_operation::calculate_fee( const fee_schedule_type& sch
|
||||||
}
|
}
|
||||||
share_type account_update_operation::calculate_fee( const fee_schedule_type& schedule )const
|
share_type account_update_operation::calculate_fee( const fee_schedule_type& schedule )const
|
||||||
{
|
{
|
||||||
if( upgrade_to_prime ) return schedule.at(prime_upgrade_fee_type);
|
|
||||||
return schedule.at(account_create_fee_type);
|
return schedule.at(account_create_fee_type);
|
||||||
}
|
}
|
||||||
void account_update_operation::get_required_auth(flat_set<account_id_type>& active_auth_set,
|
void account_update_operation::get_required_auth(flat_set<account_id_type>& active_auth_set,
|
||||||
|
|
@ -138,7 +137,7 @@ void account_update_operation::validate()const
|
||||||
{
|
{
|
||||||
FC_ASSERT( fee.amount >= 0 );
|
FC_ASSERT( fee.amount >= 0 );
|
||||||
FC_ASSERT( account != account_id_type() );
|
FC_ASSERT( account != account_id_type() );
|
||||||
FC_ASSERT( owner || active || voting_account || memo_key || vote || upgrade_to_prime );
|
FC_ASSERT( owner || active || voting_account || memo_key || vote );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
object_id_type witness_create_evaluator::do_evaluate( const witness_create_operation& op )
|
object_id_type witness_create_evaluator::do_evaluate( const witness_create_operation& op )
|
||||||
{
|
{
|
||||||
FC_ASSERT(db().get(op.witness_account).is_prime());
|
FC_ASSERT(db().get(op.witness_account).is_lifetime_member());
|
||||||
return object_id_type();
|
return object_id_type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ object_id_type worker_create_evaluator::do_evaluate(const worker_create_evaluato
|
||||||
{ try {
|
{ try {
|
||||||
database& d = db();
|
database& d = db();
|
||||||
|
|
||||||
FC_ASSERT(d.get(o.owner).is_prime());
|
FC_ASSERT(d.get(o.owner).is_lifetime_member());
|
||||||
FC_ASSERT(o.work_begin_date >= d.head_block_time());
|
FC_ASSERT(o.work_begin_date >= d.head_block_time());
|
||||||
|
|
||||||
return object_id_type();
|
return object_id_type();
|
||||||
|
|
|
||||||
|
|
@ -695,7 +695,7 @@ public:
|
||||||
|
|
||||||
account_object registrar_account_object =
|
account_object registrar_account_object =
|
||||||
this->get_account( registrar_account );
|
this->get_account( registrar_account );
|
||||||
FC_ASSERT( registrar_account_object.is_prime() );
|
FC_ASSERT( registrar_account_object.is_lifetime_member() );
|
||||||
|
|
||||||
account_id_type registrar_account_id = registrar_account_object.id;
|
account_id_type registrar_account_id = registrar_account_object.id;
|
||||||
|
|
||||||
|
|
@ -761,17 +761,11 @@ public:
|
||||||
{ try {
|
{ try {
|
||||||
FC_ASSERT( !self.is_locked() );
|
FC_ASSERT( !self.is_locked() );
|
||||||
account_object account_obj = get_account(name);
|
account_object account_obj = get_account(name);
|
||||||
FC_ASSERT( !account_obj.is_prime() );
|
FC_ASSERT( !account_obj.is_lifetime_member() );
|
||||||
|
|
||||||
account_update_operation update_op;
|
|
||||||
update_op.account = account_obj.id;
|
|
||||||
update_op.num_witness = account_obj.num_witness;
|
|
||||||
update_op.num_committee = account_obj.num_committee;
|
|
||||||
update_op.upgrade_to_prime = true;
|
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
signed_transaction tx;
|
signed_transaction tx;
|
||||||
tx.operations.push_back( update_op );
|
|
||||||
tx.visit( operation_set_fee( _remote_db->get_global_properties().parameters.current_fees ) );
|
tx.visit( operation_set_fee( _remote_db->get_global_properties().parameters.current_fees ) );
|
||||||
tx.validate();
|
tx.validate();
|
||||||
|
|
||||||
|
|
@ -802,7 +796,7 @@ public:
|
||||||
account_object referrer_account_object =
|
account_object referrer_account_object =
|
||||||
this->get_account( referrer_account );
|
this->get_account( referrer_account );
|
||||||
account_create_op.referrer = referrer_account_object.id;
|
account_create_op.referrer = referrer_account_object.id;
|
||||||
account_create_op.referrer_percent = referrer_account_object.referrer_percent;
|
account_create_op.referrer_percent = referrer_account_object.referrer_rewards_percentage;
|
||||||
|
|
||||||
// get pay_from_account_id
|
// get pay_from_account_id
|
||||||
key_create_operation owner_key_create_op;
|
key_create_operation owner_key_create_op;
|
||||||
|
|
|
||||||
|
|
@ -676,21 +676,18 @@ void database_fixture::enable_fees(
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
void database_fixture::upgrade_to_prime(account_id_type account)
|
void database_fixture::upgrade_to_lifetime_member(account_id_type account)
|
||||||
{
|
{
|
||||||
upgrade_to_prime(account(db));
|
upgrade_to_lifetime_member(account(db));
|
||||||
}
|
}
|
||||||
|
|
||||||
void database_fixture::upgrade_to_prime( const account_object& account )
|
void database_fixture::upgrade_to_lifetime_member( const account_object& account )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
account_update_operation op;
|
// TODO
|
||||||
op.account = account.id;
|
|
||||||
op.upgrade_to_prime = true;
|
|
||||||
trx.operations.emplace_back(operation(op));
|
|
||||||
db.push_transaction( trx, ~0 );
|
db.push_transaction( trx, ~0 );
|
||||||
FC_ASSERT( account.is_prime() );
|
FC_ASSERT( account.is_lifetime_member() );
|
||||||
trx.clear();
|
trx.clear();
|
||||||
}
|
}
|
||||||
FC_CAPTURE_AND_RETHROW((account))
|
FC_CAPTURE_AND_RETHROW((account))
|
||||||
|
|
|
||||||
|
|
@ -202,8 +202,8 @@ struct database_fixture {
|
||||||
void transfer( const account_object& from, const account_object& to, const asset& amount, const asset& fee = asset() );
|
void transfer( const account_object& from, const account_object& to, const asset& amount, const asset& fee = asset() );
|
||||||
void fund_fee_pool( const account_object& from, const asset_object& asset_to_fund, const share_type amount );
|
void fund_fee_pool( const account_object& from, const asset_object& asset_to_fund, const share_type amount );
|
||||||
void enable_fees( share_type fee = GRAPHENE_BLOCKCHAIN_PRECISION );
|
void enable_fees( share_type fee = GRAPHENE_BLOCKCHAIN_PRECISION );
|
||||||
void upgrade_to_prime( account_id_type account );
|
void upgrade_to_lifetime_member( account_id_type account );
|
||||||
void upgrade_to_prime( const account_object& account );
|
void upgrade_to_lifetime_member( const account_object& account );
|
||||||
void print_market( const string& syma, const string& symb )const;
|
void print_market( const string& syma, const string& symb )const;
|
||||||
string pretty( const asset& a )const;
|
string pretty( const asset& a )const;
|
||||||
void print_short_order( const short_order_object& cur )const;
|
void print_short_order( const short_order_object& cur )const;
|
||||||
|
|
|
||||||
|
|
@ -434,7 +434,7 @@ BOOST_FIXTURE_TEST_CASE( fired_delegates, database_fixture )
|
||||||
for( int i = 0; i < 15; ++i )
|
for( int i = 0; i < 15; ++i )
|
||||||
{
|
{
|
||||||
const auto& account = create_account("delegate" + fc::to_string(i+1), delegate_key_object.id);
|
const auto& account = create_account("delegate" + fc::to_string(i+1), delegate_key_object.id);
|
||||||
upgrade_to_prime(account);
|
upgrade_to_lifetime_member(account);
|
||||||
delegates.insert(create_delegate(account).vote_id);
|
delegates.insert(create_delegate(account).vote_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -980,8 +980,8 @@ BOOST_FIXTURE_TEST_CASE( bogus_signature, database_fixture )
|
||||||
BOOST_FIXTURE_TEST_CASE( voting_account, database_fixture )
|
BOOST_FIXTURE_TEST_CASE( voting_account, database_fixture )
|
||||||
{ try {
|
{ try {
|
||||||
ACTORS((nathan)(vikram));
|
ACTORS((nathan)(vikram));
|
||||||
upgrade_to_prime(nathan_id);
|
upgrade_to_lifetime_member(nathan_id);
|
||||||
upgrade_to_prime(vikram_id);
|
upgrade_to_lifetime_member(vikram_id);
|
||||||
delegate_id_type nathan_delegate = create_delegate(nathan_id(db)).id;
|
delegate_id_type nathan_delegate = create_delegate(nathan_id(db)).id;
|
||||||
delegate_id_type vikram_delegate = create_delegate(vikram_id(db)).id;
|
delegate_id_type vikram_delegate = create_delegate(vikram_id(db)).id;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -424,7 +424,7 @@ BOOST_FIXTURE_TEST_CASE( maintenance_interval, database_fixture )
|
||||||
BOOST_CHECK_GT(maintenence_time.sec_since_epoch(), db.head_block_time().sec_since_epoch());
|
BOOST_CHECK_GT(maintenence_time.sec_since_epoch(), db.head_block_time().sec_since_epoch());
|
||||||
auto initial_properties = db.get_global_properties();
|
auto initial_properties = db.get_global_properties();
|
||||||
const account_object& nathan = create_account("nathan");
|
const account_object& nathan = create_account("nathan");
|
||||||
upgrade_to_prime(nathan);
|
upgrade_to_lifetime_member(nathan);
|
||||||
const delegate_object nathans_delegate = create_delegate(nathan);
|
const delegate_object nathans_delegate = create_delegate(nathan);
|
||||||
{
|
{
|
||||||
account_update_operation op;
|
account_update_operation op;
|
||||||
|
|
|
||||||
|
|
@ -186,13 +186,13 @@ BOOST_AUTO_TEST_CASE( update_account )
|
||||||
transfer(account_id_type()(db), nathan, asset(3000000));
|
transfer(account_id_type()(db), nathan, asset(3000000));
|
||||||
|
|
||||||
enable_fees();
|
enable_fees();
|
||||||
op.upgrade_to_prime = true;
|
// TODO: op.upgrade_to_prime = true;
|
||||||
op.fee = op.calculate_fee( db.get_global_properties().parameters.current_fees );
|
op.fee = op.calculate_fee( db.get_global_properties().parameters.current_fees );
|
||||||
trx.operations.push_back(op);
|
trx.operations.push_back(op);
|
||||||
db.push_transaction(trx, ~0);
|
db.push_transaction(trx, ~0);
|
||||||
|
|
||||||
BOOST_CHECK( nathan.referrer == nathan.id );
|
BOOST_CHECK( nathan.referrer == nathan.id );
|
||||||
BOOST_CHECK( nathan.referrer_percent == 100 );
|
BOOST_CHECK( nathan.referrer_rewards_percentage == 100 );
|
||||||
} catch (fc::exception& e) {
|
} catch (fc::exception& e) {
|
||||||
edump((e.to_detail_string()));
|
edump((e.to_detail_string()));
|
||||||
throw;
|
throw;
|
||||||
|
|
@ -1872,7 +1872,7 @@ BOOST_AUTO_TEST_CASE( witness_withdraw_pay_test )
|
||||||
BOOST_CHECK_EQUAL(core->dynamic_asset_data_id(db).accumulated_fees.value, 0);
|
BOOST_CHECK_EQUAL(core->dynamic_asset_data_id(db).accumulated_fees.value, 0);
|
||||||
account_update_operation uop;
|
account_update_operation uop;
|
||||||
uop.account = nathan->get_id();
|
uop.account = nathan->get_id();
|
||||||
uop.upgrade_to_prime = true;
|
// TODO: uop.upgrade_to_prime = true;
|
||||||
trx.set_expiration(db.head_block_id());
|
trx.set_expiration(db.head_block_id());
|
||||||
trx.operations.push_back(uop);
|
trx.operations.push_back(uop);
|
||||||
trx.visit(operation_set_fee(db.current_fee_schedule()));
|
trx.visit(operation_set_fee(db.current_fee_schedule()));
|
||||||
|
|
@ -2124,7 +2124,7 @@ BOOST_AUTO_TEST_CASE( unimp_transfer_cashback_test )
|
||||||
|
|
||||||
const account_object& sam = create_account( "sam" );
|
const account_object& sam = create_account( "sam" );
|
||||||
transfer(account_id_type()(db), sam, asset(30000));
|
transfer(account_id_type()(db), sam, asset(30000));
|
||||||
upgrade_to_prime(sam);
|
upgrade_to_lifetime_member(sam);
|
||||||
|
|
||||||
ilog( "Creating alice" );
|
ilog( "Creating alice" );
|
||||||
const account_object& alice = create_account( "alice", sam, sam, 0 );
|
const account_object& alice = create_account( "alice", sam, sam, 0 );
|
||||||
|
|
|
||||||
|
|
@ -388,7 +388,7 @@ BOOST_AUTO_TEST_CASE( mia_feeds )
|
||||||
BOOST_AUTO_TEST_CASE( witness_create )
|
BOOST_AUTO_TEST_CASE( witness_create )
|
||||||
{ try {
|
{ try {
|
||||||
ACTOR(nathan);
|
ACTOR(nathan);
|
||||||
upgrade_to_prime(nathan_id);
|
upgrade_to_lifetime_member(nathan_id);
|
||||||
trx.clear();
|
trx.clear();
|
||||||
witness_id_type nathan_witness_id = create_witness(nathan_id, nathan_key_id, nathan_private_key).id;
|
witness_id_type nathan_witness_id = create_witness(nathan_id, nathan_key_id, nathan_private_key).id;
|
||||||
// Give nathan some voting stake
|
// Give nathan some voting stake
|
||||||
|
|
@ -494,7 +494,7 @@ BOOST_AUTO_TEST_CASE( global_settle_test )
|
||||||
BOOST_AUTO_TEST_CASE( worker_create_test )
|
BOOST_AUTO_TEST_CASE( worker_create_test )
|
||||||
{ try {
|
{ try {
|
||||||
ACTOR(nathan);
|
ACTOR(nathan);
|
||||||
upgrade_to_prime(nathan_id);
|
upgrade_to_lifetime_member(nathan_id);
|
||||||
generate_block();
|
generate_block();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -615,7 +615,7 @@ BOOST_AUTO_TEST_CASE( worker_pay_test )
|
||||||
BOOST_AUTO_TEST_CASE( refund_worker_test )
|
BOOST_AUTO_TEST_CASE( refund_worker_test )
|
||||||
{try{
|
{try{
|
||||||
ACTOR(nathan);
|
ACTOR(nathan);
|
||||||
upgrade_to_prime(nathan_id);
|
upgrade_to_lifetime_member(nathan_id);
|
||||||
generate_block();
|
generate_block();
|
||||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||||
trx.set_expiration(db.head_block_id());
|
trx.set_expiration(db.head_block_id());
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE( issue_whitelist_uia )
|
||||||
INVOKE(create_advanced_uia);
|
INVOKE(create_advanced_uia);
|
||||||
const asset_object& advanced = get_asset("ADVANCED");
|
const asset_object& advanced = get_asset("ADVANCED");
|
||||||
const account_object& nathan = create_account("nathan");
|
const account_object& nathan = create_account("nathan");
|
||||||
upgrade_to_prime(nathan);
|
upgrade_to_lifetime_member(nathan);
|
||||||
trx.clear();
|
trx.clear();
|
||||||
|
|
||||||
asset_issue_operation op({asset(), advanced.issuer, advanced.amount(1000), nathan.id});
|
asset_issue_operation op({asset(), advanced.issuer, advanced.amount(1000), nathan.id});
|
||||||
|
|
@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia )
|
||||||
const asset_object& advanced = get_asset("ADVANCED");
|
const asset_object& advanced = get_asset("ADVANCED");
|
||||||
const account_object& nathan = get_account("nathan");
|
const account_object& nathan = get_account("nathan");
|
||||||
const account_object& dan = create_account("dan");
|
const account_object& dan = create_account("dan");
|
||||||
upgrade_to_prime(dan);
|
upgrade_to_lifetime_member(dan);
|
||||||
trx.clear();
|
trx.clear();
|
||||||
|
|
||||||
transfer_operation op({advanced.amount(0), nathan.id, dan.id, advanced.amount(100)});
|
transfer_operation op({advanced.amount(0), nathan.id, dan.id, advanced.amount(100)});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue