diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp index b74fd441c..288aa24e1 100644 --- a/src/blockchain_db/blockchain_db.cpp +++ b/src/blockchain_db/blockchain_db.cpp @@ -296,7 +296,7 @@ uint64_t BlockchainDB::add_block( const std::pair& blck blobdata protocol_bd = tx_to_blob(blk.protocol_tx); add_transaction(blk_hash, std::make_pair(blk.protocol_tx, blobdata_ref(protocol_bd))); - if (blk.miner_tx.version == 2) + if (blk.miner_tx.version >= 2) { num_rct_outs += blk.miner_tx.vout.size(); @@ -311,7 +311,7 @@ uint64_t BlockchainDB::add_block( const std::pair& blck std::map slippage_counts; uint64_t audit_total = 0, yield_total = 0; - if (blk.protocol_tx.version == 2) + if (blk.protocol_tx.version >= 2) { num_rct_outs += blk.protocol_tx.vout.size(); diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 98999ed7a..3b4b4ae44 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3622,7 +3622,14 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio return false; } } - + + // Check for invalid TX types + if (tx.type == cryptonote::transaction_type::UNSET || tx.type > cryptonote::transaction_type::MAX) { + MERROR("TX type `" + std::to_string(tx.type) + "' is not supported"); + tvc.m_version_mismatch = true; + return false; + } + return true; } //------------------------------------------------------------------ diff --git a/src/rpc/rpc_version_str.cpp b/src/rpc/rpc_version_str.cpp index ad3c37158..528c92415 100644 --- a/src/rpc/rpc_version_str.cpp +++ b/src/rpc/rpc_version_str.cpp @@ -45,7 +45,7 @@ namespace rpc bool is_version_string_valid(const std::string& str) { return std::regex_match(str, std::regex( - "^\\d{1,2}(\\.\\d{1,2}){2}(-(release|[0-9a-f]{9}))?.+$", + "^\\d{1,2}(\\.\\d{1,2}){3}(-(release|[0-9a-f]{9}))?$", std::regex_constants::nosubs )); } diff --git a/src/version.cpp.in b/src/version.cpp.in index 561220724..32263d04d 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@" -#define DEF_SALVIUM_VERSION "0.9.6-rc1" +#define DEF_SALVIUM_VERSION "0.9.6-rc2" #define DEF_MONERO_VERSION_TAG "release" #define DEF_MONERO_VERSION "0.18.3.4" #define DEF_MONERO_RELEASE_NAME "Zero" diff --git a/tests/unit_tests/node_server.cpp b/tests/unit_tests/node_server.cpp index cc911631f..db90fb3ff 100644 --- a/tests/unit_tests/node_server.cpp +++ b/tests/unit_tests/node_server.cpp @@ -35,6 +35,7 @@ #include "cryptonote_core/i_core_events.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "cryptonote_protocol/cryptonote_protocol_handler.inl" +#include "unit_tests_utils.h" #include #define MAKE_IPV4_ADDRESS(a,b,c,d) epee::net_utils::ipv4_network_address{MAKE_IP(a,b,c,d),0} @@ -114,6 +115,18 @@ static bool is_blocked(Server &server, const epee::net_utils::network_address &a return true; } } + + if (address.get_type_id() != epee::net_utils::address_type::ipv4) + return false; + + const epee::net_utils::ipv4_network_address ipv4_address = address.as(); + + // check if in a blocked ipv4 subnet + const std::map subnets = server.get_blocked_subnets(); + for (const auto &subnet : subnets) + if (subnet.first.matches(ipv4_address)) + return true; + return false; } @@ -224,6 +237,18 @@ TEST(ban, subnet) test_core pr_core; cryptonote::t_cryptonote_protocol_handler cprotocol(pr_core, NULL); Server server(cprotocol); + { + boost::program_options::options_description opts{}; + Server::init_options(opts); + cryptonote::core::init_options(opts); + + char** args = nullptr; + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::parse_command_line(0, args, opts), vm + ); + server.init(vm); + } cprotocol.set_p2p_endpoint(&server); ASSERT_TRUE(server.block_subnet(MAKE_IPV4_SUBNET(1,2,3,4,24), 10)); @@ -266,6 +291,78 @@ TEST(ban, ignores_port) ASSERT_FALSE(is_blocked(server,MAKE_IPV4_ADDRESS_PORT(1,2,3,4,6))); } +TEST(ban, file_banlist) +{ + test_core pr_core; + cryptonote::t_cryptonote_protocol_handler cprotocol(pr_core, NULL); + Server server(cprotocol); + cprotocol.set_p2p_endpoint(&server); + + auto create_node_dir = [](){ + boost::system::error_code ec; + auto path = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("daemon-%%%%%%%%%%%%%%%%", ec); + if (ec) + return boost::filesystem::path{}; + auto success = boost::filesystem::create_directory(path, ec); + if (!ec && success) + return path; + return boost::filesystem::path{}; + }; + const auto node_dir = create_node_dir(); + ASSERT_TRUE(!node_dir.empty()); + auto auto_remove_node_dir = epee::misc_utils::create_scope_leave_handler([&node_dir](){ + boost::filesystem::remove_all(node_dir); + }); + + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::command_line_parser({ + "--data-dir", + node_dir.string(), + "--ban-list", + (unit_test::data_dir / "node" / "banlist_1.txt").string() + }).options([]{ + boost::program_options::options_description options_description{}; + cryptonote::core::init_options(options_description); + Server::init_options(options_description); + return options_description; + }()).run(), + vm + ); + + ASSERT_TRUE(server.init(vm)); + + // Test cases (look in the banlist_1.txt file) + + // magicfolk + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(255,255,255,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(128,128,128,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(150,75,0,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,98,0,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,98,0,255,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,98,1,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,98,1,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,98,255,255,9999)) ); + EXPECT_FALSE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,99,0,0,9999)) ); + + // personal enemies + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(1,2,3,4,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(6,7,8,9,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(1,0,0,7,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(1,0,0,7,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(100,98,1,13,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(100,98,1,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(100,98,1,255,9999)) ); + EXPECT_FALSE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(100,98,2,0,9999)) ); + EXPECT_FALSE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(100,98,0,255,9999)) ); + + // angel + EXPECT_FALSE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(007,007,007,007,9999)) ); + + // random IP + EXPECT_FALSE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(145,036,205,235,9999)) ); +} + TEST(node_server, bind_same_p2p_port) { struct test_data_t @@ -341,14 +438,14 @@ TEST(cryptonote_protocol_handler, race_condition) using connections_t = std::vector; using shared_state_t = typename connection_t::shared_state; using shared_state_ptr = std::shared_ptr; - using io_context_t = boost::asio::io_service; + using io_context_t = boost::asio::io_context; using event_t = epee::simple_event; using ec_t = boost::system::error_code; auto create_conn_pair = [](connection_ptr in, connection_ptr out) { using endpoint_t = boost::asio::ip::tcp::endpoint; using acceptor_t = boost::asio::ip::tcp::acceptor; io_context_t io_context; - endpoint_t endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 5262); + endpoint_t endpoint(boost::asio::ip::make_address("127.0.0.1"), 5262); acceptor_t acceptor(io_context); ec_t ec; acceptor.open(endpoint.protocol(), ec); @@ -356,7 +453,7 @@ TEST(cryptonote_protocol_handler, race_condition) acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); acceptor.bind(endpoint, ec); EXPECT_EQ(ec.value(), 0); - acceptor.listen(boost::asio::socket_base::max_connections, ec); + acceptor.listen(boost::asio::socket_base::max_listen_connections, ec); EXPECT_EQ(ec.value(), 0); out->socket().open(endpoint.protocol(), ec); EXPECT_EQ(ec.value(), 0); @@ -374,7 +471,7 @@ TEST(cryptonote_protocol_handler, race_condition) conn.get_context(context); return context.m_connection_id; }; - using work_t = boost::asio::io_service::work; + using work_t = boost::asio::executor_work_guard; using work_ptr = std::shared_ptr; using workers_t = std::vector; using commands_handler_t = epee::levin::levin_commands_handler; @@ -398,22 +495,19 @@ TEST(cryptonote_protocol_handler, race_condition) ){ auto &storage = core.get_blockchain_storage(); const auto height = storage.get_current_blockchain_height(); - const auto hardfork = 4; + const auto hardfork = storage.get_current_hard_fork_version(); block.major_version = hardfork; block.minor_version = storage.get_ideal_hard_fork_version(); block.prev_id = storage.get_tail_id(); auto &db = storage.get_db(); block.timestamp = db.get_top_block_timestamp(); block.nonce = 0xACAB; - - // set miner tx block.miner_tx.vin.clear(); block.miner_tx.vout.clear(); block.miner_tx.extra.clear(); - block.miner_tx.version = hardfork >= 4 ? 2 : 1; + block.miner_tx.version = 2; block.miner_tx.type = cryptonote::transaction_type::MINER; - block.miner_tx.amount_burnt = 1; // avoid no staking reward error - block.miner_tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; + block.miner_tx.unlock_time = CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; block.miner_tx.vin.push_back(cryptonote::txin_gen{height}); cryptonote::add_tx_pub_key_to_extra(block.miner_tx, {}); cryptonote::get_block_reward( @@ -423,6 +517,8 @@ TEST(cryptonote_protocol_handler, race_condition) reward, hardfork ); + block.miner_tx.amount_burnt = reward/5; // avoid no staking reward error + reward -= block.miner_tx.amount_burnt; cryptonote::txout_to_key out; out.asset_type = "SAL"; block.miner_tx.vout.push_back(cryptonote::tx_out{reward, out}); @@ -430,9 +526,9 @@ TEST(cryptonote_protocol_handler, race_condition) block.protocol_tx.vin.clear(); block.protocol_tx.vout.clear(); block.protocol_tx.extra.clear(); - block.protocol_tx.version = hardfork >= 4 ? 2 : 1; + block.protocol_tx.version = (height > 0) ? 2 : 1; block.protocol_tx.type = cryptonote::transaction_type::PROTOCOL; - block.protocol_tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; + block.protocol_tx.unlock_time = CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; block.protocol_tx.vin.push_back(cryptonote::txin_gen{height}); cryptonote::add_tx_pub_key_to_extra(block.protocol_tx, {}); @@ -709,7 +805,7 @@ TEST(cryptonote_protocol_handler, race_condition) }; io_context_t io_context; - work_ptr work = std::make_shared(io_context); + work_ptr work = std::make_shared(io_context.get_executor()); workers_t workers; while (workers.size() < 4) { workers.emplace_back([&io_context]{ @@ -746,7 +842,7 @@ TEST(cryptonote_protocol_handler, race_condition) auto conn = connections.first; auto shared_state = daemon.main.shared_state; const auto tag = get_conn_tag(*conn); - conn->strand_.post([tag, conn, shared_state, &events]{ + boost::asio::post(conn->strand_, [tag, conn, shared_state, &events]{ shared_state->for_connection(tag, [](context_t &context){ context.m_expect_height = -1; context.m_expect_response = -1; @@ -773,10 +869,10 @@ TEST(cryptonote_protocol_handler, race_condition) events.check.raise(); events.finish.wait(); - connections.first->strand_.post([connections]{ + boost::asio::post(connections.first->strand_, [connections]{ connections.first->cancel(); }); - connections.second->strand_.post([connections]{ + boost::asio::post(connections.second->strand_, [connections]{ connections.second->cancel(); }); connections.first.reset(); @@ -820,7 +916,7 @@ TEST(cryptonote_protocol_handler, race_condition) work_ptr work; workers_t workers; } check; - check.work = std::make_shared(check.io_context); + check.work = std::make_shared(check.io_context.get_executor()); while (check.workers.size() < 2) { check.workers.emplace_back([&check]{ check.io_context.run(); @@ -841,7 +937,7 @@ TEST(cryptonote_protocol_handler, race_condition) auto conn = daemon.main.conn.back(); auto shared_state = daemon.main.shared_state; const auto tag = get_conn_tag(*conn); - conn->strand_.post([tag, conn, shared_state, &events]{ + boost::asio::post(conn->strand_, [tag, conn, shared_state, &events]{ shared_state->for_connection(tag, [](context_t &context){ EXPECT_TRUE(context.m_state == contexts::cryptonote::state_normal); return true; @@ -893,13 +989,13 @@ TEST(cryptonote_protocol_handler, race_condition) for (;daemon.main.conn.size(); daemon.main.conn.pop_back()) { auto conn = daemon.main.conn.back(); - conn->strand_.post([conn]{ + boost::asio::post(conn->strand_, [conn]{ conn->cancel(); }); } for (;daemon.alt.conn.size(); daemon.alt.conn.pop_back()) { auto conn = daemon.alt.conn.back(); - conn->strand_.post([conn]{ + boost::asio::post(conn->strand_, [conn]{ conn->cancel(); }); } @@ -1069,8 +1165,8 @@ TEST(node_server, race_condition) using connection_ptr = boost::shared_ptr; using shared_state_t = typename connection_t::shared_state; using shared_state_ptr = std::shared_ptr; - using io_context_t = boost::asio::io_service; - using work_t = boost::asio::io_service::work; + using io_context_t = boost::asio::io_context; + using work_t = boost::asio::executor_work_guard; using work_ptr = std::shared_ptr; using workers_t = std::vector; using endpoint_t = boost::asio::ip::tcp::endpoint; @@ -1087,23 +1183,23 @@ TEST(node_server, race_condition) static void destroy(epee::levin::levin_commands_handler* ptr) { delete ptr; } }; io_context_t io_context; - work_ptr work = std::make_shared(io_context); + work_ptr work = std::make_shared(io_context.get_executor()); workers_t workers; while (workers.size() < 4) { workers.emplace_back([&io_context]{ io_context.run(); }); } - io_context.post([&]{ + boost::asio::post(io_context, [&]{ protocol.on_idle(); }); - io_context.post([&]{ + boost::asio::post(io_context, [&]{ protocol.on_idle(); }); shared_state_ptr shared_state = std::make_shared(); shared_state->set_handler(new command_handler_t, &command_handler_t::destroy); connection_ptr conn{new connection_t(io_context, shared_state, {}, {})}; - endpoint_t endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 48080); + endpoint_t endpoint(boost::asio::ip::make_address("127.0.0.1"), 48080); conn->socket().connect(endpoint); conn->socket().set_option(boost::asio::ip::tcp::socket::reuse_address(true)); conn->start({}, {}); @@ -1126,7 +1222,7 @@ TEST(node_server, race_condition) P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT ); handshaked.wait(); - conn->strand_.post([conn]{ + boost::asio::post(conn->strand_, [conn]{ conn->cancel(); }); conn.reset(); diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 5be759ded..e90412dfb 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -749,7 +749,7 @@ TEST(Serialization, portability_wallet) ++pd1; ASSERT_EQ(epee::string_tools::pod_to_hex(pd0->first), "0000000000000000000000000000000000000000000000000000000000000000"); ASSERT_EQ(epee::string_tools::pod_to_hex(pd1->first), "0000000000000000000000000000000000000000000000000000000000000000"); - if (epee::string_tools::pod_to_hex(pd0->second.m_tx_hash) == "ec34c9bb12b99af33d49691384eee5bed9171498ff04e59516505f35d1fc5efc") + if (epee::string_tools::pod_to_hex(pd0->second.m_tx_hash) == "857cbe184830d93a93c4a164fe492124152e0b21b3c04e8f4145ac83611c47ee") swap(pd0, pd1); ASSERT_EQ(epee::string_tools::pod_to_hex(pd0->second.m_tx_hash), "733674c4f446d73620c6300b8376c88903f29795e3fb808d43aeee0dc99a1a9e"); ASSERT_EQ(epee::string_tools::pod_to_hex(pd1->second.m_tx_hash), "857cbe184830d93a93c4a164fe492124152e0b21b3c04e8f4145ac83611c47ee"); @@ -1234,4 +1234,4 @@ TEST(Serialization, adl_free_function) const std::string expected = "{\"custom_fieldname\": " + std::to_string(msg.size()) + '"' + epee::string_tools::buff_to_hex_nodelimer(msg) + "\"}"; EXPECT_EQ(expected, ss.str()); } -*/ \ No newline at end of file +*/