Merge commit '1e80d8a01e6181711bba3d6462e64286d79935b1' into betting

This commit is contained in:
Eric Frias 2017-06-20 19:34:52 -04:00
commit c20978bae6
20 changed files with 557 additions and 37 deletions

12
.gitmodules vendored
View file

@ -1,8 +1,8 @@
[submodule "docs"]
path = docs
url = https://github.com/cryptonomex/graphene.wiki.git
ignore = dirty
path = docs
url = https://github.com/bitshares/bitshares-core.wiki.git
ignore = dirty
[submodule "libraries/fc"]
path = libraries/fc
url = git@bitbucket.org:peerplaysblockchain/peerplays-fc.git
ignore = dirty
path = libraries/fc
url = git@bitbucket.org:peerplaysblockchain/peerplays-fc.git
ignore = dirty

2
docs

@ -1 +1 @@
Subproject commit 8d8b69d82482101279460fa02f814d0e4030966f
Subproject commit cc4a57cf18161d591bb2ad23a2cfa630fa2f9915

View file

@ -1 +1 @@
2.0.161031
2.0.170224

View file

@ -79,6 +79,10 @@ namespace graphene { namespace app {
{
_database_api = std::make_shared< database_api >( std::ref( *_app.chain_database() ) );
}
else if( api_name == "block_api" )
{
_block_api = std::make_shared< block_api >( std::ref( *_app.chain_database() ) );
}
else if( api_name == "network_broadcast_api" )
{
_network_broadcast_api = std::make_shared< network_broadcast_api >( std::ref( _app ) );
@ -95,6 +99,10 @@ namespace graphene { namespace app {
{
_crypto_api = std::make_shared< crypto_api >();
}
else if( api_name == "asset_api" )
{
_asset_api = std::make_shared< asset_api >( std::ref( *_app.chain_database() ) );
}
else if( api_name == "debug_api" )
{
// can only enable this API if the plugin was loaded
@ -104,6 +112,20 @@ namespace graphene { namespace app {
return;
}
// block_api
block_api::block_api(graphene::chain::database& db) : _db(db) { }
block_api::~block_api() { }
vector<optional<signed_block>> block_api::get_blocks(uint32_t block_num_from, uint32_t block_num_to)const
{
FC_ASSERT( block_num_to >= block_num_from );
vector<optional<signed_block>> res;
for(uint32_t block_num=block_num_from; block_num<=block_num_to; block_num++) {
res.push_back(_db.fetch_block_by_number(block_num));
}
return res;
}
network_broadcast_api::network_broadcast_api(application& a):_app(a)
{
_applied_block_connection = _app.chain_database()->applied_block.connect([this](const signed_block& b){ on_applied_block(b); });
@ -193,6 +215,12 @@ namespace graphene { namespace app {
return *_network_broadcast_api;
}
fc::api<block_api> login_api::block()const
{
FC_ASSERT(_block_api);
return *_block_api;
}
fc::api<network_node_api> login_api::network_node()const
{
FC_ASSERT(_network_node_api);
@ -217,6 +245,12 @@ namespace graphene { namespace app {
return *_crypto_api;
}
fc::api<asset_api> login_api::asset() const
{
FC_ASSERT(_asset_api);
return *_asset_api;
}
fc::api<graphene::debug_witness::debug_api> login_api::debug() const
{
FC_ASSERT(_debug_api);
@ -437,6 +471,37 @@ namespace graphene { namespace app {
return result;
}
vector<operation_history_object> history_api::get_account_history_operations( account_id_type account,
int operation_id,
operation_history_id_type start,
operation_history_id_type stop,
unsigned limit) const
{
FC_ASSERT( _app.chain_database() );
const auto& db = *_app.chain_database();
FC_ASSERT( limit <= 100 );
vector<operation_history_object> result;
const auto& stats = account(db).statistics(db);
if( stats.most_recent_op == account_transaction_history_id_type() ) return result;
const account_transaction_history_object* node = &stats.most_recent_op(db);
if( start == operation_history_id_type() )
start = node->operation_id;
while(node && node->operation_id.instance.value > stop.instance.value && result.size() < limit)
{
if( node->operation_id.instance.value <= start.instance.value ) {
if(node->operation_id(db).op.which() == operation_id)
result.push_back( node->operation_id(db) );
}
if( node->next == account_transaction_history_id_type() )
node = nullptr;
else node = &node->next(db);
}
return result;
}
vector<operation_history_object> history_api::get_relative_account_history( account_id_type account,
uint32_t stop,
unsigned limit,
@ -568,4 +633,69 @@ namespace graphene { namespace app {
return fc::ecc::range_get_info( proof );
}
// asset_api
asset_api::asset_api(graphene::chain::database& db) : _db(db) { }
asset_api::~asset_api() { }
vector<account_asset_balance> asset_api::get_asset_holders( asset_id_type asset_id ) const {
const auto& bal_idx = _db.get_index_type< account_balance_index >().indices().get< by_asset_balance >();
auto range = bal_idx.equal_range( boost::make_tuple( asset_id ) );
vector<account_asset_balance> result;
for( const account_balance_object& bal : boost::make_iterator_range( range.first, range.second ) )
{
if( bal.balance.value == 0 ) continue;
auto account = _db.find(bal.owner);
account_asset_balance aab;
aab.name = account->name;
aab.account_id = account->id;
aab.amount = bal.balance.value;
result.push_back(aab);
}
return result;
}
// get number of asset holders.
int asset_api::get_asset_holders_count( asset_id_type asset_id ) const {
const auto& bal_idx = _db.get_index_type< account_balance_index >().indices().get< by_asset_balance >();
auto range = bal_idx.equal_range( boost::make_tuple( asset_id ) );
int count = boost::distance(range) - 1;
return count;
}
// function to get vector of system assets with holders count.
vector<asset_holders> asset_api::get_all_asset_holders() const {
vector<asset_holders> result;
vector<asset_id_type> total_assets;
for( const asset_object& asset_obj : _db.get_index_type<asset_index>().indices() )
{
const auto& dasset_obj = asset_obj.dynamic_asset_data_id(_db);
asset_id_type asset_id;
asset_id = dasset_obj.id;
const auto& bal_idx = _db.get_index_type< account_balance_index >().indices().get< by_asset_balance >();
auto range = bal_idx.equal_range( boost::make_tuple( asset_id ) );
int count = boost::distance(range) - 1;
asset_holders ah;
ah.asset_id = asset_id;
ah.count = count;
result.push_back(ah);
}
return result;
}
} } // graphene::app

View file

@ -46,10 +46,12 @@
#include <fc/rpc/api_connection.hpp>
#include <fc/rpc/websocket_api.hpp>
#include <fc/network/resolve.hpp>
#include <fc/crypto/base64.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/signals2.hpp>
#include <boost/range/algorithm/reverse.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
@ -174,7 +176,8 @@ namespace detail {
"seed04.bitsharesnodes.com:1776", // Thom
"seed05.bitsharesnodes.com:1776", // Thom
"seed06.bitsharesnodes.com:1776", // Thom
"seed07.bitsharesnodes.com:1776" // Thom
"seed07.bitsharesnodes.com:1776", // Thom
"51.15.61.160:1776" // lafona
};
for( const string& endpoint_string : seeds )
{
@ -232,21 +235,46 @@ namespace detail {
FC_CAPTURE_AND_RETHROW((endpoint_string))
}
void new_connection( const fc::http::websocket_connection_ptr& c )
{
auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(*c);
auto login = std::make_shared<graphene::app::login_api>( std::ref(*_self) );
login->enable_api("database_api");
wsc->register_api(login->database());
wsc->register_api(fc::api<graphene::app::login_api>(login));
c->set_session_data( wsc );
std::string username = "*";
std::string password = "*";
// Try to extract login information from "Authorization" header if present
std::string auth = c->get_request_header("Authorization");
if( boost::starts_with(auth, "Basic ") ) {
FC_ASSERT( auth.size() > 6 );
auto user_pass = fc::base64_decode(auth.substr(6));
std::vector<std::string> parts;
boost::split( parts, user_pass, boost::is_any_of(":") );
FC_ASSERT(parts.size() == 2);
username = parts[0];
password = parts[1];
}
login->login(username, password);
}
void reset_websocket_server()
{ try {
if( !_options->count("rpc-endpoint") )
return;
_websocket_server = std::make_shared<fc::http::websocket_server>();
_websocket_server->on_connection( std::bind(&application_impl::new_connection, this, std::placeholders::_1) );
_websocket_server->on_connection([&]( const fc::http::websocket_connection_ptr& c ){
auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(*c);
auto login = std::make_shared<graphene::app::login_api>( std::ref(*_self) );
auto db_api = std::make_shared<graphene::app::database_api>( std::ref(*_self->chain_database()) );
wsc->register_api(fc::api<graphene::app::database_api>(db_api));
wsc->register_api(fc::api<graphene::app::login_api>(login));
c->set_session_data( wsc );
});
ilog("Configured websocket rpc to listen on ${ip}", ("ip",_options->at("rpc-endpoint").as<string>()));
_websocket_server->listen( fc::ip::endpoint::from_string(_options->at("rpc-endpoint").as<string>()) );
_websocket_server->start_accept();
@ -265,15 +293,8 @@ namespace detail {
string password = _options->count("server-pem-password") ? _options->at("server-pem-password").as<string>() : "";
_websocket_tls_server = std::make_shared<fc::http::websocket_tls_server>( _options->at("server-pem").as<string>(), password );
_websocket_tls_server->on_connection( std::bind(&application_impl::new_connection, this, std::placeholders::_1) );
_websocket_tls_server->on_connection([&]( const fc::http::websocket_connection_ptr& c ){
auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(*c);
auto login = std::make_shared<graphene::app::login_api>( std::ref(*_self) );
auto db_api = std::make_shared<graphene::app::database_api>( std::ref(*_self->chain_database()) );
wsc->register_api(fc::api<graphene::app::database_api>(db_api));
wsc->register_api(fc::api<graphene::app::login_api>(login));
c->set_session_data( wsc );
});
ilog("Configured websocket TLS rpc to listen on ${ip}", ("ip",_options->at("rpc-tls-endpoint").as<string>()));
_websocket_tls_server->listen( fc::ip::endpoint::from_string(_options->at("rpc-tls-endpoint").as<string>()) );
_websocket_tls_server->start_accept();

View file

@ -76,6 +76,7 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
// Keys
vector<vector<account_id_type>> get_key_references( vector<public_key_type> key )const;
bool is_public_key_registered(string public_key) const;
// Accounts
vector<optional<account_object>> get_accounts(const vector<account_id_type>& account_ids)const;
@ -503,6 +504,35 @@ vector<vector<account_id_type>> database_api_impl::get_key_references( vector<pu
return final_result;
}
bool database_api::is_public_key_registered(string public_key) const
{
return my->is_public_key_registered(public_key);
}
bool database_api_impl::is_public_key_registered(string public_key) const
{
// Short-circuit
if (public_key.empty()) {
return false;
}
// Search among all keys using an existing map of *current* account keys
public_key_type key;
try {
key = public_key_type(public_key);
} catch ( ... ) {
// An invalid public key was detected
return false;
}
const auto& idx = _db.get_index_type<account_index>();
const auto& aidx = dynamic_cast<const primary_index<account_index>&>(idx);
const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
auto itr = refs.account_to_key_memberships.find(key);
bool is_known = itr != refs.account_to_key_memberships.end();
return is_known;
}
//////////////////////////////////////////////////////////////////////
// //
// Accounts //
@ -618,6 +648,22 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
[&acnt] (const call_order_object& call) {
acnt.call_orders.emplace_back(call);
});
// get assets issued by user
auto asset_range = _db.get_index_type<asset_index>().indices().get<by_issuer>().equal_range(account->id);
std::for_each(asset_range.first, asset_range.second,
[&acnt] (const asset_object& asset) {
acnt.assets.emplace_back(asset.id);
});
// get withdraws permissions
auto withdraw_range = _db.get_index_type<withdraw_permission_index>().indices().get<by_from>().equal_range(account->id);
std::for_each(withdraw_range.first, withdraw_range.second,
[&acnt] (const withdraw_permission_object& withdraw) {
acnt.withdraws.emplace_back(withdraw);
});
results[account_name_or_id] = acnt;
}
return results;

View file

@ -71,6 +71,18 @@ namespace graphene { namespace app {
string message_out;
};
struct account_asset_balance
{
string name;
account_id_type account_id;
share_type amount;
};
struct asset_holders
{
asset_id_type asset_id;
int count;
};
/**
* @brief The history_api class implements the RPC API for account history
*
@ -93,6 +105,22 @@ namespace graphene { namespace app {
operation_history_id_type stop = operation_history_id_type(),
unsigned limit = 100,
operation_history_id_type start = operation_history_id_type())const;
/**
* @brief Get only asked operations relevant to the specified account
* @param account The account whose history should be queried
* @param operation_id The ID of the operation we want to get operations in the account( 0 = transfer , 1 = limit order create, ...)
* @param stop ID of the earliest operation to retrieve
* @param limit Maximum number of operations to retrieve (must not exceed 100)
* @param start ID of the most recent operation to retrieve
* @return A list of operations performed by account, ordered from most recent to oldest.
*/
vector<operation_history_object> get_account_history_operations(account_id_type account,
int operation_id,
operation_history_id_type start = operation_history_id_type(),
operation_history_id_type stop = operation_history_id_type(),
unsigned limit = 100)const;
/**
* @breif Get operations relevant to the specified account referenced
* by an event numbering specific to the account. The current number of operations
@ -118,6 +146,22 @@ namespace graphene { namespace app {
application& _app;
};
/**
* @brief Block api
*/
class block_api
{
public:
block_api(graphene::chain::database& db);
~block_api();
vector<optional<signed_block>> get_blocks(uint32_t block_num_from, uint32_t block_num_to)const;
private:
graphene::chain::database& _db;
};
/**
* @brief The network_broadcast_api class allows broadcasting of transactions.
*/
@ -252,6 +296,23 @@ namespace graphene { namespace app {
range_proof_info range_get_info( const std::vector<char>& proof );
};
/**
* @brief
*/
class asset_api
{
public:
asset_api(graphene::chain::database& db);
~asset_api();
vector<account_asset_balance> get_asset_holders( asset_id_type asset_id )const;
int get_asset_holders_count( asset_id_type asset_id )const;
vector<asset_holders> get_all_asset_holders() const;
private:
graphene::chain::database& _db;
};
/**
* @brief The login_api class implements the bottom layer of the RPC API
*
@ -273,6 +334,8 @@ namespace graphene { namespace app {
* has sucessfully authenticated.
*/
bool login(const string& user, const string& password);
/// @brief Retrieve the network block API
fc::api<block_api> block()const;
/// @brief Retrieve the network broadcast API
fc::api<network_broadcast_api> network_broadcast()const;
/// @brief Retrieve the database API
@ -283,19 +346,23 @@ namespace graphene { namespace app {
fc::api<network_node_api> network_node()const;
/// @brief Retrieve the cryptography API
fc::api<crypto_api> crypto()const;
/// @brief Retrieve the asset API
fc::api<asset_api> asset()const;
/// @brief Retrieve the debug API (if available)
fc::api<graphene::debug_witness::debug_api> debug()const;
private:
/// @brief Called to enable an API, not reflected.
void enable_api( const string& api_name );
private:
application& _app;
optional< fc::api<block_api> > _block_api;
optional< fc::api<database_api> > _database_api;
optional< fc::api<network_broadcast_api> > _network_broadcast_api;
optional< fc::api<network_node_api> > _network_node_api;
optional< fc::api<history_api> > _history_api;
optional< fc::api<crypto_api> > _crypto_api;
optional< fc::api<asset_api> > _asset_api;
optional< fc::api<graphene::debug_witness::debug_api> > _debug_api;
};
@ -310,13 +377,20 @@ FC_REFLECT( graphene::app::verify_range_proof_rewind_result,
//FC_REFLECT_TYPENAME( fc::ecc::compact_signature );
//FC_REFLECT_TYPENAME( fc::ecc::commitment_type );
FC_REFLECT( graphene::app::account_asset_balance, (name)(account_id)(amount) );
FC_REFLECT( graphene::app::asset_holders, (asset_id)(count) );
FC_API(graphene::app::history_api,
(get_account_history)
(get_account_history_operations)
(get_relative_account_history)
(get_fill_order_history)
(get_market_history)
(get_market_history_buckets)
)
FC_API(graphene::app::block_api,
(get_blocks)
)
FC_API(graphene::app::network_broadcast_api,
(broadcast_transaction)
(broadcast_transaction_with_callback)
@ -341,12 +415,19 @@ FC_API(graphene::app::crypto_api,
(verify_range_proof_rewind)
(range_get_info)
)
FC_API(graphene::app::asset_api,
(get_asset_holders)
(get_asset_holders_count)
(get_all_asset_holders)
)
FC_API(graphene::app::login_api,
(login)
(block)
(network_broadcast)
(database)
(history)
(network_node)
(crypto)
(asset)
(debug)
)

View file

@ -217,6 +217,15 @@ class database_api
vector<vector<account_id_type>> get_key_references( vector<public_key_type> key )const;
/**
* Determine whether a textual representation of a public key
* (in Base-58 format) is *currently* linked
* to any *registered* (i.e. non-stealth) account on the blockchain
* @param public_key Public key
* @return Whether a public key is known
*/
bool is_public_key_registered(string public_key) const;
//////////////
// Accounts //
//////////////
@ -626,6 +635,7 @@ FC_API(graphene::app::database_api,
// Keys
(get_key_references)
(is_public_key_registered)
// Accounts
(get_accounts)

View file

@ -26,6 +26,7 @@
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/vesting_balance_object.hpp>
#include <graphene/chain/market_evaluator.hpp>
#include <graphene/chain/withdraw_permission_object.hpp>
namespace graphene { namespace app {
using namespace graphene::chain;
@ -44,6 +45,8 @@ namespace graphene { namespace app {
vector<limit_order_object> limit_orders;
vector<call_order_object> call_orders;
vector<proposal_object> proposals;
vector<asset_id_type> assets;
vector<withdraw_permission_object> withdraws;
};
} }
@ -61,4 +64,6 @@ FC_REFLECT( graphene::app::full_account,
(limit_orders)
(call_orders)
(proposals)
(assets)
(withdraws)
)

View file

@ -232,11 +232,13 @@ namespace graphene { namespace chain {
struct by_symbol;
struct by_type;
struct by_issuer;
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_unique< tag<by_type>,
composite_key< asset_object,
const_mem_fun<asset_object, bool, &asset_object::is_market_issued>,

View file

@ -264,7 +264,6 @@ namespace graphene { namespace chain {
} } // graphene::chain
FC_REFLECT(graphene::chain::account_options, (memo_key)(voting_account)(num_witness)(num_committee)(votes)(extensions))
FC_REFLECT_TYPENAME( graphene::chain::account_whitelist_operation::account_listing)
FC_REFLECT_ENUM( graphene::chain::account_whitelist_operation::account_listing,
(no_listing)(white_listed)(black_listed)(white_and_black_listed))

View file

@ -132,5 +132,4 @@ void add_authority_accounts(
} } // namespace graphene::chain
FC_REFLECT( graphene::chain::authority, (weight_threshold)(account_auths)(key_auths)(address_auths) )
FC_REFLECT_TYPENAME( graphene::chain::authority::classification )
FC_REFLECT_ENUM( graphene::chain::authority::classification, (owner)(active)(key) )

View file

@ -146,7 +146,6 @@ void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo );
} // fc
FC_REFLECT_TYPENAME( graphene::chain::vote_id_type::vote_type )
FC_REFLECT_TYPENAME( fc::flat_set<graphene::chain::vote_id_type> )
FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(VOTE_TYPE_COUNT) )

@ -1 +1 @@
Subproject commit 7a44b21acfea6728367a0cf56b1f3f7f8104aa63
Subproject commit 772c2b28226736b455e31b1fdf51e4f18bf33cee

View file

@ -96,7 +96,8 @@ void witness_plugin::plugin_initialize(const boost::program_options::variables_m
for (const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings)
{
auto key_id_to_wif_pair = graphene::app::dejsonify<std::pair<chain::public_key_type, std::string> >(key_id_to_wif_pair_string);
idump((key_id_to_wif_pair));
//idump((key_id_to_wif_pair));
ilog("Public Key: ${public}", ("public", key_id_to_wif_pair.first));
fc::optional<fc::ecc::private_key> private_key = graphene::utilities::wif_to_key(key_id_to_wif_pair.second);
if (!private_key)
{

View file

@ -258,6 +258,26 @@ namespace detail {
class wallet_api_impl;
}
/***
* A utility class for performing various state-less actions that are related to wallets
*/
class utility {
public:
/**
* Derive any number of *possible* owner keys from a given brain key.
*
* NOTE: These keys may or may not match with the owner keys of any account.
* This function is merely intended to assist with account or key recovery.
*
* @see suggest_brain_key()
*
* @param brain_key Brain key
* @param number_of_desired_keys Number of desired keys
* @return A list of keys that are deterministically derived from the brainkey
*/
static vector<brain_key_info> derive_owner_keys_from_brain_key(string brain_key, int number_of_desired_keys = 1);
};
struct operation_detail {
string memo;
string description;
@ -330,8 +350,6 @@ class wallet_api
*
* This returns a list of operation history objects, which describe activity on the account.
*
* @note this API doesn't give a way to retrieve more than the most recent 100 transactions,
* you can interface directly with the blockchain to get more history
* @param name the name or id of the account
* @param limit the number of entries to return (starting from the most recent) (max 100)
* @returns a list of \c operation_history_objects
@ -339,7 +357,7 @@ class wallet_api
vector<operation_detail> get_account_history(string name, int limit)const;
vector<bucket_object> get_market_history(string symbol, string symbol2, uint32_t bucket)const;
vector<bucket_object> get_market_history(string symbol, string symbol2, uint32_t bucket, fc::time_point_sec start, fc::time_point_sec end)const;
vector<limit_order_object> get_limit_orders(string a, string b, uint32_t limit)const;
vector<call_order_object> get_call_orders(string a, uint32_t limit)const;
vector<force_settlement_object> get_settle_orders(string a, uint32_t limit)const;
@ -578,6 +596,29 @@ class wallet_api
*/
brain_key_info suggest_brain_key()const;
/**
* Derive any number of *possible* owner keys from a given brain key.
*
* NOTE: These keys may or may not match with the owner keys of any account.
* This function is merely intended to assist with account or key recovery.
*
* @see suggest_brain_key()
*
* @param brain_key Brain key
* @param numberOfDesiredKeys Number of desired keys
* @return A list of keys that are deterministically derived from the brainkey
*/
vector<brain_key_info> derive_owner_keys_from_brain_key(string brain_key, int number_of_desired_keys = 1) const;
/**
* Determine whether a textual representation of a public key
* (in Base-58 format) is *currently* linked
* to any *registered* (i.e. non-stealth) account on the blockchain
* @param public_key Public key
* @return Whether a public key is known
*/
bool is_public_key_registered(string public_key) const;
/** Converts a signed_transaction in JSON form to its binary representation.
*
* TODO: I don't see a broadcast_transaction() function, do we need one?
@ -1632,6 +1673,7 @@ FC_API( graphene::wallet::wallet_api,
(import_account_keys)
(import_balance)
(suggest_brain_key)
(derive_owner_keys_from_brain_key)
(register_account)
(upgrade_account)
(create_account_with_brain_key)
@ -1676,6 +1718,7 @@ FC_API( graphene::wallet::wallet_api,
(get_block)
(get_account_count)
(get_account_history)
(is_public_key_registered)
(get_market_history)
(get_global_properties)
(get_dynamic_global_properties)

View file

@ -2717,7 +2717,29 @@ std::string operation_result_printer::operator()(const asset& a)
}}}
namespace graphene { namespace wallet {
vector<brain_key_info> utility::derive_owner_keys_from_brain_key(string brain_key, int number_of_desired_keys)
{
// Safety-check
FC_ASSERT( number_of_desired_keys >= 1 );
// Create as many derived owner keys as requested
vector<brain_key_info> results;
brain_key = graphene::wallet::detail::normalize_brain_key(brain_key);
for (int i = 0; i < number_of_desired_keys; ++i) {
fc::ecc::private_key priv_key = graphene::wallet::detail::derive_private_key( brain_key, i );
brain_key_info result;
result.brain_priv_key = brain_key;
result.wif_priv_key = key_to_wif( priv_key );
result.pub_key = priv_key.get_public_key();
results.push_back(result);
}
return results;
}
}}
namespace graphene { namespace wallet {
@ -2797,9 +2819,9 @@ vector<operation_detail> wallet_api::get_account_history(string name, int limit)
}
vector<bucket_object> wallet_api::get_market_history( string symbol1, string symbol2, uint32_t bucket )const
vector<bucket_object> wallet_api::get_market_history( string symbol1, string symbol2, uint32_t bucket , fc::time_point_sec start, fc::time_point_sec end )const
{
return my->_remote_hist->get_market_history( get_asset_id(symbol1), get_asset_id(symbol2), bucket, fc::time_point_sec(), fc::time_point::now() );
return my->_remote_hist->get_market_history( get_asset_id(symbol1), get_asset_id(symbol2), bucket, start, end );
}
vector<limit_order_object> wallet_api::get_limit_orders(string a, string b, uint32_t limit)const
@ -2847,6 +2869,18 @@ brain_key_info wallet_api::suggest_brain_key()const
return result;
}
vector<brain_key_info> wallet_api::derive_owner_keys_from_brain_key(string brain_key, int number_of_desired_keys) const
{
return graphene::wallet::utility::derive_owner_keys_from_brain_key(brain_key, number_of_desired_keys);
}
bool wallet_api::is_public_key_registered(string public_key) const
{
bool is_known = my->_remote_db->is_public_key_registered(public_key);
return is_known;
}
string wallet_api::serialize_transaction( signed_transaction tx )const
{
return fc::to_hex(fc::raw::pack(tx));

View file

@ -8,7 +8,7 @@ endif()
file(GLOB UNIT_TESTS "tests/*.cpp")
add_executable( chain_test ${UNIT_TESTS} ${COMMON_SOURCES} )
target_link_libraries( chain_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
target_link_libraries( chain_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} )
if(MSVC)
set_source_files_properties( tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
endif(MSVC)

View file

@ -0,0 +1,71 @@
/*
* Copyright (c) 2017 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 <boost/test/unit_test.hpp>
#include <graphene/app/database_api.hpp>
#include "../common/database_fixture.hpp"
using namespace graphene::chain;
using namespace graphene::chain::test;
BOOST_FIXTURE_TEST_SUITE(database_api_tests, database_fixture)
BOOST_AUTO_TEST_CASE(is_registered) {
try {
/***
* Arrange
*/
auto nathan_private_key = generate_private_key("nathan");
public_key_type nathan_public = nathan_private_key.get_public_key();
auto dan_private_key = generate_private_key("dan");
public_key_type dan_public = dan_private_key.get_public_key();
auto unregistered_private_key = generate_private_key("unregistered");
public_key_type unregistered_public = unregistered_private_key.get_public_key();
/***
* Act
*/
create_account("dan", dan_private_key.get_public_key()).id;
create_account("nathan", nathan_private_key.get_public_key()).id;
// Unregistered key will not be registered with any account
/***
* Assert
*/
graphene::app::database_api db_api(db);
BOOST_CHECK(db_api.is_public_key_registered((string) nathan_public));
BOOST_CHECK(db_api.is_public_key_registered((string) dan_public));
BOOST_CHECK(!db_api.is_public_key_registered((string) unregistered_public));
} FC_LOG_AND_RETHROW()
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2017 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 <boost/test/unit_test.hpp>
#include <graphene/app/database_api.hpp>
#include <graphene/wallet/wallet.hpp>
#include <iostream>
#include "../common/database_fixture.hpp"
using namespace graphene::chain;
using namespace graphene::chain::test;
using namespace graphene::wallet;
BOOST_FIXTURE_TEST_SUITE(wallet_tests, database_fixture)
/***
* Check the basic behavior of deriving potential owner keys from a brain key
*/
BOOST_AUTO_TEST_CASE(derive_owner_keys_from_brain_key) {
try {
/***
* Act
*/
int nbr_keys_desired = 3;
vector<brain_key_info> derived_keys = graphene::wallet::utility::derive_owner_keys_from_brain_key("SOME WORDS GO HERE", nbr_keys_desired);
/***
* Assert: Check the number of derived keys
*/
BOOST_CHECK_EQUAL(nbr_keys_desired, derived_keys.size());
/***
* Assert: Check that each derived key is unique
*/
set<string> set_derived_public_keys;
for (auto info : derived_keys) {
string description = (string) info.pub_key;
set_derived_public_keys.emplace(description);
}
BOOST_CHECK_EQUAL(nbr_keys_desired, set_derived_public_keys.size());
/***
* Assert: Check whether every public key begins with the expected prefix
*/
string expected_prefix = GRAPHENE_ADDRESS_PREFIX;
for (auto info : derived_keys) {
string description = (string) info.pub_key;
BOOST_CHECK_EQUAL(0, description.find(expected_prefix));
}
} FC_LOG_AND_RETHROW()
}
BOOST_AUTO_TEST_SUITE_END()