ticket_purchase_operation implemented. added lottery_options to asset

This commit is contained in:
kstdl 2017-11-13 10:14:07 +03:00 committed by gladcow
parent b953ac9e88
commit 17e6a9baf9
23 changed files with 564 additions and 41 deletions

View file

@ -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 )

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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 ) );

View file

@ -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);

View file

@ -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 )

View 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

View file

@ -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

View file

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

View file

@ -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)

View 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

View file

@ -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)

View file

@ -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) )

View file

@ -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

View 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

View file

@ -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 );

View 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

View file

@ -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;

View file

@ -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)

View file

@ -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,

View file

@ -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();

View 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()