From e731941cf0c0005d4860f1833038565490686c51 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 9 Oct 2015 13:05:19 -0400 Subject: [PATCH] wallet.cpp: Allow specifying wildcard in keys when running import_balance Also, don't put private keys in error messages. --- .../wallet/include/graphene/wallet/wallet.hpp | 4 +- libraries/wallet/wallet.cpp | 118 +++++++++++++----- 2 files changed, 88 insertions(+), 34 deletions(-) diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index de5c4f63..36007aa4 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -575,10 +575,10 @@ class wallet_api bool import_account_keys( string filename, string password, string src_account_name, string dest_account_name ); /** - * This call will construct a transaction that will claim all balances controled + * This call will construct transaction(s) that will claim all balances controled * by wif_keys and deposit them into the given account. */ - signed_transaction import_balance( string account_name_or_id, const vector& wif_keys, bool broadcast ); + vector< signed_transaction > import_balance( string account_name_or_id, const vector& wif_keys, bool broadcast ); /** Transforms a brain key to reduce the chance of errors when re-entering the key from memory. * diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index a28ec302..d940861d 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -624,7 +624,7 @@ public: { fc::optional optional_private_key = wif_to_key(wif_key); if (!optional_private_key) - FC_THROW("Invalid private key ${key}", ("key", wif_key)); + FC_THROW("Invalid private key"); graphene::chain::public_key_type wif_pub_key = optional_private_key->get_public_key(); account_object account = get_account( account_name_or_id ); @@ -646,6 +646,8 @@ public: return all_keys_for_account.find(wif_pub_key) != all_keys_for_account.end(); } + vector< signed_transaction > import_balance( string name_or_id, const vector& wif_keys, bool broadcast ); + bool load_wallet_file(string wallet_filename = "") { // TODO: Merge imported wallet with existing wallet, @@ -2571,7 +2573,7 @@ bool wallet_api::import_key(string account_name_or_id, string wif_key) // backup wallet fc::optional optional_private_key = wif_to_key(wif_key); if (!optional_private_key) - FC_THROW("Invalid private key ${key}", ("key", wif_key)); + FC_THROW("Invalid private key"); string shorthash = detail::address_to_shorthash(optional_private_key->get_public_key()); copy_wallet_file( "before-import-key-" + shorthash ); @@ -3119,65 +3121,117 @@ void wallet_api::set_password( string password ) lock(); } -signed_transaction wallet_api::import_balance( string name_or_id, const vector& wif_keys, bool broadcast ) +vector< signed_transaction > wallet_api::import_balance( string name_or_id, const vector& wif_keys, bool broadcast ) +{ + return my->import_balance( name_or_id, wif_keys, broadcast ); +} + +namespace detail { + +vector< signed_transaction > wallet_api_impl::import_balance( string name_or_id, const vector& wif_keys, bool broadcast ) { try { FC_ASSERT(!is_locked()); + const dynamic_global_property_object& dpo = _remote_db->get_dynamic_global_properties(); account_object claimer = get_account( name_or_id ); + uint32_t max_ops_per_tx = 30; - vector
addrs; - map keys; - for( auto wif_key : wif_keys ) + map< address, private_key_type > keys; // local index of address -> private key + vector< address > addrs; + bool has_wildcard = false; + addrs.reserve( wif_keys.size() ); + for( const string& wif_key : wif_keys ) { - auto priv_key = wif_to_key(wif_key); - FC_ASSERT( priv_key, "Invalid Private Key", ("key",wif_key) ); - addrs.push_back( priv_key->get_public_key() ); - keys[addrs.back()] = *priv_key; + if( wif_key == "*" ) + { + if( has_wildcard ) + continue; + for( const public_key_type& pub : _wallet.extra_keys[ claimer.id ] ) + { + addrs.push_back( pub ); + auto it = _keys.find( pub ); + if( it != _keys.end() ) + { + fc::optional< fc::ecc::private_key > privkey = wif_to_key( it->second ); + FC_ASSERT( privkey ); + keys[ addrs.back() ] = *privkey; + } + else + { + wlog( "Somehow _keys has no private key for extra_keys public key ${k}", ("k", pub) ); + } + } + has_wildcard = true; + } + else + { + optional< private_key_type > key = wif_to_key( wif_key ); + FC_ASSERT( key.valid(), "Invalid private key" ); + addrs.push_back( key->get_public_key() ); + keys[addrs.back()] = *key; + } } - auto balances = my->_remote_db->get_balance_objects( addrs ); + vector< balance_object > balances = _remote_db->get_balance_objects( addrs ); wdump((balances)); addrs.clear(); set bal_types; for( auto b : balances ) bal_types.insert( b.balance.asset_id ); - set
required_addrs; - signed_transaction trx; - for( auto a : bal_types ) + struct claim_tx + { + vector< balance_claim_operation > ops; + set< address > addrs; + }; + vector< claim_tx > claim_txs; + + for( const asset_id_type& a : bal_types ) { balance_claim_operation op; op.deposit_to_account = claimer.id; - for( const auto& b : balances ) + for( const balance_object& b : balances ) { if( b.balance.asset_id == a ) { - op.total_claimed = b.vesting_policy.valid()? asset(0, b.balance.asset_id) : b.balance; + op.total_claimed = b.available( dpo.time ); + if( op.total_claimed.amount == 0 ) + continue; op.balance_to_claim = b.id; op.balance_owner_key = keys[b.owner].get_public_key(); - trx.operations.push_back(op); - required_addrs.insert(b.owner); + if( (claim_txs.empty()) || (claim_txs.back().ops.size() >= max_ops_per_tx) ) + claim_txs.emplace_back(); + claim_txs.back().ops.push_back(op); + claim_txs.back().addrs.insert(b.owner); } } } - my->set_operation_fees( trx, my->_remote_db->get_global_properties().parameters.current_fees ); - trx.validate(); + vector< signed_transaction > result; - auto tx = sign_transaction( trx, false ); - - for( auto a : required_addrs ) - tx.sign( keys[a], my->_chain_id ); + for( const claim_tx& ctx : claim_txs ) + { + signed_transaction tx; + tx.operations.reserve( ctx.ops.size() ); + for( const balance_claim_operation& op : ctx.ops ) + tx.operations.emplace_back( op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees ); + tx.validate(); + signed_transaction signed_tx = sign_transaction( tx, false ); + for( const address& addr : ctx.addrs ) + signed_tx.sign( keys[addr], _chain_id ); + // if the key for a balance object was the same as a key for the account we're importing it into, + // we may end up with duplicate signatures, so remove those + boost::erase(signed_tx.signatures, boost::unique(boost::sort(signed_tx.signatures))); + result.push_back( signed_tx ); + if( broadcast ) + _remote_net_broadcast->broadcast_transaction(signed_tx); + } - // if the key for a balance object was the same as a key for the account we're importing it into, - // we may end up with duplicate signatures, so remove those - boost::erase(tx.signatures, boost::unique(boost::sort(tx.signatures))); - - if( broadcast ) - my->_remote_net_broadcast->broadcast_transaction(tx); - - return tx; + return result; } FC_CAPTURE_AND_RETHROW( (name_or_id) ) } +} + map wallet_api::dump_private_keys() { FC_ASSERT(!is_locked());