Merge pull request #183 from peerplays-network/son_vesting

Son vesting balance implementation
This commit is contained in:
Alfredo Garcia 2019-10-20 10:29:15 -03:00 committed by GitHub
commit 412177964c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 172 additions and 31 deletions

View file

@ -232,8 +232,10 @@
#define TOURNAMENT_MAX_START_TIME_IN_FUTURE (60*60*24*7*4) // 1 month #define TOURNAMENT_MAX_START_TIME_IN_FUTURE (60*60*24*7*4) // 1 month
#define TOURNAMENT_MAX_START_DELAY (60*60*24*7) // 1 week #define TOURNAMENT_MAX_START_DELAY (60*60*24*7) // 1 week
#define MIN_SON_MEMBER_COUNT 15 #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 MIN_SON_PAY_DAILY_MAX (GRAPHENE_BLOCKCHAIN_PRECISION * int64_t(200))
#define SWEEPS_DEFAULT_DISTRIBUTION_PERCENTAGE (2*GRAPHENE_1_PERCENT) #define SWEEPS_DEFAULT_DISTRIBUTION_PERCENTAGE (2*GRAPHENE_1_PERCENT)
#define SWEEPS_DEFAULT_DISTRIBUTION_ASSET (graphene::chain::asset_id_type(0)) #define SWEEPS_DEFAULT_DISTRIBUTION_ASSET (graphene::chain::asset_id_type(0))
#define SWEEPS_VESTING_BALANCE_MULTIPLIER 100000000 #define SWEEPS_VESTING_BALANCE_MULTIPLIER 100000000
#define SWEEPS_ACCUMULATOR_ACCOUNT (graphene::chain::account_id_type(0)) #define SWEEPS_ACCUMULATOR_ACCOUNT (graphene::chain::account_id_type(0))
#define MIN_SON_PAY_DAILY_MAX (GRAPHENE_BLOCKCHAIN_PRECISION * int64_t(200))

View file

@ -27,6 +27,8 @@
#include <graphene/chain/protocol/types.hpp> #include <graphene/chain/protocol/types.hpp>
#include <fc/smart_ref_fwd.hpp> #include <fc/smart_ref_fwd.hpp>
#include <graphene/chain/hardfork.hpp>
namespace graphene { namespace chain { struct fee_schedule; } } namespace graphene { namespace chain { struct fee_schedule; } }
namespace graphene { namespace chain { namespace graphene { namespace chain {
@ -41,6 +43,8 @@ namespace graphene { namespace chain {
optional< uint16_t > sweeps_distribution_percentage; optional< uint16_t > sweeps_distribution_percentage;
optional< asset_id_type > sweeps_distribution_asset; optional< asset_id_type > sweeps_distribution_asset;
optional< account_id_type > sweeps_vesting_accumulator_account; optional< account_id_type > sweeps_vesting_accumulator_account;
optional < uint32_t > son_vesting_amount;
optional < uint32_t > son_vesting_period;
optional < uint32_t > son_pay_daily_max; optional < uint32_t > son_pay_daily_max;
}; };
@ -125,6 +129,11 @@ namespace graphene { namespace chain {
inline uint16_t son_count()const { inline uint16_t son_count()const {
return extensions.value.son_count.valid() ? *extensions.value.son_count : MIN_SON_MEMBER_COUNT; return extensions.value.son_count.valid() ? *extensions.value.son_count : MIN_SON_MEMBER_COUNT;
} }
inline uint32_t son_vesting_amount()const {
return extensions.value.son_vesting_amount.valid() ? *extensions.value.son_vesting_amount : SON_VESTING_AMOUNT; /// current period start date
}
inline uint32_t son_vesting_period()const {
return extensions.value.son_vesting_period.valid() ? *extensions.value.son_vesting_period : SON_VESTING_PERIOD; /// current period start date
inline uint16_t son_pay_daily_max()const { inline uint16_t son_pay_daily_max()const {
return extensions.value.son_pay_daily_max.valid() ? *extensions.value.son_pay_daily_max : MIN_SON_PAY_DAILY_MAX; return extensions.value.son_pay_daily_max.valid() ? *extensions.value.son_pay_daily_max : MIN_SON_PAY_DAILY_MAX;
} }
@ -142,6 +151,8 @@ FC_REFLECT( graphene::chain::parameter_extension,
(sweeps_distribution_percentage) (sweeps_distribution_percentage)
(sweeps_distribution_asset) (sweeps_distribution_asset)
(sweeps_vesting_accumulator_account) (sweeps_vesting_accumulator_account)
(son_vesting_amount)
(son_vesting_period)
(son_pay_daily_max) (son_pay_daily_max)
) )

View file

@ -26,6 +26,8 @@
namespace graphene { namespace chain { namespace graphene { namespace chain {
enum class vesting_balance_type { normal, gpos, son };
struct linear_vesting_policy_initializer struct linear_vesting_policy_initializer
{ {
/** while vesting begins on begin_timestamp, none may be claimed before vesting_cliff_seconds have passed */ /** while vesting begins on begin_timestamp, none may be claimed before vesting_cliff_seconds have passed */
@ -42,9 +44,10 @@ namespace graphene { namespace chain {
cdd_vesting_policy_initializer( uint32_t vest_sec = 0, fc::time_point_sec sc = fc::time_point_sec() ):start_claim(sc),vesting_seconds(vest_sec){} cdd_vesting_policy_initializer( uint32_t vest_sec = 0, fc::time_point_sec sc = fc::time_point_sec() ):start_claim(sc),vesting_seconds(vest_sec){}
}; };
typedef fc::static_variant<linear_vesting_policy_initializer, cdd_vesting_policy_initializer> vesting_policy_initializer; struct dormant_vesting_policy_initializer {};
typedef fc::static_variant<linear_vesting_policy_initializer, cdd_vesting_policy_initializer,
dormant_vesting_policy_initializer> vesting_policy_initializer;
/** /**
* @brief Create a vesting balance. * @brief Create a vesting balance.
@ -72,6 +75,7 @@ namespace graphene { namespace chain {
account_id_type owner; ///< Who is able to withdraw the balance account_id_type owner; ///< Who is able to withdraw the balance
asset amount; asset amount;
vesting_policy_initializer policy; vesting_policy_initializer policy;
vesting_balance_type balance_type;
account_id_type fee_payer()const { return creator; } account_id_type fee_payer()const { return creator; }
void validate()const void validate()const
@ -112,9 +116,12 @@ namespace graphene { namespace chain {
FC_REFLECT( graphene::chain::vesting_balance_create_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::vesting_balance_create_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::vesting_balance_create_operation, (fee)(creator)(owner)(amount)(policy) ) FC_REFLECT( graphene::chain::vesting_balance_create_operation, (fee)(creator)(owner)(amount)(policy)(balance_type) )
FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation, (fee)(vesting_balance)(owner)(amount) ) FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation, (fee)(vesting_balance)(owner)(amount) )
FC_REFLECT(graphene::chain::linear_vesting_policy_initializer, (begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds) ) FC_REFLECT(graphene::chain::linear_vesting_policy_initializer, (begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds) )
FC_REFLECT(graphene::chain::cdd_vesting_policy_initializer, (start_claim)(vesting_seconds) ) FC_REFLECT(graphene::chain::cdd_vesting_policy_initializer, (start_claim)(vesting_seconds) )
FC_REFLECT(graphene::chain::dormant_vesting_policy_initializer, )
FC_REFLECT_TYPENAME( graphene::chain::vesting_policy_initializer ) FC_REFLECT_TYPENAME( graphene::chain::vesting_policy_initializer )
FC_REFLECT_ENUM( graphene::chain::vesting_balance_type, (normal)(gpos)(son) )

View file

@ -24,6 +24,7 @@
#pragma once #pragma once
#include <graphene/chain/protocol/asset.hpp> #include <graphene/chain/protocol/asset.hpp>
#include <graphene/chain/protocol/vesting.hpp>
#include <graphene/db/object.hpp> #include <graphene/db/object.hpp>
#include <graphene/db/generic_index.hpp> #include <graphene/db/generic_index.hpp>
@ -118,10 +119,32 @@ namespace graphene { namespace chain {
void on_withdraw(const vesting_policy_context& ctx); void on_withdraw(const vesting_policy_context& ctx);
}; };
/**
* @brief Cant withdraw anything while balance is in this policy.
*
* This policy is needed to register SON users where balance may be claimable only after
* the SON object is deleted(plus a linear policy).
* When deleting a SON member the dormant mode will be replaced by a linear policy.
*
* @note New funds may not be added to a dormant vesting balance.
*/
struct dormant_vesting_policy
{
asset get_allowed_withdraw(const vesting_policy_context& ctx)const;
bool is_deposit_allowed(const vesting_policy_context& ctx)const;
bool is_deposit_vested_allowed(const vesting_policy_context&)const { return false; }
bool is_withdraw_allowed(const vesting_policy_context& ctx)const;
void on_deposit(const vesting_policy_context& ctx);
void on_deposit_vested(const vesting_policy_context&)
{ FC_THROW( "May not deposit vested into a linear vesting balance." ); }
void on_withdraw(const vesting_policy_context& ctx);
};
typedef fc::static_variant< typedef fc::static_variant<
linear_vesting_policy, linear_vesting_policy,
cdd_vesting_policy cdd_vesting_policy,
> vesting_policy; dormant_vesting_policy
> vesting_policy;
/** /**
* Vesting balance object is a balance that is locked by the blockchain for a period of time. * Vesting balance object is a balance that is locked by the blockchain for a period of time.
@ -140,6 +163,9 @@ namespace graphene { namespace chain {
/// The vesting policy stores details on when funds vest, and controls when they may be withdrawn /// The vesting policy stores details on when funds vest, and controls when they may be withdrawn
vesting_policy policy; vesting_policy policy;
/// We can have 3 types of vesting, gpos, son and the rest
vesting_balance_type balance_type = vesting_balance_type::normal;
vesting_balance_object() {} vesting_balance_object() {}
asset_id_type get_asset_id() const { return balance.asset_id; } asset_id_type get_asset_id() const { return balance.asset_id; }
@ -219,10 +245,13 @@ FC_REFLECT(graphene::chain::cdd_vesting_policy,
(coin_seconds_earned_last_update) (coin_seconds_earned_last_update)
) )
FC_REFLECT(graphene::chain::dormant_vesting_policy, )
FC_REFLECT_TYPENAME( graphene::chain::vesting_policy ) FC_REFLECT_TYPENAME( graphene::chain::vesting_policy )
FC_REFLECT_DERIVED(graphene::chain::vesting_balance_object, (graphene::db::object), FC_REFLECT_DERIVED(graphene::chain::vesting_balance_object, (graphene::db::object),
(owner) (owner)
(balance) (balance)
(policy) (policy)
(balance_type)
) )

View file

@ -3,6 +3,7 @@
#include <graphene/chain/database.hpp> #include <graphene/chain/database.hpp>
#include <graphene/chain/son_object.hpp> #include <graphene/chain/son_object.hpp>
#include <graphene/chain/hardfork.hpp> #include <graphene/chain/hardfork.hpp>
#include <graphene/chain/vesting_balance_object.hpp>
namespace graphene { namespace chain { namespace graphene { namespace chain {
@ -10,7 +11,9 @@ void_result create_son_evaluator::do_evaluate(const son_create_operation& op)
{ try{ { try{
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
FC_ASSERT(db().get(op.owner_account).is_lifetime_member(), "Only Lifetime members may register a SON."); FC_ASSERT(db().get(op.owner_account).is_lifetime_member(), "Only Lifetime members may register a SON.");
return void_result(); FC_ASSERT(op.deposit(db()).policy.which() == vesting_policy::tag<dormant_vesting_policy>::value,
"Deposit balance must have dormant vesting policy");
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) } } FC_CAPTURE_AND_RETHROW( (op) ) }
object_id_type create_son_evaluator::do_apply(const son_create_operation& op) object_id_type create_son_evaluator::do_apply(const son_create_operation& op)
@ -69,7 +72,19 @@ void_result delete_son_evaluator::do_evaluate(const son_delete_operation& op)
void_result delete_son_evaluator::do_apply(const son_delete_operation& op) void_result delete_son_evaluator::do_apply(const son_delete_operation& op)
{ try { { try {
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>(); const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
db().remove(*idx.find(op.son_id)); auto son = idx.find(op.son_id);
if(son != idx.end()) {
vesting_balance_object deposit = son->deposit(db());
linear_vesting_policy new_vesting_policy;
new_vesting_policy.begin_timestamp = db().head_block_time();
new_vesting_policy.vesting_cliff_seconds = db().get_global_properties().parameters.son_vesting_period();
db().modify(son->deposit(db()), [&new_vesting_policy](vesting_balance_object &vbo) {
vbo.policy = new_vesting_policy;
});
db().remove(*son);
}
return void_result(); return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) } } FC_CAPTURE_AND_RETHROW( (op) ) }

View file

@ -42,6 +42,12 @@ void_result vesting_balance_create_evaluator::do_evaluate( const vesting_balance
FC_ASSERT( d.get_balance( creator_account.id, op.amount.asset_id ) >= op.amount ); FC_ASSERT( d.get_balance( creator_account.id, op.amount.asset_id ) >= op.amount );
FC_ASSERT( !op.amount.asset_id(d).is_transfer_restricted() ); FC_ASSERT( !op.amount.asset_id(d).is_transfer_restricted() );
if(d.head_block_time() < HARDFORK_SON_TIME) // Todo: can be removed after gpos hf time pass
FC_ASSERT( op.balance_type == vesting_balance_type::normal);
if(d.head_block_time() >= HARDFORK_SON_TIME && op.balance_type == vesting_balance_type::son) // Todo: hf check can be removed after pass
FC_ASSERT( op.amount.amount >= d.get_global_properties().parameters.son_vesting_amount() );
return void_result(); return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) } } FC_CAPTURE_AND_RETHROW( (op) ) }
@ -76,6 +82,11 @@ struct init_policy_visitor
policy.coin_seconds_earned_last_update = now; policy.coin_seconds_earned_last_update = now;
p = policy; p = policy;
} }
void operator()( const dormant_vesting_policy_initializer& i )const
{
dormant_vesting_policy policy;
p = policy;
}
}; };
object_id_type vesting_balance_create_evaluator::do_apply( const vesting_balance_create_operation& op ) object_id_type vesting_balance_create_evaluator::do_apply( const vesting_balance_create_operation& op )
@ -92,10 +103,9 @@ object_id_type vesting_balance_create_evaluator::do_apply( const vesting_balance
// If making changes to this logic, check if those changes should also be made there as well. // If making changes to this logic, check if those changes should also be made there as well.
obj.owner = op.owner; obj.owner = op.owner;
obj.balance = op.amount; obj.balance = op.amount;
obj.balance_type = op.balance_type;
op.policy.visit( init_policy_visitor( obj.policy, op.amount.amount, now ) ); op.policy.visit( init_policy_visitor( obj.policy, op.amount.amount, now ) );
} ); } );
return vbo.id; return vbo.id;
} FC_CAPTURE_AND_RETHROW( (op) ) } } FC_CAPTURE_AND_RETHROW( (op) ) }

View file

@ -157,6 +157,33 @@ bool cdd_vesting_policy::is_withdraw_allowed(const vesting_policy_context& ctx)c
return (ctx.amount <= get_allowed_withdraw(ctx)); return (ctx.amount <= get_allowed_withdraw(ctx));
} }
asset dormant_vesting_policy::get_allowed_withdraw( const vesting_policy_context& ctx )const
{
share_type allowed_withdraw = 0;
return asset( allowed_withdraw, ctx.balance.asset_id );
}
void dormant_vesting_policy::on_deposit(const vesting_policy_context& ctx)
{
}
bool dormant_vesting_policy::is_deposit_allowed(const vesting_policy_context& ctx)const
{
return (ctx.amount.asset_id == ctx.balance.asset_id)
&& sum_below_max_shares(ctx.amount, ctx.balance);
}
void dormant_vesting_policy::on_withdraw(const vesting_policy_context& ctx)
{
}
bool dormant_vesting_policy::is_withdraw_allowed(const vesting_policy_context& ctx)const
{
return (ctx.amount.asset_id == ctx.balance.asset_id)
&& (ctx.amount <= get_allowed_withdraw(ctx));
}
#define VESTING_VISITOR(NAME, MAYBE_CONST) \ #define VESTING_VISITOR(NAME, MAYBE_CONST) \
struct NAME ## _visitor \ struct NAME ## _visitor \
{ \ { \

View file

@ -1561,7 +1561,7 @@ BOOST_AUTO_TEST_CASE( vesting_balance_create_test )
op.amount = test_asset.amount( 100 ); op.amount = test_asset.amount( 100 );
//op.vesting_seconds = 60*60*24; //op.vesting_seconds = 60*60*24;
op.policy = cdd_vesting_policy_initializer{ 60*60*24 }; op.policy = cdd_vesting_policy_initializer{ 60*60*24 };
//op.balance_type == vesting_balance_type::unspecified; op.balance_type == vesting_balance_type::normal;
// Fee must be non-negative // Fee must be non-negative
REQUIRE_OP_VALIDATION_SUCCESS( op, fee, core.amount(1) ); REQUIRE_OP_VALIDATION_SUCCESS( op, fee, core.amount(1) );
@ -1581,7 +1581,7 @@ BOOST_AUTO_TEST_CASE( vesting_balance_create_test )
op.creator = alice_account.get_id(); op.creator = alice_account.get_id();
op.owner = alice_account.get_id(); op.owner = alice_account.get_id();
//op.balance_type = vesting_balance_type::unspecified; op.balance_type = vesting_balance_type::normal;
account_id_type nobody = account_id_type(1234); account_id_type nobody = account_id_type(1234);
@ -1652,7 +1652,7 @@ BOOST_AUTO_TEST_CASE( vesting_balance_withdraw_test )
create_op.owner = owner; create_op.owner = owner;
create_op.amount = amount; create_op.amount = amount;
create_op.policy = cdd_vesting_policy_initializer(vesting_seconds); create_op.policy = cdd_vesting_policy_initializer(vesting_seconds);
//create_op.balance_type = vesting_balance_type::unspecified; create_op.balance_type = vesting_balance_type::normal;
tx.operations.push_back( create_op ); tx.operations.push_back( create_op );
set_expiration( db, tx ); set_expiration( db, tx );

View file

@ -1316,7 +1316,7 @@ BOOST_AUTO_TEST_CASE(zero_second_vbo)
create_op.owner = alice_id; create_op.owner = alice_id;
create_op.amount = asset(500); create_op.amount = asset(500);
create_op.policy = pinit; create_op.policy = pinit;
//create_op.balance_type = vesting_balance_type::unspecified; create_op.balance_type = vesting_balance_type::normal;
signed_transaction create_tx; signed_transaction create_tx;
create_tx.operations.push_back( create_op ); create_tx.operations.push_back( create_op );
@ -1400,7 +1400,7 @@ BOOST_AUTO_TEST_CASE( vbo_withdraw_different )
create_op.owner = alice_id; create_op.owner = alice_id;
create_op.amount = asset(100, stuff_id); create_op.amount = asset(100, stuff_id);
create_op.policy = pinit; create_op.policy = pinit;
//create_op.balance_type = vesting_balance_type::unspecified; create_op.balance_type = vesting_balance_type::normal;
signed_transaction create_tx; signed_transaction create_tx;
create_tx.operations.push_back( create_op ); create_tx.operations.push_back( create_op );

View file

@ -5,6 +5,7 @@
#include <graphene/chain/hardfork.hpp> #include <graphene/chain/hardfork.hpp>
#include <graphene/chain/son_object.hpp> #include <graphene/chain/son_object.hpp>
#include <graphene/chain/son_evaluator.hpp> #include <graphene/chain/son_evaluator.hpp>
#include <graphene/chain/vesting_balance_object.hpp>
using namespace graphene::chain; using namespace graphene::chain;
using namespace graphene::chain::test; using namespace graphene::chain::test;
@ -13,9 +14,6 @@ BOOST_FIXTURE_TEST_SUITE( son_operation_tests, database_fixture )
BOOST_AUTO_TEST_CASE( create_son_test ) { BOOST_AUTO_TEST_CASE( create_son_test ) {
generate_blocks(HARDFORK_SON_TIME); generate_blocks(HARDFORK_SON_TIME);
while (db.head_block_time() <= HARDFORK_SON_TIME) {
generate_block();
}
generate_block(); generate_block();
set_expiration(db, trx); set_expiration(db, trx);
@ -24,8 +22,8 @@ BOOST_AUTO_TEST_CASE( create_son_test ) {
upgrade_to_lifetime_member(alice); upgrade_to_lifetime_member(alice);
upgrade_to_lifetime_member(bob); upgrade_to_lifetime_member(bob);
transfer( committee_account, alice_id, asset( 100000 ) ); transfer( committee_account, alice_id, asset( 1000*GRAPHENE_BLOCKCHAIN_PRECISION ) );
transfer( committee_account, bob_id, asset( 100000 ) ); transfer( committee_account, bob_id, asset( 1000*GRAPHENE_BLOCKCHAIN_PRECISION ) );
set_expiration(db, trx); set_expiration(db, trx);
std::string test_url = "https://create_son_test"; std::string test_url = "https://create_son_test";
@ -36,31 +34,51 @@ BOOST_AUTO_TEST_CASE( create_son_test ) {
vesting_balance_create_operation op; vesting_balance_create_operation op;
op.creator = alice_id; op.creator = alice_id;
op.owner = alice_id; op.owner = alice_id;
op.amount = asset(10); op.amount = asset(10*GRAPHENE_BLOCKCHAIN_PRECISION);
//op.balance_type = vesting_balance_type::unspecified; op.balance_type = vesting_balance_type::son;
op.policy = dormant_vesting_policy_initializer {};
trx.operations.push_back(op);
// amount in the son balance need to be at least 50
GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception );
op.amount = asset(50*GRAPHENE_BLOCKCHAIN_PRECISION);
trx.clear();
trx.operations.push_back(op); trx.operations.push_back(op);
set_expiration(db, trx);
processed_transaction ptx = PUSH_TX(db, trx, ~0); processed_transaction ptx = PUSH_TX(db, trx, ~0);
trx.clear();
deposit = ptx.operation_results[0].get<object_id_type>(); deposit = ptx.operation_results[0].get<object_id_type>();
auto deposit_vesting = db.get<vesting_balance_object>(ptx.operation_results[0].get<object_id_type>());
BOOST_CHECK_EQUAL(deposit(db).balance.amount.value, 50*GRAPHENE_BLOCKCHAIN_PRECISION);
auto now = db.head_block_time();
BOOST_CHECK_EQUAL(deposit(db).is_withdraw_allowed(now, asset(50*GRAPHENE_BLOCKCHAIN_PRECISION)), false); // cant withdraw
} }
// create payment vesting generate_block();
vesting_balance_id_type payment; set_expiration(db, trx);
// create payment normal vesting
vesting_balance_id_type payment ;
{ {
vesting_balance_create_operation op; vesting_balance_create_operation op;
op.creator = alice_id; op.creator = alice_id;
op.owner = alice_id; op.owner = alice_id;
op.amount = asset(10); op.amount = asset(1*GRAPHENE_BLOCKCHAIN_PRECISION);
//op.balance_type = vesting_balance_type::unspecified; op.balance_type = vesting_balance_type::normal;
op.validate();
trx.operations.push_back(op); trx.operations.push_back(op);
set_expiration(db, trx); trx.validate();
processed_transaction ptx = PUSH_TX(db, trx, ~0); processed_transaction ptx = PUSH_TX(db, trx, ~0);
trx.clear(); trx.clear();
payment = ptx.operation_results[0].get<object_id_type>(); payment = ptx.operation_results[0].get<object_id_type>();
} }
generate_block();
set_expiration(db, trx);
// alice became son // alice became son
{ {
son_create_operation op; son_create_operation op;
@ -112,10 +130,14 @@ BOOST_AUTO_TEST_CASE( update_son_test ) {
} }
BOOST_AUTO_TEST_CASE( delete_son_test ) { BOOST_AUTO_TEST_CASE( delete_son_test ) {
try {
INVOKE(create_son_test); INVOKE(create_son_test);
GET_ACTOR(alice); GET_ACTOR(alice);
auto deposit_vesting = db.get<vesting_balance_object>(vesting_balance_id_type(0));
auto now = db.head_block_time();
BOOST_CHECK_EQUAL(deposit_vesting.is_withdraw_allowed(now, asset(50)), false); // cant withdraw
{ {
son_delete_operation op; son_delete_operation op;
op.owner_account = alice_id; op.owner_account = alice_id;
@ -129,7 +151,25 @@ BOOST_AUTO_TEST_CASE( delete_son_test ) {
const auto& idx = db.get_index_type<son_index>().indices().get<by_account>(); const auto& idx = db.get_index_type<son_index>().indices().get<by_account>();
BOOST_REQUIRE( idx.empty() ); BOOST_REQUIRE( idx.empty() );
deposit_vesting = db.get<vesting_balance_object>(vesting_balance_id_type(0));
BOOST_CHECK_EQUAL(deposit_vesting.policy.get<linear_vesting_policy>().vesting_cliff_seconds,
db.get_global_properties().parameters.son_vesting_period()); // in linear policy
now = db.head_block_time();
BOOST_CHECK_EQUAL(deposit_vesting.is_withdraw_allowed(now, asset(50)), false); // but still cant withdraw
generate_blocks(now + fc::seconds(db.get_global_properties().parameters.son_vesting_period()));
generate_block();
deposit_vesting = db.get<vesting_balance_object>(vesting_balance_id_type(0));
now = db.head_block_time();
BOOST_CHECK_EQUAL(deposit_vesting.is_withdraw_allowed(now, asset(50)), true); // after 2 days withdraw is allowed
} }
catch (fc::exception &e) {
edump((e.to_detail_string()));
throw;
} }
BOOST_AUTO_TEST_CASE( update_delete_not_own ) { // fee payer needs to be the son object owner BOOST_AUTO_TEST_CASE( update_delete_not_own ) { // fee payer needs to be the son object owner
try { try {