aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rw-r--r--Makefile40
-rw-r--r--README.md4
-rw-r--r--contrib/epee/include/net/http_client.h4
-rw-r--r--contrib/epee/src/mlog.cpp2
-rw-r--r--src/blockchain_db/blockchain_db.h2
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp141
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h9
-rw-r--r--src/common/CMakeLists.txt9
-rw-r--r--src/common/command_line.cpp5
-rw-r--r--src/common/command_line.h1
-rw-r--r--src/common/dns_utils.cpp102
-rw-r--r--src/common/dns_utils.h2
-rw-r--r--src/common/download.cpp138
-rw-r--r--src/common/download.h36
-rw-r--r--src/common/updates.cpp114
-rw-r--r--src/common/updates.h37
-rw-r--r--src/common/util.cpp52
-rw-r--r--src/common/util.h3
-rw-r--r--src/cryptonote_basic/checkpoints.cpp109
-rw-r--r--src/cryptonote_basic/hardfork.cpp6
-rw-r--r--src/cryptonote_basic/miner.cpp84
-rw-r--r--src/cryptonote_basic/miner.h8
-rw-r--r--src/cryptonote_core/blockchain.cpp6
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp137
-rw-r--r--src/cryptonote_core/cryptonote_core.h37
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.cpp2
-rw-r--r--src/cryptonote_core/tx_pool.cpp16
-rw-r--r--src/daemon/command_parser_executor.cpp12
-rw-r--r--src/daemon/command_server.cpp2
-rw-r--r--src/daemon/rpc_command_executor.cpp5
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/ringct/rctOps.h4
-rw-r--r--src/rpc/core_rpc_server.cpp5
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h2
-rw-r--r--src/simplewallet/simplewallet.cpp18
-rw-r--r--src/wallet/api/wallet.cpp6
-rw-r--r--src/wallet/api/wallet_manager.cpp4
-rw-r--r--src/wallet/wallet2.cpp16
-rw-r--r--src/wallet/wallet_rpc_server.cpp8
-rw-r--r--tests/performance_tests/cn_fast_hash.h2
-rw-r--r--tests/unit_tests/CMakeLists.txt3
-rw-r--r--tests/unit_tests/blockchain_db.cpp2
-rw-r--r--tests/unit_tests/vercmp.cpp43
44 files changed, 952 insertions, 296 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f59493345..c01be24d4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -88,6 +88,14 @@ else()
set(OPT_FLAGS_RELEASE "-Ofast")
endif()
+# BUILD_TAG is used to select the build type to check for a new version
+if(BUILD_TAG)
+ message(STATUS "Building build tag ${BUILD_TAG}")
+ add_definitions("-DBUILD_TAG=${BUILD_TAG}")
+else()
+ message(STATUS "Building without build tag")
+endif()
+
set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG ${OPT_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${OPT_FLAGS_RELEASE}")
diff --git a/Makefile b/Makefile
index e6517ebac..3ee9d0e3e 100644
--- a/Makefile
+++ b/Makefile
@@ -58,43 +58,55 @@ release-all:
mkdir -p build/release
cd build/release && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
+release-static:
+ mkdir -p build/release
+ cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
+
coverage:
mkdir -p build/debug
cd build/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug -D COVERAGE=ON ../.. && $(MAKE) && $(MAKE) test
-release-static-armv6:
+# Targets for specific prebuilt builds which will be advertised for updates by their build tag
+
+release-static-linux-armv6:
mkdir -p build/release
- cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv6zk" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
+ cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv6zk" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv6" ../.. && $(MAKE)
-release-static-armv7:
+release-static-linux-armv7:
mkdir -p build/release
- cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
+ cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv7" ../.. && $(MAKE)
release-static-android:
mkdir -p build/release
- cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON ../.. && $(MAKE)
+ cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG="android"../.. && $(MAKE)
-release-static-armv8:
+release-static-linux-armv8:
mkdir -p build/release
- cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
+ cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv8" ../.. && $(MAKE)
-release-static: release-static-64
+release-static-linux-x86_64:
+ mkdir -p build/release
+ cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x64" ../.. && $(MAKE)
-release-static-64:
+release-static-freebsd-x86_64:
mkdir -p build/release
- cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
+ cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="freebsd-x64" ../.. && $(MAKE)
+
+release-static-freebsd-x86_64:
+ mkdir -p build/release
+ cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="mac-x64" ../.. && $(MAKE)
-release-static-32:
+release-static-linux-i686:
mkdir -p build/release
- cd build/release && cmake -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
+ cd build/release && cmake -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x86" ../.. && $(MAKE)
release-static-win64:
mkdir -p build/release
- cd build/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D CMAKE_TOOLCHAIN_FILE=../../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 ../.. && $(MAKE)
+ cd build/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=../../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 ../.. && $(MAKE)
release-static-win32:
mkdir -p build/release
- cd build/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=Release -D CMAKE_TOOLCHAIN_FILE=../../cmake/32-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys32 ../.. && $(MAKE)
+ cd build/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x32" -D CMAKE_TOOLCHAIN_FILE=../../cmake/32-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys32 ../.. && $(MAKE)
clean:
@echo "WARNING: Back-up your wallet if it exists within ./build!" ; \
diff --git a/README.md b/README.md
index 436e8398d..30b2cad89 100644
--- a/README.md
+++ b/README.md
@@ -97,7 +97,9 @@ Dates are provided in the format YYYYMMDD.
Packages are available for
-* Arch Linux via AUR: [`bitmonero-git`](https://aur.archlinux.org/packages/bitmonero-git)
+* Arch Linux (via [AUR](https://aur.archlinux.org/)):
+ - Stable release: [`monero`](https://aur.archlinux.org/packages/monero)
+ - Bleeding edge: [`bitmonero-git`](https://aur.archlinux.org/packages/bitmonero-git)
* OS X via [Homebrew](http://brew.sh)
diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h
index 3d8c759cd..d73eda39c 100644
--- a/contrib/epee/include/net/http_client.h
+++ b/contrib/epee/include/net/http_client.h
@@ -107,14 +107,14 @@ using namespace std;
//---------------------------------------------------------------------------
static inline const char* get_hex_vals()
{
- static char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ static const char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
return hexVals;
}
static inline const char* get_unsave_chars()
{
//static char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&";
- static char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&";
+ static const char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&";
return unsave_chars;
}
diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp
index c212456f6..995674abd 100644
--- a/contrib/epee/src/mlog.cpp
+++ b/contrib/epee/src/mlog.cpp
@@ -88,7 +88,7 @@ static const char *get_default_categories(int level)
switch (level)
{
case 0:
- categories = "*:WARNING,net*:FATAL,global:INFO,verify:FATAL,stacktrace:INFO";
+ categories = "*:WARNING,net:FATAL,global:INFO,verify:FATAL,stacktrace:INFO";
break;
case 1:
categories = "*:WARNING,global:INFO,stacktrace:INFO";
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 3fdb62a7b..b40793241 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1184,7 +1184,7 @@ public:
* @param offsets a list of amount-specific output indices
* @param outputs return-by-reference a list of outputs' metadata
*/
- virtual void get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs) = 0;
+ virtual void get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) = 0;
/*
* FIXME: Need to check with git blame and ask what this does to
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 0a35325e4..839d0dd37 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -377,7 +377,50 @@ void mdb_txn_safe::allow_new_txns()
creation_gate.clear();
}
+void lmdb_resized(MDB_env *env)
+{
+ mdb_txn_safe::prevent_new_txns();
+
+ MGINFO("LMDB map resize detected.");
+
+ MDB_envinfo mei;
+
+ mdb_env_info(env, &mei);
+ uint64_t old = mei.me_mapsize;
+
+ mdb_txn_safe::wait_no_active_txns();
+
+ int result = mdb_env_set_mapsize(env, 0);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to set new mapsize: ", result).c_str()));
+
+ mdb_env_info(env, &mei);
+ uint64_t new_mapsize = mei.me_mapsize;
+
+ MGINFO("LMDB Mapsize increased." << " Old: " << old / (1024 * 1024) << "MiB" << ", New: " << new_mapsize / (1024 * 1024) << "MiB");
+
+ mdb_txn_safe::allow_new_txns();
+}
+
+inline int lmdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **txn)
+{
+ int res = mdb_txn_begin(env, parent, flags, txn);
+ if (res == MDB_MAP_RESIZED) {
+ lmdb_resized(env);
+ res = mdb_txn_begin(env, parent, flags, txn);
+ }
+ return res;
+}
+inline int lmdb_txn_renew(MDB_txn *txn)
+{
+ int res = mdb_txn_renew(txn);
+ if (res == MDB_MAP_RESIZED) {
+ lmdb_resized(mdb_txn_env(txn));
+ res = mdb_txn_renew(txn);
+ }
+ return res;
+}
void BlockchainLMDB::do_resize(uint64_t increase_size)
{
@@ -561,7 +604,7 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con
{
LOG_PRINT_L1("No existing blocks to check for average block size");
}
- else if (m_cum_count)
+ else if (m_cum_count >= num_prev_blocks)
{
avg_block_size = m_cum_size / m_cum_count;
LOG_PRINT_L1("average block size across recent " << m_cum_count << " blocks: " << avg_block_size);
@@ -570,6 +613,9 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con
}
else
{
+ MDB_txn *rtxn;
+ mdb_txn_cursors *rcurs;
+ block_rtxn_start(&rtxn, &rcurs);
for (uint64_t block_num = block_start; block_num <= block_stop; ++block_num)
{
uint32_t block_size = get_block_size(block_num);
@@ -578,6 +624,7 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con
// some blocks were to be skipped for being outliers.
++num_blocks_used;
}
+ block_rtxn_stop();
avg_block_size = total_block_size / num_blocks_used;
LOG_PRINT_L1("average block size across recent " << num_blocks_used << " blocks: " << avg_block_size);
}
@@ -702,7 +749,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
uint64_t m_height = height();
int result;
- uint64_t tx_id = m_num_txs;
+ uint64_t tx_id = num_txs();
CURSOR(txs)
CURSOR(tx_indices)
@@ -735,7 +782,6 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
if (result)
throw0(DB_ERROR(lmdb_error("Failed to add tx blob to db transaction: ", result).c_str()));
- m_num_txs++;
return tx_id;
}
@@ -783,8 +829,6 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
// Don't delete the tx_indices entry until the end, after we're done with val_tx_id
if (mdb_cursor_del(m_cur_tx_indices, 0))
throw1(DB_ERROR("Failed to add removal of tx index to db transaction"));
-
- m_num_txs--;
}
uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash,
@@ -797,6 +841,7 @@ uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash,
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
uint64_t m_height = height();
+ uint64_t m_num_outputs = num_outputs();
int result = 0;
@@ -849,7 +894,6 @@ uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash,
if ((result = mdb_cursor_put(m_cur_output_amounts, &val_amount, &data, MDB_APPENDDUP)))
throw0(DB_ERROR(lmdb_error("Failed to add output pubkey to db transaction: ", result).c_str()));
- m_num_outputs++;
return ok.amount_index;
}
@@ -934,8 +978,6 @@ void BlockchainLMDB::remove_output(const uint64_t amount, const uint64_t& out_in
result = mdb_cursor_del(m_cur_output_amounts, 0);
if (result)
throw0(DB_ERROR(lmdb_error(std::string("Error deleting amount for output index ").append(boost::lexical_cast<std::string>(out_index).append(": ")).c_str(), result).c_str()));
-
- m_num_outputs--;
}
void BlockchainLMDB::add_spent_key(const crypto::key_image& k_image)
@@ -1000,7 +1042,7 @@ tx_out BlockchainLMDB::output_from_blob(const blobdata& blob) const
void BlockchainLMDB::check_open() const
{
- LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+// LOG_PRINT_L3("BlockchainLMDB::" << __func__);
if (!m_open)
throw0(DB_ERROR("DB operation attempted on a not-open DB instance"));
}
@@ -1155,16 +1197,6 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
LOG_PRINT_L2("Setting m_height to: " << db_stats.ms_entries);
uint64_t m_height = db_stats.ms_entries;
- // get and keep current number of txs
- if ((result = mdb_stat(txn, m_txs, &db_stats)))
- throw0(DB_ERROR(lmdb_error("Failed to query m_txs: ", result).c_str()));
- m_num_txs = db_stats.ms_entries;
-
- // get and keep current number of outputs
- if ((result = mdb_stat(txn, m_output_txs, &db_stats)))
- throw0(DB_ERROR(lmdb_error("Failed to query m_output_txs: ", result).c_str()));
- m_num_outputs = db_stats.ms_entries;
-
bool compatible = true;
MDB_val_copy<const char*> k("version");
@@ -1270,7 +1302,7 @@ void BlockchainLMDB::reset()
check_open();
mdb_txn_safe txn;
- if (auto result = mdb_txn_begin(m_env, NULL, 0, txn))
+ if (auto result = lmdb_txn_begin(m_env, NULL, 0, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
if (auto result = mdb_drop(txn, m_blocks, 0))
@@ -1304,7 +1336,6 @@ void BlockchainLMDB::reset()
throw0(DB_ERROR(lmdb_error("Failed to write version to database: ", result).c_str()));
txn.commit();
- m_num_outputs = 0;
m_cum_size = 0;
m_cum_count = 0;
}
@@ -1354,7 +1385,7 @@ void BlockchainLMDB::unlock()
txn_ptr = m_write_txn; \
else \
{ \
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, flags, auto_txn)) \
+ if (auto mdb_res = lmdb_txn_begin(m_env, NULL, flags, auto_txn)) \
throw0(DB_ERROR(lmdb_error(std::string("Failed to create a transaction for the db in ")+__FUNCTION__+": ", mdb_res).c_str())); \
} \
@@ -1388,7 +1419,7 @@ void BlockchainLMDB::unlock()
txn_ptr = m_write_txn; \
else \
{ \
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, flags, auto_txn)) \
+ if (auto mdb_res = lmdb_txn_begin(m_env, NULL, flags, auto_txn)) \
throw0(DB_ERROR(lmdb_error(std::string("Failed to create a transaction for the db in ")+__FUNCTION__+": ", mdb_res).c_str())); \
} \
@@ -1714,6 +1745,34 @@ uint64_t BlockchainLMDB::height() const
return db_stats.ms_entries;
}
+uint64_t BlockchainLMDB::num_txs() const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ TXN_PREFIX_RDONLY();
+ int result;
+
+ // get current height
+ MDB_stat db_stats;
+ if ((result = mdb_stat(m_txn, m_txs, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_txs: ", result).c_str()));
+ return db_stats.ms_entries;
+}
+
+uint64_t BlockchainLMDB::num_outputs() const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ TXN_PREFIX_RDONLY();
+ int result;
+
+ // get current height
+ MDB_stat db_stats;
+ if ((result = mdb_stat(m_txn, m_output_txs, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_output_txs: ", result).c_str()));
+ return db_stats.ms_entries;
+}
+
bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -2279,7 +2338,7 @@ bool BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
m_write_batch_txn = new mdb_txn_safe();
// NOTE: need to make sure it's destroyed properly when done
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, 0, *m_write_batch_txn))
+ if (auto mdb_res = lmdb_txn_begin(m_env, NULL, 0, *m_write_batch_txn))
{
delete m_write_batch_txn;
m_write_batch_txn = nullptr;
@@ -2398,12 +2457,12 @@ bool BlockchainLMDB::block_rtxn_start(MDB_txn **mtxn, mdb_txn_cursors **mcur) co
m_tinfo.reset(new mdb_threadinfo);
memset(&m_tinfo->m_ti_rcursors, 0, sizeof(m_tinfo->m_ti_rcursors));
memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
+ if (auto mdb_res = lmdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to create a read transaction for the db: ", mdb_res).c_str()));
ret = true;
} else if (!m_tinfo->m_ti_rflags.m_rf_txn)
{
- if (auto mdb_res = mdb_txn_renew(m_tinfo->m_ti_rtxn))
+ if (auto mdb_res = lmdb_txn_renew(m_tinfo->m_ti_rtxn))
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to renew a read transaction for the db: ", mdb_res).c_str()));
ret = true;
}
@@ -2436,12 +2495,12 @@ void BlockchainLMDB::block_txn_start(bool readonly)
m_tinfo.reset(new mdb_threadinfo);
memset(&m_tinfo->m_ti_rcursors, 0, sizeof(m_tinfo->m_ti_rcursors));
memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
+ if (auto mdb_res = lmdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to create a read transaction for the db: ", mdb_res).c_str()));
didit = true;
} else if (!m_tinfo->m_ti_rflags.m_rf_txn)
{
- if (auto mdb_res = mdb_txn_renew(m_tinfo->m_ti_rtxn))
+ if (auto mdb_res = lmdb_txn_renew(m_tinfo->m_ti_rtxn))
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to renew a read transaction for the db: ", mdb_res).c_str()));
didit = true;
}
@@ -2467,7 +2526,7 @@ void BlockchainLMDB::block_txn_start(bool readonly)
{
m_writer = boost::this_thread::get_id();
m_write_txn = new mdb_txn_safe();
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, 0, *m_write_txn))
+ if (auto mdb_res = lmdb_txn_begin(m_env, NULL, 0, *m_write_txn))
{
delete m_write_txn;
m_write_txn = nullptr;
@@ -2545,8 +2604,6 @@ uint64_t BlockchainLMDB::add_block(const block& blk, const size_t& block_size, c
}
}
- uint64_t num_txs = m_num_txs;
- uint64_t num_outputs = m_num_outputs;
try
{
BlockchainDB::add_block(blk, block_size, cumulative_difficulty, coins_generated, txs);
@@ -2557,8 +2614,6 @@ uint64_t BlockchainLMDB::add_block(const block& blk, const size_t& block_size, c
}
catch (...)
{
- m_num_txs = num_txs;
- m_num_outputs = num_outputs;
block_txn_abort();
throw;
}
@@ -2573,8 +2628,6 @@ void BlockchainLMDB::pop_block(block& blk, std::vector<transaction>& txs)
block_txn_start(false);
- uint64_t num_txs = m_num_txs;
- uint64_t num_outputs = m_num_outputs;
try
{
BlockchainDB::pop_block(blk, txs);
@@ -2582,8 +2635,6 @@ void BlockchainLMDB::pop_block(block& blk, std::vector<transaction>& txs)
}
catch (...)
{
- m_num_txs = num_txs;
- m_num_outputs = num_outputs;
block_txn_abort();
throw;
}
@@ -2617,7 +2668,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
TXN_POSTFIX_RDONLY();
}
-void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs)
+void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
TIME_MEASURE_START(db3);
@@ -2635,7 +2686,14 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<ui
auto get_result = mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_GET_BOTH);
if (get_result == MDB_NOTFOUND)
+ {
+ if (allow_partial)
+ {
+ MDEBUG("Partial result: " << outputs.size() << "/" << offsets.size());
+ break;
+ }
throw1(OUTPUT_DNE((std::string("Attempting to get output pubkey by global index (amount ") + boost::lexical_cast<std::string>(amount) + ", index " + boost::lexical_cast<std::string>(index) + ", count " + boost::lexical_cast<std::string>(get_num_outputs(amount)) + "), but key does not exist").c_str()));
+ }
else if (get_result)
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve an output pubkey from the db", get_result).c_str()));
@@ -3257,8 +3315,6 @@ void BlockchainLMDB::migrate_0_1()
lmdb_db_open(txn, LMDB_OUTPUT_AMOUNTS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_output_amounts, "Failed to open db handle for m_output_amounts");
mdb_set_dupsort(txn, m_output_amounts, compare_uint64);
txn.commit();
- m_num_txs = 0;
- m_num_outputs = 0;
} while(0);
do {
@@ -3329,12 +3385,9 @@ void BlockchainLMDB::migrate_0_1()
throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs: ", result).c_str()));
if (!i) {
MDB_stat ms;
- mdb_stat(txn, m_output_txs, &ms);
- m_num_outputs = ms.ms_entries;
mdb_stat(txn, m_txs, &ms);
- m_num_txs = i = ms.ms_entries;
+ i = ms.ms_entries;
if (i) {
- m_num_txs = i;
MDB_val_set(pk, "txblk");
result = mdb_cursor_get(c_props, &pk, &k, MDB_SET);
if (result)
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index e7faf8cdc..32236bbbd 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -221,7 +221,7 @@ public:
virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index);
virtual output_data_t get_output_key(const uint64_t& global_index) const;
- virtual void get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs);
+ virtual void get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false);
virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const;
virtual void get_output_tx_and_index_from_global(const std::vector<uint64_t> &global_indices,
@@ -312,6 +312,9 @@ private:
virtual void remove_spent_key(const crypto::key_image& k_image);
+ uint64_t num_txs() const;
+ uint64_t num_outputs() const;
+
// Hard fork
virtual void set_hard_fork_version(uint64_t height, uint8_t version);
virtual uint8_t get_hard_fork_version(uint64_t height) const;
@@ -369,10 +372,8 @@ private:
MDB_dbi m_properties;
- uint64_t m_num_txs;
- uint64_t m_num_outputs;
mutable uint64_t m_cum_size; // used in batch size estimation
- mutable int m_cum_count;
+ mutable unsigned int m_cum_count;
std::string m_folder;
mdb_txn_safe* m_write_txn; // may point to either a short-lived txn or a batch txn
mdb_txn_safe* m_write_batch_txn; // persist batch txn outside of BlockchainLMDB
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index c63d9d0ae..eb4d4c25d 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -30,12 +30,14 @@ set(common_sources
base58.cpp
command_line.cpp
dns_utils.cpp
+ download.cpp
util.cpp
i18n.cpp
password.cpp
perf_timer.cpp
task_region.cpp
- thread_group.cpp)
+ thread_group.cpp
+ updates.cpp)
if (STACK_TRACE)
list(APPEND common_sources stack_trace.cpp)
@@ -49,6 +51,7 @@ set(common_private_headers
command_line.h
common_fwd.h
dns_utils.h
+ download.h
http_connection.h
int-util.h
pod-class.h
@@ -62,7 +65,8 @@ set(common_private_headers
perf_timer.h
stack_trace.h
task_region.h
- thread_group.h)
+ thread_group.h
+ updates.h)
monero_private_headers(common
${common_private_headers})
@@ -74,6 +78,7 @@ target_link_libraries(common
PUBLIC
epee
crypto
+ -lcrypto
${UNBOUND_LIBRARY}
${LIBUNWIND_LIBRARIES}
${Boost_DATE_TIME_LIBRARY}
diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp
index c3df5c096..8739a93cd 100644
--- a/src/common/command_line.cpp
+++ b/src/common/command_line.cpp
@@ -120,4 +120,9 @@ namespace command_line
, "How many blocks to sync at once during chain synchronization."
, BLOCKS_SYNCHRONIZING_DEFAULT_COUNT
};
+ const command_line::arg_descriptor<std::string> arg_check_updates = {
+ "check-updates"
+ , "Check for new versions of monero: [disabled|notify|download|update]"
+ , "notify"
+ };
}
diff --git a/src/common/command_line.h b/src/common/command_line.h
index a09365a6b..f10e68e13 100644
--- a/src/common/command_line.h
+++ b/src/common/command_line.h
@@ -218,4 +218,5 @@ namespace command_line
extern const arg_descriptor<uint64_t> arg_prep_blocks_threads;
extern const arg_descriptor<uint64_t> arg_show_time_stats;
extern const arg_descriptor<size_t> arg_block_sync_size;
+ extern const arg_descriptor<std::string> arg_check_updates;
}
diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp
index 5ff39574c..f7655e3c7 100644
--- a/src/common/dns_utils.cpp
+++ b/src/common/dns_utils.cpp
@@ -37,6 +37,7 @@
#include <stdlib.h>
#include "include_base_utils.h"
+#include <random>
#include <boost/filesystem/fstream.hpp>
using namespace epee;
namespace bf = boost::filesystem;
@@ -451,6 +452,107 @@ std::string get_account_address_as_str_from_url(const std::string& url, bool& dn
return addresses[0];
}
+namespace
+{
+ bool dns_records_match(const std::vector<std::string>& a, const std::vector<std::string>& b)
+ {
+ if (a.size() != b.size()) return false;
+
+ for (const auto& record_in_a : a)
+ {
+ bool ok = false;
+ for (const auto& record_in_b : b)
+ {
+ if (record_in_a == record_in_b)
+ {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok) return false;
+ }
+
+ return true;
+ }
+}
+
+bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std::vector<std::string> &dns_urls)
+{
+ std::vector<std::vector<std::string> > records;
+ records.resize(dns_urls.size());
+
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_int_distribution<int> dis(0, dns_urls.size() - 1);
+ size_t first_index = dis(gen);
+
+ bool avail, valid;
+ size_t cur_index = first_index;
+ do
+ {
+ std::string url = dns_urls[cur_index];
+
+ records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid);
+ if (!avail)
+ {
+ records[cur_index].clear();
+ LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping.");
+ }
+ if (!valid)
+ {
+ records[cur_index].clear();
+ LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping.");
+ }
+
+ cur_index++;
+ if (cur_index == dns_urls.size())
+ {
+ cur_index = 0;
+ }
+ } while (cur_index != first_index);
+
+ size_t num_valid_records = 0;
+
+ for( const auto& record_set : records)
+ {
+ if (record_set.size() != 0)
+ {
+ num_valid_records++;
+ }
+ }
+
+ if (num_valid_records < 2)
+ {
+ LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received");
+ return false;
+ }
+
+ int good_records_index = -1;
+ for (size_t i = 0; i < records.size() - 1; ++i)
+ {
+ if (records[i].size() == 0) continue;
+
+ for (size_t j = i + 1; j < records.size(); ++j)
+ {
+ if (dns_records_match(records[i], records[j]))
+ {
+ good_records_index = i;
+ break;
+ }
+ }
+ if (good_records_index >= 0) break;
+ }
+
+ if (good_records_index < 0)
+ {
+ LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched");
+ return false;
+ }
+
+ good_records = records[good_records_index];
+ return true;
+}
+
} // namespace tools::dns_utils
} // namespace tools
diff --git a/src/common/dns_utils.h b/src/common/dns_utils.h
index 6ecf5595c..2e881f0e0 100644
--- a/src/common/dns_utils.h
+++ b/src/common/dns_utils.h
@@ -165,6 +165,8 @@ std::vector<std::string> addresses_from_url(const std::string& url, bool& dnssec
std::string get_account_address_as_str_from_url(const std::string& url, bool& dnssec_valid);
+bool load_txt_records_from_dns(std::vector<std::string> &records, const std::vector<std::string> &dns_urls);
+
} // namespace tools::dns_utils
} // namespace tools
diff --git a/src/common/download.cpp b/src/common/download.cpp
new file mode 100644
index 000000000..c5ee797d0
--- /dev/null
+++ b/src/common/download.cpp
@@ -0,0 +1,138 @@
+// 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 <string>
+#include <boost/filesystem.hpp>
+#include <boost/asio.hpp>
+#include <boost/thread/thread.hpp>
+#include "cryptonote_config.h"
+#include "include_base_utils.h"
+#include "net/http_client.h"
+#include "download.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "net.dl"
+
+namespace tools
+{
+ static bool download_thread(const std::string &path, const std::string &url)
+ {
+ try
+ {
+ MINFO("Downloading " << url << " to " << path);
+ std::ofstream f;
+ f.open(path, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
+ if (!f.good()) {
+ MERROR("Failed to open file " << path);
+ return false;
+ }
+ class download_client: public epee::net_utils::http::http_simple_client
+ {
+ public:
+ download_client(std::ofstream &f): f(f) {}
+ virtual ~download_client() { f.close(); }
+ virtual bool handle_target_data(std::string &piece_of_transfer)
+ {
+ try
+ {
+ f << piece_of_transfer;
+ return f.good();
+ }
+ catch (const std::exception &e)
+ {
+ MERROR("Error writing data: " << e.what());
+ return false;
+ }
+ }
+ private:
+ std::ofstream &f;
+ } client(f);
+ epee::net_utils::http::url_content u_c;
+ if (!epee::net_utils::parse_url(url, u_c))
+ {
+ MWARNING("Failed to parse URL " << url);
+ return false;
+ }
+ if (u_c.host.empty())
+ {
+ MWARNING("Failed to determine address from URL " << url);
+ return false;
+ }
+ uint16_t port = u_c.port ? u_c.port : 80;
+ MDEBUG("Connecting to " << u_c.host << ":" << port);
+ client.set_server(u_c.host, std::to_string(port), boost::none);
+ if (!client.connect(std::chrono::seconds(30)))
+ {
+ MERROR("Failed to connect to " << url);
+ return false;
+ }
+ MDEBUG("GETting " << u_c.uri);
+ const epee::net_utils::http::http_response_info *info = NULL;
+ if (!client.invoke_get(u_c.uri, std::chrono::seconds(30), "", &info))
+ {
+ MERROR("Failed to connect to " << url);
+ client.disconnect();
+ return false;
+ }
+ if (!info)
+ {
+ MERROR("Failed invoking GET command to " << url << ", no status info returned");
+ client.disconnect();
+ return false;
+ }
+ MDEBUG("response code: " << info->m_response_code);
+ MDEBUG("response comment: " << info->m_response_comment);
+ MDEBUG("response body: " << info->m_body);
+ for (const auto &f: info->m_additional_fields)
+ MDEBUG("additional field: " << f.first << ": " << f.second);
+ if (info->m_response_code != 200)
+ {
+ MERROR("Status code " << info->m_response_code);
+ client.disconnect();
+ return false;
+ }
+ client.disconnect();
+ f.close();
+ MDEBUG("Download complete");
+ return true;
+ }
+ catch (const std::exception &e)
+ {
+ MERROR("Exception in download thread: " << e.what());
+ return false;
+ }
+ }
+
+ bool download(const std::string &path, const std::string &url)
+ {
+ bool success;
+ std::unique_ptr<boost::thread> thread(new boost::thread([&](){ success = download_thread(path, url); }));
+ thread->join();
+ return success;
+ }
+}
diff --git a/src/common/download.h b/src/common/download.h
new file mode 100644
index 000000000..ab7644689
--- /dev/null
+++ b/src/common/download.h
@@ -0,0 +1,36 @@
+// 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 <string>
+
+namespace tools
+{
+ bool download(const std::string &path, const std::string &url);
+}
diff --git a/src/common/updates.cpp b/src/common/updates.cpp
new file mode 100644
index 000000000..936106881
--- /dev/null
+++ b/src/common/updates.cpp
@@ -0,0 +1,114 @@
+// 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 "util.h"
+#include "dns_utils.h"
+#include "updates.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "updates"
+
+namespace tools
+{
+ bool check_updates(const std::string &software, const std::string &buildtag, bool testnet, std::string &version, std::string &hash)
+ {
+ std::vector<std::string> records;
+ bool found = false;
+
+ MDEBUG("Checking updates for " << buildtag << " " << software);
+
+ // All four MoneroPulse domains have DNSSEC on and valid
+ static const std::vector<std::string> dns_urls = {
+ };
+
+ static const std::vector<std::string> testnet_dns_urls = { "testver.moneropulse.net"
+ };
+
+ if (!tools::dns_utils::load_txt_records_from_dns(records, testnet ? testnet_dns_urls : dns_urls))
+ return false;
+
+ for (const auto& record : records)
+ {
+ std::vector<std::string> fields;
+ boost::split(fields, record, boost::is_any_of(":"));
+ if (fields.size() != 4)
+ {
+ MWARNING("Updates record does not have 4 fields: " << record);
+ continue;
+ }
+
+ if (software != fields[0] || buildtag != fields[1])
+ continue;
+
+ bool alnum = true;
+ for (auto c: hash)
+ if (!isalnum(c))
+ alnum = false;
+ if (hash.size() != 64 && !alnum)
+ {
+ MWARNING("Invalid hash: " << hash);
+ continue;
+ }
+
+ // use highest version
+ if (found)
+ {
+ int cmp = vercmp(version.c_str(), fields[2].c_str());
+ if (cmp > 0)
+ continue;
+ if (cmp == 0 && hash != fields[3])
+ MWARNING("Two matches found for " << software << " version " << version << " on " << buildtag);
+ }
+
+ version = fields[2];
+ hash = fields[3];
+
+ MINFO("Found new version " << version << " with hash " << hash);
+ found = true;
+ }
+ return found;
+ }
+
+ std::string get_update_url(const std::string &software, const std::string &subdir, const std::string &buildtag, const std::string &version)
+ {
+ static const char base[] = "https://downloads.getmonero.org/";
+#ifdef _WIN32
+ static const char extension[] = ".zip";
+#else
+ static const char extension[] = ".tar.bz2";
+#endif
+
+ std::string url;
+
+ url = base;
+ if (!subdir.empty())
+ url += subdir + "/";
+ url = url + software + "-" + buildtag + "-v" + version + extension;
+ return url;
+ }
+}
diff --git a/src/common/updates.h b/src/common/updates.h
new file mode 100644
index 000000000..1a70e06fd
--- /dev/null
+++ b/src/common/updates.h
@@ -0,0 +1,37 @@
+// 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 <string>
+
+namespace tools
+{
+ bool check_updates(const std::string &software, const std::string &buildtag, bool bestnet, std::string &version, std::string &hash);
+ std::string get_update_url(const std::string &software, const std::string &subdir, const std::string &buildtag, const std::string &version);
+}
diff --git a/src/common/util.cpp b/src/common/util.cpp
index bfcf86bc6..90748ddb1 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -31,6 +31,7 @@
#include <cstdio>
#include "include_base_utils.h"
+#include "file_io_utils.h"
using namespace epee;
#include "util.h"
@@ -46,7 +47,7 @@ using namespace epee;
#endif
#include <boost/filesystem.hpp>
#include <boost/asio.hpp>
-
+#include <openssl/sha.h>
namespace tools
{
@@ -568,4 +569,53 @@ std::string get_nix_version_display_string()
MDEBUG("Address '" << address << "' is not local");
return false;
}
+ int vercmp(const char *v0, const char *v1)
+ {
+ std::vector<std::string> f0, f1;
+ boost::split(f0, v0, boost::is_any_of("."));
+ boost::split(f1, v1, boost::is_any_of("."));
+ while (f0.size() < f1.size())
+ f0.push_back("0");
+ while (f1.size() < f0.size())
+ f1.push_back("0");
+ for (size_t i = 0; i < f0.size(); ++i) {
+ int f0i = atoi(f0[i].c_str()), f1i = atoi(f1[i].c_str());
+ int n = f0i - f1i;
+ if (n)
+ return n;
+ }
+ return 0;
+ }
+
+ bool sha256sum(const std::string &filename, crypto::hash &hash)
+ {
+ if (!epee::file_io_utils::is_file_exist(filename))
+ return false;
+ std::ifstream f;
+ f.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+ f.open(filename, std::ios_base::binary | std::ios_base::in | std::ios::ate);
+ if (!f)
+ return false;
+ std::ifstream::pos_type file_size = f.tellg();
+ SHA256_CTX ctx;
+ if (!SHA256_Init(&ctx))
+ return false;
+ size_t size_left = file_size;
+ f.seekg(0, std::ios::beg);
+ while (size_left)
+ {
+ char buf[4096];
+ std::ifstream::pos_type read_size = size_left > sizeof(buf) ? sizeof(buf) : size_left;
+ f.read(buf, read_size);
+ if (!f || !f.good())
+ return false;
+ if (!SHA256_Update(&ctx, buf, read_size))
+ return false;
+ size_left -= read_size;
+ }
+ f.close();
+ if (!SHA256_Final((unsigned char*)hash.data, &ctx))
+ return false;
+ return true;
+ }
}
diff --git a/src/common/util.h b/src/common/util.h
index c2ffc44ca..8ab469129 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -183,4 +183,7 @@ namespace tools
unsigned get_max_concurrency();
bool is_local_address(const std::string &address);
+ int vercmp(const char *v0, const char *v1); // returns < 0, 0, > 0, similar to strcmp, but more human friendly than lexical - does not attempt to validate
+
+ bool sha256sum(const std::string &filename, crypto::hash &hash);
}
diff --git a/src/cryptonote_basic/checkpoints.cpp b/src/cryptonote_basic/checkpoints.cpp
index 3cf804ede..1e7754886 100644
--- a/src/cryptonote_basic/checkpoints.cpp
+++ b/src/cryptonote_basic/checkpoints.cpp
@@ -42,30 +42,6 @@ using namespace epee;
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "checkpoints"
-namespace
-{
- bool dns_records_match(const std::vector<std::string>& a, const std::vector<std::string>& b)
- {
- if (a.size() != b.size()) return false;
-
- for (const auto& record_in_a : a)
- {
- bool ok = false;
- for (const auto& record_in_b : b)
- {
- if (record_in_a == record_in_b)
- {
- ok = true;
- break;
- }
- }
- if (!ok) return false;
- }
-
- return true;
- }
-} // anonymous namespace
-
namespace cryptonote
{
//---------------------------------------------------------------------------
@@ -230,6 +206,8 @@ namespace cryptonote
bool checkpoints::load_checkpoints_from_dns(bool testnet)
{
+ std::vector<std::string> records;
+
// All four MoneroPulse domains have DNSSEC on and valid
static const std::vector<std::string> dns_urls = { "checkpoints.moneropulse.se"
, "checkpoints.moneropulse.org"
@@ -243,87 +221,10 @@ namespace cryptonote
, "testpoints.moneropulse.co"
};
- std::vector<std::vector<std::string> > records;
- records.resize(dns_urls.size());
-
- std::random_device rd;
- std::mt19937 gen(rd());
- std::uniform_int_distribution<int> dis(0, dns_urls.size() - 1);
- size_t first_index = dis(gen);
-
- bool avail, valid;
- size_t cur_index = first_index;
- do
- {
- std::string url;
- if (testnet)
- {
- url = testnet_dns_urls[cur_index];
- }
- else
- {
- url = dns_urls[cur_index];
- }
-
- records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid);
- if (!avail)
- {
- records[cur_index].clear();
- LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping.");
- }
- if (!valid)
- {
- records[cur_index].clear();
- LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping.");
- }
-
- cur_index++;
- if (cur_index == dns_urls.size())
- {
- cur_index = 0;
- }
- records[cur_index].clear();
- } while (cur_index != first_index);
-
- size_t num_valid_records = 0;
-
- for( const auto& record_set : records)
- {
- if (record_set.size() != 0)
- {
- num_valid_records++;
- }
- }
-
- if (num_valid_records < 2)
- {
- LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received");
- return true;
- }
-
- int good_records_index = -1;
- for (size_t i = 0; i < records.size() - 1; ++i)
- {
- if (records[i].size() == 0) continue;
-
- for (size_t j = i + 1; j < records.size(); ++j)
- {
- if (dns_records_match(records[i], records[j]))
- {
- good_records_index = i;
- break;
- }
- }
- if (good_records_index >= 0) break;
- }
-
- if (good_records_index < 0)
- {
- LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched");
- return true;
- }
+ if (!tools::dns_utils::load_txt_records_from_dns(records, testnet ? testnet_dns_urls : dns_urls))
+ return true; // why true ?
- for (auto& record : records[good_records_index])
+ for (const auto& record : records)
{
auto pos = record.find(":");
if (pos != std::string::npos)
diff --git a/src/cryptonote_basic/hardfork.cpp b/src/cryptonote_basic/hardfork.cpp
index 9b2434970..33188e66d 100644
--- a/src/cryptonote_basic/hardfork.cpp
+++ b/src/cryptonote_basic/hardfork.cpp
@@ -191,10 +191,10 @@ void HardFork::init()
}
catch (...) { populate = true; }
if (populate) {
- LOG_PRINT_L0("The DB has no hard fork info, reparsing from start");
+ MINFO("The DB has no hard fork info, reparsing from start");
height = 1;
}
- LOG_PRINT_L1("reorganizing from " << height);
+ MDEBUG("reorganizing from " << height);
if (populate) {
reorganize_from_chain_height(height);
// reorg will not touch the genesis block, use this as a flag for populating done
@@ -203,7 +203,7 @@ void HardFork::init()
else {
rescan_from_chain_height(height);
}
- LOG_PRINT_L1("reorganization done");
+ MDEBUG("reorganization done");
}
uint8_t HardFork::get_block_version(uint64_t height) const
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index 117c81878..70389f917 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -41,6 +41,7 @@
#include "common/command_line.h"
#include "string_coding.h"
#include "storages/portable_storage_template_helper.h"
+#include "boost/logic/tribool.hpp"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "miner"
@@ -61,6 +62,7 @@ namespace cryptonote
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<bool> arg_bg_mining_ignore_battery = {"bg-mining-ignore-battery", "if true, assumes plugged in when unable to query system power status", false, 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};
@@ -181,6 +183,7 @@ namespace cryptonote
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_ignore_battery);
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);
@@ -230,6 +233,8 @@ namespace cryptonote
// 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_ignore_battery))
+ set_ignore_battery( command_line::get_arg(vm, arg_bg_mining_ignore_battery) );
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))
@@ -254,7 +259,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 do_background)
+ bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background, bool ignore_battery)
{
m_mine_address = adr;
m_threads_total = static_cast<uint32_t>(threads_count);
@@ -278,6 +283,7 @@ 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);
+ set_ignore_battery(ignore_battery);
for(size_t i = 0; i != threads_count; i++)
{
@@ -469,6 +475,11 @@ namespace cryptonote
return m_is_background_mining_enabled;
}
//-----------------------------------------------------------------------------------------------------
+ bool miner::get_ignore_battery() const
+ {
+ return m_ignore_battery;
+ }
+ //-----------------------------------------------------------------------------------------------------
/**
* This has differing behaviour depending on if mining has been started/etc.
* Note: add documentation
@@ -482,6 +493,11 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------------
+ void miner::set_ignore_battery(bool ignore_battery)
+ {
+ m_ignore_battery = ignore_battery;
+ }
+ //-----------------------------------------------------------------------------------------------------
uint64_t miner::get_min_idle_seconds() const
{
return m_min_idle_seconds;
@@ -564,10 +580,9 @@ namespace cryptonote
// 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() ) );
+ uint64_t sleep_for_seconds = BACKGROUND_MINING_MINER_MONITOR_INVERVAL_IN_SECONDS;
+ if( !m_is_background_mining_started ) sleep_for_seconds = get_min_idle_seconds();
+ boost::this_thread::sleep_for(boost::chrono::seconds(sleep_for_seconds));
}
catch(const boost::thread_interrupted&)
{
@@ -575,7 +590,21 @@ namespace cryptonote
continue; // if interrupted because stop called, loop should end ..
}
- bool on_ac_power = !on_battery_power();
+ boost::tribool battery_powered(on_battery_power());
+ bool on_ac_power = false;
+ if(indeterminate( battery_powered ))
+ {
+ // name could be better, only ignores battery requirement if we failed
+ // to get the status of the system
+ if( m_ignore_battery )
+ {
+ on_ac_power = true;
+ }
+ }
+ else
+ {
+ on_ac_power = !battery_powered;
+ }
if( m_is_background_mining_started )
{
@@ -763,45 +792,54 @@ namespace cryptonote
return (uint8_t)( ceil( (other * 1.f / total * 1.f) * 100) );
}
//-----------------------------------------------------------------------------------------------------
- bool miner::on_battery_power()
+ boost::logic::tribool miner::on_battery_power()
{
#ifdef _WIN32
SYSTEM_POWER_STATUS power_status;
if ( GetSystemPowerStatus( &power_status ) != 0 )
{
- return power_status.ACLineStatus != 1;
+ return boost::logic::tribool(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) )
+ std::string power_supply_path = "";
+ const std::string POWER_SUPPLY_STATUS_PATHS[] =
{
- LOG_ERROR("'" << POWER_SUPPLY_STATUS_PATH << "' file does not exist, can't determine if on AC power");
- return false;
+ "/sys/class/power_supply/ACAD/online",
+ "/sys/class/power_supply/AC/online"
+ };
+
+ for(const std::string& path : POWER_SUPPLY_STATUS_PATHS)
+ {
+ if( epee::file_io_utils::is_file_exist(path) )
+ {
+ power_supply_path = path;
+ break;
+ }
+ }
+
+ if( power_supply_path.empty() )
+ {
+ LOG_ERROR("Couldn't find battery/power status file, can't determine if plugged in!");
+ return boost::logic::tribool(boost::logic::indeterminate);;
}
- std::ifstream power_stream(POWER_SUPPLY_STATUS_PATH);
+ std::ifstream power_stream(power_supply_path);
if( power_stream.fail() )
{
- LOG_ERROR("failed to open '" << POWER_SUPPLY_STATUS_PATH << "'");
- return false;
+ LOG_ERROR("failed to open '" << power_supply_path << "'");
+ return boost::logic::tribool(boost::logic::indeterminate);;
}
- return power_stream.get() != '1';
+ return boost::logic::tribool( (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.
+ return boost::logic::tribool(boost::logic::indeterminate);
}
}
diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h
index a66083ead..02987b9d9 100644
--- a/src/cryptonote_basic/miner.h
+++ b/src/cryptonote_basic/miner.h
@@ -31,6 +31,7 @@
#pragma once
#include <boost/program_options.hpp>
+#include <boost/logic/tribool_fwd.hpp>
#include <atomic>
#include "cryptonote_basic.h"
#include "difficulty.h"
@@ -67,7 +68,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 do_background = false);
+ bool start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background = false, bool ignore_battery = false);
uint64_t get_speed() const;
uint32_t get_threads_count() const;
void send_stop_signal();
@@ -82,6 +83,7 @@ namespace cryptonote
void resume();
void do_print_hashrate(bool do_hr);
bool get_is_background_mining_enabled() const;
+ bool get_ignore_battery() const;
uint64_t get_min_idle_seconds() const;
bool set_min_idle_seconds(uint64_t min_idle_seconds);
uint8_t get_idle_threshold() const;
@@ -149,8 +151,10 @@ namespace cryptonote
// background mining stuffs ..
bool set_is_background_mining_enabled(bool is_background_mining_enabled);
+ void set_ignore_battery(bool ignore_battery);
bool background_worker_thread();
std::atomic<bool> m_is_background_mining_enabled;
+ bool m_ignore_battery;
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;
@@ -164,6 +168,6 @@ namespace cryptonote
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();
+ static boost::logic::tribool on_battery_power();
};
}
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index a81286632..ccade000f 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -1986,12 +1986,14 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
return false;
}
+ m_db->block_txn_start(true);
resp.total_height = get_current_blockchain_height();
size_t count = 0;
for(size_t i = resp.start_height; i < resp.total_height && count < BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT; i++, count++)
{
resp.m_block_ids.push_back(m_db->get_block_hash_from_height(i));
}
+ m_db->block_txn_stop();
return true;
}
//------------------------------------------------------------------
@@ -2022,6 +2024,7 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons
}
}
+ m_db->block_txn_start(true);
total_height = get_current_blockchain_height();
size_t count = 0;
for(size_t i = start_height; i < total_height && count < max_count; i++, count++)
@@ -2032,6 +2035,7 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons
get_transactions(blocks.back().first.tx_hashes, blocks.back().second, mis);
CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, transaction from block not found");
}
+ m_db->block_txn_stop();
return true;
}
//------------------------------------------------------------------
@@ -3540,7 +3544,7 @@ void Blockchain::output_scan_worker(const uint64_t amount, const std::vector<uin
{
try
{
- m_db->get_output_key(amount, offsets, outputs);
+ m_db->get_output_key(amount, offsets, outputs, true);
}
catch (const std::exception& e)
{
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index b940dba3c..fd509b603 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -35,6 +35,8 @@ using namespace epee;
#include "cryptonote_core.h"
#include "common/command_line.h"
#include "common/util.h"
+#include "common/updates.h"
+#include "common/download.h"
#include "warnings.h"
#include "crypto/crypto.h"
#include "cryptonote_config.h"
@@ -148,6 +150,7 @@ namespace cryptonote
command_line::add_arg(desc, command_line::arg_db_sync_mode);
command_line::add_arg(desc, command_line::arg_show_time_stats);
command_line::add_arg(desc, command_line::arg_block_sync_size);
+ command_line::add_arg(desc, command_line::arg_check_updates);
}
//-----------------------------------------------------------------------------------------------
bool core::handle_command_line(const boost::program_options::variables_map& vm)
@@ -219,40 +222,6 @@ namespace cryptonote
return m_blockchain_storage.get_alternative_blocks_count();
}
//-----------------------------------------------------------------------------------------------
- bool core::lock_db_directory(const boost::filesystem::path &path)
- {
- // boost doesn't like locking directories...
- const boost::filesystem::path lock_path = path / ".daemon_lock";
-
- try
- {
- // ensure the file exists
- std::ofstream(lock_path.string(), std::ios::out).close();
-
- db_lock = boost::interprocess::file_lock(lock_path.string().c_str());
- LOG_PRINT_L1("Locking " << lock_path.string());
- if (!db_lock.try_lock())
- {
- LOG_ERROR("Failed to lock " << lock_path.string());
- return false;
- }
- return true;
- }
- catch (const std::exception &e)
- {
- LOG_ERROR("Error trying to lock " << lock_path.string() << ": " << e.what());
- return false;
- }
- }
- //-----------------------------------------------------------------------------------------------
- bool core::unlock_db_directory()
- {
- db_lock.unlock();
- db_lock = boost::interprocess::file_lock();
- LOG_PRINT_L1("Blockchain directory successfully unlocked");
- return true;
- }
- //-----------------------------------------------------------------------------------------------
bool core::init(const boost::program_options::variables_map& vm, const cryptonote::test_options *test_options)
{
start_time = std::time(nullptr);
@@ -276,6 +245,7 @@ namespace cryptonote
std::string db_sync_mode = command_line::get_arg(vm, command_line::arg_db_sync_mode);
bool fast_sync = command_line::get_arg(vm, command_line::arg_fast_block_sync) != 0;
uint64_t blocks_threads = command_line::get_arg(vm, command_line::arg_prep_blocks_threads);
+ std::string check_updates_string = command_line::get_arg(vm, command_line::arg_check_updates);
boost::filesystem::path folder(m_config_folder);
if (m_fakechain)
@@ -284,11 +254,6 @@ namespace cryptonote
// make sure the data directory exists, and try to lock it
CHECK_AND_ASSERT_MES (boost::filesystem::exists(folder) || boost::filesystem::create_directories(folder), false,
std::string("Failed to create directory ").append(folder.string()).c_str());
- if (!lock_db_directory (folder))
- {
- LOG_ERROR ("Failed to lock " << folder);
- return false;
- }
// check for blockchain.bin
try
@@ -418,6 +383,20 @@ namespace cryptonote
// with respect to what blocks we already have
CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
+ // DNS versions checking
+ if (check_updates_string == "disabled")
+ check_updates_level = UPDATES_DISABLED;
+ else if (check_updates_string == "notify")
+ check_updates_level = UPDATES_NOTIFY;
+ else if (check_updates_string == "download")
+ check_updates_level = UPDATES_DOWNLOAD;
+ else if (check_updates_string == "update")
+ check_updates_level = UPDATES_UPDATE;
+ else {
+ MERROR("Invalid argument to --dns-versions-check: " << check_updates_string);
+ return false;
+ }
+
r = m_miner.init(vm, m_testnet);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize miner instance");
@@ -440,7 +419,6 @@ namespace cryptonote
m_miner.stop();
m_mempool.deinit();
m_blockchain_storage.deinit();
- unlock_db_directory();
return true;
}
//-----------------------------------------------------------------------------------------------
@@ -639,6 +617,12 @@ namespace cryptonote
return false;
}
+ if (!check_tx_inputs_keyimages_domain(tx))
+ {
+ MERROR_VER("tx uses key image not in the valid domain");
+ return false;
+ }
+
if (tx.version >= 2)
{
const rct::rctSig &rv = tx.rct_signatures;
@@ -722,6 +706,18 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
+ bool core::check_tx_inputs_keyimages_domain(const transaction& tx) const
+ {
+ std::unordered_set<crypto::key_image> ki;
+ for(const auto& in: tx.vin)
+ {
+ CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
+ if (!(rct::scalarmultKey(rct::ki2rct(tokey_in.k_image), rct::curveOrder()) == rct::identity()))
+ return false;
+ }
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------
bool core::add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
{
crypto::hash tx_hash = get_transaction_hash(tx);
@@ -1040,6 +1036,7 @@ namespace cryptonote
m_fork_moaner.do_call(boost::bind(&core::check_fork_time, this));
m_txpool_auto_relayer.do_call(boost::bind(&core::relay_txpool_transactions, this));
+ m_check_updates_interval.do_call(boost::bind(&core::check_updates, this));
m_miner.on_idle();
m_mempool.on_idle();
return true;
@@ -1067,6 +1064,66 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
+ bool core::check_updates()
+ {
+ static const char software[] = "monerod";
+ static const char subdir[] = "cli"; // because it can never be simple
+#ifdef BUILD_TAG
+ static const char buildtag[] = BOOST_PP_STRINGIZE(BUILD_TAG);
+#else
+ static const char buildtag[] = "source";
+#endif
+
+ if (check_updates_level == UPDATES_DISABLED)
+ return true;
+
+ std::string version, hash;
+ MDEBUG("Checking for a new " << software << " version for " << buildtag);
+ if (!tools::check_updates(software, buildtag, m_testnet, version, hash))
+ return false;
+
+ if (tools::vercmp(version.c_str(), MONERO_VERSION) <= 0)
+ return true;
+
+ std::string url = tools::get_update_url(software, subdir, buildtag, version);
+ MGINFO("Version " << version << " of " << software << " for " << buildtag << " is available: " << url << ", SHA256 hash " << hash);
+
+ if (check_updates_level == UPDATES_NOTIFY)
+ return true;
+
+ std::string filename;
+ const char *slash = strrchr(url.c_str(), '/');
+ if (slash)
+ filename = slash + 1;
+ else
+ filename = std::string(software) + "-update-" + version;
+ boost::filesystem::path path(epee::string_tools::get_current_module_folder());
+ path /= filename;
+ if (!tools::download(path.string(), url))
+ {
+ MERROR("Failed to download " << url);
+ return false;
+ }
+ crypto::hash file_hash;
+ if (!tools::sha256sum(path.string(), file_hash))
+ {
+ MERROR("Failed to hash " << path);
+ return false;
+ }
+ if (hash != epee::string_tools::pod_to_hex(file_hash))
+ {
+ MERROR("Download from " << url << " does not match the expected hash");
+ return false;
+ }
+ MGINFO("New version downloaded to " << path);
+
+ if (check_updates_level == UPDATES_DOWNLOAD)
+ return true;
+
+ MERROR("Download/update not implemented yet");
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------
void core::set_target_blockchain_height(uint64_t target_blockchain_height)
{
m_target_blockchain_height = target_blockchain_height;
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index fe1d11916..43435b0c3 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -745,6 +745,16 @@ namespace cryptonote
bool check_tx_inputs_keyimages_diff(const transaction& tx) const;
/**
+ * @brief verify that each input key image in a transaction is in
+ * the valid domain
+ *
+ * @param tx the transaction to check
+ *
+ * @return false if any key image is not in the valid domain, otherwise true
+ */
+ bool check_tx_inputs_keyimages_domain(const transaction& tx) const;
+
+ /**
* @brief checks HardFork status and prints messages about it
*
* Checks the status of HardFork and logs/prints if an update to
@@ -764,22 +774,11 @@ namespace cryptonote
bool relay_txpool_transactions();
/**
- * @brief locks a file in the BlockchainDB directory
- *
- * @param path the directory in which to place the file
- *
- * @return true if lock acquired successfully, otherwise false
- */
- bool lock_db_directory(const boost::filesystem::path &path);
-
- /**
- * @brief unlocks the db directory
+ * @brief checks DNS versions
*
- * @note see lock_db_directory()
- *
- * @return true
+ * @return true on success, false otherwise
*/
- bool unlock_db_directory();
+ bool check_updates();
bool m_test_drop_download = true; //!< whether or not to drop incoming blocks (for testing)
@@ -801,8 +800,9 @@ namespace cryptonote
cryptonote_protocol_stub m_protocol_stub; //!< cryptonote protocol stub instance
epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; //!< interval for manual storing of Blockchain, if enabled
- epee::math_helper::once_a_time_seconds<60*60*2, false> m_fork_moaner; //!< interval for checking HardFork status
+ epee::math_helper::once_a_time_seconds<60*60*2, true> m_fork_moaner; //!< interval for checking HardFork status
epee::math_helper::once_a_time_seconds<60*2, false> m_txpool_auto_relayer; //!< interval for checking re-relaying txpool transactions
+ epee::math_helper::once_a_time_seconds<60*60*12, true> m_check_updates_interval; //!< interval for checking for new versions
friend class tx_validate_inputs;
std::atomic<bool> m_starter_message_showed; //!< has the "daemon will sync now" message been shown?
@@ -826,6 +826,13 @@ namespace cryptonote
time_t start_time;
std::unordered_set<crypto::hash> bad_semantics_txes;
+
+ enum {
+ UPDATES_DISABLED,
+ UPDATES_NOTIFY,
+ UPDATES_DOWNLOAD,
+ UPDATES_UPDATE,
+ } check_updates_level;
};
}
diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp
index 42e612e2f..8beb390fa 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.cpp
+++ b/src/cryptonote_core/cryptonote_tx_utils.cpp
@@ -339,7 +339,7 @@ namespace cryptonote
crypto::generate_ring_signature(tx_prefix_hash, boost::get<txin_to_key>(tx.vin[i]).k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data());
ss_ring_s << "signatures:" << ENDL;
std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL;});
- ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output;
+ ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL;
i++;
}
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index f48be1ff1..baceb1cb2 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -619,7 +619,11 @@ namespace cryptonote
get_block_reward(median_size, total_size, already_generated_coins, best_coinbase, version);
+#if 1
+ size_t max_total_size = (130 * median_size) / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
+#else
size_t max_total_size = 2 * median_size - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
+#endif
std::unordered_set<crypto::key_image> k_images;
LOG_PRINT_L2("Filling block template, median size " << median_size << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool");
@@ -637,6 +641,15 @@ namespace cryptonote
continue;
}
+#if 1
+ // If we've exceeded the penalty free size,
+ // stop including more tx
+ if (total_size > median_size)
+ {
+ LOG_PRINT_L2(" would exceed median block size");
+ break;
+ }
+#else
// If we're getting lower coinbase tx,
// stop including more tx
uint64_t block_reward;
@@ -653,6 +666,7 @@ namespace cryptonote
sorted_it++;
continue;
}
+#endif
// Skip transactions that are not ready to be
// included into the blockchain or that are
@@ -667,7 +681,9 @@ namespace cryptonote
bl.tx_hashes.push_back(tx_it->first);
total_size += tx_it->second.blob_size;
fee += tx_it->second.fee;
+#if 0
best_coinbase = coinbase;
+#endif
append_key_images(k_images, tx_it->second.tx);
sorted_it++;
LOG_PRINT_L2(" added, new block size " << total_size << "/" << max_total_size << ", coinbase " << print_money(best_coinbase));
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 8ed529737..e5fa5fece 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -272,12 +272,18 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
std::cout << "Mining to a testnet address, make sure this is intentional!" << std::endl;
uint64_t threads_count = 1;
bool do_background_mining = false;
- if(args.size() > 3)
+ bool ignore_battery = false;
+ if(args.size() > 4)
{
return false;
}
- if(args.size() == 3)
+ if(args.size() == 4)
+ {
+ ignore_battery = args[3] == "true";
+ }
+
+ if(args.size() >= 3)
{
do_background_mining = args[2] == "true";
}
@@ -288,7 +294,7 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
threads_count = (ok && 0 < threads_count) ? threads_count : 1;
}
- m_executor.start_mining(adr, threads_count, testnet, do_background_mining);
+ m_executor.start_mining(adr, threads_count, testnet, do_background_mining, ignore_battery);
return true;
}
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 4133b90d9..365a7d03b 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>] [do_background_mining], default 1 thread, no background mining"
+ , "Start mining for specified address, start_mining <addr> [<threads>] [do_background_mining] [ignore_battery], default 1 thread, no background mining"
);
m_command_lookup.set_handler(
"stop_mining"
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 00b349b15..219a7a1c4 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -929,13 +929,14 @@ 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 do_background_mining = false) {
+bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet, bool do_background_mining, bool ignore_battery) {
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;
-
+ req.ignore_battery = ignore_battery;
+
std::string fail_message = "Mining did not start";
if (m_is_rpc)
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index 5b7b76448..d9e874767 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 do_background_mining);
+ bool start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet, bool do_background_mining = false, bool ignore_battery = false);
bool stop_mining();
diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h
index 90f54b050..cb19bbbd6 100644
--- a/src/ringct/rctOps.h
+++ b/src/ringct/rctOps.h
@@ -66,6 +66,7 @@ namespace rct {
static const key Z = { {0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 } };
static const key I = { {0x01, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 } };
+ static const key L = { {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 } };
//Creates a zero scalar
inline key zero() { return Z; }
@@ -73,6 +74,9 @@ namespace rct {
//Creates a zero elliptic curve point
inline key identity() { return I; }
inline void identity(key &Id) { memcpy(&Id, &I, 32); }
+ //Creates a key equal to the curve order
+ inline key curveOrder() { return L; }
+ inline void curveOrder(key &l) { l = L; }
//copies a scalar or point
inline void copy(key &AA, const key &A) { memcpy(&AA, &A, 32); }
inline key copy(const key & A) { key AA; memcpy(&AA, &A, 32); return AA; }
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 8165dacbc..157076e82 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, req.do_background_mining))
+ if(!m_core.get_miner().start(adr, static_cast<size_t>(req.threads_count), attrs, req.do_background_mining, req.ignore_battery))
{
res.status = "Failed, mining not started";
LOG_PRINT_L0(res.status);
@@ -1387,6 +1387,7 @@ namespace cryptonote
std::pair<uint64_t, uint64_t> amounts = m_core.get_coinbase_tx_sum(req.height, req.count);
res.emission_amount = amounts.first;
res.fee_amount = amounts.second;
+ res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -1437,12 +1438,14 @@ namespace cryptonote
bool core_rpc_server::on_start_save_graph(const COMMAND_RPC_START_SAVE_GRAPH::request& req, COMMAND_RPC_START_SAVE_GRAPH::response& res)
{
m_p2p.set_save_graph(true);
+ res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_stop_save_graph(const COMMAND_RPC_STOP_SAVE_GRAPH::request& req, COMMAND_RPC_STOP_SAVE_GRAPH::response& res)
{
m_p2p.set_save_graph(false);
+ 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 3ab1ea175..8b744c26a 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -501,11 +501,13 @@ namespace cryptonote
std::string miner_address;
uint64_t threads_count;
bool do_background_mining;
+ bool ignore_battery;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(miner_address)
KV_SERIALIZE(threads_count)
KV_SERIALIZE(do_background_mining)
+ KV_SERIALIZE(ignore_battery)
END_KV_SERIALIZE_MAP()
};
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 41665e4d8..b466251ab 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -997,7 +997,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
cryptonote::blobdata viewkey_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key))
{
fail_msg_writer() << tr("failed to parse view key secret key");
return false;
@@ -1049,7 +1049,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
cryptonote::blobdata spendkey_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data) || spendkey_data.size() != sizeof(crypto::secret_key))
{
fail_msg_writer() << tr("failed to parse spend key secret key");
return false;
@@ -1065,7 +1065,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
cryptonote::blobdata viewkey_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key))
{
fail_msg_writer() << tr("failed to parse view key secret key");
return false;
@@ -3166,7 +3166,7 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
cryptonote::blobdata txid_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(local_args.front(), txid_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(local_args.front(), txid_data) || txid_data.size() != sizeof(crypto::hash))
{
fail_msg_writer() << tr("failed to parse txid");
return false;
@@ -3203,7 +3203,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
assert(m_wallet);
cryptonote::blobdata txid_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(local_args[0], txid_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(local_args[0], txid_data) || txid_data.size() != sizeof(crypto::hash))
{
fail_msg_writer() << tr("failed to parse txid");
return true;
@@ -3219,7 +3219,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
}
crypto::secret_key tx_key;
cryptonote::blobdata tx_key_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(local_args[1], tx_key_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(local_args[1], tx_key_data) || tx_key_data.size() != sizeof(crypto::secret_key))
{
fail_msg_writer() << tr("failed to parse tx key");
return true;
@@ -3851,7 +3851,7 @@ bool simple_wallet::set_tx_note(const std::vector<std::string> &args)
}
cryptonote::blobdata txid_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(args.front(), txid_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(args.front(), txid_data) || txid_data.size() != sizeof(crypto::hash))
{
fail_msg_writer() << tr("failed to parse txid");
return false;
@@ -3879,7 +3879,7 @@ bool simple_wallet::get_tx_note(const std::vector<std::string> &args)
}
cryptonote::blobdata txid_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(args.front(), txid_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(args.front(), txid_data) || txid_data.size() != sizeof(crypto::hash))
{
fail_msg_writer() << tr("failed to parse txid");
return false;
@@ -4179,7 +4179,7 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args)
}
cryptonote::blobdata txid_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(args.front(), txid_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(args.front(), txid_data) || txid_data.size() != sizeof(crypto::hash))
{
fail_msg_writer() << tr("failed to parse txid");
return false;
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index c46de6b06..326ca26a0 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1157,7 +1157,7 @@ void WalletImpl::setDefaultMixin(uint32_t arg)
bool WalletImpl::setUserNote(const std::string &txid, const std::string &note)
{
cryptonote::blobdata txid_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data) || txid_data.size() != sizeof(crypto::hash))
return false;
const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
@@ -1168,7 +1168,7 @@ bool WalletImpl::setUserNote(const std::string &txid, const std::string &note)
std::string WalletImpl::getUserNote(const std::string &txid) const
{
cryptonote::blobdata txid_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data) || txid_data.size() != sizeof(crypto::hash))
return "";
const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
@@ -1178,7 +1178,7 @@ std::string WalletImpl::getUserNote(const std::string &txid) const
std::string WalletImpl::getTxKey(const std::string &txid) const
{
cryptonote::blobdata txid_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data) || txid_data.size() != sizeof(crypto::hash))
{
return "";
}
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index 4104e7884..6feec75bd 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -182,7 +182,7 @@ bool WalletManagerImpl::checkPayment(const std::string &address_text, const std:
{
error = "";
cryptonote::blobdata txid_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(txid_text, txid_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(txid_text, txid_data) || txid_data.size() != sizeof(crypto::hash))
{
error = tr("failed to parse txid");
return false;
@@ -196,7 +196,7 @@ bool WalletManagerImpl::checkPayment(const std::string &address_text, const std:
}
crypto::secret_key tx_key;
cryptonote::blobdata tx_key_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(txkey_text, tx_key_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(txkey_text, tx_key_data) || tx_key_data.size() != sizeof(crypto::hash))
{
error = tr("failed to parse tx key");
return false;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index e7a175dc7..56eee6ecf 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -251,7 +251,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file,
if (field_viewkey_found)
{
cryptonote::blobdata viewkey_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(field_viewkey, viewkey_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(field_viewkey, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key))
{
tools::fail_msg_writer() << tools::wallet2::tr("failed to parse view key secret key");
return false;
@@ -269,7 +269,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file,
if (field_spendkey_found)
{
cryptonote::blobdata spendkey_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(field_spendkey, spendkey_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(field_spendkey, spendkey_data) || spendkey_data.size() != sizeof(crypto::secret_key))
{
tools::fail_msg_writer() << tools::wallet2::tr("failed to parse spend key secret key");
return false;
@@ -1456,7 +1456,7 @@ void wallet2::update_pool_state()
for (auto it: res.transactions)
{
cryptonote::blobdata txid_data;
- if(epee::string_tools::parse_hexstr_to_binbuff(it.id_hash, txid_data))
+ if(epee::string_tools::parse_hexstr_to_binbuff(it.id_hash, txid_data) && txid_data.size() == sizeof(crypto::hash))
{
const crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
if (m_unconfirmed_payments.find(txid) == m_unconfirmed_payments.end())
@@ -4217,13 +4217,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// get a random unspent output and use it to pay part (or all) of the current destination (and maybe next one, etc)
// This could be more clever, but maybe at the cost of making probabilistic inferences easier
size_t idx;
- if ((dsts.empty() || dsts[0].amount == 0) && !adding_fee)
+ if ((dsts.empty() || dsts[0].amount == 0) && !adding_fee) {
// the "make rct txes 2/2" case - we pick a small value output to "clean up" the wallet too
idx = pop_best_value(unused_dust_indices.empty() ? unused_transfers_indices : unused_dust_indices, tx.selected_transfers, true);
- else if (!prefered_inputs.empty()) {
- idx = pop_back(prefered_inputs);
- pop_if_present(unused_transfers_indices, idx);
- pop_if_present(unused_dust_indices, idx);
// since we're trying to add a second output which is not strictly needed,
// we only add it if it's unrelated enough to the first one
@@ -4233,6 +4229,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("Second outout was not strictly needed, and relatedness " << relatedness << ", not adding");
break;
}
+ } else if (!prefered_inputs.empty()) {
+ idx = pop_back(prefered_inputs);
+ pop_if_present(unused_transfers_indices, idx);
+ pop_if_present(unused_dust_indices, idx);
} else
idx = pop_best_value(unused_transfers_indices.empty() ? unused_dust_indices : unused_transfers_indices, tx.selected_transfers);
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 881279e42..ee50c3cdb 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -983,7 +983,7 @@ namespace tools
while (i != req.txids.end())
{
cryptonote::blobdata txid_blob;
- if(!epee::string_tools::parse_hexstr_to_binbuff(*i++, txid_blob))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(*i++, txid_blob) || txid_blob.size() != sizeof(crypto::hash))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_TXID;
er.message = "TX ID has invalid format";
@@ -1013,7 +1013,7 @@ namespace tools
while (i != req.txids.end())
{
cryptonote::blobdata txid_blob;
- if(!epee::string_tools::parse_hexstr_to_binbuff(*i++, txid_blob))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(*i++, txid_blob) || txid_blob.size() != sizeof(crypto::hash))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_TXID;
er.message = "TX ID has invalid format";
@@ -1206,7 +1206,7 @@ namespace tools
{
cryptonote::blobdata bd;
- if(!epee::string_tools::parse_hexstr_to_binbuff(req.signed_key_images[n].key_image, bd))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(req.signed_key_images[n].key_image, bd) || bd.size() != sizeof(crypto::key_image))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE;
er.message = "failed to parse key image";
@@ -1214,7 +1214,7 @@ namespace tools
}
ski[n].first = *reinterpret_cast<const crypto::key_image*>(bd.data());
- if(!epee::string_tools::parse_hexstr_to_binbuff(req.signed_key_images[n].signature, bd))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(req.signed_key_images[n].signature, bd) || bd.size() != sizeof(crypto::signature))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_SIGNATURE;
er.message = "failed to parse signature";
diff --git a/tests/performance_tests/cn_fast_hash.h b/tests/performance_tests/cn_fast_hash.h
index 24f2bc5e2..d02b32676 100644
--- a/tests/performance_tests/cn_fast_hash.h
+++ b/tests/performance_tests/cn_fast_hash.h
@@ -31,7 +31,7 @@
#pragma once
#include "crypto/crypto.h"
-#include "cryptonote_core/cryptonote_basic.h"
+#include "cryptonote_basic/cryptonote_basic.h"
template<size_t bytes>
class test_cn_fast_hash
diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt
index e70ed1a24..04e47e49b 100644
--- a/tests/unit_tests/CMakeLists.txt
+++ b/tests/unit_tests/CMakeLists.txt
@@ -58,7 +58,8 @@ set(unit_tests_sources
uri.cpp
varint.cpp
ringct.cpp
- output_selection.cpp)
+ output_selection.cpp
+ vercmp.cpp)
set(unit_tests_headers
unit_tests_utils.h)
diff --git a/tests/unit_tests/blockchain_db.cpp b/tests/unit_tests/blockchain_db.cpp
index 8fc10be10..faf4c776f 100644
--- a/tests/unit_tests/blockchain_db.cpp
+++ b/tests/unit_tests/blockchain_db.cpp
@@ -288,7 +288,7 @@ TYPED_TEST(BlockchainDBTest, AddBlock)
ASSERT_TRUE(compare_blocks(this->m_blocks[0], b));
// assert that we can't add the same block twice
- ASSERT_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0]), BLOCK_EXISTS);
+ ASSERT_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0]), TX_EXISTS);
for (auto& h : this->m_blocks[0].tx_hashes)
{
diff --git a/tests/unit_tests/vercmp.cpp b/tests/unit_tests/vercmp.cpp
new file mode 100644
index 000000000..d48dfdf7c
--- /dev/null
+++ b/tests/unit_tests/vercmp.cpp
@@ -0,0 +1,43 @@
+// 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 "gtest/gtest.h"
+
+#include "common/util.h"
+
+TEST(vercmp, empty) { ASSERT_TRUE(tools::vercmp("", "") == 0); }
+TEST(vercmp, empty0) { ASSERT_TRUE(tools::vercmp("", "0") == 0); }
+TEST(vercmp, empty1) { ASSERT_TRUE(tools::vercmp("0", "") == 0); }
+TEST(vercmp, zero_zero) { ASSERT_TRUE(tools::vercmp("0", "0") == 0); }
+TEST(vercmp, one_one) { ASSERT_TRUE(tools::vercmp("1", "1") == 0); }
+TEST(vercmp, one_two) { ASSERT_TRUE(tools::vercmp("1", "2") < 0); }
+TEST(vercmp, two_one) { ASSERT_TRUE(tools::vercmp("2", "1") > 0); }
+TEST(vercmp, ten_nine) { ASSERT_TRUE(tools::vercmp("10", "9") > 0); }
+TEST(vercmp, one_dot_ten_one_dot_nine) { ASSERT_TRUE(tools::vercmp("1.10", "1.9") > 0); }
+TEST(vercmp, one_one_dot_nine) { ASSERT_TRUE(tools::vercmp("1", "1.9") < 0); }
+