aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/epee/demo/demo_http_server/demo_http_server.cpp217
-rw-r--r--contrib/epee/demo/demo_http_server/demo_http_server.h103
-rw-r--r--contrib/epee/demo/demo_levin_server/demo_levin_server.cpp200
-rw-r--r--contrib/epee/demo/demo_levin_server/demo_levin_server.h76
-rw-r--r--contrib/epee/include/storages/activity_notifier.h132
-rw-r--r--contrib/epee/src/mlog.cpp62
-rw-r--r--snapcraft.yaml46
-rw-r--r--src/common/stack_trace.cpp2
-rw-r--r--src/cryptonote_core/blockchain.cpp6
-rw-r--r--src/cryptonote_core/blockchain.h3
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp33
-rw-r--r--src/cryptonote_core/cryptonote_core.h4
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl25
-rw-r--r--src/p2p/net_node.h12
-rw-r--r--src/p2p/net_node.inl88
-rw-r--r--src/p2p/net_peerlist.h46
-rw-r--r--src/ringct/rctSigs.cpp34
-rw-r--r--src/rpc/core_rpc_server.cpp10
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/wallet/wallet2.cpp53
-rw-r--r--tests/unit_tests/hardfork.cpp2
21 files changed, 322 insertions, 834 deletions
diff --git a/contrib/epee/demo/demo_http_server/demo_http_server.cpp b/contrib/epee/demo/demo_http_server/demo_http_server.cpp
deleted file mode 100644
index 85547e4c9..000000000
--- a/contrib/epee/demo/demo_http_server/demo_http_server.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * 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.
-// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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 "stdafx.h"
-#include "console_handler.h"
-#include "demo_http_server.h"
-#include "net/http_client.h"
-#include "storages/http_abstract_invoke.h"
-
-
-template<class t_request, class t_response>
-bool communicate(const std::string url, t_request& req, t_response& rsp, const std::string& ip, const std::string& port, bool use_json, bool use_jrpc = false)
-{
- epee::net_utils::http::http_simple_client http_client;
- bool r = http_client.connect(ip, port, 1000);
- CHECK_AND_ASSERT_MES(r, false, "failed to connect");
- if(use_json)
- {
- if(use_jrpc)
- {
- epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t);
- req_t.jsonrpc = "2.0";
- req_t.id = epee::serialization::storage_entry(10);
- req_t.method = "command_example_1";
- req_t.params = req;
- epee::json_rpc::response<t_response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
- if(!epee::net_utils::invoke_http_json_remote_command2("/request_json_rpc", req_t, resp_t, http_client))
- {
- return false;
- }
- rsp = resp_t.result;
- return true;
- }else
- return epee::net_utils::invoke_http_json_remote_command2(url, req, rsp, http_client);
- }
- else
- return epee::net_utils::invoke_http_bin_remote_command2(url, req, rsp, http_client);
-}
-
-
-int main(int argc, char* argv[])
-{
- TRY_ENTRY();
- string_tools::set_module_name_and_folder(argv[0]);
-
- //set up logging options
- log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
- log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
- log_space::log_singletone::add_logger(LOGGER_FILE,
- log_space::log_singletone::get_default_log_file().c_str(),
- log_space::log_singletone::get_default_log_folder().c_str());
-
-
-
- LOG_PRINT("Demo server starting ...", LOG_LEVEL_0);
-
-
- demo::demo_http_server srv;
-
- start_default_console(&srv, "#");
-
- std::string bind_param = "0.0.0.0";
- std::string port = "83";
-
- if(!srv.init(port, bind_param))
- {
- LOG_ERROR("Failed to initialize srv!");
- return 1;
- }
-
- //log loop
- srv.run();
- size_t count = 0;
- while (!srv.is_stop())
- {
-
- demo::COMMAND_EXAMPLE_1::request req;
- req.sub = demo::get_test_data();
- demo::COMMAND_EXAMPLE_1::response rsp;
- bool r = false;
- if(count%2)
- {//invoke json
- r = communicate("/request_api_json_1", req, rsp, "127.0.0.1", port, true, true);
- }else{
- r = communicate("/request_api_bin_1", req, rsp, "127.0.0.1", port, false);
- }
- CHECK_AND_ASSERT_MES(r, false, "failed to invoke http request");
- CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response");
- CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response");
- CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response");
- //misc_utils::sleep_no_w(1000);
- ++count;
- }
- bool r = srv.wait_stop();
- CHECK_AND_ASSERT_MES(r, 1, "failed to wait server stop");
- srv.deinit();
-
- LOG_PRINT("Demo server stoped.", LOG_LEVEL_0);
- return 1;
-
- CATCH_ENTRY_L0("main", 1);
-}
-
-/************************************************************************/
-/* */
-/************************************************************************/
-namespace demo
-{
- bool demo_http_server::init(const std::string& bind_port, const std::string& bind_ip)
- {
-
-
- //set self as callback handler
- m_net_server.get_config_object().m_phandler = this;
-
- //here set folder for hosting reqests
- m_net_server.get_config_object().m_folder = "";
-
- LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port);
- return m_net_server.init_server(bind_port, bind_ip);
- }
-
- bool demo_http_server::run()
- {
- m_stop = false;
- //here you can set worker threads count
- int thrds_count = 4;
-
- //go to loop
- LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0);
- if(!m_net_server.run_server(thrds_count, false))
- {
- LOG_ERROR("Failed to run net tcp server!");
- }
-
- return true;
- }
-
- bool demo_http_server::deinit()
- {
- return m_net_server.deinit_server();
- }
-
- bool demo_http_server::send_stop_signal()
- {
- m_stop = true;
- m_net_server.send_stop_signal();
- return true;
- }
-
- bool demo_http_server::on_requestr_uri_1(const net_utils::http::http_request_info& query_info,
- net_utils::http::http_response_info& response,
- const net_utils::connection_context_base& m_conn_context)
- {
- return true;
- }
-
-
- bool demo_http_server::on_requestr_uri_2(const net_utils::http::http_request_info& query_info,
- net_utils::http::http_response_info& response,
- const net_utils::connection_context_base& m_conn_context)
- {
- return true;
- }
-
-
- bool demo_http_server::on_hosting_request( const net_utils::http::http_request_info& query_info,
- net_utils::http::http_response_info& response,
- const net_utils::connection_context_base& m_conn_context)
- {
- //read file from filesystem here
- return true;
- }
-
- bool demo_http_server::on_request_api_1(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, connection_context& ctxt)
- {
- CHECK_AND_ASSERT_MES(req.sub == demo::get_test_data(), false, "wrong request");
- res.m_success = true;
- res.subs.push_back(req.sub);
- return true;
- }
-
- bool demo_http_server::on_request_api_1_with_error(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, epee::json_rpc::error& error_resp, connection_context& ctxt)
- {
- error_resp.code = 232432;
- error_resp.message = "bla bla bla";
- return false;
- }
-
- bool demo_http_server::on_request_api_2(const COMMAND_EXAMPLE_2::request& req, COMMAND_EXAMPLE_2::response& res, connection_context& ctxt)
- {
- return true;
- }
-}
diff --git a/contrib/epee/demo/demo_http_server/demo_http_server.h b/contrib/epee/demo/demo_http_server/demo_http_server.h
deleted file mode 100644
index 088ead548..000000000
--- a/contrib/epee/demo/demo_http_server/demo_http_server.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * 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.
-// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
-//
-
-
-
-#pragma once
-#include <boost/thread.hpp>
-#include <boost/bind.hpp>
-
-#include "net/http_server_cp2.h"
-#include "transport_defs.h"
-#include "net/http_server_handlers_map2.h"
-
-using namespace epee;
-
-namespace demo
-{
-
- class demo_http_server: public net_utils::http::i_http_server_handler<epee::net_utils::connection_context_base>
- {
- public:
- typedef epee::net_utils::connection_context_base connection_context;
-
- demo_http_server():m_stop(false){}
- bool run();
- bool init(const std::string& bind_port = "11112", const std::string& bind_ip = "0.0.0.0");
- bool deinit();
- bool send_stop_signal();
- bool is_stop(){return m_stop;}
- bool wait_stop(){return m_net_server.timed_wait_server_stop(100000);}
- private:
-
-
- CHAIN_HTTP_TO_MAP2(connection_context); //forward http requests to uri map
-
- BEGIN_URI_MAP2()
- MAP_URI2("/requestr_uri_1", on_requestr_uri_1)
- MAP_URI2("/requestr_uri_2", on_requestr_uri_1)
- //MAP_URI_AUTO_XML2("/request_api_xml_1", on_request_api_1, COMMAND_EXAMPLE_1)
- //MAP_URI_AUTO_XML2("/request_api_xml_2", on_request_api_2, COMMAND_EXAMPLE_2)
- MAP_URI_AUTO_JON2("/request_api_json_1", on_request_api_1, COMMAND_EXAMPLE_1)
- MAP_URI_AUTO_JON2("/request_api_json_2", on_request_api_2, COMMAND_EXAMPLE_2)
- MAP_URI_AUTO_BIN2("/request_api_bin_1", on_request_api_1, COMMAND_EXAMPLE_1)
- MAP_URI_AUTO_BIN2("/request_api_bin_2", on_request_api_2, COMMAND_EXAMPLE_2)
- BEGIN_JSON_RPC_MAP("/request_json_rpc")
- MAP_JON_RPC("command_example_1", on_request_api_1, COMMAND_EXAMPLE_1)
- MAP_JON_RPC("command_example_2", on_request_api_2, COMMAND_EXAMPLE_2)
- MAP_JON_RPC_WE("command_example_1_we", on_request_api_1_with_error, COMMAND_EXAMPLE_1)
- END_JSON_RPC_MAP()
- CHAIN_URI_MAP2(on_hosting_request)
- END_URI_MAP2()
-
-
-
- bool on_requestr_uri_1(const net_utils::http::http_request_info& query_info,
- net_utils::http::http_response_info& response,
- const net_utils::connection_context_base& m_conn_context);
-
-
- bool on_requestr_uri_2(const net_utils::http::http_request_info& query_info,
- net_utils::http::http_response_info& response,
- const net_utils::connection_context_base& m_conn_context);
-
-
-
-
- bool on_hosting_request( const net_utils::http::http_request_info& query_info,
- net_utils::http::http_response_info& response,
- const net_utils::connection_context_base& m_conn_context);
-
- bool on_request_api_1(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, connection_context& ctxt);
- bool on_request_api_2(const COMMAND_EXAMPLE_2::request& req, COMMAND_EXAMPLE_2::response& res, connection_context& ctxt);
-
- bool on_request_api_1_with_error(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, epee::json_rpc::error& error_resp, connection_context& ctxt);
-
- net_utils::boosted_http_server_custum_handling m_net_server;
- std::atomic<bool> m_stop;
- };
-}
-
diff --git a/contrib/epee/demo/demo_levin_server/demo_levin_server.cpp b/contrib/epee/demo/demo_levin_server/demo_levin_server.cpp
deleted file mode 100644
index a99a1f564..000000000
--- a/contrib/epee/demo/demo_levin_server/demo_levin_server.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * 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.
-// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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 "stdafx.h"
-#include "demo_levin_server.h"
-#include "console_handler.h"
-
-
-template<class t_request>
-bool communicate(net_utils::boosted_levin_async_server& transport, int id, t_request& req, const std::string& ip, const std::string& port, bool use_async)
-{
- if(use_async)
- {
- //IMPORTANT: do not pass local parameters from stack by reference! connect_async returns immediately, and callback will call in any thread later
- transport.connect_async(ip, port, 10000, [&transport, id, req, ip, port](net_utils::connection_context_base& ctx, const boost::system::error_code& ec_)
- {
- if(!!ec_)
- {
- LOG_ERROR("Failed to connect to " << ip << ":" << port);
- }else
- {//connected ok!
-
- epee::net_utils::async_invoke_remote_command2<demo::COMMAND_EXAMPLE_1::response>(ctx.m_connection_id, id, req, transport.get_config_object(), [&transport, ip, port](int res_code, demo::COMMAND_EXAMPLE_1::response& rsp, net_utils::connection_context_base& ctx)
- {
- if(res_code < 0)
- {
- LOG_ERROR("Failed to invoke to " << ip << ":" << port);
- }else
- {//invoked ok
- CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response");
- CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response");
- CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response");
- LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 async invoked ok", LOG_LEVEL_0);
- }
- transport.get_config_object().close(ctx.m_connection_id);
- return true;
- });
- LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 async invoke requested", LOG_LEVEL_0);
- }
- });
- }else
- {
- net_utils::connection_context_base ctx = AUTO_VAL_INIT(ctx);
- bool r = transport.connect(ip, port, 10000, ctx);
- CHECK_AND_ASSERT_MES(r, false, "failed to connect to " << ip << ":" << port);
- demo::COMMAND_EXAMPLE_1::response rsp = AUTO_VAL_INIT(rsp);
- LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 sync invoke requested", LOG_LEVEL_0);
- r = epee::net_utils::invoke_remote_command2(ctx.m_connection_id, id, req, rsp, transport.get_config_object());
- CHECK_AND_ASSERT_MES(r, false, "failed to invoke levin request");
- CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response");
- CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response");
- CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response");
- transport.get_config_object().close(ctx.m_connection_id);
- LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 sync invoked ok", LOG_LEVEL_0);
- }
- return true;
-}
-
-
-int main(int argc, char* argv[])
-{
- TRY_ENTRY();
- string_tools::set_module_name_and_folder(argv[0]);
-
- //set up logging options
- log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
- log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
- log_space::log_singletone::add_logger(LOGGER_FILE,
- log_space::log_singletone::get_default_log_file().c_str(),
- log_space::log_singletone::get_default_log_folder().c_str());
-
-
-
- LOG_PRINT("Demo server starting ...", LOG_LEVEL_0);
-
-
- demo::demo_levin_server srv;
-
- start_default_console(&srv, "#");
-
- std::string bind_param = "0.0.0.0";
- std::string port = "12345";
-
- if(!srv.init(port, bind_param))
- {
- LOG_ERROR("Failed to initialize srv!");
- return 1;
- }
-
- srv.run();
-
- size_t c = 1;
- while (!srv.is_stop())
- {
-
- demo::COMMAND_EXAMPLE_1::request req;
- req.sub = demo::get_test_data();
- bool r = communicate(srv.get_server(), demo::COMMAND_EXAMPLE_1::ID, req, "127.0.0.1", port, (c%2 == 0));
- misc_utils::sleep_no_w(1000);
- ++c;
- }
- bool r = srv.wait_stop();
- CHECK_AND_ASSERT_MES(r, 1, "failed to wait server stop");
-
-
- srv.deinit();
-
- LOG_PRINT("Demo server stoped.", LOG_LEVEL_0);
- return 1;
-
- CATCH_ENTRY_L0("main", 1);
-}
-
-/************************************************************************/
-/* */
-/************************************************************************/
-namespace demo
-{
- bool demo_levin_server::init(const std::string& bind_port, const std::string& bind_ip)
- {
- m_net_server.get_config_object().m_pcommands_handler = this;
- LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port);
- return m_net_server.init_server(bind_port, bind_ip);
- }
-
- bool demo_levin_server::run()
- {
- m_stop = false;
- //here you can set worker threads count
- int thrds_count = 4;
- m_net_server.get_config_object().m_invoke_timeout = 10000;
- m_net_server.get_config_object().m_pcommands_handler = this;
-
- //go to loop
- LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0);
- if(!m_net_server.run_server(thrds_count, false))
- {
- LOG_ERROR("Failed to run net tcp server!");
- }
-
- LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0);
- return true;
- }
-
- bool demo_levin_server::deinit()
- {
- return m_net_server.deinit_server();
- }
-
- bool demo_levin_server::send_stop_signal()
- {
- m_net_server.send_stop_signal();
- return true;
- }
- int demo_levin_server::handle_command_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context)
- {
- CHECK_AND_ASSERT_MES(arg.sub == demo::get_test_data(), false, "wrong request");
- rsp.m_success = true;
- rsp.subs.push_back(arg.sub);
- LOG_PRINT_GREEN("Server COMMAND_EXAMPLE_1 ok", LOG_LEVEL_0);
- return 1;
- }
- int demo_levin_server::handle_command_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context)
- {
- return 1;
- }
- int demo_levin_server::handle_notify_1(int command, COMMAND_EXAMPLE_1::request& arg, const net_utils::connection_context_base& context)
- {
- return 1;
- }
- int demo_levin_server::handle_notify_2(int command, COMMAND_EXAMPLE_2::request& arg, const net_utils::connection_context_base& context)
- {
- return 1;
- }
-}
diff --git a/contrib/epee/demo/demo_levin_server/demo_levin_server.h b/contrib/epee/demo/demo_levin_server/demo_levin_server.h
deleted file mode 100644
index 5a6f68f2d..000000000
--- a/contrib/epee/demo/demo_levin_server/demo_levin_server.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * 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.
-// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
-//
-
-
-
-#pragma once
-#include <boost/thread.hpp>
-#include <boost/bind.hpp>
-
-#include "net/levin_server_cp2.h"
-#include "transport_defs.h"
-#include "storages/levin_abstract_invoke2.h"
-
-using namespace epee;
-
-namespace demo
-{
-
- class demo_levin_server: public levin::levin_commands_handler<>
- {
- public:
- bool run();
- bool init(const std::string& bind_port = "11112", const std::string& bind_ip = "0.0.0.0");
- bool deinit();
- bool send_stop_signal();
- bool is_stop(){return m_stop;}
- bool wait_stop(){return m_net_server.timed_wait_server_stop(100000);}
- net_utils::boosted_levin_async_server& get_server(){return m_net_server;}
- private:
-
-
- CHAIN_LEVIN_INVOKE_MAP(); //move levin_commands_handler interface invoke(...) callbacks into invoke map
- CHAIN_LEVIN_NOTIFY_STUB(); //move levin_commands_handler interface notify(...) callbacks into nothing
-
- BEGIN_INVOKE_MAP2(demo_levin_server)
- HANDLE_INVOKE_T2(COMMAND_EXAMPLE_1, &demo_levin_server::handle_command_1)
- HANDLE_INVOKE_T2(COMMAND_EXAMPLE_2, &demo_levin_server::handle_command_2)
- HANDLE_NOTIFY_T2(COMMAND_EXAMPLE_1, &demo_levin_server::handle_notify_1)
- HANDLE_NOTIFY_T2(COMMAND_EXAMPLE_2, &demo_levin_server::handle_notify_2)
- END_INVOKE_MAP2()
-
- //----------------- commands handlers ----------------------------------------------
- int handle_command_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context);
- int handle_command_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context);
- int handle_notify_1(int command, COMMAND_EXAMPLE_1::request& arg, const net_utils::connection_context_base& context);
- int handle_notify_2(int command, COMMAND_EXAMPLE_2::request& arg, const net_utils::connection_context_base& context);
- //----------------------------------------------------------------------------------
- net_utils::boosted_levin_async_server m_net_server;
- std::atomic<bool> m_stop;
-
- };
-}
-
diff --git a/contrib/epee/include/storages/activity_notifier.h b/contrib/epee/include/storages/activity_notifier.h
deleted file mode 100644
index 14b6ebbfb..000000000
--- a/contrib/epee/include/storages/activity_notifier.h
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * 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.
-// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
-//
-
-
-
-#pragma once
-
-#include "inmemtoxml.h"
-
-//#include "levin/levin_server.h"
-
-namespace epee
-{
-
-class activity_printer_base
-{
-public:
- activity_printer_base(){}
- virtual ~activity_printer_base(){}
-};
-
-template<class A>
-class notify_activity_printer: public activity_printer_base
-{
-public:
- notify_activity_printer(int level, A& arg, bool is_notify_mode = true):m_ref_arg(arg), m_level(level), m_is_notify_mode(is_notify_mode)
- {
- m_command_name = typeid(m_ref_arg).name();
- m_command_name.erase(0, 7);
- m_command_name.erase(m_command_name.size()-10, m_command_name.size()-1);
- if(level == log_space::get_set_log_detalisation_level())
- {
- LOG_PRINT(m_command_name, level);
- }
- else if(level+1 == log_space::get_set_log_detalisation_level())
- {
- LOG_PRINT(" -->>" << m_command_name, level);
- }
- else if(level+2 == log_space::get_set_log_detalisation_level())
- {
- LOG_PRINT(" -->>" << m_command_name << "\n" << StorageNamed::xml::get_t_as_xml(m_ref_arg), level);
- }
- }
-
- virtual ~notify_activity_printer()
- {
- if(m_is_notify_mode)
- {
- if(m_level+1 == log_space::get_set_log_detalisation_level())
- {
- LOG_PRINT(" <<--" << m_command_name, m_level);
- }
- }
- }
-protected:
- std::string m_command_name;
- A& m_ref_arg;
- int m_level;
- bool m_is_notify_mode;
-};
-
-template<class A, class R>
-class command_activity_printer: public notify_activity_printer<A>
-{
-public:
- command_activity_printer(int level, A& arg, R& rsp):notify_activity_printer(level, arg, false), m_ref_rsp(rsp)
- {
- }
-
- virtual ~command_activity_printer()
- {
- if(m_level+1 == log_space::get_set_log_detalisation_level())
- {
- LOG_PRINT(" <<--" << m_command_name, m_level);
- }
- else if(m_level+2 == log_space::get_set_log_detalisation_level())
- {
- LOG_PRINT(" <<--" << m_command_name << "\n" << StorageNamed::trace_as_xml(m_ref_rsp), m_level);
- }
- }
-private:
- R& m_ref_rsp;
-};
-
-template<class A, class R>
-activity_printer_base* create_activity_printer(int level, A& arg, R& rsp)
-{
- return new command_activity_printer<A, R>(level, arg, rsp);
-}
-
-template<class A>
-activity_printer_base* create_activity_printer(int level, A& arg)
-{
- return new notify_activity_printer<A>(level, arg);
-}
-
-}
-
-#define PRINT_COMMAND_ACTIVITY(level) boost::shared_ptr<activity_printer_base> local_activity_printer(create_activity_printer(level, in_struct, out_struct));
-#define PRINT_NOTIFY_ACTIVITY(level) boost::shared_ptr<activity_printer_base> local_activity_printer(create_activity_printer(level, in_struct));
-
-#define PRINT_ACTIVITY(level) \
-{std::string some_str = typeid(in_struct).name(); \
- some_str.erase(0, 7); \
- some_str.erase(some_str.size()-10, some_str.size()-1); \
- LOG_PRINT(some_str, level);}
-
-}
-
diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp
index f1d74a2a3..139e7b7d6 100644
--- a/contrib/epee/src/mlog.cpp
+++ b/contrib/epee/src/mlog.cpp
@@ -108,6 +108,32 @@ void mlog_configure(const std::string &filename_base, bool console)
mlog_set_categories(monero_log);
}
+static const char *get_default_categories(int level)
+{
+ const char *categories = "";
+ switch (level)
+ {
+ case 0:
+ categories = "*:FATAL,net*:FATAL,global:INFO,verify:FATAL,stacktrace:INFO";
+ break;
+ case 1:
+ categories = "*:WARNING,global:INFO,stacktrace:INFO";
+ break;
+ case 2:
+ categories = "*:DEBUG";
+ break;
+ case 3:
+ categories = "*:TRACE";
+ break;
+ case 4:
+ categories = "*:TRACE";
+ break;
+ default:
+ break;
+ }
+ return categories;
+}
+
void mlog_set_categories(const char *categories)
{
el::Loggers::setCategories(categories);
@@ -117,30 +143,9 @@ void mlog_set_categories(const char *categories)
// maps epee style log level to new logging system
void mlog_set_log_level(int level)
{
- const char *settings = NULL;
- switch (level)
- {
- case 0:
- settings = "*:FATAL,net*:FATAL,global:INFO,verify:FATAL";
- break;
- case 1:
- settings = "*:WARNING,global:INFO";
- break;
- case 2:
- settings = "*:INFO";
- break;
- case 3:
- settings = "*:DEBUG";
- break;
- case 4:
- settings = "*:TRACE";
- break;
- default:
- return;
- }
-
- el::Loggers::setCategories(settings);
- MINFO("Mew log categories: " << settings);
+ const char *categories = get_default_categories(level);
+ el::Loggers::setCategories(categories);
+ MINFO("Mew log categories: " << categories);
}
void mlog_set_log(const char *log)
@@ -151,7 +156,14 @@ void mlog_set_log(const char *log)
level = strtoll(log, &ptr, 10);
if (ptr && *ptr)
{
- mlog_set_categories(log);
+ // we can have a default level, eg, 2,foo:ERROR
+ if (*ptr == ',') {
+ std::string new_categories = std::string(get_default_categories(level)) + ptr;
+ mlog_set_categories(new_categories.c_str());
+ }
+ else {
+ mlog_set_categories(log);
+ }
}
else if (level >= 0 && level <= 4)
{
diff --git a/snapcraft.yaml b/snapcraft.yaml
index 2ad7ad603..17910392b 100644
--- a/snapcraft.yaml
+++ b/snapcraft.yaml
@@ -1,5 +1,5 @@
name: monero
-version: 0 # TODO: change this to release version in CI builds
+version: 0.10.1 # Current stable version
summary: "Monero: the secure, private, untraceable cryptocurrency https://getmonero.org"
description: |
Monero is a private, secure, untraceable, decentralised digital currency.
@@ -9,37 +9,28 @@ grade: devel
confinement: strict
apps:
- d:
+ monerod:
daemon: forking
- command: daemon.bash
+ command: |
+ monerod --detach --data-dir ${SNAP_DATA}
plugs:
- network
- network-bind
-
- log:
- command: log.bash
-
- monero:
- command: wallet.bash
+ monero-wallet-rpc:
+ command: |
+ monero-wallet-rpc --log-file ${SNAP_USER_DATA}
plugs:
+ - home
+ - network
+ - network-bind
+ monero-wallet-cli:
+ command: |
+ monero-wallet-cli --log-file ${SNAP_USER_DATA}
+ plugs:
+ - home
- network
parts:
- wrapper:
- plugin: dump
- source: .
- stage-packages:
- - rlwrap
- organize:
- contrib/snap/daemon.bash: daemon.bash
- contrib/snap/log.bash: log.bash
- contrib/snap/wallet.bash: wallet.bash
- snap:
- - daemon.bash
- - log.bash
- - wallet.bash
- - usr/bin/rlwrap
-
cmake-build:
plugin: cmake
configflags:
@@ -51,7 +42,6 @@ parts:
source: .
build-packages:
- gcc
- - cmake
- pkg-config
- libunbound-dev
- libevent-dev
@@ -68,6 +58,8 @@ parts:
- libminiupnpc10
- libunbound2
- libunwind8
- snap:
+ prime:
- bin
- - usr
+ - usr/lib/
+ - -usr/lib/gcc
+ - -usr/share
diff --git a/src/common/stack_trace.cpp b/src/common/stack_trace.cpp
index ce05b7e04..99e4bda2c 100644
--- a/src/common/stack_trace.cpp
+++ b/src/common/stack_trace.cpp
@@ -38,7 +38,7 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "stacktrace"
-#define ST_LOG(x) CERROR(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x
+#define ST_LOG(x) CINFO(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x
// from http://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 8f1f0b260..789687ce0 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -636,7 +636,7 @@ crypto::hash Blockchain::get_block_id_by_height(uint64_t height) const
return null_hash;
}
//------------------------------------------------------------------
-bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk) const
+bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@@ -645,6 +645,8 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk) const
try
{
blk = m_db->get_block(h);
+ if (orphan)
+ *orphan = false;
return true;
}
// try to find block in alternative chain
@@ -654,6 +656,8 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk) const
if (m_alternative_chains.end() != it_alt)
{
blk = it_alt->second.bl;
+ if (orphan)
+ *orphan = true;
return true;
}
}
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 245dc6e73..ca665e1d4 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -197,10 +197,11 @@ namespace cryptonote
*
* @param h the hash to look for
* @param blk return-by-reference variable to put result block in
+ * @param orphan if non-NULL, will be set to true if not in the main chain, false otherwise
*
* @return true if the block was found, else false
*/
- bool get_block_by_hash(const crypto::hash &h, block &blk) const;
+ bool get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan = NULL) const;
/**
* @brief get all block hashes (main chain, alt chains, and invalid blocks)
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 5294431d6..22d473b35 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -487,6 +487,13 @@ namespace cryptonote
}
//std::cout << "!"<< tx.vin.size() << std::endl;
+ if (bad_semantics_txes.find(tx_hash) != bad_semantics_txes.end())
+ {
+ LOG_PRINT_L1("Transaction already seen with bad semantics, rejected");
+ tvc.m_verifivation_failed = true;
+ return false;
+ }
+
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
const size_t max_tx_version = version == 1 ? 1 : 2;
if (tx.version == 0 || tx.version > max_tx_version)
@@ -496,6 +503,18 @@ namespace cryptonote
return false;
}
+ if(m_mempool.have_tx(tx_hash))
+ {
+ LOG_PRINT_L2("tx " << tx_hash << "already have transaction in tx_pool");
+ return true;
+ }
+
+ if(m_blockchain_storage.have_tx(tx_hash))
+ {
+ LOG_PRINT_L2("tx " << tx_hash << " already have transaction in blockchain");
+ return true;
+ }
+
if(!check_tx_syntax(tx))
{
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " syntax, rejected");
@@ -522,6 +541,7 @@ namespace cryptonote
if(!check_tx_semantic(tx, keeped_by_block))
{
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected");
+ bad_semantics_txes.insert(tx_hash);
tvc.m_verifivation_failed = true;
return false;
}
@@ -977,9 +997,9 @@ namespace cryptonote
return m_blockchain_storage.get_block_id_by_height(height);
}
//-----------------------------------------------------------------------------------------------
- bool core::get_block_by_hash(const crypto::hash &h, block &blk) const
+ bool core::get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan) const
{
- return m_blockchain_storage.get_block_by_hash(h, blk);
+ return m_blockchain_storage.get_block_by_hash(h, blk, orphan);
}
//-----------------------------------------------------------------------------------------------
std::string core::print_pool(bool short_format) const
@@ -1000,12 +1020,11 @@ namespace cryptonote
MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
<< "The daemon will start synchronizing with the network. It may take up to several hours." << ENDL
<< ENDL
- << "You can set the level of process detailization* through \"set_log <level|categories>\" command*, where <level> is between 0 (no details) and 4 (very verbose), or custom category based levels (eg, *:WARNING)" << ENDL
- << ENDL
- << "Use \"help\" command to see the list of available commands." << ENDL
+ << "You can set the level of process detailization* through \"set_log <level|categories>\" command*," << ENDL
+ << "where <level> is between 0 (no details) and 4 (very verbose), or custom category based levels (eg, *:WARNING)" << ENDL
<< ENDL
- << "Note: in case you need to interrupt the process, use \"exit\" command. Otherwise, the current progress won't be saved." << ENDL
- << "**********************************************************************");
+ << "Use the \"help\" command to see the list of available commands." << ENDL
+ << "**********************************************************************" << ENDL);
m_starter_message_showed = true;
}
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index fa67ff265..1b9518c96 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -330,7 +330,7 @@ namespace cryptonote
*
* @note see Blockchain::get_block_by_hash
*/
- bool get_block_by_hash(const crypto::hash &h, block &blk) const;
+ bool get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan = NULL) const;
/**
* @copydoc Blockchain::get_alternative_blocks
@@ -824,6 +824,8 @@ namespace cryptonote
size_t block_sync_size;
time_t start_time;
+
+ std::unordered_set<crypto::hash> bad_semantics_txes;
};
}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 58388f8f7..73e4fa72f 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -46,6 +46,8 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net.cn"
+#define MLOG_P2P_MESSAGE(x) MCINFO("net.p2p.msg", context << x)
+
namespace cryptonote
{
@@ -314,7 +316,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_BLOCK (hop " << arg.hop << ")");
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_BLOCK (hop " << arg.hop << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
m_core.pause_mine();
@@ -365,7 +367,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_FLUFFY_BLOCK (hop " << arg.hop << ")");
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_FLUFFY_BLOCK (hop " << arg.hop << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
@@ -613,7 +615,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_REQUEST_FLUFFY_MISSING_TX");
+ MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_FLUFFY_MISSING_TX (" << arg.missing_tx_indices.size() << " txes)");
std::list<block> local_blocks;
std::list<transaction> local_txs;
@@ -671,7 +673,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_TRANSACTIONS");
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_TRANSACTIONS (" << arg.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
@@ -703,7 +705,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_REQUEST_GET_OBJECTS");
+ MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks, " << arg.txs.size() << " txes)");
NOTIFY_RESPONSE_GET_OBJECTS::request rsp;
if(!m_core.handle_get_objects(arg, rsp, context))
{
@@ -743,7 +745,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_RESPONSE_GET_OBJECTS");
+ MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_GET_OBJECTS (" << arg.blocks.size() << " blocks, " << arg.txs.size() << " txes)");
// calculate size of request - mainly for logging/debug
size_t size = 0;
@@ -933,7 +935,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << arg.block_ids.size());
+ MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
NOTIFY_RESPONSE_CHAIN_ENTRY::request r;
if(!m_core.find_blockchain_supplement(arg.block_ids, r))
{
@@ -1020,13 +1022,10 @@ namespace cryptonote
bool val_expected = false;
if(m_synchronized.compare_exchange_strong(val_expected, true))
{
- MGINFO_GREEN(ENDL << "**********************************************************************" << ENDL
+ MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
<< "You are now synchronized with the network. You may now start monero-wallet-cli." << ENDL
<< ENDL
- << "Please note, that the blockchain will be saved only after you quit the daemon with \"exit\" command or if you use \"save\" command." << ENDL
- << "Otherwise, you will possibly need to synchronize the blockchain again." << ENDL
- << ENDL
- << "Use \"help\" command to see the list of available commands." << ENDL
+ << "Use the \"help\" command to see the list of available commands." << ENDL
<< "**********************************************************************");
m_core.on_synchronized();
}
@@ -1048,7 +1047,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
+ MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
<< ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height);
if(!arg.m_block_ids.size())
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 3f5a5ad93..40598fc0f 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -110,7 +110,12 @@ namespace nodetool
void serialize(Archive &a, const t_version_type ver)
{
a & m_peerlist;
- a & m_config.m_peer_id;
+ if (ver == 0)
+ {
+ // from v1, we do not store the peer id anymore
+ peerid_type peer_id;
+ a & peer_id;
+ }
}
// debug functions
bool log_peerlist();
@@ -162,6 +167,7 @@ namespace nodetool
#endif
int handle_get_support_flags(int command, COMMAND_REQUEST_SUPPORT_FLAGS::request& arg, COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context);
bool init_config();
+ bool make_default_peer_id();
bool make_default_config();
bool store_config();
bool check_trust(const proof_of_trust& tr);
@@ -229,6 +235,9 @@ namespace nodetool
bool has_too_many_connections(const uint32_t ip);
+ bool check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp);
+ bool gray_peerlist_housekeeping();
+
void kill() { ///< will be called e.g. from deinit()
_info("Killing the net_node");
is_closing = true;
@@ -289,6 +298,7 @@ namespace nodetool
epee::math_helper::once_a_time_seconds<P2P_DEFAULT_HANDSHAKE_INTERVAL> m_peer_handshake_idle_maker_interval;
epee::math_helper::once_a_time_seconds<1> m_connections_maker_interval;
epee::math_helper::once_a_time_seconds<60*30, false> m_peerlist_store_interval;
+ epee::math_helper::once_a_time_seconds<60> m_gray_peerlist_housekeeping_interval;
std::string m_bind_ip;
std::string m_port;
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 60e51c222..0e43d9579 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -173,6 +173,9 @@ namespace nodetool
make_default_config();
}
+ // always recreate a new peer id
+ make_default_peer_id();
+
//at this moment we have hardcoded config
m_config.m_net_config.handshake_interval = P2P_DEFAULT_HANDSHAKE_INTERVAL;
m_config.m_net_config.packet_max_size = P2P_DEFAULT_PACKET_MAX_SIZE; //20 MB limit
@@ -205,20 +208,26 @@ namespace nodetool
if(time(nullptr) >= it->second)
{
m_blocked_ips.erase(it);
- MLOG_CYAN(el::Level::Info, "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
+ MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
return true;
}
return false;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::make_default_config()
+ bool node_server<t_payload_net_handler>::make_default_peer_id()
{
m_config.m_peer_id = crypto::rand<uint64_t>();
return true;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::make_default_config()
+ {
+ return make_default_peer_id();
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::block_ip(uint32_t addr, time_t seconds)
{
CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
@@ -237,7 +246,7 @@ namespace nodetool
for (const auto &c: conns)
m_net_server.get_config_object().close(c);
- MLOG_CYAN(el::Level::Info, "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " blocked.");
+ MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " blocked.");
return true;
}
//-----------------------------------------------------------------------------------
@@ -249,7 +258,7 @@ namespace nodetool
if (i == m_blocked_ips.end())
return false;
m_blocked_ips.erase(i);
- MLOG_CYAN(el::Level::Info, "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
+ MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
return true;
}
//-----------------------------------------------------------------------------------
@@ -926,6 +935,50 @@ namespace nodetool
return true;
}
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp)
+ {
+ LOG_PRINT_L1("Connecting to " << epee::string_tools::get_ip_string_from_int32(na.ip) << ":"
+ << epee::string_tools::num_to_string_fast(na.port) << "(last_seen: "
+ << (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never")
+ << ")...");
+
+ typename net_server::t_connection_context con = AUTO_VAL_INIT(con);
+ bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(na.ip),
+ epee::string_tools::num_to_string_fast(na.port),
+ m_config.m_net_config.connection_timeout,
+ con);
+
+ if (!res) {
+ bool is_priority = is_priority_node(na);
+
+ LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to "
+ << epee::string_tools::get_ip_string_from_int32(na.ip)
+ << ":" << epee::string_tools::num_to_string_fast(na.port));
+
+ return false;
+ }
+
+ peerid_type pi = AUTO_VAL_INIT(pi);
+ res = do_handshake_with_peer(pi, con, true);
+
+ if (!res) {
+ bool is_priority = is_priority_node(na);
+
+ LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Failed to HANDSHAKE with peer "
+ << epee::string_tools::get_ip_string_from_int32(na.ip)
+ << ":" << epee::string_tools::num_to_string_fast(na.port));
+
+ return false;
+ }
+
+ m_net_server.get_config_object().close(con.m_connection_id);
+
+ LOG_DEBUG_CC(con, "CONNECTION HANDSHAKED OK AND CLOSED.");
+
+ return true;
+ }
+
#undef LOG_PRINT_CC_PRIORITY_NODE
//-----------------------------------------------------------------------------------
@@ -1097,6 +1150,7 @@ namespace nodetool
{
m_peer_handshake_idle_maker_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::peer_sync_idle_maker, this));
m_connections_maker_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::connections_maker, this));
+ m_gray_peerlist_housekeeping_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::gray_peerlist_housekeeping, this));
m_peerlist_store_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::store_config, this));
return true;
}
@@ -1704,4 +1758,30 @@ namespace nodetool
return count > max_connections;
}
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::gray_peerlist_housekeeping()
+ {
+ peerlist_entry pe = AUTO_VAL_INIT(pe);
+
+ if (!m_peerlist.get_random_gray_peer(pe)) {
+ return false;
+ }
+
+ bool success = check_connection_and_handshake_with_peer(pe.adr, pe.last_seen);
+
+ if (!success) {
+ m_peerlist.remove_from_peer_gray(pe);
+
+ LOG_PRINT_L2("PEER EVICTED FROM GRAY PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id);
+
+ return true;
+ }
+
+ m_peerlist.set_peer_just_seen(pe.id, pe.adr);
+
+ LOG_PRINT_L2("PEER PROMOTED TO WHITE PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id);
+
+ return true;
+ }
}
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index db9387ceb..4797eb82b 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -81,6 +81,8 @@ namespace nodetool
bool set_peer_just_seen(peerid_type peer, const net_address& addr);
bool set_peer_unreachable(const peerlist_entry& pr);
bool is_ip_allowed(uint32_t ip);
+ bool get_random_gray_peer(peerlist_entry& pe);
+ bool remove_from_peer_gray(const peerlist_entry& pe);
private:
@@ -396,6 +398,50 @@ namespace nodetool
return true;
}
//--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::get_random_gray_peer(peerlist_entry& pe)
+ {
+ TRY_ENTRY();
+
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+
+ if (m_peers_gray.empty()) {
+ return false;
+ }
+
+ size_t x = crypto::rand<size_t>() % (m_peers_gray.size() + 1);
+ size_t res = (x * x * x) / (m_peers_gray.size() * m_peers_gray.size()); //parabola \/
+
+ LOG_PRINT_L3("Random gray peer index=" << res << "(x="<< x << ", max_index=" << m_peers_gray.size() << ")");
+
+ peers_indexed::index<by_time>::type& by_time_index = m_peers_gray.get<by_time>();
+ pe = *epee::misc_utils::move_it_backward(--by_time_index.end(), res);
+
+ return true;
+
+ CATCH_ENTRY_L0("peerlist_manager::get_random_gray_peer()", false);
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::remove_from_peer_gray(const peerlist_entry& pe)
+ {
+ TRY_ENTRY();
+
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+
+ peers_indexed::index_iterator<by_addr>::type iterator = m_peers_gray.get<by_addr>().find(pe.adr);
+
+ if (iterator != m_peers_gray.get<by_addr>().end()) {
+ m_peers_gray.erase(iterator);
+ }
+
+ return true;
+
+ CATCH_ENTRY_L0("peerlist_manager::remove_from_peer_gray()", false);
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
}
BOOST_CLASS_VERSION(nodetool::peerlist_manager, CURRENT_PEERLIST_STORAGE_ARCHIVE_VER)
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 74fed0ede..b8f3596e8 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -797,23 +797,6 @@ namespace rct {
tools::thread_group threadpool(tools::thread_group::optimal_with_max(threads));
if (semantics) {
- results.clear();
- results.resize(rv.outPk.size());
- tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
- for (size_t i = 0; i < rv.outPk.size(); i++) {
- region.run([&, i] {
- results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
- });
- }
- });
-
- for (size_t i = 0; i < results.size(); ++i) {
- if (!results[i]) {
- LOG_PRINT_L1("Range proof verified failed for output " << i);
- return false;
- }
- }
-
key sumOutpks = identity();
for (size_t i = 0; i < rv.outPk.size(); i++) {
addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
@@ -833,6 +816,23 @@ namespace rct {
LOG_PRINT_L1("Sum check failed");
return false;
}
+
+ results.clear();
+ results.resize(rv.outPk.size());
+ tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
+ for (size_t i = 0; i < rv.outPk.size(); i++) {
+ region.run([&, i] {
+ results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
+ });
+ }
+ });
+
+ for (size_t i = 0; i < results.size(); ++i) {
+ if (!results[i]) {
+ LOG_PRINT_L1("Range proof verified failed for output " << i);
+ return false;
+ }
+ }
}
else {
const key message = get_pre_mlsag_hash(rv);
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 1c5c321da..7d896e491 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -985,7 +985,8 @@ namespace cryptonote
return false;
}
block blk;
- bool have_block = m_core.get_block_by_hash(block_hash, blk);
+ bool orphan = false;
+ bool have_block = m_core.get_block_by_hash(block_hash, blk, &orphan);
if (!have_block)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
@@ -999,7 +1000,7 @@ namespace cryptonote
return false;
}
uint64_t block_height = boost::get<txin_gen>(blk.miner_tx.vin.front()).height;
- bool response_filled = fill_block_header_response(blk, false, block_height, block_hash, res.block_header);
+ bool response_filled = fill_block_header_response(blk, orphan, block_height, block_hash, res.block_header);
if (!response_filled)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
@@ -1123,7 +1124,8 @@ namespace cryptonote
block_hash = m_core.get_block_id_by_height(req.height);
}
block blk;
- bool have_block = m_core.get_block_by_hash(block_hash, blk);
+ bool orphan = false;
+ bool have_block = m_core.get_block_by_hash(block_hash, blk, &orphan);
if (!have_block)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
@@ -1137,7 +1139,7 @@ namespace cryptonote
return false;
}
uint64_t block_height = boost::get<txin_gen>(blk.miner_tx.vin.front()).height;
- bool response_filled = fill_block_header_response(blk, false, block_height, block_hash, res.block_header);
+ bool response_filled = fill_block_header_response(blk, orphan, block_height, block_hash, res.block_header);
if (!response_filled)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 84871e8bb..767bcc715 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -194,3 +194,5 @@ private:
bool m_restricted;
};
}
+
+BOOST_CLASS_VERSION(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >, 1);
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index c08b16a5f..4348b8a62 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -87,6 +87,8 @@ using namespace cryptonote;
#define FEE_ESTIMATE_GRACE_BLOCKS 10 // estimate fee valid for that many blocks
+#define SECOND_OUTPUT_RELATEDNESS_THRESHOLD 0.0f
+
#define KILL_IOSERVICE() \
do { \
work.reset(); \
@@ -2720,6 +2722,19 @@ namespace
vec.pop_back();
return res;
}
+
+ template<typename T>
+ void pop_if_present(std::vector<T>& vec, T e)
+ {
+ for (size_t i = 0; i < vec.size(); ++i)
+ {
+ if (e == vec[i])
+ {
+ pop_index (vec, i);
+ return;
+ }
+ }
+ }
}
//----------------------------------------------------------------------------------------------------
// This returns a handwavy estimation of how much two outputs are related
@@ -4028,6 +4043,17 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money) co
return picks;
}
+static bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices)
+{
+ if (!use_rct)
+ return false;
+ if (n_transfers > 1)
+ return false;
+ if (unused_dust_indices.empty() && unused_transfers_indices.empty())
+ return false;
+ return true;
+}
+
// Another implementation of transaction creation that is hopefully better
// While there is anything left to pay, it goes through random outputs and tries
// to fill the next destination/amount. If it fully fills it, it will use the
@@ -4152,9 +4178,19 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// - we have something to send
// - or we need to gather more fee
// - or we have just one input in that tx, which is rct (to try and make all/most rct txes 2/2)
- while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || (use_rct && txes.back().selected_transfers.size() == 1)) {
+ while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), unused_transfers_indices, unused_dust_indices)) {
TX &tx = txes.back();
+ LOG_PRINT_L2("Start of loop with " << unused_transfers_indices.size() << " " << unused_dust_indices.size());
+ LOG_PRINT_L2("unused_transfers_indices:");
+ for (auto t: unused_transfers_indices)
+ LOG_PRINT_L2(" " << t);
+ LOG_PRINT_L2("unused_dust_indices:");
+ for (auto t: unused_dust_indices)
+ LOG_PRINT_L2(" " << t);
+ LOG_PRINT_L2("dsts size " << dsts.size() << ", first " << (dsts.empty() ? -1 : dsts[0].amount));
+ LOG_PRINT_L2("adding_fee " << adding_fee << ", use_rct " << use_rct);
+
// if we need to spend money and don't have any left, we fail
if (unused_dust_indices.empty() && unused_transfers_indices.empty()) {
LOG_PRINT_L2("No more outputs to choose from");
@@ -4167,9 +4203,20 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
if ((dsts.empty() || dsts[0].amount == 0) && !adding_fee)
// the "make rct txes 2/2" case - we pick a small value output to "clean up" the wallet too
idx = pop_best_value(unused_dust_indices.empty() ? unused_transfers_indices : unused_dust_indices, tx.selected_transfers, true);
- else if (!prefered_inputs.empty())
+ else if (!prefered_inputs.empty()) {
idx = pop_back(prefered_inputs);
- else
+ pop_if_present(unused_transfers_indices, idx);
+ pop_if_present(unused_dust_indices, idx);
+
+ // since we're trying to add a second output which is not strictly needed,
+ // we only add it if it's unrelated enough to the first one
+ float relatedness = get_output_relatedness(m_transfers[idx], m_transfers[tx.selected_transfers.front()]);
+ if (relatedness > SECOND_OUTPUT_RELATEDNESS_THRESHOLD)
+ {
+ LOG_PRINT_L2("Second outout was not strictly needed, and relatedness " << relatedness << ", not adding");
+ break;
+ }
+ } else
idx = pop_best_value(unused_transfers_indices.empty() ? unused_dust_indices : unused_transfers_indices, tx.selected_transfers);
const transfer_details &td = m_transfers[idx];
diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp
index be17f01ad..2682f15d3 100644
--- a/tests/unit_tests/hardfork.cpp
+++ b/tests/unit_tests/hardfork.cpp
@@ -51,7 +51,7 @@ public:
virtual std::string get_db_name() const { return std::string(); }
virtual bool lock() { return true; }
virtual void unlock() { }
- virtual bool batch_start(uint64_t batch_num_blocks=0) {}
+ virtual bool batch_start(uint64_t batch_num_blocks=0) { return true; }
virtual void batch_stop() {}
virtual void set_batch_transactions(bool) {}
virtual void block_txn_start(bool readonly=false) {}