ticket_purchase_operation implemented. added lottery_options to asset
This commit is contained in:
parent
b953ac9e88
commit
17e6a9baf9
23 changed files with 564 additions and 41 deletions
|
|
@ -282,6 +282,10 @@ struct get_impacted_account_visitor
|
|||
_impacted.insert( op.affiliate );
|
||||
}
|
||||
void operator()( const affiliate_referral_payout_operation& op ) { }
|
||||
void operator()( const ticket_purchase_operation& op )
|
||||
{
|
||||
_impacted.insert( op.buyer );
|
||||
}
|
||||
};
|
||||
|
||||
void operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ add_library( graphene_chain
|
|||
protocol/proposal.cpp
|
||||
protocol/withdraw_permission.cpp
|
||||
protocol/asset_ops.cpp
|
||||
protocol/lottery_ops.cpp
|
||||
protocol/memo.cpp
|
||||
protocol/worker.cpp
|
||||
protocol/custom.cpp
|
||||
|
|
@ -72,6 +73,7 @@ add_library( graphene_chain
|
|||
witness_evaluator.cpp
|
||||
committee_member_evaluator.cpp
|
||||
asset_evaluator.cpp
|
||||
lottery_evaluator.cpp
|
||||
transfer_evaluator.cpp
|
||||
proposal_evaluator.cpp
|
||||
market_evaluator.cpp
|
||||
|
|
|
|||
|
|
@ -150,6 +150,11 @@ object_id_type asset_create_evaluator::do_apply( const asset_create_operation& o
|
|||
a.symbol = op.symbol;
|
||||
a.precision = op.precision;
|
||||
a.options = op.common_options;
|
||||
if( op.extension.which() == asset_extension::tag<lottery_asset_options>::value ) {
|
||||
a.precision = 0;
|
||||
a.lottery_options = op.extension.get<lottery_asset_options>();
|
||||
a.lottery_options->balance = asset( 0, a.lottery_options->ticket_price.asset_id );
|
||||
}
|
||||
if( a.options.core_exchange_rate.base.asset_id.instance.value == 0 )
|
||||
a.options.core_exchange_rate.quote.asset_id = next_asset_id;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -89,6 +89,12 @@ void graphene::chain::asset_bitasset_data_object::update_median_feeds(time_point
|
|||
}
|
||||
|
||||
|
||||
time_point_sec asset_object::get_lottery_expiration() const
|
||||
{
|
||||
if( lottery_options )
|
||||
return lottery_options->end_date;
|
||||
return time_point_sec();
|
||||
}
|
||||
|
||||
asset asset_object::amount_from_string(string amount_string) const
|
||||
{ try {
|
||||
|
|
|
|||
|
|
@ -465,20 +465,20 @@ signed_block database::_generate_block(
|
|||
pending_block.transaction_merkle_root = pending_block.calculate_merkle_root();
|
||||
pending_block.witness = witness_id;
|
||||
|
||||
// Genesis witnesses start with a default initial secret
|
||||
if( secret_hash_type::hash( witness_obj.previous_secret ) == witness_obj.next_secret_hash ) {
|
||||
pending_block.previous_secret = witness_obj.previous_secret;
|
||||
// Genesis witnesses start with a default initial secret
|
||||
if( witness_obj.next_secret_hash == secret_hash_type::hash( secret_hash_type() ) ) {
|
||||
pending_block.previous_secret = secret_hash_type();
|
||||
} else {
|
||||
secret_hash_type::encoder last_enc;
|
||||
fc::raw::pack( last_enc, block_signing_private_key );
|
||||
fc::raw::pack( last_enc, witness_obj.previous_secret );
|
||||
pending_block.previous_secret = last_enc.result();
|
||||
}
|
||||
secret_hash_type::encoder last_enc;
|
||||
fc::raw::pack( last_enc, block_signing_private_key );
|
||||
fc::raw::pack( last_enc, witness_obj.previous_secret );
|
||||
pending_block.previous_secret = last_enc.result();
|
||||
}
|
||||
|
||||
secret_hash_type::encoder next_enc;
|
||||
fc::raw::pack( next_enc, block_signing_private_key );
|
||||
fc::raw::pack( next_enc, pending_block.previous_secret );
|
||||
pending_block.next_secret_hash = secret_hash_type::hash(next_enc.result());
|
||||
secret_hash_type::encoder next_enc;
|
||||
fc::raw::pack( next_enc, block_signing_private_key );
|
||||
fc::raw::pack( next_enc, pending_block.previous_secret );
|
||||
pending_block.next_secret_hash = secret_hash_type::hash(next_enc.result());
|
||||
|
||||
if( !(skip & skip_witness_signature) )
|
||||
pending_block.sign( block_signing_private_key );
|
||||
|
|
@ -490,7 +490,7 @@ signed_block database::_generate_block(
|
|||
}
|
||||
|
||||
push_block( pending_block, skip );
|
||||
idump(( get_winner_numbers(asset_id_type(3), 253, 64) ));
|
||||
|
||||
return pending_block;
|
||||
} FC_CAPTURE_AND_RETHROW( (witness_id) ) }
|
||||
|
||||
|
|
@ -741,8 +741,9 @@ const witness_object& database::validate_block_header( uint32_t skip, const sign
|
|||
FC_ASSERT( head_block_time() < next_block.timestamp, "", ("head_block_time",head_block_time())("next",next_block.timestamp)("blocknum",next_block.block_num()) );
|
||||
const witness_object& witness = next_block.witness(*this);
|
||||
//DLN: TODO: Temporarily commented out to test shuffle vs RNG scheduling algorithm for witnesses, this was causing shuffle agorithm to fail during create_witness test. This should be re-enabled for RNG, and maybe for shuffle too, don't really know for sure.
|
||||
FC_ASSERT( secret_hash_type::hash( next_block.previous_secret ) == witness.next_secret_hash, "",
|
||||
("previous_secret", next_block.previous_secret)("next_secret_hash", witness.next_secret_hash));
|
||||
if( next_block.timestamp > HARDFORK_SWEEPS_TIME )
|
||||
FC_ASSERT( secret_hash_type::hash( next_block.previous_secret ) == witness.next_secret_hash, "",
|
||||
( "previous_secret", next_block.previous_secret )( "next_secret_hash", witness.next_secret_hash ) );
|
||||
|
||||
if( !(skip&skip_witness_signature) )
|
||||
FC_ASSERT( next_block.validate_signee( witness.signing_key ) );
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
|
||||
#include <graphene/chain/account_evaluator.hpp>
|
||||
#include <graphene/chain/asset_evaluator.hpp>
|
||||
#include <graphene/chain/lottery_evaluator.hpp>
|
||||
#include <graphene/chain/assert_evaluator.hpp>
|
||||
#include <graphene/chain/balance_evaluator.hpp>
|
||||
#include <graphene/chain/committee_member_evaluator.hpp>
|
||||
|
|
@ -237,6 +238,7 @@ void database::initialize_evaluators()
|
|||
register_evaluator<tournament_join_evaluator>();
|
||||
register_evaluator<game_move_evaluator>();
|
||||
register_evaluator<tournament_leave_evaluator>();
|
||||
register_evaluator<ticket_purchase_evaluator>();
|
||||
}
|
||||
|
||||
void database::initialize_indexes()
|
||||
|
|
@ -852,7 +854,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
|||
std::for_each(genesis_state.initial_witness_candidates.begin(), genesis_state.initial_witness_candidates.end(),
|
||||
[&](const genesis_state_type::initial_witness_type& witness) {
|
||||
witness_create_operation op;
|
||||
op.initial_secret = secret_hash_type::hash(witness.owner_name);
|
||||
op.initial_secret = secret_hash_type();
|
||||
op.witness_account = get_account_id(witness.owner_name);
|
||||
op.block_signing_key = witness.block_signing_key;
|
||||
apply_operation(genesis_eval_state, op);
|
||||
|
|
|
|||
|
|
@ -269,6 +269,10 @@ struct get_impacted_account_visitor
|
|||
_impacted.insert( op.affiliate );
|
||||
}
|
||||
void operator()( const affiliate_referral_payout_operation& op ) { }
|
||||
void operator()( const ticket_purchase_operation& op )
|
||||
{
|
||||
_impacted.insert( op.buyer );
|
||||
}
|
||||
};
|
||||
|
||||
void operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )
|
||||
|
|
|
|||
4
libraries/chain/hardfork.d/CORE-429.hf
Normal file
4
libraries/chain/hardfork.d/CORE-429.hf
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// bitshares-core #429 rounding issue when creating assets
|
||||
#ifndef HARDFORK_CORE_429_TIME
|
||||
#define HARDFORK_CORE_429_TIME (fc::time_point_sec( 1510320000 ))
|
||||
#endif
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
// GPOS HARDFORK Friday, March 15, 2019 11:57:28 PM
|
||||
#ifndef HARDFORK_GPOS_TIME
|
||||
#define HARDFORK_GPOS_TIME (fc::time_point_sec( 1552694248 ))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
|||
3
libraries/chain/hardfork.d/SWEEPS.hf
Normal file
3
libraries/chain/hardfork.d/SWEEPS.hf
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#ifndef HARDFORK_SWEEPS_TIME
|
||||
#define HARDFORK_SWEEPS_TIME (fc::time_point_sec( 1510320000 ))
|
||||
#endif
|
||||
|
|
@ -87,6 +87,8 @@ namespace graphene { namespace chain {
|
|||
|
||||
/// @return true if this is a market-issued asset; false otherwise.
|
||||
bool is_market_issued()const { return bitasset_data_id.valid(); }
|
||||
/// @return true if this is lottery asset; false otherwise.
|
||||
bool is_lottery()const { return lottery_options.valid(); }
|
||||
/// @return true if users may request force-settlement of this market-issued asset; false otherwise
|
||||
bool can_force_settle()const { return !(options.flags & disable_force_settle); }
|
||||
/// @return true if the issuer of this market-issued asset may globally settle the asset; false otherwise
|
||||
|
|
@ -124,7 +126,9 @@ namespace graphene { namespace chain {
|
|||
|
||||
asset_options options;
|
||||
|
||||
|
||||
// Extra data associated with lottery options. This field is non-null if is_lottery() returns true
|
||||
optional<lottery_asset_options> lottery_options;
|
||||
time_point_sec get_lottery_expiration() const;
|
||||
/// Current supply, fee pool, and collected fees are stored in a separate object as they change frequently.
|
||||
asset_dynamic_data_id_type dynamic_asset_data_id;
|
||||
/// Extra data associated with BitAssets. This field is non-null if and only if is_market_issued() returns true
|
||||
|
|
@ -238,15 +242,32 @@ namespace graphene { namespace chain {
|
|||
//typedef flat_index<asset_bitasset_data_object> asset_bitasset_data_index;
|
||||
typedef generic_index<asset_bitasset_data_object, asset_bitasset_data_object_multi_index_type> asset_bitasset_data_index;
|
||||
|
||||
// used to sort active_lotteries index
|
||||
struct lottery_asset_comparer
|
||||
{
|
||||
bool operator()(const asset_object& lhs, const asset_object& rhs) const
|
||||
{
|
||||
if ( !lhs.is_lottery() ) return false;
|
||||
if ( !lhs.lottery_options->is_active && !rhs.is_lottery()) return true; // not active lotteries first
|
||||
if ( !lhs.lottery_options->is_active ) return false;
|
||||
return lhs.get_lottery_expiration() > rhs.get_lottery_expiration();
|
||||
}
|
||||
};
|
||||
|
||||
struct by_symbol;
|
||||
struct by_type;
|
||||
struct by_issuer;
|
||||
struct active_lotteries;
|
||||
typedef multi_index_container<
|
||||
asset_object,
|
||||
indexed_by<
|
||||
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
ordered_unique< tag<by_symbol>, member<asset_object, string, &asset_object::symbol> >,
|
||||
ordered_non_unique< tag<by_issuer>, member<asset_object, account_id_type, &asset_object::issuer > >,
|
||||
ordered_non_unique< tag<active_lotteries>,
|
||||
identity< asset_object >,
|
||||
lottery_asset_comparer
|
||||
>,
|
||||
ordered_unique< tag<by_type>,
|
||||
composite_key< asset_object,
|
||||
const_mem_fun<asset_object, bool, &asset_object::is_market_issued>,
|
||||
|
|
@ -371,6 +392,7 @@ FC_REFLECT_DERIVED( graphene::chain::asset_object, (graphene::db::object),
|
|||
(precision)
|
||||
(issuer)
|
||||
(options)
|
||||
(lottery_options)
|
||||
(dynamic_asset_data_id)
|
||||
(bitasset_data_id)
|
||||
(buyback_account)
|
||||
|
|
|
|||
43
libraries/chain/include/graphene/chain/lottery_evaluator.hpp
Normal file
43
libraries/chain/include/graphene/chain/lottery_evaluator.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Peerplays, Inc., and contributors.
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/protocol/operations.hpp>
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class ticket_purchase_evaluator : public evaluator<ticket_purchase_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef ticket_purchase_operation operation_type;
|
||||
|
||||
void_result do_evaluate( const ticket_purchase_operation& o );
|
||||
object_id_type do_apply( const ticket_purchase_operation& o );
|
||||
|
||||
const asset_object* lottery;
|
||||
const asset_dynamic_data_object* asset_dynamic_data;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
@ -29,6 +29,30 @@ namespace graphene { namespace chain {
|
|||
|
||||
bool is_valid_symbol( const string& symbol );
|
||||
|
||||
struct benefactor {
|
||||
account_id_type id;
|
||||
double share;
|
||||
benefactor() = default;
|
||||
benefactor ( const benefactor & ) = default;
|
||||
benefactor( account_id_type _id, double _share ) : id( _id ), share( _share ) {}
|
||||
};
|
||||
|
||||
struct lottery_asset_options {
|
||||
std::vector<benefactor> benefactors;
|
||||
|
||||
// specifying winning tickets as shares that will be issued
|
||||
std::vector<double> winning_tickets;
|
||||
asset ticket_price;
|
||||
asset balance;
|
||||
time_point_sec end_date;
|
||||
bool ending_on_soldout;
|
||||
bool is_active;
|
||||
|
||||
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
|
||||
*
|
||||
|
|
@ -69,7 +93,7 @@ namespace graphene { namespace chain {
|
|||
flat_set<asset_id_type> whitelist_markets;
|
||||
/** defines the assets that this asset may not be traded against in the market, must not overlap whitelist */
|
||||
flat_set<asset_id_type> blacklist_markets;
|
||||
|
||||
|
||||
/**
|
||||
* data that describes the meaning/purpose of this asset, fee will be charged proportional to
|
||||
* size of description.
|
||||
|
|
@ -169,6 +193,7 @@ 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.
|
||||
};
|
||||
|
||||
|
|
@ -191,7 +216,8 @@ namespace graphene { namespace chain {
|
|||
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;
|
||||
extensions_type extensions;
|
||||
// containing lottery_asset_options now
|
||||
asset_extension extension;
|
||||
|
||||
account_id_type fee_payer()const { return issuer; }
|
||||
void validate()const;
|
||||
|
|
@ -398,7 +424,7 @@ namespace graphene { namespace chain {
|
|||
* BitAssets have some options which are not relevant to other asset types. This operation is used to update those
|
||||
* options an an existing BitAsset.
|
||||
*
|
||||
* @pre @ref issuer MUST be an existing account and MUST match asset_object::issuer on @ref asset_to_update
|
||||
* @pre @ref issuer MUST be an existing aaccount and MUST match asset_object::issuer on @ref asset_to_update
|
||||
* @pre @ref asset_to_update MUST be a BitAsset, i.e. @ref asset_object::is_market_issued() returns true
|
||||
* @pre @ref fee MUST be nonnegative, and @ref issuer MUST have a sufficient balance to pay it
|
||||
* @pre @ref new_options SHALL be internally consistent, as verified by @ref validate()
|
||||
|
|
@ -610,6 +636,10 @@ FC_REFLECT( graphene::chain::bitasset_options,
|
|||
(extensions)
|
||||
)
|
||||
|
||||
FC_REFLECT( graphene::chain::benefactor, (id)(share) )
|
||||
|
||||
FC_REFLECT( graphene::chain::lottery_asset_options, (benefactors)(winning_tickets)(ticket_price)(balance)(end_date)(ending_on_soldout)(is_active) )
|
||||
|
||||
|
||||
FC_REFLECT( graphene::chain::asset_create_operation::fee_parameters_type, (symbol3)(symbol4)(long_symbol)(price_per_kbyte) )
|
||||
FC_REFLECT( graphene::chain::asset_global_settle_operation::fee_parameters_type, (fee) )
|
||||
|
|
@ -633,7 +663,7 @@ FC_REFLECT( graphene::chain::asset_create_operation,
|
|||
(common_options)
|
||||
(bitasset_opts)
|
||||
(is_prediction_market)
|
||||
(extensions)
|
||||
(extension)
|
||||
)
|
||||
FC_REFLECT( graphene::chain::asset_update_operation,
|
||||
(fee)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Peerplays, Inc., and contributors.
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/protocol/base.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* @ingroup operations
|
||||
*/
|
||||
struct ticket_purchase_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type {
|
||||
uint64_t fee = 0;
|
||||
};
|
||||
|
||||
asset fee;
|
||||
// from what lottery is ticket
|
||||
asset_id_type lottery;
|
||||
account_id_type buyer;
|
||||
// count of tickets to buy
|
||||
uint64_t tickets_to_buy;
|
||||
// amount that can spent
|
||||
asset amount;
|
||||
|
||||
extensions_type extensions;
|
||||
|
||||
account_id_type fee_payer()const { return buyer; }
|
||||
void validate()const;
|
||||
share_type calculate_fee( const fee_parameters_type& k )const;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
|
||||
FC_REFLECT( graphene::chain::ticket_purchase_operation,
|
||||
(fee)
|
||||
(lottery)
|
||||
(buyer)
|
||||
(tickets_to_buy)
|
||||
(amount)
|
||||
(extensions)
|
||||
)
|
||||
FC_REFLECT( graphene::chain::ticket_purchase_operation::fee_parameters_type, (fee) )
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
#include <graphene/chain/protocol/affiliate.hpp>
|
||||
#include <graphene/chain/protocol/assert.hpp>
|
||||
#include <graphene/chain/protocol/asset_ops.hpp>
|
||||
#include <graphene/chain/protocol/lottery_ops.hpp>
|
||||
#include <graphene/chain/protocol/balance.hpp>
|
||||
#include <graphene/chain/protocol/custom.hpp>
|
||||
#include <graphene/chain/protocol/committee_member.hpp>
|
||||
|
|
@ -129,7 +130,8 @@ namespace graphene { namespace chain {
|
|||
sport_delete_operation,
|
||||
event_group_delete_operation,
|
||||
affiliate_payout_operation, // VIRTUAL
|
||||
affiliate_referral_payout_operation // VIRTUAL
|
||||
affiliate_referral_payout_operation, // VIRTUAL
|
||||
ticket_purchase_operation
|
||||
> operation;
|
||||
|
||||
/// @} // operations group
|
||||
|
|
|
|||
65
libraries/chain/lottery_evaluator.cpp
Normal file
65
libraries/chain/lottery_evaluator.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Cryptonomex, Inc., and contributors.
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <graphene/chain/lottery_evaluator.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/market_object.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/exceptions.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
#include <graphene/chain/is_authorized_asset.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
void_result ticket_purchase_evaluator::do_evaluate( const ticket_purchase_operation& op )
|
||||
{ try {
|
||||
lottery = &op.lottery(db());
|
||||
FC_ASSERT( lottery->is_lottery() );
|
||||
|
||||
asset_dynamic_data = &lottery->dynamic_asset_data_id(db());
|
||||
FC_ASSERT( asset_dynamic_data->current_supply < lottery->options.max_supply );
|
||||
|
||||
auto lottery_options = *lottery->lottery_options;
|
||||
FC_ASSERT( lottery_options.is_active );
|
||||
FC_ASSERT( lottery_options.ticket_price.asset_id == op.amount.asset_id );
|
||||
FC_ASSERT( (double)op.amount.amount.value / lottery_options.ticket_price.amount.value == (double)op.tickets_to_buy );
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
object_id_type ticket_purchase_evaluator::do_apply( const ticket_purchase_operation& op )
|
||||
{ try {
|
||||
db().adjust_balance( op.buyer, -op.amount );
|
||||
db().adjust_balance( op.buyer, asset( op.tickets_to_buy, lottery->id ) );
|
||||
db().modify( *asset_dynamic_data, [&]( asset_dynamic_data_object& data ){
|
||||
data.current_supply += op.tickets_to_buy;
|
||||
});
|
||||
db().modify( *lottery, [&]( asset_object& ao ){
|
||||
ao.lottery_options->balance += op.amount;
|
||||
});
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
@ -77,16 +77,19 @@ 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;
|
||||
|
||||
switch(symbol.size()) {
|
||||
case 3: core_fee_required = param.symbol3;
|
||||
break;
|
||||
case 4: core_fee_required = param.symbol4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
if( extension.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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 );
|
||||
|
||||
|
|
|
|||
38
libraries/chain/protocol/lottery_ops.cpp
Normal file
38
libraries/chain/protocol/lottery_ops.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Peerplays, Inc., and contributors.
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <graphene/chain/protocol/lottery_ops.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
void ticket_purchase_operation::validate() const
|
||||
{
|
||||
FC_ASSERT( fee.amount >= 0 );
|
||||
}
|
||||
|
||||
share_type ticket_purchase_operation::calculate_fee( const fee_parameters_type& k )const
|
||||
{
|
||||
return k.fee;
|
||||
}
|
||||
|
||||
} } // namespace graphene::chain
|
||||
|
|
@ -45,7 +45,7 @@ object_id_type witness_create_evaluator::do_apply( const witness_create_operatio
|
|||
|
||||
const auto& new_witness_object = db().create<witness_object>( [&]( witness_object& obj ) {
|
||||
obj.witness_account = op.witness_account;
|
||||
obj.signing_key = op.block_signing_key;
|
||||
obj.signing_key = op.block_signing_key;
|
||||
obj.previous_secret = op.initial_secret;
|
||||
obj.next_secret_hash = secret_hash_type::hash( op.initial_secret );
|
||||
obj.vote_id = vote_id;
|
||||
|
|
|
|||
|
|
@ -1009,6 +1009,13 @@ class wallet_api
|
|||
fc::optional<bitasset_options> bitasset_opts,
|
||||
bool broadcast = false);
|
||||
|
||||
signed_transaction create_lottery(string issuer,
|
||||
string symbol,
|
||||
uint8_t precision,
|
||||
asset_options common,
|
||||
fc::optional<bitasset_options> bitasset_opts,
|
||||
bool broadcast = false);
|
||||
|
||||
/** Issue new shares of an asset.
|
||||
*
|
||||
* @param to_account the name or id of the account to receive the new shares
|
||||
|
|
@ -1940,6 +1947,7 @@ FC_API( graphene::wallet::wallet_api,
|
|||
(transfer2)
|
||||
(get_transaction_id)
|
||||
(create_asset)
|
||||
(create_lottery)
|
||||
(update_asset)
|
||||
(update_bitasset)
|
||||
(update_dividend_asset)
|
||||
|
|
|
|||
|
|
@ -1444,6 +1444,40 @@ public:
|
|||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (issuer)(symbol)(precision)(common)(bitasset_opts)(broadcast) ) }
|
||||
|
||||
|
||||
signed_transaction create_lottery(string issuer,
|
||||
string symbol,
|
||||
uint8_t precision,
|
||||
asset_options common,
|
||||
fc::optional<bitasset_options> bitasset_opts,
|
||||
bool broadcast = false)
|
||||
{ try {
|
||||
account_object issuer_account = get_account( issuer );
|
||||
FC_ASSERT(!find_asset(symbol).valid(), "Asset with that symbol already exists!");
|
||||
|
||||
asset_create_operation create_op;
|
||||
create_op.issuer = issuer_account.id;
|
||||
create_op.symbol = symbol;
|
||||
create_op.precision = precision;
|
||||
create_op.common_options = common;
|
||||
create_op.bitasset_opts = bitasset_opts;
|
||||
|
||||
lottery_asset_options lottery_options;
|
||||
lottery_options.benefactors.push_back( benefactor( issuer_account.id, 0.5 ) );
|
||||
lottery_options.end_date = _remote_db->get_dynamic_global_properties().time + fc::minutes(120);
|
||||
lottery_options.ticket_price = asset(100);
|
||||
lottery_options.winning_tickets.push_back(0.5);
|
||||
|
||||
create_op.extension = lottery_options;
|
||||
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back( create_op );
|
||||
set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees);
|
||||
tx.validate();
|
||||
|
||||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (issuer)(symbol)(precision)(common)(bitasset_opts)(broadcast) ) }
|
||||
|
||||
signed_transaction update_asset(string symbol,
|
||||
optional<string> new_issuer,
|
||||
asset_options new_options,
|
||||
|
|
@ -1770,10 +1804,10 @@ public:
|
|||
witness_create_op.block_signing_key = witness_public_key;
|
||||
witness_create_op.url = url;
|
||||
|
||||
// secret_hash_type::encoder enc;
|
||||
// fc::raw::pack(enc, witness_private_key);
|
||||
// fc::raw::pack(enc, secret_hash_type());
|
||||
witness_create_op.initial_secret = secret_hash_type::hash(owner_account);
|
||||
secret_hash_type::encoder enc;
|
||||
fc::raw::pack(enc, witness_private_key);
|
||||
fc::raw::pack(enc, secret_hash_type());
|
||||
witness_create_op.initial_secret = secret_hash_type::hash(enc.result());
|
||||
|
||||
|
||||
if (_remote_db->get_witness_by_account(witness_create_op.witness_account))
|
||||
|
|
@ -3882,6 +3916,18 @@ signed_transaction wallet_api::create_asset(string issuer,
|
|||
return my->create_asset(issuer, symbol, precision, common, bitasset_opts, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::create_lottery(string issuer,
|
||||
string symbol,
|
||||
uint8_t precision,
|
||||
asset_options common,
|
||||
fc::optional<bitasset_options> bitasset_opts,
|
||||
bool broadcast)
|
||||
|
||||
{
|
||||
return my->create_lottery(issuer, symbol, precision, common, bitasset_opts, broadcast);
|
||||
}
|
||||
|
||||
|
||||
signed_transaction wallet_api::update_asset(string symbol,
|
||||
optional<string> new_issuer,
|
||||
asset_options new_options,
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ void database_fixture::verify_asset_supplies( const database& db )
|
|||
const auto& balance_index = db.get_index_type<account_balance_index>().indices();
|
||||
const auto& settle_index = db.get_index_type<force_settlement_index>().indices();
|
||||
const auto& tournaments_index = db.get_index_type<tournament_index>().indices();
|
||||
const auto& asst_index = db.get_index_type<asset_index>().indices();
|
||||
|
||||
map<asset_id_type,share_type> total_balances;
|
||||
map<asset_id_type,share_type> total_debts;
|
||||
|
|
@ -187,6 +188,10 @@ void database_fixture::verify_asset_supplies( const database& db )
|
|||
if (t.get_state() != tournament_state::concluded && t.get_state() != tournament_state::registration_period_expired)
|
||||
total_balances[t.options.buy_in.asset_id] += t.prize_pool;
|
||||
|
||||
for( const asset_object& ai : asst_index)
|
||||
if (ai.is_lottery())
|
||||
total_balances[ ai.lottery_options->balance.asset_id ] += ai.lottery_options->balance.amount;
|
||||
|
||||
for( const account_balance_object& b : balance_index )
|
||||
total_balances[b.asset_type] += b.balance;
|
||||
for( const force_settlement_object& s : settle_index )
|
||||
|
|
@ -700,10 +705,10 @@ const witness_object& database_fixture::create_witness( const account_object& ow
|
|||
op.witness_account = owner.id;
|
||||
op.block_signing_key = signing_private_key.get_public_key();
|
||||
|
||||
// secret_hash_type::encoder enc;
|
||||
// fc::raw::pack(enc, signing_private_key);
|
||||
// fc::raw::pack(enc, owner.name);
|
||||
op.initial_secret = secret_hash_type::hash(owner.name);
|
||||
secret_hash_type::encoder enc;
|
||||
fc::raw::pack(enc, signing_private_key);
|
||||
fc::raw::pack(enc, owner.name);
|
||||
op.initial_secret = secret_hash_type::hash(enc.result());
|
||||
|
||||
trx.operations.push_back(op);
|
||||
trx.validate();
|
||||
|
|
|
|||
164
tests/tests/lottery_tests.cpp
Normal file
164
tests/tests/lottery_tests.cpp
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2017 PBSA, Inc., and contributors.
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
|
||||
#include <fc/crypto/digest.hpp>
|
||||
#include <fc/crypto/elliptic.hpp>
|
||||
#include <fc/reflect/variant.hpp>
|
||||
|
||||
#include "../common/database_fixture.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace graphene::chain;
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE( lottery_tests, database_fixture )
|
||||
|
||||
BOOST_AUTO_TEST_CASE( create_lottery_asset_test )
|
||||
{
|
||||
try {
|
||||
asset_id_type test_asset_id = db.get_index<asset_object>().get_next_id();
|
||||
asset_create_operation creator;
|
||||
creator.issuer = account_id_type();
|
||||
creator.fee = asset();
|
||||
char symbol[5] = "LOT";
|
||||
symbol[3] = (char)('A' - 1 + test_asset_id.instance.value); symbol[4] = '\0'; // symbol depending on asset_id
|
||||
creator.symbol = symbol;
|
||||
creator.common_options.max_supply = 20;
|
||||
creator.precision = 0;
|
||||
creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/
|
||||
creator.common_options.issuer_permissions = charge_market_fee|white_list|override_authority|transfer_restricted|disable_confidential;
|
||||
creator.common_options.flags = charge_market_fee|white_list|override_authority|disable_confidential;
|
||||
creator.common_options.core_exchange_rate = price({asset(1),asset(1,asset_id_type(1))});
|
||||
creator.common_options.whitelist_authorities = creator.common_options.blacklist_authorities = {account_id_type()};
|
||||
|
||||
lottery_asset_options lottery_options;
|
||||
lottery_options.benefactors.push_back( benefactor( account_id_type(), 0.5 ) );
|
||||
lottery_options.end_date = db.get_dynamic_global_properties().time + fc::minutes(5);
|
||||
lottery_options.ticket_price = asset(100);
|
||||
lottery_options.winning_tickets.push_back(0.5);
|
||||
lottery_options.is_active = test_asset_id.instance.value % 2;
|
||||
|
||||
creator.extension = lottery_options;
|
||||
|
||||
trx.operations.push_back(std::move(creator));
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
auto test_asset = test_asset_id(db);
|
||||
// idump((test_asset.is_lottery()));
|
||||
} catch (fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( lottery_idx_test )
|
||||
{
|
||||
try {
|
||||
// generate loterries with different end_dates and is_active_flag
|
||||
for( int i = 0; i < 26; ++i ) {
|
||||
generate_blocks(30);
|
||||
graphene::chain::test::set_expiration( db, trx );
|
||||
asset_id_type test_asset_id = db.get_index<asset_object>().get_next_id();
|
||||
INVOKE( create_lottery_asset_test );
|
||||
auto test_asset = test_asset_id(db);
|
||||
}
|
||||
|
||||
auto& test_asset_idx = db.get_index_type<asset_index>().indices().get<active_lotteries>();
|
||||
auto test_itr = test_asset_idx.begin();
|
||||
bool met_not_active = false;
|
||||
// check sorting
|
||||
while( test_itr != test_asset_idx.end() ) {
|
||||
if( !met_not_active && (!test_itr->is_lottery() || !test_itr->lottery_options->is_active) )
|
||||
met_not_active = true;
|
||||
FC_ASSERT( !met_not_active || met_not_active && (!test_itr->is_lottery() || !test_itr->lottery_options->is_active), "MET ACTIVE LOTTERY AFTER NOT ACTIVE" );
|
||||
++test_itr;
|
||||
}
|
||||
} catch (fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( tickets_purchase_test )
|
||||
{
|
||||
try {
|
||||
asset_id_type test_asset_id = db.get_index<asset_object>().get_next_id();
|
||||
INVOKE( create_lottery_asset_test );
|
||||
auto& test_asset = test_asset_id(db);
|
||||
|
||||
ticket_purchase_operation tpo;
|
||||
tpo.fee = asset();
|
||||
tpo.buyer = account_id_type();
|
||||
tpo.lottery = test_asset.id;
|
||||
tpo.tickets_to_buy = 1;
|
||||
tpo.amount = asset(100);
|
||||
trx.operations.push_back(std::move(tpo));
|
||||
graphene::chain::test::set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
|
||||
BOOST_CHECK( tpo.amount == test_asset.lottery_options->balance );
|
||||
BOOST_CHECK( tpo.tickets_to_buy == get_balance( account_id_type(), test_asset.id ) );
|
||||
|
||||
} catch (fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( tickets_purchase_fail_test )
|
||||
{
|
||||
try {
|
||||
asset_id_type test_asset_id = db.get_index<asset_object>().get_next_id();
|
||||
INVOKE( create_lottery_asset_test );
|
||||
auto& test_asset = test_asset_id(db);
|
||||
|
||||
ticket_purchase_operation tpo;
|
||||
tpo.fee = asset();
|
||||
tpo.buyer = account_id_type();
|
||||
tpo.lottery = test_asset.id;
|
||||
tpo.tickets_to_buy = 2;
|
||||
tpo.amount = asset(100);
|
||||
trx.operations.push_back(tpo);
|
||||
BOOST_REQUIRE_THROW( PUSH_TX( db, trx, ~0 ), fc::exception ); // amount/tickets_to_buy != price
|
||||
trx.operations.clear();
|
||||
|
||||
tpo.amount = asset(205);
|
||||
trx.operations.push_back(tpo);
|
||||
BOOST_REQUIRE_THROW( PUSH_TX( db, trx, ~0 ), fc::exception ); // amount/tickets_to_buy != price
|
||||
|
||||
tpo.amount = asset(200, test_asset.id);
|
||||
trx.operations.push_back(tpo);
|
||||
BOOST_REQUIRE_THROW( PUSH_TX( db, trx, ~0 ), fc::exception ); // trying to buy in other asset
|
||||
} catch (fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Loading…
Reference in a new issue