diff --git a/README.md b/README.md index c3ace02f5..6b28068b1 100644 --- a/README.md +++ b/README.md @@ -23,31 +23,23 @@ An Android Wallet for Wownero - Web: [wownero.org](http://wownero.org) - Twitter: [@w0wn3r0](https://twitter.com/w0wn3r0) -- Discord: [discord.gg/sQt74ep](https://discord.gg/sQt74ep) - Reddit: [/r/wownero](https://www.reddit.com/r/wownero) - Mail: [wownero@protonmail.com](mailto:wownero@protonmail.com) - GitHub: [https://github.com/wownero/wownero](https://github.com/wownero/wownero) - IRC: [#wownero on Freenode](https://kiwiirc.com/client/irc.freenode.net/?nick=suchchatter|?#wownero) - Bitmessage Chan: wownero (`BM-2cSzWtrj2pzLva9GF1Jp2TYsnLjrnJpvba`) -- Network stats: [https://freeboard.io/board/c8mM2c](https://freeboard.io/board/c8mM2c) - Wownero Funding System: [https://funding.wownero.com](https://funding.wownero.com) - Keybase Chat Group: [https://keybase.io/team/wownero](https://keybase.io/team/wownero) Blockchain Explorers - https://explore.wownero.com - https://explorer.wowkira.com -- https://explorer.wowne.ro -- http://mk6s5cz7dudgvygg5ui6g67yhtzsk7tasnte7zbsgkx32d5o7dx42bqd.onion:8080 - http://wow5eqtzqvsg5jctqzg5g7uk3u62sfqiacj5x6lo4by7bvnj6jkvubyd.onion Free Public Nodes - wow7dhbgiljnkspkzpjyy66auegbrye2ptfv4gucgbhireg5rrjza5ad.onion:34568 - wow.aluisyo.network:34568 -[Node as a Service](https://monero.stackexchange.com/questions/11731/how-do-the-new-rpc-payment-options-for-monerod-work) -- node.wowne.ro:34568 (0.25 credits/hash) -- bzuwkwa3x64jni2u3mvcikkf3wtuxw3kdhmpsv4xqe4zuzaemllh5wyd.onion:34568 (0.25 credits/hash) - ## Introduction Wownero is a privacy-centric memecoin that was fairly launched on April 1, 2018 with no pre-mine, stealth-mine or ICO. Wownero has a maximum supply of around 184 million WOW with a slow and steady emission over 50 years. It is a fork of Monero, but with its own genesis block, so there is no degradation of privacy due to ring signatures using different participants for the same tx outputs on opposing forks. @@ -65,7 +57,8 @@ Dates are provided in the format YYYY-MM-DD. | 63469 | 2018-11-11 | Dank Doge | v0.4.0.0 | v0.4.0.0 | LWMA v4 | 81769 | 2019-02-19 | Erotic EggplantEmoji | v0.5.0.0 | v0.5.0.2 | Cryptonight/wow, LWMA v1 with N=144, Updated Bulletproofs, Fee Per Byte, Auto-churn | 114969 | 2019-06-14 | F For Fappening | v0.6.1.0 | v0.6.1.2 | RandomWOW, new block weight algorithm, slightly more efficient RingCT format -| 160777 | 2019-11-20 | Gaping Goatse | v0.7.0.0 | v0.7.0.0 | Only allow >= 2 outputs, change to the block median used to calculate penalty, rct sigs in coinbase forbidden, 4 unlock time as protocol rule +| 160777 | 2019-11-20 | Gaping Goatse | v0.7.0.0 | v0.7.1.0 | Only allow >= 2 outputs, change to the block median used to calculate penalty, rct sigs in coinbase forbidden, 4 unlock time as protocol rule +| XXXXX | 2020-04-XX | XXXX | v0.8.0.0 | v0.8.0.0 | Dandelion++ support X's indicate that these details have not been determined as of commit date. * indicates estimate as of commit date diff --git a/contrib/depends/packages/sodium.mk b/contrib/depends/packages/sodium.mk index dbf86fc5a..462bd2415 100644 --- a/contrib/depends/packages/sodium.mk +++ b/contrib/depends/packages/sodium.mk @@ -1,8 +1,8 @@ package=sodium -$(package)_version=1.0.16 +$(package)_version=1.0.18 $(package)_download_path=https://download.libsodium.org/libsodium/releases/ $(package)_file_name=libsodium-$($(package)_version).tar.gz -$(package)_sha256_hash=eeadc7e1e1bcef09680fb4837d448fbdf57224978f865ac1c16745868fbd0533 +$(package)_sha256_hash=6f504490b342a4f8a4c4a02fc9b866cbef8622d5df4e5452b46be121e46636c1 $(package)_patches=fix-whitespace.patch define $(package)_set_vars diff --git a/contrib/depends/patches/sodium/fix-whitespace.patch b/contrib/depends/patches/sodium/fix-whitespace.patch index efbfe4e83..c3d3af0b4 100644 --- a/contrib/depends/patches/sodium/fix-whitespace.patch +++ b/contrib/depends/patches/sodium/fix-whitespace.patch @@ -5,8 +5,8 @@ index b29f769..ca008ae 100755 @@ -591,7 +591,7 @@ MAKEFLAGS= PACKAGE_NAME='libsodium' PACKAGE_TARNAME='libsodium' - PACKAGE_VERSION='1.0.16' --PACKAGE_STRING='libsodium 1.0.16' + PACKAGE_VERSION='1.0.18' +-PACKAGE_STRING='libsodium 1.0.18' +PACKAGE_STRING='libsodium' PACKAGE_BUGREPORT='https://github.com/jedisct1/libsodium/issues' PACKAGE_URL='https://github.com/jedisct1/libsodium' diff --git a/contrib/depends/toolchain.cmake.in b/contrib/depends/toolchain.cmake.in index c56f3eb2e..2634423ab 100644 --- a/contrib/depends/toolchain.cmake.in +++ b/contrib/depends/toolchain.cmake.in @@ -136,11 +136,21 @@ endif() if(ARCHITECTURE STREQUAL "i686") SET(ARCH_ID "i386") if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(BUILD_TAG "linux-x86") SET(LINUX_32 ON) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(BUILD_TAG "win-x32") endif() endif() if(ARCHITECTURE STREQUAL "x86_64") + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(BUILD_TAG "linux-x64") + elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + set(BUILD_TAG "freebsd-x64") + elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(BUILD_TAG "win-x64") + endif() SET(ARCH_ID "x86_64") endif() diff --git a/contrib/epee/src/hex.cpp b/contrib/epee/src/hex.cpp index 558983f7e..b654a0269 100644 --- a/contrib/epee/src/hex.cpp +++ b/contrib/epee/src/hex.cpp @@ -84,7 +84,7 @@ namespace epee return write_hex(out, src); } - std::vector from_hex::vector(boost::string_ref src) + std::vector from_hex::vector(const boost::string_ref src) { // should we include a specific character auto include = [](char input) { @@ -104,7 +104,7 @@ namespace epee result.reserve(count / 2); // the data to work with (std::string is always null-terminated) - auto data = src.data(); + auto data = src.begin(); // convert a single hex character to an unsigned integer auto char_to_int = [](const char *input) { @@ -130,9 +130,9 @@ namespace epee }; // keep going until we reach the end - while (data[0] != '\0') { + while (data != src.end()) { // skip unwanted characters - if (!include(data[0])) { + if (!include(*data)) { ++data; continue; } diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp index c940accd2..8da4c6757 100644 --- a/src/checkpoints/checkpoints.cpp +++ b/src/checkpoints/checkpoints.cpp @@ -222,6 +222,8 @@ namespace cryptonote ADD_CHECKPOINT(115257, "338e056551087fe23d6c4b4280244bc5362b004716d85ec799a775f190f9fea9"); //Hard fork to v14 ADD_CHECKPOINT(118500, "2ef1cd0c68f1b8e1acf384109431b6377dbdbd6705964be17b7358c47ea07447"); ADD_CHECKPOINT(157400, "44445d1fcc845b4d6f8e7730c50af64c09031003d584cdeaa04d6523e0acc049"); + ADD_CHECKPOINT(160777, "9496690579af21f38f00e67e11c2e85a15912fe4f412aad33d1162be1579e755"); //Hard fork to v15 + ADD_CHECKPOINT(194444, "0aa7ea6ade2ee8f5a525a079c53888fac415826ee8d1e8c92caa52629773db35"); return true; } diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp index 4b41b5bfc..92f31a1c7 100644 --- a/src/cryptonote_protocol/levin_notify.cpp +++ b/src/cryptonote_protocol/levin_notify.cpp @@ -43,6 +43,9 @@ #include "net/dandelionpp.h" #include "p2p/net_node.h" +#undef MONERO_DEFAULT_LOG_CATEGORY +#define MONERO_DEFAULT_LOG_CATEGORY "net.p2p.tx" + namespace cryptonote { namespace levin @@ -242,6 +245,8 @@ namespace levin if (!channel.connection.is_nil()) channel.queue.push_back(std::move(message_)); + else if (destination_ == 0 && zone_->connection_count == 0) + MWARNING("Unable to send transaction(s) over anonymity network - no available outbound connections"); } }; @@ -286,8 +291,12 @@ namespace levin return true; }); + bool sent = false; for (const boost::uuids::uuid& connection : connections) - zone_->p2p->send(message_.clone(), connection); + sent |= zone_->p2p->send(message_.clone(), connection); + + if (!sent) + MWARNING("Unable to send transaction(s), no available connections"); } }; @@ -441,9 +450,12 @@ namespace levin { channel.active = nullptr; channel.connection = boost::uuids::nil_uuid(); - zone_->strand.post( - update_channels{zone_, get_out_connections(*zone_->p2p)} - ); + + auto connections = get_out_connections(*zone_->p2p); + if (connections.empty()) + MWARNING("Lost all outbound connections to anonymity network - currently unable to send transaction(s)"); + + zone_->strand.post(update_channels{zone_, std::move(connections)}); } } diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index bf1b367b1..7414dd235 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1051,17 +1051,15 @@ namespace nodetool pi = context.peer_id = rsp.node_data.peer_id; context.m_rpc_port = rsp.node_data.rpc_port; context.m_rpc_credits_per_hash = rsp.node_data.rpc_credits_per_hash; - m_network_zones.at(context.m_remote_address.get_zone()).m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_address, context.m_pruning_seed, context.m_rpc_port, context.m_rpc_credits_per_hash); + network_zone& zone = m_network_zones.at(context.m_remote_address.get_zone()); + zone.m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_address, context.m_pruning_seed, context.m_rpc_port, context.m_rpc_credits_per_hash); // move - for (auto const& zone : m_network_zones) + if(rsp.node_data.peer_id == zone.m_config.m_peer_id) { - if(rsp.node_data.peer_id == zone.second.m_config.m_peer_id) - { - LOG_DEBUG_CC(context, "Connection to self detected, dropping connection"); - hsh_result = false; - return; - } + LOG_DEBUG_CC(context, "Connection to self detected, dropping connection"); + hsh_result = false; + return; } LOG_INFO_CC(context, "New connection handshaked, pruning seed " << epee::string_tools::to_string_hex(context.m_pruning_seed)); LOG_DEBUG_CC(context, " COMMAND_HANDSHAKE INVOKED OK"); diff --git a/src/rpc/message.cpp b/src/rpc/message.cpp index 158b58005..689eb5e33 100644 --- a/src/rpc/message.cpp +++ b/src/rpc/message.cpp @@ -52,6 +52,16 @@ constexpr const char id_field[] = "id"; constexpr const char method_field[] = "method"; constexpr const char params_field[] = "params"; constexpr const char result_field[] = "result"; + +const rapidjson::Value& get_method_field(const rapidjson::Value& src) +{ + const auto member = src.FindMember(method_field); + if (member == src.MemberEnd()) + throw cryptonote::json::MISSING_KEY{method_field}; + if (!member->value.IsString()) + throw cryptonote::json::WRONG_TYPE{"Expected string"}; + return member->value; +} } rapidjson::Value Message::toJson(rapidjson::Document& doc) const @@ -120,7 +130,7 @@ FullMessage::FullMessage(const std::string& json_string, bool request) if (request) { - OBJECT_HAS_MEMBER_OR_THROW(doc, method_field) + get_method_field(doc); // throws on errors OBJECT_HAS_MEMBER_OR_THROW(doc, params_field) } else @@ -151,8 +161,7 @@ std::string FullMessage::getJson() std::string FullMessage::getRequestType() const { - OBJECT_HAS_MEMBER_OR_THROW(doc, method_field) - return doc[method_field].GetString(); + return get_method_field(doc).GetString(); } rapidjson::Value& FullMessage::getMessage() diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 94b116a89..c532b3764 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -8383,7 +8383,7 @@ bool simple_wallet::get_transfers(std::vector& local_args, std::vec m_in_manual_refresh.store(true, std::memory_order_relaxed); epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){m_in_manual_refresh.store(false, std::memory_order_relaxed);}); - std::vector> process_txs; + std::vector> process_txs; m_wallet->update_pool_state(process_txs); if (!process_txs.empty()) m_wallet->process_pool_state(process_txs); @@ -10052,7 +10052,7 @@ bool simple_wallet::show_transfer(const std::vector &args) try { - std::vector> process_txs; + std::vector> process_txs; m_wallet->update_pool_state(process_txs); if (!process_txs.empty()) m_wallet->process_pool_state(process_txs); diff --git a/src/version.cpp.in b/src/version.cpp.in index 9100a3fc1..ce7f22f2b 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.7.0.0" +#define DEF_MONERO_VERSION "0.7.1.0" #define DEF_MONERO_RELEASE_NAME "Gaping Goatse" #define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG #define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@ diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index b98c63c26..c7135783c 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2831,7 +2831,7 @@ void wallet2::remove_obsolete_pool_txs(const std::vector &tx_hashe } //---------------------------------------------------------------------------------------------------- -void wallet2::update_pool_state(std::vector> &process_txs, bool refreshed) +void wallet2::update_pool_state(std::vector> &process_txs, bool refreshed) { MTRACE("update_pool_state start"); @@ -3021,7 +3021,7 @@ void wallet2::update_pool_state(std::vector &e) { return e.first == tx_hash; }); if (i != txids.end()) { - process_txs.push_back(std::make_pair(tx, tx_entry.double_spend_seen)); + process_txs.push_back(std::make_tuple(tx, tx_hash, tx_entry.double_spend_seen)); } else { @@ -3052,14 +3052,14 @@ void wallet2::update_pool_state(std::vector> &txs) +void wallet2::process_pool_state(const std::vector> &txs) { const time_t now = time(NULL); for (const auto &e: txs) { - const cryptonote::transaction &tx = e.first; - const bool double_spend_seen = e.second; - const crypto::hash tx_hash = get_transaction_hash(tx); + const cryptonote::transaction &tx = std::get<0>(e); + const crypto::hash &tx_hash = std::get<1>(e); + const bool double_spend_seen = std::get<2>(e); process_new_transaction(tx_hash, tx, std::vector(), 0, 0, now, false, true, double_spend_seen, {}); m_scanned_pool_txs[0].insert(tx_hash); if (m_scanned_pool_txs[0].size() > 5000) @@ -3278,7 +3278,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo // since that might cause a password prompt, which would introduce a data // leak allowing a passive adversary with traffic analysis capability to // infer when we get an incoming output - std::vector> process_pool_txs; + std::vector> process_pool_txs; update_pool_state(process_pool_txs, true); bool first = true, last = false; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index c86315f7c..79b153979 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1219,8 +1219,8 @@ private: bool import_key_images(signed_tx_set & signed_tx, size_t offset=0, bool only_selected_transfers=false); crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const; - void update_pool_state(std::vector> &process_txs, bool refreshed = false); - void process_pool_state(const std::vector> &txs); + void update_pool_state(std::vector> &process_txs, bool refreshed = false); + void process_pool_state(const std::vector> &txs); void remove_obsolete_pool_txs(const std::vector &tx_hashes); std::string encrypt(const char *plaintext, size_t len, const crypto::secret_key &skey, bool authenticated = true) const; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index e753ca98d..afcf514f7 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -2438,7 +2438,7 @@ namespace tools if (req.pool) { - std::vector> process_txs; + std::vector> process_txs; m_wallet->update_pool_state(process_txs); if (!process_txs.empty()) m_wallet->process_pool_state(process_txs); @@ -2521,7 +2521,7 @@ namespace tools } } - std::vector> process_txs; + std::vector> process_txs; m_wallet->update_pool_state(process_txs); if (!process_txs.empty()) m_wallet->process_pool_state(process_txs); diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 96825f54f..17d6dfd9f 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -92,7 +92,8 @@ set(unit_tests_sources ringdb.cpp wipeable_string.cpp is_hdd.cpp - aligned.cpp) + aligned.cpp + zmq_rpc.cpp) set(unit_tests_headers unit_tests_utils.h) @@ -105,6 +106,7 @@ target_link_libraries(unit_tests ringct cryptonote_protocol cryptonote_core + daemon_messages blockchain_db lmdb_lib rpc diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp index 6f887afda..a4b339295 100644 --- a/tests/unit_tests/epee_utils.cpp +++ b/tests/unit_tests/epee_utils.cpp @@ -840,6 +840,9 @@ TEST(FromHex, String) // decoding it this way also, ignoring spaces and colons between the numbers hex.assign("00:ff 0f:f0"); EXPECT_EQ(source, epee::from_hex::vector(hex)); + + hex.append("f0"); + EXPECT_EQ(source, epee::from_hex::vector(boost::string_ref{hex.data(), hex.size() - 2})); } TEST(ToHex, Array) diff --git a/tests/unit_tests/zmq_rpc.cpp b/tests/unit_tests/zmq_rpc.cpp new file mode 100644 index 000000000..af1f1608b --- /dev/null +++ b/tests/unit_tests/zmq_rpc.cpp @@ -0,0 +1,55 @@ +// Copyright (c) 2020, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "rpc/message.h" +#include "serialization/json_object.h" + +TEST(ZmqFullMessage, InvalidRequest) +{ + EXPECT_THROW( + (cryptonote::rpc::FullMessage{"{\"jsonrpc\":\"2.0\",\"id\":0,\"params\":[]}", true}), + cryptonote::json::MISSING_KEY + ); + EXPECT_THROW( + (cryptonote::rpc::FullMessage{"{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":3,\"params\":[]}", true}), + cryptonote::json::WRONG_TYPE + ); +} + +TEST(ZmqFullMessage, Request) +{ + static constexpr const char request[] = "{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"foo\",\"params\":[]}"; + EXPECT_NO_THROW( + (cryptonote::rpc::FullMessage{request, true}) + ); + + cryptonote::rpc::FullMessage parsed{request, true}; + EXPECT_STREQ("foo", parsed.getRequestType().c_str()); +}