diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/util.cpp | 9 | ||||
-rw-r--r-- | src/common/util.h | 2 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 18 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.h | 1 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_format_utils.cpp | 14 | ||||
-rw-r--r-- | src/cryptonote_core/tx_pool.cpp | 2 | ||||
-rw-r--r-- | src/cryptonote_core/tx_pool.h | 2 | ||||
-rw-r--r-- | src/daemon/rpc_command_executor.cpp | 60 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 34 | ||||
-rw-r--r-- | src/rpc/core_rpc_server_commands_defs.h | 31 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 10 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 1 |
12 files changed, 139 insertions, 45 deletions
diff --git a/src/common/util.cpp b/src/common/util.cpp index 6f75e5bad..2337f5766 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -413,4 +413,13 @@ std::string get_nix_version_display_string() } return false; } + void set_strict_default_file_permissions(bool strict) + { +#if defined(__MINGW32__) || defined(__MINGW__) + // no clue about the odd one out +#else + mode_t mode = strict ? 077 : 0; + umask(mode); +#endif + } } diff --git a/src/common/util.h b/src/common/util.h index 7554b1df7..ed1c16cb0 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -158,4 +158,6 @@ namespace tools /*! \brief where the installed handler is stored */ static std::function<void(int)> m_handler; }; + + void set_strict_default_file_permissions(bool strict); } diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 34810d983..c19230176 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2015,18 +2015,12 @@ bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t& max_used_block TIME_MEASURE_START(a); bool res = check_tx_inputs(tx, tvc, &max_used_block_height); TIME_MEASURE_FINISH(a); - crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx); if(m_show_time_stats) LOG_PRINT_L0("HASH: " << "+" << " VIN/VOUT: " << tx.vin.size() << "/" << tx.vout.size() << " H: " << max_used_block_height << " chcktx: " << a + m_fake_scan_time); if (!res) return false; - // ND: Speedup: - // 1. keep a list of verified transactions, when the Blockchain tries to check a tx again, - // verify against list and skip if already verified to be correct. - m_check_tx_inputs_table.emplace(tx_prefix_hash, std::make_pair(res, max_used_block_height)); - CHECK_AND_ASSERT_MES(max_used_block_height < m_db->height(), false, "internal error: max used block index=" << max_used_block_height << " is not less then blockchain size = " << m_db->height()); max_used_block_id = m_db->get_block_hash_from_height(max_used_block_height); return true; @@ -2076,16 +2070,6 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx); - auto its = m_check_tx_inputs_table.find(tx_prefix_hash); - if (its != m_check_tx_inputs_table.end()) - { - if (!its->second.first) - return false; - if (pmax_used_block_height) - *pmax_used_block_height = its->second.second; - return true; - } - // from hard fork 2, we require mixin at least 2 unless one output cannot mix with 2 others // if one output cannot mix with 2 others, we accept at most 1 output that can mix if (m_hardfork->get_current_version() >= 2) @@ -2967,7 +2951,6 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) TIME_MEASURE_FINISH(t1); m_blocks_longhash_table.clear(); m_scan_table.clear(); - m_check_tx_inputs_table.clear(); m_blocks_txs_check.clear(); m_check_txin_table.clear(); @@ -3115,7 +3098,6 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e m_fake_pow_calc_time = 0; m_scan_table.clear(); - m_check_tx_inputs_table.clear(); m_check_txin_table.clear(); TIME_MEASURE_FINISH(prepare); diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index a62487d1e..21086d578 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -790,7 +790,6 @@ namespace cryptonote // metadata containers std::unordered_map<crypto::hash, std::unordered_map<crypto::key_image, std::vector<output_data_t>>> m_scan_table; - std::unordered_map<crypto::hash, std::pair<bool, uint64_t>> m_check_tx_inputs_table; std::unordered_map<crypto::hash, crypto::hash> m_blocks_longhash_table; std::unordered_map<crypto::hash, std::unordered_map<crypto::key_image, bool>> m_check_txin_table; diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 94f3d51d2..3b9dcc8a4 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -145,7 +145,19 @@ namespace cryptonote [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero"); - CHECK_AND_ASSERT_MES(max_outs >= out_amounts.size(), false, "max_out exceeded"); + if (height == 0) + { + // the genesis block was not decomposed, for unknown reasons + while (max_outs < out_amounts.size()) + { + out_amounts[out_amounts.size() - 2] += out_amounts.back(); + out_amounts.resize(out_amounts.size() - 1); + } + } + else + { + CHECK_AND_ASSERT_MES(max_outs >= out_amounts.size(), false, "max_out exceeded"); + } uint64_t summary_amounts = 0; for (size_t no = 0; no < out_amounts.size(); no++) diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index a06826163..3d5ab86e1 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -512,7 +512,7 @@ namespace cryptonote { if(txd.max_used_block_height >= m_blockchain.get_current_blockchain_height()) return false; - if(m_blockchain.get_block_id_by_height(txd.max_used_block_height) != txd.max_used_block_id) + if(true) { //if we already failed on this height and id, skip actual ring signature check if(txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height)) diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 84e11eeff..c7aab7f08 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -310,6 +310,7 @@ namespace cryptonote #define CURRENT_MEMPOOL_ARCHIVE_VER 11 +#define CURRENT_MEMPOOL_TX_DETAILS_ARCHIVE_VER 11 /** * @brief serialize the transaction pool to/from disk @@ -530,6 +531,7 @@ namespace boost } } BOOST_CLASS_VERSION(cryptonote::tx_memory_pool, CURRENT_MEMPOOL_ARCHIVE_VER) +BOOST_CLASS_VERSION(cryptonote::tx_memory_pool::tx_details, CURRENT_MEMPOOL_TX_DETAILS_ARCHIVE_VER) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 933c93ed7..ae9492111 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -70,6 +70,23 @@ namespace { << "difficulty: " << boost::lexical_cast<std::string>(header.difficulty) << std::endl << "reward: " << boost::lexical_cast<std::string>(header.reward); } + + std::string get_human_time_ago(time_t t, time_t now) + { + if (t == now) + return "now"; + time_t dt = t > now ? t - now : now - t; + std::string s; + if (dt < 90) + s = boost::lexical_cast<std::string>(dt) + " seconds"; + else if (dt < 90 * 60) + s = boost::lexical_cast<std::string>(dt/60) + " minutes"; + else if (dt < 36 * 3600) + s = boost::lexical_cast<std::string>(dt/3600) + " hours"; + else + s = boost::lexical_cast<std::string>(dt/(3600*24)) + " days"; + return s + " " + (t > now ? "in the future" : "ago"); + } } t_rpc_command_executor::t_rpc_command_executor( @@ -575,16 +592,26 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) { } } - if (1 == res.txs_as_hex.size()) + if (1 == res.txs.size() || 1 == res.txs_as_hex.size()) { + if (1 == res.txs.size()) + { + // only available for new style answers + if (res.txs.front().in_pool) + tools::success_msg_writer() << "Found in pool"; + else + tools::success_msg_writer() << "Found in blockchain at height " << res.txs.front().block_height; + } + // first as hex - tools::success_msg_writer() << res.txs_as_hex.front(); + const std::string &as_hex = (1 == res.txs.size()) ? res.txs.front().as_hex : res.txs_as_hex.front(); + tools::success_msg_writer() << as_hex; // then as json crypto::hash tx_hash, tx_prefix_hash; cryptonote::transaction tx; cryptonote::blobdata blob; - if (!string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), blob)) + if (!string_tools::parse_hexstr_to_binbuff(as_hex, blob)) { tools::fail_msg_writer() << "Failed to parse tx"; } @@ -669,6 +696,7 @@ bool t_rpc_command_executor::print_transaction_pool_long() { } if (! res.transactions.empty()) { + const time_t now = time(NULL); tools::msg_writer() << "Transactions: "; for (auto & tx_info : res.transactions) { @@ -676,7 +704,7 @@ bool t_rpc_command_executor::print_transaction_pool_long() { << tx_info.tx_json << std::endl << "blob_size: " << tx_info.blob_size << std::endl << "fee: " << cryptonote::print_money(tx_info.fee) << std::endl - << "receive_time: " << tx_info.receive_time << std::endl + << "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl << "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl << "max_used_block_height: " << tx_info.max_used_block_height << std::endl << "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl @@ -747,17 +775,21 @@ bool t_rpc_command_executor::print_transaction_pool_short() { { tools::msg_writer() << "Pool is empty" << std::endl; } - for (auto & tx_info : res.transactions) + else { - tools::msg_writer() << "id: " << tx_info.id_hash << std::endl - << "blob_size: " << tx_info.blob_size << std::endl - << "fee: " << cryptonote::print_money(tx_info.fee) << std::endl - << "receive_time: " << tx_info.receive_time << std::endl - << "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl - << "max_used_block_height: " << tx_info.max_used_block_height << std::endl - << "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl - << "last_failed_height: " << tx_info.last_failed_height << std::endl - << "last_failed_id: " << tx_info.last_failed_id_hash << std::endl; + const time_t now = time(NULL); + for (auto & tx_info : res.transactions) + { + tools::msg_writer() << "id: " << tx_info.id_hash << std::endl + << "blob_size: " << tx_info.blob_size << std::endl + << "fee: " << cryptonote::print_money(tx_info.fee) << std::endl + << "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl + << "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl + << "max_used_block_height: " << tx_info.max_used_block_height << std::endl + << "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl + << "last_failed_height: " << tx_info.last_failed_height << std::endl + << "last_failed_id: " << tx_info.last_failed_id_hash << std::endl; + } } return true; diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 165a24c22..9fcb4373b 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -240,6 +240,7 @@ namespace cryptonote // try the pool for any missing txes size_t found_in_pool = 0; + std::unordered_set<crypto::hash> pool_tx_hashes; if (!missed_txs.empty()) { std::list<transaction> pool_txs; @@ -248,9 +249,11 @@ namespace cryptonote { for (std::list<transaction>::const_iterator i = pool_txs.begin(); i != pool_txs.end(); ++i) { - std::list<crypto::hash>::iterator mi = std::find(missed_txs.begin(), missed_txs.end(), get_transaction_hash(*i)); + crypto::hash tx_hash = get_transaction_hash(*i); + std::list<crypto::hash>::iterator mi = std::find(missed_txs.begin(), missed_txs.end(), tx_hash); if (mi != missed_txs.end()) { + pool_tx_hashes.insert(tx_hash); missed_txs.erase(mi); txs.push_back(*i); ++found_in_pool; @@ -260,12 +263,33 @@ namespace cryptonote LOG_PRINT_L2("Found " << found_in_pool << "/" << vh.size() << " transactions in the pool"); } + std::list<std::string>::const_iterator txhi = req.txs_hashes.begin(); + std::vector<crypto::hash>::const_iterator vhi = vh.begin(); BOOST_FOREACH(auto& tx, txs) { + res.txs.push_back(COMMAND_RPC_GET_TRANSACTIONS::entry()); + COMMAND_RPC_GET_TRANSACTIONS::entry &e = res.txs.back(); + + crypto::hash tx_hash = *vhi++; + e.tx_hash = *txhi++; blobdata blob = t_serializable_object_to_blob(tx); - res.txs_as_hex.push_back(string_tools::buff_to_hex_nodelimer(blob)); + e.as_hex = string_tools::buff_to_hex_nodelimer(blob); + if (req.decode_as_json) + e.as_json = obj_to_json_str(tx); + e.in_pool = pool_tx_hashes.find(tx_hash) != pool_tx_hashes.end(); + if (e.in_pool) + { + e.block_height = std::numeric_limits<uint64_t>::max(); + } + else + { + e.block_height = m_core.get_blockchain_storage().get_db().get_tx_block_height(tx_hash); + } + + // fill up old style responses too, in case an old wallet asks + res.txs_as_hex.push_back(e.as_hex); if (req.decode_as_json) - res.txs_as_json.push_back(obj_to_json_str(tx)); + res.txs_as_json.push_back(e.as_json); } BOOST_FOREACH(const auto& miss_tx, missed_txs) @@ -273,7 +297,7 @@ namespace cryptonote res.missed_tx.push_back(string_tools::pod_to_hex(miss_tx)); } - LOG_PRINT_L2(res.txs_as_hex.size() << " transactions found, " << res.missed_tx.size() << " not found"); + LOG_PRINT_L2(res.txs.size() << " transactions found, " << res.missed_tx.size() << " not found"); res.status = CORE_RPC_STATUS_OK; return true; } @@ -383,7 +407,7 @@ namespace cryptonote return true; } - if(!tvc.m_should_be_relayed) + if(!tvc.m_should_be_relayed || req.do_not_relay) { LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed"); res.reason = "Not relayed"; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 91f5e2c90..6067a28b7 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -103,18 +103,41 @@ namespace cryptonote END_KV_SERIALIZE_MAP() }; + struct entry + { + std::string tx_hash; + std::string as_hex; + std::string as_json; + bool in_pool; + uint64_t block_height; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_hash) + KV_SERIALIZE(as_hex) + KV_SERIALIZE(as_json) + KV_SERIALIZE(in_pool) + KV_SERIALIZE(block_height) + END_KV_SERIALIZE_MAP() + }; struct response { - std::list<std::string> txs_as_hex; //transactions blobs as hex + // older compatibility stuff + std::list<std::string> txs_as_hex; //transactions blobs as hex (old compat) + std::list<std::string> txs_as_json; //transactions decoded as json (old compat) + + // in both old and new std::list<std::string> missed_tx; //not found transactions - std::list<std::string> txs_as_json; //transactions decoded as json + + // new style + std::vector<entry> txs; std::string status; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(txs_as_hex) - KV_SERIALIZE(missed_tx) KV_SERIALIZE(txs_as_json) + KV_SERIALIZE(txs) + KV_SERIALIZE(missed_tx) KV_SERIALIZE(status) END_KV_SERIALIZE_MAP() }; @@ -221,12 +244,14 @@ namespace cryptonote struct request { std::string tx_as_hex; + bool do_not_relay; request() {} explicit request(const transaction &); BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_as_hex) + KV_SERIALIZE(do_not_relay) END_KV_SERIALIZE_MAP() }; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index f42937606..304454b8a 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2497,13 +2497,18 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_) COMMAND_RPC_GET_TRANSACTIONS::response res; req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); if (!net_utils::invoke_http_json_remote_command2(m_daemon_address + "/gettransactions", req, res, m_http_client) || - res.txs_as_hex.empty()) + (res.txs.empty() && res.txs_as_hex.empty())) { fail_msg_writer() << tr("failed to get transaction from daemon"); return true; } cryptonote::blobdata tx_data; - if (!string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data)) + bool ok; + if (!res.txs.empty()) + ok = string_tools::parse_hexstr_to_binbuff(res.txs.front().as_hex, tx_data); + else + ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data); + if (!ok) { fail_msg_writer() << tr("failed to parse transaction from daemon"); return true; @@ -2807,6 +2812,7 @@ int main(int argc, char* argv[]) std::string lang = i18n_get_language(); tools::sanitize_locale(); + tools::set_strict_default_file_permissions(true); string_tools::set_module_name_and_folder(argv[0]); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 547336cb7..5de300ecf 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1939,6 +1939,7 @@ void wallet2::commit_tx(pending_tx& ptx) COMMAND_RPC_SEND_RAW_TX::request req; req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx)); + req.do_not_relay = false; COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp; m_daemon_rpc_mutex.lock(); bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000); |