Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove liquid vp #2263

Merged
merged 3 commits into from
Sep 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions libraries/chain/db_maint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <graphene/chain/global_property_object.hpp>
#include <graphene/chain/market_object.hpp>
#include <graphene/chain/special_authority_object.hpp>
#include <graphene/chain/ticket_object.hpp>
#include <graphene/chain/vesting_balance_object.hpp>
#include <graphene/chain/vote_count.hpp>
#include <graphene/chain/witness_object.hpp>
Expand Down Expand Up @@ -1091,6 +1092,22 @@ void delete_expired_custom_authorities( database& db )
db.remove(*index.begin());
}

/// A one-time data process to set values of existing liquid tickets to zero.
void process_hf_2262( database& db )
{
for( const auto& ticket_obj : db.get_index_type<ticket_index>().indices().get<by_id>() )
{
if( ticket_obj.current_type != liquid ) // only update liquid tickets
continue;
db.modify( db.get_account_stats_by_owner( ticket_obj.account ), [&ticket_obj](account_statistics_object& aso) {
aso.total_pol_value -= ticket_obj.value;
});
db.modify( ticket_obj, []( ticket_object& t ) {
t.value = 0;
});
}
}

namespace detail {

struct vote_recalc_times
Expand Down Expand Up @@ -1180,6 +1197,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
const dynamic_global_property_object& dprops;
const time_point_sec now;
const bool hf2103_passed;
const bool hf2262_passed;
const bool pob_activated;

optional<detail::vote_recalc_times> witness_recalc_times;
Expand All @@ -1190,6 +1208,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
vote_tally_helper( database& db )
: d(db), props( d.get_global_properties() ), dprops( d.get_dynamic_global_properties() ),
now( d.head_block_time() ), hf2103_passed( HARDFORK_CORE_2103_PASSED( now ) ),
hf2262_passed( HARDFORK_CORE_2262_PASSED( now ) ),
pob_activated( dprops.total_pob > 0 || dprops.total_inactive > 0 )
{
d._vote_tally_buffer.resize( props.next_available_vote_id, 0 );
Expand Down Expand Up @@ -1224,8 +1243,9 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
uint64_t voting_stake[3]; // 0=committee, 1=witness, 2=worker, as in vote_id_type::vote_type
uint64_t num_committee_voting_stake; // number of committee members
voting_stake[2] = ( pob_activated ? 0 : stats.total_core_in_orders.value )
+ (stake_account.cashback_vb.valid() ? (*stake_account.cashback_vb)(d).balance.amount.value: 0)
+ stats.core_in_balance.value;
+ ( ( !hf2262_passed && stake_account.cashback_vb.valid() ) ?
(*stake_account.cashback_vb)(d).balance.amount.value : 0 )
+ ( hf2262_passed ? 0 : stats.core_in_balance.value );

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI: Removing liquid BTS from voting power will strip ref UI users of their voting since you can only stake BTS with CLI.

Questions:

  • Does mobile support staking?
  • Do you have someone in mind that could update UI? Or does committee have funding for it?
  • cashback voting power is kept intentionally?
  • Liquid tickets means someone is actively seeking a say in governance, I would find it acceptable to give them 1x voting power

Copy link

@shulthz shulthz Sep 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* Liquid tickets means someone is actively seeking a say in governance, I would find it acceptable to give them 1x voting power

If giving liquid tickets 1x voting power, then nothing is changed, the vote buying will still be kept intentionally like beos and cn-vote now doing.
Otherwise, cn-vote or beos still can get the vote buying voting power from encouraging and seducing their supporter to lock the bts after this update, ok, cn-vote has done this.

I think the root problem is the defect of DPOS governance, the holders didn't need the sustained investment and spending, so they didn't have the enough motivation to govern the chain, especially some holders were zero cost holders.

On this chain, only the witnesses need sustained investment and spending to maintain the chain like miner of pow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing liquid BTS from voting power will strip ref UI users of their voting since you can only stake BTS with CLI.

Note: Uptick also supports creating and updating of voting tickets, in latest release. (Admittedly that is still a cli solution.... but still friendlier than and an alternative to cli_wallet.)

Re: liquid tickets. "liquid" isn't a ticket target type. One doesn't create "liquid" tickets. Rather it is a state that a ticket is in while it's still charging towards a lock target. (Although if the funds in the ticket are votable while it is in the charging/"liquid" state, then one could game the system by initiating a lock ticket and cancelling it prior to the next_auto_update_time, which, If I'm understanding correctly, would give you a few days of 1x voting power without actually committing you to the lock period.)

Copy link
Member Author

@abitmore abitmore Sep 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sschiessl-bcp wrote:

Just FYI: Removing liquid BTS from voting power will strip ref UI users of their voting since you can only stake BTS with CLI.

Yes it will strip users who only use the ref UI. However not only users can stake with CLI because the mobile client supports staking already.

cashback voting power is kept intentionally?

Thanks for noticing this. I overlooked it. Will fix.

I would find it acceptable to give them 1x voting power

It can be gamed as @christophersanborn said:

one could game the system by initiating a lock ticket and cancelling it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shulthz changes to witnesses will be considered in next releases. Thanks for your ideas anyway.


// voting power stats
uint64_t vp_all = 0; ///< all voting power.
Expand Down Expand Up @@ -1448,6 +1468,10 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
if ( dgpo.next_maintenance_time <= HARDFORK_CORE_2103_TIME && next_maintenance_time > HARDFORK_CORE_2103_TIME )
process_hf_2103(*this);

// Update tickets. Note: the new values will take effect only on the next maintenance interval
if ( dgpo.next_maintenance_time <= HARDFORK_CORE_2262_TIME && next_maintenance_time > HARDFORK_CORE_2262_TIME )
process_hf_2262(*this);

modify(dgpo, [last_vote_tally_time, next_maintenance_time](dynamic_global_property_object& d) {
d.next_maintenance_time = next_maintenance_time;
d.last_vote_tally_time = last_vote_tally_time;
Expand Down
7 changes: 5 additions & 2 deletions libraries/chain/db_update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,9 @@ void database::clear_expired_htlcs()

generic_operation_result database::process_tickets()
{
const auto maint_time = get_dynamic_global_properties().next_maintenance_time;
ticket_version version = ( HARDFORK_CORE_2262_PASSED(maint_time) ? ticket_v2 : ticket_v1 );

generic_operation_result result;
share_type total_delta_pob;
share_type total_delta_inactive;
Expand All @@ -627,8 +630,8 @@ generic_operation_result database::process_tickets()
{
ticket_type old_type = ticket.current_type;
share_type old_value = ticket.value;
modify( ticket, []( ticket_object& o ) {
o.auto_update();
modify( ticket, [version]( ticket_object& o ) {
o.auto_update( version );
});
result.updated_objects.insert( ticket.id );

Expand Down
6 changes: 6 additions & 0 deletions libraries/chain/hardfork.d/CORE_2262.hf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// bitshares-core issue #2262: Remove voting power from liquid BTS and tickets
#ifndef HARDFORK_CORE_2262_TIME
// Jan 1 2030, midnight; this is a dummy date until a hardfork date is scheduled
#define HARDFORK_CORE_2262_TIME (fc::time_point_sec( 1893456000 ))
#define HARDFORK_CORE_2262_PASSED(next_maint_time) (next_maint_time > HARDFORK_CORE_2262_TIME)
#endif
27 changes: 18 additions & 9 deletions libraries/chain/include/graphene/chain/ticket_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ enum ticket_status
TICKET_STATUS_COUNT
};

/// Version of a ticket
enum ticket_version
{
ticket_v1 = 1,
ticket_v2 = 2
};

/**
* @brief a ticket for governance voting
* @ingroup object
Expand Down Expand Up @@ -79,31 +86,33 @@ class ticket_object : public abstract_object<ticket_object>
static constexpr uint32_t _seconds_to_downgrade[] = { 180 * 86400, 180 * 86400, 360 * 86400 };
return _seconds_to_downgrade[ static_cast<uint8_t>(i) ];
}
static uint8_t value_multiplier( ticket_type i ) {
static constexpr uint32_t _value_multiplier[] = { 1, 2, 4, 8, 8, 0 };
return _value_multiplier[ static_cast<uint8_t>(i) ];
static uint8_t value_multiplier( ticket_type i, ticket_version version ) {
static constexpr uint32_t _value_multiplier_v1[] = { 1, 2, 4, 8, 8, 0 };
static constexpr uint32_t _value_multiplier_v2[] = { 0, 2, 4, 8, 8, 0 };
return ( version == ticket_v1 ? _value_multiplier_v1[ static_cast<uint8_t>(i) ]
: _value_multiplier_v2[ static_cast<uint8_t>(i) ] );
}

/// Initialize member variables for a ticket newly created from account balance
void init_new( time_point_sec now, account_id_type new_account,
ticket_type new_target_type, const asset& new_amount );
ticket_type new_target_type, const asset& new_amount, ticket_version version );

/// Initialize member variables for a ticket split from another ticket
void init_split( time_point_sec now, const ticket_object& old_ticket,
ticket_type new_target_type, const asset& new_amount );
ticket_type new_target_type, const asset& new_amount, ticket_version version );

/// Set a new target type and update member variables accordingly
void update_target_type( time_point_sec now, ticket_type new_target_type );
void update_target_type( time_point_sec now, ticket_type new_target_type, ticket_version version );

/// Adjust amount and update member variables accordingly
void adjust_amount( const asset& delta_amount );
void adjust_amount( const asset& delta_amount, ticket_version version );

/// Update the ticket when it's time
void auto_update();
void auto_update( ticket_version version );

private:
/// Recalculate value of the ticket
void update_value();
void update_value( ticket_version version );

};

Expand Down
22 changes: 14 additions & 8 deletions libraries/chain/ticket_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ object_id_type ticket_create_evaluator::do_apply(const ticket_create_operation&
{ try {
database& d = db();
const auto block_time = d.head_block_time();
const auto maint_time = d.get_dynamic_global_properties().next_maintenance_time;

ticket_version version = ( HARDFORK_CORE_2262_PASSED(maint_time) ? ticket_v2 : ticket_v1 );

d.adjust_balance( op.account, -op.amount );

const auto& new_ticket_object = d.create<ticket_object>([&op,block_time](ticket_object& obj){
obj.init_new( block_time, op.account, op.target_type, op.amount );
const auto& new_ticket_object = d.create<ticket_object>([&op,block_time,version](ticket_object& obj){
obj.init_new( block_time, op.account, op.target_type, op.amount, version );
});

// Note: amount.asset_id is checked in validate(), so no check here
Expand Down Expand Up @@ -88,6 +91,9 @@ generic_operation_result ticket_update_evaluator::do_apply(const ticket_update_o
{ try {
database& d = db();
const auto block_time = d.head_block_time();
const auto maint_time = d.get_dynamic_global_properties().next_maintenance_time;

ticket_version version = ( HARDFORK_CORE_2262_PASSED(maint_time) ? ticket_v2 : ticket_v1 );

generic_operation_result result;

Expand All @@ -97,21 +103,21 @@ generic_operation_result ticket_update_evaluator::do_apply(const ticket_update_o
// To partially update the ticket, aka splitting
if ( op.amount_for_new_target.valid() && *op.amount_for_new_target < _ticket->amount )
{
const auto& new_ticket_object = d.create<ticket_object>([&op,this,block_time](ticket_object& obj){
obj.init_split( block_time, *_ticket, op.target_type, *op.amount_for_new_target );
const auto& new_ticket_object = d.create<ticket_object>([&op,this,block_time,version](ticket_object& obj){
obj.init_split( block_time, *_ticket, op.target_type, *op.amount_for_new_target, version );
});

result.new_objects.insert( new_ticket_object.id );

d.modify( *_ticket, [&op](ticket_object& obj){
obj.adjust_amount( -(*op.amount_for_new_target) );
d.modify( *_ticket, [&op,version](ticket_object& obj){
obj.adjust_amount( -(*op.amount_for_new_target), version );
});
delta_value = new_ticket_object.value + _ticket->value - old_value;
}
else // To update the whole ticket
{
d.modify( *_ticket, [&op,block_time](ticket_object& obj){
obj.update_target_type( block_time, op.target_type );
d.modify( *_ticket, [&op,block_time,version](ticket_object& obj){
obj.update_target_type( block_time, op.target_type, version );
});
delta_value = _ticket->value - old_value;
}
Expand Down
29 changes: 15 additions & 14 deletions libraries/chain/ticket_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
using namespace graphene::chain;

void ticket_object::init_new( time_point_sec now, account_id_type new_account,
ticket_type new_target_type, const asset& new_amount )
ticket_type new_target_type, const asset& new_amount, ticket_version version )
{
account = new_account;
target_type = new_target_type;
Expand All @@ -40,11 +40,11 @@ void ticket_object::init_new( time_point_sec now, account_id_type new_account,
next_auto_update_time = now + seconds_per_charging_step;
next_type_downgrade_time = time_point_sec::maximum();

update_value();
update_value( version );
}

void ticket_object::init_split( time_point_sec now, const ticket_object& old_ticket,
ticket_type new_target_type, const asset& new_amount )
ticket_type new_target_type, const asset& new_amount, ticket_version version )
{
account = old_ticket.account;
target_type = old_ticket.target_type;
Expand All @@ -55,10 +55,10 @@ void ticket_object::init_split( time_point_sec now, const ticket_object& old_tic
next_auto_update_time = old_ticket.next_auto_update_time;
next_type_downgrade_time = old_ticket.next_type_downgrade_time;

update_target_type( now, new_target_type );
update_target_type( now, new_target_type, version );
}

void ticket_object::update_target_type( time_point_sec now, ticket_type new_target_type )
void ticket_object::update_target_type( time_point_sec now, ticket_type new_target_type, ticket_version version )
{
if( current_type < new_target_type )
{
Expand Down Expand Up @@ -89,16 +89,16 @@ void ticket_object::update_target_type( time_point_sec now, ticket_type new_targ
}
target_type = new_target_type;

update_value();
update_value( version );
}

void ticket_object::adjust_amount( const asset& delta_amount )
void ticket_object::adjust_amount( const asset& delta_amount, ticket_version version )
{
amount += delta_amount;
update_value();
update_value( version );
}

void ticket_object::auto_update()
void ticket_object::auto_update( ticket_version version )
{
if( status == charging )
{
Expand All @@ -119,7 +119,7 @@ void ticket_object::auto_update()
{
status = withdrawing;
next_auto_update_time += seconds_per_lock_forever_update_step;
value = amount.amount * value_multiplier(current_type);
value = amount.amount * value_multiplier( current_type, version );
}
}
}
Expand All @@ -128,7 +128,8 @@ void ticket_object::auto_update()
// Note: current_type != liquid, guaranteed by the caller
if( current_type == lock_forever )
{
share_type delta_value = amount.amount * value_multiplier(current_type) / lock_forever_update_steps;
share_type delta_value = amount.amount * value_multiplier( current_type, version )
/ lock_forever_update_steps;
if( delta_value <= 0 )
delta_value = 1;
if( value <= delta_value )
Expand Down Expand Up @@ -157,14 +158,14 @@ void ticket_object::auto_update()
}
}

update_value();
update_value( version );
}

void ticket_object::update_value()
void ticket_object::update_value( ticket_version version )
{
if( current_type != lock_forever )
{
value = amount.amount * value_multiplier(current_type);
value = amount.amount * value_multiplier( current_type, version );
}
// else lock forever and to be updated, do nothing here
}
Expand Down
Loading