diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | README.md | 22 | ||||
-rw-r--r-- | cmake/CheckLinkerFlag.cmake | 2 | ||||
-rw-r--r-- | contrib/epee/include/storages/portable_storage_from_bin.h | 8 | ||||
-rw-r--r-- | contrib/epee/include/storages/portable_storage_from_json.h | 13 | ||||
-rw-r--r-- | contrib/epee/src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/blockchain_db/lmdb/db_lmdb.cpp | 14 | ||||
-rw-r--r-- | src/blocks/checkpoints.dat | bin | 198276 -> 208420 bytes | |||
-rw-r--r-- | src/checkpoints/checkpoints.cpp | 3 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 2 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 3 | ||||
-rw-r--r-- | src/version.cpp.in | 4 | ||||
-rw-r--r-- | src/wallet/api/pending_transaction.cpp | 6 | ||||
-rw-r--r-- | src/wallet/api/wallet.cpp | 26 | ||||
-rw-r--r-- | src/wallet/api/wallet.h | 12 | ||||
-rw-r--r-- | src/wallet/ringdb.cpp | 15 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 71 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 2 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server_commands_defs.h | 2 | ||||
-rw-r--r-- | tests/unit_tests/is_hdd.cpp | 4 | ||||
-rw-r--r-- | tests/unit_tests/ringdb.cpp | 24 | ||||
-rw-r--r-- | tests/unit_tests/wipeable_string.cpp | 8 |
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") @@ -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 Binary files differindex 085558504..03e2cd2a8 100644 --- a/src/blocks/checkpoints.dat +++ b/src/blocks/checkpoints.dat 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")); } |