Added new lottery_asset_create_operation

This commit is contained in:
Prabhjot 2019-08-09 13:01:57 -04:00
parent 0386ffebce
commit a0ae945f8d
11 changed files with 278 additions and 37 deletions

View file

@ -282,6 +282,7 @@ struct get_impacted_account_visitor
_impacted.insert( op.affiliate );
}
void operator()( const affiliate_referral_payout_operation& op ) { }
void operator()( const lottery_asset_create_operation& op) { }
void operator()( const ticket_purchase_operation& op )
{
_impacted.insert( op.buyer );

View file

@ -120,12 +120,6 @@ void_result asset_create_evaluator::do_evaluate( const asset_create_operation& o
FC_ASSERT( op.precision == op.bitasset_opts->short_backing_asset(d).precision );
}
if( op.extensions.which() == asset_extension::tag<lottery_asset_options>::value ) {
FC_ASSERT( op.common_options.max_supply >= 5 );
auto lottery_options = op.extensions.get<lottery_asset_options>();
lottery_options.validate();
FC_ASSERT( lottery_options.end_date > d.head_block_time() || lottery_options.end_date == time_point_sec() );
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
@ -164,6 +158,155 @@ object_id_type asset_create_evaluator::do_apply( const asset_create_operation& o
auto next_asset_id = db().get_index_type<asset_index>().get_next_id();
const asset_object& new_asset =
db().create<asset_object>( [&]( asset_object& a ) {
a.issuer = op.issuer;
a.symbol = op.symbol;
a.precision = op.precision;
a.options = op.common_options;
if( a.options.core_exchange_rate.base.asset_id.instance.value == 0 )
a.options.core_exchange_rate.quote.asset_id = next_asset_id;
else
a.options.core_exchange_rate.base.asset_id = next_asset_id;
a.dynamic_asset_data_id = dyn_asset.id;
if( op.bitasset_opts.valid() )
a.bitasset_data_id = bit_asset_id;
});
assert( new_asset.id == next_asset_id );
return new_asset.id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
void_result lottery_asset_create_evaluator::do_evaluate( const lottery_asset_create_operation& op )
{ try {
database& d = db();
const auto& chain_parameters = d.get_global_properties().parameters;
FC_ASSERT( op.common_options.whitelist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities );
FC_ASSERT( op.common_options.blacklist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities );
// Check that all authorities do exist
for( auto id : op.common_options.whitelist_authorities )
d.get_object(id);
for( auto id : op.common_options.blacklist_authorities )
d.get_object(id);
auto& asset_indx = d.get_index_type<asset_index>().indices().get<by_symbol>();
auto asset_symbol_itr = asset_indx.find( op.symbol );
FC_ASSERT( asset_symbol_itr == asset_indx.end() );
if( d.head_block_time() > HARDFORK_385_TIME )
{
if( d.head_block_time() <= HARDFORK_409_TIME )
{
auto dotpos = op.symbol.find( '.' );
if( dotpos != std::string::npos )
{
auto prefix = op.symbol.substr( 0, dotpos );
auto asset_symbol_itr = asset_indx.find( op.symbol );
FC_ASSERT( asset_symbol_itr != asset_indx.end(), "Asset ${s} may only be created by issuer of ${p}, but ${p} has not been registered",
("s",op.symbol)("p",prefix) );
FC_ASSERT( asset_symbol_itr->issuer == op.issuer, "Asset ${s} may only be created by issuer of ${p}, ${i}",
("s",op.symbol)("p",prefix)("i", op.issuer(d).name) );
}
}
else
{
auto dotpos = op.symbol.rfind( '.' );
if( dotpos != std::string::npos )
{
auto prefix = op.symbol.substr( 0, dotpos );
auto asset_symbol_itr = asset_indx.find( prefix );
FC_ASSERT( asset_symbol_itr != asset_indx.end(), "Asset ${s} may only be created by issuer of ${p}, but ${p} has not been registered",
("s",op.symbol)("p",prefix) );
FC_ASSERT( asset_symbol_itr->issuer == op.issuer, "Asset ${s} may only be created by issuer of ${p}, ${i}",
("s",op.symbol)("p",prefix)("i", op.issuer(d).name) );
}
}
}
else
{
auto dotpos = op.symbol.find( '.' );
if( dotpos != std::string::npos )
wlog( "Asset ${s} has a name which requires hardfork 385", ("s",op.symbol) );
}
// core_fee_paid -= core_fee_paid.value/2;
if( op.bitasset_opts )
{
const asset_object& backing = op.bitasset_opts->short_backing_asset(d);
if( backing.is_market_issued() )
{
const asset_bitasset_data_object& backing_bitasset_data = backing.bitasset_data(d);
const asset_object& backing_backing = backing_bitasset_data.options.short_backing_asset(d);
FC_ASSERT( !backing_backing.is_market_issued(),
"May not create a bitasset backed by a bitasset backed by a bitasset." );
FC_ASSERT( op.issuer != GRAPHENE_COMMITTEE_ACCOUNT || backing_backing.get_id() == asset_id_type(),
"May not create a blockchain-controlled market asset which is not backed by CORE.");
} else
FC_ASSERT( op.issuer != GRAPHENE_COMMITTEE_ACCOUNT || backing.get_id() == asset_id_type(),
"May not create a blockchain-controlled market asset which is not backed by CORE.");
FC_ASSERT( op.bitasset_opts->feed_lifetime_sec > chain_parameters.block_interval &&
op.bitasset_opts->force_settlement_delay_sec > chain_parameters.block_interval );
}
if( op.is_prediction_market )
{
FC_ASSERT( op.bitasset_opts );
FC_ASSERT( op.precision == op.bitasset_opts->short_backing_asset(d).precision );
}
if( op.extensions.which() == asset_extension::tag<lottery_asset_options>::value ) {
FC_ASSERT( op.common_options.max_supply >= 5 );
auto lottery_options = op.extensions;
lottery_options.validate();
FC_ASSERT( lottery_options.end_date > d.head_block_time() || lottery_options.end_date == time_point_sec() );
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
// copied from bitshares. (https://github.com/bitshares/bitshares-core/issues/429)
void lottery_asset_create_evaluator::pay_fee()
{
fee_is_odd = core_fee_paid.value & 1;
core_fee_paid -= core_fee_paid.value/2;
generic_evaluator::pay_fee();
}
object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_create_operation& op )
{ try {
// includes changes from bitshares. (https://github.com/bitshares/bitshares-core/issues/429)
bool hf_429 = fee_is_odd && db().head_block_time() > HARDFORK_CORE_429_TIME;
const asset_dynamic_data_object& dyn_asset =
db().create<asset_dynamic_data_object>( [&]( asset_dynamic_data_object& a ) {
a.current_supply = 0;
a.fee_pool = core_fee_paid - (hf_429 ? 1 : 0);
});
if( fee_is_odd && !hf_429 )
{
const auto& core_dd = db().get<asset_object>( asset_id_type() ).dynamic_data( db() );
db().modify( core_dd, [=]( asset_dynamic_data_object& dd ) {
dd.current_supply++;
});
}
asset_bitasset_data_id_type bit_asset_id;
if( op.bitasset_opts.valid() )
bit_asset_id = db().create<asset_bitasset_data_object>( [&]( asset_bitasset_data_object& a ) {
a.options = *op.bitasset_opts;
a.is_prediction_market = op.is_prediction_market;
}).id;
auto next_asset_id = db().get_index_type<asset_index>().get_next_id();
const asset_object& new_asset =
db().create<asset_object>( [&]( asset_object& a ) {
a.issuer = op.issuer;
@ -172,7 +315,8 @@ object_id_type asset_create_evaluator::do_apply( const asset_create_operation& o
a.options = op.common_options;
if( op.extensions.which() == asset_extension::tag<lottery_asset_options>::value ) {
a.precision = 0;
a.lottery_options = op.extensions.get<lottery_asset_options>(); //a.lottery_options->balance = asset( 0, a.lottery_options->ticket_price.asset_id );
a.lottery_options = op.extensions;
//a.lottery_options->balance = asset( 0, a.lottery_options->ticket_price.asset_id );
a.lottery_options->owner = a.id;
db().create<lottery_balance_object>([&](lottery_balance_object& lbo) {
lbo.lottery_id = a.id;

View file

@ -238,6 +238,7 @@ void database::initialize_evaluators()
register_evaluator<tournament_join_evaluator>();
register_evaluator<game_move_evaluator>();
register_evaluator<tournament_leave_evaluator>();
register_evaluator<lottery_asset_create_evaluator>();
register_evaluator<ticket_purchase_evaluator>();
register_evaluator<lottery_reward_evaluator>();
register_evaluator<lottery_end_evaluator>();

View file

@ -1,3 +1,3 @@
#ifndef HARDFORK_SWEEPS_TIME
#define HARDFORK_SWEEPS_TIME (fc::time_point_sec( 1515000764 ))
#define HARDFORK_SWEEPS_TIME (fc::time_point_sec( 1565272800 ))
#endif

View file

@ -44,6 +44,22 @@ namespace graphene { namespace chain {
bool fee_is_odd;
};
class lottery_asset_create_evaluator : public evaluator<lottery_asset_create_evaluator>
{
public:
typedef lottery_asset_create_operation operation_type;
void_result do_evaluate( const lottery_asset_create_operation& o );
object_id_type do_apply( const lottery_asset_create_operation& o );
/** override the default behavior defined by generic_evalautor which is to
* post the fee to fee_paying_account_stats.pending_fees
*/
virtual void pay_fee() override;
private:
bool fee_is_odd;
};
class asset_issue_evaluator : public evaluator<asset_issue_evaluator>
{
public:

View file

@ -400,7 +400,7 @@ namespace graphene { namespace chain {
class lottery_balance_object : public abstract_object<lottery_balance_object>
{
public:
static const uint8_t space_id = protocol_ids;
static const uint8_t space_id = implementation_ids;
static const uint8_t type_id = impl_lottery_balance_object_type;
asset_id_type lottery_id;
@ -416,7 +416,7 @@ namespace graphene { namespace chain {
/**
* @ingroup object_index
*/
using lottery_balance_index_type = multi_index_container<
typedef multi_index_container<
lottery_balance_object,
indexed_by<
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
@ -424,18 +424,18 @@ namespace graphene { namespace chain {
member<lottery_balance_object, asset_id_type, &lottery_balance_object::lottery_id>
>
>
>;
> lottery_balance_index_type;
/**
* @ingroup object_index
*/
using lottery_balance_index = generic_index<lottery_balance_object, lottery_balance_index_type>;
typedef generic_index<lottery_balance_object, lottery_balance_index_type> lottery_balance_index;
class sweeps_vesting_balance_object : public abstract_object<sweeps_vesting_balance_object>
{
public:
static const uint8_t space_id = protocol_ids;
static const uint8_t space_id = implementation_ids;
static const uint8_t type_id = impl_sweeps_vesting_balance_object_type;
@ -452,7 +452,7 @@ namespace graphene { namespace chain {
/**
* @ingroup object_index
*/
using sweeps_vesting_balance_index_type = multi_index_container<
typedef multi_index_container<
sweeps_vesting_balance_object,
indexed_by<
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
@ -460,12 +460,12 @@ namespace graphene { namespace chain {
member<sweeps_vesting_balance_object, account_id_type, &sweeps_vesting_balance_object::owner>
>
>
>;
> sweeps_vesting_balance_index_type;
/**
* @ingroup object_index
*/
using sweeps_vesting_balance_index = generic_index<sweeps_vesting_balance_object, sweeps_vesting_balance_index_type>;
typedef generic_index<sweeps_vesting_balance_object, sweeps_vesting_balance_index_type> sweeps_vesting_balance_index;
} } // graphene::chain

View file

@ -52,9 +52,6 @@ namespace graphene { namespace chain {
void validate()const;
};
typedef static_variant< void_t, lottery_asset_options > asset_extension;
/**
* @brief The asset_options struct contains options available on all assets in the network
*
@ -195,7 +192,6 @@ namespace graphene { namespace chain {
uint64_t symbol3 = 500000 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint64_t symbol4 = 300000 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint64_t long_symbol = 5000 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint64_t lottery_asset = 5000 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = 10; /// only required for large memos.
};
@ -219,7 +215,42 @@ namespace graphene { namespace chain {
/// For BitAssets, set this to true if the asset implements a @ref prediction_market; false otherwise
bool is_prediction_market = false;
// containing lottery_asset_options now
asset_extension extensions;
extensions_type extensions;
account_id_type fee_payer()const { return issuer; }
void validate()const;
share_type calculate_fee( const fee_parameters_type& k )const;
};
///Operation for creation of lottery
struct lottery_asset_create_operation : public base_operation
{
struct fee_parameters_type {
uint64_t lottery_asset = 5000 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = 10; /// only required for large lottery names.
};
asset fee;
/// This account must sign and pay the fee for this operation. Later, this account may update the asset
account_id_type issuer;
/// The ticker symbol of this asset
string symbol;
/// Number of digits to the right of decimal point, must be less than or equal to 12
uint8_t precision = 0;
/// Options common to all assets.
///
/// @note common_options.core_exchange_rate technically needs to store the asset ID of this new asset. Since this
/// ID is not known at the time this operation is created, create this price as though the new asset has instance
/// ID 1, and the chain will overwrite it with the new asset's ID.
asset_options common_options;
/// Options only available for BitAssets. MUST be non-null if and only if the @ref market_issued flag is set in
/// common_options.flags
optional<bitasset_options> bitasset_opts;
/// For BitAssets, set this to true if the asset implements a @ref prediction_market; false otherwise
bool is_prediction_market = false;
// containing lottery_asset_options now
lottery_asset_options extensions;
account_id_type fee_payer()const { return issuer; }
void validate()const;
@ -661,7 +692,8 @@ FC_REFLECT( graphene::chain::benefactor, (id)(share) )
FC_REFLECT( graphene::chain::lottery_asset_options, (benefactors)(owner)(winning_tickets)(ticket_price)(end_date)(ending_on_soldout)(is_active) )
FC_REFLECT( graphene::chain::asset_create_operation::fee_parameters_type, (symbol3)(symbol4)(long_symbol)(lottery_asset)(price_per_kbyte) )
FC_REFLECT( graphene::chain::asset_create_operation::fee_parameters_type, (symbol3)(symbol4)(long_symbol)(price_per_kbyte) )
FC_REFLECT( graphene::chain::lottery_asset_create_operation::fee_parameters_type, (lottery_asset)(price_per_kbyte) )
FC_REFLECT( graphene::chain::asset_global_settle_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::asset_settle_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::asset_settle_cancel_operation::fee_parameters_type, )
@ -685,6 +717,16 @@ FC_REFLECT( graphene::chain::asset_create_operation,
(is_prediction_market)
(extensions)
)
FC_REFLECT( graphene::chain::lottery_asset_create_operation,
(fee)
(issuer)
(symbol)
(precision)
(common_options)
(bitasset_opts)
(is_prediction_market)
(extensions)
)
FC_REFLECT( graphene::chain::asset_update_operation,
(fee)
(issuer)

View file

@ -131,6 +131,7 @@ namespace graphene { namespace chain {
event_group_delete_operation,
affiliate_payout_operation, // VIRTUAL
affiliate_referral_payout_operation, // VIRTUAL
lottery_asset_create_operation,
ticket_purchase_operation,
lottery_reward_operation,
lottery_end_operation,

View file

@ -78,18 +78,13 @@ share_type asset_issue_operation::calculate_fee(const fee_parameters_type& k)con
share_type asset_create_operation::calculate_fee(const asset_create_operation::fee_parameters_type& param)const
{
auto core_fee_required = param.long_symbol;
if( extensions.which() == asset_extension::tag<lottery_asset_options>::value ) {
core_fee_required = param.lottery_asset;
} else {
switch(symbol.size()) {
case 3: core_fee_required = param.symbol3;
break;
case 4: core_fee_required = param.symbol4;
break;
default:
break;
}
switch(symbol.size()) {
case 3: core_fee_required = param.symbol3;
break;
case 4: core_fee_required = param.symbol4;
break;
default:
break;
}
// common_options contains several lists and a string. Charge fees for its size
core_fee_required += calculate_data_fee( fc::raw::pack_size(*this), param.price_per_kbyte );
@ -116,6 +111,35 @@ void asset_create_operation::validate()const
FC_ASSERT(precision <= 12);
}
share_type lottery_asset_create_operation::calculate_fee(const lottery_asset_create_operation::fee_parameters_type& param)const
{
auto core_fee_required = param.lottery_asset;
// common_options contains several lists and a string. Charge fees for its size
core_fee_required += calculate_data_fee( fc::raw::pack_size(*this), param.price_per_kbyte );
return core_fee_required;
}
void lottery_asset_create_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( is_valid_symbol(symbol) );
common_options.validate();
if( common_options.issuer_permissions & (disable_force_settle|global_settle) )
FC_ASSERT( bitasset_opts.valid() );
if( is_prediction_market )
{
FC_ASSERT( bitasset_opts.valid(), "Cannot have a User-Issued Asset implement a prediction market." );
FC_ASSERT( common_options.issuer_permissions & global_settle );
}
if( bitasset_opts ) bitasset_opts->validate();
asset dummy = asset(1) * common_options.core_exchange_rate;
FC_ASSERT(dummy.asset_id == asset_id_type(1));
FC_ASSERT(precision <= 12);
}
void asset_update_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );

View file

@ -135,6 +135,7 @@ public:
std::string operator()(const account_create_operation& op)const;
std::string operator()(const account_update_operation& op)const;
std::string operator()(const asset_create_operation& op)const;
std::string operator()(const lottery_asset_create_operation& op)const;
std::string operator()(const asset_dividend_distribution_operation& op)const;
std::string operator()(const tournament_payout_operation& op)const;
std::string operator()(const bet_place_operation& op)const;
@ -1454,7 +1455,7 @@ public:
account_object issuer_account = get_account( issuer );
FC_ASSERT(!find_asset(symbol).valid(), "Asset with that symbol already exists!");
asset_create_operation create_op;
lottery_asset_create_operation create_op;
create_op.issuer = issuer_account.id;
create_op.symbol = symbol;
create_op.precision = 0;
@ -3344,7 +3345,18 @@ std::string operation_printer::operator()(const asset_create_operation& op) cons
if( op.bitasset_opts.valid() )
out << "BitAsset ";
else
out << "User-Issue Asset ";
out << "User-Issued Asset ";
out << "'" << op.symbol << "' with issuer " << wallet.get_account(op.issuer).name;
return fee(op.fee);
}
std::string operation_printer::operator()(const lottery_asset_create_operation& op) const
{
out << "Create ";
if( op.bitasset_opts.valid() )
out << "BitAsset ";
else
out << "User-Issued Asset ";
out << "'" << op.symbol << "' with issuer " << wallet.get_account(op.issuer).name;
return fee(op.fee);
}

View file

@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE( create_lottery_asset_test )
try {
generate_block();
asset_id_type test_asset_id = db.get_index<asset_object>().get_next_id();
asset_create_operation creator;
lottery_asset_create_operation creator;
creator.issuer = account_id_type();
creator.fee = asset();
char symbol[5] = "LOT";