aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.cpp5
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.h2
-rw-r--r--src/blockchain_db/blockchain_db.cpp11
-rw-r--r--src/blockchain_db/blockchain_db.h36
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp237
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h12
-rw-r--r--src/blockchain_utilities/blockchain_import.cpp1
-rw-r--r--src/blockchain_utilities/bootstrap_file.cpp6
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/scoped_message_writer.h2
-rw-r--r--src/common/stack_trace.cpp2
-rw-r--r--src/crypto/blake256.c2
-rw-r--r--src/crypto/crypto.cpp34
-rw-r--r--src/crypto/crypto.h1
-rw-r--r--src/crypto/crypto_ops_builder/ref10/README.md4
-rw-r--r--src/crypto/crypto_ops_builder/ref10/description2
-rw-r--r--src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py4
-rw-r--r--src/crypto/crypto_ops_builder/ref10CommentedCombined/description2
-rw-r--r--src/crypto/initializer.h4
-rw-r--r--src/crypto/slow-hash.c4
-rw-r--r--src/crypto/tree-hash.c2
-rw-r--r--src/cryptonote_basic/hardfork.h15
-rw-r--r--src/cryptonote_basic/miner.cpp2
-rw-r--r--src/cryptonote_core/blockchain.cpp101
-rw-r--r--src/cryptonote_core/blockchain.h13
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp32
-rw-r--r--src/cryptonote_core/cryptonote_core.h2
-rw-r--r--src/cryptonote_core/tx_pool.cpp33
-rw-r--r--src/cryptonote_core/tx_pool.h8
-rw-r--r--src/daemon/CMakeLists.txt1
-rw-r--r--src/daemon/command_parser_executor.cpp6
-rw-r--r--src/daemon/command_server.cpp1
-rw-r--r--src/daemon/daemon.cpp3
-rw-r--r--src/daemon/main.cpp5
-rw-r--r--src/daemon/rpc_command_executor.cpp36
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/device/device_ledger.cpp470
-rw-r--r--src/device/device_ledger.hpp3
-rw-r--r--src/mnemonics/esperanto.h2
-rw-r--r--src/mnemonics/lojban.h2
-rw-r--r--src/p2p/CMakeLists.txt1
-rw-r--r--src/p2p/net_node.inl3
-rw-r--r--src/ringct/rctOps.cpp10
-rw-r--r--src/ringct/rctSigs.cpp18
-rw-r--r--src/ringct/rctSigs.h8
-rw-r--r--src/ringct/rctTypes.h2
-rw-r--r--src/rpc/CMakeLists.txt1
-rw-r--r--src/rpc/core_rpc_server.cpp148
-rw-r--r--src/rpc/core_rpc_server.h6
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h70
-rw-r--r--src/rpc/core_rpc_server_error_codes.h1
-rw-r--r--src/rpc/get_output_distribution_cache.h113
-rw-r--r--src/rpc/message_data_structs.h1
-rw-r--r--src/serialization/json_object.cpp2
-rw-r--r--src/simplewallet/CMakeLists.txt1
-rw-r--r--src/simplewallet/simplewallet.cpp88
-rw-r--r--src/simplewallet/simplewallet.h4
-rw-r--r--src/version.cpp.in2
-rw-r--r--src/wallet/CMakeLists.txt1
-rw-r--r--src/wallet/api/wallet.cpp14
-rw-r--r--src/wallet/api/wallet.h3
-rw-r--r--src/wallet/api/wallet2_api.h10
-rw-r--r--src/wallet/node_rpc_proxy.cpp72
-rw-r--r--src/wallet/node_rpc_proxy.h7
-rw-r--r--src/wallet/wallet2.cpp197
-rw-r--r--src/wallet/wallet2.h11
-rw-r--r--src/wallet/wallet_errors.h11
67 files changed, 1120 insertions, 796 deletions
diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp
index e1b76ec1e..f827ab7c3 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.cpp
+++ b/src/blockchain_db/berkeleydb/db_bdb.cpp
@@ -1213,6 +1213,11 @@ std::vector<std::string> BlockchainBDB::get_filenames() const
return full_paths;
}
+bool BlockchainBDB::remove_data_file(const std::string& folder)
+{
+ return true;
+}
+
std::string BlockchainBDB::get_db_name() const
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h
index cecbba28f..c90d030a2 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.h
+++ b/src/blockchain_db/berkeleydb/db_bdb.h
@@ -244,6 +244,8 @@ public:
virtual std::vector<std::string> get_filenames() const;
+ virtual bool remove_data_file(const std::string& folder);
+
virtual std::string get_db_name() const;
virtual bool lock();
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp
index 88ac34255..8544cc3f0 100644
--- a/src/blockchain_db/blockchain_db.cpp
+++ b/src/blockchain_db/blockchain_db.cpp
@@ -218,13 +218,22 @@ uint64_t BlockchainDB::add_block( const block& blk
// call out to add the transactions
time1 = epee::misc_utils::get_tick_count();
+
+ uint64_t num_rct_outs = 0;
add_transaction(blk_hash, blk.miner_tx);
+ if (blk.miner_tx.version == 2)
+ num_rct_outs += blk.miner_tx.vout.size();
int tx_i = 0;
crypto::hash tx_hash = crypto::null_hash;
for (const transaction& tx : txs)
{
tx_hash = blk.tx_hashes[tx_i];
add_transaction(blk_hash, tx, &tx_hash);
+ for (const auto &vout: tx.vout)
+ {
+ if (vout.amount == 0)
+ ++num_rct_outs;
+ }
++tx_i;
}
TIME_MEASURE_FINISH(time1);
@@ -232,7 +241,7 @@ uint64_t BlockchainDB::add_block( const block& blk
// call out to subclass implementation to add the block & metadata
time1 = epee::misc_utils::get_tick_count();
- add_block(blk, block_size, cumulative_difficulty, coins_generated, blk_hash);
+ add_block(blk, block_size, cumulative_difficulty, coins_generated, num_rct_outs, blk_hash);
TIME_MEASURE_FINISH(time1);
time_add_block1 += time1;
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 564016fc9..6851e2404 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -367,6 +367,7 @@ private:
, const size_t& block_size
, const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
+ , uint64_t num_rct_outs
, const crypto::hash& blk_hash
) = 0;
@@ -655,6 +656,20 @@ public:
*/
virtual std::vector<std::string> get_filenames() const = 0;
+ /**
+ * @brief remove file(s) storing the database
+ *
+ * This function is for resetting the database (for core tests, functional tests, etc).
+ * The function reset() is not usable because it needs to open the database file first
+ * which can fail if the existing database file is in an incompatible format.
+ * As such, this function needs to be called before calling open().
+ *
+ * @param folder The path of the folder containing the database file(s) which must not end with slash '/'.
+ *
+ * @return true if the operation is succesfull
+ */
+ virtual bool remove_data_file(const std::string& folder) const = 0;
+
// return the name of the folder the db's file(s) should reside in
/**
* @brief gets the name of the folder the BlockchainDB's file(s) should be in
@@ -892,6 +907,20 @@ public:
virtual uint64_t get_block_timestamp(const uint64_t& height) const = 0;
/**
+ * @brief fetch a block's cumulative number of rct outputs
+ *
+ * The subclass should return the numer of rct outputs in the blockchain
+ * up to the block with the given height (inclusive).
+ *
+ * If the block does not exist, the subclass should throw BLOCK_DNE
+ *
+ * @param height the height requested
+ *
+ * @return the cumulative number of rct outputs
+ */
+ virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const = 0;
+
+ /**
* @brief fetch the top block's timestamp
*
* The subclass should return the timestamp of the most recent block.
@@ -1536,6 +1565,13 @@ public:
*/
virtual bool is_read_only() const = 0;
+ /**
+ * @brief get disk space requirements
+ *
+ * @return the size required
+ */
+ virtual uint64_t get_database_size() const = 0;
+
// TODO: this should perhaps be (or call) a series of functions which
// progressively update through version updates
/**
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 367bfa49e..5d1679c0c 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -35,6 +35,7 @@
#include <random>
#include "string_tools.h"
+#include "file_io_utils.h"
#include "common/util.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "crypto/crypto.h"
@@ -53,7 +54,7 @@ using epee::string_tools::pod_to_hex;
using namespace crypto;
// Increase when the DB structure changes
-#define VERSION 2
+#define VERSION 3
namespace
{
@@ -250,6 +251,16 @@ inline void lmdb_db_open(MDB_txn* txn, const char* name, int flags, MDB_dbi& dbi
namespace cryptonote
{
+typedef struct mdb_block_info_old
+{
+ uint64_t bi_height;
+ uint64_t bi_timestamp;
+ uint64_t bi_coins;
+ uint64_t bi_size; // a size_t really but we need 32-bit compat
+ difficulty_type bi_diff;
+ crypto::hash bi_hash;
+} mdb_block_info_old;
+
typedef struct mdb_block_info
{
uint64_t bi_height;
@@ -258,6 +269,7 @@ typedef struct mdb_block_info
uint64_t bi_size; // a size_t really but we need 32-bit compat
difficulty_type bi_diff;
crypto::hash bi_hash;
+ uint64_t bi_cum_rct;
} mdb_block_info;
typedef struct blk_height {
@@ -667,7 +679,7 @@ estim:
}
void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated,
- const crypto::hash& blk_hash)
+ uint64_t num_rct_outs, const crypto::hash& blk_hash)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -715,6 +727,16 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const
bi.bi_size = block_size;
bi.bi_diff = cumulative_difficulty;
bi.bi_hash = blk_hash;
+ bi.bi_cum_rct = num_rct_outs;
+ if (blk.major_version >= 4)
+ {
+ uint64_t last_height = m_height-1;
+ MDB_val_set(h, last_height);
+ if ((result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &h, MDB_GET_BOTH)))
+ throw1(BLOCK_DNE(lmdb_error("Failed to get block info: ", result).c_str()));
+ const mdb_block_info *bi_prev = (const mdb_block_info*)h.mv_data;
+ bi.bi_cum_rct += bi_prev->bi_cum_rct;
+ }
MDB_val_set(val, bi);
result = mdb_cursor_put(m_cur_block_info, (MDB_val *)&zerokval, &val, MDB_APPENDDUP);
@@ -759,8 +781,6 @@ void BlockchainLMDB::remove_block()
if ((result = mdb_cursor_del(m_cur_block_heights, 0)))
throw1(DB_ERROR(lmdb_error("Failed to add removal of block height by hash to db transaction: ", result).c_str()));
- if ((result = mdb_cursor_get(m_cur_blocks, &k, NULL, MDB_SET)))
- throw1(DB_ERROR(lmdb_error("Failed to locate block for removal: ", result).c_str()));
if ((result = mdb_cursor_del(m_cur_blocks, 0)))
throw1(DB_ERROR(lmdb_error("Failed to add removal of block to db transaction: ", result).c_str()));
@@ -1143,6 +1163,8 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB()
m_cum_size = 0;
m_cum_count = 0;
+ // reset may also need changing when initialize things here
+
m_hardfork = nullptr;
}
@@ -1469,6 +1491,21 @@ std::vector<std::string> BlockchainLMDB::get_filenames() const
return filenames;
}
+bool BlockchainLMDB::remove_data_file(const std::string& folder) const
+{
+ const std::string filename = folder + "/data.mdb";
+ try
+ {
+ boost::filesystem::remove(filename);
+ }
+ catch (const std::exception &e)
+ {
+ MERROR("Failed to remove " << filename << ": " << e.what());
+ return false;
+ }
+ return true;
+}
+
std::string BlockchainLMDB::get_db_name() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -1908,6 +1945,43 @@ uint64_t BlockchainLMDB::get_block_timestamp(const uint64_t& height) const
return ret;
}
+std::vector<uint64_t> BlockchainLMDB::get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ std::vector<uint64_t> res;
+ int result;
+
+ if (heights.empty())
+ return {};
+ res.reserve(heights.size());
+
+ TXN_PREFIX_RDONLY();
+ RCURSOR(block_info);
+
+ MDB_stat db_stats;
+ if ((result = mdb_stat(m_txn, m_blocks, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str()));
+ for (size_t i = 0; i < heights.size(); ++i)
+ if (heights[i] >= db_stats.ms_entries)
+ throw0(BLOCK_DNE(std::string("Attempt to get rct distribution from height " + std::to_string(heights[i]) + " failed -- block size not in db").c_str()));
+
+ MDB_val v;
+
+ for (uint64_t height: heights)
+ {
+ MDB_val_set(v, height);
+ result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Error attempting to retrieve rct distribution from the db: ", result).c_str()));
+ const mdb_block_info *bi = (const mdb_block_info *)v.mv_data;
+ res.push_back(bi->bi_cum_rct);
+ }
+
+ TXN_POSTFIX_RDONLY();
+ return res;
+}
+
uint64_t BlockchainLMDB::get_top_block_timestamp() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -3328,6 +3402,7 @@ bool BlockchainLMDB::get_output_distribution(uint64_t amount, uint64_t from_heig
MDB_val_set(k, amount);
MDB_val v;
MDB_cursor_op op = MDB_SET;
+ base = 0;
while (1)
{
int ret = mdb_cursor_get(m_cur_output_amounts, &k, &v, op);
@@ -3346,6 +3421,9 @@ bool BlockchainLMDB::get_output_distribution(uint64_t amount, uint64_t from_heig
break;
}
+ for (size_t n = 1; n < distribution.size(); ++n)
+ distribution[n] += distribution[n - 1];
+
TXN_POSTFIX_RDONLY();
return true;
@@ -3423,6 +3501,16 @@ bool BlockchainLMDB::is_read_only() const
return false;
}
+uint64_t BlockchainLMDB::get_database_size() const
+{
+ uint64_t size = 0;
+ boost::filesystem::path datafile(m_folder);
+ datafile /= CRYPTONOTE_BLOCKCHAINDATA_FILENAME;
+ if (!epee::file_io_utils::get_file_size(datafile.string(), size))
+ size = 0;
+ return size;
+}
+
void BlockchainLMDB::fixup()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -3440,7 +3528,7 @@ void BlockchainLMDB::fixup()
if (result) \
throw0(DB_ERROR(lmdb_error("Failed to get DB record for " name ": ", result).c_str())); \
ptr = (char *)k.mv_data; \
- ptr[sizeof(name)-2] = 's'
+ ptr[sizeof(name)-2]++
#define LOGIF(y) if (ELPP->vRegistry()->allowed(y, "global"))
@@ -3580,7 +3668,7 @@ void BlockchainLMDB::migrate_0_1()
break;
}
MDB_dbi diffs, hashes, sizes, timestamps;
- mdb_block_info bi;
+ mdb_block_info_old bi;
MDB_val_set(nv, bi);
lmdb_db_open(txn, "block_diffs", 0, diffs, "Failed to open db handle for block_diffs");
@@ -4120,6 +4208,141 @@ void BlockchainLMDB::migrate_1_2()
txn.commit();
}
+void BlockchainLMDB::migrate_2_3()
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ uint64_t i;
+ int result;
+ mdb_txn_safe txn(false);
+ MDB_val k, v;
+ char *ptr;
+
+ MGINFO_YELLOW("Migrating blockchain from DB version 2 to 3 - this may take a while:");
+
+ do {
+ LOG_PRINT_L1("migrating block info:");
+
+ result = mdb_txn_begin(m_env, NULL, 0, txn);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
+
+ MDB_stat db_stats;
+ if ((result = mdb_stat(txn, m_blocks, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str()));
+ const uint64_t blockchain_height = db_stats.ms_entries;
+
+ MDEBUG("enumerating rct outputs...");
+ std::vector<uint64_t> distribution(blockchain_height, 0);
+ bool r = for_all_outputs(0, [&](uint64_t height) {
+ if (height >= blockchain_height)
+ {
+ MERROR("Output found claiming height >= blockchain height");
+ return false;
+ }
+ distribution[height]++;
+ return true;
+ });
+ if (!r)
+ throw0(DB_ERROR("Failed to build rct output distribution"));
+ for (size_t i = 1; i < distribution.size(); ++i)
+ distribution[i] += distribution[i - 1];
+
+ /* the block_info table name is the same but the old version and new version
+ * have incompatible data. Create a new table. We want the name to be similar
+ * to the old name so that it will occupy the same location in the DB.
+ */
+ MDB_dbi o_block_info = m_block_info;
+ lmdb_db_open(txn, "block_infn", MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_block_info, "Failed to open db handle for block_infn");
+ mdb_set_dupsort(txn, m_block_info, compare_uint64);
+
+ MDB_cursor *c_old, *c_cur;
+ i = 0;
+ while(1) {
+ if (!(i % 1000)) {
+ if (i) {
+ LOGIF(el::Level::Info) {
+ std::cout << i << " / " << blockchain_height << " \r" << std::flush;
+ }
+ txn.commit();
+ result = mdb_txn_begin(m_env, NULL, 0, txn);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
+ }
+ result = mdb_cursor_open(txn, m_block_info, &c_cur);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_infn: ", result).c_str()));
+ result = mdb_cursor_open(txn, o_block_info, &c_old);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_info: ", result).c_str()));
+ if (!i) {
+ MDB_stat db_stat;
+ result = mdb_stat(txn, m_block_info, &db_stats);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to query m_block_info: ", result).c_str()));
+ i = db_stats.ms_entries;
+ }
+ }
+ result = mdb_cursor_get(c_old, &k, &v, MDB_NEXT);
+ if (result == MDB_NOTFOUND) {
+ txn.commit();
+ break;
+ }
+ else if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to get a record from block_info: ", result).c_str()));
+ const mdb_block_info_old *bi_old = (const mdb_block_info_old*)v.mv_data;
+ mdb_block_info bi;
+ bi.bi_height = bi_old->bi_height;
+ bi.bi_timestamp = bi_old->bi_timestamp;
+ bi.bi_coins = bi_old->bi_coins;
+ bi.bi_size = bi_old->bi_size;
+ bi.bi_diff = bi_old->bi_diff;
+ bi.bi_hash = bi_old->bi_hash;
+ if (bi_old->bi_height >= distribution.size())
+ throw0(DB_ERROR("Bad height in block_info record"));
+ bi.bi_cum_rct = distribution[bi_old->bi_height];
+ MDB_val_set(nv, bi);
+ result = mdb_cursor_put(c_cur, (MDB_val *)&zerokval, &nv, MDB_APPENDDUP);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to put a record into block_infn: ", result).c_str()));
+ /* we delete the old records immediately, so the overall DB and mapsize should not grow.
+ * This is a little slower than just letting mdb_drop() delete it all at the end, but
+ * it saves a significant amount of disk space.
+ */
+ result = mdb_cursor_del(c_old, 0);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to delete a record from block_info: ", result).c_str()));
+ i++;
+ }
+
+ result = mdb_txn_begin(m_env, NULL, 0, txn);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
+ /* Delete the old table */
+ result = mdb_drop(txn, o_block_info, 1);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to delete old block_info table: ", result).c_str()));
+
+ RENAME_DB("block_infn");
+
+ lmdb_db_open(txn, "block_info", MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_block_info, "Failed to open db handle for block_infn");
+ mdb_set_dupsort(txn, m_block_info, compare_uint64);
+
+ txn.commit();
+ } while(0);
+
+ uint32_t version = 3;
+ v.mv_data = (void *)&version;
+ v.mv_size = sizeof(version);
+ MDB_val_copy<const char *> vk("version");
+ result = mdb_txn_begin(m_env, NULL, 0, txn);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
+ result = mdb_put(txn, m_properties, &vk, &v, 0);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to update version for the db: ", result).c_str()));
+ txn.commit();
+}
+
void BlockchainLMDB::migrate(const uint32_t oldversion)
{
switch(oldversion) {
@@ -4127,6 +4350,8 @@ void BlockchainLMDB::migrate(const uint32_t oldversion)
migrate_0_1(); /* FALLTHRU */
case 1:
migrate_1_2(); /* FALLTHRU */
+ case 2:
+ migrate_2_3(); /* FALLTHRU */
default:
;
}
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index cc1b06ca0..8b214d2df 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -166,7 +166,7 @@ struct mdb_txn_safe
class BlockchainLMDB : public BlockchainDB
{
public:
- BlockchainLMDB(bool batch_transactions=false);
+ BlockchainLMDB(bool batch_transactions=true);
~BlockchainLMDB();
virtual void open(const std::string& filename, const int mdb_flags=0);
@@ -181,6 +181,8 @@ public:
virtual std::vector<std::string> get_filenames() const;
+ virtual bool remove_data_file(const std::string& folder) const;
+
virtual std::string get_db_name() const;
virtual bool lock();
@@ -197,6 +199,8 @@ public:
virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t& height) const;
+ virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const;
+
virtual uint64_t get_block_timestamp(const uint64_t& height) const;
virtual uint64_t get_top_block_timestamp() const;
@@ -317,6 +321,7 @@ private:
, const size_t& block_size
, const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
+ , uint64_t num_rct_outs
, const crypto::hash& block_hash
);
@@ -375,6 +380,8 @@ private:
virtual bool is_read_only() const;
+ virtual uint64_t get_database_size() const;
+
// fix up anything that may be wrong due to past bugs
virtual void fixup();
@@ -387,6 +394,9 @@ private:
// migrate from DB version 1 to 2
void migrate_1_2();
+ // migrate from DB version 2 to 3
+ void migrate_2_3();
+
void cleanup_batch();
private:
diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp
index c76641598..7291dbd68 100644
--- a/src/blockchain_utilities/blockchain_import.cpp
+++ b/src/blockchain_utilities/blockchain_import.cpp
@@ -33,6 +33,7 @@
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
+#include <unistd.h>
#include "misc_log_ex.h"
#include "bootstrap_file.h"
#include "bootstrap_serialization.h"
diff --git a/src/blockchain_utilities/bootstrap_file.cpp b/src/blockchain_utilities/bootstrap_file.cpp
index aa85e5e53..ba2697226 100644
--- a/src/blockchain_utilities/bootstrap_file.cpp
+++ b/src/blockchain_utilities/bootstrap_file.cpp
@@ -400,18 +400,18 @@ uint64_t BootstrapFile::count_bytes(std::ifstream& import_file, uint64_t blocks,
{
std::cout << refresh_string;
MWARNING("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE
- << " height: " << h-1);
+ << " height: " << h-1 << ", offset " << bytes_read);
throw std::runtime_error("Aborting: chunk size exceeds buffer size");
}
if (chunk_size > CHUNK_SIZE_WARNING_THRESHOLD)
{
std::cout << refresh_string;
MDEBUG("NOTE: chunk_size " << chunk_size << " > " << CHUNK_SIZE_WARNING_THRESHOLD << " << height: "
- << h-1);
+ << h-1 << ", offset " << bytes_read);
}
else if (chunk_size <= 0) {
std::cout << refresh_string;
- MDEBUG("ERROR: chunk_size " << chunk_size << " <= 0" << " height: " << h-1);
+ MDEBUG("ERROR: chunk_size " << chunk_size << " <= 0" << " height: " << h-1 << ", offset " << bytes_read);
throw std::runtime_error("Aborting");
}
// skip to next expected block size value
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 808ef7630..f0df05b0d 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -78,7 +78,6 @@ monero_add_library(common
DEPENDS generate_translations_header)
target_link_libraries(common
PUBLIC
- epee
cncrypto
${UNBOUND_LIBRARY}
${LIBUNWIND_LIBRARIES}
diff --git a/src/common/scoped_message_writer.h b/src/common/scoped_message_writer.h
index d7517babb..d887a13c9 100644
--- a/src/common/scoped_message_writer.h
+++ b/src/common/scoped_message_writer.h
@@ -73,7 +73,7 @@ public:
#if defined(_MSC_VER)
, m_oss(std::move(rhs.m_oss))
#else
- // GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
+ // GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
, m_oss(rhs.m_oss.str(), std::ios_base::out | std::ios_base::ate)
#endif
, m_color(std::move(rhs.m_color))
diff --git a/src/common/stack_trace.cpp b/src/common/stack_trace.cpp
index 9c2bf4b53..d6dc4d7cc 100644
--- a/src/common/stack_trace.cpp
+++ b/src/common/stack_trace.cpp
@@ -51,7 +51,7 @@
#define ST_LOG(x) CINFO(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x
-// from http://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c
+// from https://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c
// The decl of __cxa_throw in /usr/include/.../cxxabi.h uses
// 'std::type_info *', but GCC's built-in protype uses 'void *'.
diff --git a/src/crypto/blake256.c b/src/crypto/blake256.c
index d503c47e0..6ef7d4207 100644
--- a/src/crypto/blake256.c
+++ b/src/crypto/blake256.c
@@ -31,7 +31,7 @@
* The blake256_* and blake224_* functions are largely copied from
* blake256_light.c and blake224_light.c from the BLAKE website:
*
- * http://131002.net/blake/
+ * https://131002.net/blake/
*
* The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224.
* HMAC is specified by RFC 2104.
diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp
index f4ef751d3..0c019938d 100644
--- a/src/crypto/crypto.cpp
+++ b/src/crypto/crypto.cpp
@@ -93,18 +93,32 @@ namespace crypto {
generate_random_bytes_not_thread_safe(N, bytes);
}
- /* generate a random 32-byte (256-bit) integer and copy it to res */
- static inline void random_scalar_not_thread_safe(ec_scalar &res) {
- unsigned char tmp[64];
- generate_random_bytes_not_thread_safe(64, tmp);
- sc_reduce(tmp);
- memcpy(&res, tmp, 32);
+ static inline bool less32(const unsigned char *k0, const unsigned char *k1)
+ {
+ for (int n = 31; n >= 0; --n)
+ {
+ if (k0[n] < k1[n])
+ return true;
+ if (k0[n] > k1[n])
+ return false;
+ }
+ return false;
}
+
+ void random32_unbiased(unsigned char *bytes)
+ {
+ // l = 2^252 + 27742317777372353535851937790883648493.
+ // it fits 15 in 32 bytes
+ static const unsigned char limit[32] = { 0xe3, 0x6a, 0x67, 0x72, 0x8b, 0xce, 0x13, 0x29, 0x8f, 0x30, 0x82, 0x8c, 0x0b, 0xa4, 0x10, 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0 };
+ do
+ {
+ generate_random_bytes_thread_safe(32, bytes);
+ } while (!less32(bytes, limit)); // should be good about 15/16 of the time
+ sc_reduce32(bytes);
+ }
+ /* generate a random 32-byte (256-bit) integer and copy it to res */
static inline void random_scalar(ec_scalar &res) {
- unsigned char tmp[64];
- generate_random_bytes_thread_safe(64, tmp);
- sc_reduce(tmp);
- memcpy(&res, tmp, 32);
+ random32_unbiased((unsigned char*)res.data);
}
void hash_to_scalar(const void *data, size_t length, ec_scalar &res) {
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 9ea0f2ec0..449af8f6d 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -99,6 +99,7 @@ namespace crypto {
#pragma pack(pop)
void hash_to_scalar(const void *data, size_t length, ec_scalar &res);
+ void random32_unbiased(unsigned char *bytes);
static_assert(sizeof(ec_point) == 32 && sizeof(ec_scalar) == 32 &&
sizeof(public_key) == 32 && sizeof(secret_key) == 32 &&
diff --git a/src/crypto/crypto_ops_builder/ref10/README.md b/src/crypto/crypto_ops_builder/ref10/README.md
new file mode 100644
index 000000000..59193305b
--- /dev/null
+++ b/src/crypto/crypto_ops_builder/ref10/README.md
@@ -0,0 +1,4 @@
+This code comes from Daniel J. Bernstein's SUPERCOP source,
+released in the public domain.
+
+[http://ed25519.cr.yp.to/software.html](http://ed25519.cr.yp.to/software.html)
diff --git a/src/crypto/crypto_ops_builder/ref10/description b/src/crypto/crypto_ops_builder/ref10/description
index cbfcb2cba..99f747747 100644
--- a/src/crypto/crypto_ops_builder/ref10/description
+++ b/src/crypto/crypto_ops_builder/ref10/description
@@ -1,2 +1,2 @@
EdDSA signatures using Curve25519
-from http://hyperelliptic.org/ebats/supercop-20141124.tar.bz2
+from https://hyperelliptic.org/ebats/supercop-20141124.tar.bz2
diff --git a/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py b/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
index 9b55d260d..0ed97d5f4 100644
--- a/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
+++ b/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
@@ -1,5 +1,5 @@
#assumes you have gnu sed, osx sed might need slight syntax changeo
-#c.f. http://unix.stackexchange.com/questions/112023/how-can-i-replace-a-string-in-a-files
+#c.f. https://unix.stackexchange.com/questions/112023/how-can-i-replace-a-string-in-a-files
#written by shen-noether monero research labs
@@ -8,7 +8,7 @@ import glob #for copy files
import textwrap #for comments etc
print("make sure you have cat and grep installed")
-print("also assumes gnu sed syntax, c.f. :http://unix.stackexchange.com/questions/112023/how-can-i-replace-a-string-in-a-files")
+print("also assumes gnu sed syntax, c.f. :https://unix.stackexchange.com/questions/112023/how-can-i-replace-a-string-in-a-files")
print("I believe osx may have slightly different version of sed")
print("maybe someone smart can replace the sed with perl..")
diff --git a/src/crypto/crypto_ops_builder/ref10CommentedCombined/description b/src/crypto/crypto_ops_builder/ref10CommentedCombined/description
index fadc9f9af..9407b400a 100644
--- a/src/crypto/crypto_ops_builder/ref10CommentedCombined/description
+++ b/src/crypto/crypto_ops_builder/ref10CommentedCombined/description
@@ -2,6 +2,6 @@ shen_ed25519_ref10
MakeCryptoOps.py makes crypto-ops.c in the Monero source from the ref10 implementation
EdDSA signatures using Curve25519
-from http://hyperelliptic.org/ebats/supercop-20141124.tar.bz2
+from https://hyperelliptic.org/ebats/supercop-20141124.tar.bz2
Commented / combined by Shen Noether, Monero Research Lab
diff --git a/src/crypto/initializer.h b/src/crypto/initializer.h
index afbace726..107988d2b 100644
--- a/src/crypto/initializer.h
+++ b/src/crypto/initializer.h
@@ -43,8 +43,8 @@
#elif defined(_MSC_VER)
#include <assert.h>
#include <stdlib.h>
-// http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc
-// http://msdn.microsoft.com/en-us/library/bb918180.aspx
+// https://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc
+// https://msdn.microsoft.com/en-us/library/bb918180.aspx
#pragma section(".CRT$XCT", read)
#define INITIALIZER(name) \
static void __cdecl name(void); \
diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c
index 35e98f2f5..9d4fc0dfa 100644
--- a/src/crypto/slow-hash.c
+++ b/src/crypto/slow-hash.c
@@ -309,7 +309,7 @@ STATIC INLINE void aes_256_assist2(__m128i* t1, __m128i * t3)
* CPU AES support.
* For more information about these functions, see page 19 of Intel's AES instructions
* white paper:
- * http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/aes-instructions-set-white-paper.pdf
+ * https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
*
* @param key the input 128 bit key
* @param expandedKey An output buffer to hold the generated key schedule
@@ -558,7 +558,7 @@ void slow_hash_free_state(void)
* AES support on x86 CPUs.
*
* A diagram of the inner loop of this function can be found at
- * http://www.cs.cmu.edu/~dga/crypto/xmr/cryptonight.png
+ * https://www.cs.cmu.edu/~dga/crypto/xmr/cryptonight.png
*
* @param data the data to hash
* @param length the length in bytes of the data
diff --git a/src/crypto/tree-hash.c b/src/crypto/tree-hash.c
index e6d6a267c..57c38b86b 100644
--- a/src/crypto/tree-hash.c
+++ b/src/crypto/tree-hash.c
@@ -67,7 +67,7 @@ size_t tree_hash_cnt(size_t count) {
}
void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) {
-// The blockchain block at height 202612 http://monerochain.info/block/bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698
+// The blockchain block at height 202612 https://moneroblocks.info/block/202612
// contained 514 transactions, that triggered bad calculation of variable "cnt" in the original version of this function
// as from CryptoNote code.
//
diff --git a/src/cryptonote_basic/hardfork.h b/src/cryptonote_basic/hardfork.h
index ee5ec0596..a63a66976 100644
--- a/src/cryptonote_basic/hardfork.h
+++ b/src/cryptonote_basic/hardfork.h
@@ -220,6 +220,14 @@ namespace cryptonote
*/
uint64_t get_window_size() const { return window_size; }
+ struct Params {
+ uint8_t version;
+ uint8_t threshold;
+ uint64_t height;
+ time_t time;
+ Params(uint8_t version, uint64_t height, uint8_t threshold, time_t time): version(version), threshold(threshold), height(height), time(time) {}
+ };
+
private:
uint8_t get_block_version(uint64_t height) const;
@@ -244,13 +252,6 @@ namespace cryptonote
uint8_t original_version;
uint64_t original_version_till_height;
- struct Params {
- uint8_t version;
- uint8_t threshold;
- uint64_t height;
- time_t time;
- Params(uint8_t version, uint64_t height, uint8_t threshold, time_t time): version(version), threshold(threshold), height(height), time(time) {}
- };
std::vector<Params> heights;
std::deque<uint8_t> versions; /* rolling window of the last N blocks' versions */
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index 3a3222f9b..dfe456ef4 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -490,7 +490,7 @@ namespace cryptonote
{
//we lucky!
++m_config.current_extra_message_index;
- MGINFO_GREEN("Found block for difficulty: " << local_diff);
+ MGINFO_GREEN("Found block " << get_block_hash(b) << " at height " << height << " for difficulty: " << local_diff);
if(!m_phandler->handle_block_found(b))
{
--m_config.current_extra_message_index;
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index fc16138d6..dad30906e 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -330,7 +330,7 @@ uint64_t Blockchain::get_current_blockchain_height() const
//------------------------------------------------------------------
//FIXME: possibly move this into the constructor, to avoid accidentally
// dereferencing a null BlockchainDB pointer
-bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline, const cryptonote::test_options *test_options)
+bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline, const cryptonote::test_options *test_options, difficulty_type fixed_difficulty)
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_tx_pool);
@@ -352,6 +352,7 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
m_nettype = test_options != NULL ? FAKECHAIN : nettype;
m_offline = offline;
+ m_fixed_difficulty = fixed_difficulty;
if (m_hardfork == nullptr)
{
if (m_nettype == FAKECHAIN || m_nettype == STAGENET)
@@ -795,6 +796,11 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
// less blocks than desired if there aren't enough.
difficulty_type Blockchain::get_difficulty_for_next_block()
{
+ if (m_fixed_difficulty)
+ {
+ return m_db->height() ? m_fixed_difficulty : 1;
+ }
+
LOG_PRINT_L3("Blockchain::" << __func__);
crypto::hash top_hash = get_tail_id();
@@ -1006,6 +1012,11 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
// an alternate chain.
difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::iterator>& alt_chain, block_extended_info& bei) const
{
+ if (m_fixed_difficulty)
+ {
+ return m_db->height() ? m_fixed_difficulty : 1;
+ }
+
LOG_PRINT_L3("Blockchain::" << __func__);
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> cumulative_difficulties;
@@ -1985,14 +1996,14 @@ void Blockchain::get_output_key_mask_unlocked(const uint64_t& amount, const uint
//------------------------------------------------------------------
bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const
{
- // rct outputs don't exist before v3
+ // rct outputs don't exist before v4
if (amount == 0)
{
switch (m_nettype)
{
- case STAGENET: start_height = stagenet_hard_forks[2].height; break;
- case TESTNET: start_height = testnet_hard_forks[2].height; break;
- case MAINNET: start_height = mainnet_hard_forks[2].height; break;
+ case STAGENET: start_height = stagenet_hard_forks[3].height; break;
+ case TESTNET: start_height = testnet_hard_forks[3].height; break;
+ case MAINNET: start_height = mainnet_hard_forks[3].height; break;
default: return false;
}
}
@@ -2000,11 +2011,40 @@ bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height,
start_height = 0;
base = 0;
+ if (to_height > 0 && to_height < from_height)
+ return false;
+
const uint64_t real_start_height = start_height;
if (from_height > start_height)
start_height = from_height;
- return m_db->get_output_distribution(amount, start_height, to_height, distribution, base);
+ distribution.clear();
+ uint64_t db_height = m_db->height();
+ if (db_height == 0)
+ return false;
+ if (to_height == 0)
+ to_height = db_height - 1;
+ if (start_height >= db_height || to_height >= db_height)
+ return false;
+ if (amount == 0)
+ {
+ std::vector<uint64_t> heights;
+ heights.reserve(to_height + 1 - start_height);
+ uint64_t real_start_height = start_height > 0 ? start_height-1 : start_height;
+ for (uint64_t h = real_start_height; h <= to_height; ++h)
+ heights.push_back(h);
+ distribution = m_db->get_block_cumulative_rct_outputs(heights);
+ if (start_height > 0)
+ {
+ base = distribution[0];
+ distribution.erase(distribution.begin());
+ }
+ return true;
+ }
+ else
+ {
+ return m_db->get_output_distribution(amount, start_height, to_height, distribution, base);
+ }
}
//------------------------------------------------------------------
// This function takes a list of block hashes from another node
@@ -2217,7 +2257,8 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
CRITICAL_REGION_LOCAL(m_blockchain_lock);
bool result = find_blockchain_supplement(qblock_ids, resp.m_block_ids, resp.start_height, resp.total_height);
- resp.cumulative_difficulty = m_db->get_block_cumulative_difficulty(resp.total_height - 1);
+ if (result)
+ resp.cumulative_difficulty = m_db->get_block_cumulative_difficulty(resp.total_height - 1);
return result;
}
@@ -3323,6 +3364,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
if(bl.prev_id != get_tail_id())
{
MERROR_VER("Block with id: " << id << std::endl << "has wrong prev_id: " << bl.prev_id << std::endl << "expected: " << get_tail_id());
+ bvc.m_verifivation_failed = true;
leave:
m_db->block_txn_stop();
return false;
@@ -3624,6 +3666,7 @@ leave:
{
//TODO: figure out the best way to deal with this failure
LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what());
+ bvc.m_verifivation_failed = true;
return_tx_to_pool(txs);
return false;
}
@@ -4406,6 +4449,39 @@ HardFork::State Blockchain::get_hard_fork_state() const
return m_hardfork->get_state();
}
+const std::vector<HardFork::Params>& Blockchain::get_hard_fork_heights(network_type nettype)
+{
+ static const std::vector<HardFork::Params> mainnet_heights = []()
+ {
+ std::vector<HardFork::Params> heights;
+ for (const auto& i : mainnet_hard_forks)
+ heights.emplace_back(i.version, i.height, i.threshold, i.time);
+ return heights;
+ }();
+ static const std::vector<HardFork::Params> testnet_heights = []()
+ {
+ std::vector<HardFork::Params> heights;
+ for (const auto& i : testnet_hard_forks)
+ heights.emplace_back(i.version, i.height, i.threshold, i.time);
+ return heights;
+ }();
+ static const std::vector<HardFork::Params> stagenet_heights = []()
+ {
+ std::vector<HardFork::Params> heights;
+ for (const auto& i : stagenet_hard_forks)
+ heights.emplace_back(i.version, i.height, i.threshold, i.time);
+ return heights;
+ }();
+ static const std::vector<HardFork::Params> dummy;
+ switch (nettype)
+ {
+ case MAINNET: return mainnet_heights;
+ case TESTNET: return testnet_heights;
+ case STAGENET: return stagenet_heights;
+ default: return dummy;
+ }
+}
+
bool Blockchain::get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const
{
return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting);
@@ -4421,9 +4497,9 @@ std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> Blockchain:: get_ou
return m_db->get_output_histogram(amounts, unlocked, recent_cutoff, min_count);
}
-std::list<std::pair<Blockchain::block_extended_info,uint64_t>> Blockchain::get_alternative_chains() const
+std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> Blockchain::get_alternative_chains() const
{
- std::list<std::pair<Blockchain::block_extended_info,uint64_t>> chains;
+ std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> chains;
for (const auto &i: m_alternative_chains)
{
@@ -4439,15 +4515,16 @@ std::list<std::pair<Blockchain::block_extended_info,uint64_t>> Blockchain::get_a
}
if (!found)
{
- uint64_t length = 1;
+ std::vector<crypto::hash> chain;
auto h = i.second.bl.prev_id;
+ chain.push_back(top);
blocks_ext_by_hash::const_iterator prev;
while ((prev = m_alternative_chains.find(h)) != m_alternative_chains.end())
{
+ chain.push_back(h);
h = prev->second.bl.prev_id;
- ++length;
}
- chains.push_back(std::make_pair(i.second, length));
+ chains.push_back(std::make_pair(i.second, chain));
}
}
return chains;
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 36d6b8609..d95c8ed15 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -114,10 +114,11 @@ namespace cryptonote
* @param nettype network type
* @param offline true if running offline, else false
* @param test_options test parameters
+ * @param fixed_difficulty fixed difficulty for testing purposes; 0 means disabled
*
* @return true on success, false if any initialization steps fail
*/
- bool init(BlockchainDB* db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL);
+ bool init(BlockchainDB* db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL, difficulty_type fixed_difficulty = 0);
/**
* @brief Initialize the Blockchain state
@@ -755,6 +756,13 @@ namespace cryptonote
HardFork::State get_hard_fork_state() const;
/**
+ * @brief gets the hardfork heights of given network
+ *
+ * @return the HardFork object
+ */
+ static const std::vector<HardFork::Params>& get_hard_fork_heights(network_type nettype);
+
+ /**
* @brief gets the current hardfork version in use/voted for
*
* @return the version
@@ -939,7 +947,7 @@ namespace cryptonote
*
* @return a list of chains
*/
- std::list<std::pair<block_extended_info,uint64_t>> get_alternative_chains() const;
+ std::list<std::pair<block_extended_info,std::vector<crypto::hash>>> get_alternative_chains() const;
void add_txpool_tx(transaction &tx, const txpool_tx_meta_t &meta);
void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta);
@@ -1040,6 +1048,7 @@ namespace cryptonote
network_type m_nettype;
bool m_offline;
+ difficulty_type m_fixed_difficulty;
std::atomic<bool> m_cancel;
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 910bf0c1f..18490c65e 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -76,6 +76,16 @@ namespace cryptonote
, "Run on stagenet. The wallet must be launched with --stagenet flag."
, false
};
+ const command_line::arg_descriptor<bool> arg_regtest_on = {
+ "regtest"
+ , "Run in a regression testing mode."
+ , false
+ };
+ const command_line::arg_descriptor<difficulty_type> arg_fixed_difficulty = {
+ "fixed-difficulty"
+ , "Fixed difficulty used for testing."
+ , 0
+ };
const command_line::arg_descriptor<std::string, false, true, 2> arg_data_dir = {
"data-dir"
, "Specify data directory"
@@ -251,6 +261,8 @@ namespace cryptonote
command_line::add_arg(desc, arg_testnet_on);
command_line::add_arg(desc, arg_stagenet_on);
+ command_line::add_arg(desc, arg_regtest_on);
+ command_line::add_arg(desc, arg_fixed_difficulty);
command_line::add_arg(desc, arg_dns_checkpoints);
command_line::add_arg(desc, arg_prep_blocks_threads);
command_line::add_arg(desc, arg_fast_block_sync);
@@ -373,7 +385,8 @@ namespace cryptonote
{
start_time = std::time(nullptr);
- if (test_options != NULL)
+ const bool regtest = command_line::get_arg(vm, arg_regtest_on);
+ if (test_options != NULL || regtest)
{
m_nettype = FAKECHAIN;
}
@@ -430,6 +443,16 @@ namespace cryptonote
blockchain_db_sync_mode sync_mode = db_defaultsync;
uint64_t blocks_per_sync = 1;
+ if (m_nettype == FAKECHAIN)
+ {
+ // reset the db by removing the database file before opening it
+ if (!db->remove_data_file(filename))
+ {
+ MERROR("Failed to remove data file in " << filename);
+ return false;
+ }
+ }
+
try
{
uint64_t db_flags = 0;
@@ -507,7 +530,12 @@ namespace cryptonote
m_blockchain_storage.set_user_options(blocks_threads,
blocks_per_sync, sync_mode, fast_sync);
- r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, test_options);
+ const std::pair<uint8_t, uint64_t> regtest_hard_forks[3] = {std::make_pair(1, 0), std::make_pair(Blockchain::get_hard_fork_heights(MAINNET).back().version, 1), std::make_pair(0, 0)};
+ const cryptonote::test_options regtest_test_options = {
+ regtest_hard_forks
+ };
+ const difficulty_type fixed_difficulty = command_line::get_arg(vm, arg_fixed_difficulty);
+ r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, regtest ? &regtest_test_options : test_options, fixed_difficulty);
r = m_mempool.init(max_txpool_size);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 03000383e..84e1bb918 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -60,6 +60,8 @@ namespace cryptonote
extern const command_line::arg_descriptor<std::string, false, true, 2> arg_data_dir;
extern const command_line::arg_descriptor<bool, false> arg_testnet_on;
extern const command_line::arg_descriptor<bool, false> arg_stagenet_on;
+ extern const command_line::arg_descriptor<bool, false> arg_regtest_on;
+ extern const command_line::arg_descriptor<difficulty_type> arg_fixed_difficulty;
extern const command_line::arg_descriptor<bool> arg_offline;
/************************************************************************/
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 8dee2b922..eac0f1f57 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -220,7 +220,7 @@ namespace cryptonote
crypto::hash max_used_block_id = null_hash;
uint64_t max_used_block_height = 0;
cryptonote::txpool_tx_meta_t meta;
- bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id, tvc, kept_by_block);
+ bool ch_inp_res = check_tx_inputs([&tx]()->cryptonote::transaction&{ return tx; }, id, max_used_block_height, max_used_block_id, tvc, kept_by_block);
if(!ch_inp_res)
{
// if the transaction was valid before (kept_by_block), then it
@@ -893,11 +893,15 @@ namespace cryptonote
//---------------------------------------------------------------------------------
bool tx_memory_pool::on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id)
{
+ CRITICAL_REGION_LOCAL(m_transactions_lock);
+ m_input_cache.clear();
return true;
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::on_blockchain_dec(uint64_t new_block_height, const crypto::hash& top_block_id)
{
+ CRITICAL_REGION_LOCAL(m_transactions_lock);
+ m_input_cache.clear();
return true;
}
//---------------------------------------------------------------------------------
@@ -937,7 +941,26 @@ namespace cryptonote
m_transactions_lock.unlock();
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::is_transaction_ready_to_go(txpool_tx_meta_t& txd, const cryptonote::blobdata &txblob, transaction &tx) const
+ bool tx_memory_pool::check_tx_inputs(const std::function<cryptonote::transaction&(void)> &get_tx, const crypto::hash &txid, uint64_t &max_used_block_height, crypto::hash &max_used_block_id, tx_verification_context &tvc, bool kept_by_block) const
+ {
+ if (!kept_by_block)
+ {
+ const std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>>::const_iterator i = m_input_cache.find(txid);
+ if (i != m_input_cache.end())
+ {
+ max_used_block_height = std::get<2>(i->second);
+ max_used_block_id = std::get<3>(i->second);
+ tvc = std::get<1>(i->second);
+ return std::get<0>(i->second);
+ }
+ }
+ bool ret = m_blockchain.check_tx_inputs(get_tx(), max_used_block_height, max_used_block_id, tvc, kept_by_block);
+ if (!kept_by_block)
+ m_input_cache.insert(std::make_pair(txid, std::make_tuple(ret, tvc, max_used_block_height, max_used_block_id)));
+ return ret;
+ }
+ //---------------------------------------------------------------------------------
+ bool tx_memory_pool::is_transaction_ready_to_go(txpool_tx_meta_t& txd, const crypto::hash &txid, const cryptonote::blobdata &txblob, transaction &tx) const
{
struct transction_parser
{
@@ -966,7 +989,7 @@ namespace cryptonote
return false;//we already sure that this tx is broken for this height
tx_verification_context tvc;
- if(!m_blockchain.check_tx_inputs(lazy_tx(), txd.max_used_block_height, txd.max_used_block_id, tvc))
+ if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{ return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc))
{
txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
@@ -983,7 +1006,7 @@ namespace cryptonote
return false;
//check ring signature again, it is possible (with very small chance) that this transaction become again valid
tx_verification_context tvc;
- if(!m_blockchain.check_tx_inputs(lazy_tx(), txd.max_used_block_height, txd.max_used_block_id, tvc))
+ if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{ return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc))
{
txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
@@ -1176,7 +1199,7 @@ namespace cryptonote
bool ready = false;
try
{
- ready = is_transaction_ready_to_go(meta, txblob, tx);
+ ready = is_transaction_ready_to_go(meta, sorted_it->second, txblob, tx);
}
catch (const std::exception &e)
{
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index 5ccb71196..4ade7ddbe 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -499,12 +499,13 @@ namespace cryptonote
* @brief check if a transaction is a valid candidate for inclusion in a block
*
* @param txd the transaction to check (and info about it)
+ * @param txid the txid of the transaction to check
* @param txblob the transaction blob to check
* @param tx the parsed transaction, if successful
*
* @return true if the transaction is good to go, otherwise false
*/
- bool is_transaction_ready_to_go(txpool_tx_meta_t& txd, const cryptonote::blobdata &txblob, transaction &tx) const;
+ bool is_transaction_ready_to_go(txpool_tx_meta_t& txd, const crypto::hash &txid, const cryptonote::blobdata &txblob, transaction &tx) const;
/**
* @brief mark all transactions double spending the one passed
@@ -557,6 +558,9 @@ private:
*/
sorted_tx_container::iterator find_tx_in_sorted_container(const crypto::hash& id) const;
+ //! cache/call Blockchain::check_tx_inputs results
+ bool check_tx_inputs(const std::function<cryptonote::transaction&(void)> &get_tx, const crypto::hash &txid, uint64_t &max_used_block_height, crypto::hash &max_used_block_id, tx_verification_context &tvc, bool kept_by_block = false) const;
+
//! transactions which are unlikely to be included in blocks
/*! These transactions are kept in RAM in case they *are* included
* in a block eventually, but this container is not saved to disk.
@@ -567,6 +571,8 @@ private:
size_t m_txpool_max_size;
size_t m_txpool_size;
+
+ mutable std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>> m_input_cache;
};
}
diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt
index 3b1d0d826..84004c3c6 100644
--- a/src/daemon/CMakeLists.txt
+++ b/src/daemon/CMakeLists.txt
@@ -92,7 +92,6 @@ target_link_libraries(daemon
daemonizer
serialization
daemon_rpc_server
- epee
${EPEE_READLINE}
version
${Boost_CHRONO_LIBRARY}
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index aa688294d..1638cf505 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -614,13 +614,13 @@ bool t_command_parser_executor::print_coinbase_tx_sum(const std::vector<std::str
bool t_command_parser_executor::alt_chain_info(const std::vector<std::string>& args)
{
- if(args.size())
+ if(args.size() > 1)
{
- std::cout << "No parameters allowed" << std::endl;
+ std::cout << "usage: alt_chain_info [block_hash]" << std::endl;
return false;
}
- return m_executor.alt_chain_info();
+ return m_executor.alt_chain_info(args.size() == 1 ? args[0] : "");
}
bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector<std::string>& args)
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 144603597..35504f2c9 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -255,6 +255,7 @@ t_command_server::t_command_server(
m_command_lookup.set_handler(
"alt_chain_info"
, std::bind(&t_command_parser_executor::alt_chain_info, &m_parser, p::_1)
+ , "alt_chain_info [blockhash]"
, "Print the information about alternative chains."
);
m_command_lookup.set_handler(
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index 48671f190..ea24e32eb 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -77,9 +77,10 @@ public:
const auto testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
const auto stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
+ const auto regtest = command_line::get_arg(vm, cryptonote::arg_regtest_on);
const auto restricted = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_restricted_rpc);
const auto main_rpc_port = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_port);
- rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, testnet ? cryptonote::TESTNET : stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, main_rpc_port, "core"});
+ rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, testnet ? cryptonote::TESTNET : stagenet ? cryptonote::STAGENET : regtest ? cryptonote::FAKECHAIN : cryptonote::MAINNET, main_rpc_port, "core"});
auto restricted_rpc_port_arg = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port;
if(!command_line::is_arg_defaulted(vm, restricted_rpc_port_arg))
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index 88bb1fd0c..82ece62a9 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -163,9 +163,10 @@ int main(int argc, char const * argv[])
const bool testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
const bool stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
- if (testnet && stagenet)
+ const bool regtest = command_line::get_arg(vm, cryptonote::arg_regtest_on);
+ if (testnet + stagenet + regtest > 1)
{
- std::cerr << "Can't specify more than one of --tesnet and --stagenet" << ENDL;
+ std::cerr << "Can't specify more than one of --tesnet and --stagenet and --regtest" << ENDL;
return 1;
}
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 956c84a01..e2b42c806 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -75,7 +75,9 @@ namespace {
<< "hash: " << header.hash << std::endl
<< "difficulty: " << boost::lexical_cast<std::string>(header.difficulty) << std::endl
<< "POW hash: " << header.pow_hash << std::endl
- << "reward: " << boost::lexical_cast<std::string>(header.reward);
+ << "block size: " << header.block_size << std::endl
+ << "num txes: " << header.num_txes << std::endl
+ << "reward: " << cryptonote::print_money(header.reward);
}
std::string get_human_time_ago(time_t t, time_t now)
@@ -1628,7 +1630,7 @@ bool t_rpc_command_executor::print_coinbase_tx_sum(uint64_t height, uint64_t cou
return true;
}
-bool t_rpc_command_executor::alt_chain_info()
+bool t_rpc_command_executor::alt_chain_info(const std::string &tip)
{
cryptonote::COMMAND_RPC_GET_INFO::request ireq;
cryptonote::COMMAND_RPC_GET_INFO::response ires;
@@ -1663,12 +1665,32 @@ bool t_rpc_command_executor::alt_chain_info()
}
}
- tools::msg_writer() << boost::lexical_cast<std::string>(res.chains.size()) << " alternate chains found:";
- for (const auto &chain: res.chains)
+ if (tip.empty())
{
- uint64_t start_height = (chain.height - chain.length + 1);
- tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1)
- << " deep), diff " << chain.difficulty << ": " << chain.block_hash;
+ tools::msg_writer() << boost::lexical_cast<std::string>(res.chains.size()) << " alternate chains found:";
+ for (const auto &chain: res.chains)
+ {
+ uint64_t start_height = (chain.height - chain.length + 1);
+ tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1)
+ << " deep), diff " << chain.difficulty << ": " << chain.block_hash;
+ }
+ }
+ else
+ {
+ const auto i = std::find_if(res.chains.begin(), res.chains.end(), [&tip](cryptonote::COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info &info){ return info.block_hash == tip; });
+ if (i != res.chains.end())
+ {
+ const auto &chain = *i;
+ tools::success_msg_writer() << "Found alternate chain with tip " << tip;
+ uint64_t start_height = (chain.height - chain.length + 1);
+ tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1)
+ << " deep), diff " << chain.difficulty << ":";
+ for (const std::string &block_id: chain.block_hashes)
+ tools::msg_writer() << " " << block_id;
+ tools::msg_writer() << "Chain parent on main chain: " << chain.main_chain_parent_block;
+ }
+ else
+ tools::fail_msg_writer() << "Block hash " << tip << " is not the tip of any known alternate chain";
}
return true;
}
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index 46168c93b..9e6010c5b 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -143,7 +143,7 @@ public:
bool print_coinbase_tx_sum(uint64_t height, uint64_t count);
- bool alt_chain_info();
+ bool alt_chain_info(const std::string &tip);
bool print_blockchain_dynamic_stats(uint64_t nblocks);
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
index f716f8ded..f7bf58531 100644
--- a/src/device/device_ledger.cpp
+++ b/src/device/device_ledger.cpp
@@ -274,22 +274,32 @@ namespace hw {
/* ======================================================================= */
/* MISC */
/* ======================================================================= */
- bool device_ledger::reset() {
- int offset;
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_RESET;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
+ int device_ledger::set_command_header(BYTE ins, BYTE p1, BYTE p2) {
+ reset_buffer();
+ int offset = 0;
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = ins;
+ this->buffer_send[2] = p1;
+ this->buffer_send[3] = p2;
+ this->buffer_send[4] = 0x00;
+ return 5;
+ }
- this->buffer_send[4] = offset-5;
- this->length_send = offset;
- this->exchange();
+ int device_ledger::set_command_header_noopt(BYTE ins, BYTE p1, BYTE p2) {
+ int offset = set_command_header(ins, p1, p2);
+ //options
+ this->buffer_send[offset++] = 0;
+ this->buffer_send[4] = offset - 5;
+ return offset;
+ }
+
+ void device_ledger::send_simple(BYTE ins, BYTE p1) {
+ this->length_send = set_command_header_noopt(ins, p1);
+ this->exchange();
+ }
+
+ bool device_ledger::reset() {
+ send_simple(INS_RESET);
return true;
}
@@ -451,20 +461,10 @@ namespace hw {
int offset;
- reset_buffer();
-
switch(mode) {
case TRANSACTION_CREATE_REAL:
case TRANSACTION_CREATE_FAKE:
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_SET_SIGNATURE_MODE;
- this->buffer_send[2] = 0x01;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
+ offset = set_command_header_noopt(INS_SET_SIGNATURE_MODE, 1);
//account
this->buffer_send[offset] = mode;
offset += 1;
@@ -495,22 +495,7 @@ namespace hw {
bool device_ledger::get_public_address(cryptonote::account_public_address &pubkey){
AUTO_LOCK_CMD();
- int offset;
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_GET_KEY;
- this->buffer_send[2] = 0x01;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
-
- this->buffer_send[4] = offset-5;
- this->length_send = offset;
- this->exchange();
+ send_simple(INS_GET_KEY, 1);
memmove(pubkey.m_view_public_key.data, this->buffer_recv, 32);
memmove(pubkey.m_spend_public_key.data, this->buffer_recv+32, 32);
@@ -526,22 +511,7 @@ namespace hw {
memset(skey.data, 0xFF, 32);
//spcialkey, normal conf handled in decrypt
- int offset;
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_GET_KEY;
- this->buffer_send[2] = 0x02;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
-
- this->buffer_send[4] = offset-5;
- this->length_send = offset;
- this->exchange();
+ send_simple(INS_GET_KEY, 0x02);
//View key is retrievied, if allowed, to speed up blockchain parsing
memmove(this->viewkey.data, this->buffer_recv+0, 32);
@@ -563,7 +533,6 @@ namespace hw {
bool device_ledger::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) {
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
crypto::chacha_key key_x;
@@ -571,20 +540,7 @@ namespace hw {
this->controle_device->generate_chacha_key(keys_x, key_x);
#endif
- reset_buffer();
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_GET_CHACHA8_PREKEY;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
-
- this->buffer_send[4] = offset-5;
- this->length_send = offset;
- this->exchange();
+ send_simple(INS_GET_CHACHA8_PREKEY);
char prekey[200];
memmove(prekey, &this->buffer_recv[0], 200);
@@ -627,19 +583,7 @@ namespace hw {
crypto::derive_subaddress_public_key(pub, derivation, output_index,derived_pub);
} else {
- int offset =0;
-
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_DERIVE_SUBADDRESS_PUBLIC_KEY;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
+ int offset = set_command_header_noopt(INS_DERIVE_SUBADDRESS_PUBLIC_KEY);
//pub
memmove(this->buffer_send+offset, pub.data, 32);
offset += 32;
@@ -670,7 +614,6 @@ namespace hw {
crypto::public_key device_ledger::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) {
AUTO_LOCK_CMD();
crypto::public_key D;
- int offset;
#ifdef DEBUG_HWDEVICE
const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys);
@@ -687,17 +630,7 @@ namespace hw {
D = keys.m_account_address.m_spend_public_key;
} else {
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
+ int offset = set_command_header_noopt(INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY);
//index
static_assert(sizeof(cryptonote::subaddress_index) == 8, "cryptonote::subaddress_index shall be 8 bytes length");
memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index));
@@ -732,7 +665,6 @@ namespace hw {
cryptonote::account_public_address device_ledger::get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) {
AUTO_LOCK_CMD();
cryptonote::account_public_address address;
- int offset;
#ifdef DEBUG_HWDEVICE
const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys);
@@ -751,17 +683,7 @@ namespace hw {
if (index.is_zero()) {
address = keys.m_account_address;
} else {
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_GET_SUBADDRESS;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
+ int offset = set_command_header_noopt(INS_GET_SUBADDRESS);
//index
static_assert(sizeof(cryptonote::subaddress_index) == 8, "cryptonote::subaddress_index shall be 8 bytes length");
memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index));
@@ -786,7 +708,6 @@ namespace hw {
crypto::secret_key device_ledger::get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index) {
AUTO_LOCK_CMD();
crypto::secret_key sub_sec;
- int offset;
#ifdef DEBUG_HWDEVICE
const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
@@ -798,17 +719,7 @@ namespace hw {
hw::ledger::log_hexbuffer("get_subaddress_secret_key: [[OUT]] sub_sec", sub_sec_x.data, 32);
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_GET_SUBADDRESS_SECRET_KEY;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
+ int offset = set_command_header_noopt(INS_GET_SUBADDRESS_SECRET_KEY);
//sec
memmove(this->buffer_send+offset, sec.data, 32);
offset += 32;
@@ -839,16 +750,7 @@ namespace hw {
AUTO_LOCK_CMD();
int offset, sw;
- reset_buffer();
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_VERIFY_KEY;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
+ offset = set_command_header_noopt(INS_VERIFY_KEY);
//sec
memmove(this->buffer_send+offset, secret_key.data, 32);
offset += 32;
@@ -871,7 +773,6 @@ namespace hw {
bool device_ledger::scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) {
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
const rct::key P_x = P;
@@ -883,17 +784,7 @@ namespace hw {
hw::ledger::log_hexbuffer("scalarmultKey: [[OUT]] aP", (char*)aP_x.bytes, 32);
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_SECRET_SCAL_MUL_KEY;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
+ int offset = set_command_header_noopt(INS_SECRET_SCAL_MUL_KEY);
//pub
memmove(this->buffer_send+offset, P.bytes, 32);
offset += 32;
@@ -918,7 +809,6 @@ namespace hw {
bool device_ledger::scalarmultBase(rct::key &aG, const rct::key &a) {
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
const rct::key a_x = hw::ledger::decrypt(a);
@@ -928,17 +818,7 @@ namespace hw {
hw::ledger::log_hexbuffer("scalarmultKey: [[OUT]] aG", (char*)aG_x.bytes, 32);
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_SECRET_SCAL_MUL_BASE;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
+ int offset = set_command_header_noopt(INS_SECRET_SCAL_MUL_BASE);
//sec
memmove(this->buffer_send+offset, a.bytes, 32);
offset += 32;
@@ -959,7 +839,6 @@ namespace hw {
bool device_ledger::sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) {
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
const crypto::secret_key a_x = hw::ledger::decrypt(a);
@@ -968,17 +847,7 @@ namespace hw {
this->controle_device->sc_secret_add(r_x, a_x, b_x);
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_SECRET_KEY_ADD;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
+ int offset = set_command_header_noopt(INS_SECRET_KEY_ADD);
//sec key
memmove(this->buffer_send+offset, a.data, 32);
offset += 32;
@@ -1007,8 +876,6 @@ namespace hw {
throw std::runtime_error("device generate key does not support recover");
}
- int offset;
-
#ifdef DEBUG_HWDEVICE
bool recover_x = recover;
const crypto::secret_key recovery_key_x = recovery_key;
@@ -1016,21 +883,7 @@ namespace hw {
crypto::secret_key sec_x;
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_GENERATE_KEYPAIR;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
-
- this->buffer_send[4] = offset-5;
- this->length_send = offset;
- this->exchange();
+ send_simple(INS_GENERATE_KEYPAIR);
//pub key
memmove(pub.data, &this->buffer_recv[0], 32);
@@ -1070,19 +923,7 @@ namespace hw {
r = crypto::generate_key_derivation(pub, this->viewkey, derivation);
} else {
- int offset;
-
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_GEN_KEY_DERIVATION;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
+ int offset = set_command_header_noopt(INS_GEN_KEY_DERIVATION);
//pub
memmove(this->buffer_send+offset, pub.data, 32);
offset += 32;
@@ -1131,7 +972,6 @@ namespace hw {
bool device_ledger::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) {
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
@@ -1143,17 +983,7 @@ namespace hw {
hw::ledger::log_hexbuffer("derivation_to_scalar: [[OUT]] res ", res_x.data, 32);
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_DERIVATION_TO_SCALAR;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
+ int offset = set_command_header_noopt(INS_DERIVATION_TO_SCALAR);
//derivattion
memmove(this->buffer_send+offset, derivation.data, 32);
offset += 32;
@@ -1181,7 +1011,6 @@ namespace hw {
bool device_ledger::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) {
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
@@ -1195,17 +1024,7 @@ namespace hw {
hw::ledger::log_hexbuffer("derive_secret_key: [[OUT]] derived_sec", derived_sec_x.data, 32);
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_DERIVE_SECRET_KEY;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
+ int offset = set_command_header_noopt(INS_DERIVE_SECRET_KEY);
//derivation
memmove(this->buffer_send+offset, derivation.data, 32);
offset += 32;
@@ -1236,7 +1055,6 @@ namespace hw {
bool device_ledger::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub){
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
@@ -1250,17 +1068,7 @@ namespace hw {
hw::ledger::log_hexbuffer("derive_public_key: [[OUT]] derived_pub ", derived_pub_x.data, 32);
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_DERIVE_PUBLIC_KEY;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
+ int offset = set_command_header_noopt(INS_DERIVE_PUBLIC_KEY);
//derivation
memmove(this->buffer_send+offset, derivation.data, 32);
offset += 32;
@@ -1290,7 +1098,6 @@ namespace hw {
bool device_ledger::secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) {
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
@@ -1303,17 +1110,7 @@ namespace hw {
}
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_SECRET_KEY_TO_PUBLIC_KEY;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
+ int offset = set_command_header_noopt(INS_SECRET_KEY_TO_PUBLIC_KEY);
//sec key
memmove(this->buffer_send+offset, sec.data, 32);
offset += 32;
@@ -1334,7 +1131,6 @@ namespace hw {
bool device_ledger::generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image){
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
const crypto::public_key pub_x = pub;
@@ -1346,17 +1142,7 @@ namespace hw {
hw::ledger::log_hexbuffer("generate_key_image: [[OUT]] image ", image_x.data, 32);
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_GEN_KEY_IMAGE;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0;
- offset += 1;
+ int offset = set_command_header_noopt(INS_GEN_KEY_IMAGE);
//pub
memmove(this->buffer_send+offset, pub.data, 32);
offset += 32;
@@ -1384,20 +1170,10 @@ namespace hw {
bool device_ledger::open_tx(crypto::secret_key &tx_key) {
AUTO_LOCK_CMD();
- int offset;
- reset_buffer();
key_map.clear();
+ int offset = set_command_header_noopt(INS_OPEN_TX, 0x01);
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_OPEN_TX;
- this->buffer_send[2] = 0x01;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
//account
this->buffer_send[offset+0] = 0x00;
this->buffer_send[offset+1] = 0x00;
@@ -1416,7 +1192,6 @@ namespace hw {
bool device_ledger::encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) {
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
const crypto::public_key public_key_x = public_key;
@@ -1425,17 +1200,7 @@ namespace hw {
this->controle_device->encrypt_payment_id(payment_id_x, public_key_x, secret_key_x);
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_STEALTH;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
+ int offset = set_command_header_noopt(INS_STEALTH);
//pub
memmove(&this->buffer_send[offset], public_key.data, 32);
offset += 32;
@@ -1467,7 +1232,6 @@ namespace hw {
bool device_ledger::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & AKout) {
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
const rct::key AKout_x = hw::ledger::decrypt(AKout);
@@ -1475,17 +1239,7 @@ namespace hw {
this->controle_device->ecdhEncode(unmasked_x, AKout_x);
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_BLIND;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
+ int offset = set_command_header_noopt(INS_BLIND);
// AKout
memmove(this->buffer_send+offset, AKout.bytes, 32);
offset += 32;
@@ -1515,7 +1269,6 @@ namespace hw {
bool device_ledger::ecdhDecode(rct::ecdhTuple & masked, const rct::key & AKout) {
AUTO_LOCK_CMD();
- int offset;
#ifdef DEBUG_HWDEVICE
const rct::key AKout_x = hw::ledger::decrypt(AKout);
@@ -1523,17 +1276,8 @@ namespace hw {
this->controle_device->ecdhDecode(masked_x, AKout_x);
#endif
- reset_buffer();
+ int offset = set_command_header_noopt(INS_UNBLIND);
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_UNBLIND;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
// AKout
memmove(this->buffer_send+offset, AKout.bytes, 32);
offset += 32;
@@ -1583,16 +1327,7 @@ namespace hw {
data = blob.data();
// ====== u8 type, varint txnfee ======
- int offset;
-
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_VALIDATE;
- this->buffer_send[2] = 0x01;
- this->buffer_send[3] = 0x01;
- this->buffer_send[4] = 0x00;
- offset = 5;
+ int offset = set_command_header(INS_VALIDATE, 0x01, 0x01);
//options
this->buffer_send[offset] = (inputs_size == 0)?0x00:0x80;
offset += 1;
@@ -1620,13 +1355,7 @@ namespace hw {
//pseudoOuts
if ((type == rct::RCTTypeSimple) || (type == rct::RCTTypeSimpleBulletproof)) {
for ( i = 0; i < inputs_size; i++) {
- reset_buffer();
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_VALIDATE;
- this->buffer_send[2] = 0x01;
- this->buffer_send[3] = i+2;
- this->buffer_send[4] = 0x00;
- offset = 5;
+ offset = set_command_header(INS_VALIDATE, 0x01, i+2);
//options
this->buffer_send[offset] = (i==inputs_size-1)? 0x00:0x80;
offset += 1;
@@ -1653,14 +1382,7 @@ namespace hw {
log_hexbuffer("Pout not found", (char*)outPk[i].dest.bytes, 32);
CHECK_AND_ASSERT_THROW_MES(found, "Pout not found");
}
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_VALIDATE;
- this->buffer_send[2] = 0x02;
- this->buffer_send[3] = i+1;
- this->buffer_send[4] = 0x00;
- offset = 5;
+ offset = set_command_header(INS_VALIDATE, 0x02, i+1);
//options
this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ;
offset += 1;
@@ -1705,14 +1427,7 @@ namespace hw {
// ====== C[], message, proof======
C_offset = kv_offset;
for (i = 0; i < outputs_size; i++) {
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_VALIDATE;
- this->buffer_send[2] = 0x03;
- this->buffer_send[3] = i+1;
- this->buffer_send[4] = 0x00;
- offset = 5;
+ offset = set_command_header(INS_VALIDATE, 0x03, i+1);
//options
this->buffer_send[offset] = 0x80 ;
offset += 1;
@@ -1727,17 +1442,7 @@ namespace hw {
}
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_VALIDATE;
- this->buffer_send[2] = 0x03;
- this->buffer_send[3] = i+1;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
+ offset = set_command_header_noopt(INS_VALIDATE, 0x03, i+1);
//message
memmove(this->buffer_send+offset, hashes[0].bytes,32);
offset += 32;
@@ -1762,7 +1467,6 @@ namespace hw {
bool device_ledger::mlsag_prepare(const rct::key &H, const rct::key &xx,
rct::key &a, rct::key &aG, rct::key &aHP, rct::key &II) {
AUTO_LOCK_CMD();
- int offset;
unsigned char options;
#ifdef DEBUG_HWDEVICE
@@ -1774,17 +1478,7 @@ namespace hw {
rct::key II_x;
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_MLSAG;
- this->buffer_send[2] = 0x01;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
+ int offset = set_command_header_noopt(INS_MLSAG, 0x01);
//value H
memmove(this->buffer_send+offset, H.bytes, 32);
offset += 32;
@@ -1817,7 +1511,6 @@ namespace hw {
bool device_ledger::mlsag_prepare(rct::key &a, rct::key &aG) {
AUTO_LOCK_CMD();
- int offset;
unsigned char options;
#ifdef DEBUG_HWDEVICE
@@ -1825,21 +1518,7 @@ namespace hw {
rct::key aG_x;
#endif
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_MLSAG;
- this->buffer_send[2] = 0x01;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
-
- this->buffer_send[4] = offset-5;
- this->length_send = offset;
- this->exchange();
+ send_simple(INS_MLSAG, 0x01);
memmove(a.bytes, &this->buffer_recv[32*0], 32);
memmove(aG.bytes, &this->buffer_recv[32*1], 32);
@@ -1855,7 +1534,6 @@ namespace hw {
bool device_ledger::mlsag_hash(const rct::keyV &long_message, rct::key &c) {
AUTO_LOCK_CMD();
- int offset;
unsigned char options;
size_t cnt;
@@ -1867,14 +1545,7 @@ namespace hw {
cnt = long_message.size();
for (size_t i = 0; i<cnt; i++) {
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_MLSAG;
- this->buffer_send[2] = 0x02;
- this->buffer_send[3] = i+1;
- this->buffer_send[4] = 0x00;
- offset = 5;
+ int offset = set_command_header(INS_MLSAG, 0x02, i+1);
//options
this->buffer_send[offset] =
(i==(cnt-1))?0x00:0x80; //last
@@ -1899,7 +1570,6 @@ namespace hw {
bool device_ledger::mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) {
AUTO_LOCK_CMD();
- int offset;
CHECK_AND_ASSERT_THROW_MES(dsRows<=rows, "dsRows greater than rows");
CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "xx size does not match rows");
@@ -1917,14 +1587,7 @@ namespace hw {
#endif
for (size_t j = 0; j < dsRows; j++) {
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_MLSAG;
- this->buffer_send[2] = 0x03;
- this->buffer_send[3] = j+1;
- this->buffer_send[4] = 0x00;
- offset = 5;
+ int offset = set_command_header(INS_MLSAG, 0x03, j+1);
//options
this->buffer_send[offset] = 0x00;
if (j==(dsRows-1)) {
@@ -1961,24 +1624,7 @@ namespace hw {
bool device_ledger::close_tx() {
AUTO_LOCK_CMD();
- int offset;
-
- reset_buffer();
-
- this->buffer_send[0] = 0x00;
- this->buffer_send[1] = INS_CLOSE_TX;
- this->buffer_send[2] = 0x00;
- this->buffer_send[3] = 0x00;
- this->buffer_send[4] = 0x00;
- offset = 5;
- //options
- this->buffer_send[offset] = 0x00;
- offset += 1;
-
- this->buffer_send[4] = offset-5;
- this->length_send = offset;
- this->exchange();
-
+ send_simple(INS_CLOSE_TX);
return true;
}
diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp
index b62bdf959..c30a38aca 100644
--- a/src/device/device_ledger.hpp
+++ b/src/device/device_ledger.hpp
@@ -102,6 +102,9 @@ namespace hw {
void logRESP(void);
unsigned int exchange(unsigned int ok=0x9000, unsigned int mask=0xFFFF);
void reset_buffer(void);
+ int set_command_header(BYTE ins, BYTE p1 = 0x00, BYTE p2 = 0x00);
+ int set_command_header_noopt(BYTE ins, BYTE p1 = 0x00, BYTE p2 = 0x00);
+ void send_simple(BYTE ins, BYTE p1 = 0x00);
// hw running mode
device_mode mode;
diff --git a/src/mnemonics/esperanto.h b/src/mnemonics/esperanto.h
index cb377a58e..a1d1a3f30 100644
--- a/src/mnemonics/esperanto.h
+++ b/src/mnemonics/esperanto.h
@@ -37,7 +37,7 @@
* Sources:
* Baza Radikaro Oficiala
* Reta Vortaro (http://www.reta-vortaro.de/revo/)
- * Esperanto Panorama - Esperanto-English Dictionary (http://www.esperanto-panorama.net/vortaro/eoen.htm)
+ * Esperanto Panorama - Esperanto-English Dictionary (https://www.esperanto-panorama.net/vortaro/eoen.htm)
* ESPDIC - Paul Denisowski (http://www.denisowski.org/Esperanto/ESPDIC/espdic.txt)
*/
diff --git a/src/mnemonics/lojban.h b/src/mnemonics/lojban.h
index 412531a23..0966a1169 100644
--- a/src/mnemonics/lojban.h
+++ b/src/mnemonics/lojban.h
@@ -35,7 +35,7 @@
/*
* Word list authored by: sorpaas
* Sources:
- * lo gimste jo'u lo ma'oste (http://guskant.github.io/lojbo/gismu-cmavo.html)
+ * lo gimste jo'u lo ma'oste (https://guskant.github.io/lojbo/gismu-cmavo.html)
* N-grams of Lojban corpus (https://mw.lojban.org/papri/N-grams_of_Lojban_corpus)
*/
diff --git a/src/p2p/CMakeLists.txt b/src/p2p/CMakeLists.txt
index 83bdffab5..9b924907e 100644
--- a/src/p2p/CMakeLists.txt
+++ b/src/p2p/CMakeLists.txt
@@ -38,7 +38,6 @@ source_group(p2p FILES ${P2P})
monero_add_library(p2p ${P2P})
target_link_libraries(p2p
PUBLIC
- epee
version
cryptonote_core
${UPNP_LIBRARIES}
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 85470f799..9390626a8 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -402,6 +402,9 @@ namespace nodetool
full_addrs.insert("162.210.173.150:38080");
full_addrs.insert("162.210.173.151:38080");
}
+ else if (nettype == cryptonote::FAKECHAIN)
+ {
+ }
else
{
full_addrs.insert("107.152.130.98:18080");
diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp
index 68cc43128..50693bad7 100644
--- a/src/ringct/rctOps.cpp
+++ b/src/ringct/rctOps.cpp
@@ -62,14 +62,13 @@ namespace rct {
//generates a random scalar which can be used as a secret key or mask
void skGen(key &sk) {
- sk = crypto::rand<key>();
- sc_reduce32(sk.bytes);
+ random32_unbiased(sk.bytes);
}
//generates a random scalar which can be used as a secret key or mask
key skGen() {
- key sk = crypto::rand<key>();
- sc_reduce32(sk.bytes);
+ key sk;
+ skGen(sk);
return sk;
}
@@ -79,9 +78,8 @@ namespace rct {
CHECK_AND_ASSERT_THROW_MES(rows > 0, "0 keys requested");
keyV rv(rows);
size_t i = 0;
- crypto::rand(rows * sizeof(key), (uint8_t*)&rv[0]);
for (i = 0 ; i < rows ; i++) {
- sc_reduce32(rv[i].bytes);
+ skGen(rv[i]);
}
return rv;
}
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index cc6fbe738..f74216ed4 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -147,7 +147,7 @@ namespace rct {
//This is a just slghtly more efficient version than the ones described below
//(will be explained in more detail in Ring Multisig paper
//These are aka MG signatutes in earlier drafts of the ring ct paper
- // c.f. http://eprint.iacr.org/2015/1098 section 2.
+ // c.f. https://eprint.iacr.org/2015/1098 section 2.
// Gen creates a signature which proves that for some column in the keymatrix "pk"
// the signer knows a secret key for each row in that column
// Ver verifies that the MG sig was created correctly
@@ -244,7 +244,7 @@ namespace rct {
//This is a just slghtly more efficient version than the ones described below
//(will be explained in more detail in Ring Multisig paper
//These are aka MG signatutes in earlier drafts of the ring ct paper
- // c.f. http://eprint.iacr.org/2015/1098 section 2.
+ // c.f. https://eprint.iacr.org/2015/1098 section 2.
// Gen creates a signature which proves that for some column in the keymatrix "pk"
// the signer knows a secret key for each row in that column
// Ver verifies that the MG sig was created correctly
@@ -307,7 +307,7 @@ namespace rct {
//proveRange and verRange
//proveRange gives C, and mask such that \sumCi = C
- // c.f. http://eprint.iacr.org/2015/1098 section 5.1
+ // c.f. https://eprint.iacr.org/2015/1098 section 5.1
// and Ci is a commitment to either 0 or 2^i, i=0,...,63
// thus this proves that "amount" is in [0, 2^64]
// mask is a such that C = aG + bH, and b = amount
@@ -339,7 +339,7 @@ namespace rct {
//proveRange and verRange
//proveRange gives C, and mask such that \sumCi = C
- // c.f. http://eprint.iacr.org/2015/1098 section 5.1
+ // c.f. https://eprint.iacr.org/2015/1098 section 5.1
// and Ci is a commitment to either 0 or 2^i, i=0,...,63
// thus this proves that "amount" is in [0, 2^64]
// mask is a such that C = aG + bH, and b = amount
@@ -441,7 +441,7 @@ namespace rct {
//Ring-ct MG sigs
//Prove:
- // c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10.
+ // c.f. https://eprint.iacr.org/2015/1098 section 4. definition 10.
// This does the MG sig on the "dest" part of the given key matrix, and
// the last row is the sum of input commitments from that column - sum output commitments
// this shows that sum inputs = sum outputs
@@ -527,7 +527,7 @@ namespace rct {
//Ring-ct MG sigs
//Prove:
- // c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10.
+ // c.f. https://eprint.iacr.org/2015/1098 section 4. definition 10.
// This does the MG sig on the "dest" part of the given key matrix, and
// the last row is the sum of input commitments from that column - sum output commitments
// this shows that sum inputs = sum outputs
@@ -650,7 +650,7 @@ namespace rct {
// Also contains masked "amount" and "mask" so the receiver can see how much they received
//verRct:
// verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct
- //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
+ //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1)
// uses the attached ecdh info to find the amounts represented by each output commitment
// must know the destination private key to find the correct amount, else will return a random number
// Note: For txn fees, the last index in the amounts vector should contain that
@@ -828,7 +828,7 @@ namespace rct {
// Also contains masked "amount" and "mask" so the receiver can see how much they received
//verRct:
// verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct
- //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
+ //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1)
// uses the attached ecdh info to find the amounts represented by each output commitment
// must know the destination private key to find the correct amount, else will return a random number
bool verRct(const rctSig & rv, bool semantics) {
@@ -1023,7 +1023,7 @@ namespace rct {
// Also contains masked "amount" and "mask" so the receiver can see how much they received
//verRct:
// verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct
- //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
+ //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1)
// uses the attached ecdh info to find the amounts represented by each output commitment
// must know the destination private key to find the correct amount, else will return a random number
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev) {
diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h
index b8aab0f11..5a9b2dd44 100644
--- a/src/ringct/rctSigs.h
+++ b/src/ringct/rctSigs.h
@@ -70,7 +70,7 @@ namespace rct {
//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
//These are aka MG signatutes in earlier drafts of the ring ct paper
- // c.f. http://eprint.iacr.org/2015/1098 section 2.
+ // c.f. https://eprint.iacr.org/2015/1098 section 2.
// Gen creates a signature which proves that for some column in the keymatrix "pk"
// the signer knows a secret key for each row in that column
// Ver verifies that the MG sig was created correctly
@@ -80,7 +80,7 @@ namespace rct {
//proveRange and verRange
//proveRange gives C, and mask such that \sumCi = C
- // c.f. http://eprint.iacr.org/2015/1098 section 5.1
+ // c.f. https://eprint.iacr.org/2015/1098 section 5.1
// and Ci is a commitment to either 0 or 2^i, i=0,...,63
// thus this proves that "amount" is in [0, 2^64]
// mask is a such that C = aG + bH, and b = amount
@@ -90,7 +90,7 @@ namespace rct {
//Ring-ct MG sigs
//Prove:
- // c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10.
+ // c.f. https://eprint.iacr.org/2015/1098 section 4. definition 10.
// This does the MG sig on the "dest" part of the given key matrix, and
// the last row is the sum of input commitments from that column - sum output commitments
// this shows that sum inputs = sum outputs
@@ -116,7 +116,7 @@ namespace rct {
// Also contains masked "amount" and "mask" so the receiver can see how much they received
//verRct:
// verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct
- //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
+ //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1)
// uses the attached ecdh info to find the amounts represented by each output commitment
// must know the destination private key to find the correct amount, else will return a random number
rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev);
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index eba1e3d93..844291d0c 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -150,7 +150,7 @@ namespace rct {
};
//just contains the necessary keys to represent MLSAG sigs
- //c.f. http://eprint.iacr.org/2015/1098
+ //c.f. https://eprint.iacr.org/2015/1098
struct mgSig {
keyM ss;
key cc;
diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt
index 7162317ed..4f8f96524 100644
--- a/src/rpc/CMakeLists.txt
+++ b/src/rpc/CMakeLists.txt
@@ -111,7 +111,6 @@ target_link_libraries(rpc
common
cryptonote_core
cryptonote_protocol
- epee
${Boost_REGEX_LIBRARY}
${Boost_THREAD_LIBRARY}
PRIVATE
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index b55b1994b..0a6daf8f0 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -47,7 +47,6 @@ using namespace epee;
#include "rpc/rpc_args.h"
#include "core_rpc_server_error_codes.h"
#include "p2p/net_node.h"
-#include "get_output_distribution_cache.h"
#include "version.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -194,6 +193,7 @@ namespace cryptonote
res.mainnet = m_nettype == MAINNET;
res.testnet = m_nettype == TESTNET;
res.stagenet = m_nettype == STAGENET;
+ res.nettype = m_nettype == MAINNET ? "mainnet" : m_nettype == TESTNET ? "testnet" : m_nettype == STAGENET ? "stagenet" : "fakechain";
res.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.height - 1);
res.block_size_limit = m_core.get_blockchain_storage().get_current_cumulative_blocksize_limit();
res.block_size_median = m_core.get_blockchain_storage().get_current_cumulative_blocksize_median();
@@ -207,6 +207,7 @@ namespace cryptonote
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
}
+ res.database_size = m_core.get_blockchain_storage().get_db().get_database_size();
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -982,11 +983,11 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin)
+ bool core_rpc_server::on_get_transaction_pool_hashes_bin(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_get_transaction_pool_hashes);
bool r;
- if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES>(invoke_http_mode::JON, "/get_transaction_pool_hashes.bin", req, res, r))
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN>(invoke_http_mode::JON, "/get_transaction_pool_hashes.bin", req, res, r))
return r;
m_core.get_pool_transaction_hashes(res.tx_hashes, !request_has_rpc_origin || !m_restricted);
@@ -994,6 +995,22 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin)
+ {
+ PERF_TIMER(on_get_transaction_pool_hashes);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES>(invoke_http_mode::JON, "/get_transaction_pool_hashes", req, res, r))
+ return r;
+
+ std::vector<crypto::hash> tx_hashes;
+ m_core.get_pool_transaction_hashes(tx_hashes, !request_has_rpc_origin || !m_restricted);
+ res.tx_hashes.reserve(tx_hashes.size());
+ for (const crypto::hash &tx_hash: tx_hashes)
+ res.tx_hashes.push_back(epee::string_tools::pod_to_hex(tx_hash));
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_get_transaction_pool_stats);
@@ -1210,6 +1227,68 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_generateblocks(const COMMAND_RPC_GENERATEBLOCKS::request& req, COMMAND_RPC_GENERATEBLOCKS::response& res, epee::json_rpc::error& error_resp)
+ {
+ PERF_TIMER(on_generateblocks);
+
+ CHECK_CORE_READY();
+
+ res.status = CORE_RPC_STATUS_OK;
+
+ if(m_core.get_nettype() != FAKECHAIN)
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_REGTEST_REQUIRED;
+ error_resp.message = "Regtest required when generating blocks";
+ return false;
+ }
+
+ COMMAND_RPC_GETBLOCKTEMPLATE::request template_req;
+ COMMAND_RPC_GETBLOCKTEMPLATE::response template_res;
+ COMMAND_RPC_SUBMITBLOCK::request submit_req;
+ COMMAND_RPC_SUBMITBLOCK::response submit_res;
+
+ template_req.reserve_size = 1;
+ template_req.wallet_address = req.wallet_address;
+ submit_req.push_back(boost::value_initialized<std::string>());
+ res.height = m_core.get_blockchain_storage().get_current_blockchain_height();
+
+ bool r;
+
+ for(size_t i = 0; i < req.amount_of_blocks; i++)
+ {
+ r = on_getblocktemplate(template_req, template_res, error_resp);
+ res.status = template_res.status;
+
+ if (!r) return false;
+
+ blobdata blockblob;
+ if(!string_tools::parse_hexstr_to_binbuff(template_res.blocktemplate_blob, blockblob))
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB;
+ error_resp.message = "Wrong block blob";
+ return false;
+ }
+ block b = AUTO_VAL_INIT(b);
+ if(!parse_and_validate_block_from_blob(blockblob, b))
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB;
+ error_resp.message = "Wrong block blob";
+ return false;
+ }
+ miner::find_nonce_for_given_block(b, template_res.difficulty, template_res.height);
+
+ submit_req.front() = string_tools::buff_to_hex_nodelimer(block_to_blob(b));
+ r = on_submitblock(submit_req, submit_res, error_resp);
+ res.status = submit_res.status;
+
+ if (!r) return false;
+
+ res.height = template_res.height;
+ }
+
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
uint64_t core_rpc_server::get_block_reward(const block& blk)
{
uint64_t reward = 0;
@@ -1565,6 +1644,7 @@ namespace cryptonote
res.mainnet = m_nettype == MAINNET;
res.testnet = m_nettype == TESTNET;
res.stagenet = m_nettype == STAGENET;
+ res.nettype = m_nettype == MAINNET ? "mainnet" : m_nettype == TESTNET ? "testnet" : m_nettype == STAGENET ? "stagenet" : "fakechain";
res.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.height - 1);
res.block_size_limit = m_core.get_blockchain_storage().get_current_cumulative_blocksize_limit();
res.block_size_median = m_core.get_blockchain_storage().get_current_cumulative_blocksize_median();
@@ -1578,6 +1658,7 @@ namespace cryptonote
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
}
+ res.database_size = m_core.get_blockchain_storage().get_db().get_database_size();
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -1775,10 +1856,22 @@ namespace cryptonote
PERF_TIMER(on_get_alternate_chains);
try
{
- std::list<std::pair<Blockchain::block_extended_info, uint64_t>> chains = m_core.get_blockchain_storage().get_alternative_chains();
+ std::list<std::pair<Blockchain::block_extended_info, std::vector<crypto::hash>>> chains = m_core.get_blockchain_storage().get_alternative_chains();
for (const auto &i: chains)
{
- res.chains.push_back(COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info{epee::string_tools::pod_to_hex(get_block_hash(i.first.bl)), i.first.height, i.second, i.first.cumulative_difficulty});
+ res.chains.push_back(COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info{epee::string_tools::pod_to_hex(get_block_hash(i.first.bl)), i.first.height, i.second.size(), i.first.cumulative_difficulty, {}, std::string()});
+ res.chains.back().block_hashes.reserve(i.second.size());
+ for (const crypto::hash &block_id: i.second)
+ res.chains.back().block_hashes.push_back(epee::string_tools::pod_to_hex(block_id));
+ if (i.first.height < i.second.size())
+ {
+ res.status = "Error finding alternate chain attachment point";
+ return true;
+ }
+ cryptonote::block main_chain_parent_block;
+ try { main_chain_parent_block = m_core.get_blockchain_storage().get_db().get_block_from_height(i.first.height - i.second.size()); }
+ catch (const std::exception &e) { res.status = "Error finding alternate chain attachment point"; return true; }
+ res.chains.back().main_chain_parent_block = epee::string_tools::pod_to_hex(get_block_hash(main_chain_parent_block));
}
res.status = CORE_RPC_STATUS_OK;
}
@@ -2071,6 +2164,10 @@ namespace cryptonote
bool core_rpc_server::on_get_output_distribution(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_output_distribution);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_DISTRIBUTION>(invoke_http_mode::JON_RPC, "get_output_distribution", req, res, r))
+ return r;
+
try
{
for (uint64_t amount: req.amounts)
@@ -2087,38 +2184,17 @@ namespace cryptonote
if (d.cached && amount == 0 && d.cached_from == req.from_height && d.cached_to == req.to_height)
{
- res.distributions.push_back({amount, d.cached_start_height, d.cached_distribution, d.cached_base});
- if (req.cumulative)
+ res.distributions.push_back({amount, d.cached_start_height, req.binary, d.cached_distribution, d.cached_base});
+ if (!req.cumulative)
{
auto &distribution = res.distributions.back().distribution;
- distribution[0] += d.cached_base;
- for (size_t n = 1; n < distribution.size(); ++n)
- distribution[n] += distribution[n-1];
+ for (size_t n = distribution.size() - 1; n > 0; --n)
+ distribution[n] -= distribution[n-1];
+ distribution[0] -= d.cached_base;
}
continue;
}
- // this is a slow operation, so we have precomputed caches of common cases
- bool found = false;
- for (const auto &slot: get_output_distribution_cache)
- {
- if (slot.amount == amount && slot.from_height == req.from_height && slot.to_height == req.to_height)
- {
- res.distributions.push_back({amount, slot.start_height, slot.distribution, slot.base});
- found = true;
- if (req.cumulative)
- {
- auto &distribution = res.distributions.back().distribution;
- distribution[0] += slot.base;
- for (size_t n = 1; n < distribution.size(); ++n)
- distribution[n] += distribution[n-1];
- }
- break;
- }
- }
- if (found)
- continue;
-
std::vector<uint64_t> distribution;
uint64_t start_height, base;
if (!m_core.get_output_distribution(amount, req.from_height, req.to_height, start_height, distribution, base))
@@ -2144,14 +2220,14 @@ namespace cryptonote
d.cached = true;
}
- if (req.cumulative)
+ if (!req.cumulative)
{
- distribution[0] += base;
- for (size_t n = 1; n < distribution.size(); ++n)
- distribution[n] += distribution[n-1];
+ for (size_t n = distribution.size() - 1; n > 0; --n)
+ distribution[n] -= distribution[n-1];
+ distribution[0] -= base;
}
- res.distributions.push_back({amount, start_height, std::move(distribution), base});
+ res.distributions.push_back({amount, start_height, req.binary, std::move(distribution), base});
}
}
catch (const std::exception &e)
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 324f219f8..166020d01 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -107,7 +107,8 @@ namespace cryptonote
MAP_URI_AUTO_JON2_IF("/set_log_level", on_set_log_level, COMMAND_RPC_SET_LOG_LEVEL, !m_restricted)
MAP_URI_AUTO_JON2_IF("/set_log_categories", on_set_log_categories, COMMAND_RPC_SET_LOG_CATEGORIES, !m_restricted)
MAP_URI_AUTO_JON2("/get_transaction_pool", on_get_transaction_pool, COMMAND_RPC_GET_TRANSACTION_POOL)
- MAP_URI_AUTO_JON2("/get_transaction_pool_hashes.bin", on_get_transaction_pool_hashes, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES)
+ MAP_URI_AUTO_JON2("/get_transaction_pool_hashes.bin", on_get_transaction_pool_hashes_bin, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN)
+ MAP_URI_AUTO_JON2("/get_transaction_pool_hashes", on_get_transaction_pool_hashes, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES)
MAP_URI_AUTO_JON2("/get_transaction_pool_stats", on_get_transaction_pool_stats, COMMAND_RPC_GET_TRANSACTION_POOL_STATS)
MAP_URI_AUTO_JON2_IF("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON, !m_restricted)
MAP_URI_AUTO_JON2("/get_info", on_get_info, COMMAND_RPC_GET_INFO)
@@ -129,6 +130,7 @@ namespace cryptonote
MAP_JON_RPC_WE("getblocktemplate", on_getblocktemplate, COMMAND_RPC_GETBLOCKTEMPLATE)
MAP_JON_RPC_WE("submit_block", on_submitblock, COMMAND_RPC_SUBMITBLOCK)
MAP_JON_RPC_WE("submitblock", on_submitblock, COMMAND_RPC_SUBMITBLOCK)
+ MAP_JON_RPC_WE_IF("generateblocks", on_generateblocks, COMMAND_RPC_GENERATEBLOCKS, !m_restricted)
MAP_JON_RPC_WE("get_last_block_header", on_get_last_block_header, COMMAND_RPC_GET_LAST_BLOCK_HEADER)
MAP_JON_RPC_WE("getlastblockheader", on_get_last_block_header, COMMAND_RPC_GET_LAST_BLOCK_HEADER)
MAP_JON_RPC_WE("get_block_header_by_hash", on_get_block_header_by_hash, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH)
@@ -180,6 +182,7 @@ namespace cryptonote
bool on_set_log_level(const COMMAND_RPC_SET_LOG_LEVEL::request& req, COMMAND_RPC_SET_LOG_LEVEL::response& res);
bool on_set_log_categories(const COMMAND_RPC_SET_LOG_CATEGORIES::request& req, COMMAND_RPC_SET_LOG_CATEGORIES::response& res);
bool on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, bool request_has_rpc_origin = true);
+ bool on_get_transaction_pool_hashes_bin(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::response& res, bool request_has_rpc_origin = true);
bool on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin = true);
bool on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, bool request_has_rpc_origin = true);
bool on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res);
@@ -196,6 +199,7 @@ namespace cryptonote
bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp);
bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp);
bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp);
+ bool on_generateblocks(const COMMAND_RPC_GENERATEBLOCKS::request& req, COMMAND_RPC_GENERATEBLOCKS::response& res, epee::json_rpc::error& error_resp);
bool on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp);
bool on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp);
bool on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp);
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 49b730149..e2d120cad 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -49,7 +49,7 @@ namespace cryptonote
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 1
-#define CORE_RPC_VERSION_MINOR 20
+#define CORE_RPC_VERSION_MINOR 21
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@@ -955,6 +955,7 @@ namespace cryptonote
bool mainnet;
bool testnet;
bool stagenet;
+ std::string nettype;
std::string top_block_hash;
uint64_t cumulative_difficulty;
uint64_t block_size_limit;
@@ -966,6 +967,7 @@ namespace cryptonote
std::string bootstrap_daemon_address;
uint64_t height_without_bootstrap;
bool was_bootstrap_ever_used;
+ uint64_t database_size;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
@@ -984,6 +986,7 @@ namespace cryptonote
KV_SERIALIZE(mainnet)
KV_SERIALIZE(testnet)
KV_SERIALIZE(stagenet)
+ KV_SERIALIZE(nettype)
KV_SERIALIZE(top_block_hash)
KV_SERIALIZE(cumulative_difficulty)
KV_SERIALIZE(block_size_limit)
@@ -995,6 +998,7 @@ namespace cryptonote
KV_SERIALIZE(bootstrap_daemon_address)
KV_SERIALIZE(height_without_bootstrap)
KV_SERIALIZE(was_bootstrap_ever_used)
+ KV_SERIALIZE(database_size)
END_KV_SERIALIZE_MAP()
};
};
@@ -1151,6 +1155,31 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
};
+
+ struct COMMAND_RPC_GENERATEBLOCKS
+ {
+ struct request
+ {
+ uint64_t amount_of_blocks;
+ std::string wallet_address;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(amount_of_blocks)
+ KV_SERIALIZE(wallet_address)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ uint64_t height;
+ std::string status;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(height)
+ KV_SERIALIZE(status)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
struct block_header_response
{
@@ -1489,7 +1518,7 @@ namespace cryptonote
};
};
- struct COMMAND_RPC_GET_TRANSACTION_POOL_HASHES
+ struct COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN
{
struct request
{
@@ -1511,6 +1540,28 @@ namespace cryptonote
};
};
+ struct COMMAND_RPC_GET_TRANSACTION_POOL_HASHES
+ {
+ struct request
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string status;
+ std::vector<std::string> tx_hashes;
+ bool untrusted;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ KV_SERIALIZE(tx_hashes)
+ KV_SERIALIZE(untrusted)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
struct tx_backlog_entry
{
uint64_t blob_size;
@@ -2090,12 +2141,16 @@ namespace cryptonote
uint64_t height;
uint64_t length;
uint64_t difficulty;
+ std::vector<std::string> block_hashes;
+ std::string main_chain_parent_block;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_hash)
KV_SERIALIZE(height)
KV_SERIALIZE(length)
KV_SERIALIZE(difficulty)
+ KV_SERIALIZE(block_hashes)
+ KV_SERIALIZE(main_chain_parent_block)
END_KV_SERIALIZE_MAP()
};
@@ -2231,12 +2286,14 @@ namespace cryptonote
uint64_t from_height;
uint64_t to_height;
bool cumulative;
+ bool binary;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amounts)
KV_SERIALIZE_OPT(from_height, (uint64_t)0)
KV_SERIALIZE_OPT(to_height, (uint64_t)0)
KV_SERIALIZE_OPT(cumulative, false)
+ KV_SERIALIZE_OPT(binary, true)
END_KV_SERIALIZE_MAP()
};
@@ -2244,13 +2301,18 @@ namespace cryptonote
{
uint64_t amount;
uint64_t start_height;
+ bool binary;
std::vector<uint64_t> distribution;
uint64_t base;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount)
KV_SERIALIZE(start_height)
- KV_SERIALIZE_CONTAINER_POD_AS_BLOB(distribution)
+ KV_SERIALIZE(binary)
+ if (this_ref.binary)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(distribution)
+ else
+ KV_SERIALIZE(distribution)
KV_SERIALIZE(base)
END_KV_SERIALIZE_MAP()
};
@@ -2259,10 +2321,12 @@ namespace cryptonote
{
std::string status;
std::vector<distribution> distributions;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(distributions)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
diff --git a/src/rpc/core_rpc_server_error_codes.h b/src/rpc/core_rpc_server_error_codes.h
index 69caaa6a6..5a754749f 100644
--- a/src/rpc/core_rpc_server_error_codes.h
+++ b/src/rpc/core_rpc_server_error_codes.h
@@ -42,5 +42,6 @@
#define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB_SIZE -10
#define CORE_RPC_ERROR_CODE_UNSUPPORTED_RPC -11
#define CORE_RPC_ERROR_CODE_MINING_TO_SUBADDRESS -12
+#define CORE_RPC_ERROR_CODE_REGTEST_REQUIRED -13
diff --git a/src/rpc/get_output_distribution_cache.h b/src/rpc/get_output_distribution_cache.h
deleted file mode 100644
index 6495e7d4c..000000000
--- a/src/rpc/get_output_distribution_cache.h
+++ /dev/null
@@ -1,113 +0,0 @@
-static const struct
-{
- uint64_t amount;
- uint64_t from_height;
- uint64_t to_height;
- uint64_t start_height;
- uint64_t base;
- std::vector<uint64_t> distribution;
-}
-get_output_distribution_cache[] =
-{
- {
- 0,
- 1544704,
- 1546001,
- 1544704,
- 5143500,
- {
- 5, 38, 37, 33, 39, 7, 1, 1, 5, 9, 7, 5, 17, 5, 3, 9, 3, 17, 5, 17, 1, 1, 15, 13, 3, 10, 5, 3, 34, 1, 45, 7,
- 5, 17, 5, 22, 3, 1, 17, 16, 5, 1, 3, 43, 5, 13, 3, 23, 9, 7, 9, 13, 1, 11, 1, 17, 1, 3, 16, 11, 5, 11, 7, 7,
- 33, 11, 7, 1, 5, 1, 21, 19, 1, 17, 1, 49, 17, 3, 3, 9, 35, 46, 46, 39, 26, 33, 21, 3, 23, 3, 9, 37, 1, 33, 11, 32,
- 1, 13, 16, 12, 3, 21, 1, 18, 3, 19, 1, 25, 5, 3, 18, 7, 17, 5, 9, 15, 7, 7, 11, 9, 9, 17, 5, 16, 1, 3, 13, 3,
- 5, 5, 5, 13, 5, 9, 5, 13, 3, 17, 15, 36, 13, 3, 20, 12, 6, 23, 17, 10, 22, 23, 1, 7, 21, 6, 23, 1, 3, 19, 13, 1,
- 3, 43, 35, 13, 1, 31, 7, 3, 17, 1, 15, 5, 11, 15, 24, 1, 18, 13, 5, 15, 1, 29, 3, 3, 13, 3, 15, 7, 17, 3, 1, 1,
- 17, 1, 1, 45, 39, 27, 45, 46, 34, 7, 3, 3, 9, 3, 3, 11, 7, 5, 9, 25, 19, 3, 33, 1, 5, 17, 1, 45, 4, 1, 45, 11,
- 44, 32, 3, 1, 3, 7, 17, 15, 5, 45, 35, 41, 1, 35, 3, 3, 19, 1, 9, 17, 29, 29, 3, 1, 13, 1, 3, 47, 21, 13, 7, 1,
- 7, 5, 1, 11, 1, 40, 9, 7, 3, 3, 13, 25, 1, 47, 5, 7, 3, 7, 31, 40, 34, 6, 3, 15, 3, 31, 5, 13, 27, 9, 12, 21,
- 3, 1, 19, 1, 19, 5, 47, 49, 47, 42, 50, 34, 29, 23, 1, 5, 9, 16, 11, 7, 1, 19, 7, 5, 1, 15, 1, 1, 9, 13, 9, 5,
- 27, 3, 3, 29, 1, 33, 3, 9, 5, 35, 5, 1, 17, 7, 3, 39, 3, 28, 19, 1, 1, 9, 1, 3, 27, 1, 37, 3, 1, 1, 16, 3,
- 25, 11, 5, 3, 33, 45, 17, 11, 7, 22, 9, 1, 5, 5, 5, 15, 1, 15, 9, 7, 11, 13, 37, 49, 46, 38, 11, 1, 25, 1, 13, 18,
- 3, 7, 39, 3, 37, 19, 35, 3, 1, 3, 19, 1, 3, 15, 21, 3, 27, 1, 45, 48, 1, 13, 29, 9, 1, 1, 46, 43, 5, 15, 3, 7,
- 29, 26, 5, 5, 21, 37, 17, 21, 3, 13, 1, 5, 1, 17, 5, 31, 13, 1, 11, 3, 46, 9, 3, 7, 1, 1, 41, 1, 21, 1, 5, 12,
- 7, 13, 9, 25, 1, 47, 47, 48, 48, 48, 48, 48, 47, 48, 45, 45, 33, 52, 50, 46, 45, 47, 35, 41, 38, 35, 42, 38, 34, 41, 39, 35,
- 51, 51, 45, 43, 49, 52, 53, 45, 42, 46, 37, 53, 49, 41, 46, 49, 46, 47, 48, 37, 41, 33, 43, 38, 15, 3, 3, 27, 11, 5, 23, 13,
- 1, 1, 37, 3, 15, 3, 30, 13, 3, 45, 12, 3, 5, 11, 1, 1, 21, 9, 11, 19, 1, 1, 1, 25, 5, 21, 3, 1, 32, 44, 3, 33,
- 11, 7, 5, 23, 1, 37, 47, 48, 48, 48, 48, 48, 48, 46, 47, 47, 50, 45, 49, 50, 46, 47, 49, 45, 51, 49, 50, 49, 49, 46, 47, 48,
- 46, 48, 46, 50, 46, 43, 46, 46, 48, 47, 46, 47, 45, 49, 46, 43, 50, 45, 45, 49, 45, 48, 45, 49, 48, 45, 45, 51, 45, 51, 45, 46,
- 52, 45, 45, 51, 51, 52, 44, 45, 52, 50, 50, 46, 47, 51, 51, 46, 47, 47, 47, 50, 47, 51, 48, 49, 51, 50, 48, 48, 48, 50, 49, 49,
- 52, 52, 49, 50, 49, 49, 49, 51, 52, 49, 52, 50, 49, 47, 29, 15, 39, 17, 31, 5, 40, 5, 18, 23, 25, 7, 35, 26, 5, 31, 49, 22,
- 3, 17, 7, 49, 7, 49, 47, 12, 44, 46, 36, 15, 3, 1, 47, 13, 35, 40, 5, 21, 19, 39, 21, 33, 31, 29, 1, 1, 37, 1, 15, 47,
- 7, 7, 47, 41, 13, 3, 47, 31, 9, 33, 13, 43, 29, 5, 1, 9, 33, 7, 27, 15, 15, 25, 5, 43, 22, 31, 7, 1, 47, 1, 15, 27,
- 3, 27, 45, 15, 1, 36, 17, 1, 23, 39, 38, 45, 7, 7, 19, 7, 11, 47, 33, 16, 3, 45, 45, 45, 9, 27, 3, 3, 21, 3, 7, 21,
- 7, 3, 43, 1, 17, 1, 45, 37, 46, 5, 5, 13, 46, 40, 48, 48, 45, 34, 1, 46, 19, 25, 9, 7, 47, 23, 37, 31, 3, 25, 13, 46,
- 31, 25, 5, 46, 35, 52, 11, 23, 27, 4, 15, 11, 11, 11, 9, 34, 7, 9, 15, 34, 9, 27, 37, 28, 25, 45, 13, 30, 5, 25, 15, 7,
- 3, 19, 27, 1, 7, 11, 1, 32, 3, 45, 11, 9, 21, 25, 9, 13, 13, 1, 7, 1, 33, 11, 5, 3, 3, 27, 27, 5, 3, 37, 17, 17,
- 3, 7, 5, 13, 1, 3, 44, 45, 26, 25, 1, 13, 3, 13, 3, 11, 1, 11, 7, 45, 3, 3, 1, 43, 1, 19, 3, 1, 15, 5, 39, 7,
- 7, 1, 9, 1, 11, 19, 3, 35, 29, 7, 15, 11, 40, 7, 44, 38, 34, 7, 9, 7, 1, 27, 1, 9, 5, 45, 1, 21, 3, 1, 5, 9,
- 3, 21, 23, 33, 3, 1, 7, 3, 3, 7, 41, 9, 7, 1, 5, 31, 9, 7, 1, 1, 11, 41, 51, 20, 9, 47, 39, 17, 9, 35, 1, 41,
- 1, 19, 1, 19, 15, 1, 13, 5, 23, 15, 9, 15, 17, 1, 15, 27, 33, 31, 29, 7, 13, 1, 5, 45, 5, 1, 1, 11, 1, 13, 3, 7,
- 9, 1, 13, 39, 3, 33, 5, 3, 7, 7, 5, 29, 11, 1, 7, 1, 15, 3, 13, 3, 15, 3, 3, 1, 5, 1, 9, 1, 44, 49, 24, 25,
- 1, 1, 34, 22, 7, 5, 5, 5, 10, 9, 13, 3, 9, 1, 9, 19, 7, 43, 48, 7, 11, 7, 3, 3, 7, 21, 1, 1, 3, 3, 11, 31,
- 1, 1, 13, 22, 23, 7, 27, 9, 3, 3, 21, 1, 35, 21, 9, 11, 13, 39, 1, 3, 7, 23, 3, 28, 3, 45, 47, 38, 32, 37, 34, 1,
- 23, 3, 3, 1, 19, 19, 1, 5, 13, 1, 5, 11, 38, 3, 1, 36, 13, 1, 1, 23, 5, 17, 11, 1, 13, 1, 3, 7, 11, 3, 33, 7,
- 19, 5, 5, 1, 1, 3, 5, 41, 1, 3, 25, 1, 7, 7, 9, 3, 11, 3, 13, 5, 7, 1, 3, 9, 1, 1, 43, 47, 47, 47, 17, 7,
- 17, 3, 19, 1, 9, 9, 33, 22, 1, 25, 1, 3, 3, 32, 5, 1, 23, 9, 5, 1, 31, 5, 9, 1, 3, 7, 19, 1, 12, 11, 5, 1,
- 1, 9, 25, 15, 15, 13, 5, 3, 15, 1, 17, 1, 1, 5, 5, 41, 11, 15, 7, 3, 21, 21, 35, 22, 46, 35, 3, 27, 5, 3, 45, 22,
- 27, 1, 19, 9, 1, 25, 1, 29, 3, 5, 25, 17, 27, 5, 19, 5, 25, 7, 19, 1, 9, 21, 3, 7, 29, 27, 17, 3, 3, 15, 7, 19,
- 5, 25, 1, 23, 45, 4, 31, 1, 37, 14, 29, 3, 29, 1, 23, 29, 19, 11, 1, 13, 13, 9, 1, 25, 1, 33, 1, 37, 37, 23, 7, 21,
- 7, 3, 13, 7, 3, 7, 21, 11, 9, 1, 31, 3, 1, 7, 39, 46, 3, 30,
- },
- },
- {
- 0,
- 1562704,
- 1564001,
- 1562704,
- 5521986,
- {
- 35, 45, 23, 3, 44, 47, 44, 3, 17, 35, 7, 11, 7, 29, 43, 27, 11, 7, 5, 31, 13, 9, 45, 45, 7, 42, 17, 15, 19, 11, 45, 19,
- 45, 46, 45, 46, 32, 34, 43, 34, 46, 47, 45, 30, 17, 45, 46, 36, 35, 38, 19, 9, 23, 17, 3, 19, 31, 41, 35, 24, 15, 45, 15, 5,
- 11, 5, 19, 11, 11, 7, 15, 19, 45, 34, 7, 7, 29, 1, 9, 36, 7, 44, 45, 33, 25, 8, 17, 7, 44, 43, 48, 45, 42, 46, 40, 44,
- 1, 43, 45, 46, 46, 35, 19, 19, 23, 5, 13, 19, 7, 16, 9, 3, 25, 34, 3, 27, 9, 39, 3, 43, 21, 1, 45, 45, 39, 25, 23, 13,
- 39, 39, 3, 45, 43, 46, 44, 40, 39, 33, 45, 47, 38, 45, 45, 39, 47, 47, 45, 46, 35, 45, 43, 47, 45, 40, 34, 42, 42, 48, 49, 47,
- 47, 48, 47, 45, 43, 48, 37, 48, 41, 45, 48, 34, 42, 44, 9, 19, 27, 1, 47, 47, 43, 25, 29, 5, 5, 21, 39, 35, 43, 37, 13, 45,
- 25, 31, 26, 47, 45, 23, 23, 39, 32, 25, 44, 47, 35, 47, 15, 17, 7, 9, 5, 35, 31, 3, 45, 47, 46, 13, 17, 48, 45, 9, 13, 45,
- 45, 31, 1, 53, 44, 46, 39, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 47, 47, 47, 47, 47, 47, 47, 47, 53, 49, 45, 45, 50,
- 50, 27, 43, 46, 47, 46, 45, 48, 36, 42, 42, 46, 45, 47, 41, 45, 43, 47, 38, 48, 47, 33, 11, 45, 46, 34, 42, 32, 3, 45, 37, 45,
- 15, 3, 45, 29, 31, 9, 5, 3, 27, 5, 21, 25, 7, 15, 46, 34, 5, 3, 17, 3, 9, 13, 7, 11, 3, 1, 34, 13, 7, 45, 33, 26,
- 9, 5, 9, 41, 43, 34, 3, 35, 3, 17, 37, 11, 17, 3, 15, 27, 15, 45, 46, 13, 26, 16, 11, 7, 5, 45, 38, 45, 45, 22, 44, 44,
- 43, 6, 11, 35, 15, 44, 17, 27, 13, 3, 40, 5, 9, 7, 35, 19, 5, 5, 1, 28, 33, 15, 45, 5, 29, 3, 31, 12, 5, 32, 24, 3,
- 23, 13, 47, 45, 42, 46, 39, 21, 21, 1, 44, 44, 47, 41, 5, 1, 11, 36, 20, 5, 45, 39, 45, 45, 44, 45, 32, 22, 40, 11, 38, 1,
- 45, 46, 37, 9, 23, 9, 15, 44, 7, 16, 38, 46, 11, 14, 24, 19, 19, 7, 26, 25, 45, 37, 17, 1, 35, 1, 3, 28, 3, 11, 22, 13,
- 3, 1, 7, 38, 5, 3, 1, 26, 1, 3, 43, 44, 46, 45, 21, 11, 1, 44, 27, 1, 11, 26, 10, 44, 45, 45, 45, 47, 47, 45, 48, 45,
- 38, 9, 5, 44, 46, 27, 3, 12, 1, 11, 3, 44, 43, 1, 5, 2, 46, 17, 13, 19, 1, 12, 7, 23, 1, 17, 6, 13, 3, 5, 27, 7,
- 46, 36, 19, 25, 1, 1, 3, 8, 15, 3, 45, 45, 45, 37, 6, 15, 3, 5, 38, 14, 41, 1, 13, 45, 45, 39, 44, 29, 43, 48, 51, 50,
- 37, 5, 17, 46, 47, 31, 5, 42, 49, 38, 39, 24, 7, 11, 44, 35, 21, 6, 15, 5, 47, 13, 28, 45, 34, 27, 24, 15, 35, 13, 7, 25,
- 43, 13, 14, 5, 3, 5, 46, 45, 45, 35, 5, 21, 28, 3, 13, 4, 30, 19, 45, 45, 40, 37, 5, 40, 17, 9, 3, 9, 13, 4, 17, 33,
- 44, 39, 17, 45, 28, 5, 11, 45, 19, 45, 21, 44, 31, 43, 49, 48, 15, 3, 1, 44, 45, 43, 11, 1, 1, 27, 43, 45, 39, 3, 1, 3,
- 5, 31, 1, 43, 23, 19, 7, 5, 45, 31, 11, 7, 3, 9, 5, 7, 13, 43, 47, 45, 46, 47, 14, 3, 25, 45, 7, 17, 32, 21, 3, 17,
- 5, 11, 31, 40, 45, 20, 45, 45, 32, 38, 47, 38, 45, 41, 49, 30, 45, 5, 36, 31, 22, 3, 46, 45, 13, 21, 23, 5, 46, 45, 33, 19,
- 25, 1, 7, 13, 5, 44, 23, 29, 23, 24, 7, 5, 37, 13, 29, 13, 7, 17, 7, 43, 3, 21, 7, 44, 1, 19, 15, 9, 34, 43, 26, 3,
- 17, 5, 6, 5, 7, 3, 33, 35, 43, 41, 48, 47, 30, 45, 19, 7, 5, 33, 11, 34, 25, 1, 21, 11, 29, 7, 1, 4, 5, 10, 14, 3,
- 44, 11, 47, 45, 33, 3, 9, 7, 40, 23, 9, 1, 3, 1, 7, 5, 9, 9, 6, 11, 45, 41, 45, 19, 5, 11, 10, 39, 9, 19, 3, 11,
- 43, 42, 1, 13, 35, 5, 32, 7, 5, 5, 43, 37, 3, 32, 17, 3, 23, 1, 13, 45, 17, 1, 21, 45, 43, 46, 49, 47, 45, 30, 9, 31,
- 19, 42, 19, 44, 17, 14, 19, 25, 1, 7, 5, 45, 19, 13, 7, 3, 1, 1, 9, 21, 37, 9, 11, 1, 3, 37, 27, 13, 5, 21, 33, 3,
- 27, 9, 27, 1, 39, 1, 46, 21, 10, 13, 21, 40, 22, 35, 41, 9, 33, 3, 17, 8, 45, 46, 42, 46, 47, 47, 47, 48, 48, 47, 43, 48,
- 37, 39, 50, 35, 3, 40, 45, 40, 46, 36, 34, 28, 9, 9, 37, 9, 5, 7, 13, 31, 1, 7, 3, 3, 44, 45, 25, 15, 1, 21, 43, 25,
- 1, 38, 34, 42, 31, 23, 33, 35, 37, 20, 7, 15, 3, 7, 7, 27, 45, 45, 48, 47, 45, 44, 47, 23, 25, 36, 11, 3, 18, 24, 27, 13,
- 41, 13, 5, 5, 7, 19, 15, 7, 5, 14, 45, 45, 37, 1, 5, 17, 21, 41, 17, 37, 53, 41, 45, 45, 45, 45, 45, 45, 45, 45, 43, 47,
- 47, 48, 53, 47, 47, 47, 49, 27, 45, 47, 47, 47, 47, 45, 45, 45, 47, 43, 48, 34, 34, 43, 46, 15, 37, 21, 5, 27, 11, 1, 9, 7,
- 19, 15, 1, 1, 19, 3, 36, 27, 29, 13, 21, 9, 17, 5, 16, 45, 23, 34, 3, 1, 7, 25, 28, 13, 29, 15, 11, 19, 17, 1, 27, 23,
- 31, 19, 41, 41, 40, 47, 28, 31, 26, 26, 36, 17, 5, 1, 23, 1, 45, 34, 49, 51, 34, 43, 37, 5, 41, 15, 5, 21, 1, 7, 9, 19,
- 5, 11, 39, 19, 45, 45, 38, 17, 9, 1, 15, 11, 5, 13, 47, 46, 48, 45, 19, 32, 7, 19, 5, 7, 23, 29, 5, 45, 41, 37, 1, 5,
- 27, 5, 5, 7, 19, 9, 1, 35, 48, 38, 38, 39, 42, 43, 21, 23, 43, 41, 7, 3, 7, 13, 1, 46, 47, 46, 23, 46, 45, 25, 7, 9,
- 21, 7, 41, 13, 20, 1, 21, 15, 37, 5, 40, 45, 45, 5, 45, 46, 15, 33, 46, 12, 13, 7, 24, 7, 5, 30, 7, 46, 13, 8, 44, 35,
- 45, 33, 40, 36, 47, 47, 29, 43, 36, 43, 45, 42, 36, 19, 7, 7, 43, 3, 44, 25, 48, 29, 11, 45, 30, 1, 17, 13, 25, 1, 48, 45,
- 45, 45, 44, 49, 37, 9, 21, 17, 15, 7, 15, 25, 1, 1, 9, 43, 33, 11, 3, 29, 45, 45, 9, 7, 7, 27, 47, 45, 47, 48, 45, 47,
- 26, 1, 43, 15, 45, 17, 1, 5, 35, 31, 9, 3, 9, 19, 9, 21, 43, 5, 27, 1, 5, 9, 4, 34, 19, 3, 7, 11, 45, 46, 45, 45,
- 46, 47, 47, 44, 45, 43, 27, 9, 17, 15, 19, 44, 45, 46, 47, 47, 45, 45,
- }
- }
-};
-
diff --git a/src/rpc/message_data_structs.h b/src/rpc/message_data_structs.h
index 17ae9629f..fc1b2329d 100644
--- a/src/rpc/message_data_structs.h
+++ b/src/rpc/message_data_structs.h
@@ -181,6 +181,7 @@ namespace rpc
bool mainnet;
bool testnet;
bool stagenet;
+ std::string nettype;
crypto::hash top_block_hash;
uint64_t cumulative_difficulty;
uint64_t block_size_limit;
diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp
index a7fb58ee4..c2467b863 100644
--- a/src/serialization/json_object.cpp
+++ b/src/serialization/json_object.cpp
@@ -1175,6 +1175,7 @@ void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::DaemonInfo& in
INSERT_INTO_JSON_OBJECT(val, doc, white_peerlist_size, info.white_peerlist_size);
INSERT_INTO_JSON_OBJECT(val, doc, grey_peerlist_size, info.grey_peerlist_size);
INSERT_INTO_JSON_OBJECT(val, doc, testnet, info.testnet);
+ INSERT_INTO_JSON_OBJECT(val, doc, nettype, info.nettype);
INSERT_INTO_JSON_OBJECT(val, doc, top_block_hash, info.top_block_hash);
INSERT_INTO_JSON_OBJECT(val, doc, cumulative_difficulty, info.cumulative_difficulty);
INSERT_INTO_JSON_OBJECT(val, doc, block_size_limit, info.block_size_limit);
@@ -1200,6 +1201,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf
GET_FROM_JSON_OBJECT(val, info.white_peerlist_size, white_peerlist_size);
GET_FROM_JSON_OBJECT(val, info.grey_peerlist_size, grey_peerlist_size);
GET_FROM_JSON_OBJECT(val, info.testnet, testnet);
+ GET_FROM_JSON_OBJECT(val, info.nettype, nettype);
GET_FROM_JSON_OBJECT(val, info.top_block_hash, top_block_hash);
GET_FROM_JSON_OBJECT(val, info.cumulative_difficulty, cumulative_difficulty);
GET_FROM_JSON_OBJECT(val, info.block_size_limit, block_size_limit);
diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt
index 8bb295931..c31cdebde 100644
--- a/src/simplewallet/CMakeLists.txt
+++ b/src/simplewallet/CMakeLists.txt
@@ -48,7 +48,6 @@ target_link_libraries(simplewallet
cncrypto
common
mnemonics
- epee
${EPEE_READLINE}
version
${Boost_CHRONO_LIBRARY}
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 16866a80d..6a6f98a20 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -1423,7 +1423,6 @@ bool simple_wallet::set_ring(const std::vector<std::string> &args)
}
ring.push_back(offset);
ptr += read;
- MGINFO("read offset: " << offset);
}
if (!valid)
continue;
@@ -2092,6 +2091,19 @@ bool simple_wallet::set_segregation_height(const std::vector<std::string> &args/
return true;
}
+bool simple_wallet::set_ignore_fractional_outputs(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ const auto pwd_container = get_and_verify_password();
+ if (pwd_container)
+ {
+ parse_bool_and_use(args[1], [&](bool r) {
+ m_wallet->ignore_fractional_outputs(r);
+ m_wallet->rewrite(m_wallet_file, pwd_container->password());
+ });
+ }
+ return true;
+}
+
bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
if(args.empty())
@@ -2157,6 +2169,10 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::locked_transfer, this, _1),
tr("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <addr> <amount> <lockblocks> [<payment_id>]"),
tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
+ m_cmd_binder.set_handler("locked_sweep_all",
+ boost::bind(&simple_wallet::locked_sweep_all, this, _1),
+ tr("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id>]"),
+ tr("Send all unlocked balance to an address and lock it for <lockblocks> (max. 1000000). If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used. <priority> is the priority of the sweep. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability."));
m_cmd_binder.set_handler("sweep_unmixable",
boost::bind(&simple_wallet::sweep_unmixable, this, _1),
tr("Send all unmixable outputs to yourself with ring_size 1"));
@@ -2479,6 +2495,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
const std::pair<size_t, size_t> lookahead = m_wallet->get_subaddress_lookahead();
success_msg_writer() << "subaddress-lookahead = " << lookahead.first << ":" << lookahead.second;
success_msg_writer() << "segregation-height = " << m_wallet->segregation_height();
+ success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs();
return true;
}
else
@@ -2533,6 +2550,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("key-reuse-mitigation2", set_key_reuse_mitigation2, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("subaddress-lookahead", set_subaddress_lookahead, tr("<major>:<minor>"));
CHECK_SIMPLE_VARIABLE("segregation-height", set_segregation_height, tr("unsigned integer"));
+ CHECK_SIMPLE_VARIABLE("ignore-fractional-outputs", set_ignore_fractional_outputs, tr("0 or 1"));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
return true;
@@ -4278,12 +4296,7 @@ uint64_t simple_wallet::get_daemon_blockchain_height(std::string& err)
{
throw std::runtime_error("simple_wallet null wallet");
}
-
- COMMAND_RPC_GET_HEIGHT::request req;
- COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized<COMMAND_RPC_GET_HEIGHT::response>();
- bool r = m_wallet->invoke_http_json("/getheight", req, res);
- err = interpret_rpc_response(r, res.status);
- return res.height;
+ return m_wallet->get_daemon_blockchain_height(err);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
@@ -4861,6 +4874,11 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
return transfer_main(TransferLocked, args_);
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::locked_sweep_all(const std::vector<std::string> &args_)
+{
+ return sweep_main(0, true, args_);
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
{
@@ -4968,12 +4986,16 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
return true;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &args_)
+bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<std::string> &args_)
{
- // sweep_all [index=<N1>[,<N2>,...]] [<ring_size>] <address> [<payment_id>]
+ auto print_usage = [below]()
+ {
+ fail_msg_writer() << boost::format(tr("usage: %s [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]")) % (below ? "sweep_below" : "sweep_all");
+ };
if (args_.size() == 0)
{
fail_msg_writer() << tr("No address given");
+ print_usage();
return true;
}
@@ -4987,7 +5009,10 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
if (local_args.size() > 0 && local_args[0].substr(0, 6) == "index=")
{
if (!parse_subaddress_indices(local_args[0], subaddr_indices))
+ {
+ print_usage();
return true;
+ }
local_args.erase(local_args.begin());
}
@@ -5024,9 +5049,44 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
return true;
}
+ uint64_t unlock_block = 0;
+ if (locked) {
+ uint64_t locked_blocks = 0;
+
+ if (local_args.size() < 2) {
+ fail_msg_writer() << tr("missing lockedblocks parameter");
+ return true;
+ }
+
+ try
+ {
+ locked_blocks = boost::lexical_cast<uint64_t>(local_args[1]);
+ }
+ catch (const std::exception &e)
+ {
+ fail_msg_writer() << tr("bad locked_blocks parameter");
+ return true;
+ }
+ if (locked_blocks > 1000000)
+ {
+ fail_msg_writer() << tr("Locked blocks too high, max 1000000 (˜4 yrs)");
+ return true;
+ }
+ std::string err;
+ uint64_t bc_height = get_daemon_blockchain_height(err);
+ if (!err.empty())
+ {
+ fail_msg_writer() << tr("failed to get blockchain height: ") << err;
+ return true;
+ }
+ unlock_block = bc_height + locked_blocks;
+
+ local_args.erase(local_args.begin() + 1);
+ }
+
std::vector<uint8_t> extra;
bool payment_id_seen = false;
- if (2 >= local_args.size())
+ if (local_args.size() >= 2)
{
std::string payment_id_str = local_args.back();
@@ -5055,6 +5115,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
if(!r && local_args.size() == 3)
{
fail_msg_writer() << tr("payment id has invalid format, expected 16 or 64 character hex string: ") << payment_id_str;
+ print_usage();
return true;
}
if (payment_id_seen)
@@ -5065,6 +5126,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[0], oa_prompter))
{
fail_msg_writer() << tr("failed to parse address");
+ print_usage();
return true;
}
@@ -5106,7 +5168,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
try
{
// figure out what tx will be necessary
- auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
+ auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
if (ptx_vector.empty())
{
@@ -5402,7 +5464,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_all(const std::vector<std::string> &args_)
{
- return sweep_main(0, args_);
+ return sweep_main(0, false, args_);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
@@ -5418,7 +5480,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
fail_msg_writer() << tr("invalid amount threshold");
return true;
}
- return sweep_main(below, std::vector<std::string>(++args_.begin(), args_.end()));
+ return sweep_main(below, false, std::vector<std::string>(++args_.begin(), args_.end()));
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::donate(const std::vector<std::string> &args_)
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 7a788d432..b8f7bb84b 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -137,6 +137,7 @@ namespace cryptonote
bool set_key_reuse_mitigation2(const std::vector<std::string> &args = std::vector<std::string>());
bool set_subaddress_lookahead(const std::vector<std::string> &args = std::vector<std::string>());
bool set_segregation_height(const std::vector<std::string> &args = std::vector<std::string>());
+ bool set_ignore_fractional_outputs(const std::vector<std::string> &args = std::vector<std::string>());
bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool start_mining(const std::vector<std::string> &args);
bool stop_mining(const std::vector<std::string> &args);
@@ -152,7 +153,8 @@ namespace cryptonote
bool transfer(const std::vector<std::string> &args);
bool transfer_new(const std::vector<std::string> &args);
bool locked_transfer(const std::vector<std::string> &args);
- bool sweep_main(uint64_t below, const std::vector<std::string> &args);
+ bool locked_sweep_all(const std::vector<std::string> &args);
+ bool sweep_main(uint64_t below, bool locked, const std::vector<std::string> &args);
bool sweep_all(const std::vector<std::string> &args);
bool sweep_below(const std::vector<std::string> &args);
bool sweep_single(const std::vector<std::string> &args);
diff --git a/src/version.cpp.in b/src/version.cpp.in
index a03da7889..55ba51f50 100644
--- a/src/version.cpp.in
+++ b/src/version.cpp.in
@@ -1,5 +1,5 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
-#define DEF_MONERO_VERSION "0.12.2.0-master"
+#define DEF_MONERO_VERSION "0.12.3.0-master"
#define DEF_MONERO_RELEASE_NAME "Lithium Luna"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index a5a4c7f56..a16f4fe19 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -85,7 +85,6 @@ monero_add_executable(wallet_rpc_server
target_link_libraries(wallet_rpc_server
PRIVATE
wallet
- epee
rpc_base
cryptonote_core
cncrypto
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 3f6bfec9e..680da26ce 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -2205,6 +2205,20 @@ void WalletImpl::keyReuseMitigation2(bool mitigation)
m_wallet->key_reuse_mitigation2(mitigation);
}
+bool WalletImpl::lockKeysFile()
+{
+ return m_wallet->lock_keys_file();
+}
+
+bool WalletImpl::unlockKeysFile()
+{
+ return m_wallet->unlock_keys_file();
+}
+
+bool WalletImpl::isKeysFileLocked()
+{
+ return m_wallet->is_keys_file_locked();
+}
} // namespace
namespace Bitmonero = Monero;
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index eefb2fe94..58be686fc 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -188,6 +188,9 @@ public:
virtual void segregatePreForkOutputs(bool segregate) override;
virtual void segregationHeight(uint64_t height) override;
virtual void keyReuseMitigation2(bool mitigation) override;
+ virtual bool lockKeysFile() override;
+ virtual bool unlockKeysFile() override;
+ virtual bool isKeysFileLocked() override;
private:
void clearStatus() const;
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index f54255e91..0cd0ff5cf 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -900,6 +900,12 @@ struct Wallet
//! Initiates a light wallet import wallet request
virtual bool lightWalletImportWalletRequest(std::string &payment_id, uint64_t &fee, bool &new_request, bool &request_fulfilled, std::string &payment_address, std::string &status) = 0;
+
+ //! locks/unlocks the keys file; returns true on success
+ virtual bool lockKeysFile() = 0;
+ virtual bool unlockKeysFile() = 0;
+ //! returns true if the keys file is locked
+ virtual bool isKeysFileLocked() = 0;
};
/**
@@ -1070,6 +1076,10 @@ struct WalletManager
* @param password - password to verify
* @param no_spend_key - verify only view keys?
* @return - true if password is correct
+ *
+ * @note
+ * This function will fail when the wallet keys file is opened because the wallet program locks the keys file.
+ * In this case, Wallet::unlockKeysFile() and Wallet::lockKeysFile() need to be called before and after the call to this function, respectively.
*/
virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const = 0;
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp
index c5d869354..401ada61b 100644
--- a/src/wallet/node_rpc_proxy.cpp
+++ b/src/wallet/node_rpc_proxy.cpp
@@ -41,21 +41,13 @@ static const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::c
NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::mutex &mutex)
: m_http_client(http_client)
, m_daemon_rpc_mutex(mutex)
- , m_height(0)
- , m_height_time(0)
- , m_earliest_height()
- , m_dynamic_per_kb_fee_estimate(0)
- , m_dynamic_per_kb_fee_estimate_cached_height(0)
- , m_dynamic_per_kb_fee_estimate_grace_blocks(0)
- , m_rpc_version(0)
- , m_target_height(0)
- , m_target_height_time(0)
-{}
+{
+ invalidate();
+}
void NodeRPCProxy::invalidate()
{
m_height = 0;
- m_height_time = 0;
for (size_t n = 0; n < 256; ++n)
m_earliest_height[n] = 0;
m_dynamic_per_kb_fee_estimate = 0;
@@ -63,7 +55,8 @@ void NodeRPCProxy::invalidate()
m_dynamic_per_kb_fee_estimate_grace_blocks = 0;
m_rpc_version = 0;
m_target_height = 0;
- m_target_height_time = 0;
+ m_block_size_limit = 0;
+ m_get_info_time = 0;
}
boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version) const
@@ -84,36 +77,15 @@ boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version
return boost::optional<std::string>();
}
-boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height) const
-{
- const time_t now = time(NULL);
- if (m_height == 0 || now >= m_height_time + 30) // re-cache every 30 seconds
- {
- cryptonote::COMMAND_RPC_GET_HEIGHT::request req = AUTO_VAL_INIT(req);
- cryptonote::COMMAND_RPC_GET_HEIGHT::response res = AUTO_VAL_INIT(res);
-
- m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_json("/getheight", req, res, m_http_client, rpc_timeout);
- m_daemon_rpc_mutex.unlock();
- CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon");
- CHECK_AND_ASSERT_MES(res.status != CORE_RPC_STATUS_BUSY, res.status, "Failed to connect to daemon");
- CHECK_AND_ASSERT_MES(res.status == CORE_RPC_STATUS_OK, res.status, "Failed to get current blockchain height");
- m_height = res.height;
- m_height_time = now;
- }
- height = m_height;
- return boost::optional<std::string>();
-}
-
void NodeRPCProxy::set_height(uint64_t h)
{
m_height = h;
}
-boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) const
+boost::optional<std::string> NodeRPCProxy::get_info() const
{
const time_t now = time(NULL);
- if (m_target_height == 0 || now >= m_target_height_time + 30) // re-cache every 30 seconds
+ if (now >= m_get_info_time + 30) // re-cache every 30 seconds
{
cryptonote::COMMAND_RPC_GET_INFO::request req_t = AUTO_VAL_INIT(req_t);
cryptonote::COMMAND_RPC_GET_INFO::response resp_t = AUTO_VAL_INIT(resp_t);
@@ -125,13 +97,41 @@ boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) c
CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon");
CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon");
CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get target blockchain height");
+ m_height = resp_t.height;
m_target_height = resp_t.target_height;
- m_target_height_time = now;
+ m_block_size_limit = resp_t.block_size_limit;
+ m_get_info_time = now;
}
+ return boost::optional<std::string>();
+}
+
+boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height) const
+{
+ auto res = get_info();
+ if (res)
+ return res;
+ height = m_height;
+ return boost::optional<std::string>();
+}
+
+boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) const
+{
+ auto res = get_info();
+ if (res)
+ return res;
height = m_target_height;
return boost::optional<std::string>();
}
+boost::optional<std::string> NodeRPCProxy::get_block_size_limit(uint64_t &block_size_limit) const
+{
+ auto res = get_info();
+ if (res)
+ return res;
+ block_size_limit = m_block_size_limit;
+ return boost::optional<std::string>();
+}
+
boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height) const
{
if (m_earliest_height[version] == 0)
diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h
index 1b183212d..8a65884f7 100644
--- a/src/wallet/node_rpc_proxy.h
+++ b/src/wallet/node_rpc_proxy.h
@@ -47,22 +47,25 @@ public:
boost::optional<std::string> get_height(uint64_t &height) const;
void set_height(uint64_t h);
boost::optional<std::string> get_target_height(uint64_t &height) const;
+ boost::optional<std::string> get_block_size_limit(uint64_t &block_size_limit) const;
boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height) const;
boost::optional<std::string> get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const;
private:
+ boost::optional<std::string> get_info() const;
+
epee::net_utils::http::http_simple_client &m_http_client;
boost::mutex &m_daemon_rpc_mutex;
mutable uint64_t m_height;
- mutable time_t m_height_time;
mutable uint64_t m_earliest_height[256];
mutable uint64_t m_dynamic_per_kb_fee_estimate;
mutable uint64_t m_dynamic_per_kb_fee_estimate_cached_height;
mutable uint64_t m_dynamic_per_kb_fee_estimate_grace_blocks;
mutable uint32_t m_rpc_version;
mutable uint64_t m_target_height;
- mutable time_t m_target_height_time;
+ mutable uint64_t m_block_size_limit;
+ mutable time_t m_get_info_time;
};
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index d99371673..9e50f3229 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -676,6 +676,7 @@ wallet2::wallet2(network_type nettype, bool restricted):
m_segregate_pre_fork_outputs(true),
m_key_reuse_mitigation2(true),
m_segregation_height(0),
+ m_ignore_fractional_outputs(true),
m_is_initialized(false),
m_restricted(restricted),
is_old_file_format(false),
@@ -1057,6 +1058,16 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
tx_scan_info.error = false;
}
//----------------------------------------------------------------------------------------------------
+void wallet2::check_acc_out_precomp_once(const tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info, bool &already_seen) const
+{
+ tx_scan_info.received = boost::none;
+ if (already_seen)
+ return;
+ check_acc_out_precomp(o, derivation, additional_derivations, i, is_out_data, tx_scan_info);
+ if (tx_scan_info.received)
+ already_seen = true;
+}
+//----------------------------------------------------------------------------------------------------
static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &derivation, unsigned int i, rct::key & mask, hw::device &hwdev)
{
crypto::secret_key scalar1;
@@ -1173,7 +1184,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
// Don't try to extract tx public key if tx has no ouputs
size_t pk_index = 0;
std::vector<tx_scan_info_t> tx_scan_info(tx.vout.size());
- std::unordered_set<crypto::public_key> public_keys_seen;
+ std::deque<bool> output_found(tx.vout.size(), false);
while (!tx.vout.empty())
{
// if tx.vout is not empty, we loop through all tx pubkeys
@@ -1194,13 +1205,6 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
error::wallet_internal_error, "tx_cache_data is out of sync");
}
- if (public_keys_seen.find(pub_key_field.pub_key) != public_keys_seen.end())
- {
- MWARNING("The same transaction pubkey is present more than once, ignoring extra instance");
- continue;
- }
- public_keys_seen.insert(pub_key_field.pub_key);
-
int num_vouts_received = 0;
tx_pub_key = pub_key_field.pub_key;
tools::threadpool& tpool = tools::threadpool::getInstance();
@@ -1264,7 +1268,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
}
else if (miner_tx && m_refresh_type == RefreshOptimizeCoinbase)
{
- check_acc_out_precomp(tx.vout[0], derivation, additional_derivations, 0, is_out_data_ptr, tx_scan_info[0]);
+ check_acc_out_precomp_once(tx.vout[0], derivation, additional_derivations, 0, is_out_data_ptr, tx_scan_info[0], output_found[0]);
THROW_WALLET_EXCEPTION_IF(tx_scan_info[0].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys());
// this assumes that the miner tx pays a single address
@@ -1274,8 +1278,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
// the first one was already checked
for (size_t i = 1; i < tx.vout.size(); ++i)
{
- tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i,
- std::cref(is_out_data_ptr), std::ref(tx_scan_info[i])), true);
+ tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp_once, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i,
+ std::cref(is_out_data_ptr), std::ref(tx_scan_info[i]), std::ref(output_found[i])), true);
}
waiter.wait(&tpool);
// then scan all outputs from 0
@@ -1297,8 +1301,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
for (size_t i = 0; i < tx.vout.size(); ++i)
{
- tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i,
- std::cref(is_out_data_ptr), std::ref(tx_scan_info[i])), true);
+ tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp_once, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i,
+ std::cref(is_out_data_ptr), std::ref(tx_scan_info[i]), std::ref(output_found[i])), true);
}
waiter.wait(&tpool);
@@ -1319,7 +1323,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
for (size_t i = 0; i < tx.vout.size(); ++i)
{
- check_acc_out_precomp(tx.vout[i], derivation, additional_derivations, i, is_out_data_ptr, tx_scan_info[i]);
+ check_acc_out_precomp_once(tx.vout[i], derivation, additional_derivations, i, is_out_data_ptr, tx_scan_info[i], output_found[i]);
THROW_WALLET_EXCEPTION_IF(tx_scan_info[i].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys());
if (tx_scan_info[i].received)
{
@@ -1820,7 +1824,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
blocks_added = 0;
THROW_WALLET_EXCEPTION_IF(blocks.size() != parsed_blocks.size(), error::wallet_internal_error, "size mismatch");
- THROW_WALLET_EXCEPTION_IF(!m_blockchain.is_in_bounds(current_index), error::wallet_internal_error, "Index out of bounds of hashchain");
+ THROW_WALLET_EXCEPTION_IF(!m_blockchain.is_in_bounds(current_index), error::out_of_hashchain_bounds_error);
tools::threadpool& tpool = tools::threadpool::getInstance();
tools::threadpool::waiter waiter;
@@ -2052,8 +2056,8 @@ void wallet2::update_pool_state(bool refreshed)
MDEBUG("update_pool_state start");
// get the pool state
- cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request req;
- cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response res;
+ cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::request req;
+ cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::response res;
m_daemon_rpc_mutex.lock();
bool r = epee::net_utils::invoke_http_json("/get_transaction_pool_hashes.bin", req, res, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
@@ -2266,12 +2270,12 @@ void wallet2::update_pool_state(bool refreshed)
MDEBUG("update_pool_state end");
}
//----------------------------------------------------------------------------------------------------
-void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history)
+void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force)
{
std::vector<crypto::hash> hashes;
const uint64_t checkpoint_height = m_checkpoints.get_max_height();
- if (stop_height > checkpoint_height && m_blockchain.size()-1 < checkpoint_height)
+ if ((stop_height > checkpoint_height && m_blockchain.size()-1 < checkpoint_height) && !force)
{
// we will drop all these, so don't bother getting them
uint64_t missing_blocks = m_checkpoints.get_max_height() - m_blockchain.size();
@@ -2436,6 +2440,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
std::vector<cryptonote::block_complete_entry> next_blocks;
std::vector<parsed_block> next_parsed_blocks;
bool error = false;
+ added_blocks = 0;
if (!first && blocks.empty())
{
refreshed = false;
@@ -2445,7 +2450,33 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
if (!first)
{
- process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks);
+ try
+ {
+ process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks);
+ }
+ catch (const tools::error::out_of_hashchain_bounds_error&)
+ {
+ MINFO("Daemon claims next refresh block is out of hash chain bounds, resetting hash chain");
+ uint64_t stop_height = m_blockchain.offset();
+ std::vector<crypto::hash> tip(m_blockchain.size() - m_blockchain.offset());
+ for (size_t i = m_blockchain.offset(); i < m_blockchain.size(); ++i)
+ tip[i - m_blockchain.offset()] = m_blockchain[i];
+ cryptonote::block b;
+ generate_genesis(b);
+ m_blockchain.clear();
+ m_blockchain.push_back(get_block_hash(b));
+ short_chain_history.clear();
+ get_short_chain_history(short_chain_history);
+ fast_refresh(stop_height, blocks_start_height, short_chain_history, true);
+ THROW_WALLET_EXCEPTION_IF(m_blockchain.size() != stop_height, error::wallet_internal_error, "Unexpected hashchain size");
+ THROW_WALLET_EXCEPTION_IF(m_blockchain.offset() != 0, error::wallet_internal_error, "Unexpected hashchain offset");
+ for (const auto &h: tip)
+ m_blockchain.push_back(h);
+ short_chain_history.clear();
+ get_short_chain_history(short_chain_history);
+ start_height = stop_height;
+ throw std::runtime_error(""); // loop again
+ }
blocks_fetched += added_blocks;
}
waiter.wait(&tpool);
@@ -2475,6 +2506,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
if(try_count < 3)
{
LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")...");
+ first = true;
++try_count;
}
else
@@ -2651,7 +2683,7 @@ void wallet2::detach_blockchain(uint64_t height)
bool wallet2::deinit()
{
m_is_initialized=false;
- m_keys_file_locker.reset();
+ unlock_keys_file();
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -2797,6 +2829,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetUint(m_segregation_height);
json.AddMember("segregation_height", value2, json.GetAllocator());
+ value2.SetInt(m_ignore_fractional_outputs ? 1 : 0);
+ json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator());
+
value2.SetUint(m_subaddress_lookahead_major);
json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator());
@@ -2818,12 +2853,12 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
crypto::chacha20(account_data.data(), account_data.size(), key, keys_file_data.iv, &cipher[0]);
keys_file_data.account_data = cipher;
- m_keys_file_locker.reset();
+ unlock_keys_file();
std::string buf;
r = ::serialization::dump_binary(keys_file_data, buf);
r = r && epee::file_io_utils::save_string_to_file(keys_file_name, buf); //and never touch wallet_keys_file again, only read
CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << keys_file_name);
- m_keys_file_locker.reset(new tools::file_locker(m_keys_file));
+ lock_keys_file();
return true;
}
@@ -2879,6 +2914,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_segregate_pre_fork_outputs = true;
m_key_reuse_mitigation2 = true;
m_segregation_height = 0;
+ m_ignore_fractional_outputs = true;
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
m_key_on_device = false;
@@ -3005,6 +3041,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_key_reuse_mitigation2 = field_key_reuse_mitigation2;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, segregation_height, int, Uint, false, 0);
m_segregation_height = field_segregation_height;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true);
+ m_ignore_fractional_outputs = field_ignore_fractional_outputs;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR);
m_subaddress_lookahead_major = field_subaddress_lookahead_major;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR);
@@ -3044,9 +3082,13 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
* can be used prior to rewriting wallet keys file, to ensure user has entered the correct password
*
*/
-bool wallet2::verify_password(const epee::wipeable_string& password) const
+bool wallet2::verify_password(const epee::wipeable_string& password)
{
- return verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device());
+ // this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded).
+ unlock_keys_file();
+ bool r = verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device());
+ lock_keys_file();
+ return r;
}
/*!
@@ -3953,17 +3995,17 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
boost::system::error_code e;
bool exists = boost::filesystem::exists(m_keys_file, e);
THROW_WALLET_EXCEPTION_IF(e || !exists, error::file_not_found, m_keys_file);
- m_keys_file_locker.reset(new tools::file_locker(m_keys_file));
- THROW_WALLET_EXCEPTION_IF(!m_keys_file_locker->locked(), error::wallet_internal_error, "internal error: \"" + m_keys_file + "\" is opened by another wallet program");
+ lock_keys_file();
+ THROW_WALLET_EXCEPTION_IF(!is_keys_file_locked(), error::wallet_internal_error, "internal error: \"" + m_keys_file + "\" is opened by another wallet program");
// this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded).
- m_keys_file_locker.reset();
+ unlock_keys_file();
if (!load_keys(m_keys_file, password))
{
THROW_WALLET_EXCEPTION_IF(true, error::file_read_error, m_keys_file);
}
LOG_PRINT_L0("Loaded wallet keys file, with public address: " << m_account.get_public_address_str(m_nettype));
- m_keys_file_locker.reset(new tools::file_locker(m_keys_file));
+ lock_keys_file();
//keys loaded ok!
//try to load wallet file. but even if we failed, it is not big problem
@@ -5615,15 +5657,10 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
}
// get the current full reward zone
- cryptonote::COMMAND_RPC_GET_INFO::request getinfo_req = AUTO_VAL_INIT(getinfo_req);
- cryptonote::COMMAND_RPC_GET_INFO::response getinfo_res = AUTO_VAL_INIT(getinfo_res);
- m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_info", getinfo_req, getinfo_res, m_http_client);
- m_daemon_rpc_mutex.unlock();
- THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_info");
- THROW_WALLET_EXCEPTION_IF(getinfo_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_info");
- THROW_WALLET_EXCEPTION_IF(getinfo_res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error);
- const uint64_t full_reward_zone = getinfo_res.block_size_limit / 2;
+ uint64_t block_size_limit = 0;
+ const auto result = m_node_rpc_proxy.get_block_size_limit(block_size_limit);
+ throw_on_rpc_response_error(result, "get_info");
+ const uint64_t full_reward_zone = block_size_limit / 2;
// get the last N block headers and sum the block sizes
const size_t N = 10;
@@ -5637,7 +5674,7 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
m_daemon_rpc_mutex.lock();
getbh_req.start_height = m_blockchain.size() - N;
getbh_req.end_height = m_blockchain.size() - 1;
- r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, m_http_client, rpc_timeout);
+ bool r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblockheadersrange");
THROW_WALLET_EXCEPTION_IF(getbh_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblockheadersrange");
@@ -6004,6 +6041,33 @@ bool wallet2::is_output_blackballed(const crypto::public_key &output) const
catch (const std::exception &e) { return false; }
}
+bool wallet2::lock_keys_file()
+{
+ if (m_keys_file_locker)
+ {
+ MDEBUG(m_keys_file << " is already locked.");
+ return false;
+ }
+ m_keys_file_locker.reset(new tools::file_locker(m_keys_file));
+ return true;
+}
+
+bool wallet2::unlock_keys_file()
+{
+ if (!m_keys_file_locker)
+ {
+ MDEBUG(m_keys_file << " is already unlocked.");
+ return false;
+ }
+ m_keys_file_locker.reset();
+ return true;
+}
+
+bool wallet2::is_keys_file_locked() const
+{
+ return m_keys_file_locker->locked();
+}
+
bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& output_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const
{
if (!unlocked) // don't add locked outs
@@ -7688,12 +7752,24 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
for (uint32_t i : subaddr_indices)
LOG_PRINT_L2("Candidate subaddress index for spending: " << i);
+ // determine threshold for fractional amount
+ const size_t tx_size_one_ring = estimate_tx_size(use_rct, 1, fake_outs_count, 2, 0, bulletproof);
+ const size_t tx_size_two_rings = estimate_tx_size(use_rct, 2, fake_outs_count, 2, 0, bulletproof);
+ THROW_WALLET_EXCEPTION_IF(tx_size_one_ring > tx_size_two_rings, error::wallet_internal_error, "Estimated tx size with 1 input is larger than with 2 inputs!");
+ const size_t tx_size_per_ring = tx_size_two_rings - tx_size_one_ring;
+ const uint64_t fractional_threshold = (fee_multiplier * fee_per_kb * tx_size_per_ring) / 1024;
+
// gather all dust and non-dust outputs belonging to specified subaddresses
size_t num_nondust_outputs = 0;
size_t num_dust_outputs = 0;
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
+ if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
+ {
+ MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold));
+ continue;
+ }
if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
const uint32_t index_minor = td.m_subaddr_index.minor;
@@ -9399,31 +9475,15 @@ uint64_t wallet2::get_daemon_blockchain_height(string &err) const
uint64_t wallet2::get_daemon_blockchain_target_height(string &err)
{
- cryptonote::COMMAND_RPC_GET_INFO::request req_t = AUTO_VAL_INIT(req_t);
- cryptonote::COMMAND_RPC_GET_INFO::response resp_t = AUTO_VAL_INIT(resp_t);
- m_daemon_rpc_mutex.lock();
- bool ok = net_utils::invoke_http_json_rpc("/json_rpc", "get_info", req_t, resp_t, m_http_client);
- m_daemon_rpc_mutex.unlock();
- if (ok)
- {
- if (resp_t.status == CORE_RPC_STATUS_BUSY)
- {
- err = "daemon is busy. Please try again later.";
- }
- else if (resp_t.status != CORE_RPC_STATUS_OK)
- {
- err = resp_t.status;
- }
- else // success, cleaning up error message
- {
- err = "";
- }
- }
- else
+ err = "";
+ uint64_t target_height = 0;
+ const auto result = m_node_rpc_proxy.get_target_height(target_height);
+ if (result && *result != CORE_RPC_STATUS_OK)
{
- err = "possibly lost connection to daemon";
+ err= *result;
+ return 0;
}
- return resp_t.target_height;
+ return target_height;
}
uint64_t wallet2::get_approximate_blockchain_height() const
@@ -10781,15 +10841,10 @@ std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(const std::
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_txpool_backlog");
THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error);
- cryptonote::COMMAND_RPC_GET_INFO::request req_t = AUTO_VAL_INIT(req_t);
- cryptonote::COMMAND_RPC_GET_INFO::response resp_t = AUTO_VAL_INIT(resp_t);
- m_daemon_rpc_mutex.lock();
- r = net_utils::invoke_http_json_rpc("/json_rpc", "get_info", req_t, resp_t, m_http_client);
- m_daemon_rpc_mutex.unlock();
- THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_info");
- THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_info");
- THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error);
- uint64_t full_reward_zone = resp_t.block_size_limit / 2;
+ uint64_t block_size_limit = 0;
+ const auto result = m_node_rpc_proxy.get_block_size_limit(block_size_limit);
+ throw_on_rpc_response_error(result, "get_info");
+ uint64_t full_reward_zone = block_size_limit / 2;
std::vector<std::pair<uint64_t, uint64_t>> blocks;
for (const auto &fee_level: fee_levels)
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index d33d8258b..220eca8a8 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -609,7 +609,7 @@ namespace tools
/*!
* \brief verifies given password is correct for default wallet keys file
*/
- bool verify_password(const epee::wipeable_string& password) const;
+ bool verify_password(const epee::wipeable_string& password);
cryptonote::account_base& get_account(){return m_account;}
const cryptonote::account_base& get_account()const{return m_account;}
@@ -925,6 +925,8 @@ namespace tools
void key_reuse_mitigation2(bool value) { m_key_reuse_mitigation2 = value; }
uint64_t segregation_height() const { return m_segregation_height; }
void segregation_height(uint64_t height) { m_segregation_height = height; }
+ bool ignore_fractional_outputs() const { return m_ignore_fractional_outputs; }
+ void ignore_fractional_outputs(bool value) { m_ignore_fractional_outputs = value; }
bool confirm_non_default_ring_size() const { return m_confirm_non_default_ring_size; }
void confirm_non_default_ring_size(bool always) { m_confirm_non_default_ring_size = always; }
@@ -1144,6 +1146,9 @@ namespace tools
bool unblackball_output(const crypto::public_key &output);
bool is_output_blackballed(const crypto::public_key &output) const;
+ bool lock_keys_file();
+ bool unlock_keys_file();
+ bool is_keys_file_locked() const;
private:
/*!
* \brief Stores wallet information to wallet file.
@@ -1167,7 +1172,7 @@ namespace tools
bool clear();
void pull_blocks(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices> &o_indices);
void pull_hashes(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<crypto::hash> &hashes);
- void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history);
+ void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force = false);
void pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &error);
void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added);
uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers, bool trusted_daemon) const;
@@ -1181,6 +1186,7 @@ namespace tools
crypto::hash get_payment_id(const pending_tx &ptx) const;
void check_acc_out_precomp(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, tx_scan_info_t &tx_scan_info) const;
void check_acc_out_precomp(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info) const;
+ void check_acc_out_precomp_once(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info, bool &already_seen) const;
void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const;
uint64_t get_upper_transaction_size_limit() const;
std::vector<uint64_t> get_unspent_amounts_vector() const;
@@ -1283,6 +1289,7 @@ namespace tools
bool m_segregate_pre_fork_outputs;
bool m_key_reuse_mitigation2;
uint64_t m_segregation_height;
+ bool m_ignore_fractional_outputs;
bool m_is_initialized;
NodeRPCProxy m_node_rpc_proxy;
std::unordered_set<crypto::hash> m_scanned_pool_txs[2];
diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h
index 214d51cde..e80652750 100644
--- a/src/wallet/wallet_errors.h
+++ b/src/wallet/wallet_errors.h
@@ -70,6 +70,7 @@ namespace tools
// get_out_indexes_error
// tx_parse_error
// get_tx_pool_error
+ // out_of_hashchain_bounds_error
// transfer_error *
// get_random_outs_general_error
// not_enough_unlocked_money
@@ -398,6 +399,16 @@ namespace tools
std::string to_string() const { return refresh_error::to_string(); }
};
//----------------------------------------------------------------------------------------------------
+ struct out_of_hashchain_bounds_error : public refresh_error
+ {
+ explicit out_of_hashchain_bounds_error(std::string&& loc)
+ : refresh_error(std::move(loc), "Index out of bounds of of hashchain")
+ {
+ }
+
+ std::string to_string() const { return refresh_error::to_string(); }
+ };
+ //----------------------------------------------------------------------------------------------------
struct transfer_error : public wallet_logic_error
{
protected: