aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/epee/include/misc_log_ex.h1
-rw-r--r--contrib/epee/include/misc_os_dependent.h12
-rw-r--r--src/cryptonote_core/tx_pool.cpp2
-rw-r--r--src/cryptonote_core/tx_pool.h2
-rw-r--r--src/daemon/rpc_command_executor.cpp60
-rw-r--r--src/rpc/core_rpc_server.cpp34
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h31
-rw-r--r--src/simplewallet/simplewallet.cpp9
-rw-r--r--src/wallet/wallet2.cpp1
-rw-r--r--tests/core_tests/chaingen.h6
10 files changed, 126 insertions, 32 deletions
diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h
index d1451ff12..7cb1e61aa 100644
--- a/contrib/epee/include/misc_log_ex.h
+++ b/contrib/epee/include/misc_log_ex.h
@@ -424,6 +424,7 @@ namespace log_space
}
std::cout << buf;
+ std::cout << std::flush;
#endif
reset_console_color();
return true;
diff --git a/contrib/epee/include/misc_os_dependent.h b/contrib/epee/include/misc_os_dependent.h
index 2abca0446..806d3e83e 100644
--- a/contrib/epee/include/misc_os_dependent.h
+++ b/contrib/epee/include/misc_os_dependent.h
@@ -53,11 +53,13 @@ namespace misc_utils
#if defined(_MSC_VER)
return ::GetTickCount64();
#elif defined(WIN32)
-# if defined(WIN64)
- return GetTickCount64();
-# else
- return GetTickCount();
-# endif
+ static LARGE_INTEGER pcfreq = {0};
+ LARGE_INTEGER ticks;
+ if (!pcfreq.QuadPart)
+ QueryPerformanceFrequency(&pcfreq);
+ QueryPerformanceCounter(&ticks);
+ ticks.QuadPart *= 1000; /* we want msec */
+ return ticks.QuadPart / pcfreq.QuadPart;
#elif defined(__MACH__)
clock_serv_t cclock;
mach_timespec_t mts;
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 aa571755f..30c958381 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;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index a9a65535f..cdd472528 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1974,6 +1974,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);
diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h
index 44170d116..652413b8a 100644
--- a/tests/core_tests/chaingen.h
+++ b/tests/core_tests/chaingen.h
@@ -470,13 +470,15 @@ inline bool replay_events_through_core(cryptonote::core& cr, const std::vector<t
CATCH_ENTRY_L0("replay_events_through_core", false);
}
//--------------------------------------------------------------------------
-template<class t_test_class>
+template<typename t_test_class>
struct get_test_options {
- const std::pair<uint8_t, uint64_t> hard_forks[1] = {std::make_pair((uint8_t)1, (uint64_t)0)};
+ const std::pair<uint8_t, uint64_t> hard_forks[1];
const cryptonote::test_options test_options = {
hard_forks
};
+ get_test_options():hard_forks{std::make_pair((uint8_t)1, (uint64_t)0)}{}
};
+
//--------------------------------------------------------------------------
template<class t_test_class>
inline bool do_replay_events(std::vector<test_event_entry>& events)