diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 6b14f2bc3..7ac0f7629 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -217,6 +217,10 @@ class database_api_impl : public std::enable_shared_from_this vector get_offer_history_by_item(const offer_history_id_type lower_id, const nft_id_type item, uint32_t limit) const; vector get_offer_history_by_bidder(const offer_history_id_type lower_id, const account_id_type bidder_account_id, uint32_t limit) const; + // rng + vector get_random_number_ex(uint64_t minimum, uint64_t maximum, uint64_t selections, bool duplicates) const; + uint64_t get_random_number(uint64_t bound) const; + //private: const account_object* get_account_from_string( const std::string& name_or_id, bool throw_if_not_found = true ) const; @@ -2888,6 +2892,60 @@ vector database_api_impl::get_offer_history_by_bidder(cons return result; } + +////////////////////////////////////////////////////////////////////// +// // +// Random numbers // +// // +////////////////////////////////////////////////////////////////////// + +vector database_api::get_random_number_ex(uint64_t minimum, uint64_t maximum, uint64_t selections, bool duplicates) const +{ + return my->get_random_number_ex(minimum, maximum, selections, duplicates); +} + +vector database_api_impl::get_random_number_ex(uint64_t minimum, uint64_t maximum, uint64_t selections, bool duplicates) const +{ + FC_ASSERT( selections <= 100000 ); + if (duplicates == false) { + FC_ASSERT( maximum - minimum >= selections ); + } + + vector v; + v.reserve(selections); + + if (duplicates) { + for (uint64_t i = 0; i < selections; i++) { + int64_t rnd = _db.get_random_bits(maximum - minimum) + minimum; + v.push_back(rnd); + } + } else { + vector tmpv; + tmpv.reserve(selections); + for (uint64_t i = minimum; i < maximum; i++) { + tmpv.push_back(i); + } + + for (uint64_t i = 0; (i < selections) && (tmpv.size() > 0); i++) { + uint64_t idx = _db.get_random_bits(tmpv.size()); + v.push_back(tmpv.at(idx)); + tmpv.erase(tmpv.begin() + idx); + } + } + + return v; +} + +uint64_t database_api::get_random_number(uint64_t bound) const +{ + return my->get_random_number(bound); +} + +uint64_t database_api_impl::get_random_number(uint64_t bound) const { + vector v = get_random_number_ex(0, bound, 1, false); + return v.at(0); +} + ////////////////////////////////////////////////////////////////////// // // // Private methods // diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 0b1411252..4d3c0a841 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -829,7 +829,28 @@ class database_api vector get_offer_history_by_issuer(const offer_history_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const; vector get_offer_history_by_item(const offer_history_id_type lower_id, const nft_id_type item, uint32_t limit) const; vector get_offer_history_by_bidder(const offer_history_id_type lower_id, const account_id_type bidder_account_id, uint32_t limit) const; -private: + + ///////////////////////////// + // Random number generator // + ///////////////////////////// + /** + * @brief Returns the random number + * @param minimum Lower bound of segment containing random number + * @param maximum Upper bound of segment containing random number + * @param selections Number of random numbers to return + * @param duplicates Allow duplicated numbers + * @return Vector containing random numbers from segment [minimum, maximum) + */ + vector get_random_number_ex(uint64_t minimum, uint64_t maximum, uint64_t selections, bool duplicates) const; + + /** + * @brief Returns the random number + * @param bound Upper bound of segment containing random number + * @return Random number from segment [0, bound) + */ + uint64_t get_random_number(uint64_t bound) const; + + private: std::shared_ptr< database_api_impl > my; }; @@ -999,4 +1020,8 @@ FC_API(graphene::app::database_api, (get_offer_history_by_issuer) (get_offer_history_by_item) (get_offer_history_by_bidder) + + // rngs + (get_random_number_ex) + (get_random_number) ) diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 88d868e5e..dcd2fc699 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -125,6 +125,8 @@ add_library( graphene_chain nft_evaluator.cpp protocol/nft.cpp + random_number_evaluator.cpp + ${HEADERS} ${PROTOCOL_HEADERS} "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 9ae1fb964..28a73a23f 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -85,6 +86,7 @@ #include #include #include +#include #include @@ -186,6 +188,9 @@ const uint8_t offer_object::type_id; const uint8_t offer_history_object::space_id; const uint8_t offer_history_object::type_id; +const uint8_t random_number_object::space_id; +const uint8_t random_number_object::type_id; + void database::initialize_evaluators() { _operation_evaluators.resize(255); @@ -275,6 +280,7 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); } void database::initialize_indexes() @@ -353,6 +359,7 @@ void database::initialize_indexes() add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); + add_index< primary_index >(); } diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index f56e3d8b3..e10a72661 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -344,6 +344,9 @@ struct get_impacted_account_visitor void operator()( const finalize_offer_operation& op ) { _impacted.insert( op.fee_paying_account ); } + void operator()( const random_number_store_operation& op ) { + _impacted.insert( op.account ); + } }; void graphene::chain::operation_get_impacted_accounts( const operation& op, flat_set& result ) diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index 1285d3531..430726c59 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -49,6 +49,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -155,7 +156,8 @@ namespace graphene { namespace chain { nft_mint_operation, nft_safe_transfer_from_operation, nft_approve_operation, - nft_set_approval_for_all_operation + nft_set_approval_for_all_operation, + random_number_store_operation > operation; /// @} // operations group diff --git a/libraries/chain/include/graphene/chain/protocol/random_number.hpp b/libraries/chain/include/graphene/chain/protocol/random_number.hpp new file mode 100644 index 000000000..3dbe487fd --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/random_number.hpp @@ -0,0 +1,25 @@ +#pragma once + +namespace graphene { namespace chain { + + struct random_number_store_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 5000 * GRAPHENE_BLOCKCHAIN_PRECISION; }; + + asset fee; + + account_id_type account; + vector random_number; + std::string data; + + account_id_type fee_payer()const { return account; } + }; + +} } // graphene::chain + +FC_REFLECT( graphene::chain::random_number_store_operation::fee_parameters_type, (fee) ) +FC_REFLECT( graphene::chain::random_number_store_operation, (fee) + (account) + (random_number) + (data) ) + diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index 6fa2ab4d1..2be8ae345 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -176,6 +176,7 @@ namespace graphene { namespace chain { offer_object_type, nft_metadata_type, nft_object_type, + random_number_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; @@ -241,6 +242,7 @@ namespace graphene { namespace chain { class offer_object; class nft_metadata_object; class nft_object; + class random_number_object; typedef object_id< protocol_ids, account_object_type, account_object> account_id_type; typedef object_id< protocol_ids, asset_object_type, asset_object> asset_id_type; @@ -272,6 +274,7 @@ namespace graphene { namespace chain { typedef object_id< protocol_ids, offer_object_type, offer_object> offer_id_type; typedef object_id< protocol_ids, nft_metadata_type, nft_metadata_object> nft_metadata_id_type; typedef object_id< protocol_ids, nft_object_type, nft_object> nft_id_type; + typedef object_id< protocol_ids, random_number_object_type, random_number_object> random_number_id_type; // implementation types class global_property_object; @@ -459,6 +462,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type, (offer_object_type) (nft_metadata_type) (nft_object_type) + (random_number_object_type) (OBJECT_TYPE_COUNT) ) FC_REFLECT_ENUM( graphene::chain::impl_object_type, @@ -535,6 +539,7 @@ FC_REFLECT_TYPENAME( graphene::chain::custom_account_authority_id_type ) FC_REFLECT_TYPENAME( graphene::chain::offer_history_id_type ) FC_REFLECT_TYPENAME( graphene::chain::nft_metadata_id_type ) FC_REFLECT_TYPENAME( graphene::chain::nft_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::random_number_id_type ) FC_REFLECT( graphene::chain::void_t, ) diff --git a/libraries/chain/include/graphene/chain/random_number_evaluator.hpp b/libraries/chain/include/graphene/chain/random_number_evaluator.hpp new file mode 100644 index 000000000..a26b9f3ec --- /dev/null +++ b/libraries/chain/include/graphene/chain/random_number_evaluator.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include +#include +#include + +namespace graphene { namespace chain { + + class random_number_store_evaluator : public evaluator + { + public: + typedef random_number_store_operation operation_type; + + void_result do_evaluate( const random_number_store_operation& o ); + object_id_type do_apply( const random_number_store_operation& o ); + }; + +} } // graphene::chain + diff --git a/libraries/chain/include/graphene/chain/random_number_object.hpp b/libraries/chain/include/graphene/chain/random_number_object.hpp new file mode 100644 index 000000000..3613d7a19 --- /dev/null +++ b/libraries/chain/include/graphene/chain/random_number_object.hpp @@ -0,0 +1,41 @@ +#pragma once + +namespace graphene { namespace chain { + using namespace graphene::db; + + class random_number_object : public abstract_object + { + public: + static const uint8_t space_id = protocol_ids; + static const uint8_t type_id = random_number_object_type; + + account_id_type account; /* account who requested random number */ + time_point_sec timestamp; /* date and time when the number is read */ + vector random_number; /* random number(s) */ + std::string data; /* custom data in json format */ + }; + + struct by_account; + struct by_timestamp; + using random_number_multi_index_type = multi_index_container< + random_number_object, + indexed_by< + ordered_unique< tag, + member + >, + ordered_non_unique< tag, + member + >, + ordered_non_unique< tag, + member + > + > + >; + using random_number_index = generic_index; + +} } // graphene::chain + +FC_REFLECT_DERIVED( graphene::chain::random_number_object, (graphene::db::object), + (account) (timestamp) + (random_number) (data) ) + diff --git a/libraries/chain/random_number_evaluator.cpp b/libraries/chain/random_number_evaluator.cpp new file mode 100644 index 000000000..acfab042a --- /dev/null +++ b/libraries/chain/random_number_evaluator.cpp @@ -0,0 +1,24 @@ +#include +#include + +namespace graphene { namespace chain { + +void_result random_number_store_evaluator::do_evaluate( const random_number_store_operation& op ) +{ try { + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +object_id_type random_number_store_evaluator::do_apply( const random_number_store_operation& op ) +{ try { + const auto& new_random_number_object = db().create( [&]( random_number_object& obj ) { + obj.account = op.account; + obj.timestamp = db().head_block_time(); + obj.random_number = op.random_number; + obj.data = op.data; + }); + return new_random_number_object.id; +} FC_CAPTURE_AND_RETHROW( (op) ) } + +} } // graphene::chain + diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 7f5913287..d224cff66 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -68,7 +68,7 @@ struct brain_key_info * the meta data about the receipt that helps the sender identify which receipt is * for the receiver and which is for the change address. */ -struct blind_confirmation +struct blind_confirmation { struct output { @@ -312,7 +312,7 @@ class wallet_api */ uint64_t get_account_count()const; /** Lists all accounts controlled by this wallet. - * This returns a list of the full account objects for all accounts whose private keys + * This returns a list of the full account objects for all accounts whose private keys * we possess. * @returns a list of account objects */ @@ -324,14 +324,14 @@ class wallet_api * start by setting \c lowerbound to the empty string \c "", and then each iteration, pass * the last account name returned as the \c lowerbound for the next \c list_accounts() call. * - * @param lowerbound the name of the first account to return. If the named account does not exist, + * @param lowerbound the name of the first account to return. If the named account does not exist, * the list will start at the account that comes after \c lowerbound * @param limit the maximum number of accounts to return (max: 1000) * @returns a list of accounts mapping account names to account ids */ map list_accounts(const string& lowerbound, uint32_t limit); /** List the balances of an account. - * Each account can have multiple balances, one for each type of asset owned by that + * Each account can have multiple balances, one for each type of asset owned by that * account. The returned list will only contain assets for which the account has a * nonzero balance * @param id the name or id of the account whose balances you want @@ -339,7 +339,7 @@ class wallet_api */ vector list_account_balances(const string& id); /** Lists all assets registered on the blockchain. - * + * * To list all assets, pass the empty string \c "" for the lowerbound to start * at the beginning of the list, and iterate as necessary. * @@ -350,12 +350,12 @@ class wallet_api vector list_assets(const string& lowerbound, uint32_t limit)const; /** Returns assets count registered on the blockchain. - * + * * @returns assets count */ uint64_t get_asset_count()const; - - + + vector get_lotteries( asset_id_type stop = asset_id_type(), unsigned limit = 100, asset_id_type start = asset_id_type() )const; @@ -391,7 +391,7 @@ class wallet_api vector get_limit_orders(string a, string b, uint32_t limit)const; vector get_call_orders(string a, uint32_t limit)const; vector get_settle_orders(string a, uint32_t limit)const; - + /** Returns the block chain's slowly-changing settings. * This object contains all of the properties of the blockchain that are fixed * or that change only once per maintenance interval (daily) such as the @@ -447,8 +447,8 @@ class wallet_api * Returns the blockchain object corresponding to the given id. * * This generic function can be used to retrieve any object from the blockchain - * that is assigned an ID. Certain types of objects have specialized convenience - * functions to return their objects -- e.g., assets have \c get_asset(), accounts + * that is assigned an ID. Certain types of objects have specialized convenience + * functions to return their objects -- e.g., assets have \c get_asset(), accounts * have \c get_account(), but this function will work for any object. * * @param id the id of the object to return @@ -456,7 +456,7 @@ class wallet_api */ variant get_object(object_id_type id) const; - /** Returns the current wallet filename. + /** Returns the current wallet filename. * * This is the filename that will be used when automatically saving the wallet. * @@ -532,21 +532,21 @@ class wallet_api * @ingroup Wallet Management */ bool is_new()const; - - /** Checks whether the wallet is locked (is unable to use its private keys). + + /** Checks whether the wallet is locked (is unable to use its private keys). * * This state can be changed by calling \c lock() or \c unlock(). * @return true if the wallet is locked * @ingroup Wallet Management */ bool is_locked()const; - + /** Locks the wallet immediately. * @ingroup Wallet Management */ void lock(); - - /** Unlocks the wallet. + + /** Unlocks the wallet. * * The wallet remain unlocked until the \c lock is called * or the program exits. @@ -554,7 +554,7 @@ class wallet_api * @ingroup Wallet Management */ void unlock(string password); - + /** Sets a new password on the wallet. * * The wallet must be either 'new' or 'unlocked' to @@ -567,7 +567,7 @@ class wallet_api * * The keys are printed in WIF format. You can import these keys into another wallet * using \c import_key() - * @returns a map containing the private keys, indexed by their public key + * @returns a map containing the private keys, indexed by their public key */ map dump_private_keys(); @@ -602,13 +602,13 @@ class wallet_api bool load_wallet_file(string wallet_filename = ""); /** Quitting from Peerplays wallet. - * + * * The current wallet will be closed. */ void quit(); /** Saves the current wallet to the given filename. - * + * * @warning This does not change the wallet filename that will be used for future * writes, so think of this function as 'Save a Copy As...' instead of * 'Save As...'. Use \c set_wallet_filename() to make the filename @@ -677,7 +677,7 @@ class wallet_api /** Imports the private key for an existing account. * * The private key must match either an owner key or an active key for the - * named account. + * named account. * * @see dump_private_keys() * @@ -780,7 +780,7 @@ class wallet_api * @param to the name or id of the account receiving the funds * @param amount the amount to send (in nominal units -- to send half of a BTS, specify 0.5) * @param asset_symbol the symbol or id of the asset to send - * @param memo a memo to attach to the transaction. The memo will be encrypted in the + * @param memo a memo to attach to the transaction. The memo will be encrypted in the * transaction and readable for the receiver. There is no length limit * other than the limit imposed by maximum transaction size, but transaction * increase with transaction size @@ -855,7 +855,7 @@ class wallet_api * who sent it. * * @param opt_from - if not empty and the sender is a unknown public key, then the unknown public key will be given the label opt_from - * @param confirmation_receipt - a base58 encoded stealth confirmation + * @param confirmation_receipt - a base58 encoded stealth confirmation */ blind_receipt receive_blind_transfer( string confirmation_receipt, string opt_from, string opt_memo ); @@ -863,18 +863,18 @@ class wallet_api * Transfers a public balance from @from to one or more blinded balances using a * stealth transfer. */ - blind_confirmation transfer_to_blind( string from_account_id_or_name, + blind_confirmation transfer_to_blind( string from_account_id_or_name, string asset_symbol, /** map from key or label to amount */ - vector> to_amounts, + vector> to_amounts, bool broadcast = false ); /** * Transfers funds from a set of blinded balances to a public account balance. */ - blind_confirmation transfer_from_blind( + blind_confirmation transfer_from_blind( string from_blind_account_key_or_label, - string to_account_id_or_name, + string to_account_id_or_name, string amount, string asset_symbol, bool broadcast = false ); @@ -890,14 +890,14 @@ class wallet_api /** Place a limit order attempting to sell one asset for another. * - * Buying and selling are the same operation on Graphene; if you want to buy BTS + * Buying and selling are the same operation on Graphene; if you want to buy BTS * with USD, you should sell USD for BTS. * * The blockchain will attempt to sell the \c symbol_to_sell for as - * much \c symbol_to_receive as possible, as long as the price is at - * least \c min_to_receive / \c amount_to_sell. + * much \c symbol_to_receive as possible, as long as the price is at + * least \c min_to_receive / \c amount_to_sell. * - * In addition to the transaction fees, market fees will apply as specified + * In addition to the transaction fees, market fees will apply as specified * by the issuer of both the selling asset and the receiving asset as * a percentage of the amount exchanged. * @@ -910,16 +910,16 @@ class wallet_api * * @todo Allow order expiration to be set here. Document default/max expiration time * - * @param seller_account the account providing the asset being sold, and which will + * @param seller_account the account providing the asset being sold, and which will * receive the proceeds of the sale. * @param amount_to_sell the amount of the asset being sold to sell (in nominal units) * @param symbol_to_sell the name or id of the asset to sell * @param min_to_receive the minimum amount you are willing to receive in return for * selling the entire amount_to_sell * @param symbol_to_receive the name or id of the asset you wish to receive - * @param timeout_sec if the order does not fill immediately, this is the length of - * time the order will remain on the order books before it is - * cancelled and the un-spent funds are returned to the seller's + * @param timeout_sec if the order does not fill immediately, this is the length of + * time the order will remain on the order books before it is + * cancelled and the un-spent funds are returned to the seller's * account * @param fill_or_kill if true, the order will only be included in the blockchain * if it is filled immediately; if false, an open order will be @@ -936,12 +936,12 @@ class wallet_api uint32_t timeout_sec = 0, bool fill_or_kill = false, bool broadcast = false); - + /** Place a limit order attempting to sell one asset for another. - * + * * This API call abstracts away some of the details of the sell_asset call to be more * user friendly. All orders placed with sell never timeout and will not be killed if they - * cannot be filled immediately. If you wish for one of these parameters to be different, + * cannot be filled immediately. If you wish for one of these parameters to be different, * then sell_asset should be used instead. * * @param seller_account the account providing the asset being sold, and which will @@ -951,7 +951,7 @@ class wallet_api * @param rate The rate in base:quote at which you want to sell. * @param amount The amount of base you want to sell. * @param broadcast true to broadcast the transaction on the network. - * @returns The signed transaction selling the funds. + * @returns The signed transaction selling the funds. */ signed_transaction sell( string seller_account, string base, @@ -959,7 +959,7 @@ class wallet_api double rate, double amount, bool broadcast ); - + /** Place a limit order attempting to buy one asset with another. * * This API call abstracts away some of the details of the sell_asset call to be more @@ -1014,14 +1014,14 @@ class wallet_api * Right now this function is difficult to use because you must provide raw JSON data * structures for the options objects, and those include prices and asset ids. * - * @param issuer the name or id of the account who will pay the fee and become the + * @param issuer the name or id of the account who will pay the fee and become the * issuer of the new asset. This can be updated later * @param symbol the ticker symbol of the new asset * @param precision the number of digits of precision to the right of the decimal point, * must be less than or equal to 12 * @param common asset options required for all new assets. - * Note that 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 + * Note that 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. * @param bitasset_opts options specific to BitAssets. This may be null unless the @@ -1041,7 +1041,7 @@ class wallet_api asset_options common, lottery_asset_options lottery_opts, bool broadcast = false); - + signed_transaction buy_ticket( asset_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy ); /** Issue new shares of an asset. @@ -1059,8 +1059,8 @@ class wallet_api bool broadcast = false); /** Update the core options on an asset. - * There are a number of options which all assets in the network use. These options are - * enumerated in the asset_object::asset_options struct. This command is used to update + * There are a number of options which all assets in the network use. These options are + * enumerated in the asset_object::asset_options struct. This command is used to update * these options for an existing asset. * * @note This operation cannot be used to update BitAsset-specific options. For these options, @@ -1124,7 +1124,7 @@ class wallet_api signed_transaction update_asset_feed_producers(string symbol, flat_set new_feed_producers, bool broadcast = false); - + /** Publishes a price feed for the named asset. * * Price feed providers use this command to publish their price feeds for market-issued assets. A price feed is @@ -1152,7 +1152,7 @@ class wallet_api /** Pay into the fee pool for the given asset. * - * User-issued assets can optionally have a pool of the core asset which is + * User-issued assets can optionally have a pool of the core asset which is * automatically used to pay transaction fees for any transaction using that * asset (using the asset's core exchange rate). * @@ -1193,7 +1193,7 @@ class wallet_api * used as backing for other bitassets, those bitassets will be force settled at their current * feed price. * - * @note this operation is used only by the asset issuer, \c settle_asset() may be used by + * @note this operation is used only by the asset issuer, \c settle_asset() may be used by * any user owning the asset * * @param symbol the name or id of the asset to force settlement on @@ -1261,7 +1261,7 @@ class wallet_api * @returns the signed transaction registering a committee_member */ signed_transaction create_committee_member(string owner_account, - string url, + string url, bool broadcast = false); /** Lists all witnesses registered in the blockchain. @@ -1272,7 +1272,7 @@ class wallet_api * start by setting \c lowerbound to the empty string \c "", and then each iteration, pass * the last witness name returned as the \c lowerbound for the next \c list_witnesss() call. * - * @param lowerbound the name of the first witness to return. If the named witness does not exist, + * @param lowerbound the name of the first witness to return. If the named witness does not exist, * the list will start at the witness that comes after \c lowerbound * @param limit the maximum number of witnesss to return (max: 1000) * @returns a list of witnesss mapping witness names to witness ids @@ -1287,7 +1287,7 @@ class wallet_api * start by setting \c lowerbound to the empty string \c "", and then each iteration, pass * the last committee_member name returned as the \c lowerbound for the next \c list_committee_members() call. * - * @param lowerbound the name of the first committee_member to return. If the named committee_member does not exist, + * @param lowerbound the name of the first committee_member to return. If the named committee_member does not exist, * the list will start at the committee_member that comes after \c lowerbound * @param limit the maximum number of committee_members to return (max: 1000) * @returns a list of committee_members mapping committee_member names to committee_member ids @@ -1413,7 +1413,7 @@ class wallet_api /** Vote for a given committee_member. * - * An account can publish a list of all committee_memberes they approve of. This + * An account can publish a list of all committee_memberes they approve of. This * command allows you to add or remove committee_memberes from this list. * Each account's vote is weighted according to the number of shares of the * core asset owned by that account at the time the votes are tallied. @@ -1423,7 +1423,7 @@ class wallet_api * * @param voting_account the name or id of the account who is voting with their shares * @param committee_member the name or id of the committee_member' owner account - * @param approve true if you wish to vote in favor of that committee_member, false to + * @param approve true if you wish to vote in favor of that committee_member, false to * remove your vote in favor of that committee_member * @param broadcast true if you wish to broadcast the transaction * @return the signed transaction changing your vote for the given committee_member @@ -1435,7 +1435,7 @@ class wallet_api /** Vote for a given witness. * - * An account can publish a list of all witnesses they approve of. This + * An account can publish a list of all witnesses they approve of. This * command allows you to add or remove witnesses from this list. * Each account's vote is weighted according to the number of shares of the * core asset owned by that account at the time the votes are tallied. @@ -1445,7 +1445,7 @@ class wallet_api * * @param voting_account the name or id of the account who is voting with their shares * @param witness the name or id of the witness' owner account - * @param approve true if you wish to vote in favor of that witness, false to + * @param approve true if you wish to vote in favor of that witness, false to * remove your vote in favor of that witness * @param broadcast true if you wish to broadcast the transaction * @return the signed transaction changing your vote for the given witness @@ -1457,12 +1457,12 @@ class wallet_api /** Change your witness votes. * - * An account can publish a list of all witnesses they approve of. + * An account can publish a list of all witnesses they approve of. * Each account's vote is weighted according to the number of shares of the * core asset owned by that account at the time the votes are tallied. - * This command allows you to add or remove one or more witnesses from this list + * This command allows you to add or remove one or more witnesses from this list * in one call. When you are changing your vote on several witnesses, this - * may be easier than multiple `vote_for_witness` and + * may be easier than multiple `vote_for_witness` and * `set_desired_witness_and_committee_member_count` calls. * * @note you cannot vote against a witness, you can only vote for the witness @@ -1477,7 +1477,7 @@ class wallet_api * you currently approve). This list can be empty. * @param desired_number_of_witnesses the number of witnesses you believe the network * should have. You must vote for at least this many - * witnesses. You can set this to 0 to abstain from + * witnesses. You can set this to 0 to abstain from * voting on the number of witnesses. * @param broadcast true if you wish to broadcast the transaction * @return the signed transaction changing your vote for the given witnesses @@ -1508,23 +1508,23 @@ class wallet_api signed_transaction set_voting_proxy(string account_to_modify, optional voting_account, bool broadcast = false); - + /** Set your vote for the number of witnesses and committee_members in the system. * - * Each account can voice their opinion on how many committee_members and how many + * Each account can voice their opinion on how many committee_members and how many * witnesses there should be in the active committee_member/active witness list. These * are independent of each other. You must vote your approval of at least as many * committee_members or witnesses as you claim there should be (you can't say that there should - * be 20 committee_members but only vote for 10). + * be 20 committee_members but only vote for 10). * - * There are maximum values for each set in the blockchain parameters (currently + * There are maximum values for each set in the blockchain parameters (currently * defaulting to 1001). * * This setting can be changed at any time. If your account has a voting proxy * set, your preferences will be ignored. * * @param account_to_modify the name or id of the account to update - * @param number_of_committee_members the number + * @param number_of_committee_members the number * * @param broadcast true if you wish to broadcast the transaction * @return the signed transaction changing your vote proxy settings @@ -1577,16 +1577,16 @@ class wallet_api /** Returns an uninitialized object representing a given blockchain operation. * - * This returns a default-initialized object of the given type; it can be used + * This returns a default-initialized object of the given type; it can be used * during early development of the wallet when we don't yet have custom commands for - * creating all of the operations the blockchain supports. + * creating all of the operations the blockchain supports. * * Any operation the blockchain supports can be created using the transaction builder's - * \c add_operation_to_builder_transaction() , but to do that from the CLI you need to + * \c add_operation_to_builder_transaction() , but to do that from the CLI you need to * know what the JSON form of the operation looks like. This will give you a template * you can fill in. It's better than nothing. - * - * @param operation_type the type of operation to return, must be one of the + * + * @param operation_type the type of operation to return, must be one of the * operations defined in `graphene/chain/operations.hpp` * (e.g., "global_parameters_update_operation") * @return a default-constructed operation of the given type @@ -1611,7 +1611,7 @@ class wallet_api bool broadcast = false); /** Propose a fee change. - * + * * @param proposing_account The account paying the fee to propose the tx * @param expiration_time Timestamp specifying when the proposal will either take effect or expire. * @param changed_values Map of operation type to new fee. Operations may be specified by name or ID. @@ -1653,7 +1653,33 @@ class wallet_api const approval_delta& delta, bool broadcast /* = false */ ); - + + /** Get random numbers + * @brief Returns the random number + * @param minimum Lower bound of segment containing random number + * @param maximum Upper bound of segment containing random number + * @param selections Number of random numbers to return + * @param duplicates Allow duplicated numbers + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + * @return Vector containing random numbers from segment [minimum, maximum) + */ + vector get_random_number_ex(string account, + uint64_t minimum, + uint64_t maximum, + uint64_t selections, + bool duplicates, + bool broadcast); + + /** Get random number + * @brief Returns the random number + * @param bound Upper bound of segment containing random number + * @return Random number from segment [0, bound) + */ + uint64_t get_random_number(string account, + uint64_t bound, + bool broadcast); + order_book get_order_book( const string& base, const string& quote, unsigned limit = 50); asset get_total_matched_bet_amount_for_betting_market_group(betting_market_group_id_type group_id); @@ -1692,7 +1718,7 @@ class wallet_api sport_id_type sport_id, fc::optional name, bool broadcast = false); - + signed_transaction propose_delete_sport( const string& proposing_account, fc::time_point_sec expiration_time, @@ -1719,7 +1745,7 @@ class wallet_api fc::time_point_sec expiration_time, event_group_id_type event_group, bool broadcast = false); - + signed_transaction propose_create_event( const string& proposing_account, fc::time_point_sec expiration_time, @@ -1790,7 +1816,7 @@ class wallet_api fc::optional payout_condition, bool broadcast = false); - /** Place a bet + /** Place a bet * @param bettor the account placing the bet * @param betting_market_id the market on which to bet * @param back_or_lay back or lay @@ -1866,7 +1892,7 @@ class wallet_api tournament_state state); /** Get specific information about a tournament - * @param tournament_id the ID of the tournament + * @param tournament_id the ID of the tournament */ tournament_object get_tournament(tournament_id_type id); @@ -1926,6 +1952,7 @@ class wallet_api vector get_custom_account_authorities_by_permission_id(custom_permission_id_type permission_id) const; vector get_custom_account_authorities_by_permission_name(string owner, string permission_name) const; vector get_active_custom_account_authorities_by_operation(string owner, int operation_type) const; + ///////// // NFT // ///////// @@ -2202,7 +2229,7 @@ FC_REFLECT_DERIVED( graphene::wallet::signed_block_with_info, (graphene::chain:: FC_REFLECT_DERIVED( graphene::wallet::vesting_balance_object_with_info, (graphene::chain::vesting_balance_object), (allowed_withdraw)(allowed_withdraw_time) ) -FC_REFLECT( graphene::wallet::operation_detail, +FC_REFLECT( graphene::wallet::operation_detail, (memo)(description)(op) ) FC_API( graphene::wallet::wallet_api, @@ -2312,6 +2339,8 @@ FC_API( graphene::wallet::wallet_api, (propose_fee_change) (propose_dividend_asset_update) (approve_proposal) + (get_random_number_ex) + (get_random_number) (dbg_make_uia) (dbg_make_mia) (dbg_push_blocks) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 97b31370f..2617a8262 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -615,7 +615,7 @@ class wallet_api_impl throw fc::canceled_exception(); } - + bool copy_wallet_file( string destination_filename ) { fc::path src_path = get_wallet_filename(); @@ -907,7 +907,7 @@ class wallet_api_impl const rock_paper_scissors_game_details& rps_details = game_obj.game_details.get(); for (unsigned i = 0; i < 2; ++i) { - if (rps_details.commit_moves.at(i) && + if (rps_details.commit_moves.at(i) && !rps_details.reveal_moves.at(i)) // if this player has committed but not revealed { const account_id_type& account_id = game_obj.players[i]; @@ -927,7 +927,7 @@ class wallet_api_impl if (iter != _wallet.committed_game_moves.end()) { const rock_paper_scissors_throw_reveal& reveal = iter->second; - + game_move_operation move_operation; move_operation.game_id = game_obj.id; move_operation.player_account_id = account_id; @@ -970,7 +970,7 @@ class wallet_api_impl } } FC_RETHROW_EXCEPTIONS(warn, "") } - // Cache all matches in the tournament, which will also register us for + // Cache all matches in the tournament, which will also register us for // updates on those matches void monitor_matches_in_tournament(const tournament_object& tournament_obj) { try { @@ -1127,8 +1127,8 @@ class wallet_api_impl dlog( "validated successfully tmp wallet file ${fn}", ("fn", tmp_wallet_filename) ); fc::rename( tmp_wallet_filename, wallet_filename ); dlog( "renamed successfully tmp wallet file ${fn}", ("fn", tmp_wallet_filename) ); - } - else + } + else { FC_THROW("tmp wallet file cannot be validated ${fn}", ("fn", tmp_wallet_filename) ); } @@ -1527,7 +1527,7 @@ class wallet_api_impl return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (issuer)(symbol)(common)(broadcast) ) } - + signed_transaction buy_ticket( asset_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy ) { try { auto asset_obj = get_asset( lottery ); @@ -1538,7 +1538,7 @@ class wallet_api_impl top.buyer = buyer; top.tickets_to_buy = tickets_to_buy; top.amount = asset( asset_obj.lottery_options->ticket_price.amount * tickets_to_buy, asset_obj.lottery_options->ticket_price.asset_id ); - + signed_transaction tx; tx.operations.push_back( top ); set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); @@ -1546,8 +1546,8 @@ class wallet_api_impl return sign_transaction( tx, true ); } FC_CAPTURE_AND_RETHROW( (lottery)(tickets_to_buy) ) } - - + + signed_transaction update_asset(string symbol, optional new_issuer, asset_options new_options, @@ -2102,13 +2102,13 @@ class wallet_api_impl fc::optional vbid = maybe_id(witness_name); if( !vbid ) { - if (is_witness(witness_name)) + if (is_witness(witness_name)) { witness_object wit = get_witness( witness_name ); FC_ASSERT( wit.pay_vb, "Account ${account} has no core Token ${TOKEN} vested and thus its not allowed to withdraw.", ("account", witness_name)("TOKEN", GRAPHENE_SYMBOL)); vbid = wit.pay_vb; } - else + else FC_THROW("Account ${account} has no core Token ${TOKEN} vested and thus its not allowed to withdraw.", ("account", witness_name)("TOKEN", GRAPHENE_SYMBOL)); } @@ -2151,14 +2151,14 @@ class wallet_api_impl if( !vbid ) { vbos = _remote_db->get_vesting_balances( account_name ); - if( vbos.size() == 0 ) + if( vbos.size() == 0 ) FC_THROW("Account ${account} has no core TOKEN vested and thus its not allowed to withdraw.", ("account", account_name)); } - //whether it is a witness or user, keep it in a container and iterate over to process all vesting balances and types + //whether it is a witness or user, keep it in a container and iterate over to process all vesting balances and types if(!vbos.size()) vbos.emplace_back( get_object(*vbid) ); - + for (const vesting_balance_object& vesting_balance_obj: vbos) { if(vesting_balance_obj.balance_type == vesting_balance_type::gpos) { @@ -2188,7 +2188,7 @@ class wallet_api_impl bool broadcast /* = false */) { try { std::vector vbo_info = get_vesting_balances(voting_account); - + time_point_sec now = time_point::now(); if(now >= HARDFORK_GPOS_TIME) //can be removed after GPOS HARDFORK time pass { @@ -2215,7 +2215,7 @@ class wallet_api_impl const auto vesting_subperiod = _remote_db->get_global_properties().parameters.gpos_subperiod(); const auto gpos_start_time = fc::time_point_sec(_remote_db->get_global_properties().parameters.gpos_period_start()); const auto subperiod_start_time = gpos_start_time.sec_since_epoch() + (gpos_info.current_subperiod - 1) * vesting_subperiod; - + if (!insert_result.second && (gpos_info.last_voted_time.sec_since_epoch() >= subperiod_start_time)) FC_THROW("Account ${account} was already voting for committee_member ${committee_member} in the current GPOS sub-period", ("account", voting_account)("committee_member", committee_member)); else @@ -2252,7 +2252,7 @@ class wallet_api_impl bool broadcast /* = false */) { try { std::vector vbo_info = get_vesting_balances(voting_account); - + time_point_sec now = time_point::now(); if(now >= HARDFORK_GPOS_TIME) //can be removed after GPOS HARDFORK time pass { @@ -2263,7 +2263,7 @@ class wallet_api_impl } account_object voting_account_object = get_account(voting_account); - + fc::optional witness_obj = _remote_db->get_witness_by_account(witness); if (!witness_obj) FC_THROW("Account ${witness} is not registered as a witness", ("witness", witness)); @@ -2279,7 +2279,7 @@ class wallet_api_impl const auto vesting_subperiod = _remote_db->get_global_properties().parameters.gpos_subperiod(); const auto gpos_start_time = fc::time_point_sec(_remote_db->get_global_properties().parameters.gpos_period_start()); const auto subperiod_start_time = gpos_start_time.sec_since_epoch() + (gpos_info.current_subperiod - 1) * vesting_subperiod; - + if (!insert_result.second && (gpos_info.last_voted_time.sec_since_epoch() >= subperiod_start_time)) FC_THROW("Account ${account} was already voting for witness ${witness} in the current GPOS sub-period", ("account", voting_account)("witness", witness)); else @@ -2297,7 +2297,7 @@ class wallet_api_impl if (!votes_removed) FC_THROW("Account ${account} has not voted for witness ${witness}", ("account", voting_account)("witness", witness)); } - + account_update_operation account_update_op; account_update_op.account = voting_account_object.id; account_update_op.new_options = voting_account_object.options; @@ -2906,7 +2906,7 @@ class wallet_api_impl { unsigned row_offset = (1 << round) - 1; unsigned row_vertical_spacing = 1 << (round + 1); - if (row >= row_offset && + if (row >= row_offset && (row - row_offset) % row_vertical_spacing == 0) { unsigned player_number_in_round = (row - row_offset) / row_vertical_spacing; @@ -2920,7 +2920,7 @@ class wallet_api_impl if (round == num_rounds) { match_object match = get_object(tournament_details.matches[num_matches - 1]); - if (match.get_state() == match_state::match_complete && + if (match.get_state() == match_state::match_complete && !match.match_winners.empty()) { assert(match.match_winners.size() == 1); @@ -3376,6 +3376,38 @@ class wallet_api_impl return _remote_db->get_active_custom_account_authorities_by_operation(get_account(owner).id, operation_type); } + vector get_random_number_ex(string account, + uint64_t minimum, + uint64_t maximum, + uint64_t selections, + bool duplicates, + bool broadcast) + { + + vector v = _remote_db->get_random_number_ex(minimum, maximum, selections, duplicates); + + random_number_store_operation op; + op.account = get_account(account).id; + op.random_number = v; + op.data = ""; + + signed_transaction trx; + trx.operations.push_back(op); + set_operation_fees( trx, _remote_db->get_global_properties().parameters.current_fees ); + trx.validate(); + sign_transaction( trx, broadcast ); + + return v; + } + + uint64_t get_random_number(string account, + uint64_t bound, + bool broadcast) + { + vector v = get_random_number_ex(account, 0, bound, 1, false, broadcast); + return v.at(0); + } + void dbg_make_uia(string creator, string symbol) { asset_options opts; @@ -3733,7 +3765,7 @@ std::string operation_printer::operator()(const bet_place_operation& op)const auto asset = wallet.get_asset(op.amount_to_bet.asset_id); auto bettor = wallet.get_account(op.bettor_id); - out << bettor.name << " placed a " << fc::json::to_string(op.back_or_lay) << " bet for " + out << bettor.name << " placed a " << fc::json::to_string(op.back_or_lay) << " bet for " << asset.amount_to_pretty_string(op.amount_to_bet) << " at odds " << ((double)op.backer_multiplier / GRAPHENE_BETTING_ODDS_PRECISION) << " on market " << fc::json::to_string(op.betting_market_id) << " fee: " << fee_asset.amount_to_pretty_string(op.fee); @@ -3876,7 +3908,7 @@ vector wallet_api::get_account_lotteries( account_id_type issuer, return my->_remote_db->get_account_lotteries( issuer, stop, limit, start ); } -asset wallet_api::get_lottery_balance( asset_id_type lottery_id )const +asset wallet_api::get_lottery_balance( asset_id_type lottery_id )const { return my->_remote_db->get_lottery_balance( lottery_id ); } @@ -3884,7 +3916,7 @@ asset wallet_api::get_lottery_balance( asset_id_type lottery_id )const vector wallet_api::get_account_history(string name, int limit) const { vector result; - + while (limit > 0) { bool skip_first_row = false; @@ -3935,9 +3967,9 @@ vector wallet_api::get_account_history(string name, int limit) vector wallet_api::get_relative_account_history(string name, uint32_t stop, int limit, uint32_t start)const { - + FC_ASSERT( start > 0 || limit <= 100 ); - + vector result; while( limit > 0 ) @@ -4754,6 +4786,23 @@ vector wallet_api::get_active_custom_account_authorities_by_operation return my->get_active_custom_account_authorities_by_operation(owner, operation_type); } +vector wallet_api::get_random_number_ex(string account, + uint64_t minimum, + uint64_t maximum, + uint64_t selections, + bool duplicates, + bool broadcast) +{ + return my->get_random_number_ex( account, minimum, maximum, selections, duplicates, broadcast ); +} + +uint64_t wallet_api::get_random_number(string account, + uint64_t bound, + bool broadcast) +{ + return my->get_random_number( account, bound, broadcast ); +} + global_property_object wallet_api::get_global_properties() const { return my->get_global_properties(); @@ -5722,22 +5771,22 @@ signed_transaction wallet_api::propose_delete_sport( { FC_ASSERT( !is_locked() ); const chain_parameters& current_params = get_global_properties().parameters; - + sport_delete_operation sport_delete_op; sport_delete_op.sport_id = sport_id; - + proposal_create_operation prop_op; prop_op.expiration_time = expiration_time; prop_op.review_period_seconds = current_params.committee_proposal_review_period; prop_op.fee_paying_account = get_account(proposing_account).id; prop_op.proposed_ops.emplace_back( sport_delete_op ); current_params.current_fees->set_fee( prop_op.proposed_ops.back().op ); - + signed_transaction tx; tx.operations.push_back(prop_op); my->set_operation_fees(tx, current_params.current_fees); tx.validate(); - + return my->sign_transaction(tx, broadcast); } @@ -5800,7 +5849,7 @@ signed_transaction wallet_api::propose_update_event_group( return my->sign_transaction(tx, broadcast); } - + signed_transaction wallet_api::propose_delete_event_group( const string& proposing_account, fc::time_point_sec expiration_time, @@ -5809,22 +5858,22 @@ signed_transaction wallet_api::propose_delete_event_group( { FC_ASSERT( !is_locked() ); const chain_parameters& current_params = get_global_properties().parameters; - + event_group_delete_operation event_group_delete_op; event_group_delete_op.event_group_id = event_group; - + proposal_create_operation prop_op; prop_op.expiration_time = expiration_time; prop_op.review_period_seconds = current_params.committee_proposal_review_period; prop_op.fee_paying_account = get_account(proposing_account).id; prop_op.proposed_ops.emplace_back( event_group_delete_op ); current_params.current_fees->set_fee( prop_op.proposed_ops.back().op ); - + signed_transaction tx; tx.operations.push_back(prop_op); my->set_operation_fees(tx, current_params.current_fees); tx.validate(); - + return my->sign_transaction(tx, broadcast); } @@ -6209,10 +6258,10 @@ signed_transaction wallet_api::tournament_create( string creator, tournament_opt return my->sign_transaction( tx, broadcast ); } -signed_transaction wallet_api::tournament_join( string payer_account, - string player_account, - tournament_id_type tournament_id, - string buy_in_amount, +signed_transaction wallet_api::tournament_join( string payer_account, + string player_account, + tournament_id_type tournament_id, + string buy_in_amount, string buy_in_asset_symbol, bool broadcast ) { @@ -6294,7 +6343,7 @@ signed_transaction wallet_api::rps_throw(game_id_type game_id, graphene::chain::game_object game_obj = my->get_object(game_id); graphene::chain::match_object match_obj = my->get_object(game_obj.match_id); graphene::chain::tournament_object tournament_obj = my->get_object(match_obj.tournament_id); - graphene::chain::rock_paper_scissors_game_options game_options = + graphene::chain::rock_paper_scissors_game_options game_options = tournament_obj.options.game_options.get(); if ((int)gesture >= game_options.number_of_gestures) FC_THROW("Gesture ${gesture} not supported in this game", ("gesture", gesture));