aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--contrib/epee/include/misc_log_ex.h5
-rw-r--r--contrib/epee/src/mlog.cpp4
-rw-r--r--external/easylogging++/easylogging++.h3
-rw-r--r--src/blockchain_db/blockchain_db.cpp12
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp1
-rw-r--r--src/common/stack_trace.cpp2
-rw-r--r--src/cryptonote_basic/miner.cpp405
-rw-r--r--src/cryptonote_basic/miner.h53
-rw-r--r--src/cryptonote_core/tx_pool.cpp1
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_defs.h10
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl110
-rw-r--r--src/daemon/command_parser_executor.cpp13
-rw-r--r--src/daemon/command_server.cpp2
-rw-r--r--src/daemon/daemon.cpp2
-rw-r--r--src/daemon/rpc_command_executor.cpp5
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/p2p/net_node.h2
-rw-r--r--src/rpc/core_rpc_server.cpp5
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h4
-rw-r--r--src/wallet/CMakeLists.txt2
-rw-r--r--tests/CMakeLists.txt38
-rw-r--r--tests/core_proxy/core_proxy.h2
-rw-r--r--tests/performance_tests/cn_fast_hash.h57
-rw-r--r--tests/performance_tests/main.cpp10
-rw-r--r--tests/performance_tests/performance_tests.h16
-rw-r--r--tests/performance_tests/sc_reduce32.h53
-rw-r--r--tests/unit_tests/ban.cpp2
28 files changed, 730 insertions, 97 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 54ee522e1..f59493345 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -608,11 +608,13 @@ endif()
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
if(MINGW)
set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi)
-elseif(APPLE OR FREEBSD OR OPENBSD OR ANDROID)
+elseif(APPLE OR OPENBSD OR ANDROID)
set(EXTRA_LIBRARIES "")
+elseif(FREEBSD)
+ set(EXTRA_LIBRARIES execinfo)
elseif(DRAGONFLY)
find_library(COMPAT compat)
- set(EXTRA_LIBRARIES ${COMPAT})
+ set(EXTRA_LIBRARIES execinfo ${COMPAT})
elseif(NOT MSVC)
find_library(RT rt)
set(EXTRA_LIBRARIES ${RT})
diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h
index b1685f382..ae61965fa 100644
--- a/contrib/epee/include/misc_log_ex.h
+++ b/contrib/epee/include/misc_log_ex.h
@@ -51,8 +51,9 @@
#define ELPP_THREAD_SAFE
#define ELPP_DEFAULT_LOG_FILE ""
-#ifndef __ANDROID__
-#define ELPP_STACKTRACE_ON_CRASH 0
+#if !defined __GNUC__ || defined __MINGW32__ || defined __MINGW64__ || defined __ANDROID__
+#else
+#define ELPP_STACKTRACE_ON_CRASH 1
#endif
#define ELPP_DISABLE_DEFAULT_CRASH_HANDLING
#define ELPP_FEATURE_CRASH_LOG 1
diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp
index 7f9ef4b3a..c212456f6 100644
--- a/contrib/epee/src/mlog.cpp
+++ b/contrib/epee/src/mlog.cpp
@@ -142,7 +142,7 @@ void mlog_configure(const std::string &filename_base, bool console)
void mlog_set_categories(const char *categories)
{
el::Loggers::setCategories(categories);
- MINFO("Mew log categories: " << categories);
+ MGINFO("New log categories: " << categories);
}
// maps epee style log level to new logging system
@@ -150,7 +150,7 @@ void mlog_set_log_level(int level)
{
const char *categories = get_default_categories(level);
el::Loggers::setCategories(categories);
- MINFO("Mew log categories: " << categories);
+ MGINFO("New log categories: " << categories);
}
void mlog_set_log(const char *log)
diff --git a/external/easylogging++/easylogging++.h b/external/easylogging++/easylogging++.h
index 24e271e80..1cf9dbac8 100644
--- a/external/easylogging++/easylogging++.h
+++ b/external/easylogging++/easylogging++.h
@@ -198,12 +198,15 @@ ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStre
# if (ELPP_COMPILER_GCC && !ELPP_MINGW)
# define ELPP_STACKTRACE 1
# else
+# define ELPP_STACKTRACE 0
# if ELPP_COMPILER_MSVC
# pragma message("Stack trace not available for this compiler")
# else
# warning "Stack trace not available for this compiler";
# endif // ELPP_COMPILER_MSVC
# endif // ELPP_COMPILER_GCC
+#else
+# define ELPP_STACKTRACE 0
#endif // (defined(ELPP_STACKTRACE_ON_CRASH))
// Miscellaneous macros
#define ELPP_UNUSED(x) (void)x
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp
index 1cb0ada0c..7ac046bc9 100644
--- a/src/blockchain_db/blockchain_db.cpp
+++ b/src/blockchain_db/blockchain_db.cpp
@@ -130,12 +130,6 @@ uint64_t BlockchainDB::add_block( const block& blk
uint64_t prev_height = height();
- // call out to subclass implementation to add the block & metadata
- time1 = epee::misc_utils::get_tick_count();
- add_block(blk, block_size, cumulative_difficulty, coins_generated, blk_hash);
- TIME_MEASURE_FINISH(time1);
- time_add_block1 += time1;
-
// call out to add the transactions
time1 = epee::misc_utils::get_tick_count();
@@ -151,6 +145,12 @@ uint64_t BlockchainDB::add_block( const block& blk
TIME_MEASURE_FINISH(time1);
time_add_transaction += time1;
+ // call out to subclass implementation to add the block & metadata
+ time1 = epee::misc_utils::get_tick_count();
+ add_block(blk, block_size, cumulative_difficulty, coins_generated, blk_hash);
+ TIME_MEASURE_FINISH(time1);
+ time_add_block1 += time1;
+
m_hardfork->add(blk, prev_height);
block_txn_stop();
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 863f54246..0a35325e4 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -628,6 +628,7 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const
CURSOR(blocks)
CURSOR(block_info)
+ // this call to mdb_cursor_put will change height()
MDB_val_copy<blobdata> blob(block_to_blob(blk));
result = mdb_cursor_put(m_cur_blocks, &key, &blob, MDB_APPEND);
if (result)
diff --git a/src/common/stack_trace.cpp b/src/common/stack_trace.cpp
index 67065aae7..ef64c20c5 100644
--- a/src/common/stack_trace.cpp
+++ b/src/common/stack_trace.cpp
@@ -26,7 +26,7 @@
// 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.
-#if !defined __GNUC__ || defined __MINGW32__ || defined __MINGW64__
+#if !defined __GNUC__ || defined __MINGW32__ || defined __MINGW64__ || defined __ANDROID__
#define USE_UNWIND
#endif
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index 88c631f80..117c81878 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -60,6 +60,10 @@ namespace cryptonote
const command_line::arg_descriptor<std::string> arg_extra_messages = {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true};
const command_line::arg_descriptor<std::string> arg_start_mining = {"start-mining", "Specify wallet address to mining for", "", true};
const command_line::arg_descriptor<uint32_t> arg_mining_threads = {"mining-threads", "Specify mining threads count", 0, true};
+ const command_line::arg_descriptor<bool> arg_bg_mining_enable = {"bg-mining-enable", "enable/disable background mining", true, true};
+ const command_line::arg_descriptor<uint64_t> arg_bg_mining_min_idle_interval_seconds = {"bg-mining-min-idle-interval", "Specify min lookback interval in seconds for determining idle state", miner::BACKGROUND_MINING_DEFAULT_MIN_IDLE_INTERVAL_IN_SECONDS, true};
+ const command_line::arg_descriptor<uint8_t> arg_bg_mining_idle_threshold_percentage = {"bg-mining-idle-threshold", "Specify minimum avg idle percentage over lookback interval", miner::BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE, true};
+ const command_line::arg_descriptor<uint8_t> arg_bg_mining_miner_target_percentage = {"bg-mining-miner-target", "Specificy maximum percentage cpu use by miner(s)", miner::BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE, true};
}
@@ -77,7 +81,12 @@ namespace cryptonote
m_hashes(0),
m_do_print_hashrate(false),
m_do_mining(false),
- m_current_hash_rate(0)
+ m_current_hash_rate(0),
+ m_is_background_mining_enabled(false),
+ m_min_idle_seconds(BACKGROUND_MINING_DEFAULT_MIN_IDLE_INTERVAL_IN_SECONDS),
+ m_idle_threshold(BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE),
+ m_mining_target(BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE),
+ m_miner_extra_sleep(BACKGROUND_MINING_DEFAULT_MINER_EXTRA_SLEEP_MILLIS)
{
}
@@ -137,7 +146,7 @@ namespace cryptonote
merge_hr();
return true;
});
-
+
return true;
}
//-----------------------------------------------------------------------------------------------------
@@ -171,6 +180,10 @@ namespace cryptonote
command_line::add_arg(desc, arg_extra_messages);
command_line::add_arg(desc, arg_start_mining);
command_line::add_arg(desc, arg_mining_threads);
+ command_line::add_arg(desc, arg_bg_mining_enable);
+ command_line::add_arg(desc, arg_bg_mining_min_idle_interval_seconds);
+ command_line::add_arg(desc, arg_bg_mining_idle_threshold_percentage);
+ command_line::add_arg(desc, arg_bg_mining_miner_target_percentage);
}
//-----------------------------------------------------------------------------------------------------
bool miner::init(const boost::program_options::variables_map& vm, bool testnet)
@@ -213,6 +226,17 @@ namespace cryptonote
}
}
+ // Background mining parameters
+ // Let init set all parameters even if background mining is not enabled, they can start later with params set
+ if(command_line::has_arg(vm, arg_bg_mining_enable))
+ set_is_background_mining_enabled( command_line::get_arg(vm, arg_bg_mining_enable) );
+ if(command_line::has_arg(vm, arg_bg_mining_min_idle_interval_seconds))
+ set_min_idle_seconds( command_line::get_arg(vm, arg_bg_mining_min_idle_interval_seconds) );
+ if(command_line::has_arg(vm, arg_bg_mining_idle_threshold_percentage))
+ set_idle_threshold( command_line::get_arg(vm, arg_bg_mining_idle_threshold_percentage) );
+ if(command_line::has_arg(vm, arg_bg_mining_miner_target_percentage))
+ set_mining_target( command_line::get_arg(vm, arg_bg_mining_miner_target_percentage) );
+
return true;
}
//-----------------------------------------------------------------------------------------------------
@@ -230,7 +254,7 @@ namespace cryptonote
return m_threads_total;
}
//-----------------------------------------------------------------------------------------------------
- bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs)
+ bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background)
{
m_mine_address = adr;
m_threads_total = static_cast<uint32_t>(threads_count);
@@ -253,13 +277,21 @@ namespace cryptonote
boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0);
boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0);
-
+ set_is_background_mining_enabled(do_background);
+
for(size_t i = 0; i != threads_count; i++)
{
m_threads.push_back(boost::thread(attrs, boost::bind(&miner::worker_thread, this)));
}
LOG_PRINT_L0("Mining has started with " << threads_count << " threads, good luck!" );
+
+ if( get_is_background_mining_enabled() )
+ {
+ m_background_mining_thread = boost::thread(attrs, boost::bind(&miner::background_worker_thread, this));
+ LOG_PRINT_L0("Background mining controller thread started" );
+ }
+
return true;
}
//-----------------------------------------------------------------------------------------------------
@@ -291,9 +323,18 @@ namespace cryptonote
send_stop_signal();
CRITICAL_REGION_LOCAL(m_threads_lock);
+ // In case background mining was active and the miner threads are waiting
+ // on the background miner to signal start.
+ m_is_background_mining_started_cond.notify_all();
+
for(boost::thread& th: m_threads)
th.join();
+ // The background mining thread could be sleeping for a long time, so we
+ // interrupt it just in case
+ m_background_mining_thread.interrupt();
+ m_background_mining_thread.join();
+
MINFO("Mining has been stopped, " << m_threads.size() << " finished" );
m_threads.clear();
return true;
@@ -321,7 +362,7 @@ namespace cryptonote
boost::thread::attributes attrs;
attrs.set_stack_size(THREAD_STACK_SIZE);
- start(m_mine_address, m_threads_total, attrs);
+ start(m_mine_address, m_threads_total, attrs, get_is_background_mining_enabled());
}
}
//-----------------------------------------------------------------------------------------------------
@@ -364,6 +405,19 @@ namespace cryptonote
misc_utils::sleep_no_w(100);
continue;
}
+ else if( m_is_background_mining_enabled )
+ {
+ misc_utils::sleep_no_w(m_miner_extra_sleep);
+ while( !m_is_background_mining_started )
+ {
+ MGINFO("background mining is enabled, but not started, waiting until start triggers");
+ boost::unique_lock<boost::mutex> started_lock( m_is_background_mining_started_mutex );
+ m_is_background_mining_started_cond.wait( started_lock );
+ if( m_stop ) break;
+ }
+
+ if( m_stop ) continue;
+ }
if(local_template_ver != m_template_no)
{
@@ -410,5 +464,344 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------------
-}
+ bool miner::get_is_background_mining_enabled() const
+ {
+ return m_is_background_mining_enabled;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ /**
+ * This has differing behaviour depending on if mining has been started/etc.
+ * Note: add documentation
+ */
+ bool miner::set_is_background_mining_enabled(bool is_background_mining_enabled)
+ {
+ m_is_background_mining_enabled = is_background_mining_enabled;
+ // Extra logic will be required if we make this function public in the future
+ // and allow toggling smart mining without start/stop
+ //m_is_background_mining_enabled_cond.notify_one();
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ uint64_t miner::get_min_idle_seconds() const
+ {
+ return m_min_idle_seconds;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::set_min_idle_seconds(uint64_t min_idle_seconds)
+ {
+ if(min_idle_seconds > BACKGROUND_MINING_MAX_MIN_IDLE_INTERVAL_IN_SECONDS) return false;
+ if(min_idle_seconds < BACKGROUND_MINING_MIN_MIN_IDLE_INTERVAL_IN_SECONDS) return false;
+ m_min_idle_seconds = min_idle_seconds;
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ uint8_t miner::get_idle_threshold() const
+ {
+ return m_idle_threshold;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::set_idle_threshold(uint8_t idle_threshold)
+ {
+ if(idle_threshold > BACKGROUND_MINING_MAX_IDLE_THRESHOLD_PERCENTAGE) return false;
+ if(idle_threshold < BACKGROUND_MINING_MIN_IDLE_THRESHOLD_PERCENTAGE) return false;
+ m_idle_threshold = idle_threshold;
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ uint8_t miner::get_mining_target() const
+ {
+ return m_mining_target;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::set_mining_target(uint8_t mining_target)
+ {
+ if(mining_target > BACKGROUND_MINING_MAX_MINING_TARGET_PERCENTAGE) return false;
+ if(mining_target < BACKGROUND_MINING_MIN_MINING_TARGET_PERCENTAGE) return false;
+ m_mining_target = mining_target;
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::background_worker_thread()
+ {
+ uint64_t prev_total_time, current_total_time;
+ uint64_t prev_idle_time, current_idle_time;
+ uint64_t previous_process_time = 0, current_process_time = 0;
+ m_is_background_mining_started = false;
+
+ if(!get_system_times(prev_total_time, prev_idle_time))
+ {
+ LOG_ERROR("get_system_times call failed, background mining will NOT work!");
+ return false;
+ }
+
+ while(!m_stop)
+ {
+
+ try
+ {
+ // Commenting out the below since we're going with privatizing the bg mining enabled
+ // function, but I'll leave the code/comments here for anyone that wants to modify the
+ // patch in the future
+ // -------------------------------------------------------------------------------------
+ // All of this might be overkill if we just enforced some simple requirements
+ // about changing this variable before/after the miner starts, but I envision
+ // in the future a checkbox that you can tick on/off for background mining after
+ // you've clicked "start mining". There's still an issue here where if background
+ // mining is disabled when start is called, this thread is never created, and so
+ // enabling after does nothing, something I have to fix in the future. However,
+ // this should take care of the case where mining is started with bg-enabled,
+ // and then the user decides to un-check background mining, and just do
+ // regular full-speed mining. I might just be over-doing it and thinking up
+ // non-existant use-cases, so if the concensus is to simplify, we can remove all this fluff.
+ /*
+ while( !m_is_background_mining_enabled )
+ {
+ MGINFO("background mining is disabled, waiting until enabled!");
+ boost::unique_lock<boost::mutex> enabled_lock( m_is_background_mining_enabled_mutex );
+ m_is_background_mining_enabled_cond.wait( enabled_lock );
+ }
+ */
+
+ // If we're already mining, then sleep for the miner monitor interval.
+ // If we're NOT mining, then sleep for the idle monitor interval
+ boost::this_thread::sleep_for(
+ m_is_background_mining_started ?
+ boost::chrono::seconds( BACKGROUND_MINING_MINER_MONITOR_INVERVAL_IN_SECONDS ) :
+ boost::chrono::seconds( get_min_idle_seconds() ) );
+ }
+ catch(const boost::thread_interrupted&)
+ {
+ MDEBUG("background miner thread interrupted ");
+ continue; // if interrupted because stop called, loop should end ..
+ }
+
+ bool on_ac_power = !on_battery_power();
+ if( m_is_background_mining_started )
+ {
+ // figure out if we need to stop, and monitor mining usage
+
+ // If we get here, then previous values are initialized.
+ // Let's get some current data for comparison.
+
+ if(!get_system_times(current_total_time, current_idle_time))
+ {
+ MERROR("get_system_times call failed");
+ continue;
+ }
+
+ if(!get_process_time(current_process_time))
+ {
+ MERROR("get_process_time call failed!");
+ continue;
+ }
+
+ uint64_t total_diff = (current_total_time - prev_total_time);
+ uint64_t idle_diff = (current_idle_time - prev_idle_time);
+ uint64_t process_diff = (current_process_time - previous_process_time);
+ uint8_t idle_percentage = get_percent_of_total(idle_diff, total_diff);
+ uint8_t process_percentage = get_percent_of_total(process_diff, total_diff);
+
+ MGINFO("idle percentage is " << unsigned(idle_percentage) << "\%, miner percentage is " << unsigned(process_percentage) << "\%, ac power : " << on_ac_power);
+ if( idle_percentage + process_percentage < get_idle_threshold() || !on_ac_power )
+ {
+ MGINFO("cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining stopping, thanks for your contribution!");
+ m_is_background_mining_started = false;
+
+ // reset process times
+ previous_process_time = 0;
+ current_process_time = 0;
+ }
+ else
+ {
+ previous_process_time = current_process_time;
+
+ // adjust the miner extra sleep variable
+ int64_t miner_extra_sleep_change = (-1 * (get_mining_target() - process_percentage) );
+ int64_t new_miner_extra_sleep = m_miner_extra_sleep + miner_extra_sleep_change;
+ // if you start the miner with few threads on a multicore system, this could
+ // fall below zero because all the time functions aggregate across all processors.
+ // I'm just hard limiting to 5 millis min sleep here, other options?
+ m_miner_extra_sleep = std::max( new_miner_extra_sleep , (int64_t)5 );
+ MDEBUG("m_miner_extra_sleep " << m_miner_extra_sleep);
+ }
+
+ prev_total_time = current_total_time;
+ prev_idle_time = current_idle_time;
+ }
+ else if( on_ac_power )
+ {
+ // figure out if we need to start
+
+ if(!get_system_times(current_total_time, current_idle_time))
+ {
+ MERROR("get_system_times call failed");
+ continue;
+ }
+
+ uint64_t total_diff = (current_total_time - prev_total_time);
+ uint64_t idle_diff = (current_idle_time - prev_idle_time);
+ uint8_t idle_percentage = get_percent_of_total(idle_diff, total_diff);
+
+ MGINFO("idle percentage is " << unsigned(idle_percentage));
+ if( idle_percentage >= get_idle_threshold() && on_ac_power )
+ {
+ MGINFO("cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining started, good luck!");
+ m_is_background_mining_started = true;
+ m_is_background_mining_started_cond.notify_all();
+
+ // Wait for a little mining to happen ..
+ boost::this_thread::sleep_for(boost::chrono::seconds( 1 ));
+
+ // Starting data ...
+ if(!get_process_time(previous_process_time))
+ {
+ m_is_background_mining_started = false;
+ MERROR("get_process_time call failed!");
+ }
+ }
+
+ prev_total_time = current_total_time;
+ prev_idle_time = current_idle_time;
+ }
+ }
+
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::get_system_times(uint64_t& total_time, uint64_t& idle_time)
+ {
+ #ifdef _WIN32
+
+ FILETIME idleTime;
+ FILETIME kernelTime;
+ FILETIME userTime;
+ if ( GetSystemTimes( &idleTime, &kernelTime, &userTime ) != -1 )
+ {
+ total_time =
+ ( (((uint64_t)(kernelTime.dwHighDateTime)) << 32) | ((uint64_t)kernelTime.dwLowDateTime) )
+ + ( (((uint64_t)(userTime.dwHighDateTime)) << 32) | ((uint64_t)userTime.dwLowDateTime) );
+
+ idle_time = ( (((uint64_t)(idleTime.dwHighDateTime)) << 32) | ((uint64_t)idleTime.dwLowDateTime) );
+
+ return true;
+ }
+
+ #elif defined(__linux__)
+
+ const std::string STR_CPU("cpu");
+ const std::size_t STR_CPU_LEN = STR_CPU.size();
+ const std::string STAT_FILE_PATH = "/proc/stat";
+
+ if( !epee::file_io_utils::is_file_exist(STAT_FILE_PATH) )
+ {
+ LOG_ERROR("'" << STAT_FILE_PATH << "' file does not exist");
+ return false;
+ }
+
+ std::ifstream stat_file_stream(STAT_FILE_PATH);
+ if( stat_file_stream.fail() )
+ {
+ LOG_ERROR("failed to open '" << STAT_FILE_PATH << "'");
+ return false;
+ }
+
+ std::string line;
+ std::getline(stat_file_stream, line);
+ std::istringstream stat_file_iss(line);
+ stat_file_iss.ignore(65536, ' '); // skip cpu label ...
+ uint64_t utime, ntime, stime, itime;
+ if( !(stat_file_iss >> utime && stat_file_iss >> ntime && stat_file_iss >> stime && stat_file_iss >> itime) )
+ {
+ LOG_ERROR("failed to read '" << STAT_FILE_PATH << "'");
+ return false;
+ }
+
+ idle_time = itime;
+ total_time = utime + ntime + stime + itime;
+
+ return true;
+
+ #endif
+
+ return false; // unsupported systemm..
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::get_process_time(uint64_t& total_time)
+ {
+ #ifdef _WIN32
+
+ FILETIME createTime;
+ FILETIME exitTime;
+ FILETIME kernelTime;
+ FILETIME userTime;
+ if ( GetProcessTimes( GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime ) != -1 )
+ {
+ total_time =
+ ( (((uint64_t)(kernelTime.dwHighDateTime)) << 32) | ((uint64_t)kernelTime.dwLowDateTime) )
+ + ( (((uint64_t)(userTime.dwHighDateTime)) << 32) | ((uint64_t)userTime.dwLowDateTime) );
+
+ return true;
+ }
+
+ #elif defined(__linux__) && defined(_SC_CLK_TCK)
+
+ struct tms tms;
+ if ( times(&tms) != (clock_t)-1 )
+ {
+ total_time = tms.tms_utime + tms.tms_stime;
+ return true;
+ }
+
+ #endif
+
+ return false; // unsupported system..
+ }
+ //-----------------------------------------------------------------------------------------------------
+ uint8_t miner::get_percent_of_total(uint64_t other, uint64_t total)
+ {
+ return (uint8_t)( ceil( (other * 1.f / total * 1.f) * 100) );
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::on_battery_power()
+ {
+ #ifdef _WIN32
+
+ SYSTEM_POWER_STATUS power_status;
+ if ( GetSystemPowerStatus( &power_status ) != 0 )
+ {
+ return power_status.ACLineStatus != 1;
+ }
+
+ #elif defined(__linux__)
+
+ // i've only tested on UBUNTU, these paths might be different on other systems
+ // need to figure out a way to make this more flexible
+ const std::string POWER_SUPPLY_STATUS_PATH = "/sys/class/power_supply/ACAD/online";
+
+ if( !epee::file_io_utils::is_file_exist(POWER_SUPPLY_STATUS_PATH) )
+ {
+ LOG_ERROR("'" << POWER_SUPPLY_STATUS_PATH << "' file does not exist, can't determine if on AC power");
+ return false;
+ }
+
+ std::ifstream power_stream(POWER_SUPPLY_STATUS_PATH);
+ if( power_stream.fail() )
+ {
+ LOG_ERROR("failed to open '" << POWER_SUPPLY_STATUS_PATH << "'");
+ return false;
+ }
+
+ return power_stream.get() != '1';
+
+ #endif
+
+ LOG_ERROR("couldn't query power status");
+ return false; // shouldn't get here unless no support for querying battery status
+ // TODO: return enum with ability to signify failure in querying for power status
+ // and change bg-mining logic so that it stops. As @vtnerd states, with the current
+ // setup "If someone enabled background mining on a system that fails to grab ac
+ // status, it will just continually check with little hope of ever being resolved
+ // automagically". This is also the case for time/idle stats functions.
+ }
+}
diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h
index f24f6e960..a66083ead 100644
--- a/src/cryptonote_basic/miner.h
+++ b/src/cryptonote_basic/miner.h
@@ -35,7 +35,14 @@
#include "cryptonote_basic.h"
#include "difficulty.h"
#include "math_helper.h"
-
+#ifdef _WIN32
+#include <windows.h>
+#elif defined(__linux__)
+#include <unistd.h>
+#include <sys/resource.h>
+#include <sys/times.h>
+#include <time.h>
+#endif
namespace cryptonote
{
@@ -60,7 +67,7 @@ namespace cryptonote
static void init_options(boost::program_options::options_description& desc);
bool set_block_template(const block& bl, const difficulty_type& diffic, uint64_t height);
bool on_block_chain_update();
- bool start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs);
+ bool start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background = false);
uint64_t get_speed() const;
uint32_t get_threads_count() const;
void send_stop_signal();
@@ -74,6 +81,26 @@ namespace cryptonote
void pause();
void resume();
void do_print_hashrate(bool do_hr);
+ bool get_is_background_mining_enabled() const;
+ uint64_t get_min_idle_seconds() const;
+ bool set_min_idle_seconds(uint64_t min_idle_seconds);
+ uint8_t get_idle_threshold() const;
+ bool set_idle_threshold(uint8_t idle_threshold);
+ uint8_t get_mining_target() const;
+ bool set_mining_target(uint8_t mining_target);
+
+ static constexpr uint8_t BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE = 90;
+ static constexpr uint8_t BACKGROUND_MINING_MIN_IDLE_THRESHOLD_PERCENTAGE = 50;
+ static constexpr uint8_t BACKGROUND_MINING_MAX_IDLE_THRESHOLD_PERCENTAGE = 99;
+ static constexpr uint16_t BACKGROUND_MINING_DEFAULT_MIN_IDLE_INTERVAL_IN_SECONDS = 10;
+ static constexpr uint16_t BACKGROUND_MINING_MIN_MIN_IDLE_INTERVAL_IN_SECONDS = 10;
+ static constexpr uint16_t BACKGROUND_MINING_MAX_MIN_IDLE_INTERVAL_IN_SECONDS = 3600;
+ static constexpr uint8_t BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE = 40;
+ static constexpr uint8_t BACKGROUND_MINING_MIN_MINING_TARGET_PERCENTAGE = 5;
+ static constexpr uint8_t BACKGROUND_MINING_MAX_MINING_TARGET_PERCENTAGE = 50;
+ static constexpr uint8_t BACKGROUND_MINING_MINER_MONITOR_INVERVAL_IN_SECONDS = 10;
+ static constexpr uint64_t BACKGROUND_MINING_DEFAULT_MINER_EXTRA_SLEEP_MILLIS = 400; // ramp up
+ static constexpr uint64_t BACKGROUND_MINING_MIN_MINER_EXTRA_SLEEP_MILLIS = 5;
private:
bool worker_thread();
@@ -119,8 +146,24 @@ namespace cryptonote
bool m_do_print_hashrate;
bool m_do_mining;
+ // background mining stuffs ..
+
+ bool set_is_background_mining_enabled(bool is_background_mining_enabled);
+ bool background_worker_thread();
+ std::atomic<bool> m_is_background_mining_enabled;
+ boost::mutex m_is_background_mining_enabled_mutex;
+ boost::condition_variable m_is_background_mining_enabled_cond;
+ std::atomic<bool> m_is_background_mining_started;
+ boost::mutex m_is_background_mining_started_mutex;
+ boost::condition_variable m_is_background_mining_started_cond;
+ boost::thread m_background_mining_thread;
+ uint64_t m_min_idle_seconds;
+ uint8_t m_idle_threshold;
+ uint8_t m_mining_target;
+ std::atomic<uint64_t> m_miner_extra_sleep;
+ static bool get_system_times(uint64_t& total_time, uint64_t& idle_time);
+ static bool get_process_time(uint64_t& total_time);
+ static uint8_t get_percent_of_total(uint64_t some_time, uint64_t total_time);
+ static bool on_battery_power();
};
}
-
-
-
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 9188f8329..f48be1ff1 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -255,6 +255,7 @@ namespace cryptonote
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)blob_size, receive_time), id);
+ MINFO("Transaction " << id << " added to pool");
return true;
}
//---------------------------------------------------------------------------------
diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h
index 843504621..427aa62df 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_defs.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h
@@ -257,16 +257,16 @@ namespace cryptonote
struct request
{
- block_complete_entry b;
+ crypto::hash block_hash;
uint64_t current_blockchain_height;
std::vector<size_t> missing_tx_indices;
uint32_t hop;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(b)
- KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missing_tx_indices)
- KV_SERIALIZE(hop)
- KV_SERIALIZE(current_blockchain_height)
+ KV_SERIALIZE_VAL_POD_AS_BLOB(block_hash)
+ KV_SERIALIZE(current_blockchain_height)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missing_tx_indices)
+ KV_SERIALIZE(hop)
END_KV_SERIALIZE_MAP()
};
};
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index f1317a838..72940d36a 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -367,7 +367,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context)
{
- MLOG_P2P_MESSAGE("Received NOTIFY_NEW_FLUFFY_BLOCK (hop " << arg.hop << ", " << arg.b.txs.size() << " txes)");
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_FLUFFY_BLOCK (height " << arg.current_blockchain_height << ", hop " << arg.hop << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
@@ -377,7 +377,7 @@ namespace cryptonote
transaction miner_tx;
if(parse_and_validate_block_from_blob(arg.b.block, new_block))
{
- // This is a seccond notification, we must have asked for some missing tx
+ // This is a second notification, we must have asked for some missing tx
if(!context.m_requested_objects.empty())
{
// What we asked for != to what we received ..
@@ -475,6 +475,7 @@ namespace cryptonote
// sent in our pool, so don't verify again..
if(!m_core.get_pool_transaction(tx_hash, tx))
{
+ MDEBUG("Incoming tx " << tx_hash << " not in pool, adding");
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
if(!m_core.handle_incoming_tx(tx_blob, tvc, true, true, false) || tvc.m_verifivation_failed)
{
@@ -496,9 +497,9 @@ namespace cryptonote
{
LOG_ERROR_CCONTEXT
(
- "sent wrong tx: failed to parse and validate transaction: \r\n"
+ "sent wrong tx: failed to parse and validate transaction: "
<< epee::string_tools::buff_to_hex_nodelimer(tx_blob)
- << "\r\n dropping connection"
+ << ", dropping connection"
);
m_p2p->drop_connection(context);
@@ -535,7 +536,19 @@ namespace cryptonote
}
else
{
- need_tx_indices.push_back(tx_idx);
+ std::vector<crypto::hash> tx_ids;
+ std::list<transaction> txes;
+ std::list<crypto::hash> missing;
+ tx_ids.push_back(tx_hash);
+ if (m_core.get_transactions(tx_ids, txes, missing) && missing.empty())
+ {
+ have_tx.push_back(tx_to_blob(tx));
+ }
+ else
+ {
+ MDEBUG("Tx " << tx_hash << " not found in pool");
+ need_tx_indices.push_back(tx_idx);
+ }
}
++tx_idx;
@@ -544,8 +557,11 @@ namespace cryptonote
if(!need_tx_indices.empty()) // drats, we don't have everything..
{
// request non-mempool txs
+ MDEBUG("We are missing " << need_tx_indices.size() << " txes for this fluffy block");
+ for (auto txidx: need_tx_indices)
+ MDEBUG(" tx " << new_block.tx_hashes[txidx]);
NOTIFY_REQUEST_FLUFFY_MISSING_TX::request missing_tx_req;
- missing_tx_req.b = arg.b;
+ missing_tx_req.block_hash = get_block_hash(new_block);
missing_tx_req.hop = arg.hop;
missing_tx_req.current_blockchain_height = arg.current_blockchain_height;
missing_tx_req.missing_tx_indices = std::move(need_tx_indices);
@@ -555,6 +571,8 @@ namespace cryptonote
}
else // whoo-hoo we've got em all ..
{
+ MDEBUG("We have all needed txes for this fluffy block");
+
block_complete_entry b;
b.block = arg.b.block;
b.txs = have_tx;
@@ -598,9 +616,9 @@ namespace cryptonote
{
LOG_ERROR_CCONTEXT
(
- "sent wrong block: failed to parse and validate block: \r\n"
+ "sent wrong block: failed to parse and validate block: "
<< epee::string_tools::buff_to_hex_nodelimer(arg.b.block)
- << "\r\n dropping connection"
+ << ", dropping connection"
);
m_core.resume_mine();
@@ -615,34 +633,29 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context)
{
- MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_FLUFFY_MISSING_TX (" << arg.missing_tx_indices.size() << " txes)");
-
- std::list<block> local_blocks;
- std::list<transaction> local_txs;
- if(!m_core.get_blocks(arg.current_blockchain_height - 1, 1, local_blocks, local_txs))
- {
+ MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_FLUFFY_MISSING_TX (" << arg.missing_tx_indices.size() << " txes), block hash " << arg.block_hash);
- LOG_ERROR_CCONTEXT
- (
- "Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
- << ", get_blocks( start_offset = " << (arg.current_blockchain_height - 1) << " ) failed"
- << ", dropping connection"
- );
-
+ block b;
+ if (!m_core.get_block_by_hash(arg.block_hash, b))
+ {
+ LOG_ERROR_CCONTEXT("failed to find block: " << arg.block_hash << ", dropping connection");
m_p2p->drop_connection(context);
- return 1;
+ return 1;
}
+ for (auto txidx: arg.missing_tx_indices)
+ MDEBUG(" tx " << b.tx_hashes[txidx]);
+
+ std::vector<crypto::hash> txids;
NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
- fluffy_response.b = arg.b;
- fluffy_response.current_blockchain_height = m_core.get_current_blockchain_height();
+ fluffy_response.b.block = t_serializable_object_to_blob(b);
+ fluffy_response.current_blockchain_height = arg.current_blockchain_height;
fluffy_response.hop = arg.hop;
- size_t local_txs_count = local_txs.size();
for(auto& tx_idx: arg.missing_tx_indices)
{
- if(tx_idx < local_txs_count)
+ if(tx_idx < b.tx_hashes.size())
{
- fluffy_response.b.txs.push_back(t_serializable_object_to_blob( *(std::next(local_txs.begin(), tx_idx)) ));
+ txids.push_back(b.tx_hashes[tx_idx]);
}
else
{
@@ -650,7 +663,8 @@ namespace cryptonote
(
"Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
<< ", request is asking for a tx whose index is out of bounds "
- << ", tx index = " << tx_idx << ", block_height = " << arg.current_blockchain_height
+ << ", tx index = " << tx_idx << ", block tx count " << b.tx_hashes.size()
+ << ", block_height = " << arg.current_blockchain_height
<< ", dropping connection"
);
@@ -658,7 +672,29 @@ namespace cryptonote
return 1;
}
}
-
+
+ std::list<cryptonote::transaction> txs;
+ std::list<crypto::hash> missed;
+ if (!m_core.get_transactions(txids, txs, missed))
+ {
+ LOG_ERROR_CCONTEXT("Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX, "
+ << "failed to get requested transactions");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ if (!missed.empty() || txs.size() != txids.size())
+ {
+ LOG_ERROR_CCONTEXT("Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX, "
+ << missed.size() << " requested transactions not found" << ", dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+
+ for(auto& tx: txs)
+ {
+ fluffy_response.b.txs.push_back(t_serializable_object_to_blob(tx));
+ }
+
LOG_PRINT_CCONTEXT_L2
(
"-->>NOTIFY_RESPONSE_FLUFFY_MISSING_TX: "
@@ -803,8 +839,8 @@ namespace cryptonote
block b;
if(!parse_and_validate_block_from_blob(block_entry.block, b))
{
- LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: \r\n"
- << epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection");
+ LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: "
+ << epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
m_p2p->drop_connection(context);
return 1;
}
@@ -903,7 +939,7 @@ namespace cryptonote
m_core.handle_incoming_tx(tx_blob, tvc, true, true, false);
if(tvc.m_verifivation_failed)
{
- LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = "
+ LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, tx_id = "
<< epee::string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection");
m_p2p->drop_connection(context);
m_core.cleanup_handle_incoming_blocks();
@@ -1099,9 +1135,9 @@ namespace cryptonote
context.m_last_response_height = arg.start_height + arg.m_block_ids.size()-1;
if(context.m_last_response_height > context.m_remote_blockchain_height)
{
- LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with \r\nm_total_height=" << arg.total_height
- << "\r\nm_start_height=" << arg.start_height
- << "\r\nm_block_ids.size()=" << arg.m_block_ids.size());
+ LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with m_total_height=" << arg.total_height
+ << ", m_start_height=" << arg.start_height
+ << ", m_block_ids.size()=" << arg.m_block_ids.size());
m_p2p->drop_connection(context);
}
@@ -1138,12 +1174,12 @@ namespace cryptonote
{
if(m_core.get_testnet() && (support_flags & P2P_SUPPORT_FLAG_FLUFFY_BLOCKS))
{
- MDEBUG("PEER SUPPORTS FLUFFY BLOCKS - RELAYING THIN/COMPACT WHATEVER BLOCK");
+ LOG_DEBUG_CC(context, "PEER SUPPORTS FLUFFY BLOCKS - RELAYING THIN/COMPACT WHATEVER BLOCK");
fluffyConnections.push_back(context.m_connection_id);
}
else
{
- MDEBUG("PEER DOESN'T SUPPORT FLUFFY BLOCKS - RELAYING FULL BLOCK");
+ LOG_DEBUG_CC(context, "PEER DOESN'T SUPPORT FLUFFY BLOCKS - RELAYING FULL BLOCK");
fullConnections.push_back(context.m_connection_id);
}
}
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index fd73654ac..8ed529737 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -271,17 +271,24 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
if(testnet)
std::cout << "Mining to a testnet address, make sure this is intentional!" << std::endl;
uint64_t threads_count = 1;
- if(args.size() > 2)
+ bool do_background_mining = false;
+ if(args.size() > 3)
{
return false;
}
- else if(args.size() == 2)
+
+ if(args.size() == 3)
+ {
+ do_background_mining = args[2] == "true";
+ }
+
+ if(args.size() >= 2)
{
bool ok = epee::string_tools::get_xtype_from_string(threads_count, args[1]);
threads_count = (ok && 0 < threads_count) ? threads_count : 1;
}
- m_executor.start_mining(adr, threads_count, testnet);
+ m_executor.start_mining(adr, threads_count, testnet, do_background_mining);
return true;
}
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 34868b576..4133b90d9 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -96,7 +96,7 @@ t_command_server::t_command_server(
m_command_lookup.set_handler(
"start_mining"
, std::bind(&t_command_parser_executor::start_mining, &m_parser, p::_1)
- , "Start mining for specified address, start_mining <addr> [<threads>], default 1 thread"
+ , "Start mining for specified address, start_mining <addr> [<threads>] [do_background_mining], default 1 thread, no background mining"
);
m_command_lookup.set_handler(
"stop_mining"
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index e40136a71..19013cbc8 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -141,6 +141,7 @@ bool t_daemon::run(bool interactive)
}
mp_internals->rpc.stop();
+ mp_internals->core.get().get_miner().stop();
MGINFO("Node stopped.");
return true;
}
@@ -162,6 +163,7 @@ void t_daemon::stop()
{
throw std::runtime_error{"Can't stop stopped daemon"};
}
+ mp_internals->core.get().get_miner().stop();
mp_internals->p2p.stop();
mp_internals->rpc.stop();
mp_internals.reset(nullptr); // Ensure resources are cleaned up before we return
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 469f83014..00b349b15 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -377,7 +377,7 @@ bool t_rpc_command_executor::show_status() {
% (unsigned long long)(ires.target_height >= ires.height ? ires.target_height : ires.height)
% get_sync_percentage(ires)
% (ires.testnet ? "testnet" : "mainnet")
- % (mining_busy ? "syncing" : mres.active ? "mining at " + get_mining_speed(mres.speed) : "not mining")
+ % (mining_busy ? "syncing" : mres.active ? ( ( mres.is_background_mining_enabled ? "smart " : "" ) + std::string("mining at ") + get_mining_speed(mres.speed) ) : "not mining")
% get_mining_speed(ires.difficulty / ires.target)
% (unsigned)hfres.version
% get_fork_extra_info(hfres.earliest_height, ires.height, ires.target)
@@ -929,11 +929,12 @@ bool t_rpc_command_executor::print_transaction_pool_stats() {
return true;
}
-bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet) {
+bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet, bool do_background_mining = false) {
cryptonote::COMMAND_RPC_START_MINING::request req;
cryptonote::COMMAND_RPC_START_MINING::response res;
req.miner_address = cryptonote::get_account_address_as_str(testnet, address);
req.threads_count = num_threads;
+ req.do_background_mining = do_background_mining;
std::string fail_message = "Mining did not start";
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index 4691844fa..5b7b76448 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -106,7 +106,7 @@ public:
bool print_transaction_pool_stats();
- bool start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet);
+ bool start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet, bool do_background_mining);
bool stop_mining();
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 5ed96c00b..4243e35f1 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -112,7 +112,7 @@ namespace nodetool
if (ver == 0)
{
// from v1, we do not store the peer id anymore
- peerid_type peer_id;
+ peerid_type peer_id = AUTO_VAL_INIT (peer_id);
a & peer_id;
}
}
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 5442b6ac4..8165dacbc 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -635,7 +635,7 @@ namespace cryptonote
boost::thread::attributes attrs;
attrs.set_stack_size(THREAD_STACK_SIZE);
- if(!m_core.get_miner().start(adr, static_cast<size_t>(req.threads_count), attrs))
+ if(!m_core.get_miner().start(adr, static_cast<size_t>(req.threads_count), attrs, req.do_background_mining))
{
res.status = "Failed, mining not started";
LOG_PRINT_L0(res.status);
@@ -663,6 +663,7 @@ namespace cryptonote
const miner& lMiner = m_core.get_miner();
res.active = lMiner.is_mining();
+ res.is_background_mining_enabled = lMiner.get_is_background_mining_enabled();
if ( lMiner.is_mining() ) {
res.speed = lMiner.get_speed();
@@ -736,7 +737,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_set_log_categories(const COMMAND_RPC_SET_LOG_CATEGORIES::request& req, COMMAND_RPC_SET_LOG_CATEGORIES::response& res)
{
- mlog_set_categories(req.categories.c_str());
+ mlog_set_log(req.categories.c_str());
res.status = CORE_RPC_STATUS_OK;
return true;
}
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 83ef2ebd4..3ab1ea175 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -500,10 +500,12 @@ namespace cryptonote
{
std::string miner_address;
uint64_t threads_count;
+ bool do_background_mining;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(miner_address)
KV_SERIALIZE(threads_count)
+ KV_SERIALIZE(do_background_mining)
END_KV_SERIALIZE_MAP()
};
@@ -608,6 +610,7 @@ namespace cryptonote
uint64_t speed;
uint32_t threads_count;
std::string address;
+ bool is_background_mining_enabled;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
@@ -615,6 +618,7 @@ namespace cryptonote
KV_SERIALIZE(speed)
KV_SERIALIZE(threads_count)
KV_SERIALIZE(address)
+ KV_SERIALIZE(is_background_mining_enabled)
END_KV_SERIALIZE_MAP()
};
};
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index 8626001ce..3c103bc29 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -126,7 +126,7 @@ endif()
# build and install libwallet_merged only if we building for GUI
if (BUILD_GUI_DEPS)
- set(libs_to_merge wallet cryptonote_core mnemonics common crypto ringct)
+ set(libs_to_merge wallet cryptonote_core cryptonote_basic mnemonics common crypto ringct)
foreach(lib ${libs_to_merge})
list(APPEND objlibs $<TARGET_OBJECTS:obj_${lib}>) # matches naming convention in src/CMakeLists.txt
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 60b7a4dba..b3c40799e 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -43,24 +43,30 @@ if (GTest_FOUND)
include_directories(SYSTEM ${GTEST_INCLUDE_DIRS})
else ()
message(STATUS "GTest not found on the system: will use GTest bundled with this source")
- add_subdirectory(gtest)
- include_directories(SYSTEM "${gtest_SOURCE_DIR}/include" "${gtest_SOURCE_DIR}")
- # Emulate the FindGTest module's variable.
- set(GTEST_LIBRARIES gtest)
-
- # Ignore some warnings when building gtest binaries.
- if(NOT MSVC)
- set_property(TARGET gtest
- APPEND_STRING
- PROPERTY
- COMPILE_FLAGS " -Wno-undef -Wno-sign-compare")
- endif()
+ include(ExternalProject)
+ ExternalProject_Add(googletest
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/gtest
+ BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/gtest
+ DOWNLOAD_COMMAND ""
+ UPDATE_COMMAND ""
+ INSTALL_COMMAND ""
+ )
+ add_library(gtest UNKNOWN IMPORTED)
+ add_library(gtest_main UNKNOWN IMPORTED)
+ set_target_properties(gtest PROPERTIES
+ IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/gtest/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}"
+ )
+ set_target_properties(gtest_main PROPERTIES
+ IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/gtest/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}"
+ )
+ add_dependencies(gtest googletest)
+ add_dependencies(gtest_main googletest)
- set_property(TARGET gtest
- PROPERTY
- FOLDER "${folder}")
-endif ()
+ # Emulate the FindGTest module's variable.
+ set(GTEST_LIBRARIES gtest gtest_main)
+ include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/gtest/include")
+endif (GTest_FOUND)
file(COPY
data/wallet_9svHk1.keys
diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h
index c649f51cc..09e16c4cc 100644
--- a/tests/core_proxy/core_proxy.h
+++ b/tests/core_proxy/core_proxy.h
@@ -92,5 +92,7 @@ namespace tests
bool get_testnet() const { return false; }
bool get_pool_transaction(const crypto::hash& id, cryptonote::transaction& tx) const { return false; }
bool get_blocks(uint64_t start_offset, size_t count, std::list<cryptonote::block>& blocks, std::list<cryptonote::transaction>& txs) const { return false; }
+ bool get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<cryptonote::transaction>& txs, std::list<crypto::hash>& missed_txs) const { return false; }
+ bool get_block_by_hash(const crypto::hash &h, cryptonote::block &blk, bool *orphan = NULL) const { return false; }
};
}
diff --git a/tests/performance_tests/cn_fast_hash.h b/tests/performance_tests/cn_fast_hash.h
new file mode 100644
index 000000000..24f2bc5e2
--- /dev/null
+++ b/tests/performance_tests/cn_fast_hash.h
@@ -0,0 +1,57 @@
+// 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include "crypto/crypto.h"
+#include "cryptonote_core/cryptonote_basic.h"
+
+template<size_t bytes>
+class test_cn_fast_hash
+{
+public:
+ static const size_t loop_count = bytes < 256 ? 100000 : bytes < 4096 ? 10000 : 1000;
+
+ bool init()
+ {
+ crypto::rand(bytes, m_data.data());
+ return true;
+ }
+
+ bool test()
+ {
+ crypto::hash hash;
+ crypto::cn_fast_hash(&m_data, bytes, hash);
+ return true;
+ }
+
+private:
+ std::array<uint8_t, bytes> m_data;
+};
diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp
index d08698433..cc9fe86ef 100644
--- a/tests/performance_tests/main.cpp
+++ b/tests/performance_tests/main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -43,12 +43,17 @@
#include "generate_key_image_helper.h"
#include "generate_keypair.h"
#include "is_out_to_acc.h"
+#include "sc_reduce32.h"
+#include "cn_fast_hash.h"
int main(int argc, char** argv)
{
set_process_affinity(1);
set_thread_high_priority();
+ mlog_configure(mlog_get_default_log_path("performance_tests.log"), true);
+ mlog_set_log_level(0);
+
performance_timer timer;
timer.start();
@@ -102,8 +107,11 @@ int main(int argc, char** argv)
TEST_PERFORMANCE0(test_derive_secret_key);
TEST_PERFORMANCE0(test_ge_frombytes_vartime);
TEST_PERFORMANCE0(test_generate_keypair);
+ TEST_PERFORMANCE0(test_sc_reduce32);
TEST_PERFORMANCE0(test_cn_slow_hash);
+ TEST_PERFORMANCE1(test_cn_fast_hash, 32);
+ TEST_PERFORMANCE1(test_cn_fast_hash, 16384);
std::cout << "Tests finished. Elapsed time: " << timer.elapsed_ms() / 1000 << " sec" << std::endl;
diff --git a/tests/performance_tests/performance_tests.h b/tests/performance_tests/performance_tests.h
index 77707148b..88e8b592c 100644
--- a/tests/performance_tests/performance_tests.h
+++ b/tests/performance_tests/performance_tests.h
@@ -95,10 +95,10 @@ public:
int elapsed_time() const { return m_elapsed; }
- int time_per_call() const
+ int time_per_call(int scale = 1) const
{
static_assert(0 < T::loop_count, "T::loop_count must be greater than 0");
- return m_elapsed / T::loop_count;
+ return m_elapsed * scale / T::loop_count;
}
private:
@@ -130,7 +130,17 @@ void run_test(const char* test_name)
std::cout << test_name << " - OK:\n";
std::cout << " loop count: " << T::loop_count << '\n';
std::cout << " elapsed: " << runner.elapsed_time() << " ms\n";
- std::cout << " time per call: " << runner.time_per_call() << " ms/call\n" << std::endl;
+ const char *unit = "ms";
+ int time_per_call = runner.time_per_call();
+ if (time_per_call < 30000) {
+ time_per_call = runner.time_per_call(1000);
+#ifdef _WIN32
+ unit = "\xb5s";
+#else
+ unit = "µs";
+#endif
+ }
+ std::cout << " time per call: " << time_per_call << " " << unit << "/call\n" << std::endl;
}
else
{
diff --git a/tests/performance_tests/sc_reduce32.h b/tests/performance_tests/sc_reduce32.h
new file mode 100644
index 000000000..bb3ad1694
--- /dev/null
+++ b/tests/performance_tests/sc_reduce32.h
@@ -0,0 +1,53 @@
+// 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.
+
+#pragma once
+
+#include "crypto/crypto.h"
+
+class test_sc_reduce32
+{
+public:
+ static const size_t loop_count = 10000000;
+
+ bool init()
+ {
+ m_hash = crypto::rand<crypto::hash>();
+ return true;
+ }
+
+ bool test()
+ {
+ crypto::hash reduced = m_hash;
+ sc_reduce32((unsigned char*)reduced.data);
+ return true;
+ }
+
+private:
+ crypto::hash m_hash;
+};
diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp
index c6a3a14f0..88bbf7eec 100644
--- a/tests/unit_tests/ban.cpp
+++ b/tests/unit_tests/ban.cpp
@@ -67,6 +67,8 @@ public:
bool get_testnet() const { return false; }
bool get_pool_transaction(const crypto::hash& id, cryptonote::transaction& tx) const { return false; }
bool get_blocks(uint64_t start_offset, size_t count, std::list<cryptonote::block>& blocks, std::list<cryptonote::transaction>& txs) const { return false; }
+ bool get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<cryptonote::transaction>& txs, std::list<crypto::hash>& missed_txs) const { return false; }
+ bool get_block_by_hash(const crypto::hash &h, cryptonote::block &blk, bool *orphan = NULL) const { return false; }
};
typedef nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<test_core>> Server;