aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.cpp4
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.h4
-rw-r--r--src/blockchain_db/blockchain_db.cpp13
-rw-r--r--src/blockchain_db/blockchain_db.h36
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp348
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h21
-rw-r--r--src/blockchain_utilities/blockchain_usage.cpp2
-rw-r--r--src/blocks/checkpoints.datbin191524 -> 197348 bytes
-rw-r--r--src/checkpoints/checkpoints.cpp2
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp64
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.h4
-rw-r--r--src/cryptonote_core/blockchain.cpp52
-rw-r--r--src/cryptonote_core/blockchain.h20
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp4
-rw-r--r--src/cryptonote_core/cryptonote_core.h2
-rw-r--r--src/cryptonote_core/tx_pool.cpp4
-rw-r--r--src/rpc/core_rpc_server.cpp19
-rw-r--r--src/rpc/daemon_handler.cpp2
-rw-r--r--src/simplewallet/simplewallet.cpp58
-rw-r--r--src/simplewallet/simplewallet.h3
-rw-r--r--src/version.cpp.in2
-rw-r--r--src/wallet/wallet2.cpp44
-rw-r--r--src/wallet/wallet2.h28
-rw-r--r--tests/unit_tests/hardfork.cpp6
24 files changed, 577 insertions, 165 deletions
diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp
index 3a66ecb93..e1b76ec1e 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.cpp
+++ b/src/blockchain_db/berkeleydb/db_bdb.cpp
@@ -313,7 +313,7 @@ void BlockchainBDB::remove_block()
throw1(DB_ERROR("Failed to add removal of block hash to db transaction"));
}
-void BlockchainBDB::add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash)
+void BlockchainBDB::add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash)
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
check_open();
@@ -655,7 +655,7 @@ bool BlockchainBDB::for_all_blocks(std::function<bool(uint64_t, const crypto::ha
return ret;
}
-bool BlockchainBDB::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f) const
+bool BlockchainBDB::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f, bool pruned) const
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
check_open();
diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h
index 238a90686..cecbba28f 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.h
+++ b/src/blockchain_db/berkeleydb/db_bdb.h
@@ -360,7 +360,7 @@ private:
virtual void remove_block();
- virtual void add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash);
+ virtual void add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash);
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx);
@@ -381,7 +381,7 @@ private:
virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const;
virtual bool for_all_blocks(std::function<bool(uint64_t, const crypto::hash&, const cryptonote::block&)>) const;
- virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>) const;
+ virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const;
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, size_t tx_idx)> f) const;
// Hard fork related storage
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp
index 9f760dc0d..88ac34255 100644
--- a/src/blockchain_db/blockchain_db.cpp
+++ b/src/blockchain_db/blockchain_db.cpp
@@ -121,10 +121,10 @@ void BlockchainDB::pop_block()
pop_block(blk, txs);
}
-void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr)
+void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr, const crypto::hash* tx_prunable_hash_ptr)
{
bool miner_tx = false;
- crypto::hash tx_hash;
+ crypto::hash tx_hash, tx_prunable_hash;
if (!tx_hash_ptr)
{
// should only need to compute hash for miner transactions
@@ -135,6 +135,13 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
{
tx_hash = *tx_hash_ptr;
}
+ if (tx.version >= 2)
+ {
+ if (!tx_prunable_hash_ptr)
+ tx_prunable_hash = get_transaction_prunable_hash(tx);
+ else
+ tx_prunable_hash = *tx_prunable_hash_ptr;
+ }
for (const txin_v& tx_input : tx.vin)
{
@@ -161,7 +168,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
}
}
- uint64_t tx_id = add_transaction_data(blk_hash, tx, tx_hash);
+ uint64_t tx_id = add_transaction_data(blk_hash, tx, tx_hash, tx_prunable_hash);
std::vector<uint64_t> amount_output_indices;
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 1ed715315..19ba32340 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -398,9 +398,10 @@ private:
* @param blk_hash the hash of the block containing the transaction
* @param tx the transaction to be added
* @param tx_hash the hash of the transaction
+ * @param tx_prunable_hash the hash of the prunable part of the transaction
* @return the transaction ID
*/
- virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) = 0;
+ virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) = 0;
/**
* @brief remove data about a transaction
@@ -526,8 +527,9 @@ protected:
* @param blk_hash hash of the block which has the transaction
* @param tx the transaction to add
* @param tx_hash_ptr the hash of the transaction, if already calculated
+ * @param tx_prunable_hash_ptr the hash of the prunable part of the transaction, if already calculated
*/
- void add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr = NULL);
+ void add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr = NULL, const crypto::hash* tx_prunable_hash_ptr = NULL);
mutable uint64_t time_tx_exists = 0; //!< a performance metric
uint64_t time_commit1 = 0; //!< a performance metric
@@ -1120,6 +1122,33 @@ public:
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const = 0;
/**
+ * @brief fetches the pruned transaction blob with the given hash
+ *
+ * The subclass should return the pruned transaction stored which has the given
+ * hash.
+ *
+ * If the transaction does not exist, the subclass should return false.
+ *
+ * @param h the hash to look for
+ *
+ * @return true iff the transaction was found
+ */
+ virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const = 0;
+
+ /**
+ * @brief fetches the prunable transaction hash
+ *
+ * The subclass should return the hash of the prunable transaction data.
+ *
+ * If the transaction hash does not exist, the subclass should return false.
+ *
+ * @param h the tx hash to look for
+ *
+ * @return true iff the transaction was found
+ */
+ virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const = 0;
+
+ /**
* @brief fetches the total number of transactions ever
*
* The subclass should return a count of all the transactions from
@@ -1426,10 +1455,11 @@ public:
* not found. Current implementations simply return false.
*
* @param std::function fn the function to run
+ * @param bool pruned whether to only get pruned tx data, or the whole
*
* @return false if the function returns false for any transaction, otherwise true
*/
- virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>) const = 0;
+ virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const = 0;
/**
* @brief runs a function over all outputs stored
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index fbf7629c6..300fb6d2f 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -52,9 +52,8 @@
using epee::string_tools::pod_to_hex;
using namespace crypto;
-// Increase when the DB changes in a non backward compatible way, and there
-// is no automatic conversion, so that a full resync is needed.
-#define VERSION 1
+// Increase when the DB structure changes
+#define VERSION 2
namespace
{
@@ -164,7 +163,9 @@ int compare_string(const MDB_val *a, const MDB_val *b)
* block_heights block hash block height
* block_info block ID {block metadata}
*
- * txs txn ID txn blob
+ * txs_pruned txn ID pruned txn blob
+ * txs_prunable txn ID prunable txn blob
+ * txs_prunable_hash txn ID prunable txn hash
* tx_indices txn hash {txn ID, metadata}
* tx_outputs txn ID [txn amount output indices]
*
@@ -189,6 +190,9 @@ const char* const LMDB_BLOCK_HEIGHTS = "block_heights";
const char* const LMDB_BLOCK_INFO = "block_info";
const char* const LMDB_TXS = "txs";
+const char* const LMDB_TXS_PRUNED = "txs_pruned";
+const char* const LMDB_TXS_PRUNABLE = "txs_prunable";
+const char* const LMDB_TXS_PRUNABLE_HASH = "txs_prunable_hash";
const char* const LMDB_TX_INDICES = "tx_indices";
const char* const LMDB_TX_OUTPUTS = "tx_outputs";
@@ -764,7 +768,7 @@ void BlockchainLMDB::remove_block()
throw1(DB_ERROR(lmdb_error("Failed to add removal of block info to db transaction: ", result).c_str()));
}
-uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash)
+uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -774,7 +778,9 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
int result;
uint64_t tx_id = get_tx_count();
- CURSOR(txs)
+ CURSOR(txs_pruned)
+ CURSOR(txs_prunable)
+ CURSOR(txs_prunable_hash)
CURSOR(tx_indices)
MDB_val_set(val_tx_id, tx_id);
@@ -800,10 +806,35 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
if (result)
throw0(DB_ERROR(lmdb_error("Failed to add tx data to db transaction: ", result).c_str()));
- MDB_val_copy<blobdata> blob(tx_to_blob(tx));
- result = mdb_cursor_put(m_cur_txs, &val_tx_id, &blob, MDB_APPEND);
+ cryptonote::blobdata blob = tx_to_blob(tx);
+ MDB_val_copy<blobdata> blobval(blob);
+
+ std::stringstream ss;
+ binary_archive<true> ba(ss);
+ bool r = const_cast<cryptonote::transaction&>(tx).serialize_base(ba);
+ if (!r)
+ throw0(DB_ERROR("Failed to serialize pruned tx"));
+ std::string pruned = ss.str();
+ MDB_val_copy<blobdata> pruned_blob(pruned);
+ result = mdb_cursor_put(m_cur_txs_pruned, &val_tx_id, &pruned_blob, MDB_APPEND);
if (result)
- throw0(DB_ERROR(lmdb_error("Failed to add tx blob to db transaction: ", result).c_str()));
+ throw0(DB_ERROR(lmdb_error("Failed to add pruned tx blob to db transaction: ", result).c_str()));
+
+ if (pruned.size() > blob.size())
+ throw0(DB_ERROR("pruned tx size is larger than tx size"));
+ cryptonote::blobdata prunable(blob.data() + pruned.size(), blob.size() - pruned.size());
+ MDB_val_copy<blobdata> prunable_blob(prunable);
+ result = mdb_cursor_put(m_cur_txs_prunable, &val_tx_id, &prunable_blob, MDB_APPEND);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to add prunable tx blob to db transaction: ", result).c_str()));
+
+ if (tx.version > 1)
+ {
+ MDB_val_set(val_prunable_hash, tx_prunable_hash);
+ result = mdb_cursor_put(m_cur_txs_prunable_hash, &val_tx_id, &val_prunable_hash, MDB_APPEND);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to add prunable tx prunable hash to db transaction: ", result).c_str()));
+ }
return tx_id;
}
@@ -819,7 +850,9 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
mdb_txn_cursors *m_cursors = &m_wcursors;
CURSOR(tx_indices)
- CURSOR(txs)
+ CURSOR(txs_pruned)
+ CURSOR(txs_prunable)
+ CURSOR(txs_prunable_hash)
CURSOR(tx_outputs)
MDB_val_set(val_h, tx_hash);
@@ -829,11 +862,26 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
txindex *tip = (txindex *)val_h.mv_data;
MDB_val_set(val_tx_id, tip->data.tx_id);
- if ((result = mdb_cursor_get(m_cur_txs, &val_tx_id, NULL, MDB_SET)))
- throw1(DB_ERROR(lmdb_error("Failed to locate tx for removal: ", result).c_str()));
- result = mdb_cursor_del(m_cur_txs, 0);
+ if ((result = mdb_cursor_get(m_cur_txs_pruned, &val_tx_id, NULL, MDB_SET)))
+ throw1(DB_ERROR(lmdb_error("Failed to locate pruned tx for removal: ", result).c_str()));
+ result = mdb_cursor_del(m_cur_txs_pruned, 0);
+ if (result)
+ throw1(DB_ERROR(lmdb_error("Failed to add removal of pruned tx to db transaction: ", result).c_str()));
+
+ if ((result = mdb_cursor_get(m_cur_txs_prunable, &val_tx_id, NULL, MDB_SET)))
+ throw1(DB_ERROR(lmdb_error("Failed to locate prunable tx for removal: ", result).c_str()));
+ result = mdb_cursor_del(m_cur_txs_prunable, 0);
if (result)
- throw1(DB_ERROR(lmdb_error("Failed to add removal of tx to db transaction: ", result).c_str()));
+ throw1(DB_ERROR(lmdb_error("Failed to add removal of prunable tx to db transaction: ", result).c_str()));
+
+ if (tx.version > 1)
+ {
+ if ((result = mdb_cursor_get(m_cur_txs_prunable_hash, &val_tx_id, NULL, MDB_SET)))
+ throw1(DB_ERROR(lmdb_error("Failed to locate prunable hash tx for removal: ", result).c_str()));
+ result = mdb_cursor_del(m_cur_txs_prunable_hash, 0);
+ if (result)
+ throw1(DB_ERROR(lmdb_error("Failed to add removal of prunable hash tx to db transaction: ", result).c_str()));
+ }
remove_tx_outputs(tip->data.tx_id, tx);
@@ -1199,6 +1247,9 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
lmdb_db_open(txn, LMDB_BLOCK_HEIGHTS, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_block_heights, "Failed to open db handle for m_block_heights");
lmdb_db_open(txn, LMDB_TXS, MDB_INTEGERKEY | MDB_CREATE, m_txs, "Failed to open db handle for m_txs");
+ lmdb_db_open(txn, LMDB_TXS_PRUNED, MDB_INTEGERKEY | MDB_CREATE, m_txs_pruned, "Failed to open db handle for m_txs_pruned");
+ lmdb_db_open(txn, LMDB_TXS_PRUNABLE, MDB_INTEGERKEY | MDB_CREATE, m_txs_prunable, "Failed to open db handle for m_txs_prunable");
+ lmdb_db_open(txn, LMDB_TXS_PRUNABLE_HASH, MDB_INTEGERKEY | MDB_CREATE, m_txs_prunable_hash, "Failed to open db handle for m_txs_prunable_hash");
lmdb_db_open(txn, LMDB_TX_INDICES, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_tx_indices, "Failed to open db handle for m_tx_indices");
lmdb_db_open(txn, LMDB_TX_OUTPUTS, MDB_INTEGERKEY | MDB_CREATE, m_tx_outputs, "Failed to open db handle for m_tx_outputs");
@@ -1365,8 +1416,12 @@ void BlockchainLMDB::reset()
throw0(DB_ERROR(lmdb_error("Failed to drop m_block_info: ", result).c_str()));
if (auto result = mdb_drop(txn, m_block_heights, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_block_heights: ", result).c_str()));
- if (auto result = mdb_drop(txn, m_txs, 0))
- throw0(DB_ERROR(lmdb_error("Failed to drop m_txs: ", result).c_str()));
+ if (auto result = mdb_drop(txn, m_txs_pruned, 0))
+ throw0(DB_ERROR(lmdb_error("Failed to drop m_txs_pruned: ", result).c_str()));
+ if (auto result = mdb_drop(txn, m_txs_prunable, 0))
+ throw0(DB_ERROR(lmdb_error("Failed to drop m_txs_prunable: ", result).c_str()));
+ if (auto result = mdb_drop(txn, m_txs_prunable_hash, 0))
+ throw0(DB_ERROR(lmdb_error("Failed to drop m_txs_prunable_hash: ", result).c_str()));
if (auto result = mdb_drop(txn, m_tx_indices, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_tx_indices: ", result).c_str()));
if (auto result = mdb_drop(txn, m_tx_outputs, 0))
@@ -2064,7 +2119,6 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
TXN_PREFIX_RDONLY();
RCURSOR(tx_indices);
- RCURSOR(txs);
MDB_val_set(key, h);
bool tx_found = false;
@@ -2076,8 +2130,6 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
else if (get_result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch transaction index from hash ") + epee::string_tools::pod_to_hex(h) + ": ", get_result).c_str()));
- // This isn't needed as part of the check. we're not checking consistency of db.
- // get_result = mdb_cursor_get(m_cur_txs, &val_tx_index, &result, MDB_SET);
TIME_MEASURE_FINISH(time1);
time_tx_exists += time1;
@@ -2089,11 +2141,6 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
return false;
}
- // Below not needed due to above comment.
- // if (get_result == MDB_NOTFOUND)
- // throw0(DB_ERROR(std::string("transaction with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found at index").c_str()));
- // else if (get_result)
- // throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch transaction ") + epee::string_tools::pod_to_hex(h) + " at index: ", get_result).c_str()));
return true;
}
@@ -2159,7 +2206,43 @@ bool BlockchainLMDB::get_tx_blob(const crypto::hash& h, cryptonote::blobdata &bd
TXN_PREFIX_RDONLY();
RCURSOR(tx_indices);
- RCURSOR(txs);
+ RCURSOR(txs_pruned);
+ RCURSOR(txs_prunable);
+
+ MDB_val_set(v, h);
+ MDB_val result0, result1;
+ auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
+ if (get_result == 0)
+ {
+ txindex *tip = (txindex *)v.mv_data;
+ MDB_val_set(val_tx_id, tip->data.tx_id);
+ get_result = mdb_cursor_get(m_cur_txs_pruned, &val_tx_id, &result0, MDB_SET);
+ if (get_result == 0)
+ {
+ get_result = mdb_cursor_get(m_cur_txs_prunable, &val_tx_id, &result1, MDB_SET);
+ }
+ }
+ if (get_result == MDB_NOTFOUND)
+ return false;
+ else if (get_result)
+ throw0(DB_ERROR(lmdb_error("DB error attempting to fetch tx from hash", get_result).c_str()));
+
+ bd.assign(reinterpret_cast<char*>(result0.mv_data), result0.mv_size);
+ bd.append(reinterpret_cast<char*>(result1.mv_data), result1.mv_size);
+
+ TXN_POSTFIX_RDONLY();
+
+ return true;
+}
+
+bool BlockchainLMDB::get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &bd) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ TXN_PREFIX_RDONLY();
+ RCURSOR(tx_indices);
+ RCURSOR(txs_pruned);
MDB_val_set(v, h);
MDB_val result;
@@ -2168,7 +2251,7 @@ bool BlockchainLMDB::get_tx_blob(const crypto::hash& h, cryptonote::blobdata &bd
{
txindex *tip = (txindex *)v.mv_data;
MDB_val_set(val_tx_id, tip->data.tx_id);
- get_result = mdb_cursor_get(m_cur_txs, &val_tx_id, &result, MDB_SET);
+ get_result = mdb_cursor_get(m_cur_txs_pruned, &val_tx_id, &result, MDB_SET);
}
if (get_result == MDB_NOTFOUND)
return false;
@@ -2182,6 +2265,36 @@ bool BlockchainLMDB::get_tx_blob(const crypto::hash& h, cryptonote::blobdata &bd
return true;
}
+bool BlockchainLMDB::get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ TXN_PREFIX_RDONLY();
+ RCURSOR(tx_indices);
+ RCURSOR(txs_prunable_hash);
+
+ MDB_val_set(v, tx_hash);
+ MDB_val result, val_tx_prunable_hash;
+ auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
+ if (get_result == 0)
+ {
+ txindex *tip = (txindex *)v.mv_data;
+ MDB_val_set(val_tx_id, tip->data.tx_id);
+ get_result = mdb_cursor_get(m_cur_txs_prunable_hash, &val_tx_id, &result, MDB_SET);
+ }
+ if (get_result == MDB_NOTFOUND)
+ return false;
+ else if (get_result)
+ throw0(DB_ERROR(lmdb_error("DB error attempting to fetch tx prunable hash from tx hash", get_result).c_str()));
+
+ prunable_hash = *(const crypto::hash*)result.mv_data;
+
+ TXN_POSTFIX_RDONLY();
+
+ return true;
+}
+
uint64_t BlockchainLMDB::get_tx_count() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -2191,8 +2304,8 @@ uint64_t BlockchainLMDB::get_tx_count() const
int result;
MDB_stat db_stats;
- if ((result = mdb_stat(m_txn, m_txs, &db_stats)))
- throw0(DB_ERROR(lmdb_error("Failed to query m_txs: ", result).c_str()));
+ if ((result = mdb_stat(m_txn, m_txs_pruned, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_txs_pruned: ", result).c_str()));
TXN_POSTFIX_RDONLY();
@@ -2268,7 +2381,6 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t &global_index) const
TXN_PREFIX_RDONLY();
RCURSOR(output_txs);
RCURSOR(tx_indices);
- RCURSOR(txs);
output_data_t od;
MDB_val_set(v, global_index);
@@ -2288,7 +2400,7 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t &global_index) const
txindex *tip = (txindex *)val_h.mv_data;
MDB_val_set(val_tx_id, tip->data.tx_id);
MDB_val result;
- get_result = mdb_cursor_get(m_cur_txs, &val_tx_id, &result, MDB_SET);
+ get_result = mdb_cursor_get(m_cur_txs_pruned, &val_tx_id, &result, MDB_SET);
if (get_result == MDB_NOTFOUND)
throw1(TX_DNE(std::string("tx with hash ").append(epee::string_tools::pod_to_hex(ot->tx_hash)).append(" not found in db").c_str()));
else if (get_result)
@@ -2298,7 +2410,7 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t &global_index) const
bd.assign(reinterpret_cast<char*>(result.mv_data), result.mv_size);
transaction tx;
- if (!parse_and_validate_tx_from_blob(bd, tx))
+ if (!parse_and_validate_tx_base_from_blob(bd, tx))
throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
const tx_out tx_output = tx.vout[ot->local_index];
@@ -2517,13 +2629,14 @@ bool BlockchainLMDB::for_blocks_range(const uint64_t& h1, const uint64_t& h2, st
return fret;
}
-bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f) const
+bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f, bool pruned) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
TXN_PREFIX_RDONLY();
- RCURSOR(txs);
+ RCURSOR(txs_pruned);
+ RCURSOR(txs_prunable);
RCURSOR(tx_indices);
MDB_val k;
@@ -2544,16 +2657,29 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
const crypto::hash hash = ti->key;
k.mv_data = (void *)&ti->data.tx_id;
k.mv_size = sizeof(ti->data.tx_id);
- ret = mdb_cursor_get(m_cur_txs, &k, &v, MDB_SET);
+
+ ret = mdb_cursor_get(m_cur_txs_pruned, &k, &v, MDB_SET);
if (ret == MDB_NOTFOUND)
break;
if (ret)
throw0(DB_ERROR(lmdb_error("Failed to enumerate transactions: ", ret).c_str()));
+ transaction tx;
blobdata bd;
bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
- transaction tx;
- if (!parse_and_validate_tx_from_blob(bd, tx))
- throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
+ if (pruned)
+ {
+ if (!parse_and_validate_tx_base_from_blob(bd, tx))
+ throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
+ }
+ else
+ {
+ ret = mdb_cursor_get(m_cur_txs_prunable, &k, &v, MDB_SET);
+ if (ret)
+ throw0(DB_ERROR(lmdb_error("Failed to get prunable tx data the db: ", ret).c_str()));
+ bd.append(reinterpret_cast<char*>(v.mv_data), v.mv_size);
+ if (!parse_and_validate_tx_from_blob(bd, tx))
+ throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
+ }
if (!f(hash, tx)) {
fret = false;
break;
@@ -3312,7 +3438,7 @@ void BlockchainLMDB::fixup()
ptr = (char *)k.mv_data; \
ptr[sizeof(name)-2] = 's'
-#define LOGIF(y) if (ELPP->vRegistry()->allowed(y, MONERO_DEFAULT_LOG_CATEGORY))
+#define LOGIF(y) if (ELPP->vRegistry()->allowed(y, "global"))
void BlockchainLMDB::migrate_0_1()
{
@@ -3323,7 +3449,7 @@ void BlockchainLMDB::migrate_0_1()
MDB_val k, v;
char *ptr;
- MLOG_YELLOW(el::Level::Info, "Migrating blockchain from DB version 0 to 1 - this may take a while:");
+ MGINFO_YELLOW("Migrating blockchain from DB version 0 to 1 - this may take a while:");
MINFO("updating blocks, hf_versions, outputs, txs, and spent_keys tables...");
do {
@@ -3848,11 +3974,155 @@ void BlockchainLMDB::migrate_0_1()
txn.commit();
}
+void BlockchainLMDB::migrate_1_2()
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ uint64_t i, z;
+ int result;
+ mdb_txn_safe txn(false);
+ MDB_val k, v;
+ char *ptr;
+
+ MGINFO_YELLOW("Migrating blockchain from DB version 1 to 2 - this may take a while:");
+ MINFO("updating txs_pruned and txs_prunable tables...");
+
+ do {
+ 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_txs;
+ MDB_stat db_stats_txs_pruned;
+ MDB_stat db_stats_txs_prunable;
+ MDB_stat db_stats_txs_prunable_hash;
+ if ((result = mdb_stat(txn, m_txs, &db_stats_txs)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_txs: ", result).c_str()));
+ if ((result = mdb_stat(txn, m_txs_pruned, &db_stats_txs_pruned)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_txs_pruned: ", result).c_str()));
+ if ((result = mdb_stat(txn, m_txs_prunable, &db_stats_txs_prunable)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_txs_prunable: ", result).c_str()));
+ if ((result = mdb_stat(txn, m_txs_prunable_hash, &db_stats_txs_prunable_hash)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_txs_prunable_hash: ", result).c_str()));
+ if (db_stats_txs_pruned.ms_entries != db_stats_txs_prunable.ms_entries)
+ throw0(DB_ERROR("Mismatched sizes for txs_pruned and txs_prunable"));
+ if (db_stats_txs_pruned.ms_entries == db_stats_txs.ms_entries)
+ {
+ txn.commit();
+ MINFO("txs already migrated");
+ break;
+ }
+
+ MINFO("updating txs tables:");
+
+ MDB_cursor *c_old, *c_cur0, *c_cur1, *c_cur2;
+ i = 0;
+
+ while(1) {
+ if (!(i % 1000)) {
+ if (i) {
+ result = mdb_stat(txn, m_txs, &db_stats_txs);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to query m_txs: ", result).c_str()));
+ LOGIF(el::Level::Info) {
+ std::cout << i << " / " << (i + db_stats_txs.ms_entries) << " \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_txs_pruned, &c_cur0);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs_pruned: ", result).c_str()));
+ result = mdb_cursor_open(txn, m_txs_prunable, &c_cur1);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs_prunable: ", result).c_str()));
+ result = mdb_cursor_open(txn, m_txs_prunable_hash, &c_cur2);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs_prunable_hash: ", result).c_str()));
+ result = mdb_cursor_open(txn, m_txs, &c_old);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs: ", result).c_str()));
+ if (!i) {
+ i = db_stats_txs_pruned.ms_entries;
+ }
+ }
+ MDB_val_set(k, i);
+ result = mdb_cursor_get(c_old, &k, &v, MDB_SET);
+ if (result == MDB_NOTFOUND) {
+ txn.commit();
+ break;
+ }
+ else if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to get a record from txs: ", result).c_str()));
+
+ cryptonote::blobdata bd;
+ bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
+ transaction tx;
+ if (!parse_and_validate_tx_from_blob(bd, tx))
+ throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
+ std::stringstream ss;
+ binary_archive<true> ba(ss);
+ bool r = tx.serialize_base(ba);
+ if (!r)
+ throw0(DB_ERROR("Failed to serialize pruned tx"));
+ std::string pruned = ss.str();
+
+ if (pruned.size() > bd.size())
+ throw0(DB_ERROR("Pruned tx is larger than raw tx"));
+ if (memcmp(pruned.data(), bd.data(), pruned.size()))
+ throw0(DB_ERROR("Pruned tx is not a prefix of the raw tx"));
+
+ MDB_val nv;
+ nv.mv_data = (void*)pruned.data();
+ nv.mv_size = pruned.size();
+ result = mdb_cursor_put(c_cur0, (MDB_val *)&k, &nv, 0);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to put a record into txs_pruned: ", result).c_str()));
+
+ nv.mv_data = (void*)(bd.data() + pruned.size());
+ nv.mv_size = bd.size() - pruned.size();
+ result = mdb_cursor_put(c_cur1, (MDB_val *)&k, &nv, 0);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to put a record into txs_prunable: ", result).c_str()));
+
+ if (tx.version > 1)
+ {
+ crypto::hash prunable_hash = get_transaction_prunable_hash(tx);
+ MDB_val_set(val_prunable_hash, prunable_hash);
+ result = mdb_cursor_put(c_cur2, (MDB_val *)&k, &val_prunable_hash, 0);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to put a record into txs_prunable_hash: ", result).c_str()));
+ }
+
+ result = mdb_cursor_del(c_old, 0);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to delete a record from txs: ", result).c_str()));
+
+ i++;
+ }
+ } while(0);
+
+ uint32_t version = 2;
+ 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) {
case 0:
migrate_0_1(); /* FALLTHRU */
+ case 1:
+ migrate_1_2(); /* FALLTHRU */
default:
;
}
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index f1773bac8..cc1b06ca0 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -50,6 +50,9 @@ typedef struct mdb_txn_cursors
MDB_cursor *m_txc_output_amounts;
MDB_cursor *m_txc_txs;
+ MDB_cursor *m_txc_txs_pruned;
+ MDB_cursor *m_txc_txs_prunable;
+ MDB_cursor *m_txc_txs_prunable_hash;
MDB_cursor *m_txc_tx_indices;
MDB_cursor *m_txc_tx_outputs;
@@ -67,6 +70,9 @@ typedef struct mdb_txn_cursors
#define m_cur_output_txs m_cursors->m_txc_output_txs
#define m_cur_output_amounts m_cursors->m_txc_output_amounts
#define m_cur_txs m_cursors->m_txc_txs
+#define m_cur_txs_pruned m_cursors->m_txc_txs_pruned
+#define m_cur_txs_prunable m_cursors->m_txc_txs_prunable
+#define m_cur_txs_prunable_hash m_cursors->m_txc_txs_prunable_hash
#define m_cur_tx_indices m_cursors->m_txc_tx_indices
#define m_cur_tx_outputs m_cursors->m_txc_tx_outputs
#define m_cur_spent_keys m_cursors->m_txc_spent_keys
@@ -83,6 +89,9 @@ typedef struct mdb_rflags
bool m_rf_output_txs;
bool m_rf_output_amounts;
bool m_rf_txs;
+ bool m_rf_txs_pruned;
+ bool m_rf_txs_prunable;
+ bool m_rf_txs_prunable_hash;
bool m_rf_tx_indices;
bool m_rf_tx_outputs;
bool m_rf_spent_keys;
@@ -218,6 +227,8 @@ public:
virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const;
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
+ virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
+ virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const;
virtual uint64_t get_tx_count() const;
@@ -254,7 +265,7 @@ public:
virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const;
virtual bool for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::function<bool(uint64_t, const crypto::hash&, const cryptonote::block&)>) const;
- virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>) const;
+ virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const;
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const;
virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const;
@@ -311,7 +322,7 @@ private:
virtual void remove_block();
- virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash);
+ virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash);
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx);
@@ -373,6 +384,9 @@ private:
// migrate from DB version 0 to 1
void migrate_0_1();
+ // migrate from DB version 1 to 2
+ void migrate_1_2();
+
void cleanup_batch();
private:
@@ -383,6 +397,9 @@ private:
MDB_dbi m_block_info;
MDB_dbi m_txs;
+ MDB_dbi m_txs_pruned;
+ MDB_dbi m_txs_prunable;
+ MDB_dbi m_txs_prunable_hash;
MDB_dbi m_tx_indices;
MDB_dbi m_tx_outputs;
diff --git a/src/blockchain_utilities/blockchain_usage.cpp b/src/blockchain_utilities/blockchain_usage.cpp
index 7c3c83167..b78f3591b 100644
--- a/src/blockchain_utilities/blockchain_usage.cpp
+++ b/src/blockchain_utilities/blockchain_usage.cpp
@@ -234,7 +234,7 @@ int main(int argc, char* argv[])
}
}
return true;
- });
+ }, true);
std::unordered_map<uint64_t, uint64_t> counts;
size_t total = 0;
diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat
index cff103804..501a55673 100644
--- a/src/blocks/checkpoints.dat
+++ b/src/blocks/checkpoints.dat
Binary files differ
diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp
index 2c11af4b2..ef1ee171d 100644
--- a/src/checkpoints/checkpoints.cpp
+++ b/src/checkpoints/checkpoints.cpp
@@ -207,7 +207,7 @@ namespace cryptonote
ADD_CHECKPOINT(1390000, "a8f5649dd4ded60eedab475f2bec8c934681c07e3cf640e9be0617554f13ff6c");
ADD_CHECKPOINT(1450000, "ac94e8860093bc7c83e4e91215cba1d663421ecf4067a0ae609c3a8b52bcfac2");
ADD_CHECKPOINT(1530000, "01759bce497ec38e63c78b1038892169203bb78f87e488172f6b854fcd63ba7e");
-
+ ADD_CHECKPOINT(1579000, "7d0d7a2346373afd41ed1e744a939fc5d474a7dbaa257be5c6fff4009e789241");
return true;
}
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 3c6885896..428be1c9c 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -779,6 +779,61 @@ namespace cryptonote
return get_transaction_hash(t, res, NULL);
}
//---------------------------------------------------------------
+ bool calculate_transaction_prunable_hash(const transaction& t, crypto::hash& res)
+ {
+ if (t.version == 1)
+ return false;
+ transaction &tt = const_cast<transaction&>(t);
+ std::stringstream ss;
+ binary_archive<true> ba(ss);
+ const size_t inputs = t.vin.size();
+ const size_t outputs = t.vout.size();
+ const size_t mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(t.vin[0]).key_offsets.size() - 1 : 0;
+ bool r = tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin);
+ CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures prunable");
+ cryptonote::get_blob_hash(ss.str(), res);
+ return true;
+ }
+ //---------------------------------------------------------------
+ crypto::hash get_transaction_prunable_hash(const transaction& t)
+ {
+ crypto::hash res;
+ CHECK_AND_ASSERT_THROW_MES(calculate_transaction_prunable_hash(t, res), "Failed to calculate tx prunable hash");
+ return res;
+ }
+ //---------------------------------------------------------------
+ crypto::hash get_pruned_transaction_hash(const transaction& t, const crypto::hash &pruned_data_hash)
+ {
+ // v1 transactions hash the entire blob
+ CHECK_AND_ASSERT_THROW_MES(t.version > 1, "Hash for pruned v1 tx cannot be calculated");
+
+ // v2 transactions hash different parts together, than hash the set of those hashes
+ crypto::hash hashes[3];
+
+ // prefix
+ get_transaction_prefix_hash(t, hashes[0]);
+
+ transaction &tt = const_cast<transaction&>(t);
+
+ // base rct
+ {
+ std::stringstream ss;
+ binary_archive<true> ba(ss);
+ const size_t inputs = t.vin.size();
+ const size_t outputs = t.vout.size();
+ bool r = tt.rct_signatures.serialize_rctsig_base(ba, inputs, outputs);
+ CHECK_AND_ASSERT_THROW_MES(r, "Failed to serialize rct signatures base");
+ cryptonote::get_blob_hash(ss.str(), hashes[1]);
+ }
+
+ // prunable rct
+ hashes[2] = pruned_data_hash;
+
+ // the tx hash is the hash of the 3 hashes
+ crypto::hash res = cn_fast_hash(hashes, sizeof(hashes));
+ return res;
+ }
+ //---------------------------------------------------------------
bool calculate_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size)
{
// v1 transactions hash the entire blob
@@ -814,14 +869,7 @@ namespace cryptonote
}
else
{
- std::stringstream ss;
- binary_archive<true> ba(ss);
- const size_t inputs = t.vin.size();
- const size_t outputs = t.vout.size();
- const size_t mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(t.vin[0]).key_offsets.size() - 1 : 0;
- bool r = tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin);
- CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures prunable");
- cryptonote::get_blob_hash(ss.str(), hashes[2]);
+ CHECK_AND_ASSERT_MES(calculate_transaction_prunable_hash(t, hashes[2]), false, "Failed to get tx prunable hash");
}
// the tx hash is the hash of the 3 hashes
diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h
index 79466e9c4..8a5296d5b 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.h
+++ b/src/cryptonote_basic/cryptonote_format_utils.h
@@ -100,7 +100,11 @@ namespace cryptonote
bool get_transaction_hash(const transaction& t, crypto::hash& res);
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size);
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size);
+ bool calculate_transaction_prunable_hash(const transaction& t, crypto::hash& res);
+ crypto::hash get_transaction_prunable_hash(const transaction& t);
bool calculate_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size);
+ crypto::hash get_pruned_transaction_hash(const transaction& t, const crypto::hash &pruned_data_hash);
+
blobdata get_block_hashing_blob(const block& b);
bool calculate_block_hash(const block& b, crypto::hash& res);
bool get_block_hash(const block& b, crypto::hash& res);
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index d1ef7d6fe..0661b8409 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -156,7 +156,9 @@ static const struct {
//------------------------------------------------------------------
Blockchain::Blockchain(tx_memory_pool& tx_pool) :
m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_current_block_cumul_sz_median(0),
- m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false)
+ m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false),
+ m_difficulty_for_next_block_top_hash(crypto::null_hash),
+ m_difficulty_for_next_block(1)
{
LOG_PRINT_L3("Blockchain::" << __func__);
}
@@ -804,7 +806,17 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
difficulty_type Blockchain::get_difficulty_for_next_block()
{
LOG_PRINT_L3("Blockchain::" << __func__);
- CRITICAL_REGION_LOCAL(m_blockchain_lock);
+
+ CRITICAL_REGION_LOCAL(m_difficulty_lock);
+ // we can call this without the blockchain lock, it might just give us
+ // something a bit out of date, but that's fine since anything which
+ // requires the blockchain lock will have acquired it in the first place,
+ // and it will be unlocked only when called from the getinfo RPC
+ crypto::hash top_hash = get_tail_id();
+ if (top_hash == m_difficulty_for_next_block_top_hash)
+ return m_difficulty_for_next_block;
+
+ CRITICAL_REGION_LOCAL1(m_blockchain_lock);
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> difficulties;
auto height = m_db->height();
@@ -847,7 +859,10 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
m_difficulties = difficulties;
}
size_t target = get_difficulty_target();
- return next_difficulty(timestamps, difficulties, target);
+ difficulty_type diff = next_difficulty(timestamps, difficulties, target);
+ m_difficulty_for_next_block_top_hash = top_hash;
+ m_difficulty_for_next_block = diff;
+ return diff;
}
//------------------------------------------------------------------
// This function removes blocks from the blockchain until it gets to the
@@ -1195,6 +1210,12 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
b.prev_id = get_tail_id();
b.timestamp = time(NULL);
+ uint64_t median_ts;
+ if (!check_block_timestamp(b, median_ts))
+ {
+ b.timestamp = median_ts;
+ }
+
diffic = get_difficulty_for_next_block();
CHECK_AND_ASSERT_MES(diffic, false, "difficulty overhead.");
@@ -2092,7 +2113,7 @@ bool Blockchain::get_blocks(const t_ids_container& block_ids, t_blocks_container
//TODO: return type should be void, throw on exception
// alternatively, return true only if no transactions missed
template<class t_ids_container, class t_tx_container, class t_missed_container>
-bool Blockchain::get_transactions_blobs(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const
+bool Blockchain::get_transactions_blobs(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs, bool pruned) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@@ -2102,7 +2123,9 @@ bool Blockchain::get_transactions_blobs(const t_ids_container& txs_ids, t_tx_con
try
{
cryptonote::blobdata tx;
- if (m_db->get_tx_blob(tx_hash, tx))
+ if (pruned && m_db->get_pruned_tx_blob(tx_hash, tx))
+ txs.push_back(std::move(tx));
+ else if (!pruned && m_db->get_tx_blob(tx_hash, tx))
txs.push_back(std::move(tx));
else
missed_txs.push_back(tx_hash);
@@ -2187,7 +2210,7 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
// find split point between ours and foreign blockchain (or start at
// blockchain height <req_start_block>), and return up to max_count FULL
// blocks by reference.
-bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const
+bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, size_t max_count) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@@ -2220,7 +2243,7 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons
block b;
CHECK_AND_ASSERT_MES(parse_and_validate_block_from_blob(blocks.back().first, b), false, "internal error, invalid block");
std::list<crypto::hash> mis;
- get_transactions_blobs(b.tx_hashes, blocks.back().second, mis);
+ get_transactions_blobs(b.tx_hashes, blocks.back().second, mis, pruned);
CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, transaction from block not found");
size += blocks.back().first.size();
for (const auto &t: blocks.back().second)
@@ -3165,10 +3188,10 @@ uint64_t Blockchain::get_adjusted_time() const
}
//------------------------------------------------------------------
//TODO: revisit, has changed a bit on upstream
-bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const block& b) const
+bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const block& b, uint64_t& median_ts) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
- uint64_t median_ts = epee::misc_utils::median(timestamps);
+ median_ts = epee::misc_utils::median(timestamps);
if(b.timestamp < median_ts)
{
@@ -3186,7 +3209,7 @@ bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const
// true if the block's timestamp is not less than the timestamp of the
// median of the selected blocks
// false otherwise
-bool Blockchain::check_block_timestamp(const block& b) const
+bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
if(b.timestamp > get_adjusted_time() + CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT)
@@ -3211,7 +3234,7 @@ bool Blockchain::check_block_timestamp(const block& b) const
timestamps.push_back(m_db->get_block_timestamp(offset));
}
- return check_block_timestamp(timestamps, b);
+ return check_block_timestamp(timestamps, b, median_ts);
}
//------------------------------------------------------------------
void Blockchain::return_tx_to_pool(std::vector<transaction> &txs)
@@ -4403,7 +4426,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
-static const char expected_block_hashes_hash[] = "1d3df1a177bd6f752d87c0d7b960e502605742721afb39953265f1e0f7f9b01f";
+static const char expected_block_hashes_hash[] = "59261c03b54bcb21bd463f9fe40a94f40840a12642e9a3b3bfb11b35839a5fe3";
void Blockchain::load_compiled_in_block_hashes()
{
const bool testnet = m_nettype == TESTNET;
@@ -4514,9 +4537,9 @@ bool Blockchain::for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::f
return m_db->for_blocks_range(h1, h2, f);
}
-bool Blockchain::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f) const
+bool Blockchain::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f, bool pruned) const
{
- return m_db->for_all_transactions(f);
+ return m_db->for_all_transactions(f, pruned);
}
bool Blockchain::for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const
@@ -4531,4 +4554,5 @@ bool Blockchain::for_all_outputs(uint64_t amount, std::function<bool(uint64_t he
namespace cryptonote {
template bool Blockchain::get_transactions(const std::vector<crypto::hash>&, std::list<transaction>&, std::list<crypto::hash>&) const;
+template bool Blockchain::get_transactions_blobs(const std::vector<crypto::hash>&, std::list<cryptonote::blobdata>&, std::list<crypto::hash>&, bool) const;
}
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index f58885812..769e608ca 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -415,11 +415,12 @@ namespace cryptonote
* @param blocks return-by-reference the blocks and their transactions
* @param total_height return-by-reference our current blockchain height
* @param start_height return-by-reference the height of the first block returned
+ * @param pruned whether to return full or pruned tx blobs
* @param max_count the max number of blocks to get
*
* @return true if a block found in common or req_start_block specified, else false
*/
- bool find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const;
+ bool find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, size_t max_count) const;
/**
* @brief retrieves a set of blocks and their transactions, and possibly other transactions
@@ -679,11 +680,12 @@ namespace cryptonote
* @param txs_ids a container of hashes for which to get the corresponding transactions
* @param txs return-by-reference a container to store result transactions in
* @param missed_txs return-by-reference a container to store missed transactions in
+ * @param pruned whether to return full or pruned blobs
*
* @return false if an unexpected exception occurs, else true
*/
template<class t_ids_container, class t_tx_container, class t_missed_container>
- bool get_transactions_blobs(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const;
+ bool get_transactions_blobs(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs, bool pruned = false) const;
template<class t_ids_container, class t_tx_container, class t_missed_container>
bool get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const;
@@ -858,10 +860,11 @@ namespace cryptonote
* @brief perform a check on all transactions in the blockchain
*
* @param std::function the check to perform, pass/fail
+ * @param bool pruned whether to return pruned txes only
*
* @return false if any transaction fails the check, otherwise true
*/
- bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>) const;
+ bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const;
/**
* @brief perform a check on all outputs in the blockchain
@@ -1008,6 +1011,10 @@ namespace cryptonote
std::vector<difficulty_type> m_difficulties;
uint64_t m_timestamps_and_difficulties_height;
+ epee::critical_section m_difficulty_lock;
+ crypto::hash m_difficulty_for_next_block_top_hash;
+ difficulty_type m_difficulty_for_next_block;
+
boost::asio::io_service m_async_service;
boost::thread_group m_async_pool;
std::unique_ptr<boost::asio::io_service::work> m_async_work_idle;
@@ -1293,10 +1300,12 @@ namespace cryptonote
* false otherwise
*
* @param b the block to be checked
+ * @param median_ts return-by-reference the median of timestamps
*
* @return true if the block's timestamp is valid, otherwise false
*/
- bool check_block_timestamp(const block& b) const;
+ bool check_block_timestamp(const block& b, uint64_t& median_ts) const;
+ bool check_block_timestamp(const block& b) const { uint64_t median_ts; return check_block_timestamp(b, median_ts); }
/**
* @brief checks a block's timestamp
@@ -1309,7 +1318,8 @@ namespace cryptonote
*
* @return true if the block's timestamp is valid, otherwise false
*/
- bool check_block_timestamp(std::vector<uint64_t>& timestamps, const block& b) const;
+ bool check_block_timestamp(std::vector<uint64_t>& timestamps, const block& b, uint64_t& median_ts) const;
+ bool check_block_timestamp(std::vector<uint64_t>& timestamps, const block& b) const { uint64_t median_ts; return check_block_timestamp(timestamps, b, median_ts); }
/**
* @brief get the "adjusted time"
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 668e7a2b7..d2796deeb 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1054,9 +1054,9 @@ namespace cryptonote
return m_blockchain_storage.find_blockchain_supplement(qblock_ids, resp);
}
//-----------------------------------------------------------------------------------------------
- bool core::find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const
+ bool core::find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, size_t max_count) const
{
- return m_blockchain_storage.find_blockchain_supplement(req_start_block, qblock_ids, blocks, total_height, start_height, max_count);
+ return m_blockchain_storage.find_blockchain_supplement(req_start_block, qblock_ids, blocks, total_height, start_height, pruned, max_count);
}
//-----------------------------------------------------------------------------------------------
bool core::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) const
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index f3b9dddc0..17b5680e5 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -517,7 +517,7 @@ namespace cryptonote
*
* @note see Blockchain::find_blockchain_supplement(const uint64_t, const std::list<crypto::hash>&, std::list<std::pair<cryptonote::blobdata, std::list<transaction> > >&, uint64_t&, uint64_t&, size_t) const
*/
- bool find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const;
+ bool find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, size_t max_count) const;
/**
* @brief gets some stats about the daemon
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 5dfbc1dd4..bf1fe476e 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -1068,10 +1068,6 @@ namespace cryptonote
//TODO: investigate whether boolean return is appropriate
bool tx_memory_pool::fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t &expected_reward, uint8_t version)
{
- // Warning: This function takes already_generated_
- // coins as an argument and appears to do nothing
- // with it.
-
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index e28914d96..b5ef2557a 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -219,18 +219,6 @@ namespace cryptonote
return ss.str();
}
//------------------------------------------------------------------------------------------------------------------------------
- static cryptonote::blobdata get_pruned_tx_blob(const cryptonote::blobdata &blobdata)
- {
- cryptonote::transaction tx;
-
- if (!cryptonote::parse_and_validate_tx_from_blob(blobdata, tx))
- {
- MERROR("Failed to parse and validate tx from blob");
- return cryptonote::blobdata();
- }
- return get_pruned_tx_blob(tx);
- }
- //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res)
{
PERF_TIMER(on_get_blocks);
@@ -240,7 +228,7 @@ namespace cryptonote
std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > > bs;
- if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
+ if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, bs, res.current_height, res.start_height, req.prune, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
{
res.status = "Failed";
return false;
@@ -272,10 +260,7 @@ namespace cryptonote
for (std::list<cryptonote::blobdata>::iterator i = bd.second.begin(); i != bd.second.end(); ++i)
{
unpruned_size += i->size();
- if (req.prune)
- res.blocks.back().txs.push_back(get_pruned_tx_blob(std::move(*i)));
- else
- res.blocks.back().txs.push_back(std::move(*i));
+ res.blocks.back().txs.push_back(std::move(*i));
i->clear();
i->shrink_to_fit();
pruned_size += res.blocks.back().txs.back().size();
diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp
index 29020aa57..39f169cdf 100644
--- a/src/rpc/daemon_handler.cpp
+++ b/src/rpc/daemon_handler.cpp
@@ -52,7 +52,7 @@ namespace rpc
{
std::list<std::pair<blobdata, std::list<blobdata> > > blocks;
- if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, blocks, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
+ if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, blocks, res.current_height, res.start_height, req.prune, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
{
res.status = Message::STATUS_FAILED;
res.error_details = "core::find_blockchain_supplement() returned false";
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index d573f317b..81896ca55 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -131,6 +131,7 @@ namespace
const command_line::arg_descriptor<bool> arg_restore_multisig_wallet = {"restore-multisig-wallet", sw::tr("Recover multisig wallet using Electrum-style mnemonic seed"), false};
const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false};
const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false};
+ const command_line::arg_descriptor<bool> arg_untrusted_daemon = {"untrusted-daemon", sw::tr("Disable commands which rely on a trusted daemon"), false};
const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false};
const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0};
const command_line::arg_descriptor<bool> arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the monero network"), false};
@@ -1077,7 +1078,7 @@ bool simple_wallet::import_multisig(const std::vector<std::string> &args)
fail_msg_writer() << tr("Failed to import multisig info: ") << e.what();
return true;
}
- if (m_trusted_daemon)
+ if (is_daemon_trusted())
{
try
{
@@ -1229,7 +1230,7 @@ bool simple_wallet::submit_multisig(const std::vector<std::string> &args)
}
catch (const std::exception &e)
{
- handle_transfer_exception(std::current_exception(), m_trusted_daemon);
+ handle_transfer_exception(std::current_exception(), is_daemon_trusted());
}
catch (...)
{
@@ -3117,18 +3118,21 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
- // set --trusted-daemon if local
- try
+ // set --trusted-daemon if local and not overridden
+ if (!m_trusted_daemon)
{
- if (tools::is_local_address(m_wallet->get_daemon_address()))
+ try
{
- MINFO(tr("Daemon is local, assuming trusted"));
- m_trusted_daemon = true;
+ if (tools::is_local_address(m_wallet->get_daemon_address()))
+ {
+ MINFO(tr("Daemon is local, assuming trusted"));
+ m_trusted_daemon = true;
+ }
}
+ catch (const std::exception &e) { }
}
- catch (const std::exception &e) { }
- if (!m_trusted_daemon)
+ if (!is_daemon_trusted())
message_writer() << (boost::format(tr("Warning: using an untrusted daemon at %s, privacy will be lessened")) % m_wallet->get_daemon_address()).str();
if (m_wallet->get_ring_database().empty())
@@ -3162,7 +3166,10 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_restore_deterministic_wallet = command_line::get_arg(vm, arg_restore_deterministic_wallet);
m_restore_multisig_wallet = command_line::get_arg(vm, arg_restore_multisig_wallet);
m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic);
- m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon);
+ if (!command_line::is_arg_defaulted(vm, arg_trusted_daemon) || !command_line::is_arg_defaulted(vm, arg_untrusted_daemon))
+ m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon) && !command_line::get_arg(vm, arg_untrusted_daemon);
+ if (!command_line::is_arg_defaulted(vm, arg_trusted_daemon) && !command_line::is_arg_defaulted(vm, arg_untrusted_daemon))
+ message_writer() << tr("--trusted-daemon and --untrusted-daemon are both seen, assuming untrusted");
m_allow_mismatched_daemon_version = command_line::get_arg(vm, arg_allow_mismatched_daemon_version);
m_restore_height = command_line::get_arg(vm, arg_restore_height);
m_do_not_relay = command_line::get_arg(vm, arg_do_not_relay);
@@ -3649,7 +3656,7 @@ bool simple_wallet::save_watch_only(const std::vector<std::string> &args/* = std
//----------------------------------------------------------------------------------------------------
bool simple_wallet::start_mining(const std::vector<std::string>& args)
{
- if (!m_trusted_daemon)
+ if (!is_daemon_trusted())
{
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
return true;
@@ -3830,7 +3837,7 @@ void simple_wallet::on_skip_transaction(uint64_t height, const crypto::hash &txi
//----------------------------------------------------------------------------------------------------
bool simple_wallet::refresh_main(uint64_t start_height, bool reset, bool is_init)
{
- if (!try_connect_to_daemon())
+ if (!try_connect_to_daemon(is_init))
return true;
LOCK_IDLE_SCOPE();
@@ -4145,7 +4152,7 @@ bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::rescan_spent(const std::vector<std::string> &args)
{
- if (!m_trusted_daemon)
+ if (!is_daemon_trusted())
{
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
return true;
@@ -4491,16 +4498,16 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
return true;
}
unlock_block = bc_height + locked_blocks;
- ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, m_trusted_daemon);
+ ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
break;
case TransferNew:
- ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, m_trusted_daemon);
+ ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
break;
default:
LOG_ERROR("Unknown transfer method, using original");
/* FALLTHRU */
case TransferOriginal:
- ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_trusted_daemon);
+ ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, is_daemon_trusted());
break;
}
@@ -4676,7 +4683,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
catch (const std::exception &e)
{
- handle_transfer_exception(std::current_exception(), m_trusted_daemon);
+ handle_transfer_exception(std::current_exception(), is_daemon_trusted());
}
catch (...)
{
@@ -4713,7 +4720,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
try
{
// figure out what tx will be necessary
- auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon);
+ auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(is_daemon_trusted());
if (ptx_vector.empty())
{
@@ -4784,7 +4791,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
}
catch (const std::exception &e)
{
- handle_transfer_exception(std::current_exception(), m_trusted_daemon);
+ handle_transfer_exception(std::current_exception(), is_daemon_trusted());
}
catch (...)
{
@@ -4933,7 +4940,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, m_trusted_daemon);
+ 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());
if (ptx_vector.empty())
{
@@ -5017,7 +5024,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
}
catch (const std::exception& e)
{
- handle_transfer_exception(std::current_exception(), m_trusted_daemon);
+ handle_transfer_exception(std::current_exception(), is_daemon_trusted());
}
catch (...)
{
@@ -5146,7 +5153,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
try
{
// figure out what tx will be necessary
- auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra, m_trusted_daemon);
+ auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra, is_daemon_trusted());
if (ptx_vector.empty())
{
@@ -5216,7 +5223,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
}
catch (const std::exception& e)
{
- handle_transfer_exception(std::current_exception(), m_trusted_daemon);
+ handle_transfer_exception(std::current_exception(), is_daemon_trusted());
}
catch (...)
{
@@ -5521,7 +5528,7 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_)
}
catch (const std::exception& e)
{
- handle_transfer_exception(std::current_exception(), m_trusted_daemon);
+ handle_transfer_exception(std::current_exception(), is_daemon_trusted());
}
catch (...)
{
@@ -7109,7 +7116,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
fail_msg_writer() << tr("command not supported by HW wallet");
return true;
}
- if (!m_trusted_daemon)
+ if (!is_daemon_trusted())
{
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
return true;
@@ -7495,6 +7502,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_non_deterministic );
command_line::add_arg(desc_params, arg_electrum_seed );
command_line::add_arg(desc_params, arg_trusted_daemon);
+ command_line::add_arg(desc_params, arg_untrusted_daemon);
command_line::add_arg(desc_params, arg_allow_mismatched_daemon_version);
command_line::add_arg(desc_params, arg_restore_height);
command_line::add_arg(desc_params, arg_do_not_relay);
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 39a91c5f5..7a788d432 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -229,6 +229,7 @@ namespace cryptonote
bool print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr);
std::string get_prompt() const;
bool print_seed(bool encrypted);
+ bool is_daemon_trusted() const { return *m_trusted_daemon; }
/*!
* \brief Prints the seed with a nice message
@@ -331,7 +332,7 @@ namespace cryptonote
bool m_restore_deterministic_wallet; // recover flag
bool m_restore_multisig_wallet; // recover flag
bool m_non_deterministic; // old 2-random generation
- bool m_trusted_daemon;
+ boost::optional<bool> m_trusted_daemon;
bool m_allow_mismatched_daemon_version;
bool m_restoring; // are we restoring, by whatever method?
uint64_t m_restore_height; // optional
diff --git a/src/version.cpp.in b/src/version.cpp.in
index f83a85d9d..9fed91d99 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.0.0-master"
+#define DEF_MONERO_VERSION "0.12.1.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/wallet2.cpp b/src/wallet/wallet2.cpp
index cd3ca3245..d11c99378 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -2883,6 +2883,7 @@ bool wallet2::verify_password(const epee::wipeable_string& password) const
* \param keys_file_name Keys file to verify password for
* \param password Password to verify
* \param no_spend_key If set = only verify view keys, otherwise also spend keys
+ * \param hwdev The hardware device to use
* \return true if password is correct
*
* for verification only
@@ -2933,9 +2934,10 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip
/*!
* \brief Generates a wallet or restores one.
- * \param wallet_ Name of wallet file
- * \param password Password of wallet file
- * \param multisig_data The multisig restore info and keys
+ * \param wallet_ Name of wallet file
+ * \param password Password of wallet file
+ * \param multisig_data The multisig restore info and keys
+ * \param create_address_file Whether to create an address file
*/
void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
const std::string& multisig_data, bool create_address_file)
@@ -3028,12 +3030,13 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
/*!
* \brief Generates a wallet or restores one.
- * \param wallet_ Name of wallet file
- * \param password Password of wallet file
- * \param recovery_param If it is a restore, the recovery key
- * \param recover Whether it is a restore
- * \param two_random Whether it is a non-deterministic wallet
- * \return The secret key of the generated wallet
+ * \param wallet_ Name of wallet file
+ * \param password Password of wallet file
+ * \param recovery_param If it is a restore, the recovery key
+ * \param recover Whether it is a restore
+ * \param two_random Whether it is a non-deterministic wallet
+ * \param create_address_file Whether to create an address file
+ * \return The secret key of the generated wallet
*/
crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
const crypto::secret_key& recovery_param, bool recover, bool two_random, bool create_address_file)
@@ -3129,9 +3132,11 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
/*!
* \brief Creates a watch only wallet from a public address and a view secret key.
-* \param wallet_ Name of wallet file
-* \param password Password of wallet file
-* \param viewkey view secret key
+* \param wallet_ Name of wallet file
+* \param password Password of wallet file
+* \param account_public_address The account's public address
+* \param viewkey view secret key
+* \param create_address_file Whether to create an address file
*/
void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
const cryptonote::account_public_address &account_public_address,
@@ -3178,10 +3183,12 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
/*!
* \brief Creates a wallet from a public address and a spend/view secret key pair.
-* \param wallet_ Name of wallet file
-* \param password Password of wallet file
-* \param spendkey spend secret key
-* \param viewkey view secret key
+* \param wallet_ Name of wallet file
+* \param password Password of wallet file
+* \param account_public_address The account's public address
+* \param spendkey spend secret key
+* \param viewkey view secret key
+* \param create_address_file Whether to create an address file
*/
void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
const cryptonote::account_public_address &account_public_address,
@@ -3628,8 +3635,9 @@ void wallet2::rewrite(const std::string& wallet_name, const epee::wipeable_strin
}
/*!
* \brief Writes to a file named based on the normal wallet (doesn't generate key, assumes it's already there)
- * \param wallet_name Base name of wallet file
- * \param password Password for wallet file
+ * \param wallet_name Base name of wallet file
+ * \param password Password for wallet file
+ * \param new_keys_filename [OUT] Name of new keys file
*/
void wallet2::write_watch_only_wallet(const std::string& wallet_name, const epee::wipeable_string& password, std::string &new_keys_filename)
{
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 69b63876a..61e6927bc 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -477,21 +477,23 @@ namespace tools
bool two_random = false, bool create_address_file = false);
/*!
* \brief Creates a wallet from a public address and a spend/view secret key pair.
- * \param wallet_ Name of wallet file
- * \param password Password of wallet file
- * \param viewkey view secret key
- * \param spendkey spend secret key
- * \param create_address_file Whether to create an address file
+ * \param wallet_ Name of wallet file
+ * \param password Password of wallet file
+ * \param account_public_address The account's public address
+ * \param spendkey spend secret key
+ * \param viewkey view secret key
+ * \param create_address_file Whether to create an address file
*/
void generate(const std::string& wallet, const epee::wipeable_string& password,
const cryptonote::account_public_address &account_public_address,
const crypto::secret_key& spendkey, const crypto::secret_key& viewkey, bool create_address_file = false);
/*!
* \brief Creates a watch only wallet from a public address and a view secret key.
- * \param wallet_ Name of wallet file
- * \param password Password of wallet file
- * \param viewkey view secret key
- * \param create_address_file Whether to create an address file
+ * \param wallet_ Name of wallet file
+ * \param password Password of wallet file
+ * \param account_public_address The account's public address
+ * \param viewkey view secret key
+ * \param create_address_file Whether to create an address file
*/
void generate(const std::string& wallet, const epee::wipeable_string& password,
const cryptonote::account_public_address &account_public_address,
@@ -561,9 +563,9 @@ namespace tools
void load(const std::string& wallet, const epee::wipeable_string& password);
void store();
/*!
- * \brief store_to - stores wallet to another file(s), deleting old ones
- * \param path - path to the wallet file (keys and address filenames will be generated based on this filename)
- * \param password - password to protect new wallet (TODO: probably better save the password in the wallet object?)
+ * \brief store_to Stores wallet to another file(s), deleting old ones
+ * \param path Path to the wallet file (keys and address filenames will be generated based on this filename)
+ * \param password Password to protect new wallet (TODO: probably better save the password in the wallet object?)
*/
void store_to(const std::string &path, const epee::wipeable_string &password);
@@ -959,7 +961,7 @@ namespace tools
/*!
* \brief Set the label of the given tag.
* \param tag Tag's name (which must be non-empty).
- * \param label Tag's description.
+ * \param description Tag's description.
*/
void set_account_tag_description(const std::string& tag, const std::string& description);
diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp
index f60b18eef..7c27b9c5d 100644
--- a/tests/unit_tests/hardfork.cpp
+++ b/tests/unit_tests/hardfork.cpp
@@ -64,6 +64,8 @@ public:
virtual blobdata get_block_blob_from_height(const uint64_t& height) const { return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); }
virtual blobdata get_block_blob(const crypto::hash& h) const { return blobdata(); }
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const { return false; }
+ virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const { return false; }
+ virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const { return false; }
virtual uint64_t get_block_height(const crypto::hash& h) const { return 0; }
virtual block_header get_block_header(const crypto::hash& h) const { return block_header(); }
virtual uint64_t get_block_timestamp(const uint64_t& height) const { return 0; }
@@ -99,7 +101,7 @@ public:
virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_index) const { return std::vector<uint64_t>(); }
virtual bool has_key_image(const crypto::key_image& img) const { return false; }
virtual void remove_block() { blocks.pop_back(); }
- virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) {return 0;}
+ virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) {return 0;}
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) {}
virtual uint64_t add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) {return 0;}
virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector<uint64_t>& amount_output_indices) {}
@@ -108,7 +110,7 @@ public:
virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const { return true; }
virtual bool for_blocks_range(const uint64_t&, const uint64_t&, std::function<bool(uint64_t, const crypto::hash&, const cryptonote::block&)>) const { return true; }
- virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>) const { return true; }
+ virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const { return true; }
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const { return true; }
virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const { return true; }
virtual bool is_read_only() const { return false; }