aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/epee/include/console_handler.h27
-rw-r--r--contrib/epee/include/misc_os_dependent.h15
-rw-r--r--contrib/epee/include/profile_tools.h7
-rw-r--r--contrib/epee/include/serialization/keyvalue_serialization.h5
-rw-r--r--contrib/epee/include/storages/levin_abstract_invoke2.h4
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/blockchain_utilities/CMakeLists.txt23
-rw-r--r--src/common/perf_timer.h15
-rw-r--r--src/cryptonote_basic/connection_context.h3
-rw-r--r--src/cryptonote_basic/difficulty.h4
-rw-r--r--src/cryptonote_basic/miner.cpp2
-rw-r--r--src/cryptonote_core/blockchain.cpp34
-rw-r--r--src/cryptonote_core/blockchain.h13
-rw-r--r--src/cryptonote_protocol/block_queue.cpp109
-rw-r--r--src/cryptonote_protocol/block_queue.h6
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_defs.h5
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl78
-rw-r--r--src/daemon/rpc_command_executor.cpp2
-rw-r--r--src/debug_utilities/CMakeLists.txt73
-rw-r--r--src/debug_utilities/cn_deserialize.cpp (renamed from src/blockchain_utilities/cn_deserialize.cpp)3
-rw-r--r--src/debug_utilities/object_sizes.cpp116
-rw-r--r--src/p2p/net_node.h2
-rw-r--r--src/p2p/net_node.inl1
-rw-r--r--src/simplewallet/simplewallet.cpp72
-rw-r--r--src/simplewallet/simplewallet.h1
-rw-r--r--src/wallet/api/wallet_manager.cpp4
-rw-r--r--src/wallet/api/wallet_manager.h1
-rw-r--r--src/wallet/node_rpc_proxy.cpp37
-rw-r--r--src/wallet/node_rpc_proxy.h25
-rw-r--r--src/wallet/wallet2.cpp66
-rw-r--r--src/wallet/wallet2.h18
-rw-r--r--src/wallet/wallet2_api.h11
-rw-r--r--src/wallet/wallet_rpc_server.cpp4
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h2
-rw-r--r--tests/unit_tests/block_queue.cpp188
35 files changed, 583 insertions, 397 deletions
diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h
index e780ad4de..a3b2d30eb 100644
--- a/contrib/epee/include/console_handler.h
+++ b/contrib/epee/include/console_handler.h
@@ -293,13 +293,13 @@ namespace epee
}
template<class t_server, class chain_handler>
- bool run(t_server* psrv, chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "")
+ bool run(t_server* psrv, chain_handler ch_handler, std::function<std::string(void)> prompt, const std::string& usage = "")
{
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(psrv, cmd); }, [&] { psrv->send_stop_signal(); });
}
template<class chain_handler>
- bool run(chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "", std::function<void(void)> exit_handler = NULL)
+ bool run(chain_handler ch_handler, std::function<std::string(void)> prompt, const std::string& usage = "", std::function<void(void)> exit_handler = NULL)
{
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(cmd); }, exit_handler);
}
@@ -312,18 +312,19 @@ namespace epee
void print_prompt()
{
- if (!m_prompt.empty())
+ std::string prompt = m_prompt();
+ if (!prompt.empty())
{
#ifdef HAVE_READLINE
- std::string color_prompt = "\001\033[1;33m\002" + m_prompt;
- if (' ' != m_prompt.back())
+ std::string color_prompt = "\001\033[1;33m\002" + prompt;
+ if (' ' != prompt.back())
color_prompt += " ";
color_prompt += "\001\033[0m\002";
m_stdin_reader.get_readline_buffer().set_prompt(color_prompt);
#else
epee::set_console_color(epee::console_color_yellow, true);
- std::cout << m_prompt;
- if (' ' != m_prompt.back())
+ std::cout << prompt;
+ if (' ' != prompt.back())
std::cout << ' ';
epee::reset_console_color();
std::cout.flush();
@@ -333,7 +334,7 @@ namespace epee
private:
template<typename t_cmd_handler>
- bool run(const std::string& prompt, const std::string& usage, const t_cmd_handler& cmd_handler, std::function<void(void)> exit_handler)
+ bool run(std::function<std::string(void)> prompt, const std::string& usage, const t_cmd_handler& cmd_handler, std::function<void(void)> exit_handler)
{
bool continue_handle = true;
m_prompt = prompt;
@@ -394,7 +395,7 @@ namespace epee
private:
async_stdin_reader m_stdin_reader;
std::atomic<bool> m_running = {true};
- std::string m_prompt;
+ std::function<std::string(void)> m_prompt;
};
@@ -516,19 +517,23 @@ namespace epee
std::unique_ptr<boost::thread> m_console_thread;
async_console_handler m_console_handler;
public:
- bool start_handling(const std::string& prompt, const std::string& usage_string = "", std::function<void(void)> exit_handler = NULL)
+ bool start_handling(std::function<std::string(void)> prompt, const std::string& usage_string = "", std::function<void(void)> exit_handler = NULL)
{
m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, prompt, usage_string, exit_handler)));
m_console_thread->detach();
return true;
}
+ bool start_handling(const std::string &prompt, const std::string& usage_string = "", std::function<void(void)> exit_handler = NULL)
+ {
+ return start_handling([prompt](){ return prompt; }, usage_string, exit_handler);
+ }
void stop_handling()
{
m_console_handler.stop();
}
- bool run_handling(const std::string& prompt, const std::string& usage_string, std::function<void(void)> exit_handler = NULL)
+ bool run_handling(std::function<std::string(void)> prompt, const std::string& usage_string, std::function<void(void)> exit_handler = NULL)
{
return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string, exit_handler);
}
diff --git a/contrib/epee/include/misc_os_dependent.h b/contrib/epee/include/misc_os_dependent.h
index 806d3e83e..69ded09e5 100644
--- a/contrib/epee/include/misc_os_dependent.h
+++ b/contrib/epee/include/misc_os_dependent.h
@@ -48,17 +48,17 @@ namespace epee
namespace misc_utils
{
- inline uint64_t get_tick_count()
+ inline uint64_t get_ns_count()
{
#if defined(_MSC_VER)
- return ::GetTickCount64();
+ return ::GetTickCount64() * 1000000;
#elif defined(WIN32)
static LARGE_INTEGER pcfreq = {0};
LARGE_INTEGER ticks;
if (!pcfreq.QuadPart)
QueryPerformanceFrequency(&pcfreq);
QueryPerformanceCounter(&ticks);
- ticks.QuadPart *= 1000; /* we want msec */
+ ticks.QuadPart *= 1000000000; /* we want nsec */
return ticks.QuadPart / pcfreq.QuadPart;
#elif defined(__MACH__)
clock_serv_t cclock;
@@ -68,16 +68,21 @@ namespace misc_utils
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
- return (mts.tv_sec * 1000) + (mts.tv_nsec/1000000);
+ return (mts.tv_sec * 1000000000) + (mts.tv_nsec);
#else
struct timespec ts;
if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
return 0;
}
- return (ts.tv_sec * 1000) + (ts.tv_nsec/1000000);
+ return (ts.tv_sec * 1000000000) + (ts.tv_nsec);
#endif
}
+ inline uint64_t get_tick_count()
+ {
+ return get_ns_count() / 1000000;
+ }
+
inline int call_sys_cmd(const std::string& cmd)
{
diff --git a/contrib/epee/include/profile_tools.h b/contrib/epee/include/profile_tools.h
index d3b1e4db4..f285fe48b 100644
--- a/contrib/epee/include/profile_tools.h
+++ b/contrib/epee/include/profile_tools.h
@@ -57,8 +57,15 @@ namespace epee
#define TIME_MEASURE_START(var_name) uint64_t var_name = epee::misc_utils::get_tick_count();
+#define TIME_MEASURE_PAUSE(var_name) var_name = epee::misc_utils::get_tick_count() - var_name;
+#define TIME_MEASURE_RESTART(var_name) var_name = epee::misc_utils::get_tick_count() - var_name;
#define TIME_MEASURE_FINISH(var_name) var_name = epee::misc_utils::get_tick_count() - var_name;
+#define TIME_MEASURE_NS_START(var_name) uint64_t var_name = epee::misc_utils::get_ns_count();
+#define TIME_MEASURE_NS_PAUSE(var_name) var_name = epee::misc_utils::get_ns_count() - var_name;
+#define TIME_MEASURE_NS_RESTART(var_name) var_name = epee::misc_utils::get_ns_count() - var_name;
+#define TIME_MEASURE_NS_FINISH(var_name) var_name = epee::misc_utils::get_ns_count() - var_name;
+
namespace profile_tools
{
struct local_call_account
diff --git a/contrib/epee/include/serialization/keyvalue_serialization.h b/contrib/epee/include/serialization/keyvalue_serialization.h
index f4442e46c..d4413a71b 100644
--- a/contrib/epee/include/serialization/keyvalue_serialization.h
+++ b/contrib/epee/include/serialization/keyvalue_serialization.h
@@ -70,10 +70,13 @@ public: \
#define KV_SERIALIZE_N(varialble, val_name) \
epee::serialization::selector<is_store>::serialize(this_ref.varialble, stg, hparent_section, val_name);
+ template<typename T> inline void serialize_default(const T &t, T v) { }
+ template<typename T> inline void serialize_default(T &t, T v) { t = v; }
+
#define KV_SERIALIZE_OPT_N(variable, val_name, default_value) \
do { \
if (!epee::serialization::selector<is_store>::serialize(this_ref.variable, stg, hparent_section, val_name)) \
- this_ref.variable = default_value; \
+ epee::serialize_default(this_ref.variable, default_value); \
} while (0);
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) \
diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h
index 14e7d402a..8ced9d689 100644
--- a/contrib/epee/include/storages/levin_abstract_invoke2.h
+++ b/contrib/epee/include/storages/levin_abstract_invoke2.h
@@ -115,7 +115,7 @@ namespace epee
{
typename serialization::portable_storage stg;
const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation
- std::string buff_to_send, buff_to_recv;
+ std::string buff_to_send;
stg.store_to_binary(buff_to_send);
int res = transport.invoke_async(command, buff_to_send, conn_id, [cb, command](int code, const std::string& buff, typename t_transport::connection_context& context)->bool
{
@@ -151,7 +151,7 @@ namespace epee
serialization::portable_storage stg;
out_struct.store(stg);
- std::string buff_to_send, buff_to_recv;
+ std::string buff_to_send;
stg.store_to_binary(buff_to_send);
int res = transport.notify(command, buff_to_send, conn_id);
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d83242a3c..e473c2984 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -120,6 +120,10 @@ if(NOT IOS)
add_subdirectory(blockchain_utilities)
endif()
+if(CMAKE_BUILD_TYPE STREQUAL Debug)
+ add_subdirectory(debug_utilities)
+endif()
+
if(PER_BLOCK_CHECKPOINT)
add_subdirectory(blocks)
endif()
diff --git a/src/blockchain_utilities/CMakeLists.txt b/src/blockchain_utilities/CMakeLists.txt
index 628c037b3..ffdaad4af 100644
--- a/src/blockchain_utilities/CMakeLists.txt
+++ b/src/blockchain_utilities/CMakeLists.txt
@@ -67,11 +67,6 @@ monero_private_headers(blockchain_export
${blockchain_export_private_headers})
-set(cn_deserialize_sources
- cn_deserialize.cpp
- )
-
-
monero_add_executable(blockchain_import
${blockchain_import_sources}
${blockchain_import_private_headers}
@@ -122,21 +117,3 @@ set_property(TARGET blockchain_export
PROPERTY
OUTPUT_NAME "monero-blockchain-export")
-monero_add_executable(cn_deserialize
- ${cn_deserialize_sources}
- ${cn_deserialize_private_headers})
-
-target_link_libraries(cn_deserialize
- LINK_PRIVATE
- cryptonote_core
- blockchain_db
- p2p
- epee
- ${CMAKE_THREAD_LIBS_INIT})
-
-add_dependencies(cn_deserialize
- version)
-set_property(TARGET cn_deserialize
- PROPERTY
- OUTPUT_NAME "monero-utils-deserialize")
-
diff --git a/src/common/perf_timer.h b/src/common/perf_timer.h
index 56662ff24..bc8e05800 100644
--- a/src/common/perf_timer.h
+++ b/src/common/perf_timer.h
@@ -46,9 +46,9 @@ extern __thread std::vector<PerformanceTimer*> *performance_timers;
class PerformanceTimer
{
public:
- PerformanceTimer(const std::string &s, el::Level l = el::Level::Debug): name(s), level(l), started(false)
+ PerformanceTimer(const std::string &s, uint64_t unit, el::Level l = el::Level::Debug): name(s), unit(unit), level(l), started(false)
{
- ticks = epee::misc_utils::get_tick_count();
+ ticks = epee::misc_utils::get_ns_count();
if (!performance_timers)
{
MLOG(level, "PERF ----------");
@@ -69,9 +69,9 @@ public:
~PerformanceTimer()
{
performance_timers->pop_back();
- ticks = epee::misc_utils::get_tick_count() - ticks;
+ ticks = epee::misc_utils::get_ns_count() - ticks;
char s[12];
- snprintf(s, sizeof(s), "%8llu ", (unsigned long long)ticks);
+ snprintf(s, sizeof(s), "%8llu ", (unsigned long long)ticks / (1000000000 / unit));
MLOG(level, "PERF " << s << std::string(performance_timers->size() * 2, ' ') << " " << name);
if (performance_timers->empty())
{
@@ -82,6 +82,7 @@ public:
private:
std::string name;
+ uint64_t unit;
el::Level level;
uint64_t ticks;
bool started;
@@ -89,7 +90,9 @@ private:
void set_performance_timer_log_level(el::Level level);
-#define PERF_TIMER(name) tools::PerformanceTimer pt_##name(#name, tools::performance_timer_log_level)
-#define PERF_TIMER_L(name, l) tools::PerformanceTimer pt_##name(#name, l)
+#define PERF_TIMER_UNIT(name, unit) tools::PerformanceTimer pt_##name(#name, unit, tools::performance_timer_log_level)
+#define PERF_TIMER_UNIT_L(name, unit, l) tools::PerformanceTimer pt_##name(#name, unit, l)
+#define PERF_TIMER(name) PERF_TIMER_UNIT(name, 1000)
+#define PERF_TIMER_L(name, l) PERF_TIMER_UNIT_L(name, 1000, l)
}
diff --git a/src/cryptonote_basic/connection_context.h b/src/cryptonote_basic/connection_context.h
index fefd91e1a..06f66120b 100644
--- a/src/cryptonote_basic/connection_context.h
+++ b/src/cryptonote_basic/connection_context.h
@@ -39,6 +39,8 @@ namespace cryptonote
struct cryptonote_connection_context: public epee::net_utils::connection_context_base
{
+ cryptonote_connection_context(): m_state(state_befor_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
+ m_last_known_hash(cryptonote::null_hash) {}
enum state
{
@@ -55,6 +57,7 @@ namespace cryptonote
uint64_t m_last_response_height;
boost::posix_time::ptime m_last_request_time;
epee::copyable_atomic m_callback_request_count; //in debug purpose: problem with double callback rise
+ crypto::hash m_last_known_hash;
//size_t m_score; TODO: add score calculations
};
diff --git a/src/cryptonote_basic/difficulty.h b/src/cryptonote_basic/difficulty.h
index aed6cb289..aeb1c030d 100644
--- a/src/cryptonote_basic/difficulty.h
+++ b/src/cryptonote_basic/difficulty.h
@@ -42,9 +42,9 @@ namespace cryptonote
/**
* @brief checks if a hash fits the given difficulty
*
- * The hash passes if (hash * difficulty) < 2^192.
+ * The hash passes if (hash * difficulty) < 2^256.
* Phrased differently, if (hash * difficulty) fits without overflow into
- * the least significant 192 bits of the 256 bit multiplication result.
+ * the least significant 256 bits of the 320 bit multiplication result.
*
* @param hash the hash to check
* @param difficulty the difficulty to check against
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index 9248e2e1d..b14532d44 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -382,7 +382,7 @@ namespace cryptonote
boost::thread::attributes attrs;
attrs.set_stack_size(THREAD_STACK_SIZE);
- start(m_mine_address, m_threads_total, attrs, get_is_background_mining_enabled());
+ start(m_mine_address, m_threads_total, attrs, get_is_background_mining_enabled(), get_ignore_battery());
}
}
//-----------------------------------------------------------------------------------------------------
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 404321e0f..61ddff3d0 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -125,8 +125,8 @@ static const uint64_t testnet_hard_fork_version_1_till = 624633;
//------------------------------------------------------------------
Blockchain::Blockchain(tx_memory_pool& tx_pool) :
- m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false),
- m_is_blockchain_storing(false), m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false)
+ m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0),
+ m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false)
{
LOG_PRINT_L3("Blockchain::" << __func__);
}
@@ -1353,7 +1353,6 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
}
// Check the block's hash against the difficulty target for its alt chain
- m_is_in_checkpoint_zone = false;
difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei);
CHECK_AND_ASSERT_MES(current_diff, false, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!");
crypto::hash proof_of_work = null_hash;
@@ -1428,7 +1427,9 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
{
//block orphaned
bvc.m_marked_as_orphaned = true;
- MERROR_VER("Block recognized as orphaned and rejected, id = " << id);
+ MERROR_VER("Block recognized as orphaned and rejected, id = " << id << ", height " << block_height
+ << ", parent in alt " << (it_prev != m_alternative_chains.end()) << ", parent in main " << parent_in_main
+ << " (parent " << b.prev_id << ", current top " << get_tail_id() << ", chain height " << get_current_blockchain_height() << ")");
}
return true;
@@ -2499,7 +2500,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
assert(it != m_check_txin_table.end());
}
- uint64_t t_t1 = 0;
std::vector<std::vector<rct::ctkey>> pubkeys(tx.vin.size());
std::vector < uint64_t > results;
results.resize(tx.vin.size(), 0);
@@ -2633,7 +2633,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
if (failed)
{
- MERROR_VER("Failed to check ring signatures!, t_loop: " << t_t1);
+ MERROR_VER("Failed to check ring signatures!");
return false;
}
}
@@ -2782,12 +2782,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
//------------------------------------------------------------------
void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const crypto::key_image &key_image, const std::vector<rct::ctkey> &pubkeys, const std::vector<crypto::signature>& sig, uint64_t &result)
{
- if (m_is_in_checkpoint_zone)
- {
- result = true;
- return;
- }
-
std::vector<const crypto::public_key *> p_output_keys;
for (auto &key : pubkeys)
{
@@ -3883,17 +3877,17 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
offset_map[in_to_key.amount].push_back(offset);
}
-
- // sort and remove duplicate absolute_offsets in offset_map
- for (auto &offsets : offset_map)
- {
- std::sort(offsets.second.begin(), offsets.second.end());
- auto last = std::unique(offsets.second.begin(), offsets.second.end());
- offsets.second.erase(last, offsets.second.end());
- }
}
}
+ // sort and remove duplicate absolute_offsets in offset_map
+ for (auto &offsets : offset_map)
+ {
+ std::sort(offsets.second.begin(), offsets.second.end());
+ auto last = std::unique(offsets.second.begin(), offsets.second.end());
+ offsets.second.erase(last, offsets.second.end());
+ }
+
// [output] stores all transactions for each tx_out_index::hash found
std::vector<std::unordered_map<crypto::hash, cryptonote::transaction>> transactions(amounts.size());
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index bd8a8313c..7137f50a7 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -585,7 +585,7 @@ namespace cryptonote
*
* @return true if Blockchain is having the chain stored currently, else false
*/
- bool is_storing_blockchain()const{return m_is_blockchain_storing;}
+ bool is_storing_blockchain()const{return false;}
/**
* @brief gets the difficulty of the block with a given height
@@ -746,6 +746,15 @@ namespace cryptonote
uint8_t get_ideal_hard_fork_version(uint64_t height) const { return m_hardfork->get_ideal_version(height); }
/**
+ * @brief returns the actual hardfork version for a given block height
+ *
+ * @param height the height for which to check version info
+ *
+ * @return the version
+ */
+ uint8_t get_hard_fork_version(uint64_t height) const { return m_hardfork->get(height); }
+
+ /**
* @brief get information about hardfork voting for a version
*
* @param version the version in question
@@ -934,8 +943,6 @@ namespace cryptonote
checkpoints m_checkpoints;
- std::atomic<bool> m_is_in_checkpoint_zone;
- std::atomic<bool> m_is_blockchain_storing;
bool m_enforce_dns_checkpoints;
HardFork *m_hardfork;
diff --git a/src/cryptonote_protocol/block_queue.cpp b/src/cryptonote_protocol/block_queue.cpp
index 583c3abf4..4f760582b 100644
--- a/src/cryptonote_protocol/block_queue.cpp
+++ b/src/cryptonote_protocol/block_queue.cpp
@@ -118,25 +118,6 @@ void block_queue::remove_spans(const boost::uuids::uuid &connection_id, uint64_t
}
}
-void block_queue::mark_last_block(uint64_t last_block_height)
-{
- boost::unique_lock<boost::recursive_mutex> lock(mutex);
- if (!blocks.empty() && is_blockchain_placeholder(*blocks.begin()))
- blocks.erase(*blocks.begin());
- for (block_map::iterator i = blocks.begin(); i != blocks.end(); )
- {
- block_map::iterator j = i++;
- if (j->start_block_height + j->nblocks - 1 <= last_block_height)
- {
- blocks.erase(j);
- }
- }
-
- // mark the current state of the db (for a fresh db, it's just the genesis block)
- add_blocks(0, last_block_height + 1, boost::uuids::nil_uuid());
- MDEBUG("last blocked marked at " << last_block_height);
-}
-
uint64_t block_queue::get_max_block_height() const
{
boost::unique_lock<boost::recursive_mutex> lock(mutex);
@@ -171,7 +152,19 @@ std::string block_queue::get_overview() const
return s;
}
-std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, boost::posix_time::ptime time)
+bool block_queue::requested(const crypto::hash &hash) const
+{
+ boost::unique_lock<boost::recursive_mutex> lock(mutex);
+ for (const auto &span: blocks)
+ {
+ for (const auto &h: span.hashes)
+ if (h == hash)
+ return true;
+ }
+ return false;
+}
+
+std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, const std::list<crypto::hash> &block_hashes, boost::posix_time::ptime time)
{
boost::unique_lock<boost::recursive_mutex> lock(mutex);
@@ -181,71 +174,27 @@ std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_hei
return std::make_pair(0, 0);
}
- uint64_t max_block_height = get_max_block_height();
- if (last_block_height > max_block_height)
- max_block_height = last_block_height;
- if (max_block_height == 0)
+ uint64_t span_start_height = last_block_height - block_hashes.size() + 1;
+ std::list<crypto::hash>::const_iterator i = block_hashes.begin();
+ while (i != block_hashes.end() && requested(*i))
{
- MDEBUG("reserve_span: max_block_height is 0");
- return std::make_pair(first_block_height, std::min(last_block_height - first_block_height + 1, max_blocks));
- }
-
- uint64_t base = 0, last_placeholder_block = 0;
- bool has_placeholder = false;
- block_map::const_iterator i = blocks.begin();
- if (i != blocks.end() && is_blockchain_placeholder(*i))
- {
- base = i->start_block_height + i->nblocks;
- last_placeholder_block = base - 1;
- has_placeholder = true;
++i;
- for (block_map::const_iterator j = i; j != blocks.end(); ++j)
- {
- if (j->start_block_height < base)
- base = j->start_block_height;
- }
+ ++span_start_height;
}
- if (base > first_block_height)
- base = first_block_height;
-
- CHECK_AND_ASSERT_MES (base <= max_block_height + 1, std::make_pair(0, 0), "Blockchain placeholder larger than max block height");
- std::vector<uint8_t> bitmap(max_block_height + 1 - base, 0);
- MDEBUG("base " << base << ", last_placeholder_block " << (has_placeholder ? std::to_string(last_placeholder_block) : "none") << ", first_block_height " << first_block_height);
- if (has_placeholder && last_placeholder_block >= base)
- memset(bitmap.data(), 1, last_placeholder_block + 1 - base);
- while (i != blocks.end())
+ uint64_t span_length = 0;
+ std::list<crypto::hash> hashes;
+ while (i != block_hashes.end() && span_length < max_blocks)
{
- CHECK_AND_ASSERT_MES (i->start_block_height >= base, std::make_pair(0, 0), "Span starts before blochckain placeholder");
- memset(bitmap.data() + i->start_block_height - base, 1, i->nblocks);
+ hashes.push_back(*i);
++i;
+ ++span_length;
}
-
- const uint8_t *ptr = (const uint8_t*)memchr(bitmap.data() + first_block_height - base, 0, bitmap.size() - (first_block_height - base));
- if (!ptr)
- {
- MDEBUG("reserve_span: 0 not found in bitmap: " << first_block_height << " " << bitmap.size());
- print();
- return std::make_pair(0, 0);
- }
- uint64_t start_block_height = ptr - bitmap.data() + base;
- if (start_block_height > last_block_height)
- {
- MDEBUG("reserve_span: start_block_height > last_block_height: " << start_block_height << " < " << last_block_height);
- return std::make_pair(0, 0);
- }
- if (start_block_height + max_blocks - 1 < first_block_height)
- {
- MDEBUG("reserve_span: start_block_height + max_blocks - 1 < first_block_height: " << start_block_height << " + " << max_blocks << " - 1 < " << first_block_height);
+ if (span_length == 0)
return std::make_pair(0, 0);
- }
-
- uint64_t nblocks = 1;
- while (start_block_height + nblocks <= last_block_height && nblocks < max_blocks && bitmap[start_block_height + nblocks - base] == 0)
- ++nblocks;
-
- MDEBUG("Reserving span " << start_block_height << " - " << (start_block_height + nblocks - 1) << " for " << connection_id);
- add_blocks(start_block_height, nblocks, connection_id, time);
- return std::make_pair(start_block_height, nblocks);
+ MDEBUG("Reserving span " << span_start_height << " - " << (span_start_height + span_length - 1) << " for " << connection_id);
+ add_blocks(span_start_height, span_length, connection_id, time);
+ set_span_hashes(span_start_height, connection_id, hashes);
+ return std::make_pair(span_start_height, span_length);
}
bool block_queue::is_blockchain_placeholder(const span &span) const
@@ -366,13 +315,15 @@ size_t block_queue::get_num_filled_spans() const
return size;
}
-crypto::hash block_queue::get_last_known_hash() const
+crypto::hash block_queue::get_last_known_hash(const boost::uuids::uuid &connection_id) const
{
boost::unique_lock<boost::recursive_mutex> lock(mutex);
crypto::hash hash = cryptonote::null_hash;
uint64_t highest_height = 0;
for (const auto &span: blocks)
{
+ if (span.connection_id != connection_id)
+ continue;
uint64_t h = span.start_block_height + span.nblocks - 1;
if (h > highest_height && span.hashes.size() == span.nblocks)
{
diff --git a/src/cryptonote_protocol/block_queue.h b/src/cryptonote_protocol/block_queue.h
index c75ebc0b9..9a211ac47 100644
--- a/src/cryptonote_protocol/block_queue.h
+++ b/src/cryptonote_protocol/block_queue.h
@@ -73,11 +73,10 @@ namespace cryptonote
void flush_stale_spans(const std::set<boost::uuids::uuid> &live_connections);
void remove_span(uint64_t start_block_height);
void remove_spans(const boost::uuids::uuid &connection_id, uint64_t start_block_height);
- void mark_last_block(uint64_t last_block_height);
uint64_t get_max_block_height() const;
void print() const;
std::string get_overview() const;
- std::pair<uint64_t, uint64_t> reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, boost::posix_time::ptime time = boost::posix_time::microsec_clock::universal_time());
+ std::pair<uint64_t, uint64_t> reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, const std::list<crypto::hash> &block_hashes, boost::posix_time::ptime time = boost::posix_time::microsec_clock::universal_time());
bool is_blockchain_placeholder(const span &span) const;
std::pair<uint64_t, uint64_t> get_start_gap_span() const;
std::pair<uint64_t, uint64_t> get_next_span_if_scheduled(std::list<crypto::hash> &hashes, boost::uuids::uuid &connection_id, boost::posix_time::ptime &time) const;
@@ -86,9 +85,10 @@ namespace cryptonote
size_t get_data_size() const;
size_t get_num_filled_spans_prefix() const;
size_t get_num_filled_spans() const;
- crypto::hash get_last_known_hash() const;
+ crypto::hash get_last_known_hash(const boost::uuids::uuid &connection_id) const;
float get_speed(const boost::uuids::uuid &connection_id) const;
bool foreach(std::function<bool(const span&)> f, bool include_blockchain_placeholder = false) const;
+ bool requested(const crypto::hash &hash) const;
private:
block_map blocks;
diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h
index 042ae49f6..6e6c83f04 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_defs.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h
@@ -76,6 +76,8 @@ namespace cryptonote
boost::uuids::uuid connection_id;
+ uint64_t height;
+
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(incoming)
KV_SERIALIZE(localhost)
@@ -97,6 +99,7 @@ namespace cryptonote
KV_SERIALIZE(current_upload)
KV_SERIALIZE(support_flags)
KV_SERIALIZE_VAL_POD_AS_BLOB(connection_id)
+ KV_SERIALIZE(height)
END_KV_SERIALIZE_MAP()
};
@@ -195,10 +198,12 @@ namespace cryptonote
{
uint64_t current_height;
crypto::hash top_id;
+ uint8_t top_version;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(current_height)
KV_SERIALIZE_VAL_POD_AS_BLOB(top_id)
+ KV_SERIALIZE_OPT(top_version, (uint8_t)0)
END_KV_SERIALIZE_MAP()
};
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 4652bf23e..0e79c0e48 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -239,6 +239,8 @@ namespace cryptonote
cnx.connection_id = cntxt.m_connection_id;
+ cnx.height = cntxt.m_remote_blockchain_height;
+
connections.push_back(cnx);
return true;
@@ -256,6 +258,16 @@ namespace cryptonote
if(context.m_state == cryptonote_connection_context::state_synchronizing)
return true;
+ // from v6, if the peer advertises a top block version, reject if it's not what it should be (will only work if no voting)
+ const uint8_t version = m_core.get_blockchain_storage().get_ideal_hard_fork_version(hshd.current_height - 1);
+ if (version >= 6 && version != hshd.top_version)
+ {
+ LOG_DEBUG_CC(context, "Ignoring due to wrong top version (" << hshd.top_version << ", expected " << version);
+ return false;
+ }
+
+ context.m_remote_blockchain_height = hshd.current_height;
+
uint64_t target = m_core.get_target_blockchain_height();
if (target == 0)
target = m_core.get_current_blockchain_height();
@@ -285,7 +297,6 @@ namespace cryptonote
}
LOG_PRINT_L1("Remote blockchain height: " << hshd.current_height << ", id: " << hshd.top_id);
context.m_state = cryptonote_connection_context::state_synchronizing;
- context.m_remote_blockchain_height = hshd.current_height;
//let the socket to send response to handshake, but request callback, to let send request data after response
LOG_PRINT_CCONTEXT_L2("requesting callback");
++context.m_callback_request_count;
@@ -297,6 +308,7 @@ namespace cryptonote
bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(CORE_SYNC_DATA& hshd)
{
m_core.get_blockchain_top(hshd.current_height, hshd.top_id);
+ hshd.top_version = m_core.get_blockchain_storage().get_hard_fork_version(hshd.current_height);
hshd.current_height +=1;
return true;
}
@@ -348,6 +360,7 @@ namespace cryptonote
{
LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
m_p2p->drop_connection(context);
+ m_p2p->add_host_fail(context.m_remote_address);
m_block_queue.flush_spans(context.m_connection_id);
return 1;
}
@@ -616,6 +629,7 @@ namespace cryptonote
{
LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
m_p2p->drop_connection(context);
+ m_p2p->add_host_fail(context.m_remote_address);
m_block_queue.flush_spans(context.m_connection_id);
return 1;
}
@@ -936,7 +950,8 @@ namespace cryptonote
}
{
- MLOG_YELLOW(el::Level::Debug, "Got NEW BLOCKS inside of " << __FUNCTION__ << ": size: " << arg.blocks.size());
+ MLOG_YELLOW(el::Level::Debug, context << " Got NEW BLOCKS inside of " << __FUNCTION__ << ": size: " << arg.blocks.size()
+ << ", blocks: " << start_height << " - " << (start_height + arg.blocks.size() - 1));
// add that new span to the block queue
const boost::posix_time::time_duration dt = now - context.m_last_request_time;
@@ -944,6 +959,8 @@ namespace cryptonote
MDEBUG(context << " adding span: " << arg.blocks.size() << " at height " << start_height << ", " << dt.total_microseconds()/1e6 << " seconds, " << (rate/1e3) << " kB/s, size now " << (m_block_queue.get_data_size() + blocks_size) / 1048576.f << " MB");
m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, rate, blocks_size);
+ context.m_last_known_hash = cryptonote::get_blob_hash(arg.blocks.back().block);
+
if (m_core.get_test_drop_download() && m_core.get_test_drop_download_height()) { // DISCARD BLOCKS for testing
// We try to lock the sync lock. If we can, it means no other thread is
@@ -967,7 +984,6 @@ namespace cryptonote
uint64_t start_height;
std::list<cryptonote::block_complete_entry> blocks;
boost::uuids::uuid span_connection_id;
- m_block_queue.mark_last_block(previous_height - 1);
if (!m_block_queue.get_next_span(start_height, blocks, span_connection_id))
{
MDEBUG(context << " no next span found, going back to download");
@@ -975,9 +991,41 @@ namespace cryptonote
}
MDEBUG(context << " next span in the queue has blocks " << start_height << "-" << (start_height + blocks.size() - 1)
<< ", we need " << previous_height);
- if (previous_height < start_height || previous_height >= start_height + blocks.size())
+
+
+ block new_block;
+ if (!parse_and_validate_block_from_blob(blocks.front().block, new_block))
{
- MDEBUG(context << " this span is not what we need, going back to download");
+ MERROR("Failed to parse block, but it should already have been parsed");
+ break;
+ }
+ bool parent_known = m_core.have_block(new_block.prev_id);
+ if (!parent_known)
+ {
+ // it could be:
+ // - later in the current chain
+ // - later in an alt chain
+ // - orphan
+ // if it was requested, then it'll be resolved later, otherwise it's an orphan
+ bool parent_requested = false;
+ m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
+ if (context.m_requested_objects.find(new_block.prev_id) != context.m_requested_objects.end())
+ {
+ parent_requested = true;
+ return false;
+ }
+ return true;
+ });
+ if (!parent_requested)
+ {
+ LOG_ERROR_CCONTEXT("Got block with unknown parent which was not requested - dropping connection");
+ // in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
+ m_block_queue.remove_spans(span_connection_id, start_height);
+ return 1;
+ }
+
+ // parent was requested, so we wait for it to be retrieved
+ MINFO(context << " parent was requested, we'll get back to it");
break;
}
@@ -1072,7 +1120,7 @@ namespace cryptonote
m_core.cleanup_handle_incoming_blocks();
- m_block_queue.mark_last_block(m_core.get_current_blockchain_height() - 1);
+ m_block_queue.remove_spans(span_connection_id, start_height);
if (m_core.get_current_blockchain_height() > previous_height)
{
@@ -1190,8 +1238,6 @@ skip:
template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::request_missing_objects(cryptonote_connection_context& context, bool check_having_blocks, bool force_next_span)
{
- m_block_queue.mark_last_block(m_core.get_current_blockchain_height() - 1);
-
// flush stale spans
std::set<boost::uuids::uuid> live_connections;
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
@@ -1297,8 +1343,13 @@ skip:
context.m_last_response_height = 0;
goto skip;
}
+ // take out blocks we already have
+ while (!context.m_needed_objects.empty() && m_core.have_block(context.m_needed_objects.front()))
+ {
+ context.m_needed_objects.pop_front();
+ }
const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
- span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id);
+ span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, context.m_needed_objects);
MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second);
}
if (span.second == 0 && !force_next_span)
@@ -1349,8 +1400,6 @@ skip:
auto j = it++;
context.m_needed_objects.erase(j);
}
-
- m_block_queue.set_span_hashes(span.first, context.m_connection_id, hashes);
}
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
@@ -1373,10 +1422,9 @@ skip:
if (!start_from_current_chain)
{
- // we'll want to start off from where we are on the download side, which may not be added yet
- crypto::hash last_known_hash = m_block_queue.get_last_known_hash();
- if (last_known_hash != cryptonote::null_hash && r.block_ids.front() != last_known_hash)
- r.block_ids.push_front(last_known_hash);
+ // we'll want to start off from where we are on that peer, which may not be added yet
+ if (context.m_last_known_hash != cryptonote::null_hash && r.block_ids.front() != context.m_last_known_hash)
+ r.block_ids.push_front(context.m_last_known_hash);
}
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 34d87d282..995fee484 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -1742,7 +1742,7 @@ bool t_rpc_command_executor::sync_info()
for (const auto &s: res.spans)
if (s.rate > 0.0f && s.connection_id == p.info.connection_id)
nblocks += s.nblocks, size += s.size;
- tools::success_msg_writer() << address << " " << p.info.peer_id << " " << p.info.current_download << " kB/s, " << nblocks << " blocks / " << size/1e6 << " MB queued";
+ tools::success_msg_writer() << address << " " << p.info.peer_id << " " << p.info.height << " " << p.info.current_download << " kB/s, " << nblocks << " blocks / " << size/1e6 << " MB queued";
}
uint64_t total_size = 0;
diff --git a/src/debug_utilities/CMakeLists.txt b/src/debug_utilities/CMakeLists.txt
new file mode 100644
index 000000000..99198dc57
--- /dev/null
+++ b/src/debug_utilities/CMakeLists.txt
@@ -0,0 +1,73 @@
+# Copyright (c) 2014-2017, The Monero Project
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of
+# conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list
+# of conditions and the following disclaimer in the documentation and/or other
+# materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors may be
+# used to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set(cn_deserialize_sources
+ cn_deserialize.cpp
+ )
+
+monero_add_executable(cn_deserialize
+ ${cn_deserialize_sources}
+ ${cn_deserialize_private_headers})
+
+target_link_libraries(cn_deserialize
+ LINK_PRIVATE
+ cryptonote_core
+ blockchain_db
+ p2p
+ epee
+ ${CMAKE_THREAD_LIBS_INIT})
+
+add_dependencies(cn_deserialize
+ version)
+set_property(TARGET cn_deserialize
+ PROPERTY
+ OUTPUT_NAME "monero-utils-deserialize")
+
+
+set(object_sizes_sources
+ object_sizes.cpp
+ )
+
+monero_add_executable(object_sizes
+ ${object_sizes_sources}
+ ${object_sizes_private_headers})
+
+target_link_libraries(object_sizes
+ LINK_PRIVATE
+ cryptonote_core
+ blockchain_db
+ p2p
+ epee
+ ${CMAKE_THREAD_LIBS_INIT})
+
+add_dependencies(object_sizes
+ version)
+set_property(TARGET object_sizes
+ PROPERTY
+ OUTPUT_NAME "monero-utils-object-sizes")
+
diff --git a/src/blockchain_utilities/cn_deserialize.cpp b/src/debug_utilities/cn_deserialize.cpp
index b178e4e03..a1b569554 100644
--- a/src/blockchain_utilities/cn_deserialize.cpp
+++ b/src/debug_utilities/cn_deserialize.cpp
@@ -29,12 +29,11 @@
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/tx_extra.h"
#include "cryptonote_core/blockchain.h"
-#include "blockchain_utilities.h"
#include "common/command_line.h"
#include "version.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
-#define MONERO_DEFAULT_LOG_CATEGORY "bcutil"
+#define MONERO_DEFAULT_LOG_CATEGORY "debugtools.deserialize"
namespace po = boost::program_options;
using namespace epee;
diff --git a/src/debug_utilities/object_sizes.cpp b/src/debug_utilities/object_sizes.cpp
new file mode 100644
index 000000000..47ba5cf6c
--- /dev/null
+++ b/src/debug_utilities/object_sizes.cpp
@@ -0,0 +1,116 @@
+// Copyright (c) 2017, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <map>
+#include "cryptonote_basic/cryptonote_basic.h"
+#include "cryptonote_basic/tx_extra.h"
+#include "cryptonote_core/blockchain.h"
+#include "p2p/p2p_protocol_defs.h"
+#include "p2p/connection_basic.hpp"
+#include "p2p/net_peerlist.h"
+#include "p2p/net_node.h"
+#include "cryptonote_protocol/cryptonote_protocol_handler.h"
+#include "blockchain_db/lmdb/db_lmdb.h"
+#include "wallet/wallet2.h"
+#include "wallet/api/wallet.h"
+#include "wallet/api/transaction_info.h"
+#include "wallet/api/transaction_history.h"
+#include "wallet/api/unsigned_transaction.h"
+#include "wallet/api/pending_transaction.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "debugtools.objectsizes"
+
+class size_logger
+{
+public:
+ ~size_logger()
+ {
+ for (const auto i: types)
+ std::cout << std::to_string(i.first) << "\t" << i.second << std::endl;
+ }
+ void add(const char *type, size_t size) { types.insert(std::make_pair(size, type)); }
+private:
+ std::multimap<size_t, const std::string> types;
+};
+#define SL(type) sl.add(#type, sizeof(type))
+
+int main(int argc, char* argv[])
+{
+ size_logger sl;
+
+ tools::sanitize_locale();
+
+ mlog_configure("", true);
+
+ SL(boost::thread);
+ SL(boost::asio::io_service);
+ SL(boost::asio::io_service::work);
+ SL(boost::asio::deadline_timer);
+
+ SL(cryptonote::DB_ERROR);
+ SL(cryptonote::mdb_txn_safe);
+ SL(cryptonote::mdb_threadinfo);
+
+ SL(cryptonote::block_header);
+ SL(cryptonote::block);
+ SL(cryptonote::transaction_prefix);
+ SL(cryptonote::transaction);
+
+ SL(cryptonote::txpool_tx_meta_t);
+
+ SL(epee::net_utils::network_address_base);
+ SL(epee::net_utils::ipv4_network_address);
+ SL(epee::net_utils::network_address);
+ SL(epee::net_utils::connection_context_base);
+ SL(epee::net_utils::connection_basic);
+
+ SL(nodetool::peerlist_entry);
+ SL(nodetool::anchor_peerlist_entry);
+ SL(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core>>);
+ SL(nodetool::p2p_connection_context_t<cryptonote::t_cryptonote_protocol_handler<cryptonote::core>::connection_context>);
+ SL(nodetool::network_address_old);
+
+ SL(tools::wallet2::transfer_details);
+ SL(tools::wallet2::payment_details);
+ SL(tools::wallet2::unconfirmed_transfer_details);
+ SL(tools::wallet2::confirmed_transfer_details);
+ SL(tools::wallet2::tx_construction_data);
+ SL(tools::wallet2::pending_tx);
+ SL(tools::wallet2::unsigned_tx_set);
+ SL(tools::wallet2::signed_tx_set);
+
+ SL(Monero::WalletImpl);
+ SL(Monero::AddressBookRow);
+ SL(Monero::TransactionInfoImpl);
+ SL(Monero::TransactionHistoryImpl);
+ SL(Monero::PendingTransactionImpl);
+ SL(Monero::UnsignedTransactionImpl);
+
+ return 0;
+}
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index fb7cebde2..4e1e60d27 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -61,7 +61,7 @@ namespace nodetool
template<class base_type>
struct p2p_connection_context_t: base_type //t_payload_net_handler::connection_context //public net_utils::connection_context_base
{
- p2p_connection_context_t(): support_flags(0), m_in_timedsync(false) {}
+ p2p_connection_context_t(): peer_id(0), support_flags(0), m_in_timedsync(false) {}
peerid_type peer_id;
uint32_t support_flags;
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index a977f17b7..58a7f3563 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -1678,6 +1678,7 @@ namespace nodetool
//associate peer_id with this connection
context.peer_id = arg.node_data.peer_id;
+ context.m_in_timedsync = false;
if(arg.node_data.peer_id != m_config.m_peer_id && arg.node_data.my_port)
{
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 596c298d7..aa9fe2bca 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -919,14 +919,19 @@ bool simple_wallet::ask_wallet_create_if_needed()
}
else if(!wallet_file_exists && !keys_file_exists) //No wallet, no keys
{
- message_writer() << tr(m_restoring ? "Confirm wallet name: " : "No wallet found with that name. Confirm creation of new wallet named: ") << wallet_path;
- confirm_creation = command_line::input_line(tr("(Y/Yes/N/No): "));
- if(std::cin.eof())
+ bool ok = true;
+ if (!m_restoring)
{
- LOG_ERROR("Unexpected std::cin.eof() - Exited simple_wallet::ask_wallet_create_if_needed()");
- return false;
+ message_writer() << tr("No wallet found with that name. Confirm creation of new wallet named: ") << wallet_path;
+ confirm_creation = command_line::input_line(tr("(Y/Yes/N/No): "));
+ if(std::cin.eof())
+ {
+ LOG_ERROR("Unexpected std::cin.eof() - Exited simple_wallet::ask_wallet_create_if_needed()");
+ return false;
+ }
+ ok = command_line::is_yes(confirm_creation);
}
- if(command_line::is_yes(confirm_creation))
+ if (ok)
{
success_msg_writer() << tr("Generating new wallet...");
m_generate_new = wallet_path;
@@ -1093,7 +1098,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse spend secret key
- std::string spendkey_string = command_line::input_line("Spend key: ");
+ std::string spendkey_string = command_line::input_line("Secret spend key: ");
if (std::cin.eof())
return false;
if (spendkey_string.empty()) {
@@ -1109,7 +1114,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
crypto::secret_key spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data());
// parse view secret key
- std::string viewkey_string = command_line::input_line("View key: ");
+ std::string viewkey_string = command_line::input_line("Secret view key: ");
if (std::cin.eof())
return false;
if (viewkey_string.empty()) {
@@ -3867,6 +3872,22 @@ static std::string get_human_readable_timestamp(uint64_t ts)
return std::string(buffer);
}
//----------------------------------------------------------------------------------------------------
+static std::string get_human_readable_timespan(std::chrono::seconds seconds)
+{
+ uint64_t ts = seconds.count();
+ if (ts < 60)
+ return std::to_string(ts) + tr(" seconds");
+ if (ts < 3600)
+ return std::to_string((uint64_t)(ts / 60)) + tr(" minutes");
+ if (ts < 3600 * 24)
+ return std::to_string((uint64_t)(ts / 3600)) + tr(" hours");
+ if (ts < 3600 * 24 * 30.5)
+ return std::to_string((uint64_t)(ts / (3600 * 24))) + tr(" days");
+ if (ts < 3600 * 24 * 365.25)
+ return std::to_string((uint64_t)(ts / (3600 * 24 * 365.25))) + tr(" months");
+ return tr("a long time");
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
{
std::vector<std::string> local_args = args_;
@@ -4175,6 +4196,19 @@ void simple_wallet::wallet_idle_thread()
}
}
//----------------------------------------------------------------------------------------------------
+std::string simple_wallet::get_prompt() const
+{
+ std::string addr_start = m_wallet->get_account().get_public_address_str(m_wallet->testnet()).substr(0, 6);
+ std::string prompt = std::string("[") + tr("wallet") + " " + addr_start;
+ uint32_t version;
+ if (!m_wallet->check_connection(&version))
+ prompt += tr(" (no daemon)");
+ else if (!m_wallet->is_synced())
+ prompt += tr(" (out of sync)");
+ prompt += "]: ";
+ return prompt;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::run()
{
// check and display warning, but go on anyway
@@ -4185,9 +4219,8 @@ bool simple_wallet::run()
m_auto_refresh_enabled = m_wallet->auto_refresh();
m_idle_thread = boost::thread([&]{wallet_idle_thread();});
- std::string addr_start = m_wallet->get_account().get_public_address_str(m_wallet->testnet()).substr(0, 6);
message_writer(console_color_green, false) << "Background refresh thread started";
- return m_cmd_binder.run_handling(std::string("[") + tr("wallet") + " " + addr_start + "]: ", "");
+ return m_cmd_binder.run_handling([this](){return get_prompt();}, "");
}
//----------------------------------------------------------------------------------------------------
void simple_wallet::stop()
@@ -4673,6 +4706,8 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args)
}
crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
+ const uint64_t last_block_height = m_wallet->get_blockchain_current_height();
+
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
m_wallet->get_payments(payments, 0);
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
@@ -4687,6 +4722,23 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args)
success_msg_writer() << "Timestamp: " << get_human_readable_timestamp(pd.m_timestamp);
success_msg_writer() << "Amount: " << print_money(pd.m_amount);
success_msg_writer() << "Payment ID: " << payment_id;
+ if (pd.m_unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER)
+ {
+ uint64_t bh = std::max(pd.m_unlock_time, pd.m_block_height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE);
+ if (bh >= last_block_height)
+ success_msg_writer() << "Locked: " << (bh - last_block_height) << " blocks to unlock";
+ else
+ success_msg_writer() << std::to_string(last_block_height - bh) << " confirmations";
+ }
+ else
+ {
+ uint64_t current_time = static_cast<uint64_t>(time(NULL));
+ uint64_t threshold = current_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1);
+ if (threshold >= pd.m_unlock_time)
+ success_msg_writer() << "unlocked for " << get_human_readable_timespan(std::chrono::seconds(threshold - pd.m_unlock_time));
+ else
+ success_msg_writer() << "locked for " << get_human_readable_timespan(std::chrono::seconds(pd.m_unlock_time - threshold));
+ }
success_msg_writer() << "Note: " << m_wallet->get_tx_note(txid);
return true;
}
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 1fb85a3c7..cca5d4928 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -182,6 +182,7 @@ namespace cryptonote
bool accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs);
bool accept_loaded_tx(const tools::wallet2::signed_tx_set &txs);
bool print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr);
+ std::string get_prompt() const;
/*!
* \brief Prints the seed with a nice message
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index b2f947972..a23533530 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -125,6 +125,10 @@ bool WalletManagerImpl::walletExists(const std::string &path)
return false;
}
+bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool watch_only) const
+{
+ return tools::wallet2::verify_password(keys_file_name, password, watch_only);
+}
std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path)
{
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index 033e8108f..aa6ea439e 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -50,6 +50,7 @@ public:
const std::string &spendKeyString = "");
virtual bool closeWallet(Wallet *wallet);
bool walletExists(const std::string &path);
+ bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool watch_only) const;
std::vector<std::string> findWallets(const std::string &path);
std::string errorString() const;
void setDaemonAddress(const std::string &address);
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp
index 1143a89d7..9f30e4ac5 100644
--- a/src/wallet/node_rpc_proxy.cpp
+++ b/src/wallet/node_rpc_proxy.cpp
@@ -48,6 +48,8 @@ NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_clien
, m_dynamic_per_kb_fee_estimate_cached_height(0)
, m_dynamic_per_kb_fee_estimate_grace_blocks(0)
, m_rpc_version(0)
+ , m_target_height(0)
+ , m_target_height_time(0)
{}
void NodeRPCProxy::invalidate()
@@ -60,9 +62,11 @@ void NodeRPCProxy::invalidate()
m_dynamic_per_kb_fee_estimate_cached_height = 0;
m_dynamic_per_kb_fee_estimate_grace_blocks = 0;
m_rpc_version = 0;
+ m_target_height = 0;
+ m_target_height_time = 0;
}
-boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version)
+boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version) const
{
const time_t now = time(NULL);
if (m_rpc_version == 0)
@@ -84,7 +88,7 @@ boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version
return boost::optional<std::string>();
}
-boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height)
+boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height) const
{
const time_t now = time(NULL);
if (m_height == 0 || now >= m_height_time + 30) // re-cache every 30 seconds
@@ -110,7 +114,32 @@ void NodeRPCProxy::set_height(uint64_t h)
m_height = h;
}
-boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height)
+boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) const
+{
+ const time_t now = time(NULL);
+ if (m_height == 0 || now >= m_height_time + 30) // re-cache every 30 seconds
+ {
+ epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_INFO::request> req_t = AUTO_VAL_INIT(req_t);
+ epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_INFO::response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
+
+ req_t.jsonrpc = "2.0";
+ req_t.id = epee::serialization::storage_entry(0);
+ req_t.method = "get_info";
+ m_daemon_rpc_mutex.lock();
+ bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client, rpc_timeout);
+ m_daemon_rpc_mutex.unlock();
+
+ CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon");
+ CHECK_AND_ASSERT_MES(resp_t.result.status != CORE_RPC_STATUS_BUSY, resp_t.result.status, "Failed to connect to daemon");
+ CHECK_AND_ASSERT_MES(resp_t.result.status == CORE_RPC_STATUS_OK, resp_t.result.status, "Failed to get target blockchain height");
+ m_target_height = resp_t.result.target_height;
+ m_target_height_time = now;
+ }
+ height = m_target_height;
+ return boost::optional<std::string>();
+}
+
+boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height) const
{
if (m_earliest_height[version] == 0)
{
@@ -134,7 +163,7 @@ boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version,
return boost::optional<std::string>();
}
-boost::optional<std::string> NodeRPCProxy::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee)
+boost::optional<std::string> NodeRPCProxy::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const
{
uint64_t height;
diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h
index 02d1d8d93..fb288189a 100644
--- a/src/wallet/node_rpc_proxy.h
+++ b/src/wallet/node_rpc_proxy.h
@@ -43,23 +43,26 @@ public:
void invalidate();
- boost::optional<std::string> get_rpc_version(uint32_t &version);
- boost::optional<std::string> get_height(uint64_t &height);
+ boost::optional<std::string> get_rpc_version(uint32_t &version) const;
+ boost::optional<std::string> get_height(uint64_t &height) const;
void set_height(uint64_t h);
- boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height);
- boost::optional<std::string> get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee);
+ boost::optional<std::string> get_target_height(uint64_t &height) const;
+ boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height) const;
+ boost::optional<std::string> get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const;
private:
epee::net_utils::http::http_simple_client &m_http_client;
boost::mutex &m_daemon_rpc_mutex;
- uint64_t m_height;
- time_t m_height_time;
- uint64_t m_earliest_height[256];
- uint64_t m_dynamic_per_kb_fee_estimate;
- uint64_t m_dynamic_per_kb_fee_estimate_cached_height;
- uint64_t m_dynamic_per_kb_fee_estimate_grace_blocks;
- uint32_t m_rpc_version;
+ mutable uint64_t m_height;
+ mutable time_t m_height_time;
+ mutable uint64_t m_earliest_height[256];
+ mutable uint64_t m_dynamic_per_kb_fee_estimate;
+ mutable uint64_t m_dynamic_per_kb_fee_estimate_cached_height;
+ mutable uint64_t m_dynamic_per_kb_fee_estimate_grace_blocks;
+ mutable uint32_t m_rpc_version;
+ mutable uint64_t m_target_height;
+ mutable time_t m_target_height_time;
};
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index e569197b8..b63e07b2d 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1097,6 +1097,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
}
entry.first->second.m_block_height = height;
entry.first->second.m_timestamp = ts;
+ entry.first->second.m_unlock_time = tx.unlock_time;
}
//----------------------------------------------------------------------------------------------------
void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const crypto::hash& bl_id, uint64_t height, const cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices &o_indices)
@@ -1878,6 +1879,10 @@ bool wallet2::clear()
m_payments.clear();
m_tx_keys.clear();
m_confirmed_txs.clear();
+ m_unconfirmed_payments.clear();
+ m_scanned_pool_txs[0].clear();
+ m_scanned_pool_txs[1].clear();
+ m_address_book.clear();
m_local_bc_height = 1;
return true;
}
@@ -1958,6 +1963,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const std::string& p
value2.SetInt(m_merge_destinations ? 1 :0);
json.AddMember("merge_destinations", value2, json.GetAllocator());
+ value2.SetInt(m_testnet ? 1 :0);
+ json.AddMember("testnet", value2, json.GetAllocator());
+
// Serialize the JSON object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
@@ -2099,6 +2107,11 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
m_min_output_value = field_min_output_value;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, merge_destinations, int, Int, false, false);
m_merge_destinations = field_merge_destinations;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, testnet, int, Int, false, m_testnet);
+ // Wallet is being opened with testnet flag, but is saved as a mainnet wallet
+ THROW_WALLET_EXCEPTION_IF(m_testnet && !field_testnet, error::wallet_internal_error, "Mainnet wallet can not be opened as testnet wallet");
+ // Wallet is being opened without testnet flag but is saved as a testnet wallet.
+ THROW_WALLET_EXCEPTION_IF(!m_testnet && field_testnet, error::wallet_internal_error, "Testnet wallet can not be opened as mainnet wallet");
}
const cryptonote::account_keys& keys = m_account.get_keys();
@@ -2113,6 +2126,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
/*!
* \brief verify password for default wallet keys file.
* \param password Password to verify
+ * \return true if password is correct
*
* for verification only
* should not mutate state, unlike load_keys()
@@ -2121,7 +2135,23 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
*/
bool wallet2::verify_password(const std::string& password) const
{
- const std::string keys_file_name = m_keys_file;
+ return verify_password(m_keys_file, password, m_watch_only);
+}
+
+/*!
+ * \brief verify password for specified wallet keys file.
+ * \param keys_file_name Keys file to verify password for
+ * \param password Password to verify
+ * \param watch_only If set = only verify view keys, otherwise also spend keys
+ * \return true if password is correct
+ *
+ * for verification only
+ * should not mutate state, unlike load_keys()
+ * can be used prior to rewriting wallet keys file, to ensure user has entered the correct password
+ *
+ */
+bool wallet2::verify_password(const std::string& keys_file_name, const std::string& password, bool watch_only)
+{
wallet2::keys_file_data keys_file_data;
std::string buf;
bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
@@ -2154,7 +2184,7 @@ bool wallet2::verify_password(const std::string& password) const
const cryptonote::account_keys& keys = account_data_check.get_keys();
r = r && verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key);
- if(!m_watch_only)
+ if(!watch_only)
r = r && verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key);
return r;
}
@@ -2192,9 +2222,26 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const std::stri
// try asking the daemon first
if(m_refresh_from_block_height == 0 && !recover){
std::string err;
- uint64_t height = get_daemon_blockchain_height(err);
- if (err.empty())
- m_refresh_from_block_height = height - blocks_per_month;
+ uint64_t height = 0;
+
+ // we get the max of approximated height and known height
+ // approximated height is the least of daemon target height
+ // (the max of what the other daemons are claiming is their
+ // height) and the theoretical height based on the local
+ // clock. This will be wrong only if both the local clock
+ // is bad *and* a peer daemon claims a highest height than
+ // the real chain.
+ // known height is the height the local daemon is currently
+ // synced to, it will be lower than the real chain height if
+ // the daemon is currently syncing.
+ height = get_approximate_blockchain_height();
+ uint64_t target_height = get_daemon_blockchain_target_height(err);
+ if (err.empty() && target_height < height)
+ height = target_height;
+ uint64_t local_height = get_daemon_blockchain_height(err);
+ if (err.empty() && local_height > height)
+ height = local_height;
+ m_refresh_from_block_height = height >= blocks_per_month ? height - blocks_per_month : 0;
}
if(m_refresh_from_block_height == 0 && !recover){
@@ -5685,6 +5732,15 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
}
}
//----------------------------------------------------------------------------------------------------
+bool wallet2::is_synced() const
+{
+ uint64_t height;
+ boost::optional<std::string> result = m_node_rpc_proxy.get_target_height(height);
+ if (result && *result != CORE_RPC_STATUS_OK)
+ return false;
+ return get_blockchain_current_height() >= height;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::generate_genesis(cryptonote::block& b) {
if (m_testnet)
{
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index b853c5f3c..ba9abacf5 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -129,6 +129,8 @@ namespace tools
//! Just parses variables.
static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm);
+ static bool verify_password(const std::string& keys_file_name, const std::string& password, bool watch_only);
+
wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_is_initialized(false), m_restricted(restricted), is_old_file_format(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
struct transfer_details
@@ -199,10 +201,11 @@ namespace tools
std::vector<cryptonote::tx_destination_entry> m_dests;
crypto::hash m_payment_id;
uint64_t m_timestamp;
+ uint64_t m_unlock_time;
- confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(cryptonote::null_hash) {}
+ confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(cryptonote::null_hash), m_timestamp(0), m_unlock_time(0) {}
confirmed_transfer_details(const unconfirmed_transfer_details &utd, uint64_t height):
- m_amount_in(utd.m_amount_in), m_amount_out(utd.m_amount_out), m_change(utd.m_change), m_block_height(height), m_dests(utd.m_dests), m_payment_id(utd.m_payment_id), m_timestamp(utd.m_timestamp) {}
+ m_amount_in(utd.m_amount_in), m_amount_out(utd.m_amount_out), m_change(utd.m_change), m_block_height(height), m_dests(utd.m_dests), m_payment_id(utd.m_payment_id), m_timestamp(utd.m_timestamp), m_unlock_time(utd.m_tx.unlock_time) {}
};
struct tx_construction_data
@@ -597,6 +600,8 @@ namespace tools
uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31
+ bool is_synced() const;
+
private:
/*!
* \brief Stores wallet information to wallet file.
@@ -704,7 +709,7 @@ BOOST_CLASS_VERSION(tools::wallet2, 18)
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 7)
BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1)
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6)
-BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 3)
+BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 4)
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 16)
BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 0)
BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 0)
@@ -879,6 +884,13 @@ namespace boost
x.m_amount_out += x.m_change;
}
}
+ if (ver < 4)
+ {
+ if (!typename Archive::is_saving())
+ x.m_unlock_time = 0;
+ return;
+ }
+ a & x.m_unlock_time;
}
template <class Archive>
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index ce431ee6b..b7483ef8c 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -669,11 +669,20 @@ struct WalletManager
/*!
* @brief TODO: delme walletExists - check if the given filename is the wallet
* @param path - filename
- * @return
+ * @return - true if wallet exists
*/
virtual bool walletExists(const std::string &path) = 0;
/*!
+ * @brief verifyWalletPassword - check if the given filename is the wallet
+ * @param keys_file_name - location of keys file
+ * @param password - password to verify
+ * @param watch_only - verify only view keys?
+ * @return - true if password is correct
+ */
+ virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool watch_only) const = 0;
+
+ /*!
* \brief findWallets - searches for the wallet files by given path name recursively
* \param path - starting point to search
* \return - list of strings with found wallets (absolute paths);
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index f014c573a..da55c2141 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -236,6 +236,7 @@ namespace tools
entry.height = pd.m_block_height;
entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount;
+ entry.unlock_time = pd.m_unlock_time;
entry.fee = 0; // TODO
entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
entry.type = "in";
@@ -249,6 +250,7 @@ namespace tools
entry.payment_id = entry.payment_id.substr(0,16);
entry.height = pd.m_block_height;
entry.timestamp = pd.m_timestamp;
+ entry.unlock_time = pd.m_unlock_time;
entry.fee = pd.m_amount_in - pd.m_amount_out;
uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known
entry.amount = pd.m_amount_in - change - entry.fee;
@@ -276,6 +278,7 @@ namespace tools
entry.timestamp = pd.m_timestamp;
entry.fee = pd.m_amount_in - pd.m_amount_out;
entry.amount = pd.m_amount_in - pd.m_change - entry.fee;
+ entry.unlock_time = pd.m_tx.unlock_time;
entry.note = m_wallet->get_tx_note(txid);
entry.type = is_failed ? "failed" : "pending";
}
@@ -289,6 +292,7 @@ namespace tools
entry.height = 0;
entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount;
+ entry.unlock_time = pd.m_unlock_time;
entry.fee = 0; // TODO
entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
entry.type = "pool";
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 5832bb032..fa5c154de 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -560,6 +560,7 @@ namespace wallet_rpc
std::string note;
std::list<transfer_destination> destinations;
std::string type;
+ uint64_t unlock_time;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txid);
@@ -571,6 +572,7 @@ namespace wallet_rpc
KV_SERIALIZE(note);
KV_SERIALIZE(destinations);
KV_SERIALIZE(type);
+ KV_SERIALIZE(unlock_time)
END_KV_SERIALIZE_MAP()
};
diff --git a/tests/unit_tests/block_queue.cpp b/tests/unit_tests/block_queue.cpp
index a52e221d6..f05d5487a 100644
--- a/tests/unit_tests/block_queue.cpp
+++ b/tests/unit_tests/block_queue.cpp
@@ -85,191 +85,3 @@ TEST(block_queue, flush_uuid)
bq.add_blocks(0, 200, uuid1());
ASSERT_EQ(bq.get_max_block_height(), 399);
}
-
-TEST(block_queue, reserve_overlaps_both)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
-
- bq.add_blocks(0, 100, uuid1());
- bq.add_blocks(200, 100, uuid1());
- ASSERT_EQ(bq.get_max_block_height(), 299);
-
- span = bq.reserve_span(50, 250, 250, uuid2());
- ASSERT_EQ(span.first, 100);
- ASSERT_EQ(span.second, 100);
-}
-
-TEST(block_queue, reserve_overlaps_none)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
-
- bq.add_blocks(0, 100, uuid1());
- bq.add_blocks(200, 100, uuid1());
- ASSERT_EQ(bq.get_max_block_height(), 299);
-
- span = bq.reserve_span(120, 180, 250, uuid2());
- ASSERT_EQ(span.first, 120);
- ASSERT_EQ(span.second, 61);
-}
-
-TEST(block_queue, reserve_overlaps_none_max_hit)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
-
- bq.add_blocks(0, 100, uuid1());
- bq.add_blocks(200, 100, uuid1());
- ASSERT_EQ(bq.get_max_block_height(), 299);
-
- span = bq.reserve_span(120, 500, 50, uuid2());
- ASSERT_EQ(span.first, 120);
- ASSERT_EQ(span.second, 50);
-}
-
-TEST(block_queue, reserve_overlaps_start)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
-
- bq.add_blocks(0, 100, uuid1());
- bq.add_blocks(200, 100, uuid1());
- ASSERT_EQ(bq.get_max_block_height(), 299);
-
- span = bq.reserve_span(50, 150, 250, uuid2());
- ASSERT_EQ(span.first, 100);
- ASSERT_EQ(span.second, 51);
-}
-
-TEST(block_queue, reserve_overlaps_start_max_hit)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
-
- bq.add_blocks(0, 100, uuid1());
- bq.add_blocks(200, 100, uuid1());
- ASSERT_EQ(bq.get_max_block_height(), 299);
-
- span = bq.reserve_span(50, 300, 75, uuid2());
- ASSERT_EQ(span.first, 100);
- ASSERT_EQ(span.second, 75);
-}
-
-TEST(block_queue, reserve_overlaps_stop)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
-
- bq.add_blocks(0, 100, uuid1());
- bq.add_blocks(200, 100, uuid1());
- ASSERT_EQ(bq.get_max_block_height(), 299);
-
- span = bq.reserve_span(150, 300, 250, uuid2());
- ASSERT_EQ(span.first, 150);
- ASSERT_EQ(span.second, 50);
-}
-
-TEST(block_queue, reserve_start_is_empty_after)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
-
- bq.add_blocks(100, 100, uuid1());
- span = bq.reserve_span(150, 250, 100, uuid1());
- ASSERT_EQ(span.first, 200);
- ASSERT_EQ(span.second, 51);
-}
-
-TEST(block_queue, reserve_start_is_empty_start_fits)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
-
- bq.add_blocks(100, 100, uuid1());
- span = bq.reserve_span(0, 250, 50, uuid1());
- ASSERT_EQ(span.first, 0);
- ASSERT_EQ(span.second, 50);
-}
-
-TEST(block_queue, reserve_start_is_empty_start_overflows)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
-
- bq.add_blocks(100, 100, uuid1());
- span = bq.reserve_span(0, 250, 150, uuid1());
- ASSERT_EQ(span.first, 0);
- ASSERT_EQ(span.second, 100);
-}
-
-TEST(block_queue, flush_spans)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
-
- bq.add_blocks(100, 100, uuid2());
- bq.add_blocks(200, 100, uuid1());
- bq.add_blocks(300, 100, uuid2());
- ASSERT_EQ(bq.get_max_block_height(), 399);
- bq.flush_spans(uuid2());
- ASSERT_EQ(bq.get_max_block_height(), 299);
- span = bq.reserve_span(0, 500, 500, uuid1());
- ASSERT_EQ(span.first, 0);
- ASSERT_EQ(span.second, 200);
- bq.flush_spans(uuid1());
- ASSERT_EQ(bq.get_max_block_height(), 0);
-}
-
-TEST(block_queue, get_next_span)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
- uint64_t height;
- std::list<cryptonote::block_complete_entry> blocks;
- boost::uuids::uuid uuid;
-
- bq.add_blocks(100, std::list<cryptonote::block_complete_entry>(100), uuid2(), 0, 0);
- bq.add_blocks(200, std::list<cryptonote::block_complete_entry>(101), uuid1(), 0, 0);
- bq.add_blocks(300, std::list<cryptonote::block_complete_entry>(102), uuid2(), 0, 0);
-
- ASSERT_TRUE(bq.get_next_span(height, blocks, uuid));
- ASSERT_EQ(height, 100);
- ASSERT_EQ(blocks.size(), 100);
- ASSERT_EQ(uuid, uuid2());
- bq.remove_span(height);
-
- ASSERT_TRUE(bq.get_next_span(height, blocks, uuid));
- ASSERT_EQ(height, 200);
- ASSERT_EQ(blocks.size(), 101);
- ASSERT_EQ(uuid, uuid1());
- bq.remove_span(height);
-
- ASSERT_TRUE(bq.get_next_span(height, blocks, uuid));
- ASSERT_EQ(height, 300);
- ASSERT_EQ(blocks.size(), 102);
- ASSERT_EQ(uuid, uuid2());
- bq.remove_span(height);
-
- ASSERT_FALSE(bq.get_next_span(height, blocks, uuid));
-}
-
-TEST(block_queue, get_next_span_if_scheduled)
-{
- cryptonote::block_queue bq;
- std::pair<uint64_t, uint64_t> span;
- uint64_t height;
- std::list<cryptonote::block_complete_entry> blocks;
- boost::uuids::uuid uuid;
- std::list<crypto::hash> hashes;
- boost::posix_time::ptime time;
-
- bq.reserve_span(0, 100, 100, uuid1());
- span = bq.get_next_span_if_scheduled(hashes, uuid, time);
- ASSERT_EQ(span.first, 0);
- ASSERT_EQ(span.second, 100);
- ASSERT_EQ(uuid, uuid1());
- bq.add_blocks(0, std::list<cryptonote::block_complete_entry>(100), uuid1(), 0, 0);
- span = bq.get_next_span_if_scheduled(hashes, uuid, time);
- ASSERT_EQ(span.second, 0);
-}