Merge commit '1e80d8a01e6181711bba3d6462e64286d79935b1' into betting
This commit is contained in:
commit
c20978bae6
20 changed files with 557 additions and 37 deletions
12
.gitmodules
vendored
12
.gitmodules
vendored
|
|
@ -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
2
docs
|
|
@ -1 +1 @@
|
|||
Subproject commit 8d8b69d82482101279460fa02f814d0e4030966f
|
||||
Subproject commit cc4a57cf18161d591bb2ad23a2cfa630fa2f9915
|
||||
|
|
@ -1 +1 @@
|
|||
2.0.161031
|
||||
2.0.170224
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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) )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
71
tests/tests/database_api_tests.cpp
Normal file
71
tests/tests/database_api_tests.cpp
Normal 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()
|
||||
79
tests/tests/wallet_tests.cpp
Normal file
79
tests/tests/wallet_tests.cpp
Normal 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()
|
||||
Loading…
Reference in a new issue