24 #include <boost/algorithm/string/replace.hpp>
25 #include <boost/range/adaptors.hpp>
38 # include <sys/types.h>
39 # include <sys/stat.h>
44 template class api<graphene::wallet::wallet_api, identity_member_with_optionals>;
51 namespace graphene {
namespace wallet {
namespace detail {
53 wallet_api_impl::wallet_api_impl( wallet_api& s,
const wallet_data& initial_data,
fc::api<login_api> rapi )
55 _chain_id(initial_data.chain_id),
58 _remote_net_broadcast(rapi->network_broadcast()),
59 _remote_hist(rapi->history())
62 _custom_operations = rapi->custom_operations();
66 wlog(
"Custom operations API is not active on server.");
69 if( remote_chain_id != _chain_id )
71 FC_THROW(
"Remote server gave us an unexpected chain_id",
72 (
"remote_chain_id", remote_chain_id)
73 (
"chain_id", _chain_id) );
77 _remote_db->set_block_applied_callback( [
this](
const variant& block_id )
79 on_block_applied( block_id );
82 _wallet.chain_id = _chain_id;
83 _wallet.ws_server = initial_data.ws_server;
84 _wallet.ws_user = initial_data.ws_user;
85 _wallet.ws_password = initial_data.ws_password;
88 wallet_api_impl::~wallet_api_impl()
92 _remote_db->cancel_all_subscriptions();
106 auto chain_props = get_chain_properties();
107 auto global_props = get_global_properties();
108 auto dynamic_props = get_dynamic_global_properties();
110 result[
"head_block_num"] = dynamic_props.head_block_number;
111 result[
"head_block_id"] =
fc::variant(dynamic_props.head_block_id, 1);
115 result[
"next_maintenance_time"] =
117 result[
"chain_id"] = chain_props.chain_id;
118 stringstream participation;
119 participation << fixed << std::setprecision(2) << (100.0*
fc::popcount(dynamic_props.recent_slots_filled)) / 128.0;
120 result[
"participation"] = participation.str();
122 result[
"active_committee_members"] =
133 const size_t pos = client_version.find(
'/' );
134 if( pos != string::npos && client_version.size() > pos )
135 client_version = client_version.substr( pos + 1 );
140 result[
"client_version"] = client_version;
147 result[
"compile_date"] =
"compiled on " __DATE__
" at " __TIME__;
148 result[
"boost_version"] = boost::replace_all_copy(std::string(BOOST_LIB_VERSION),
"_",
".");
149 result[
"openssl_version"] = OPENSSL_VERSION_TEXT;
151 std::string bitness = boost::lexical_cast<std::string>(8 *
sizeof(
int*)) +
"-bit";
152 #if defined(__APPLE__)
153 std::string os =
"osx";
154 #elif defined(__linux__)
155 std::string os =
"linux";
156 #elif defined(_MSC_VER)
157 std::string os =
"win32";
159 std::string os =
"other";
161 result[
"build"] = os +
" " + bitness;
166 void wallet_api_impl::quit()
168 ilog(
"Quitting Cli Wallet ..." );
170 throw fc::canceled_exception();
175 return _remote_db->get_chain_properties();
179 return _remote_db->get_global_properties();
183 return _remote_db->get_dynamic_global_properties();
186 void wallet_api_impl::on_block_applied(
const variant& block_id )
188 fc::async([
this]{resync();},
"Resync after block");
197 operation wallet_api_impl::get_prototype_operation(
string operation_name )
199 auto it = _prototype_ops.find( operation_name );
200 if( it == _prototype_ops.end() )
201 FC_THROW(
"Unsupported operation: \"${operation_name}\"", (
"operation_name", operation_name));
205 void wallet_api_impl::init_prototype_ops()
208 int64_t op_count = op.
count();
209 for( int64_t t=0; t<op_count; t++ )
217 int wallet_api_impl::find_first_unused_derived_key_index(
const fc::ecc::private_key& parent_key)
219 int first_unused_index = 0;
220 int number_of_consecutive_unused_keys = 0;
221 for (
int key_index = 0; ; ++key_index)
225 if( _keys.find(derived_public_key) == _keys.end() )
227 if (number_of_consecutive_unused_keys)
229 ++number_of_consecutive_unused_keys;
230 if (number_of_consecutive_unused_keys > 5)
231 return first_unused_index;
235 first_unused_index = key_index;
236 number_of_consecutive_unused_keys = 1;
242 first_unused_index = 0;
243 number_of_consecutive_unused_keys = 0;
248 void wallet_api_impl::enable_umask_protection()
251 _old_umask = umask( S_IRWXG | S_IRWXO );
255 void wallet_api_impl::disable_umask_protection()
262 bool wallet_api_impl::copy_wallet_file(
string destination_filename )
264 fc::path src_path = get_wallet_filename();
267 fc::path dest_path = destination_filename + _wallet_filename_extension;
272 dest_path = destination_filename +
"-" +
to_string( suffix ) + _wallet_filename_extension;
274 wlog(
"backing up wallet ${src} to ${dest}",
276 (
"dest", dest_path) );
281 enable_umask_protection();
285 disable_umask_protection();
289 disable_umask_protection();
298 bool wallet_api_impl::is_locked()
const
303 void wallet_api_impl::resync()
314 if( !_wallet.pending_account_registrations.empty() )
317 std::vector<string> pending_account_names =
318 boost::copy_range<std::vector<string> >(boost::adaptors::keys(_wallet.pending_account_registrations));
321 std::vector<fc::optional<graphene::chain::account_object >>
322 pending_account_objects = _remote_db->lookup_account_names( pending_account_names );
326 if( optional_account )
327 claim_registered_account(*optional_account);
330 if (!_wallet.pending_witness_registrations.empty())
333 std::vector<string> pending_witness_names =
334 boost::copy_range<std::vector<string> >(boost::adaptors::keys(_wallet.pending_witness_registrations));
337 std::vector<fc::optional<graphene::chain::account_object>> owner_account_objects =
338 _remote_db->lookup_account_names(pending_witness_names);
342 if (optional_account)
344 auto account_id = std::string(optional_account->id);
347 claim_registered_witness(optional_account->name);
352 string wallet_api_impl::get_wallet_filename()
const
354 return _wallet_filename;
357 bool wallet_api_impl::load_wallet_file(
string wallet_filename)
361 if( wallet_filename ==
"" )
362 wallet_filename = _wallet_filename;
368 if( _wallet.chain_id != _chain_id )
369 FC_THROW(
"Wallet chain ID does not match",
370 (
"wallet.chain_id", _wallet.chain_id)
371 (
"chain_id", _chain_id) );
373 size_t account_pagination = 100;
374 vector< std::string > account_ids_to_send;
375 size_t n = _wallet.my_accounts.size();
376 account_ids_to_send.reserve( std::min( account_pagination, n ) );
377 auto it = _wallet.my_accounts.begin();
379 for(
size_t start=0; start<n; start+=account_pagination )
381 size_t end = std::min( start+account_pagination, n );
382 assert( end > start );
383 account_ids_to_send.clear();
384 std::vector< account_object > old_accounts;
385 for(
size_t i=start; i<end; i++ )
387 assert( it != _wallet.my_accounts.end() );
388 old_accounts.push_back( *it );
389 auto account_id = std::string(old_accounts.back().id);
390 account_ids_to_send.push_back( account_id );
393 std::vector< optional< account_object > > accounts = _remote_db->get_accounts(account_ids_to_send, {});
395 FC_ASSERT( accounts.size() == account_ids_to_send.size() );
402 elog(
"Could not find account ${id} : \"${name}\" does not exist on the chain!",
403 (
"id", old_acct.
id)(
"name", old_acct.
name) );
412 wlog(
"Account ${id} : \"${name}\" updated on chain", (
"id", acct->id)(
"name", acct->name) );
414 _wallet.update_account( *acct );
422 void wallet_api_impl::save_wallet_file(
string wallet_filename)
433 if( wallet_filename ==
"" )
434 wallet_filename = _wallet_filename;
436 wlog(
"saving wallet to file ${fn}", (
"fn", wallet_filename) );
442 enable_umask_protection();
449 std::string tmp_wallet_filename = wallet_filename +
".tmp";
451 outfile.write( data.c_str(), data.length() );
455 wlog(
"saved successfully wallet to tmp file ${fn}", (
"fn", tmp_wallet_filename) );
457 std::string wallet_file_content;
460 if (wallet_file_content == data) {
461 wlog(
"validated successfully tmp wallet file ${fn}", (
"fn", tmp_wallet_filename) );
463 fc::rename( tmp_wallet_filename, wallet_filename );
465 wlog(
"renamed successfully tmp wallet file ${fn}", (
"fn", tmp_wallet_filename) );
469 FC_THROW(
"tmp wallet file cannot be validated ${fn}", (
"fn", tmp_wallet_filename) );
472 wlog(
"successfully saved wallet to file ${fn}", (
"fn", wallet_filename) );
474 disable_umask_protection();
478 string ws_password = _wallet.ws_password;
479 _wallet.ws_password =
"";
481 _wallet.ws_password = ws_password;
483 disable_umask_protection();