diff --git a/libraries/api/wallet_api.json b/libraries/api/wallet_api.json index 1f0ce26a2..20e8370be 100644 --- a/libraries/api/wallet_api.json +++ b/libraries/api/wallet_api.json @@ -672,7 +672,7 @@ { "method_name" : "wallet_account_register", "description" : "Updates the data published about a given account", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "account_name", @@ -692,7 +692,7 @@ }, { "name" : "delegate_pay_rate", - "type" : "uint32_t", + "type" : "uint8_t", "description" : "A value between 0 and 100 for delegates, 255 for non delegates", "default_value" : 255 } @@ -723,7 +723,7 @@ { "method_name" : "wallet_account_update_registration", "description" : "Updates the data published about a given account", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "account_name", @@ -754,7 +754,7 @@ { "method_name" : "wallet_account_update_active_key", "description" : "Updates the specified account's active key and broadcasts the transaction.", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "account_to_update", @@ -857,7 +857,7 @@ { "method_name" : "wallet_asset_create", "description" : "Creates a new user issued asset", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "symbol", @@ -910,7 +910,7 @@ { "method_name" : "wallet_asset_issue", "description" : "Issues new shares of a given asset type", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "amount", @@ -970,7 +970,7 @@ { "method_name" : "wallet_delegate_withdraw_pay", "description" : "Used to transfer some of the delegate's pay from their balance", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "delegate_name", @@ -1029,7 +1029,7 @@ { "method_name" : "wallet_market_submit_bid", "description" : "Used to place a request to buy a quantity of assets at a price specified in another asset", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "from_account_name", @@ -1069,7 +1069,7 @@ { "method_name" : "wallet_market_submit_ask", "description" : "Used to place a request to sell a quantity of assets at a price specified in another asset", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "from_account_name", @@ -1109,7 +1109,7 @@ { "method_name" : "wallet_market_submit_short", "description" : "Used to place a request to short sell a quantity of assets at a price specified", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "from_account_name", @@ -1144,7 +1144,7 @@ { "method_name" : "wallet_market_cover", "description" : "Used to place a request to cover an existing short position", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "from_account_name", @@ -1173,7 +1173,7 @@ { "method_name" : "wallet_market_cover2", "description" : "Used to place a request to cover an existing short position", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "from_account_name", @@ -1202,7 +1202,7 @@ { "method_name" : "wallet_market_add_collateral", "description" : "Add collateral to a short position", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "from_account_name", @@ -1226,7 +1226,7 @@ { "method_name" : "wallet_market_add_collateral2", "description" : "Add collateral to a short position", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "from_account_name", @@ -1312,7 +1312,7 @@ { "method_name" : "wallet_market_cancel_order", "description" : "Cancel an order", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "order_id", @@ -1326,7 +1326,7 @@ { "method_name" : "wallet_market_cancel_order2", "description" : "Cancel an order", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "order_id", @@ -1486,7 +1486,7 @@ { "method_name" : "wallet_publish_slate", "description" : "Publishes the current wallet delegate slate to the public data associated with the account", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "publishing_account_name", @@ -1570,7 +1570,7 @@ { "method_name" : "wallet_publish_price_feed", "description" : "publishes a price feed for BitAssets, only active delegates may do this", - "return_type" : "signed_transaction", + "return_type" : "transaction_record", "parameters" : [ { "name" : "delegate_account", diff --git a/libraries/blockchain/chain_database.cpp b/libraries/blockchain/chain_database.cpp index fe3bcabde..8484230d4 100644 --- a/libraries/blockchain/chain_database.cpp +++ b/libraries/blockchain/chain_database.cpp @@ -1036,12 +1036,18 @@ namespace bts { namespace blockchain { uint32_t last_block_num = -1; block_id_type last_block_id; my->_block_num_to_id_db.last( last_block_num, last_block_id ); - if( !must_rebuild_index && last_block_num != uint32_t(-1) ) - { - my->_head_block_header = get_block_digest( last_block_id ); - my->_head_block_id = last_block_id; + + try { + if( !must_rebuild_index && last_block_num != uint32_t(-1) ) + { + my->_head_block_header = get_block_digest( last_block_id ); + my->_head_block_id = last_block_id; + } + } catch (...) { + must_rebuild_index = true; } - else + + if( must_rebuild_index || last_block_num == uint32_t(-1) ) { close(); fc::remove_all( data_dir / "index" ); @@ -1055,10 +1061,8 @@ namespace bts { namespace blockchain { if( !reindex_status_callback ) std::cout << "Please be patient, this will take a few minutes...\r\nRe-indexing database..." << std::flush << std::fixed; - else { - std::cout << "Progress: 0" << std::endl; + else reindex_status_callback(0); - } uint32_t blocks_indexed = 0; const float total_blocks = num_to_id.size(); @@ -1077,10 +1081,8 @@ namespace bts { namespace blockchain { if( !reindex_status_callback ) std::cout << "\rRe-indexing database... " "Approximately " << std::setprecision(2) << progress << "% complete." << std::flush; - else { - std::cout << "progress: " << progress << std::endl; + else reindex_status_callback(progress); - } } push_block(block); @@ -2717,6 +2719,8 @@ namespace bts { namespace blockchain { record_itr.key().timestamp, fc::variant(string(record_itr.value().highest_bid.ratio * base->precision / quote->precision)).as_double() / (BTS_BLOCKCHAIN_MAX_SHARES*1000), fc::variant(string(record_itr.value().lowest_ask.ratio * base->precision / quote->precision)).as_double() / (BTS_BLOCKCHAIN_MAX_SHARES*1000), + fc::variant(string(record_itr.value().opening_price.ratio * base->precision / quote->precision)).as_double() / (BTS_BLOCKCHAIN_MAX_SHARES*1000), + fc::variant(string(record_itr.value().closing_price.ratio * base->precision / quote->precision)).as_double() / (BTS_BLOCKCHAIN_MAX_SHARES*1000), record_itr.value().volume, record_itr.value().recent_average_price? to_pretty_price_double(*record_itr.value().recent_average_price) : fc::optional() } ); diff --git a/libraries/blockchain/include/bts/blockchain/checkpoints.hpp b/libraries/blockchain/include/bts/blockchain/checkpoints.hpp index ddccd7f99..d4eb166cb 100644 --- a/libraries/blockchain/include/bts/blockchain/checkpoints.hpp +++ b/libraries/blockchain/include/bts/blockchain/checkpoints.hpp @@ -13,5 +13,6 @@ const static std::map CHECKPOINT_BLOCK {332000, bts::blockchain::block_id_type("2ab4e4de53568149de0a0a37f46fce05d861d43f")}, {341000, bts::blockchain::block_id_type("b77a53d3d3c8dfd1c03d04fb989606bc1a738166")}, {358310, bts::blockchain::block_id_type("4fb5498c0f1bce18740dca639389e307a194de2a")}, - {384100, bts::blockchain::block_id_type("9f2ffbebd7722b566547507028954fb81cc37271")} + {384100, bts::blockchain::block_id_type("9f2ffbebd7722b566547507028954fb81cc37271")}, + {398900, bts::blockchain::block_id_type("0260a868051d0e43316c165bc912cfb8444262ef")} }; diff --git a/libraries/blockchain/include/bts/blockchain/config.hpp b/libraries/blockchain/include/bts/blockchain/config.hpp index beae1dba9..345f03d38 100644 --- a/libraries/blockchain/include/bts/blockchain/config.hpp +++ b/libraries/blockchain/include/bts/blockchain/config.hpp @@ -3,7 +3,7 @@ #include /* Define client version here */ -#define BTS_CLIENT_VERSION "0.4.11" +#define BTS_CLIENT_VERSION "0.4.12" /* Comment out this line for a non-test network */ //#define BTS_TEST_NETWORK @@ -13,7 +13,7 @@ * @brief Defines global constants that determine blockchain behavior */ #define BTS_BLOCKCHAIN_VERSION 109 -#define BTS_BLOCKCHAIN_DATABASE_VERSION 133 +#define BTS_BLOCKCHAIN_DATABASE_VERSION 134 /** * The address prepended to string representation of @@ -29,6 +29,7 @@ #define BTS_BLOCKCHAIN_MAX_TRANSACTION_EXPIRATION_SEC (60*60*24*2) #define BTS_BLOCKCHAIN_DEFAULT_RELAY_FEE 10000 // XTS +#define BTS_BLOCKCHAIN_MINIMUM_SHORT_ORDER_SIZE (BTS_BLOCKCHAIN_PRECISION*100) /** * The number of delegates that the blockchain is designed to support diff --git a/libraries/blockchain/include/bts/blockchain/fork_blocks.hpp b/libraries/blockchain/include/bts/blockchain/fork_blocks.hpp index 385368556..52d5400f3 100644 --- a/libraries/blockchain/include/bts/blockchain/fork_blocks.hpp +++ b/libraries/blockchain/include/bts/blockchain/fork_blocks.hpp @@ -9,4 +9,4 @@ #define BTSX_MARKET_FORK_2_BLOCK_NUM 316001 #define BTSX_MARKET_FORK_3_BLOCK_NUM 340000 #define BTSX_MARKET_FORK_4_BLOCK_NUM 357000 -#define BTSX_MARKET_FORK_5_BLOCK_NUM 407500 +#define BTSX_MARKET_FORK_5_BLOCK_NUM 408750 diff --git a/libraries/blockchain/include/bts/blockchain/market_records.hpp b/libraries/blockchain/include/bts/blockchain/market_records.hpp index 165771fb8..d2e9c3340 100644 --- a/libraries/blockchain/include/bts/blockchain/market_records.hpp +++ b/libraries/blockchain/include/bts/blockchain/market_records.hpp @@ -71,16 +71,22 @@ namespace bts { namespace blockchain { { market_history_record(price highest_bid = price(), price lowest_ask = price(), + price opening_price = price(), + price closing_price = price(), share_type volume = 0, fc::optional recent_average_price = fc::optional()) : highest_bid(highest_bid), lowest_ask(lowest_ask), + opening_price(opening_price), + closing_price(closing_price), volume(volume), recent_average_price(recent_average_price) {} price highest_bid; price lowest_ask; + price opening_price; + price closing_price; share_type volume; fc::optional recent_average_price; @@ -99,6 +105,8 @@ namespace bts { namespace blockchain { fc::time_point_sec timestamp; double highest_bid; double lowest_ask; + double opening_price; + double closing_price; share_type volume; fc::optional recent_average_price; @@ -244,9 +252,9 @@ FC_REFLECT_ENUM( bts::blockchain::market_history_key::time_granularity_enum, (ea FC_REFLECT( bts::blockchain::market_status, (quote_id)(base_id)(bid_depth)(ask_depth)(avg_price_1h)(last_error) ) FC_REFLECT_DERIVED( bts::blockchain::api_market_status, (bts::blockchain::market_status), (avg_price_1h) ) FC_REFLECT( bts::blockchain::market_index_key, (order_price)(owner) ) -FC_REFLECT( bts::blockchain::market_history_record, (highest_bid)(lowest_ask)(volume)(recent_average_price) ) +FC_REFLECT( bts::blockchain::market_history_record, (highest_bid)(lowest_ask)(opening_price)(closing_price)(volume)(recent_average_price) ) FC_REFLECT( bts::blockchain::market_history_key, (quote_id)(base_id)(granularity)(timestamp) ) -FC_REFLECT( bts::blockchain::market_history_point, (timestamp)(highest_bid)(lowest_ask)(volume)(recent_average_price) ) +FC_REFLECT( bts::blockchain::market_history_point, (timestamp)(highest_bid)(lowest_ask)(opening_price)(closing_price)(volume)(recent_average_price) ) FC_REFLECT( bts::blockchain::order_record, (balance) ) FC_REFLECT( bts::blockchain::collateral_record, (collateral_balance)(payoff_balance) ) FC_REFLECT( bts::blockchain::market_order, (type)(market_index)(state)(collateral) ) diff --git a/libraries/blockchain/market_engine.cpp b/libraries/blockchain/market_engine.cpp index 33969f355..95798cf3f 100644 --- a/libraries/blockchain/market_engine.cpp +++ b/libraries/blockchain/market_engine.cpp @@ -52,6 +52,8 @@ class market_engine price max_short_bid; price min_cover_ask; + price opening_price; + price closing_price; // while bootstraping we use this metric auto median_price = _db_impl.self->get_median_delegate_price( quote_id ); @@ -118,6 +120,9 @@ class market_engine trading_volume += mtrx.ask_received; else if( mtrx.bid_received.asset_id == 0 ) trading_volume += mtrx.bid_received; + if( opening_price == price() ) + opening_price = mtrx.bid_price; + closing_price = mtrx.bid_price; if( mtrx.ask_type == ask_order ) pay_current_ask( mtrx, *base_asset ); @@ -198,6 +203,17 @@ class market_engine _current_bid.reset(); continue; } + /** + * Don't allow shorts to be executed if they are too far over priced or they will be + * immediately under collateralized. + */ + if( mtrx.bid_price < market_stat->minimum_ask() ) + { + //wlog( "skipping short ${x} < max_short_bid ${b}", ("x",mtrx.bid_price)("b", max_short_bid) ); + // TODO: cancel the short order... + _current_ask.reset(); + continue; + } } else { @@ -209,7 +225,6 @@ class market_engine continue; } } - mtrx.ask_price = mtrx.bid_price; // we want to sell enough XTS to cover our balance. @@ -264,6 +279,22 @@ class market_engine if( mtrx.ask_price < mtrx.bid_price ) break; // the call price has not been reached + if( pending_block_num >= BTSX_MARKET_FORK_5_BLOCK_NUM ) + { + /** + * Don't allow margin calls to be executed too far below + * the minimum ask, this could lead to an attack where someone + * walks the whole book to steal the collateral. + */ + if( mtrx.bid_price < market_stat->minimum_ask() ) + { + //wlog( "skipping short ${x} < max_short_bid ${b}", ("x",mtrx.bid_price)("b", max_short_bid) ); + // TODO: cancel the short order... + _current_ask.reset(); + continue; + } + } + mtrx.ask_price = mtrx.bid_price; if( pending_block_num < BTSX_MARKET_FORK_4_BLOCK_NUM ) @@ -407,6 +438,9 @@ class market_engine trading_volume += mtrx.ask_received; else if( mtrx.bid_received.asset_id == 0 ) trading_volume += mtrx.bid_received; + if( opening_price == price() ) + opening_price = mtrx.bid_price; + closing_price = mtrx.bid_price; accumulate_fees( mtrx, *quote_asset ); } // while( next bid && next ask ) @@ -514,7 +548,7 @@ class market_engine } _pending_state->store_market_status( *market_stat ); - update_market_history( trading_volume, market_stat, timestamp ); + update_market_history( trading_volume, opening_price, closing_price, market_stat, timestamp ); wlog( "done matching orders" ); _pending_state->apply_changes(); @@ -843,15 +877,23 @@ class market_engine /** - * This method should not effect market execution or validation and + * This method should not affect market execution or validation and * is for historical purposes only. */ - void update_market_history( const asset& trading_volume, const omarket_status& market_stat, const fc::time_point_sec& timestamp ) + void update_market_history( const asset& trading_volume, + const price& opening_price, + const price& closing_price, + const omarket_status& market_stat, + const fc::time_point_sec& timestamp ) { if( trading_volume.amount > 0 && get_next_bid() && get_next_ask() ) { market_history_key key(_quote_id, _base_id, market_history_key::each_block, _db_impl._head_block_header.timestamp); - market_history_record new_record(_current_bid->get_price(), _current_ask->get_price(), trading_volume.amount); + market_history_record new_record(_current_bid->get_price(), + _current_ask->get_price(), + opening_price, + closing_price, + trading_volume.amount); FC_ASSERT( market_stat ); new_record.recent_average_price = market_stat->avg_price_1h; diff --git a/libraries/blockchain/market_operations.cpp b/libraries/blockchain/market_operations.cpp index 4a0cac369..f3c3aad55 100644 --- a/libraries/blockchain/market_operations.cpp +++ b/libraries/blockchain/market_operations.cpp @@ -145,7 +145,6 @@ namespace bts { namespace blockchain { FC_ASSERT( asset_to_short->is_market_issued(), "${symbol} is not a market issued asset", ("symbol",asset_to_short->symbol) ); - auto current_short = eval_state._current_state->get_short_record( this->short_index ); //if( current_short ) wdump( (current_short) ); @@ -163,6 +162,7 @@ namespace bts { namespace blockchain { } else // this->amount > 0 - deposit { + FC_ASSERT( this->amount >= (BTS_BLOCKCHAIN_MINIMUM_SHORT_ORDER_SIZE) ); // 100 XTS min short order if( NOT current_short ) // then initialize to 0 current_short = order_record(); // sub the delta amount from the eval state that we deposited to the short diff --git a/libraries/blockchain/original_market_engine.cpp b/libraries/blockchain/original_market_engine.cpp index 22406b432..20c8a9c8a 100644 --- a/libraries/blockchain/original_market_engine.cpp +++ b/libraries/blockchain/original_market_engine.cpp @@ -244,7 +244,7 @@ if( trading_volume.amount > 0 && get_next_bid() && get_next_ask() ) { market_history_key key(quote_id, base_id, market_history_key::each_block, _db_impl._head_block_header.timestamp); - market_history_record new_record(_current_bid->get_price(), _current_ask->get_price(), trading_volume.amount); + market_history_record new_record(_current_bid->get_price(), _current_ask->get_price(), price(), price(), trading_volume.amount); //LevelDB iterators are dumb and don't support proper past-the-end semantics. auto last_key_itr = _db_impl._market_history_db.lower_bound(key); if( !last_key_itr.valid() ) diff --git a/libraries/cli/cli.cpp b/libraries/cli/cli.cpp index 5de9e1f2c..0c5bb4a0e 100644 --- a/libraries/cli/cli.cpp +++ b/libraries/cli/cli.cpp @@ -681,8 +681,26 @@ namespace bts { namespace cli { const auto& balances = result.as(); *_out << pretty_balances( balances, _client ); } - else if( method_name == "wallet_transfer" - || method_name == "wallet_get_transaction" ) + else if( + method_name == "wallet_transfer" + || method_name == "wallet_transfer_from" + || method_name == "wallet_get_transaction" + || method_name == "wallet_account_register" + || method_name == "wallet_account_update_registration" + || method_name == "wallet_account_update_active_key" + || method_name == "wallet_asset_create" + || method_name == "wallet_asset_issue" + || method_name == "wallet_delegate_withdraw_pay" + || method_name == "wallet_market_submit_bid" + || method_name == "wallet_market_submit_ask" + || method_name == "wallet_market_submit_short" + || method_name == "wallet_market_cover" + || method_name == "wallet_market_add_collateral" + || method_name == "wallet_market_cancel_order" + || method_name == "wallet_publish_slate" + || method_name == "wallet_recover_transaction" + || method_name == "wallet_publish_price_feed" + ) { const auto& record = result.as(); const auto& pretty = _client->get_wallet()->to_pretty_trx( record ); @@ -944,7 +962,7 @@ namespace bts { namespace cli { oprice median_price = _client->get_chain()->get_median_delegate_price( quote_id ); auto status = _client->get_chain()->get_market_status( quote_id, base_id ); auto max_short_price = median_price ? *median_price : ( status ? status->avg_price_1h : price(0, quote_id, base_id) ); - + while( bid_itr != bids_asks.first.end() || ask_itr != bids_asks.second.end() ) { @@ -956,10 +974,10 @@ namespace bts { namespace cli { { if( bid_itr->get_price() > *median_price ) filtered_shorts.push_back(*bid_itr++); - else + else break; } - else + else break; } } @@ -1162,15 +1180,19 @@ namespace bts { namespace cli { *_out << std::setw(20) << "TIME" << std::setw(20) << "HIGHEST BID" << std::setw(20) << "LOWEST ASK" + << std::setw(20) << "OPENING PRICE" + << std::setw(20) << "CLOSING PRICE" << std::setw(20) << "TRADING VOLUME" << std::setw(20) << "AVERAGE PRICE" - << "\n" << std::string(100,'-') << "\n"; + << "\n" << std::string(140,'-') << "\n"; for( auto point : points ) { *_out << std::setw(20) << pretty_timestamp(point.timestamp) << std::setw(20) << point.highest_bid << std::setw(20) << point.lowest_ask + << std::setw(20) << point.opening_price + << std::setw(20) << point.closing_price << std::setw(20) << _client->get_chain()->to_pretty_asset(asset(point.volume)); if(point.recent_average_price) *_out << std::setw(20) << *point.recent_average_price; diff --git a/libraries/client/client.cpp b/libraries/client/client.cpp index 22e2dc06d..a441f1ae3 100644 --- a/libraries/client/client.cpp +++ b/libraries/client/client.cpp @@ -1241,7 +1241,7 @@ config load_config( const fc::path& datadir ) // assume anything longer than our limit is an attacker (limit is currently ~26 items) if (blockchain_synopsis.size() > _blockchain_synopsis_size_limit) - FC_THROW("Peer provided unreasonably long blockchain synopsis during sync (actual length: ${size}, limit: ${blockchain_synopsis_size_limit})", + FC_THROW("Peer provided unreasonably long blockchain synopsis during sync (actual length: ${size}, limit: ${blockchain_synopsis_size_limit})", ("size", blockchain_synopsis.size()) ("blockchain_synopsis_size_limit", _blockchain_synopsis_size_limit)); @@ -1309,7 +1309,7 @@ config load_config( const fc::path& datadir ) ulog("Error: your chain database is in an inconsistent state. Please shut down and relaunch using --rebuild-index or --resync-blockchain to repair the database"); assert(!"I assume this can never happen"); // our database doesn't make sense, so just act as if we have no blocks so the remote node doesn't try to sync with us - remaining_item_count = 0; + remaining_item_count = 0; hashes_to_return.clear(); return hashes_to_return; } @@ -1831,12 +1831,12 @@ config load_config( const fc::path& datadir ) return errors; } - signed_transaction detail::client_impl::wallet_publish_slate( const string& publishing_account_name, const string& paying_account_name ) + wallet_transaction_record detail::client_impl::wallet_publish_slate( const string& publishing_account_name, + const string& paying_account_name ) { - auto trx = _wallet->publish_slate( publishing_account_name, paying_account_name ); - network_broadcast_transaction( trx ); - - return trx; + const auto record = _wallet->publish_slate( publishing_account_name, paying_account_name ); + network_broadcast_transaction( record.trx ); + return record; } int32_t detail::client_impl::wallet_recover_accounts( int32_t accounts_to_recover, int32_t maximum_number_of_attempts ) @@ -1862,20 +1862,11 @@ config load_config( const fc::path& datadir ) const string& from_account_name, const string& to_account_name, const string& memo_message, - const vote_selection_method& selection_method - ) + const vote_selection_method& selection_method ) { - const auto record = _wallet->transfer_asset( - amount_to_transfer, - asset_symbol, - from_account_name, - from_account_name, - to_account_name, - memo_message, - selection_method, - true - ); - + const auto record = _wallet->transfer_asset( amount_to_transfer, asset_symbol, + from_account_name, from_account_name, to_account_name, + memo_message, selection_method ); network_broadcast_transaction( record.trx ); return record; } @@ -1887,51 +1878,40 @@ config load_config( const fc::path& datadir ) const string& from_account_name, const string& to_account_name, const string& memo_message, - const vote_selection_method& selection_method - ) + const vote_selection_method& selection_method ) { - const auto record = _wallet->transfer_asset( - amount_to_transfer, - asset_symbol, - paying_account_name, - from_account_name, - to_account_name, - memo_message, - selection_method, - true - ); - + const auto record = _wallet->transfer_asset( amount_to_transfer, asset_symbol, + paying_account_name, from_account_name, to_account_name, + memo_message, selection_method ); network_broadcast_transaction( record.trx ); return record; } - bts::blockchain::signed_transaction detail::client_impl::wallet_asset_create(const string& symbol, - const string& asset_name, - const string& issuer_name, - const string& description, - const variant& data, - double maximum_share_supply , - int64_t precision, - bool is_market_issued /* = false */) + wallet_transaction_record detail::client_impl::wallet_asset_create( + const string& symbol, + const string& asset_name, + const string& issuer_name, + const string& description, + const variant& data, + double maximum_share_supply , + int64_t precision, + bool is_market_issued /* = false */ ) { - generate_transaction_flag flag = sign_and_broadcast; - bool sign = flag != do_not_sign; - auto create_asset_trx = - _wallet->create_asset(symbol, asset_name, description, data, issuer_name, maximum_share_supply, precision, is_market_issued, sign); - if (flag == sign_and_broadcast) - network_broadcast_transaction(create_asset_trx); - return create_asset_trx; + const auto record = _wallet->create_asset( symbol, asset_name, description, data, issuer_name, + maximum_share_supply, precision, is_market_issued ); + network_broadcast_transaction( record.trx ); + return record; } - signed_transaction detail::client_impl::wallet_asset_issue(double real_amount, - const string& symbol, - const string& to_account_name, - const string& memo_message - ) + wallet_transaction_record detail::client_impl::wallet_asset_issue( + double real_amount, + const string& symbol, + const string& to_account_name, + const string& memo_message ) { - const auto issue_asset_trx = _wallet->issue_asset(real_amount,symbol,to_account_name, memo_message, true); - network_broadcast_transaction(issue_asset_trx); - return issue_asset_trx; + const auto record = _wallet->issue_asset( real_amount, symbol, to_account_name, memo_message ); + network_broadcast_transaction( record.trx ); + return record; } vector detail::client_impl::wallet_list() const @@ -2595,7 +2575,7 @@ config load_config( const fc::path& datadir ) fc::optional growl_password; if (option_variables.count("growl-password")) growl_password = option_variables["growl-password"].as(); - else + else growl_password = my->_config.growl_password; std::string bts_instance_identifier = "BitShares"; @@ -2707,16 +2687,16 @@ config load_config( const fc::path& datadir ) /* static */ fc::ip::endpoint client::string_to_endpoint(const std::string& remote_endpoint) { - try + try { ASSERT_TASK_NOT_PREEMPTED(); // make sure no cancel gets swallowed by catch(...) // first, try and parse the endpoint as a numeric_ipv4_address:port that doesn't need DNS lookup return fc::ip::endpoint::from_string(remote_endpoint.c_str()); - } - catch (...) + } + catch (...) { string::size_type colon_pos = remote_endpoint.find(':'); - try + try { uint16_t port = boost::lexical_cast( remote_endpoint.substr( colon_pos + 1, remote_endpoint.size() ) ); @@ -2724,13 +2704,13 @@ config load_config( const fc::path& datadir ) std::vector endpoints = fc::resolve(hostname, port); if ( endpoints.empty() ) FC_THROW_EXCEPTION(fc::unknown_host_exception, "The host name can not be resolved: ${hostname}", ("hostname", hostname)); - return endpoints.back(); + return endpoints.back(); } catch (const boost::bad_lexical_cast&) { FC_THROW("Bad port: ${port}", ("port", remote_endpoint.substr( colon_pos + 1, remote_endpoint.size() ))); } - } + } } void client::add_node( const string& remote_endpoint ) @@ -2742,7 +2722,7 @@ config load_config( const fc::path& datadir ) } catch (const fc::exception& e) { - ulog("Unable to add peer ${remote_endpoint}: ${error}", + ulog("Unable to add peer ${remote_endpoint}: ${error}", ("remote_endpoint", remote_endpoint)("error", e.to_string())); return; } @@ -2765,7 +2745,7 @@ config load_config( const fc::path& datadir ) } catch (const fc::exception& e) { - ulog("Unable to initiate connection to peer ${remote_endpoint}: ${error}", + ulog("Unable to initiate connection to peer ${remote_endpoint}: ${error}", ("remote_endpoint", remote_endpoint)("error", e.to_string())); return; } @@ -3098,15 +3078,14 @@ config load_config( const fc::path& datadir ) return state; } - signed_transaction client_impl::wallet_account_register( const string& account_name, - const string& pay_with_account, - const fc::variant& data, - uint32_t delegate_pay_rate ) + wallet_transaction_record client_impl::wallet_account_register( const string& account_name, + const string& pay_with_account, + const fc::variant& data, + uint8_t delegate_pay_rate ) { try { - FC_ASSERT( delegate_pay_rate <= 255 ); - const auto trx = _wallet->register_account(account_name, data, delegate_pay_rate, pay_with_account); - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->register_account( account_name, data, delegate_pay_rate, pay_with_account ); + network_broadcast_transaction( record.trx ); + return record; } FC_RETHROW_EXCEPTIONS(warn, "", ("account_name", account_name)("data", data)) } variant_object client_impl::wallet_get_info() @@ -3120,28 +3099,24 @@ config load_config( const fc::path& datadir ) _wallet->update_account_private_data(account_to_update, private_data); } - signed_transaction client_impl::wallet_account_update_registration( const string& account_to_update, - const string& pay_from_account, - const variant& public_data, - uint8_t delegate_pay_rate ) + wallet_transaction_record client_impl::wallet_account_update_registration( + const string& account_to_update, + const string& pay_from_account, + const variant& public_data, + uint8_t delegate_pay_rate ) { - const auto trx = _wallet->update_registered_account( account_to_update, - pay_from_account, - public_data, - delegate_pay_rate, - true ); - - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->update_registered_account( account_to_update, pay_from_account, public_data, delegate_pay_rate ); + network_broadcast_transaction( record.trx ); + return record; } - signed_transaction detail::client_impl::wallet_account_update_active_key( const std::string& account_to_update, - const std::string& pay_from_account, - const std::string& new_active_key ) + wallet_transaction_record detail::client_impl::wallet_account_update_active_key( const std::string& account_to_update, + const std::string& pay_from_account, + const std::string& new_active_key ) { - const auto trx = _wallet->update_active_key(account_to_update, pay_from_account, new_active_key); - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->update_active_key( account_to_update, pay_from_account, new_active_key ); + network_broadcast_transaction( record.trx ); + return record; } fc::variant_object client_impl::network_get_info() const @@ -3196,10 +3171,13 @@ config load_config( const fc::path& datadir ) return _wallet->get_account_balances( account_name ); } - signed_transaction client_impl::wallet_market_submit_bid( const string& from_account, - double quantity, const string& quantity_symbol, - double quote_price, const string& quote_symbol, - bool allow_stupid_bid ) + wallet_transaction_record client_impl::wallet_market_submit_bid( + const string& from_account, + double quantity, + const string& quantity_symbol, + double quote_price, + const string& quote_symbol, + bool allow_stupid_bid ) { vector lowest_ask = blockchain_market_order_book(quote_symbol, quantity_symbol, 1).second; @@ -3209,17 +3187,18 @@ config load_config( const fc::path& datadir ) "This bid is based on economically unsound principles, and is ill-advised. " "If you're sure you want to do this, place your bid again and set allow_stupid_bid to true."); - auto trx = _wallet->submit_bid( from_account, quantity, quantity_symbol, - quote_price, quote_symbol, true ); - - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->submit_bid( from_account, quantity, quantity_symbol, quote_price, quote_symbol ); + network_broadcast_transaction( record.trx ); + return record; } - signed_transaction client_impl::wallet_market_submit_ask( const string& from_account, - double quantity, const string& quantity_symbol, - double quote_price, const string& quote_symbol, - bool allow_stupid_ask ) + wallet_transaction_record client_impl::wallet_market_submit_ask( + const string& from_account, + double quantity, + const string& quantity_symbol, + double quote_price, + const string& quote_symbol, + bool allow_stupid_ask ) { vector highest_bid = blockchain_market_order_book(quote_symbol, quantity_symbol, 1).first; @@ -3229,17 +3208,17 @@ config load_config( const fc::path& datadir ) "This ask is based on economically unsound principles, and is ill-advised. " "If you're sure you want to do this, place your ask again and set allow_stupid_ask to true."); - auto trx = _wallet->submit_ask( from_account, quantity, quantity_symbol, - quote_price, quote_symbol, true ); - - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->submit_ask( from_account, quantity, quantity_symbol, quote_price, quote_symbol ); + network_broadcast_transaction( record.trx ); + return record; } - signed_transaction client_impl::wallet_market_submit_short( const string& from_account, - double quantity, - double quote_price, const string& quote_symbol, - bool allow_stupid_short ) + wallet_transaction_record client_impl::wallet_market_submit_short( + const string& from_account, + double quantity, + double quote_price, + const string& quote_symbol, + bool allow_stupid_short ) { vector lowest_ask = blockchain_market_order_book(quote_symbol, _chain_db->get_asset_symbol(0), 1).second; @@ -3249,43 +3228,41 @@ config load_config( const fc::path& datadir ) "This short is based on economically unsound principles, and is ill-advised. " "If you're sure you want to do this, place your short again and set allow_stupid_short to true."); - auto trx = _wallet->submit_short( from_account, quantity, quote_price, quote_symbol, true ); - - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->submit_short( from_account, quantity, quote_price, quote_symbol ); + network_broadcast_transaction( record.trx ); + return record; } - signed_transaction client_impl::wallet_market_cover( const string& from_account, - double quantity, - const string& quantity_symbol, - const address& order_id ) + wallet_transaction_record client_impl::wallet_market_cover( + const string& from_account, + double quantity, + const string& quantity_symbol, + const address& order_id ) { - auto trx = _wallet->cover_short( from_account, quantity, quantity_symbol, order_id, true ); - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->cover_short( from_account, quantity, quantity_symbol, order_id ); + network_broadcast_transaction( record.trx ); + return record; } - signed_transaction client_impl::wallet_market_cover2( const string& from_account, - double quantity, - const string& quantity_symbol, - const order_id_type& short_id ) + wallet_transaction_record client_impl::wallet_market_cover2( + const string& from_account, + double quantity, + const string& quantity_symbol, + const order_id_type& short_id ) { - const auto trx = _wallet->cover_short2( from_account, quantity, quantity_symbol, short_id, true ); - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->cover_short2( from_account, quantity, quantity_symbol, short_id ); + network_broadcast_transaction( record.trx ); + return record; } - signed_transaction client_impl::wallet_delegate_withdraw_pay( const string& delegate_name, - const string& to_account_name, - double amount_to_withdraw, - const string& memo_message ) + wallet_transaction_record client_impl::wallet_delegate_withdraw_pay( const string& delegate_name, + const string& to_account_name, + double amount_to_withdraw, + const string& memo_message ) { - auto trx = _wallet->withdraw_delegate_pay( delegate_name, - amount_to_withdraw, - to_account_name, - memo_message, true ); - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->withdraw_delegate_pay( delegate_name, amount_to_withdraw, to_account_name, memo_message ); + network_broadcast_transaction( record.trx ); + return record; } asset client_impl::wallet_set_transaction_fee( double fee ) @@ -3376,11 +3353,11 @@ config load_config( const fc::path& datadir ) return std::make_pair(bids, asks); } - std::vector client_impl::blockchain_market_order_history(const std::string "e_symbol, - const std::string &base_symbol, - uint32_t skip_count, - uint32_t limit, - const string& owner) const + std::vector client_impl::blockchain_market_order_history( const std::string "e_symbol, + const std::string &base_symbol, + uint32_t skip_count, + uint32_t limit, + const string& owner )const { auto quote_id = _chain_db->get_asset_id(quote_symbol); auto base_id = _chain_db->get_asset_id(base_symbol); @@ -3393,35 +3370,35 @@ config load_config( const fc::path& datadir ) const std::string& base_symbol, const fc::time_point& start_time, const fc::microseconds& duration, - const market_history_key::time_granularity_enum& granularity ) const + const market_history_key::time_granularity_enum& granularity )const { return _chain_db->get_market_price_history( _chain_db->get_asset_id(quote_symbol), _chain_db->get_asset_id(base_symbol), start_time, duration, granularity ); } - signed_transaction client_impl::wallet_market_add_collateral(const std::string &from_account_name, - const address &short_id, - const share_type &collateral_to_add) + wallet_transaction_record client_impl::wallet_market_add_collateral( const std::string &from_account_name, + const address &short_id, + const share_type &collateral_to_add ) { - auto trx = _wallet->add_collateral(from_account_name, short_id, collateral_to_add); - network_broadcast_transaction(trx); - return trx; + const auto record = _wallet->add_collateral( from_account_name, short_id, collateral_to_add ); + network_broadcast_transaction( record.trx ); + return record; } - signed_transaction client_impl::wallet_market_add_collateral2(const std::string &from_account_name, - const order_id_type &short_id, - const share_type &collateral_to_add) + wallet_transaction_record client_impl::wallet_market_add_collateral2( const std::string &from_account_name, + const order_id_type &short_id, + const share_type &collateral_to_add ) { - const auto trx = _wallet->add_collateral2( from_account_name, short_id, collateral_to_add ); - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->add_collateral2( from_account_name, short_id, collateral_to_add ); + network_broadcast_transaction( record.trx ); + return record; } vector client_impl::wallet_market_order_list( const string& quote_symbol, const string& base_symbol, int64_t limit, - const string& account_name ) + const string& account_name ) { return _wallet->get_market_orders( quote_symbol, base_symbol, limit, account_name ); } @@ -3429,23 +3406,23 @@ config load_config( const fc::path& datadir ) map client_impl::wallet_market_order_list2( const string& quote_symbol, const string& base_symbol, int64_t limit, - const string& account_name ) + const string& account_name ) { return _wallet->get_market_orders2( quote_symbol, base_symbol, limit, account_name ); } - signed_transaction client_impl::wallet_market_cancel_order( const address& order_address ) + wallet_transaction_record client_impl::wallet_market_cancel_order( const address& order_address ) { - auto trx = _wallet->cancel_market_order( order_address ); - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->cancel_market_order( order_address ); + network_broadcast_transaction( record.trx ); + return record; } - signed_transaction client_impl::wallet_market_cancel_order2( const order_id_type& order_id ) + wallet_transaction_record client_impl::wallet_market_cancel_order2( const order_id_type& order_id ) { - const auto trx = _wallet->cancel_market_order2( order_id ); - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->cancel_market_order2( order_id ); + network_broadcast_transaction( record.trx ); + return record; } account_vote_summary_type client_impl::wallet_account_vote_summary( const string& account_name )const @@ -3719,14 +3696,15 @@ config load_config( const fc::path& datadir ) return _chain_db->unclaimed_genesis(); } - bts::blockchain::signed_transaction client_impl::wallet_publish_price_feed( const std::string& delegate_account, - double real_amount_per_xts, - const std::string& real_amount_symbol ) + wallet_transaction_record client_impl::wallet_publish_price_feed( const std::string& delegate_account, + double real_amount_per_xts, + const std::string& real_amount_symbol ) { - auto trx = _wallet->publish_price( delegate_account, real_amount_per_xts, real_amount_symbol ); - network_broadcast_transaction( trx ); - return trx; + const auto record = _wallet->publish_price( delegate_account, real_amount_per_xts, real_amount_symbol ); + network_broadcast_transaction( record.trx ); + return record; } + int32_t client_impl::wallet_regenerate_keys( const std::string& account, uint32_t number_to_regenerate ) { return _wallet->regenerate_keys( account, number_to_regenerate ); diff --git a/libraries/net/include/bts/net/message_oriented_connection.hpp b/libraries/net/include/bts/net/message_oriented_connection.hpp index ea4d02c62..20057afc6 100644 --- a/libraries/net/include/bts/net/message_oriented_connection.hpp +++ b/libraries/net/include/bts/net/message_oriented_connection.hpp @@ -29,6 +29,7 @@ namespace bts { namespace net { void send_message(const message& message_to_send); void close_connection(); + void destroy_connection(); uint64_t get_total_bytes_sent() const; uint64_t get_total_bytes_received() const; diff --git a/libraries/net/message_oriented_connection.cpp b/libraries/net/message_oriented_connection.cpp index d85b48379..d71c139b1 100644 --- a/libraries/net/message_oriented_connection.cpp +++ b/libraries/net/message_oriented_connection.cpp @@ -57,6 +57,7 @@ namespace bts { namespace net { void send_message(const message& message_to_send); void close_connection(); + void destroy_connection(); uint64_t get_total_bytes_sent() const; uint64_t get_total_bytes_received() const; @@ -82,28 +83,7 @@ namespace bts { namespace net { message_oriented_connection_impl::~message_oriented_connection_impl() { VERIFY_CORRECT_THREAD(); - fc::optional remote_endpoint; - if (_sock.get_socket().is_open()) - remote_endpoint = _sock.get_socket().remote_endpoint(); - ilog( "in ~message_oriented_connection_impl() for ${endpoint}", ("endpoint", remote_endpoint) ); - - if (_send_message_in_progress) - elog("Error: message_oriented_connection is being destroyed while a send_message is in progress. " - "The task calling send_message() should have been canceled already"); - assert(!_send_message_in_progress); - - try - { - _read_loop_done.cancel_and_wait(__FUNCTION__); - } - catch ( const fc::exception& e ) - { - wlog( "Exception thrown while canceling message_oriented_connection's read_loop, ignoring: ${e}", ("e",e) ); - } - catch (...) - { - wlog( "Exception thrown while canceling message_oriented_connection's read_loop, ignoring" ); - } + destroy_connection(); } fc::tcp_socket& message_oriented_connection_impl::get_socket() @@ -261,6 +241,34 @@ namespace bts { namespace net { _sock.close(); } + void message_oriented_connection_impl::destroy_connection() + { + VERIFY_CORRECT_THREAD(); + + fc::optional remote_endpoint; + if (_sock.get_socket().is_open()) + remote_endpoint = _sock.get_socket().remote_endpoint(); + ilog( "in destroy_connection() for ${endpoint}", ("endpoint", remote_endpoint) ); + + if (_send_message_in_progress) + elog("Error: message_oriented_connection is being destroyed while a send_message is in progress. " + "The task calling send_message() should have been canceled already"); + assert(!_send_message_in_progress); + + try + { + _read_loop_done.cancel_and_wait(__FUNCTION__); + } + catch ( const fc::exception& e ) + { + wlog( "Exception thrown while canceling message_oriented_connection's read_loop, ignoring: ${e}", ("e",e) ); + } + catch (...) + { + wlog( "Exception thrown while canceling message_oriented_connection's read_loop, ignoring" ); + } + } + uint64_t message_oriented_connection_impl::get_total_bytes_sent() const { VERIFY_CORRECT_THREAD(); @@ -333,6 +341,11 @@ namespace bts { namespace net { my->close_connection(); } + void message_oriented_connection::destroy_connection() + { + my->destroy_connection(); + } + uint64_t message_oriented_connection::get_total_bytes_sent() const { return my->get_total_bytes_sent(); diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index 398cfb79d..cd3d09613 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -479,6 +479,8 @@ namespace bts { namespace net { namespace detail { std::set _allowed_peers; #endif // ENABLE_P2P_DEBUGGING_API + bool _node_is_shutting_down; // set to true when we begin our destructor, used to prevent us from starting new tasks while we're shutting down + node_impl(); virtual ~node_impl(); @@ -697,7 +699,8 @@ namespace bts { namespace net { namespace detail { _average_network_usage_minutes(60), _average_network_usage_hours(72), _average_network_usage_second_counter(0), - _average_network_usage_minute_counter(0) + _average_network_usage_minute_counter(0), + _node_is_shutting_down(false) { _rate_limiter.set_actual_rate_time_constant(fc::seconds(2)); } @@ -706,6 +709,8 @@ namespace bts { namespace net { namespace detail { { VERIFY_CORRECT_THREAD(); ilog( "cleaning up node" ); + _node_is_shutting_down = true; + for( const peer_connection_ptr& active_peer : _active_connections ) { potential_peer_record updated_peer_record = _potential_peer_db.lookup_or_create_entry_for_endpoint( *active_peer->get_remote_endpoint() ); @@ -1245,7 +1250,7 @@ namespace bts { namespace net { namespace detail { schedule_peer_for_deletion(peer); } - if( !_terminate_inactive_connections_loop_done.canceled() ) + if (!_node_is_shutting_down && !_terminate_inactive_connections_loop_done.canceled()) _terminate_inactive_connections_loop_done = fc::schedule( [this](){ terminate_inactive_connections_loop(); }, fc::time_point::now() + fc::seconds(BTS_NET_PEER_HANDSHAKE_INACTIVITY_TIMEOUT / 2), "terminate_inactive_connections_loop" ); @@ -1273,7 +1278,7 @@ namespace bts { namespace net { namespace detail { } } - if( !_fetch_updated_peer_lists_loop_done.canceled() ) + if (!_node_is_shutting_down && !_fetch_updated_peer_lists_loop_done.canceled() ) _fetch_updated_peer_lists_loop_done = fc::schedule( [this](){ fetch_updated_peer_lists_loop(); }, fc::time_point::now() + fc::minutes(15), "fetch_updated_peer_lists_loop" ); @@ -1313,7 +1318,7 @@ namespace bts { namespace net { namespace detail { update_bandwidth_data(usage_this_second); _bandwidth_monitor_last_update_time = current_time; - if (!_bandwidth_monitor_loop_done.canceled()) + if (!_node_is_shutting_down && !_bandwidth_monitor_loop_done.canceled()) _bandwidth_monitor_loop_done = fc::schedule( [=](){ bandwidth_monitor_loop(); }, fc::time_point::now() + fc::seconds(1), "bandwidth_monitor_loop" ); @@ -1323,7 +1328,7 @@ namespace bts { namespace net { namespace detail { { VERIFY_CORRECT_THREAD(); dump_node_status(); - if (!_dump_node_status_task_done.canceled()) + if (!_node_is_shutting_down && !_dump_node_status_task_done.canceled()) _dump_node_status_task_done = fc::schedule([=](){ dump_node_status_task(); }, fc::time_point::now() + fc::minutes(1), "dump_node_status_task"); @@ -1368,7 +1373,8 @@ namespace bts { namespace net { namespace detail { } dlog("peer scheduled for deletion: ${peer}", ("peer", peer_to_delete->get_remote_endpoint())); - if (!_delayed_peer_deletion_task_done.valid() || _delayed_peer_deletion_task_done.ready()) + if (!_node_is_shutting_down && + (!_delayed_peer_deletion_task_done.valid() || _delayed_peer_deletion_task_done.ready())) { dlog("asyncing delayed_peer_deletion_task to delete ${size} peers", ("size", number_of_peers_to_delete)); _delayed_peer_deletion_task_done = fc::async([this](){ delayed_peer_deletion_task(); }, "delayed_peer_deletion_task" ); @@ -1378,7 +1384,8 @@ namespace bts { namespace net { namespace detail { #else dlog("scheduling peer for deletion: ${peer} (this will not block)"); _peers_to_delete.push_back(peer_to_delete); - if (!_delayed_peer_deletion_task_done.valid() || _delayed_peer_deletion_task_done.ready()) + if (!_node_is_shutting_down && + (!_delayed_peer_deletion_task_done.valid() || _delayed_peer_deletion_task_done.ready())) { dlog("asyncing delayed_peer_deletion_task to delete ${size} peers", ("size", _peers_to_delete.size())); _delayed_peer_deletion_task_done = fc::async([this](){ delayed_peer_deletion_task(); }, "delayed_peer_deletion_task" ); @@ -2619,7 +2626,10 @@ namespace bts { namespace net { namespace detail { if (_suspend_fetching_sync_blocks) { dlog("we stopped processing the backlog because it was taking too long, rescheduling"); - _process_backlog_of_sync_blocks_done = fc::schedule([=](){ process_backlog_of_sync_blocks(); }, fc::time_point::now() + fc::milliseconds(400), "process_backlog_of_sync_blocks"); + if (!_node_is_shutting_down) + _process_backlog_of_sync_blocks_done = fc::schedule([=](){ process_backlog_of_sync_blocks(); }, + fc::time_point::now() + fc::milliseconds(400), + "process_backlog_of_sync_blocks"); } else trigger_fetch_sync_items_loop(); @@ -2627,7 +2637,8 @@ namespace bts { namespace net { namespace detail { void node_impl::trigger_process_backlog_of_sync_blocks() { - if (!_process_backlog_of_sync_blocks_done.valid() || _process_backlog_of_sync_blocks_done.ready()) + if (!_node_is_shutting_down && + (!_process_backlog_of_sync_blocks_done.valid() || _process_backlog_of_sync_blocks_done.ready())) _process_backlog_of_sync_blocks_done = fc::async([=](){ process_backlog_of_sync_blocks(); }, "process_backlog_of_sync_blocks"); } @@ -3149,6 +3160,8 @@ namespace bts { namespace net { namespace detail { { _tcp_server.accept( new_peer->get_socket() ); ilog( "accepted inbound connection from ${remote_endpoint}", ("remote_endpoint", new_peer->get_socket().remote_endpoint() ) ); + if (_node_is_shutting_down) + return; new_peer->connection_initiation_time = fc::time_point::now(); _handshaking_connections.insert( new_peer ); _rate_limiter.add_tcp_socket( &new_peer->get_socket() ); @@ -3482,6 +3495,10 @@ namespace bts { namespace net { namespace detail { new_peer->connection_initiation_time = fc::time_point::now(); _handshaking_connections.insert( new_peer ); _rate_limiter.add_tcp_socket( &new_peer->get_socket() ); + + if (_node_is_shutting_down) + return; + std::weak_ptr new_weak_peer(new_peer); new_peer->accept_or_connect_task_done = fc::async( [this, new_weak_peer, remote_endpoint](){ peer_connection_ptr new_peer(new_weak_peer.lock()); diff --git a/libraries/net/peer_connection.cpp b/libraries/net/peer_connection.cpp index f3c661cfd..ca96adccb 100644 --- a/libraries/net/peer_connection.cpp +++ b/libraries/net/peer_connection.cpp @@ -108,6 +108,8 @@ namespace bts { namespace net { wlog("Unexpected exception from peer_connection's accept_or_connect_task"); } + + _message_connection.destroy_connection(); // shut down the read loop } peer_connection::~peer_connection() diff --git a/libraries/wallet/include/bts/wallet/exceptions.hpp b/libraries/wallet/include/bts/wallet/exceptions.hpp index 49f4cc0fe..dbd7ef46f 100644 --- a/libraries/wallet/include/bts/wallet/exceptions.hpp +++ b/libraries/wallet/include/bts/wallet/exceptions.hpp @@ -41,6 +41,7 @@ namespace bts { namespace wallet { FC_DECLARE_DERIVED_EXCEPTION( stupid_order, bts::wallet::wallet_exception, 20034, "stupid order" ); FC_DECLARE_DERIVED_EXCEPTION( invalid_expiration_time, bts::wallet::wallet_exception, 20035, "invalid expiration time" ); FC_DECLARE_DERIVED_EXCEPTION( bad_collateral_amount, bts::wallet::wallet_exception, 20036, "bad collateral amount" ); + FC_DECLARE_DERIVED_EXCEPTION( unknown_slate, bts::wallet::wallet_exception, 20037, "unknown slate" ); // registered in wallet.cpp } } // bts::wallet diff --git a/libraries/wallet/include/bts/wallet/wallet.hpp b/libraries/wallet/include/bts/wallet/wallet.hpp index ad558bc25..9a487af90 100644 --- a/libraries/wallet/include/bts/wallet/wallet.hpp +++ b/libraries/wallet/include/bts/wallet/wallet.hpp @@ -164,12 +164,17 @@ namespace bts { namespace wallet { public_key_type create_account( const string& account_name, const variant& private_data = variant() ); + void update_account_private_data( const string& account_to_update, + const variant& private_data ); + void account_set_favorite ( const string& account_name, const bool is_favorite ); address get_new_address( const string& account_name ); public_key_type get_new_public_key( const string& account_name ); + wallet_account_record get_account( const string& account_name )const; + /** * A contact is an account for which we do not have the private key. */ @@ -198,8 +203,6 @@ namespace bts { namespace wallet { ///@param delegates_to_retrieve Type is delegate_status_flags. Uses int type to allow ORing multiple flags vector get_my_delegates( int delegates_to_retrieve = any_delegate_status )const; - ///@param delegates_to_retrieve Type is delegate_status_flags. Uses int type to allow ORing multiple flags - vector get_my_delegate_private_keys( int delegates_to_retrieve = any_delegate_status )const; optional get_next_producible_block_timestamp( const vector& delegate_records )const; @@ -276,167 +279,198 @@ namespace bts { namespace wallet { * and producing a single output. The only different aspect with transfer_asset is that * this will send to a address. */ - signed_transaction transfer_asset_to_address( double real_amount_to_transfer, - const string& amount_to_transfer_symbol, - const string& from_account_name, - const address& to_address, - const string& memo_message, - vote_selection_method selection_method, - bool sign ); + wallet_transaction_record transfer_asset_to_address( + double real_amount_to_transfer, + const string& amount_to_transfer_symbol, + const string& from_account_name, + const address& to_address, + const string& memo_message, + vote_selection_method selection_method, + bool sign = true + ); /** * This transfer works like a bitcoin sendmany transaction combining multiple inputs * and producing a single output. */ - signed_transaction transfer_asset_to_many_address( const string& amount_to_transfer_symbol, - const string& from_account_name, - const unordered_map< address, double >& to_address_amounts, - const string& memo_message, - bool sign ); + wallet_transaction_record transfer_asset_to_many_address( + const string& amount_to_transfer_symbol, + const string& from_account_name, + const unordered_map& to_address_amounts, + const string& memo_message, + bool sign = true + ); /** * This transfer works like a bitcoin transaction combining multiple inputs * and producing a single output. */ - wallet_transaction_record transfer_asset(double real_amount_to_transfer, - const string& amount_to_transfer_symbol, - const string& paying_account_name, - const string& from_account_name, - const string& to_account_name, - const string& memo_message, - vote_selection_method m, - bool sign ); - - signed_transaction withdraw_delegate_pay( const string& delegate_name, - double amount_to_withdraw, - const string& withdraw_to_account_name, - const string& memo_message, - bool sign ); - - signed_transaction create_asset( const string& symbol, - const string& asset_name, - const string& description, - const variant& data, - const string& issuer_name, - double max_share_supply, - int64_t precision, - bool is_market_issued = false, - bool sign = true ); - - signed_transaction issue_asset( double amount, - const string& symbol, - const string& to_account_name, - const string& memo_message, - bool sign = true ); - + wallet_transaction_record transfer_asset( + double real_amount_to_transfer, + const string& amount_to_transfer_symbol, + const string& paying_account_name, + const string& from_account_name, + const string& to_account_name, + const string& memo_message, + vote_selection_method m, + bool sign = true + ); + /** + * if the active_key is null then the active key will be made the same as the master key. + * if the name already exists then it will be updated if this wallet controls the active key + * or master key + */ + wallet_transaction_record register_account( + const string& account_name, + const variant& json_data, + uint8_t delegate_pay_rate, + const string& pay_with_account_name, + bool sign = true + ); + wallet_transaction_record update_registered_account( + const string& account_name, + const string& pay_from_account, + optional public_data, + uint8_t delegate_pay_rate = 255, + bool sign = true + ); + wallet_transaction_record update_active_key( + const std::string& account_to_update, + const std::string& pay_from_account, + const std::string& new_active_key, + bool sign = true + ); + wallet_transaction_record withdraw_delegate_pay( + const string& delegate_name, + double amount_to_withdraw, + const string& withdraw_to_account_name, + const string& memo_message, + bool sign = true + ); + wallet_transaction_record publish_slate( + const string& account, + string account_to_pay_with, + bool sign = true + ); + wallet_transaction_record publish_price( + const string& account, + double amount_per_xts, + const string& amount_asset_symbol, + bool sign = true + ); + wallet_transaction_record create_asset( + const string& symbol, + const string& asset_name, + const string& description, + const variant& data, + const string& issuer_name, + double max_share_supply, + int64_t precision, + bool is_market_issued = false, + bool sign = true + ); + wallet_transaction_record issue_asset( + double amount, + const string& symbol, + const string& to_account_name, + const string& memo_message, + bool sign = true + ); /** * ie: submit_bid( 10 BTC at 600.34 USD per BTC ) * * Requires the user have 6003.4 USD */ - signed_transaction submit_bid( const string& from_account_name, - double real_quantity, - const string& quantity_symbol, - double price_per_unit, - const string& quote_symbol, - bool sign = true ); - + wallet_transaction_record submit_bid( + const string& from_account_name, + double real_quantity, + const string& quantity_symbol, + double price_per_unit, + const string& quote_symbol, + bool sign = true + ); /** * ie: submit_ask( 10 BTC at 600.34 USD per BTC ) * * Requires the user have 10 BTC + fees */ - signed_transaction submit_ask( const string& from_account_name, - double real_quantity, - const string& quantity_symbol, - double price_per_unit, - const string& quote_symbol, - bool sign = true ); - + wallet_transaction_record submit_ask( + const string& from_account_name, + double real_quantity, + const string& quantity_symbol, + double price_per_unit, + const string& quote_symbol, + bool sign = true + ); /** * ie: submit_short( 10 USD at 600.34 USD per XTS ) * * Requires the user have 10 / 600.34 XTS + fees */ - signed_transaction submit_short( const string& from_account_name, - double real_quantity_usd, - double price_per_unit, - const string& quote_symbol, - bool sign = true ); - - signed_transaction cover_short( const string& from_account_name, - double real_quantity_usd, - const string& quote_symbol, - const address& owner_address, - bool sign = true ); - - signed_transaction add_collateral( const string& from_account_name, - const address& short_id, - share_type collateral_to_add, - bool sign = true ); - - signed_transaction cancel_market_order( const address& owner_address ); - + wallet_transaction_record submit_short( + const string& from_account_name, + double real_quantity_usd, + double price_per_unit, + const string& quote_symbol, + bool sign = true + ); + wallet_transaction_record cover_short( + const string& from_account_name, + double real_quantity_usd, + const string& quote_symbol, + const address& owner_address, + bool sign = true + ); + wallet_transaction_record add_collateral( + const string& from_account_name, + const address& short_id, + share_type collateral_to_add, + bool sign = true + ); + wallet_transaction_record cancel_market_order( + const address& owner_address, + bool sign = true + ); + /*************************/ /* New market order APIs */ - signed_transaction cover_short2( const string& from_account_name, - double real_quantity_usd, - const string& quote_symbol, - const order_id_type& short_id, - bool sign = true ); - - signed_transaction add_collateral2( const string& from_account_name, - const order_id_type& short_id, - share_type collateral_to_add, - bool sign = true ); - - signed_transaction cancel_market_order2( const order_id_type& order_id ); + wallet_transaction_record cover_short2( + const string& from_account_name, + double real_quantity_usd, + const string& quote_symbol, + const order_id_type& short_id, + bool sign = true + ); + wallet_transaction_record add_collateral2( + const string& from_account_name, + const order_id_type& short_id, + share_type collateral_to_add, + bool sign = true + ); + wallet_transaction_record cancel_market_order2( + const order_id_type& order_id, + bool sign = true + ); map get_market_orders2( const string& quote, const string& base, int32_t limit, const string& account_name )const; /*************************/ - - wallet_account_record get_account( const string& account_name )const; - - /** - * if the active_key is null then the active key will be made the same as the master key. - * if the name already exists then it will be updated if this wallet controls the active key - * or master key - */ - signed_transaction register_account( const string& account_name, - const variant& json_data, - uint8_t delegate_pay_rate, - const string& pay_with_account_name, - bool sign = true ); - - void update_account_private_data( const string& account_to_update, - const variant& private_data ); - - signed_transaction update_registered_account( const string& account_name, - const string& pay_from_account, - optional public_data, - uint8_t delegate_pay_rate = 255, - bool sign = true ); - - signed_transaction update_active_key( const std::string& account_to_update, - const std::string& pay_from_account, - const std::string& new_active_key, - bool sign = true ); - #if 0 - signed_transaction create_proposal( const string& delegate_account_name, - const string& subject, - const string& body, - const string& proposal_type, - const variant& data, - bool sign = true ); - - signed_transaction vote_proposal( const string& delegate_account_name, - proposal_id_type proposal_id, - proposal_vote::vote_type vote, - const string& message = string(), - bool sign = true); + wallet_transaction_record create_proposal( + const string& delegate_account_name, + const string& subject, + const string& body, + const string& proposal_type, + const variant& data, + bool sign = true + ); + wallet_transaction_record vote_proposal( + const string& delegate_account_name, + proposal_id_type proposal_id, + proposal_vote::vote_type vote, + const string& message = string(), + bool sign = tru + ); #endif - - ///@} Transaction Generation Methods + string get_key_label( const public_key_type& key )const; pretty_transaction to_pretty_trx( const wallet_transaction_record& trx_rec ) const; @@ -463,10 +497,6 @@ namespace bts { namespace wallet { const string& asset_symbol = "" )const; void remove_transaction_record( const string& record_id ); - signed_transaction publish_slate(const string& account, string account_to_pay_with, bool sign = true ); - signed_transaction publish_price( const string& account, - double amount_per_xts, - const string& amount_asset_symbol, bool sign = true ); uint32_t regenerate_keys( const string& account_name, uint32_t max_number_of_attempts ); int32_t recover_accounts(int32_t number_of_accounts , int32_t max_number_of_attempts); @@ -488,11 +518,8 @@ namespace bts { namespace wallet { */ /** signs transaction with the specified keys for the specified addresses */ - void sign_transaction( signed_transaction& trx, const unordered_set
& req_sigs ); - void sign_and_cache_transaction( - signed_transaction& transaction, - const std::unordered_set
& required_signatures, - wallet_transaction_record& record ); + void sign_transaction( signed_transaction& transaction, const unordered_set
& required_signatures )const; + void cache_transaction( const signed_transaction& transaction, wallet_transaction_record& record ); slate_id_type select_slate( signed_transaction& transaction, const asset_id_type& deposit_asset_id = asset_id_type( 0 ), vote_selection_method = vote_random ); diff --git a/libraries/wallet/include/bts/wallet/wallet_db.hpp b/libraries/wallet/include/bts/wallet/wallet_db.hpp index 055b035cb..514f86bba 100644 --- a/libraries/wallet/include/bts/wallet/wallet_db.hpp +++ b/libraries/wallet/include/bts/wallet/wallet_db.hpp @@ -11,8 +11,6 @@ namespace bts { namespace wallet { - typedef vector private_keys; - namespace detail { class wallet_db_impl; } class wallet_db @@ -28,11 +26,11 @@ namespace bts { namespace wallet { int32_t new_wallet_record_index(); int32_t new_key_child_index( const address& parent_account_address ); - fc::ecc::private_key get_private_key( const fc::sha512& password, int index ); + private_key_type get_private_key( const fc::sha512& password, int index ); - fc::ecc::private_key new_private_key( const fc::sha512& password, - const address& parent_account_address = address(), - bool store_key = true ); + private_key_type new_private_key( const fc::sha512& password, + const address& parent_account_address = address(), + bool store_key = true ); void set_property( property_enum property_id, const fc::variant& v ); fc::variant get_property( property_enum property_id )const; @@ -42,7 +40,7 @@ namespace bts { namespace wallet { void cache_balance( const bts::blockchain::balance_record& b ); void cache_account( const wallet_account_record& ); void cache_memo( const memo_status& memo, - const fc::ecc::private_key& account_key, + const private_key_type& account_key, const fc::sha512& password ); void cache_order( const bts::blockchain::market_order& ); @@ -57,8 +55,8 @@ namespace bts { namespace wallet { owallet_transaction_record lookup_transaction( const transaction_id_type& record_id )const; - private_keys get_account_private_keys( const fc::sha512& password )const; - string get_account_name( const address& account_address )const; + vector get_account_private_keys( const fc::sha512& password )const; + string get_account_name( const address& account_address )const; owallet_account_record lookup_account( const address& address_of_public_key )const; owallet_account_record lookup_account( const string& account_name )const; diff --git a/libraries/wallet/include/bts/wallet/wallet_records.hpp b/libraries/wallet/include/bts/wallet/wallet_records.hpp index bc59f8f4f..56845a4e0 100644 --- a/libraries/wallet/include/bts/wallet/wallet_records.hpp +++ b/libraries/wallet/include/bts/wallet/wallet_records.hpp @@ -134,8 +134,8 @@ namespace bts { namespace wallet { address get_address()const { return address( public_key ); } bool has_private_key()const; void encrypt_private_key( const fc::sha512& password, - const fc::ecc::private_key& ); - fc::ecc::private_key decrypt_private_key( const fc::sha512& password )const; + const private_key_type& ); + private_key_type decrypt_private_key( const fc::sha512& password )const; }; struct ledger_entry diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 57669621c..a820b7c45 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -50,7 +50,6 @@ namespace bts { namespace wallet { fc::sha512 _wallet_password; fc::optional _scheduled_lock_time; fc::future _relocker_done; - bool _use_deterministic_one_time_keys = true; fc::future _scan_in_progress; std::unique_ptr _scanner_thread; @@ -58,7 +57,7 @@ namespace bts { namespace wallet { struct login_record { - fc::ecc::private_key key; + private_key_type key; fc::time_point_sec insertion_time; }; std::map _login_map; @@ -76,7 +75,7 @@ namespace bts { namespace wallet { void relocker(); public: - fc::ecc::private_key create_one_time_key(); + private_key_type create_one_time_key(); /** * This method is called anytime the blockchain state changes including @@ -107,7 +106,7 @@ namespace bts { namespace wallet { bool scan_withdraw( const withdraw_operation& op, wallet_transaction_record& trx_rec, asset& total_fee ); bool scan_withdraw_pay( const withdraw_pay_operation& op, wallet_transaction_record& trx_rec, asset& total_fee ); - bool scan_deposit( const deposit_operation& op, const private_keys& keys, wallet_transaction_record& trx_rec, asset& total_fee ); + bool scan_deposit( const deposit_operation& op, const vector& keys, wallet_transaction_record& trx_rec, asset& total_fee ); bool scan_register_account( const register_account_operation& op, wallet_transaction_record& trx_rec ); bool scan_update_account( const update_account_operation& op, wallet_transaction_record& trx_rec ); @@ -149,12 +148,9 @@ namespace bts { namespace wallet { try { if( _scanner_thread ) _scanner_thread->quit(); } catch( ... ) {} } - fc::ecc::private_key wallet_impl::create_one_time_key() + private_key_type wallet_impl::create_one_time_key() { - if( !_use_deterministic_one_time_keys ) - return fc::ecc::private_key::generate(); - - return _wallet_db.new_private_key( _wallet_password ); + return _wallet_db.new_private_key( _wallet_password ); } void wallet_impl::state_changed( const pending_chain_state_ptr& state ) @@ -173,6 +169,7 @@ namespace bts { namespace wallet { if( !self->is_open() || !self->is_unlocked() ) return; if( !self->get_transaction_scanning() ) return; if( summary.block_data.block_num <= self->get_last_scanned_block_number() ) return; + if( _scan_in_progress.valid() && !_scan_in_progress.ready() ) return; self->scan_chain( self->get_last_scanned_block_number(), summary.block_data.block_num ); } @@ -528,7 +525,7 @@ namespace bts { namespace wallet { return fc::ripemd160::hash( enc.result() ); } - void wallet_impl::scan_block( uint32_t block_num, const private_keys& keys, const time_point_sec& received_time ) + void wallet_impl::scan_block( uint32_t block_num, const vector& keys, const time_point_sec& received_time ) { const auto block = _blockchain->get_block( block_num ); for( const auto& transaction : block.user_transactions ) @@ -1169,7 +1166,7 @@ namespace bts { namespace wallet { } FC_CAPTURE_AND_RETHROW( (op) ) } // TODO: optimize - bool wallet_impl::scan_deposit( const deposit_operation& op, const private_keys& keys, + bool wallet_impl::scan_deposit( const deposit_operation& op, const vector& keys, wallet_transaction_record& trx_rec, asset& total_fee ) { try { auto amount = asset( op.amount, op.condition.asset_id ); @@ -1934,11 +1931,12 @@ namespace bts { namespace wallet { /* Scan blocks we have missed while locked */ const uint32_t first = get_last_scanned_block_number(); - scan_chain( first, - my->_blockchain->get_head_block_num(), - [first](uint32_t current, uint32_t end){ - std::cout << " Scanning for new transactions in block: " << current-first << '/' << end-first << "\r" << std::flush; - }); + if( first < my->_blockchain->get_head_block_num() ) + scan_chain( first, + my->_blockchain->get_head_block_num(), + [first](uint32_t current, uint32_t end){ + std::cout << " Scanning for new transactions in block: " << current-first << '/' << end-first << "\r" << std::flush; + }); std::cout << "Finished scanning for new transactions. " << std::endl; } catch( ... ) @@ -2442,47 +2440,43 @@ namespace bts { namespace wallet { return transactions; } FC_RETHROW_EXCEPTIONS( warn, "" ) } - void wallet::sign_transaction( signed_transaction& trx, const std::unordered_set
& req_sigs ) + void wallet::sign_transaction( signed_transaction& transaction, const unordered_set
& required_signatures )const { try { - trx.expiration = blockchain::now() + get_transaction_expiration(); + transaction.expiration = blockchain::now() + get_transaction_expiration(); const auto chain_id = my->_blockchain->chain_id(); - for( const auto& addr : req_sigs ) trx.sign( get_private_key( addr ), chain_id ); - } FC_RETHROW_EXCEPTIONS( warn, "", ("trx",trx)("req_sigs",req_sigs) ) } - - void wallet::sign_and_cache_transaction( - signed_transaction& transaction, - const std::unordered_set
& required_signatures, - wallet_transaction_record& record - ) + for( const auto& addr : required_signatures ) + transaction.sign( get_private_key( addr ), chain_id ); + } FC_RETHROW_EXCEPTIONS( warn, "" ) } + + void wallet::cache_transaction( const signed_transaction& transaction, wallet_transaction_record& record ) { try { - sign_transaction( transaction, required_signatures ); - my->_blockchain->store_pending_transaction( transaction, true ); + my->_blockchain->store_pending_transaction( transaction, true ); - record.record_id = transaction.id(); - record.trx = transaction; - record.created_time = blockchain::now(); - record.received_time = record.created_time; - my->_wallet_db.store_transaction( record ); + record.record_id = transaction.id(); + record.trx = transaction; + record.created_time = blockchain::now(); + record.received_time = record.created_time; + my->_wallet_db.store_transaction( record ); - for( const auto& op : transaction.operations ) - { - if( operation_type_enum( op.type ) == withdraw_op_type ) - my->sync_balance_with_blockchain( op.as().balance_id ); - } + for( const auto& op : transaction.operations ) + { + if( operation_type_enum( op.type ) == withdraw_op_type ) + my->sync_balance_with_blockchain( op.as().balance_id ); + } } FC_RETHROW_EXCEPTIONS( warn, "" ) } slate_id_type wallet::select_slate( signed_transaction& transaction, const asset_id_type& deposit_asset_id, vote_selection_method selection_method ) { - auto slate_id = slate_id_type( 0 ); - if( deposit_asset_id != asset_id_type( 0 ) ) return slate_id; + auto slate_id = slate_id_type( 0 ); + if( deposit_asset_id != asset_id_type( 0 ) ) return slate_id; - const auto slate = select_delegate_vote( selection_method ); - slate_id = slate.id(); + const auto slate = select_delegate_vote( selection_method ); + slate_id = slate.id(); - if( slate_id != slate_id_type( 0 ) && !my->_blockchain->get_delegate_slate( slate_id ).valid() ) - transaction.define_delegate_slate( slate ); + if( slate_id != slate_id_type( 0 ) && !my->_blockchain->get_delegate_slate( slate_id ).valid() ) + transaction.define_delegate_slate( slate ); - return slate_id; + return slate_id; } private_key_type wallet::get_private_key( const address& addr )const @@ -2505,7 +2499,7 @@ namespace bts { namespace wallet { FC_ASSERT( key.valid() ); FC_ASSERT( key->has_private_key() ); - fc::ecc::private_key one_time_key = fc::ecc::private_key::generate(); + private_key_type one_time_key = private_key_type::generate(); public_key_type one_time_public_key = one_time_key.get_public_key(); my->_login_map[one_time_public_key] = {one_time_key, fc::time_point::now()}; @@ -2530,7 +2524,7 @@ namespace bts { namespace wallet { FC_ASSERT( is_unlocked() ); FC_ASSERT( my->_login_map.find(server_key) != my->_login_map.end(), "Login session has expired. Generate a new login URL and try again." ); - fc::ecc::private_key private_key = my->_login_map[server_key].key; + private_key_type private_key = my->_login_map[server_key].key; my->_login_map.erase(server_key); auto secret = private_key.get_shared_secret( fc::ecc::public_key_data(client_key) ); auto user_account_key = fc::ecc::public_key(client_signature, fc::sha256::hash(secret.data(), sizeof(secret))); @@ -2804,15 +2798,6 @@ namespace bts { namespace wallet { return delegate_records; } - vector wallet::get_my_delegate_private_keys(int delegates_to_retrieve )const - { - vector private_keys; - const auto& delegate_records = get_my_delegates( delegates_to_retrieve ); - for( const auto& delegate_record : delegate_records ) - private_keys.push_back( get_private_key( address( delegate_record.active_key() ) ) ); - return private_keys; - } - optional wallet::get_next_producible_block_timestamp( const vector& delegate_records )const { try { if( !is_open() || is_locked() ) return optional(); @@ -2845,9 +2830,11 @@ namespace bts { namespace wallet { FC_ASSERT( header.validate_signee( delegate_pub_key ) ); } FC_RETHROW_EXCEPTIONS( warn, "", ("header",header) ) } - signed_transaction wallet::publish_price( const string& account_to_publish_under, - double amount_per_xts, - const string& amount_asset_symbol, bool sign ) + wallet_transaction_record wallet::publish_price( + const string& account_to_publish_under, + double amount_per_xts, + const string& amount_asset_symbol, + bool sign ) { try { FC_ASSERT( is_open() ); FC_ASSERT( is_unlocked() ); @@ -2901,25 +2888,26 @@ namespace bts { namespace wallet { trx, required_signatures ); } required_signatures.insert( current_account->active_key() ); - if (sign) - { - auto entry = ledger_entry(); - entry.from_account = payer_public_key; - entry.to_account = payer_public_key; - entry.memo = "publish price " + my->_blockchain->to_pretty_price( quote_price_shares ); - auto record = wallet_transaction_record(); - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto entry = ledger_entry(); + entry.from_account = payer_public_key; + entry.to_account = payer_public_key; + entry.memo = "publish price " + my->_blockchain->to_pretty_price( quote_price_shares ); - sign_and_cache_transaction( trx, required_signatures, record ); - my->_blockchain->store_pending_transaction( trx ); - } - return trx; + auto record = wallet_transaction_record(); + record.ledger_entries.push_back( entry ); + record.fee = required_fees; + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_CAPTURE_AND_RETHROW( (account_to_publish_under)(amount_per_xts)(amount_asset_symbol)(sign) ) } - signed_transaction wallet::publish_slate( const string& account_to_publish_under, string account_to_pay_with, bool sign ) + wallet_transaction_record wallet::publish_slate( + const string& account_to_publish_under, + string account_to_pay_with, + bool sign ) { try { FC_ASSERT( is_open() ); FC_ASSERT( is_unlocked() ); @@ -2969,21 +2957,20 @@ namespace bts { namespace wallet { trx, required_signatures ); } - if (sign) - { - auto entry = ledger_entry(); - entry.from_account = payer_public_key; - entry.to_account = payer_public_key; - entry.memo = "publish slate " + fc::variant(slate_id).as_string(); - auto record = wallet_transaction_record(); - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto entry = ledger_entry(); + entry.from_account = payer_public_key; + entry.to_account = payer_public_key; + entry.memo = "publish slate " + fc::variant(slate_id).as_string(); - sign_and_cache_transaction( trx, required_signatures, record ); - my->_blockchain->store_pending_transaction( trx ); - } - return trx; + auto record = wallet_transaction_record(); + record.ledger_entries.push_back( entry ); + record.fee = required_fees; + + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_CAPTURE_AND_RETHROW( (account_to_publish_under) ) } uint32_t wallet::regenerate_keys( const string& account_name, uint32_t count ) @@ -3045,7 +3032,7 @@ namespace bts { namespace wallet { while( recoveries < number_of_accounts && attempts++ < max_number_of_attempts ) { - fc::ecc::private_key new_priv_key = my->_wallet_db.new_private_key( my->_wallet_password, address(), false ); + private_key_type new_priv_key = my->_wallet_db.new_private_key( my->_wallet_password, address(), false ); fc::ecc::public_key new_pub_key = new_priv_key.get_public_key(); auto recovered_account = my->_blockchain->get_account_record(new_pub_key); @@ -3103,7 +3090,7 @@ namespace bts { namespace wallet { const auto withdraw_condition = deposit_op.condition.as(); FC_ASSERT( withdraw_condition.memo.valid() ); - fc::ecc::private_key private_key; + private_key_type private_key; try { /* We had to have stored the one-time key */ @@ -3158,12 +3145,12 @@ namespace bts { namespace wallet { my->_wallet_db.store_transaction( transaction_record ); /* Wipe memory */ - private_key = fc::ecc::private_key(); + private_key = private_key_type(); } catch( ... ) { /* Wipe memory */ - private_key = fc::ecc::private_key(); + private_key = private_key_type(); throw; } @@ -3385,11 +3372,12 @@ namespace bts { namespace wallet { ("to_account_name",to_account_name) ("memo_message",memo_message) ) } - signed_transaction wallet::withdraw_delegate_pay( const string& delegate_name, - double real_amount_to_withdraw, - const string& withdraw_to_account_name, - const string& memo_message, - bool sign ) + wallet_transaction_record wallet::withdraw_delegate_pay( + const string& delegate_name, + double real_amount_to_withdraw, + const string& withdraw_to_account_name, + const string& memo_message, + bool sign ) { try { FC_ASSERT( is_open() ); FC_ASSERT( is_unlocked() ); @@ -3430,31 +3418,31 @@ namespace bts { namespace wallet { from_memo ); - if( sign ) - { - auto entry = ledger_entry(); - entry.from_account = delegate_private_key.get_public_key(); - entry.to_account = receiver_public_key; - entry.amount = asset( amount_to_withdraw ); - entry.memo = memo_message; + auto entry = ledger_entry(); + entry.from_account = delegate_private_key.get_public_key(); + entry.to_account = receiver_public_key; + entry.amount = asset( amount_to_withdraw ); + entry.memo = memo_message; - auto record = wallet_transaction_record(); - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.ledger_entries.push_back( entry ); + record.fee = required_fees; - sign_and_cache_transaction( trx, required_signatures, record ); - } - return trx; + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_RETHROW_EXCEPTIONS( warn, "", ("delegate_name",delegate_name) ("amount_to_withdraw",real_amount_to_withdraw ) ) } - signed_transaction wallet::transfer_asset_to_address( double real_amount_to_transfer, - const string& amount_to_transfer_symbol, - const string& from_account_name, - const address& to_address, - const string& memo_message, - vote_selection_method selection_method, - bool sign ) + wallet_transaction_record wallet::transfer_asset_to_address( + double real_amount_to_transfer, + const string& amount_to_transfer_symbol, + const string& from_account_name, + const address& to_address, + const string& memo_message, + vote_selection_method selection_method, + bool sign ) { try { FC_ASSERT( is_open() ); FC_ASSERT( is_unlocked() ); @@ -3501,19 +3489,20 @@ namespace bts { namespace wallet { trx.deposit( to_address, asset_to_transfer, slate_id); - if( sign ) - { - auto entry = ledger_entry(); - entry.from_account = sender_public_key; - entry.amount = asset_to_transfer; - entry.memo = memo_message; + auto entry = ledger_entry(); + entry.from_account = sender_public_key; + entry.amount = asset_to_transfer; + entry.memo = memo_message; - auto record = wallet_transaction_record(); - record.ledger_entries.push_back( entry ); - record.fee = required_fees; - record.extra_addresses.push_back( to_address ); - } - return trx; + auto record = wallet_transaction_record(); + record.ledger_entries.push_back( entry ); + record.fee = required_fees; + record.extra_addresses.push_back( to_address ); + + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_RETHROW_EXCEPTIONS( warn, "", ("real_amount_to_transfer",real_amount_to_transfer) ("amount_to_transfer_symbol",amount_to_transfer_symbol) @@ -3521,11 +3510,12 @@ namespace bts { namespace wallet { ("to_address",to_address) ("memo_message",memo_message) ) } - signed_transaction wallet::transfer_asset_to_many_address( const string& amount_to_transfer_symbol, - const string& from_account_name, - const std::unordered_map< address, double >& to_address_amounts, - const string& memo_message, - bool sign ) + wallet_transaction_record wallet::transfer_asset_to_many_address( + const string& amount_to_transfer_symbol, + const string& from_account_name, + const std::unordered_map& to_address_amounts, + const string& memo_message, + bool sign ) { try { FC_ASSERT( is_open() ); @@ -3572,21 +3562,20 @@ namespace bts { namespace wallet { trx, required_signatures ); - if( sign ) - { - auto entry = ledger_entry(); - entry.from_account = sender_public_key; - entry.amount = total_asset_to_transfer; - entry.memo = memo_message; + auto entry = ledger_entry(); + entry.from_account = sender_public_key; + entry.amount = total_asset_to_transfer; + entry.memo = memo_message; + + auto record = wallet_transaction_record(); + record.ledger_entries.push_back( entry ); + record.fee = required_fees; + record.extra_addresses = to_addresses; - auto record = wallet_transaction_record(); - record.ledger_entries.push_back( entry ); - record.fee = required_fees; - record.extra_addresses = to_addresses; + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); - sign_and_cache_transaction( trx, required_signatures, record ); - } - return trx; + return record; } FC_RETHROW_EXCEPTIONS( warn, "", ("amount_to_transfer_symbol",amount_to_transfer_symbol) ("from_account_name",from_account_name) @@ -3601,8 +3590,7 @@ namespace bts { namespace wallet { const string& to_account_name, const string& memo_message, vote_selection_method selection_method, - bool sign - ) + bool sign ) { try { FC_ASSERT( is_open() ); FC_ASSERT( is_unlocked() ); @@ -3682,24 +3670,21 @@ namespace bts { namespace wallet { from_memo ); - /* TODO: Fix this when we don't sign and broadcast transactions without user confirmation */ - //if( sign ) - //{ - auto entry = ledger_entry(); - entry.from_account = payer_public_key; - entry.to_account = receiver_public_key; - entry.amount = asset_to_transfer; - entry.memo = memo_message; - if( payer_public_key != sender_public_key ) - entry.memo_from_account = sender_public_key; + auto entry = ledger_entry(); + entry.from_account = payer_public_key; + entry.to_account = receiver_public_key; + entry.amount = asset_to_transfer; + entry.memo = memo_message; + if( payer_public_key != sender_public_key ) + entry.memo_from_account = sender_public_key; - auto record = wallet_transaction_record(); - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.ledger_entries.push_back( entry ); + record.fee = required_fees; + + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); - sign_and_cache_transaction( trx, required_signatures, record ); - //} - //return trx; return record; } FC_CAPTURE_AND_RETHROW( (real_amount_to_transfer) (amount_to_transfer_symbol) @@ -3708,11 +3693,12 @@ namespace bts { namespace wallet { (to_account_name) (memo_message ) ) } - signed_transaction wallet::register_account( const string& account_to_register, - const variant& public_data, - uint8_t delegate_pay_rate, - const string& pay_with_account_name, - bool sign ) + wallet_transaction_record wallet::register_account( + const string& account_to_register, + const variant& public_data, + uint8_t delegate_pay_rate, + const string& pay_with_account_name, + bool sign ) { try { if( !is_valid_account_name( account_to_register ) ) FC_THROW_EXCEPTION( invalid_name, "Invalid account name!", ("account_to_register",account_to_register) ); @@ -3764,36 +3750,35 @@ namespace bts { namespace wallet { trx, required_signatures ); - if( sign ) - { - auto entry = ledger_entry(); - entry.from_account = payer_public_key; - entry.to_account = account_public_key; - entry.memo = "register " + account_to_register + (as_delegate ? " as a delegate" : ""); + auto entry = ledger_entry(); + entry.from_account = payer_public_key; + entry.to_account = account_public_key; + entry.memo = "register " + account_to_register + (as_delegate ? " as a delegate" : ""); - auto record = wallet_transaction_record(); - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.ledger_entries.push_back( entry ); + record.fee = required_fees; - sign_and_cache_transaction( trx, required_signatures, record ); - } - return trx; + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_RETHROW_EXCEPTIONS( warn, "", ("account_to_register",account_to_register) ("public_data", public_data) ("pay_with_account_name", pay_with_account_name) ("delegate_pay_rate",int(delegate_pay_rate)) ) } - signed_transaction wallet::create_asset( const string& symbol, - const string& asset_name, - const string& description, - const variant& data, - const string& issuer_account_name, - double max_share_supply, - int64_t precision, - bool is_market_issued, - bool sign ) + wallet_transaction_record wallet::create_asset( + const string& symbol, + const string& asset_name, + const string& description, + const variant& data, + const string& issuer_account_name, + double max_share_supply, + int64_t precision, + bool is_market_issued, + bool sign ) { try { - FC_ASSERT( create_asset_operation::is_power_of_ten( precision ) ); FC_ASSERT( is_open() ); FC_ASSERT( is_unlocked() ); @@ -3835,31 +3820,31 @@ namespace bts { namespace wallet { asset_record::market_issued_asset, max_share_supply_in_internal_units, precision ); } - if( sign ) - { - auto entry = ledger_entry(); - entry.from_account = from_account_address; - entry.to_account = from_account_address; - entry.memo = "create " + symbol + " (" + asset_name + ")"; + auto entry = ledger_entry(); + entry.from_account = from_account_address; + entry.to_account = from_account_address; + entry.memo = "create " + symbol + " (" + asset_name + ")"; - auto record = wallet_transaction_record(); - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.ledger_entries.push_back( entry ); + record.fee = required_fees; - sign_and_cache_transaction( trx, required_signatures, record ); - } - return trx; + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_RETHROW_EXCEPTIONS( warn, "", ("symbol",symbol) ("name", asset_name ) ("description", description) ( "issuer_account", issuer_account_name) ) } - signed_transaction wallet::issue_asset( double amount_to_issue, - const string& symbol, - const string& to_account_name, - const string& memo_message, - bool sign ) - { + wallet_transaction_record wallet::issue_asset( + double amount_to_issue, + const string& symbol, + const string& to_account_name, + const string& memo_message, + bool sign ) + { try { if( !is_valid_account_name( to_account_name ) ) FC_THROW_EXCEPTION( invalid_name, "Invalid account name!", ("to_account_name",to_account_name) ); @@ -3903,22 +3888,21 @@ namespace bts { namespace wallet { from_memo ); - if( sign ) - { - auto entry = ledger_entry(); - entry.from_account = issuer->active_key(); - entry.to_account = receiver_public_key; - entry.amount = shares_to_issue; - entry.memo = "issue " + my->_blockchain->to_pretty_asset( shares_to_issue ); + auto entry = ledger_entry(); + entry.from_account = issuer->active_key(); + entry.to_account = receiver_public_key; + entry.amount = shares_to_issue; + entry.memo = "issue " + my->_blockchain->to_pretty_asset( shares_to_issue ); - auto record = wallet_transaction_record(); - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.ledger_entries.push_back( entry ); + record.fee = required_fees; - sign_and_cache_transaction( trx, required_signatures, record ); - } - return trx; - } + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; + } FC_RETHROW_EXCEPTIONS( warn, "" ) } void wallet::update_account_private_data( const string& account_to_update, const variant& private_data ) @@ -3930,11 +3914,12 @@ namespace bts { namespace wallet { my->_wallet_db.cache_account( *oacct ); } - signed_transaction wallet::update_registered_account( const string& account_to_update, - const string& pay_from_account, - optional public_data, - uint8_t delegate_pay_rate, - bool sign ) + wallet_transaction_record wallet::update_registered_account( + const string& account_to_update, + const string& pay_from_account, + optional public_data, + uint8_t delegate_pay_rate, + bool sign ) { try { if( !is_valid_account_name( account_to_update ) ) FC_THROW_EXCEPTION( invalid_name, "Invalid account name!", ("account_to_update",account_to_update) ); @@ -3978,29 +3963,29 @@ namespace bts { namespace wallet { trx.update_account( account->id, delegate_pay_rate, public_data, optional() ); - if (sign) - { - auto entry = ledger_entry(); - entry.from_account = payer_public_key; - entry.to_account = account_public_key; - entry.memo = "update " + account_to_update; // TODO: Note if upgrading to delegate + auto entry = ledger_entry(); + entry.from_account = payer_public_key; + entry.to_account = account_public_key; + entry.memo = "update " + account_to_update; // TODO: Note if upgrading to delegate - auto record = wallet_transaction_record(); - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.ledger_entries.push_back( entry ); + record.fee = required_fees; - sign_and_cache_transaction( trx, required_signatures, record ); - } - return trx; + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_RETHROW_EXCEPTIONS( warn, "", ("account_to_update",account_to_update) ("pay_from_account",pay_from_account) ("public_data",public_data) ("sign",sign) ) } - signed_transaction wallet::update_active_key( const std::string& account_to_update, - const std::string& pay_from_account, - const std::string& new_active_key, - bool sign ) + wallet_transaction_record wallet::update_active_key( + const std::string& account_to_update, + const std::string& pay_from_account, + const std::string& new_active_key, + bool sign ) { try { if( !is_valid_account_name( account_to_update ) ) FC_THROW_EXCEPTION( invalid_name, "Invalid account name!", ("account_to_update",account_to_update) ); @@ -4050,20 +4035,19 @@ namespace bts { namespace wallet { trx.update_account( account->id, account->delegate_pay_rate(), optional(), account_public_key ); - if (sign) - { - auto entry = ledger_entry(); - entry.from_account = payer_public_key; - entry.to_account = account_public_key; - entry.memo = "update " + account_to_update + " active key"; + auto entry = ledger_entry(); + entry.from_account = payer_public_key; + entry.to_account = account_public_key; + entry.memo = "update " + account_to_update + " active key"; - auto record = wallet_transaction_record(); - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.ledger_entries.push_back( entry ); + record.fee = required_fees; - sign_and_cache_transaction( trx, required_signatures, record ); - } - return trx; + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_RETHROW_EXCEPTIONS( warn, "", ("account_to_update",account_to_update) ("pay_from_account",pay_from_account) ("sign",sign) ) } @@ -4202,7 +4186,9 @@ namespace bts { namespace wallet { * price_per_unit = 1 / price_per_unit * @endcode */ - signed_transaction wallet::cancel_market_order( const address& owner_address ) + wallet_transaction_record wallet::cancel_market_order( + const address& owner_address, + bool sign ) { try { if( NOT is_open() ) FC_CAPTURE_AND_THROW( wallet_closed ); if( NOT is_unlocked() ) FC_CAPTURE_AND_THROW( login_required ); @@ -4288,11 +4274,15 @@ namespace bts { namespace wallet { record.ledger_entries.push_back( entry ); record.fee = required_fees; - sign_and_cache_transaction( trx, required_signatures, record ); - return trx; + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_CAPTURE_AND_RETHROW( (owner_address) ) } - signed_transaction wallet::cancel_market_order2( const order_id_type& order_id ) + wallet_transaction_record wallet::cancel_market_order2( + const order_id_type& order_id, + bool sign ) { try { if( NOT is_open() ) FC_CAPTURE_AND_THROW( wallet_closed ); if( NOT is_unlocked() ) FC_CAPTURE_AND_THROW( login_required ); @@ -4380,11 +4370,13 @@ namespace bts { namespace wallet { record.ledger_entries.push_back( entry ); record.fee = required_fees; - sign_and_cache_transaction( trx, required_signatures, record ); - return trx; + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_CAPTURE_AND_RETHROW( (order_id) ) } - signed_transaction wallet::submit_bid( + wallet_transaction_record wallet::submit_bid( const string& from_account_name, double real_quantity, const string& quantity_symbol, @@ -4468,35 +4460,34 @@ namespace bts { namespace wallet { trx.bid( cost_shares, quote_price_shares, order_address ); - if( sign ) - { - std::stringstream memo; - memo << "buy " << base_asset_record->symbol << " @ " << my->_blockchain->to_pretty_price( quote_price_shares ); + std::stringstream memo; + memo << "buy " << base_asset_record->symbol << " @ " << my->_blockchain->to_pretty_price( quote_price_shares ); - auto entry = ledger_entry(); - entry.from_account = from_account_key; - entry.to_account = order_key; - entry.amount = cost_shares; - entry.memo = memo.str(); + auto entry = ledger_entry(); + entry.from_account = from_account_key; + entry.to_account = order_key; + entry.amount = cost_shares; + entry.memo = memo.str(); - auto record = wallet_transaction_record(); - record.is_market = true; - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.is_market = true; + record.ledger_entries.push_back( entry ); + record.fee = required_fees; - sign_and_cache_transaction( trx, required_signatures, record ); + auto key_rec = my->_wallet_db.lookup_key( order_key ); + FC_ASSERT( key_rec.valid() ); + key_rec->memo = "BID-" + variant( address( order_key ) ).as_string().substr( 3, 8 ); + my->_wallet_db.store_key( *key_rec ); - auto key_rec = my->_wallet_db.lookup_key( order_key ); - FC_ASSERT( key_rec.valid() ); - key_rec->memo = "BID-" + variant( address( order_key ) ).as_string().substr( 3, 8 ); - my->_wallet_db.store_key( *key_rec ); - } - return trx; + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_CAPTURE_AND_RETHROW( (from_account_name) (real_quantity)(quantity_symbol) (quote_price)(quote_symbol)(sign) ) } - signed_transaction wallet::submit_ask( + wallet_transaction_record wallet::submit_ask( const string& from_account_name, double real_quantity, const string& quantity_symbol, @@ -4580,30 +4571,29 @@ namespace bts { namespace wallet { trx.ask( cost_shares, quote_price_shares, order_address ); - if( sign ) - { - std::stringstream memo; - memo << "sell " << base_asset_record->symbol << " @ " << my->_blockchain->to_pretty_price( quote_price_shares ); + std::stringstream memo; + memo << "sell " << base_asset_record->symbol << " @ " << my->_blockchain->to_pretty_price( quote_price_shares ); - auto entry = ledger_entry(); - entry.from_account = from_account_key; - entry.to_account = order_key; - entry.amount = cost_shares; - entry.memo = memo.str(); + auto entry = ledger_entry(); + entry.from_account = from_account_key; + entry.to_account = order_key; + entry.amount = cost_shares; + entry.memo = memo.str(); - auto record = wallet_transaction_record(); - record.is_market = true; - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.is_market = true; + record.ledger_entries.push_back( entry ); + record.fee = required_fees; - sign_and_cache_transaction( trx, required_signatures, record ); + auto key_rec = my->_wallet_db.lookup_key( order_key ); + FC_ASSERT( key_rec.valid() ); + key_rec->memo = "ASK-" + variant( address( order_key ) ).as_string().substr( 3, 8 ); + my->_wallet_db.store_key( *key_rec ); - auto key_rec = my->_wallet_db.lookup_key( order_key ); - FC_ASSERT( key_rec.valid() ); - key_rec->memo = "ASK-" + variant( address( order_key ) ).as_string().substr( 3, 8 ); - my->_wallet_db.store_key( *key_rec ); - } - return trx; + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); + + return record; } FC_CAPTURE_AND_RETHROW( (from_account_name) (real_quantity)(quantity_symbol) (quote_price)(quote_symbol)(sign) ) } @@ -4616,7 +4606,7 @@ namespace bts { namespace wallet { * @param from_account - the account that will be providing real_quantity / quote_price XTS to * fund the transaction. */ - signed_transaction wallet::submit_short( + wallet_transaction_record wallet::submit_short( const string& from_account_name, double real_quantity, double quote_price, @@ -4675,39 +4665,37 @@ namespace bts { namespace wallet { // withdraw to transaction cost_share_quantity + fee trx.short_sell( cost_shares, quote_price_shares, order_address ); - if( sign ) - { - std::stringstream memo; - memo << "short " << quote_asset_record->symbol << " @ " << my->_blockchain->to_pretty_price( quote_price_shares ); + std::stringstream memo; + memo << "short " << quote_asset_record->symbol << " @ " << my->_blockchain->to_pretty_price( quote_price_shares ); - auto entry = ledger_entry(); - entry.from_account = from_account_key; - entry.to_account = order_key; - entry.amount = cost_shares; - entry.memo = memo.str(); + auto entry = ledger_entry(); + entry.from_account = from_account_key; + entry.to_account = order_key; + entry.amount = cost_shares; + entry.memo = memo.str(); - auto record = wallet_transaction_record(); - record.is_market = true; - record.ledger_entries.push_back( entry ); - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.is_market = true; + record.ledger_entries.push_back( entry ); + record.fee = required_fees; - sign_and_cache_transaction( trx, required_signatures, record ); + auto key_rec = my->_wallet_db.lookup_key( order_key ); + FC_ASSERT( key_rec.valid() ); + key_rec->memo = "SHORT-" + variant( address( order_key ) ).as_string().substr( 3, 8 ); + my->_wallet_db.store_key( *key_rec ); - auto key_rec = my->_wallet_db.lookup_key( order_key ); - FC_ASSERT( key_rec.valid() ); - key_rec->memo = "SHORT-" + variant( address( order_key ) ).as_string().substr( 3, 8 ); - my->_wallet_db.store_key( *key_rec ); - } + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); - return trx; + return record; } FC_CAPTURE_AND_RETHROW( (from_account_name) (real_quantity) (quote_price)(quote_symbol)(sign) ) } - signed_transaction wallet::add_collateral( - const string& from_account_name, - const address& short_id, - share_type collateral_to_add, - bool sign) + wallet_transaction_record wallet::add_collateral( + const string& from_account_name, + const address& short_id, + share_type collateral_to_add, + bool sign ) { try { if (!is_open()) FC_CAPTURE_AND_THROW (wallet_closed); if (!is_unlocked()) FC_CAPTURE_AND_THROW (login_required); @@ -4732,30 +4720,28 @@ namespace bts { namespace wallet { trx, required_signatures); - if (sign) - { - auto record = wallet_transaction_record(); - record.is_market = true; - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.is_market = true; + record.fee = required_fees; - auto entry = ledger_entry(); - entry.from_account = from_account_key; - entry.to_account = get_private_key(order_itr->second.order.get_owner()).get_public_key(); - entry.amount = asset(collateral_to_add); - entry.memo = "add collateral to short"; - record.ledger_entries.push_back(entry); + auto entry = ledger_entry(); + entry.from_account = from_account_key; + entry.to_account = get_private_key(order_itr->second.order.get_owner()).get_public_key(); + entry.amount = asset(collateral_to_add); + entry.memo = "add collateral to short"; + record.ledger_entries.push_back(entry); - sign_and_cache_transaction(trx, required_signatures, record); - } + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); - return trx; + return record; } FC_CAPTURE_AND_RETHROW((from_account_name)(short_id)(collateral_to_add)(sign)) } - signed_transaction wallet::add_collateral2( - const string& from_account_name, - const order_id_type& short_id, - share_type collateral_to_add, - bool sign) + wallet_transaction_record wallet::add_collateral2( + const string& from_account_name, + const order_id_type& short_id, + share_type collateral_to_add, + bool sign ) { try { if (!is_open()) FC_CAPTURE_AND_THROW (wallet_closed); if (!is_unlocked()) FC_CAPTURE_AND_THROW (login_required); @@ -4786,31 +4772,29 @@ namespace bts { namespace wallet { trx, required_signatures); - if (sign) - { - auto record = wallet_transaction_record(); - record.is_market = true; - record.fee = required_fees; + auto record = wallet_transaction_record(); + record.is_market = true; + record.fee = required_fees; - auto entry = ledger_entry(); - entry.from_account = from_account_key; - entry.to_account = get_private_key( owner_address ).get_public_key(); - entry.amount = asset(collateral_to_add); - entry.memo = "add collateral to short"; - record.ledger_entries.push_back(entry); + auto entry = ledger_entry(); + entry.from_account = from_account_key; + entry.to_account = get_private_key( owner_address ).get_public_key(); + entry.amount = asset(collateral_to_add); + entry.memo = "add collateral to short"; + record.ledger_entries.push_back(entry); - sign_and_cache_transaction(trx, required_signatures, record); - } + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); - return trx; + return record; } FC_CAPTURE_AND_RETHROW((from_account_name)(short_id)(collateral_to_add)(sign)) } - signed_transaction wallet::cover_short( + wallet_transaction_record wallet::cover_short( const string& from_account_name, double real_quantity_usd, const string& quote_symbol, const address& owner_address, - bool sign ) + bool sign ) { try { if( NOT is_open() ) FC_CAPTURE_AND_THROW( wallet_closed ); if( NOT is_unlocked() ) FC_CAPTURE_AND_THROW( login_required ); @@ -4893,41 +4877,40 @@ namespace bts { namespace wallet { my->withdraw_to_transaction( required_fees, from_address, trx, required_signatures ); } - if( sign ) + auto record = wallet_transaction_record(); + record.is_market = true; + record.fee = required_fees; + + { + auto entry = ledger_entry(); + entry.from_account = from_account_key; + entry.to_account = get_private_key( order_to_cover->get_owner() ).get_public_key(); + entry.amount = amount_to_cover; + entry.memo = "payoff debt"; + record.ledger_entries.push_back( entry ); + } + if( collateral_recovered.amount > 0 ) { - auto record = wallet_transaction_record(); - record.is_market = true; - record.fee = required_fees; + auto entry = ledger_entry(); + entry.from_account = get_private_key( order_to_cover->get_owner() ).get_public_key(); + entry.to_account = from_account_key; + entry.amount = collateral_recovered; + entry.memo = "cover proceeds"; + record.ledger_entries.push_back( entry ); + } - { - auto entry = ledger_entry(); - entry.from_account = from_account_key; - entry.to_account = get_private_key( order_to_cover->get_owner() ).get_public_key(); - entry.amount = amount_to_cover; - entry.memo = "payoff debt"; - record.ledger_entries.push_back( entry ); - } - if( collateral_recovered.amount > 0 ) - { - auto entry = ledger_entry(); - entry.from_account = get_private_key( order_to_cover->get_owner() ).get_public_key(); - entry.to_account = from_account_key; - entry.amount = collateral_recovered; - entry.memo = "cover proceeds"; - record.ledger_entries.push_back( entry ); - } + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); - sign_and_cache_transaction( trx, required_signatures, record ); - } - return trx; + return record; } FC_CAPTURE_AND_RETHROW( (from_account_name)(real_quantity_usd)(quote_symbol)(owner_address)(sign) ) } - signed_transaction wallet::cover_short2( + wallet_transaction_record wallet::cover_short2( const string& from_account_name, double real_quantity_usd, const string& quote_symbol, const order_id_type& short_id, - bool sign ) + bool sign ) { try { if( NOT is_open() ) FC_CAPTURE_AND_THROW( wallet_closed ); if( NOT is_unlocked() ) FC_CAPTURE_AND_THROW( login_required ); @@ -5010,33 +4993,32 @@ namespace bts { namespace wallet { my->withdraw_to_transaction( required_fees, from_address, trx, required_signatures ); } - if( sign ) + auto record = wallet_transaction_record(); + record.is_market = true; + record.fee = required_fees; + { - auto record = wallet_transaction_record(); - record.is_market = true; - record.fee = required_fees; + auto entry = ledger_entry(); + entry.from_account = from_account_key; + entry.to_account = get_private_key( owner_address ).get_public_key(); + entry.amount = amount_to_cover; + entry.memo = "payoff debt"; + record.ledger_entries.push_back( entry ); + } + if( collateral_recovered.amount > 0 ) + { + auto entry = ledger_entry(); + entry.from_account = get_private_key( owner_address ).get_public_key(); + entry.to_account = from_account_key; + entry.amount = collateral_recovered; + entry.memo = "cover proceeds"; + record.ledger_entries.push_back( entry ); + } - { - auto entry = ledger_entry(); - entry.from_account = from_account_key; - entry.to_account = get_private_key( owner_address ).get_public_key(); - entry.amount = amount_to_cover; - entry.memo = "payoff debt"; - record.ledger_entries.push_back( entry ); - } - if( collateral_recovered.amount > 0 ) - { - auto entry = ledger_entry(); - entry.from_account = get_private_key( owner_address ).get_public_key(); - entry.to_account = from_account_key; - entry.amount = collateral_recovered; - entry.memo = "cover proceeds"; - record.ledger_entries.push_back( entry ); - } + if( sign ) sign_transaction( trx, required_signatures ); + cache_transaction( trx, record ); - sign_and_cache_transaction( trx, required_signatures, record ); - } - return trx; + return record; } FC_CAPTURE_AND_RETHROW( (from_account_name)(real_quantity_usd)(quote_symbol)(short_id)(sign) ) } void wallet::set_transaction_fee( const asset& fee ) @@ -5063,8 +5045,8 @@ namespace bts { namespace wallet { if( lowest_ask ) { xts_fee += xts_fee + xts_fee; - // fees paid in something other than XTS are discounted 50% - auto alt_fees_paid = xts_fee * lowest_ask->market_index.order_price; + // fees paid in something other than XTS are discounted 50% + auto alt_fees_paid = xts_fee * lowest_ask->market_index.order_price; return alt_fees_paid; } } @@ -5945,7 +5927,7 @@ namespace bts { namespace wallet { if( !okey_rec.valid() || !okey_rec->has_private_key() ) continue; const auto oaccount_rec = my->_wallet_db.lookup_account( okey_rec->account_address ); - FC_ASSERT( oaccount_rec.valid() ); + if( !oaccount_rec.valid() ) FC_THROW_EXCEPTION( unknown_account, "Unknown account name!" ); if( !account_name.empty() && oaccount_rec->name != account_name ) continue; const auto obalance = pending_state->get_balance_record( item.first ); @@ -5958,7 +5940,7 @@ namespace bts { namespace wallet { if( slate_id == 0 ) continue; const auto slate = pending_state->get_delegate_slate( slate_id ); - FC_ASSERT( slate.valid() ); + if( !slate.valid() ) FC_THROW_EXCEPTION( unknown_slate, "Unknown slate!" ); for( const auto& delegate_id : slate->supported_delegates ) { diff --git a/libraries/wallet/wallet_db.cpp b/libraries/wallet/wallet_db.cpp index 8da0b9320..584310997 100644 --- a/libraries/wallet/wallet_db.cpp +++ b/libraries/wallet/wallet_db.cpp @@ -270,8 +270,8 @@ namespace bts { namespace wallet { return next_child_index; } - fc::ecc::private_key wallet_db::get_private_key( const fc::sha512& password, - int index ) + private_key_type wallet_db::get_private_key( const fc::sha512& password, + int index ) { FC_ASSERT( wallet_master_key.valid() ); @@ -281,9 +281,9 @@ namespace bts { namespace wallet { return new_priv_key; } - fc::ecc::private_key wallet_db::new_private_key( const fc::sha512& password, - const address& parent_account_address, - bool store_key ) + private_key_type wallet_db::new_private_key( const fc::sha512& password, + const address& parent_account_address, + bool store_key ) { FC_ASSERT( wallet_master_key.valid() ); @@ -492,7 +492,7 @@ namespace bts { namespace wallet { } FC_RETHROW_EXCEPTIONS( warn, "", ("address",a) ) } void wallet_db::cache_memo( const memo_status& memo, - const fc::ecc::private_key& account_key, + const private_key_type& account_key, const fc::sha512& password ) { key_data data; @@ -504,33 +504,45 @@ namespace bts { namespace wallet { store_key( data ); } - private_keys wallet_db::get_account_private_keys( const fc::sha512& password )const + vector wallet_db::get_account_private_keys( const fc::sha512& password )const { try { - private_keys keys; - keys.reserve( accounts.size() * 2 ); + vector public_keys; + vector private_keys; - auto insert_key = [&keys,&password]( const owallet_key_record& key_rec ) + public_keys.reserve( accounts.size() ); + private_keys.reserve( accounts.size() ); + + const auto insert_key = [&]( const owallet_key_record& key_record ) { - if( key_rec.valid() && key_rec->has_private_key() ) - { - try { - keys.push_back( key_rec->decrypt_private_key( password ) ); - } catch ( const fc::exception& e ) - { - elog( "error decrypting private key: ${e}", ("e", e.to_detail_string() ) ); - } - } + if( !key_record.valid() || !key_record->has_private_key() ) + return; + + if( std::find( public_keys.begin(), public_keys.end(), key_record->public_key ) != public_keys.end() ) + return; + + private_key_type key; + try + { + key = key_record->decrypt_private_key( password ); + } + catch( const fc::exception& e ) + { + elog( "error decrypting private key: ${e}", ("e",e.to_detail_string()) ); + return; + } + + private_keys.push_back( key ); + public_keys.push_back( key_record->public_key ); }; - for( const auto& item : accounts ) + for( const auto& account_item : accounts ) { - insert_key(lookup_key(item.second.account_address)); - for( const auto& active_key : item.second.active_key_history ) - insert_key(lookup_key(active_key.second)); + insert_key( lookup_key( account_item.second.account_address ) ); + for( const auto& key_item : account_item.second.active_key_history ) + insert_key( lookup_key( key_item.second ) ); } - keys.shrink_to_fit(); - return keys; + return private_keys; } FC_RETHROW_EXCEPTIONS( warn, "" ) } owallet_balance_record wallet_db::lookup_balance( const balance_id_type& balance_id )const diff --git a/libraries/wallet/wallet_records.cpp b/libraries/wallet/wallet_records.cpp index 5319403dc..82d656aa6 100644 --- a/libraries/wallet/wallet_records.cpp +++ b/libraries/wallet/wallet_records.cpp @@ -16,7 +16,7 @@ namespace bts { namespace wallet { return checksum == fc::sha512::hash(password); } - void master_key::encrypt_key( const fc::sha512& password, + void master_key::encrypt_key( const fc::sha512& password, const extended_private_key& k ) { try { FC_ASSERT( password != fc::sha512() ); @@ -28,13 +28,13 @@ namespace bts { namespace wallet { decrypt_key( password ); } FC_CAPTURE_AND_RETHROW() } - bool key_data::has_private_key()const - { - return encrypted_private_key.size() > 0; + bool key_data::has_private_key()const + { + return encrypted_private_key.size() > 0; } - void key_data::encrypt_private_key( const fc::sha512& password, - const fc::ecc::private_key& key_to_encrypt ) + void key_data::encrypt_private_key( const fc::sha512& password, + const private_key_type& key_to_encrypt ) { try { FC_ASSERT( password != fc::sha512() ); public_key = key_to_encrypt.get_public_key(); @@ -44,11 +44,11 @@ namespace bts { namespace wallet { FC_ASSERT( key_to_encrypt == decrypt_private_key( password ) ); } FC_CAPTURE_AND_RETHROW() } - fc::ecc::private_key key_data::decrypt_private_key( const fc::sha512& password )const + private_key_type key_data::decrypt_private_key( const fc::sha512& password )const { try { FC_ASSERT( password != fc::sha512() ); const auto plain_text = fc::aes_decrypt( password, encrypted_private_key ); - return fc::raw::unpack( plain_text ); + return fc::raw::unpack( plain_text ); } FC_CAPTURE_AND_RETHROW() } order_type_enum market_order_status::get_type()const diff --git a/tests/regression_tests/titan/client0.log b/tests/regression_tests/titan/client0.log index 7fd98ee98..43b77cdfd 100644 --- a/tests/regression_tests/titan/client0.log +++ b/tests/regression_tests/titan/client0.log @@ -10,32 +10,9 @@ default (unlocked) >>> wallet_account_create test-account Account created successfully. You may give the following link to others to allow them to add you as a contact and send you funds: xts:test-account:XTS5drpKagoTFiMsg1urDXvrtY7Fkuyb4vkgBUCxrsnrer8ioRGrp default (unlocked) >>> wallet_account_register test-account delegate0 -{ - "expiration": "20140620T154750", - "delegate_slate_id": null, - "operations": [{ - "type": "register_account_op_type", - "data": { - "name": "test-account", - "public_data": null, - "owner_key": "XTS5drpKagoTFiMsg1urDXvrtY7Fkuyb4vkgBUCxrsnrer8ioRGrp", - "active_key": "XTS5drpKagoTFiMsg1urDXvrtY7Fkuyb4vkgBUCxrsnrer8ioRGrp", - "delegate_pay_rate": 255, - "meta_data": null - } - },{ - "type": "withdraw_op_type", - "data": { - "balance_id": "XTS6GvhLUV93rQZLJSstvyhMeoU9cnZ578kz", - "amount": 50000, - "claim_input_data": "" - } - } - ], - "signatures": [ - "208513ec7641898a4a37e0bfe8617a37bef25351eada00e9d0c04e79869bd335f6cf6e97e7bbabe3e17bf2f1cf2125879262636273ba022145368abaaa1c18c64c" - ] -} +RECEIVED BLOCK FROM TO AMOUNT MEMO FEE ID +====================================================================================================================================================================== +[redacted] PENDING delegate0 test-account 0.00000 XTS register test-account 0.50000 XTS [redacted] default (unlocked) >>> wallet_transfer 150 XTS delegate0 account-for-client1 "send this back" RECEIVED BLOCK FROM TO AMOUNT MEMO FEE ID ======================================================================================================================================================================