diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a3f79f9b..fe6e147aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -413,7 +413,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug") else() set(DEFAULT_BUILD_DEBUG_UTILITIES OFF) endif() -option(BUILD_DEBUG_UTILITIES "Build debug utilities." DEFAULT_BUILD_DEBUG_UTILITIES) +option(BUILD_DEBUG_UTILITIES "Build debug utilities." ${DEFAULT_BUILD_DEBUG_UTILITIES}) if(OSSFUZZ) message(STATUS "Using OSS-Fuzz fuzzing system") diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 5f6ab66d1..916c76957 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -219,6 +219,19 @@ int main(int argc, char const * argv[]) { po::store(po::parse_config_file(config_path.string().c_str(), core_settings), vm); } + catch (const po::unknown_option &e) + { + std::string unrecognized_option = e.get_option_name(); + if (all_options.find_nothrow(unrecognized_option, false)) + { + std::cerr << "Option '" << unrecognized_option << "' is not allowed in the config file, please use it as a command line flag." << std::endl; + } + else + { + std::cerr << "Unrecognized option '" << unrecognized_option << "' in config file." << std::endl; + } + return 1; + } catch (const std::exception &e) { // log system isn't initialized yet diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 17b96ea74..1bebf3426 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1251,6 +1251,7 @@ namespace cryptonote { LOG_PRINT_L0("[on_send_raw_tx]: Failed to parse tx from hexbuff: " << req.tx_as_hex); res.status = "Failed"; + res.reason = "Hex decoding failed"; return true; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0a1d9d074..84669cd53 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3851,7 +3851,7 @@ void wallet2::detach_blockchain(uint64_t height, std::mapon_reorg(height, blocks_detached, transfers_detached); + LOG_PRINT_L0("Detached blockchain on height " << height << ", transfers detached " << transfers_detached << ", blocks detached " << blocks_detached); } //---------------------------------------------------------------------------------------------------- @@ -6930,6 +6933,24 @@ void wallet2::commit_tx(pending_tx& ptx) crypto::hash txid; txid = get_transaction_hash(ptx.tx); + + // if it's already processed, bail + if (std::find_if(m_transfers.begin(), m_transfers.end(), [&txid](const transfer_details &td) { return td.m_txid == txid; }) != m_transfers.end()) + { + MDEBUG("Transaction " << txid << " already processed"); + return; + } + if (m_unconfirmed_txs.find(txid) != m_unconfirmed_txs.end()) + { + MDEBUG("Transaction " << txid << " already processed"); + return; + } + if (m_confirmed_txs.find(txid) != m_confirmed_txs.end()) + { + MDEBUG("Transaction " << txid << " already processed"); + return; + } + crypto::hash payment_id = crypto::null_hash; std::vector dests; uint64_t amount_in = 0; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 70d03b339..c4a2879a6 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -138,6 +138,7 @@ private: public: // Full wallet callbacks virtual void on_new_block(uint64_t height, const cryptonote::block& block) {} + virtual void on_reorg(uint64_t height, uint64_t blocks_detached, size_t transfers_detached) {} virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, uint64_t burnt, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) {} virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) {} virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index) {} diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 8b984646e..36dc04fe2 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -576,9 +576,9 @@ namespace tools if (!m_wallet) return not_open(er); try { - if (req.count < 1 || req.count > 64) { + if (req.count < 1 || req.count > 65536) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Count must be between 1 and 64."; + er.message = "Count must be between 1 and 65536."; return false; } diff --git a/tests/functional_tests/transfer.py b/tests/functional_tests/transfer.py index dd15369d3..fc3906f7e 100755 --- a/tests/functional_tests/transfer.py +++ b/tests/functional_tests/transfer.py @@ -52,6 +52,7 @@ class TransferTest(): self.check_tx_notes() self.check_rescan() self.check_is_key_image_spent() + self.check_multiple_submissions() def reset(self): print('Resetting blockchain') @@ -829,6 +830,39 @@ class TransferTest(): res = daemon.is_key_image_spent(ki) assert res.spent_status == expected + def check_multiple_submissions(self): + daemon = Daemon() + + print('Testing multiple submissions') + + dst = {'address': '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 'amount': 1000000000000} + + self.wallet[0].refresh() + res = self.wallet[0].get_balance() + balance = res.balance + + res = self.wallet[0].transfer([dst], ring_size = 16, get_tx_key = False, get_tx_hex = False, get_tx_metadata = True) + tx_hex = res.tx_metadata + tx_fee = res.fee + res = self.wallet[0].relay_tx(tx_hex) + + # submit again before mined + res = self.wallet[0].relay_tx(tx_hex) + daemon.generateblocks('44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 1) + + self.wallet[0].refresh() + res = self.wallet[0].get_balance() + assert res.balance == balance - tx_fee + + balance = res.balance + + # submit again after mined + res = self.wallet[0].relay_tx(tx_hex) + daemon.generateblocks('44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 1) + + self.wallet[0].refresh() + res = self.wallet[0].get_balance() + assert res.balance == balance if __name__ == '__main__': TransferTest().run_test()