wallet.cpp: Allow specifying wildcard in keys when running import_balance

Also, don't put private keys in error messages.
This commit is contained in:
theoreticalbts 2015-10-09 13:05:19 -04:00
parent f0f96d5a8f
commit e731941cf0
2 changed files with 88 additions and 34 deletions

View file

@ -575,10 +575,10 @@ class wallet_api
bool import_account_keys( string filename, string password, string src_account_name, string dest_account_name ); 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. * by wif_keys and deposit them into the given account.
*/ */
signed_transaction import_balance( string account_name_or_id, const vector<string>& wif_keys, bool broadcast ); vector< signed_transaction > import_balance( string account_name_or_id, const vector<string>& wif_keys, bool broadcast );
/** Transforms a brain key to reduce the chance of errors when re-entering the key from memory. /** Transforms a brain key to reduce the chance of errors when re-entering the key from memory.
* *

View file

@ -624,7 +624,7 @@ public:
{ {
fc::optional<fc::ecc::private_key> optional_private_key = wif_to_key(wif_key); fc::optional<fc::ecc::private_key> optional_private_key = wif_to_key(wif_key);
if (!optional_private_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(); graphene::chain::public_key_type wif_pub_key = optional_private_key->get_public_key();
account_object account = get_account( account_name_or_id ); 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(); 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<string>& wif_keys, bool broadcast );
bool load_wallet_file(string wallet_filename = "") bool load_wallet_file(string wallet_filename = "")
{ {
// TODO: Merge imported wallet with existing wallet, // 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 // backup wallet
fc::optional<fc::ecc::private_key> optional_private_key = wif_to_key(wif_key); fc::optional<fc::ecc::private_key> optional_private_key = wif_to_key(wif_key);
if (!optional_private_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()); string shorthash = detail::address_to_shorthash(optional_private_key->get_public_key());
copy_wallet_file( "before-import-key-" + shorthash ); copy_wallet_file( "before-import-key-" + shorthash );
@ -3119,65 +3121,117 @@ void wallet_api::set_password( string password )
lock(); lock();
} }
signed_transaction wallet_api::import_balance( string name_or_id, const vector<string>& wif_keys, bool broadcast ) vector< signed_transaction > wallet_api::import_balance( string name_or_id, const vector<string>& 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<string>& wif_keys, bool broadcast )
{ try { { try {
FC_ASSERT(!is_locked()); FC_ASSERT(!is_locked());
const dynamic_global_property_object& dpo = _remote_db->get_dynamic_global_properties();
account_object claimer = get_account( name_or_id ); account_object claimer = get_account( name_or_id );
uint32_t max_ops_per_tx = 30;
vector<address> addrs; map< address, private_key_type > keys; // local index of address -> private key
map<address,private_key_type> keys; vector< address > addrs;
for( auto wif_key : wif_keys ) bool has_wildcard = false;
addrs.reserve( wif_keys.size() );
for( const string& wif_key : wif_keys )
{ {
auto priv_key = wif_to_key(wif_key); if( wif_key == "*" )
FC_ASSERT( priv_key, "Invalid Private Key", ("key",wif_key) ); {
addrs.push_back( priv_key->get_public_key() ); if( has_wildcard )
keys[addrs.back()] = *priv_key; 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)); wdump((balances));
addrs.clear(); addrs.clear();
set<asset_id_type> bal_types; set<asset_id_type> bal_types;
for( auto b : balances ) bal_types.insert( b.balance.asset_id ); for( auto b : balances ) bal_types.insert( b.balance.asset_id );
set<address> required_addrs; struct claim_tx
signed_transaction trx; {
for( auto a : bal_types ) 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; balance_claim_operation op;
op.deposit_to_account = claimer.id; op.deposit_to_account = claimer.id;
for( const auto& b : balances ) for( const balance_object& b : balances )
{ {
if( b.balance.asset_id == a ) 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_to_claim = b.id;
op.balance_owner_key = keys[b.owner].get_public_key(); op.balance_owner_key = keys[b.owner].get_public_key();
trx.operations.push_back(op); if( (claim_txs.empty()) || (claim_txs.back().ops.size() >= max_ops_per_tx) )
required_addrs.insert(b.owner); 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 ); vector< signed_transaction > result;
trx.validate();
auto tx = sign_transaction( trx, false ); 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::return_found_end>(boost::sort(signed_tx.signatures)));
result.push_back( signed_tx );
if( broadcast )
_remote_net_broadcast->broadcast_transaction(signed_tx);
}
for( auto a : required_addrs ) return result;
tx.sign( keys[a], my->_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(tx.signatures, boost::unique<boost::return_found_end>(boost::sort(tx.signatures)));
if( broadcast )
my->_remote_net_broadcast->broadcast_transaction(tx);
return tx;
} FC_CAPTURE_AND_RETHROW( (name_or_id) ) } } FC_CAPTURE_AND_RETHROW( (name_or_id) ) }
}
map<public_key_type, string> wallet_api::dump_private_keys() map<public_key_type, string> wallet_api::dump_private_keys()
{ {
FC_ASSERT(!is_locked()); FC_ASSERT(!is_locked());