aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--README.md22
-rw-r--r--cmake/CheckLinkerFlag.cmake2
-rw-r--r--contrib/epee/include/storages/portable_storage_from_bin.h8
-rw-r--r--contrib/epee/include/storages/portable_storage_from_json.h13
-rw-r--r--contrib/epee/src/CMakeLists.txt2
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp14
-rw-r--r--src/blocks/checkpoints.datbin198276 -> 208420 bytes
-rw-r--r--src/checkpoints/checkpoints.cpp3
-rw-r--r--src/cryptonote_core/blockchain.cpp2
-rw-r--r--src/simplewallet/simplewallet.cpp3
-rw-r--r--src/version.cpp.in4
-rw-r--r--src/wallet/api/pending_transaction.cpp6
-rw-r--r--src/wallet/api/wallet.cpp26
-rw-r--r--src/wallet/api/wallet.h12
-rw-r--r--src/wallet/ringdb.cpp15
-rw-r--r--src/wallet/wallet2.cpp71
-rw-r--r--src/wallet/wallet_rpc_server.cpp2
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h2
-rw-r--r--tests/unit_tests/is_hdd.cpp4
-rw-r--r--tests/unit_tests/ringdb.cpp24
-rw-r--r--tests/unit_tests/wipeable_string.cpp8
22 files changed, 175 insertions, 70 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 75d8ba9c3..fc0ecb14b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -769,7 +769,7 @@ else()
endif()
if(APPLE)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -DGTEST_HAS_TR1_TUPLE=0")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -DGTEST_HAS_TR1_TUPLE=0")
endif()
set(DEBUG_FLAGS "-g3")
diff --git a/README.md b/README.md
index 2ded4eb51..d16b21528 100644
--- a/README.md
+++ b/README.md
@@ -180,7 +180,7 @@ invokes cmake commands as needed.
* Change to the root of the source code directory, change to the most recent release branch, and build:
cd monero
- git checkout v0.12.3.0
+ git checkout v0.13.0.0
make
*Optional*: If your machine has several cores and enough memory, enable
@@ -242,7 +242,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
```
git clone https://github.com/monero-project/monero.git
cd monero
- git checkout tags/v0.12.3.0
+ git checkout tags/v0.13.0.0
```
* Build:
```
@@ -339,9 +339,9 @@ application.
cd monero
-* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.12.3.0'. If you dont care about the version and just want binaries from master, skip this step:
+* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.13.0.0'. If you dont care about the version and just want binaries from master, skip this step:
- git checkout v0.12.3.0
+ git checkout v0.13.0.0
* If you are on a 64-bit system, run:
@@ -666,9 +666,19 @@ Type `run` to run monerod
### Analysing memory corruption
-We use the tool `valgrind` for this.
+There are two tools available:
-Run with `valgrind /path/to/monerod`. It will be slow.
+* ASAN
+
+Configure Monero with the -D SANITIZE=ON cmake flag, eg:
+
+ cd build/debug && cmake -D SANITIZE=ON -D CMAKE_BUILD_TYPE=Debug ../..
+
+You can then run the monero tools normally. Performance will typically halve.
+
+* valgrind
+
+Install valgrind and run as `valgrind /path/to/monerod`. It will be very slow.
### LMDB
diff --git a/cmake/CheckLinkerFlag.cmake b/cmake/CheckLinkerFlag.cmake
index a3879d0be..2b507ab71 100644
--- a/cmake/CheckLinkerFlag.cmake
+++ b/cmake/CheckLinkerFlag.cmake
@@ -39,7 +39,7 @@ macro(CHECK_LINKER_FLAG flag VARIABLE)
endif()
set(${VARIABLE} "" CACHE INTERNAL "Have linker flag ${flag}")
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Determining if the ${flag} linker flag is suppored "
+ "Determining if the ${flag} linker flag is supported "
"failed with the following output:\n"
"${OUTPUT}\n\n")
endif()
diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h
index 44a80cb21..f9cc22d27 100644
--- a/contrib/epee/include/storages/portable_storage_from_bin.h
+++ b/contrib/epee/include/storages/portable_storage_from_bin.h
@@ -59,6 +59,7 @@ namespace epee
storage_entry load_storage_entry();
void read(section& sec);
void read(std::string& str);
+ void read(array_entry &ae);
private:
struct recursuion_limitation_guard
{
@@ -114,6 +115,7 @@ namespace epee
void throwable_buffer_reader::read(t_pod_type& pod_val)
{
RECURSION_LIMITATION();
+ static_assert(std::is_pod<t_pod_type>::value, "POD type expected");
read(&pod_val, sizeof(pod_val));
}
@@ -277,5 +279,11 @@ namespace epee
m_ptr+=len;
m_count -= len;
}
+ inline
+ void throwable_buffer_reader::read(array_entry &ae)
+ {
+ RECURSION_LIMITATION();
+ CHECK_AND_ASSERT_THROW_MES(false, "Reading array entry is not supported");
+ }
}
}
diff --git a/contrib/epee/include/storages/portable_storage_from_json.h b/contrib/epee/include/storages/portable_storage_from_json.h
index 727f36552..5b2eafa9a 100644
--- a/contrib/epee/include/storages/portable_storage_from_json.h
+++ b/contrib/epee/include/storages/portable_storage_from_json.h
@@ -30,6 +30,8 @@
#include "parserse_base_utils.h"
#include "file_io_utils.h"
+#define EPEE_JSON_RECURSION_LIMIT_INTERNAL 100
+
namespace epee
{
using namespace misc_utils::parse;
@@ -44,8 +46,9 @@ namespace epee
ASSERT_MES_AND_THROW("json parse error");
}*/
template<class t_storage>
- inline void run_handler(typename t_storage::hsection current_section, std::string::const_iterator& sec_buf_begin, std::string::const_iterator buf_end, t_storage& stg)
+ inline void run_handler(typename t_storage::hsection current_section, std::string::const_iterator& sec_buf_begin, std::string::const_iterator buf_end, t_storage& stg, unsigned int recursion)
{
+ CHECK_AND_ASSERT_THROW_MES(recursion < EPEE_JSON_RECURSION_LIMIT_INTERNAL, "Wrong JSON data: recursion limitation (" << EPEE_JSON_RECURSION_LIMIT_INTERNAL << ") exceeded");
std::string::const_iterator sub_element_start;
std::string name;
@@ -157,7 +160,7 @@ namespace epee
//sub section here
typename t_storage::hsection new_sec = stg.open_section(name, current_section, true);
CHECK_AND_ASSERT_THROW_MES(new_sec, "Failed to insert new section in json: " << std::string(it, buf_end));
- run_handler(new_sec, it, buf_end, stg);
+ run_handler(new_sec, it, buf_end, stg, recursion + 1);
state = match_state_wonder_after_value;
}else if(*it == '[')
{//array of something
@@ -186,7 +189,7 @@ namespace epee
typename t_storage::hsection new_sec = nullptr;
h_array = stg.insert_first_section(name, new_sec, current_section);
CHECK_AND_ASSERT_THROW_MES(h_array&&new_sec, "failed to create new section");
- run_handler(new_sec, it, buf_end, stg);
+ run_handler(new_sec, it, buf_end, stg, recursion + 1);
state = match_state_array_after_value;
array_md = array_mode_sections;
}else if(*it == '"')
@@ -260,7 +263,7 @@ namespace epee
typename t_storage::hsection new_sec = NULL;
bool res = stg.insert_next_section(h_array, new_sec);
CHECK_AND_ASSERT_THROW_MES(res&&new_sec, "failed to insert next section");
- run_handler(new_sec, it, buf_end, stg);
+ run_handler(new_sec, it, buf_end, stg, recursion + 1);
state = match_state_array_after_value;
}else CHECK_ISSPACE();
break;
@@ -362,7 +365,7 @@ namespace epee
std::string::const_iterator sec_buf_begin = buff_json.begin();
try
{
- run_handler(nullptr, sec_buf_begin, buff_json.end(), stg);
+ run_handler(nullptr, sec_buf_begin, buff_json.end(), stg, 0);
return true;
}
catch(const std::exception& ex)
diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt
index 0b5e7ae6c..bc437deb9 100644
--- a/contrib/epee/src/CMakeLists.txt
+++ b/contrib/epee/src/CMakeLists.txt
@@ -54,7 +54,9 @@ endif()
target_link_libraries(epee
PUBLIC
easylogging
+ ${Boost_CHRONO_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
+ ${Boost_THREAD_LIBRARY}
PRIVATE
${OPENSSL_LIBRARIES}
${EXTRA_LIBRARIES})
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index b0f3ca5f0..d8f7df5f7 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -3490,7 +3490,17 @@ void BlockchainLMDB::fixup()
BlockchainDB::fixup();
}
-#define RENAME_DB(name) \
+#define RENAME_DB(name) do { \
+ char n2[] = name; \
+ MDB_dbi tdbi; \
+ n2[sizeof(n2)-2]--; \
+ /* play some games to put (name) on a writable page */ \
+ result = mdb_dbi_open(txn, n2, MDB_CREATE, &tdbi); \
+ if (result) \
+ throw0(DB_ERROR(lmdb_error("Failed to create " + std::string(n2) + ": ", result).c_str())); \
+ result = mdb_drop(txn, tdbi, 1); \
+ if (result) \
+ throw0(DB_ERROR(lmdb_error("Failed to delete " + std::string(n2) + ": ", result).c_str())); \
k.mv_data = (void *)name; \
k.mv_size = sizeof(name)-1; \
result = mdb_cursor_open(txn, 1, &c_cur); \
@@ -3500,7 +3510,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]++
+ ptr[sizeof(name)-2]++; } while(0)
#define LOGIF(y) if (ELPP->vRegistry()->allowed(y, "global"))
diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat
index 085558504..03e2cd2a8 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 ef1ee171d..6251fcc91 100644
--- a/src/checkpoints/checkpoints.cpp
+++ b/src/checkpoints/checkpoints.cpp
@@ -165,6 +165,7 @@ namespace cryptonote
{
ADD_CHECKPOINT(0, "48ca7cd3c8de5b6a4d53d2861fbdaedca141553559f9be9520068053cda8430b");
ADD_CHECKPOINT(1000000, "46b690b710a07ea051bc4a6b6842ac37be691089c0f7758cfeec4d5fc0b4a258");
+ ADD_CHECKPOINT(1058600, "12904f6b4d9e60fd875674e07147d2c83d6716253f046af7b894c3e81da7e1bd");
return true;
}
if (nettype == STAGENET)
@@ -208,7 +209,7 @@ namespace cryptonote
ADD_CHECKPOINT(1450000, "ac94e8860093bc7c83e4e91215cba1d663421ecf4067a0ae609c3a8b52bcfac2");
ADD_CHECKPOINT(1530000, "01759bce497ec38e63c78b1038892169203bb78f87e488172f6b854fcd63ba7e");
ADD_CHECKPOINT(1579000, "7d0d7a2346373afd41ed1e744a939fc5d474a7dbaa257be5c6fff4009e789241");
-
+ ADD_CHECKPOINT(1668900, "ac2dcaf3d2f58ffcf8391639f0f1ebafcb8eac43c49479c7c37f611868d07568");
return true;
}
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 6f1d26c5a..0e175cdbe 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -4398,7 +4398,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
-static const char expected_block_hashes_hash[] = "0924bc1c47aae448321fde949554be192878dd800e6489379865218f84eacbca";
+static const char expected_block_hashes_hash[] = "954cb2bbfa2fe6f74b2cdd22a1a4c767aea249ad47ad4f7c9445f0f03260f511";
void Blockchain::load_compiled_in_block_hashes()
{
const bool testnet = m_nettype == TESTNET;
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 302d2a999..06655ed69 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -4157,10 +4157,11 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce))
{
crypto::hash8 payment_id8 = crypto::null_hash8;
+ crypto::hash payment_id = crypto::null_hash;
if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
message_writer() <<
tr("NOTE: this transaction uses an encrypted payment ID: consider using subaddresses instead");
- else
+ else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
message_writer(console_color_red, false) <<
tr("WARNING: this transaction uses an unencrypted payment ID: consider using subaddresses instead");
}
diff --git a/src/version.cpp.in b/src/version.cpp.in
index 55ba51f50..55075a064 100644
--- a/src/version.cpp.in
+++ b/src/version.cpp.in
@@ -1,6 +1,6 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
-#define DEF_MONERO_VERSION "0.12.3.0-master"
-#define DEF_MONERO_RELEASE_NAME "Lithium Luna"
+#define DEF_MONERO_VERSION "0.13.0.1-rc"
+#define DEF_MONERO_RELEASE_NAME "Beryllium Bullet"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
#include "version.h"
diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp
index 8d200220d..913e3156f 100644
--- a/src/wallet/api/pending_transaction.cpp
+++ b/src/wallet/api/pending_transaction.cpp
@@ -200,7 +200,11 @@ std::string PendingTransactionImpl::multisigSignData() {
throw std::runtime_error("wallet is not multisig");
}
- auto cipher = m_wallet.m_wallet->save_multisig_tx(m_pending_tx);
+ tools::wallet2::multisig_tx_set txSet;
+ txSet.m_ptx = m_pending_tx;
+ txSet.m_signers = m_signers;
+ auto cipher = m_wallet.m_wallet->save_multisig_tx(txSet);
+
return epee::string_tools::buff_to_hex_nodelimer(cipher);
} catch (const std::exception& e) {
m_status = Status_Error;
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 5827e4d1a..96e5c8629 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -376,15 +376,15 @@ WalletImpl::WalletImpl(NetworkType nettype, uint64_t kdf_rounds)
, m_rebuildWalletCache(false)
, m_is_connected(false)
{
- m_wallet = new tools::wallet2(static_cast<cryptonote::network_type>(nettype), kdf_rounds, true);
- m_history = new TransactionHistoryImpl(this);
- m_wallet2Callback = new Wallet2CallbackImpl(this);
+ m_wallet = std::make_unique<tools::wallet2>(static_cast<cryptonote::network_type>(nettype), kdf_rounds, true);
+ m_history = std::make_unique<TransactionHistoryImpl>(this);
+ m_wallet2Callback = std::make_unique<Wallet2CallbackImpl>(this);
m_wallet->callback(m_wallet2Callback);
m_refreshThreadDone = false;
m_refreshEnabled = false;
- m_addressBook = new AddressBookImpl(this);
- m_subaddress = new SubaddressImpl(this);
- m_subaddressAccount = new SubaddressAccountImpl(this);
+ m_addressBook = std::make_unique<AddressBookImpl>(this);
+ m_subaddress = std::make_unique<SubaddressImpl>(this);
+ m_subaddressAccount = std::make_unique<SubaddressAccountImpl>(this);
m_refreshIntervalMillis = DEFAULT_REFRESH_INTERVAL_MILLIS;
@@ -405,12 +405,6 @@ WalletImpl::~WalletImpl()
close(false); // do not store wallet as part of the closing activities
// Stop refresh thread
stopRefresh();
- delete m_wallet2Callback;
- delete m_history;
- delete m_addressBook;
- delete m_subaddress;
- delete m_subaddressAccount;
- delete m_wallet;
LOG_PRINT_L1(__FUNCTION__ << " finished");
}
@@ -1551,22 +1545,22 @@ void WalletImpl::disposeTransaction(PendingTransaction *t)
TransactionHistory *WalletImpl::history()
{
- return m_history;
+ return m_history.get();
}
AddressBook *WalletImpl::addressBook()
{
- return m_addressBook;
+ return m_addressBook.get();
}
Subaddress *WalletImpl::subaddress()
{
- return m_subaddress;
+ return m_subaddress.get();
}
SubaddressAccount *WalletImpl::subaddressAccount()
{
- return m_subaddressAccount;
+ return m_subaddressAccount.get();
}
void WalletImpl::setListener(WalletListener *l)
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 64350cee7..5963a7607 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -215,16 +215,16 @@ private:
friend class SubaddressImpl;
friend class SubaddressAccountImpl;
- tools::wallet2 * m_wallet;
+ std::unique_ptr<tools::wallet2> m_wallet;
mutable boost::mutex m_statusMutex;
mutable int m_status;
mutable std::string m_errorString;
std::string m_password;
- TransactionHistoryImpl * m_history;
- Wallet2CallbackImpl * m_wallet2Callback;
- AddressBookImpl * m_addressBook;
- SubaddressImpl * m_subaddress;
- SubaddressAccountImpl * m_subaddressAccount;
+ std::unique_ptr<TransactionHistoryImpl> m_history;
+ std::unique_ptr<Wallet2CallbackImpl> m_wallet2Callback;
+ std::unique_ptr<AddressBookImpl> m_addressBook;
+ std::unique_ptr<SubaddressImpl> m_subaddress;
+ std::unique_ptr<SubaddressAccountImpl> m_subaddressAccount;
// multi-threaded refresh stuff
std::atomic<bool> m_refreshEnabled;
diff --git a/src/wallet/ringdb.cpp b/src/wallet/ringdb.cpp
index e9fc6866d..e5995e7fb 100644
--- a/src/wallet/ringdb.cpp
+++ b/src/wallet/ringdb.cpp
@@ -398,6 +398,8 @@ bool ringdb::blackball_worker(const std::vector<std::pair<uint64_t, uint64_t>> &
epee::misc_utils::auto_scope_leave_caller txn_dtor = epee::misc_utils::create_scope_leave_handler([&](){if (tx_active) mdb_txn_abort(txn);});
tx_active = true;
+ dbr = mdb_cursor_open(txn, dbi_blackballs, &cursor);
+ THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create cursor for blackballs table: " + std::string(mdb_strerror(dbr)));
MDB_val key, data;
for (const std::pair<uint64_t, uint64_t> &output: outputs)
@@ -411,25 +413,22 @@ bool ringdb::blackball_worker(const std::vector<std::pair<uint64_t, uint64_t>> &
{
case BLACKBALL_BLACKBALL:
MDEBUG("Blackballing output " << output.first << "/" << output.second);
- dbr = mdb_put(txn, dbi_blackballs, &key, &data, MDB_APPENDDUP);
+ dbr = mdb_cursor_put(cursor, &key, &data, MDB_APPENDDUP);
if (dbr == MDB_KEYEXIST)
dbr = 0;
break;
case BLACKBALL_UNBLACKBALL:
MDEBUG("Unblackballing output " << output.first << "/" << output.second);
- dbr = mdb_del(txn, dbi_blackballs, &key, &data);
- if (dbr == MDB_NOTFOUND)
- dbr = 0;
+ dbr = mdb_cursor_get(cursor, &key, &data, MDB_GET_BOTH);
+ if (dbr == 0)
+ dbr = mdb_cursor_del(cursor, 0);
break;
case BLACKBALL_QUERY:
- dbr = mdb_cursor_open(txn, dbi_blackballs, &cursor);
- THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create cursor for blackballs table: " + std::string(mdb_strerror(dbr)));
dbr = mdb_cursor_get(cursor, &key, &data, MDB_GET_BOTH);
THROW_WALLET_EXCEPTION_IF(dbr && dbr != MDB_NOTFOUND, tools::error::wallet_internal_error, "Failed to lookup in blackballs table: " + std::string(mdb_strerror(dbr)));
ret = dbr != MDB_NOTFOUND;
if (dbr == MDB_NOTFOUND)
dbr = 0;
- mdb_cursor_close(cursor);
break;
case BLACKBALL_CLEAR:
break;
@@ -439,6 +438,8 @@ bool ringdb::blackball_worker(const std::vector<std::pair<uint64_t, uint64_t>> &
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to query blackballs table: " + std::string(mdb_strerror(dbr)));
}
+ mdb_cursor_close(cursor);
+
if (op == BLACKBALL_CLEAR)
{
dbr = mdb_drop(txn, dbi_blackballs, 0);
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 00b40fef8..33699cb79 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1344,6 +1344,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
size_t pk_index = 0;
std::vector<tx_scan_info_t> tx_scan_info(tx.vout.size());
std::deque<bool> output_found(tx.vout.size(), false);
+ uint64_t total_received_1 = 0;
while (!tx.vout.empty())
{
// if tx.vout is not empty, we loop through all tx pubkeys
@@ -1518,6 +1519,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
+ ", m_transfers.size() is " + boost::lexical_cast<std::string>(m_transfers.size()));
if (kit == m_pub_keys.end())
{
+ uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount;
if (!pool)
{
m_transfers.push_back(boost::value_initialized<transfer_details>());
@@ -1530,14 +1532,13 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_key_image = tx_scan_info[o].ki;
td.m_key_image_known = !m_watch_only && !m_multisig;
td.m_key_image_partial = m_multisig;
- td.m_amount = tx.vout[o].amount;
+ td.m_amount = amount;
td.m_pk_index = pk_index - 1;
td.m_subaddr_index = tx_scan_info[o].received->index;
expand_subaddresses(tx_scan_info[o].received->index);
- if (td.m_amount == 0)
+ if (tx.vout[o].amount == 0)
{
td.m_mask = tx_scan_info[o].mask;
- td.m_amount = tx_scan_info[o].amount;
td.m_rct = true;
}
else if (miner_tx && tx.version == 2)
@@ -1565,6 +1566,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
if (0 != m_callback)
m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index);
}
+ total_received_1 += amount;
}
else if (m_transfers[kit->second].m_spent || m_transfers[kit->second].amount() >= tx_scan_info[o].amount)
{
@@ -1572,6 +1574,9 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
<< " from received " << print_money(tx_scan_info[o].amount) << " output already exists with "
<< (m_transfers[kit->second].m_spent ? "spent" : "unspent") << " "
<< print_money(m_transfers[kit->second].amount()) << " in tx " << m_transfers[kit->second].m_txid << ", received output ignored");
+ THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info[o].received->index] < tx_scan_info[o].amount,
+ error::wallet_internal_error, "Unexpected values of new and old outputs");
+ tx_money_got_in_outs[tx_scan_info[o].received->index] -= tx_scan_info[o].amount;
}
else
{
@@ -1579,8 +1584,14 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
<< " from received " << print_money(tx_scan_info[o].amount) << " output already exists with "
<< print_money(m_transfers[kit->second].amount()) << ", replacing with new output");
// The new larger output replaced a previous smaller one
- tx_money_got_in_outs[tx_scan_info[o].received->index] -= tx_scan_info[o].amount;
-
+ THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info[o].received->index] < tx_scan_info[o].amount,
+ error::wallet_internal_error, "Unexpected values of new and old outputs");
+ THROW_WALLET_EXCEPTION_IF(m_transfers[kit->second].amount() > tx_scan_info[o].amount,
+ error::wallet_internal_error, "Unexpected values of new and old outputs");
+ tx_money_got_in_outs[tx_scan_info[o].received->index] -= m_transfers[kit->second].amount();
+
+ uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount;
+ uint64_t extra_amount = amount - m_transfers[kit->second].amount();
if (!pool)
{
transfer_details &td = m_transfers[kit->second];
@@ -1589,14 +1600,13 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_global_output_index = o_indices[o];
td.m_tx = (const cryptonote::transaction_prefix&)tx;
td.m_txid = txid;
- td.m_amount = tx.vout[o].amount;
+ td.m_amount = amount;
td.m_pk_index = pk_index - 1;
td.m_subaddr_index = tx_scan_info[o].received->index;
expand_subaddresses(tx_scan_info[o].received->index);
- if (td.m_amount == 0)
+ if (tx.vout[o].amount == 0)
{
td.m_mask = tx_scan_info[o].mask;
- td.m_amount = tx_scan_info[o].amount;
td.m_rct = true;
}
else if (miner_tx && tx.version == 2)
@@ -1623,6 +1633,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
if (0 != m_callback)
m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index);
}
+ total_received_1 += extra_amount;
}
}
}
@@ -1744,6 +1755,20 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
}
}
+ uint64_t total_received_2 = 0;
+ for (const auto& i : tx_money_got_in_outs)
+ total_received_2 += i.second;
+ if (total_received_1 != total_received_2)
+ {
+ const el::Level level = el::Level::Warning;
+ MCLOG_RED(level, "global", "**********************************************************************");
+ MCLOG_RED(level, "global", "Consistency failure in amounts received");
+ MCLOG_RED(level, "global", "Check transaction " << txid);
+ MCLOG_RED(level, "global", "**********************************************************************");
+ exit(1);
+ return;
+ }
+
for (const auto& i : tx_money_got_in_outs)
{
payment_details payment;
@@ -6698,11 +6723,23 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
}
// while we still need more mixins
+ uint64_t num_usable_outs = num_outs;
+ bool allow_blackballed = false;
while (num_found < requested_outputs_count)
{
// if we've gone through every possible output, we've gotten all we can
- if (seen_indices.size() == num_outs)
- break;
+ if (seen_indices.size() == num_usable_outs)
+ {
+ // there is a first pass which rejects blackballed outputs, then a second pass
+ // which allows them if we don't have enough non blackballed outputs to reach
+ // the required amount of outputs (since consensus does not care about blackballed
+ // outputs, we still need to reach the minimum ring size)
+ if (allow_blackballed)
+ break;
+ MINFO("Not enough non blackballed outputs, we'll allow blackballed ones");
+ allow_blackballed = true;
+ num_usable_outs = num_outs;
+ }
// get a random output index from the DB. If we've already seen it,
// return to the top of the loop and try again, otherwise add it to the
@@ -6776,14 +6813,26 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (seen_indices.count(i))
continue;
- if (is_output_blackballed(std::make_pair(amount, i))) // don't add blackballed outputs
+ if (!allow_blackballed && is_output_blackballed(std::make_pair(amount, i))) // don't add blackballed outputs
+ {
+ --num_usable_outs;
continue;
+ }
seen_indices.emplace(i);
LOG_PRINT_L2("picking " << i << " as " << type);
req.outputs.push_back({amount, i});
++num_found;
}
+
+ // if we had enough unusable outputs, we might fall off here and still
+ // have too few outputs, so we stuff with one to keep counts good, and
+ // we'll error out later
+ while (num_found < requested_outputs_count)
+ {
+ req.outputs.push_back({amount, 0});
+ ++num_found;
+ }
}
// sort the subsection, to ensure the daemon doesn't know which output is ours
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index e6eb64d12..27631187c 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -1554,7 +1554,7 @@ namespace tools
rpc_transfers.global_index = td.m_global_output_index;
rpc_transfers.tx_hash = epee::string_tools::pod_to_hex(td.m_txid);
rpc_transfers.subaddr_index = {td.m_subaddr_index.major, td.m_subaddr_index.minor};
- rpc_transfers.key_image = req.verbose && td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : "";
+ rpc_transfers.key_image = td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : "";
res.transfers.push_back(rpc_transfers);
}
}
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 2168e0f71..81ea22928 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -883,13 +883,11 @@ namespace wallet_rpc
std::string transfer_type;
uint32_t account_index;
std::set<uint32_t> subaddr_indices;
- bool verbose;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(transfer_type)
KV_SERIALIZE(account_index)
KV_SERIALIZE(subaddr_indices)
- KV_SERIALIZE(verbose)
END_KV_SERIALIZE_MAP()
};
diff --git a/tests/unit_tests/is_hdd.cpp b/tests/unit_tests/is_hdd.cpp
index 1be670e5e..040af4f47 100644
--- a/tests/unit_tests/is_hdd.cpp
+++ b/tests/unit_tests/is_hdd.cpp
@@ -6,12 +6,12 @@
TEST(is_hdd, linux_os_root)
{
std::string path = "/";
- EXPECT_TRUE(tools::is_hdd(path.c_str()));
+ EXPECT_TRUE(tools::is_hdd(path.c_str()) != boost::none);
}
#else
TEST(is_hdd, unknown_os)
{
std::string path = "";
- EXPECT_FALSE(tools::is_hdd(path.c_str()));
+ EXPECT_FALSE(tools::is_hdd(path.c_str()) != boost::none);
}
#endif
diff --git a/tests/unit_tests/ringdb.cpp b/tests/unit_tests/ringdb.cpp
index 416ae0890..0d92049ac 100644
--- a/tests/unit_tests/ringdb.cpp
+++ b/tests/unit_tests/ringdb.cpp
@@ -150,6 +150,30 @@ TEST(blackball, found)
ASSERT_TRUE(ringdb.blackballed(OUTPUT_1));
}
+TEST(blackball, vector)
+{
+ RingDB ringdb;
+ std::vector<std::pair<uint64_t, uint64_t>> outputs;
+ outputs.push_back(std::make_pair(0, 1));
+ outputs.push_back(std::make_pair(10, 3));
+ outputs.push_back(std::make_pair(10, 4));
+ outputs.push_back(std::make_pair(10, 8));
+ outputs.push_back(std::make_pair(20, 0));
+ outputs.push_back(std::make_pair(20, 1));
+ outputs.push_back(std::make_pair(30, 5));
+ ASSERT_TRUE(ringdb.blackball(outputs));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(0, 1)));
+ ASSERT_FALSE(ringdb.blackballed(std::make_pair(10, 2)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(10, 3)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(10, 4)));
+ ASSERT_FALSE(ringdb.blackballed(std::make_pair(10, 5)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(10, 8)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(20, 0)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(20, 1)));
+ ASSERT_FALSE(ringdb.blackballed(std::make_pair(20, 2)));
+ ASSERT_TRUE(ringdb.blackballed(std::make_pair(30, 5)));
+}
+
TEST(blackball, unblackball)
{
RingDB ringdb;
diff --git a/tests/unit_tests/wipeable_string.cpp b/tests/unit_tests/wipeable_string.cpp
index 65718fd45..44e050c5c 100644
--- a/tests/unit_tests/wipeable_string.cpp
+++ b/tests/unit_tests/wipeable_string.cpp
@@ -194,13 +194,13 @@ TEST(wipeable_string, parse_hexstr)
ASSERT_EQ(boost::none, epee::wipeable_string("0").parse_hexstr());
ASSERT_EQ(boost::none, epee::wipeable_string("000").parse_hexstr());
- ASSERT_TRUE((s = epee::wipeable_string("").parse_hexstr()));
+ ASSERT_TRUE((s = epee::wipeable_string("").parse_hexstr()) != boost::none);
ASSERT_EQ(*s, "");
- ASSERT_TRUE((s = epee::wipeable_string("00").parse_hexstr()));
+ ASSERT_TRUE((s = epee::wipeable_string("00").parse_hexstr()) != boost::none);
ASSERT_EQ(*s, epee::wipeable_string("", 1));
- ASSERT_TRUE((s = epee::wipeable_string("41").parse_hexstr()));
+ ASSERT_TRUE((s = epee::wipeable_string("41").parse_hexstr()) != boost::none);
ASSERT_EQ(*s, epee::wipeable_string("A"));
- ASSERT_TRUE((s = epee::wipeable_string("414243").parse_hexstr()));
+ ASSERT_TRUE((s = epee::wipeable_string("414243").parse_hexstr()) != boost::none);
ASSERT_EQ(*s, epee::wipeable_string("ABC"));
}