Merge branch 'master' of github.com:cryptonomex/graphene
This commit is contained in:
commit
31502d1959
5 changed files with 180 additions and 40 deletions
|
|
@ -520,8 +520,6 @@ void_result asset_publish_feeds_evaluator::do_evaluate(const asset_publish_feed_
|
|||
{
|
||||
FC_ASSERT(o.feed.settlement_price.quote.asset_id == bitasset.options.short_backing_asset);
|
||||
|
||||
bool is_nop = false;
|
||||
|
||||
try
|
||||
{
|
||||
// these two changes should go in price_feed::validate() when creating new network
|
||||
|
|
@ -559,7 +557,6 @@ void_result asset_publish_feeds_evaluator::do_evaluate(const asset_publish_feed_
|
|||
("n", d.head_block_num()+1)
|
||||
("name", o.publisher(d).name)
|
||||
);
|
||||
is_nop = true;
|
||||
}
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
|
|
|
|||
|
|
@ -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<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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -624,7 +624,7 @@ public:
|
|||
{
|
||||
fc::optional<fc::ecc::private_key> 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<string>& 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<fc::ecc::private_key> 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 );
|
||||
|
||||
|
|
@ -2626,14 +2628,28 @@ map<string, bool> wallet_api::import_accounts( string filename, string password
|
|||
|
||||
if( should_proceed )
|
||||
{
|
||||
uint32_t import_successes = 0;
|
||||
uint32_t import_failures = 0;
|
||||
// TODO: First check that all private keys match public keys
|
||||
for( const auto& encrypted_key : item.encrypted_private_keys )
|
||||
{
|
||||
const auto plain_text = fc::aes_decrypt( password_hash, encrypted_key );
|
||||
const auto private_key = fc::raw::unpack<private_key_type>( plain_text );
|
||||
try
|
||||
{
|
||||
const auto plain_text = fc::aes_decrypt( password_hash, encrypted_key );
|
||||
const auto private_key = fc::raw::unpack<private_key_type>( plain_text );
|
||||
|
||||
import_key( item.account_name, string( graphene::utilities::key_to_wif( private_key ) ) );
|
||||
import_key( item.account_name, string( graphene::utilities::key_to_wif( private_key ) ) );
|
||||
++import_successes;
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
elog( "Couldn't import key due to exception ${e}", ("e", e.to_detail_string()) );
|
||||
++import_failures;
|
||||
}
|
||||
}
|
||||
ilog( "successfully imported ${n} keys for account ${name}", ("n", import_successes)("name", item.account_name) );
|
||||
if( import_failures > 0 )
|
||||
elog( "failed to import ${n} keys for account ${name}", ("n", import_failures)("name", item.account_name) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3119,65 +3135,117 @@ void wallet_api::set_password( string password )
|
|||
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 {
|
||||
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<address> addrs;
|
||||
map<address,private_key_type> 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<asset_id_type> bal_types;
|
||||
for( auto b : balances ) bal_types.insert( b.balance.asset_id );
|
||||
|
||||
set<address> 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::return_found_end>(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::return_found_end>(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<public_key_type, string> wallet_api::dump_private_keys()
|
||||
{
|
||||
FC_ASSERT(!is_locked());
|
||||
|
|
|
|||
14
programs/genesis_util/python_format.py
Executable file
14
programs/genesis_util/python_format.py
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
print("syntax: "+sys.argv[0]+" INFILE OUTFILE")
|
||||
sys.exit(0)
|
||||
|
||||
with open(sys.argv[1], "r") as infile:
|
||||
genesis = json.load(infile)
|
||||
with open(sys.argv[2], "w") as outfile:
|
||||
json.dump(genesis, outfile, indent=2, sort_keys=True)
|
||||
61
programs/genesis_util/upgrade_members.py
Executable file
61
programs/genesis_util/upgrade_members.py
Executable file
|
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
def dump_json(obj, out, pretty):
|
||||
if pretty:
|
||||
json.dump(obj, out, indent=2, sort_keys=True)
|
||||
else:
|
||||
json.dump(obj, out, separators=(",", ":"), sort_keys=True)
|
||||
return
|
||||
|
||||
re_init = re.compile(r"^init[0-9]+$")
|
||||
|
||||
def load_names(infile):
|
||||
names = set()
|
||||
for line in infile:
|
||||
if '#' in line:
|
||||
line = line[:line.index('#')]
|
||||
line = line.strip()
|
||||
if line == "":
|
||||
continue
|
||||
names.add(line)
|
||||
return names
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Remove entities from snapshot")
|
||||
parser.add_argument("-o", "--output", metavar="OUT", default="-", help="output filename (default: stdout)")
|
||||
parser.add_argument("-i", "--input", metavar="IN", default="-", help="input filename (default: stdin)")
|
||||
parser.add_argument("-n", "--names", metavar="NAMES", default="", help="file containing names to upgrade")
|
||||
parser.add_argument("-p", "--pretty", action="store_true", default=False, help="pretty print output")
|
||||
opts = parser.parse_args()
|
||||
|
||||
if opts.input == "-":
|
||||
genesis = json.load(sys.stdin)
|
||||
else:
|
||||
with open(opts.input, "r") as f:
|
||||
genesis = json.load(f)
|
||||
|
||||
if opts.names == "-":
|
||||
names = load_names(sys.stdin)
|
||||
else:
|
||||
with open(opts.names, "r") as f:
|
||||
names = load_names(f)
|
||||
|
||||
for account in genesis["initial_accounts"]:
|
||||
if account["name"] in names:
|
||||
account["is_lifetime_member"] = True
|
||||
|
||||
if opts.output == "-":
|
||||
dump_json( genesis, sys.stdout, opts.pretty )
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
with open(opts.output, "w") as f:
|
||||
dump_json( genesis, f, opts.pretty )
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in a new issue