Merge branch 'develop' into feature/son-for-ethereum
This commit is contained in:
commit
79efcb8dc9
14 changed files with 184 additions and 351 deletions
|
|
@ -917,6 +917,7 @@ void application::initialize(const fc::path &data_dir, const boost::program_opti
|
||||||
wanted.insert("accounts_list");
|
wanted.insert("accounts_list");
|
||||||
wanted.insert("affiliate_stats");
|
wanted.insert("affiliate_stats");
|
||||||
}
|
}
|
||||||
|
if (!wanted.count("delayed_node") && !wanted.count("witness")) // explicitly requested delayed_node functionality suppresses witness functions
|
||||||
wanted.insert("witness");
|
wanted.insert("witness");
|
||||||
wanted.insert("bookie");
|
wanted.insert("bookie");
|
||||||
|
|
||||||
|
|
@ -949,7 +950,7 @@ void application::startup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<abstract_plugin> application::get_plugin(const string &name) const {
|
std::shared_ptr<abstract_plugin> application::get_plugin(const string &name) const {
|
||||||
return my->_active_plugins[name];
|
return is_plugin_enabled(name) ? my->_active_plugins[name] : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool application::is_plugin_enabled(const string &name) const {
|
bool application::is_plugin_enabled(const string &name) const {
|
||||||
|
|
|
||||||
|
|
@ -47,4 +47,3 @@ namespace graphene { namespace net {
|
||||||
const core_message_type_enum get_current_connections_reply_message::type = core_message_type_enum::get_current_connections_reply_message_type;
|
const core_message_type_enum get_current_connections_reply_message::type = core_message_type_enum::get_current_connections_reply_message_type;
|
||||||
|
|
||||||
} } // graphene::net
|
} } // graphene::net
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#define GRAPHENE_NET_PROTOCOL_VERSION 106
|
#define GRAPHENE_NET_PROTOCOL_VERSION 106
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -110,3 +112,6 @@
|
||||||
#define GRAPHENE_NET_MAX_NESTED_OBJECTS (250)
|
#define GRAPHENE_NET_MAX_NESTED_OBJECTS (250)
|
||||||
|
|
||||||
#define MAXIMUM_PEERDB_SIZE 1000
|
#define MAXIMUM_PEERDB_SIZE 1000
|
||||||
|
|
||||||
|
constexpr size_t MAX_BLOCKS_TO_HANDLE_AT_ONCE = 200;
|
||||||
|
constexpr size_t MAX_SYNC_BLOCKS_TO_PREFETCH = 10 * MAX_BLOCKS_TO_HANDLE_AT_ONCE;
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ namespace graphene { namespace net {
|
||||||
class node_delegate
|
class node_delegate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~node_delegate(){}
|
virtual ~node_delegate() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If delegate has the item, the network has no need to fetch it.
|
* If delegate has the item, the network has no need to fetch it.
|
||||||
|
|
@ -71,7 +71,9 @@ namespace graphene { namespace net {
|
||||||
/**
|
/**
|
||||||
* @brief Called when a new block comes in from the network
|
* @brief Called when a new block comes in from the network
|
||||||
*
|
*
|
||||||
|
* @param blk_msg the message which contains the block
|
||||||
* @param sync_mode true if the message was fetched through the sync process, false during normal operation
|
* @param sync_mode true if the message was fetched through the sync process, false during normal operation
|
||||||
|
* @param contained_transaction_msg_ids container for the transactions to write back into
|
||||||
* @returns true if this message caused the blockchain to switch forks, false if it did not
|
* @returns true if this message caused the blockchain to switch forks, false if it did not
|
||||||
*
|
*
|
||||||
* @throws exception if error validating the item, otherwise the item is
|
* @throws exception if error validating the item, otherwise the item is
|
||||||
|
|
@ -195,7 +197,7 @@ namespace graphene { namespace net {
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
node(const std::string& user_agent);
|
node(const std::string& user_agent);
|
||||||
~node();
|
virtual ~node();
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
|
|
@ -213,11 +215,34 @@ namespace graphene { namespace net {
|
||||||
*/
|
*/
|
||||||
void add_node( const fc::ip::endpoint& ep );
|
void add_node( const fc::ip::endpoint& ep );
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* @brief add a list of nodes to seed the p2p network
|
||||||
|
* @param seeds a vector of url strings
|
||||||
|
*/
|
||||||
|
void add_seed_nodes( std::vector<std::string> seeds );
|
||||||
|
|
||||||
|
/****
|
||||||
|
* @brief add a node to seed the p2p network
|
||||||
|
* @param in the url as a string
|
||||||
|
*/
|
||||||
|
void add_seed_node( const std::string& in);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to connect to the specified endpoint immediately.
|
* Attempt to connect to the specified endpoint immediately.
|
||||||
*/
|
*/
|
||||||
virtual void connect_to_endpoint( const fc::ip::endpoint& ep );
|
virtual void connect_to_endpoint( const fc::ip::endpoint& ep );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper to convert a string to a collection of endpoints
|
||||||
|
*
|
||||||
|
* This converts a string (i.e. "bitshares.eu:665535" to a collection of endpoints.
|
||||||
|
* NOTE: Throws an exception if not in correct format or was unable to resolve URL.
|
||||||
|
*
|
||||||
|
* @param in the incoming string
|
||||||
|
* @returns a vector of endpoints
|
||||||
|
*/
|
||||||
|
static std::vector<fc::ip::endpoint> resolve_string_to_ip_endpoints( const std::string& in );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the network interface and port upon which incoming
|
* Specifies the network interface and port upon which incoming
|
||||||
* connections should be accepted.
|
* connections should be accepted.
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ namespace graphene { namespace net
|
||||||
class peer_connection_delegate
|
class peer_connection_delegate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~peer_connection_delegate() = default;
|
||||||
virtual void on_message(peer_connection* originating_peer,
|
virtual void on_message(peer_connection* originating_peer,
|
||||||
const message& received_message) = 0;
|
const message& received_message) = 0;
|
||||||
virtual void on_connection_closed(peer_connection* originating_peer) = 0;
|
virtual void on_connection_closed(peer_connection* originating_peer) = 0;
|
||||||
|
|
@ -125,7 +126,7 @@ namespace graphene { namespace net
|
||||||
* it is sitting on the queue
|
* it is sitting on the queue
|
||||||
*/
|
*/
|
||||||
virtual size_t get_size_in_queue() = 0;
|
virtual size_t get_size_in_queue() = 0;
|
||||||
virtual ~queued_message() {}
|
virtual ~queued_message() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* when you queue up a 'real_queued_message', a full copy of the message is
|
/* when you queue up a 'real_queued_message', a full copy of the message is
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ namespace graphene { namespace net {
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
peer_database();
|
peer_database();
|
||||||
~peer_database();
|
virtual ~peer_database();
|
||||||
|
|
||||||
void open(const fc::path& databaseFilename);
|
void open(const fc::path& databaseFilename);
|
||||||
void close();
|
void close();
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@
|
||||||
#include <fc/io/raw_fwd.hpp>
|
#include <fc/io/raw_fwd.hpp>
|
||||||
#include <fc/network/rate_limiting.hpp>
|
#include <fc/network/rate_limiting.hpp>
|
||||||
#include <fc/network/ip.hpp>
|
#include <fc/network/ip.hpp>
|
||||||
|
#include <fc/network/resolve.hpp>
|
||||||
|
|
||||||
#include <graphene/net/node.hpp>
|
#include <graphene/net/node.hpp>
|
||||||
#include <graphene/net/peer_database.hpp>
|
#include <graphene/net/peer_database.hpp>
|
||||||
|
|
@ -555,6 +556,10 @@ namespace graphene { namespace net { namespace detail {
|
||||||
fc::future<void> _bandwidth_monitor_loop_done;
|
fc::future<void> _bandwidth_monitor_loop_done;
|
||||||
|
|
||||||
fc::future<void> _dump_node_status_task_done;
|
fc::future<void> _dump_node_status_task_done;
|
||||||
|
/// Used by the task that checks whether addresses of seed nodes have been updated
|
||||||
|
/// @{
|
||||||
|
boost::container::flat_set<std::string> _seed_nodes;
|
||||||
|
fc::future<void> _update_seed_nodes_loop_done;
|
||||||
|
|
||||||
/* We have two alternate paths through the schedule_peer_for_deletion code -- one that
|
/* We have two alternate paths through the schedule_peer_for_deletion code -- one that
|
||||||
* uses a mutex to prevent one fiber from adding items to the queue while another is deleting
|
* uses a mutex to prevent one fiber from adding items to the queue while another is deleting
|
||||||
|
|
@ -728,6 +733,11 @@ namespace graphene { namespace net { namespace detail {
|
||||||
void listen_to_p2p_network();
|
void listen_to_p2p_network();
|
||||||
void connect_to_p2p_network();
|
void connect_to_p2p_network();
|
||||||
void add_node( const fc::ip::endpoint& ep );
|
void add_node( const fc::ip::endpoint& ep );
|
||||||
|
void add_seed_node( const std::string& in);
|
||||||
|
void add_seed_nodes( std::vector<std::string> seeds );
|
||||||
|
void resolve_seed_node_and_add( const std::string& seed_string );
|
||||||
|
void update_seed_nodes_task();
|
||||||
|
void schedule_next_update_seed_nodes_task();
|
||||||
void initiate_connect_to(const peer_connection_ptr& peer);
|
void initiate_connect_to(const peer_connection_ptr& peer);
|
||||||
void connect_to_endpoint(const fc::ip::endpoint& ep);
|
void connect_to_endpoint(const fc::ip::endpoint& ep);
|
||||||
void listen_on_endpoint(const fc::ip::endpoint& ep , bool wait_if_not_available);
|
void listen_on_endpoint(const fc::ip::endpoint& ep , bool wait_if_not_available);
|
||||||
|
|
@ -4757,6 +4767,68 @@ namespace graphene { namespace net { namespace detail {
|
||||||
_potential_peer_db.update_entry(updated_peer_record);
|
_potential_peer_db.update_entry(updated_peer_record);
|
||||||
trigger_p2p_network_connect_loop();
|
trigger_p2p_network_connect_loop();
|
||||||
}
|
}
|
||||||
|
void node_impl::add_seed_node(const std::string& endpoint_string)
|
||||||
|
{
|
||||||
|
VERIFY_CORRECT_THREAD();
|
||||||
|
_seed_nodes.insert( endpoint_string );
|
||||||
|
resolve_seed_node_and_add( endpoint_string );
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_impl::resolve_seed_node_and_add(const std::string& endpoint_string)
|
||||||
|
{
|
||||||
|
VERIFY_CORRECT_THREAD();
|
||||||
|
std::vector<fc::ip::endpoint> endpoints;
|
||||||
|
ilog("Resolving seed node ${endpoint}", ("endpoint", endpoint_string));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
endpoints = graphene::net::node::resolve_string_to_ip_endpoints(endpoint_string);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
wlog( "Unable to resolve endpoint during attempt to add seed node ${ep}", ("ep", endpoint_string) );
|
||||||
|
}
|
||||||
|
for (const fc::ip::endpoint& endpoint : endpoints)
|
||||||
|
{
|
||||||
|
ilog("Adding seed node ${endpoint}", ("endpoint", endpoint));
|
||||||
|
add_node(endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void node_impl::update_seed_nodes_task()
|
||||||
|
{
|
||||||
|
VERIFY_CORRECT_THREAD();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dlog("Starting an iteration of update_seed_nodes loop.");
|
||||||
|
for( const std::string& endpoint_string : _seed_nodes )
|
||||||
|
{
|
||||||
|
resolve_seed_node_and_add( endpoint_string );
|
||||||
|
}
|
||||||
|
dlog("Done an iteration of update_seed_nodes loop.");
|
||||||
|
}
|
||||||
|
catch (const fc::canceled_exception&)
|
||||||
|
{
|
||||||
|
ilog( "update_seed_nodes_task canceled" );
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
FC_CAPTURE_AND_LOG( (_seed_nodes) )
|
||||||
|
|
||||||
|
schedule_next_update_seed_nodes_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_impl::schedule_next_update_seed_nodes_task()
|
||||||
|
{
|
||||||
|
VERIFY_CORRECT_THREAD();
|
||||||
|
|
||||||
|
if( _node_is_shutting_down )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( _update_seed_nodes_loop_done.valid() && _update_seed_nodes_loop_done.canceled() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
_update_seed_nodes_loop_done = fc::schedule( [this]() { update_seed_nodes_task(); },
|
||||||
|
fc::time_point::now() + fc::hours(3),
|
||||||
|
"update_seed_nodes_loop" );
|
||||||
|
}
|
||||||
|
|
||||||
void node_impl::initiate_connect_to(const peer_connection_ptr& new_peer)
|
void node_impl::initiate_connect_to(const peer_connection_ptr& new_peer)
|
||||||
{
|
{
|
||||||
|
|
@ -5296,6 +5368,11 @@ namespace graphene { namespace net { namespace detail {
|
||||||
INVOKE_IN_IMPL(add_node, ep);
|
INVOKE_IN_IMPL(add_node, ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void node::add_seed_node(const std::string& in)
|
||||||
|
{
|
||||||
|
INVOKE_IN_IMPL(add_seed_node, in);
|
||||||
|
}
|
||||||
|
|
||||||
void node::connect_to_endpoint( const fc::ip::endpoint& remote_endpoint )
|
void node::connect_to_endpoint( const fc::ip::endpoint& remote_endpoint )
|
||||||
{
|
{
|
||||||
INVOKE_IN_IMPL(connect_to_endpoint, remote_endpoint);
|
INVOKE_IN_IMPL(connect_to_endpoint, remote_endpoint);
|
||||||
|
|
@ -5677,5 +5754,45 @@ namespace graphene { namespace net { namespace detail {
|
||||||
#undef INVOKE_AND_COLLECT_STATISTICS
|
#undef INVOKE_AND_COLLECT_STATISTICS
|
||||||
|
|
||||||
} // end namespace detail
|
} // end namespace detail
|
||||||
|
std::vector<fc::ip::endpoint> node::resolve_string_to_ip_endpoints(const std::string& in)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::string::size_type colon_pos = in.find(':');
|
||||||
|
if (colon_pos == std::string::npos)
|
||||||
|
FC_THROW("Missing required port number in endpoint string \"${endpoint_string}\"",
|
||||||
|
("endpoint_string", in));
|
||||||
|
std::string port_string = in.substr(colon_pos + 1);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
uint16_t port = boost::lexical_cast<uint16_t>(port_string);
|
||||||
|
|
||||||
|
std::string hostname = in.substr(0, colon_pos);
|
||||||
|
std::vector<fc::ip::endpoint> endpoints = fc::resolve(hostname, port);
|
||||||
|
if (endpoints.empty())
|
||||||
|
FC_THROW_EXCEPTION( fc::unknown_host_exception,
|
||||||
|
"The host name can not be resolved: ${hostname}",
|
||||||
|
("hostname", hostname) );
|
||||||
|
return endpoints;
|
||||||
|
}
|
||||||
|
catch (const boost::bad_lexical_cast&)
|
||||||
|
{
|
||||||
|
FC_THROW("Bad port: ${port}", ("port", port_string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FC_CAPTURE_AND_RETHROW((in))
|
||||||
|
}
|
||||||
|
void node::add_seed_nodes(std::vector<std::string> seeds)
|
||||||
|
{
|
||||||
|
for(const std::string& endpoint_string : seeds )
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
add_seed_node(endpoint_string);
|
||||||
|
} catch( const fc::exception& e ) {
|
||||||
|
wlog( "caught exception ${e} while adding seed node ${endpoint}",
|
||||||
|
("e", e.to_detail_string())("endpoint", endpoint_string) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} } // end namespace graphene::net
|
} } // end namespace graphene::net
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,8 @@ namespace graphene { namespace net {
|
||||||
indexed_by<ordered_non_unique<tag<last_seen_time_index>,
|
indexed_by<ordered_non_unique<tag<last_seen_time_index>,
|
||||||
member<potential_peer_record,
|
member<potential_peer_record,
|
||||||
fc::time_point_sec,
|
fc::time_point_sec,
|
||||||
&potential_peer_record::last_seen_time> >,
|
&potential_peer_record::last_seen_time>,
|
||||||
|
std::greater<fc::time_point_sec> >,
|
||||||
hashed_unique<tag<endpoint_index>,
|
hashed_unique<tag<endpoint_index>,
|
||||||
member<potential_peer_record,
|
member<potential_peer_record,
|
||||||
fc::ip::endpoint,
|
fc::ip::endpoint,
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,24 @@ void delayed_node_plugin::plugin_set_program_options(bpo::options_description& c
|
||||||
|
|
||||||
void delayed_node_plugin::connect()
|
void delayed_node_plugin::connect()
|
||||||
{
|
{
|
||||||
my->client_connection = std::make_shared<fc::rpc::websocket_api_connection>(my->client.connect(my->remote_endpoint), GRAPHENE_MAX_NESTED_OBJECTS);
|
fc::http::websocket_connection_ptr con;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
con = my->client.connect(my->remote_endpoint);
|
||||||
|
}
|
||||||
|
catch( const fc::exception& e )
|
||||||
|
{
|
||||||
|
wlog("Error while connecting: ${e}", ("e", e.to_detail_string()));
|
||||||
|
connection_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
my->client_connection = std::make_shared<fc::rpc::websocket_api_connection>(
|
||||||
|
con, GRAPHENE_NET_MAX_NESTED_OBJECTS );
|
||||||
my->database_api = my->client_connection->get_remote_api<graphene::app::database_api>(0);
|
my->database_api = my->client_connection->get_remote_api<graphene::app::database_api>(0);
|
||||||
|
my->database_api->set_block_applied_callback([this]( const fc::variant& block_id )
|
||||||
|
{
|
||||||
|
fc::from_variant( block_id, my->last_received_remote_head, GRAPHENE_MAX_NESTED_OBJECTS );
|
||||||
|
} );
|
||||||
my->client_connection_closed = my->client_connection->closed.connect([this] {
|
my->client_connection_closed = my->client_connection->closed.connect([this] {
|
||||||
connection_failed();
|
connection_failed();
|
||||||
});
|
});
|
||||||
|
|
@ -73,7 +89,9 @@ void delayed_node_plugin::connect()
|
||||||
void delayed_node_plugin::plugin_initialize(const boost::program_options::variables_map& options)
|
void delayed_node_plugin::plugin_initialize(const boost::program_options::variables_map& options)
|
||||||
{
|
{
|
||||||
FC_ASSERT(options.count("trusted-node") > 0);
|
FC_ASSERT(options.count("trusted-node") > 0);
|
||||||
|
ilog("delayed_node_plugin: plugin_initialize() begin");
|
||||||
my->remote_endpoint = "ws://" + options.at("trusted-node").as<std::string>();
|
my->remote_endpoint = "ws://" + options.at("trusted-node").as<std::string>();
|
||||||
|
ilog("delayed_node_plugin: plugin_initialize() end");
|
||||||
}
|
}
|
||||||
|
|
||||||
void delayed_node_plugin::sync_with_trusted_node()
|
void delayed_node_plugin::sync_with_trusted_node()
|
||||||
|
|
@ -100,8 +118,11 @@ void delayed_node_plugin::sync_with_trusted_node()
|
||||||
while( remote_dpo.last_irreversible_block_num > db.head_block_num() )
|
while( remote_dpo.last_irreversible_block_num > db.head_block_num() )
|
||||||
{
|
{
|
||||||
fc::optional<graphene::chain::signed_block> block = my->database_api->get_block( db.head_block_num()+1 );
|
fc::optional<graphene::chain::signed_block> block = my->database_api->get_block( db.head_block_num()+1 );
|
||||||
|
// TODO: during sync, decouple requesting blocks from preprocessing + applying them
|
||||||
FC_ASSERT(block, "Trusted node claims it has blocks it doesn't actually have.");
|
FC_ASSERT(block, "Trusted node claims it has blocks it doesn't actually have.");
|
||||||
ilog("Pushing block #${n}", ("n", block->block_num()));
|
ilog("Pushing block #${n}", ("n", block->block_num()));
|
||||||
|
// timur: failed to merge from bitshares, API n/a in peerplays
|
||||||
|
// db.precompute_parallel( *block, graphene::chain::database::skip_nothing ).wait();
|
||||||
db.push_block(*block);
|
db.push_block(*block);
|
||||||
synced_blocks++;
|
synced_blocks++;
|
||||||
}
|
}
|
||||||
|
|
@ -136,24 +157,12 @@ void delayed_node_plugin::plugin_startup()
|
||||||
mainloop();
|
mainloop();
|
||||||
});
|
});
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
connect();
|
connect();
|
||||||
my->database_api->set_block_applied_callback([this]( const fc::variant& block_id )
|
|
||||||
{
|
|
||||||
fc::from_variant( block_id, my->last_received_remote_head, GRAPHENE_MAX_NESTED_OBJECTS );
|
|
||||||
} );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (const fc::exception& e)
|
|
||||||
{
|
|
||||||
elog("Error during connection: ${e}", ("e", e.to_detail_string()));
|
|
||||||
}
|
|
||||||
fc::async([this]{connection_failed();});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void delayed_node_plugin::connection_failed()
|
void delayed_node_plugin::connection_failed()
|
||||||
{
|
{
|
||||||
|
my->last_received_remote_head = my->last_processed_remote_head;
|
||||||
elog("Connection to trusted node failed; retrying in 5 seconds...");
|
elog("Connection to trusted node failed; retrying in 5 seconds...");
|
||||||
fc::schedule([this]{connect();}, fc::time_point::now() + fc::seconds(5));
|
fc::schedule([this]{connect();}, fc::time_point::now() + fc::seconds(5));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ if( BUILD_PEERPLAYS_PROGRAMS )
|
||||||
add_subdirectory( genesis_util )
|
add_subdirectory( genesis_util )
|
||||||
add_subdirectory( witness_node )
|
add_subdirectory( witness_node )
|
||||||
add_subdirectory( debug_node )
|
add_subdirectory( debug_node )
|
||||||
add_subdirectory( delayed_node )
|
|
||||||
add_subdirectory( js_operation_serializer )
|
add_subdirectory( js_operation_serializer )
|
||||||
add_subdirectory( size_checker )
|
add_subdirectory( size_checker )
|
||||||
endif( BUILD_PEERPLAYS_PROGRAMS )
|
endif( BUILD_PEERPLAYS_PROGRAMS )
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
add_executable( delayed_node main.cpp )
|
|
||||||
if( UNIX AND NOT APPLE )
|
|
||||||
set(rt_library rt )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package( Gperftools QUIET )
|
|
||||||
if( GPERFTOOLS_FOUND )
|
|
||||||
message( STATUS "Found gperftools; compiling delayed_node with TCMalloc")
|
|
||||||
list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries( delayed_node
|
|
||||||
PRIVATE graphene_app graphene_egenesis_full graphene_delayed_node ${PLATFORM_SPECIFIC_LIBS} )
|
|
||||||
|
|
||||||
install( TARGETS
|
|
||||||
delayed_node
|
|
||||||
|
|
||||||
RUNTIME DESTINATION bin
|
|
||||||
LIBRARY DESTINATION lib
|
|
||||||
ARCHIVE DESTINATION lib
|
|
||||||
)
|
|
||||||
|
|
@ -1,305 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2015 Cryptonomex, Inc., and contributors.
|
|
||||||
*
|
|
||||||
* The MIT License
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include <graphene/app/application.hpp>
|
|
||||||
|
|
||||||
#include <graphene/delayed_node/delayed_node_plugin.hpp>
|
|
||||||
#include <graphene/account_history/account_history_plugin.hpp>
|
|
||||||
#include <graphene/market_history/market_history_plugin.hpp>
|
|
||||||
|
|
||||||
#include <fc/exception/exception.hpp>
|
|
||||||
#include <fc/thread/thread.hpp>
|
|
||||||
#include <fc/interprocess/signals.hpp>
|
|
||||||
#include <fc/log/console_appender.hpp>
|
|
||||||
#include <fc/log/file_appender.hpp>
|
|
||||||
#include <fc/log/logger.hpp>
|
|
||||||
#include <fc/log/logger_config.hpp>
|
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
|
|
||||||
#include <boost/property_tree/ptree.hpp>
|
|
||||||
#include <boost/property_tree/ini_parser.hpp>
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
|
||||||
#include <boost/algorithm/string/classification.hpp>
|
|
||||||
#include <boost/algorithm/string/split.hpp>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
# include <signal.h>
|
|
||||||
#else
|
|
||||||
# include <csignal>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace graphene;
|
|
||||||
namespace bpo = boost::program_options;
|
|
||||||
|
|
||||||
void write_default_logging_config_to_stream(std::ostream& out);
|
|
||||||
fc::optional<fc::logging_config> load_logging_config_from_ini_file(const fc::path& config_ini_filename);
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
try {
|
|
||||||
app::application node;
|
|
||||||
bpo::options_description app_options("Graphene Delayed Node");
|
|
||||||
bpo::options_description cfg_options("Graphene Delayed Node");
|
|
||||||
app_options.add_options()
|
|
||||||
("help,h", "Print this help message and exit.")
|
|
||||||
("data-dir,d", bpo::value<boost::filesystem::path>()->default_value("delayed_node_data_dir"), "Directory containing databases, configuration file, etc.")
|
|
||||||
;
|
|
||||||
|
|
||||||
bpo::variables_map options;
|
|
||||||
|
|
||||||
bpo::options_description cli, cfg;
|
|
||||||
node.set_program_options(cli, cfg);
|
|
||||||
cfg_options.add(cfg);
|
|
||||||
|
|
||||||
cfg_options.add_options()
|
|
||||||
("plugins", bpo::value<std::string>()->default_value("delayed_node account_history market_history"),
|
|
||||||
"Space-separated list of plugins to activate");
|
|
||||||
|
|
||||||
auto delayed_plug = node.register_plugin<delayed_node::delayed_node_plugin>();
|
|
||||||
auto history_plug = node.register_plugin<account_history::account_history_plugin>();
|
|
||||||
auto market_history_plug = node.register_plugin<market_history::market_history_plugin>();
|
|
||||||
|
|
||||||
// add plugin options to config
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bpo::options_description cli, cfg;
|
|
||||||
node.set_program_options(cli, cfg);
|
|
||||||
app_options.add(cli);
|
|
||||||
cfg_options.add(cfg);
|
|
||||||
bpo::store(bpo::parse_command_line(argc, argv, app_options), options);
|
|
||||||
}
|
|
||||||
catch (const boost::program_options::error& e)
|
|
||||||
{
|
|
||||||
std::cerr << "Error parsing command line: " << e.what() << "\n";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( options.count("help") )
|
|
||||||
{
|
|
||||||
std::cout << app_options << "\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fc::path data_dir;
|
|
||||||
if( options.count("data-dir") )
|
|
||||||
{
|
|
||||||
data_dir = options["data-dir"].as<boost::filesystem::path>();
|
|
||||||
if( data_dir.is_relative() )
|
|
||||||
data_dir = fc::current_path() / data_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
fc::path config_ini_path = data_dir / "config.ini";
|
|
||||||
// Create config file if not already present
|
|
||||||
if( !fc::exists(config_ini_path) )
|
|
||||||
{
|
|
||||||
ilog("Writing new config file at ${path}", ("path", config_ini_path));
|
|
||||||
if( !fc::exists(data_dir) )
|
|
||||||
fc::create_directories(data_dir);
|
|
||||||
|
|
||||||
std::ofstream out_cfg(config_ini_path.preferred_string());
|
|
||||||
for( const boost::shared_ptr<bpo::option_description> od : cfg_options.options() )
|
|
||||||
{
|
|
||||||
if( !od->description().empty() )
|
|
||||||
out_cfg << "# " << od->description() << "\n";
|
|
||||||
boost::any store;
|
|
||||||
if( !od->semantic()->apply_default(store) )
|
|
||||||
out_cfg << "# " << od->long_name() << " = \n";
|
|
||||||
else {
|
|
||||||
auto example = od->format_parameter();
|
|
||||||
if( example.empty() )
|
|
||||||
// This is a boolean switch
|
|
||||||
out_cfg << od->long_name() << " = " << "false\n";
|
|
||||||
else {
|
|
||||||
// The string is formatted "arg (=<interesting part>)"
|
|
||||||
example.erase(0, 6);
|
|
||||||
example.erase(example.length()-1);
|
|
||||||
out_cfg << od->long_name() << " = " << example << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out_cfg << "\n";
|
|
||||||
}
|
|
||||||
write_default_logging_config_to_stream(out_cfg);
|
|
||||||
out_cfg.close();
|
|
||||||
// read the default logging config we just wrote out to the file and start using it
|
|
||||||
fc::optional<fc::logging_config> logging_config = load_logging_config_from_ini_file(config_ini_path);
|
|
||||||
if (logging_config)
|
|
||||||
fc::configure_logging(*logging_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse configuration file
|
|
||||||
try {
|
|
||||||
bpo::store(bpo::parse_config_file<char>(config_ini_path.preferred_string().c_str(), cfg_options, true), options);
|
|
||||||
// try to get logging options from the config file.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fc::optional<fc::logging_config> logging_config = load_logging_config_from_ini_file(config_ini_path);
|
|
||||||
if (logging_config)
|
|
||||||
fc::configure_logging(*logging_config);
|
|
||||||
}
|
|
||||||
catch (const fc::exception&)
|
|
||||||
{
|
|
||||||
wlog("Error parsing logging config from config file ${config}, using default config", ("config", config_ini_path.preferred_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
bpo::notify(options);
|
|
||||||
} catch( const boost::program_options::error& e ) {
|
|
||||||
elog("Error parsing configuration file: ${e}", ("e", e.what()));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !options.count("plugins") )
|
|
||||||
options.insert( std::make_pair( "plugins", bpo::variable_value(std::string("delayed_node account_history market_history"), true) ) );
|
|
||||||
|
|
||||||
node.initialize(data_dir, options);
|
|
||||||
node.initialize_plugins( options );
|
|
||||||
|
|
||||||
node.startup();
|
|
||||||
node.startup_plugins();
|
|
||||||
|
|
||||||
fc::promise<int>::ptr exit_promise = new fc::promise<int>("UNIX Signal Handler");
|
|
||||||
fc::set_signal_handler([&exit_promise](int signal) {
|
|
||||||
exit_promise->set_value(signal);
|
|
||||||
}, SIGINT);
|
|
||||||
|
|
||||||
ilog("Started delayed node on a chain with ${h} blocks.", ("h", node.chain_database()->head_block_num()));
|
|
||||||
ilog("Chain ID is ${id}", ("id", node.chain_database()->get_chain_id()) );
|
|
||||||
|
|
||||||
int signal = exit_promise->wait();
|
|
||||||
ilog("Exiting from signal ${n}", ("n", signal));
|
|
||||||
node.shutdown_plugins();
|
|
||||||
return 0;
|
|
||||||
} catch( const fc::exception& e ) {
|
|
||||||
elog("Exiting with error:\n${e}", ("e", e.to_detail_string()));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// logging config is too complicated to be parsed by boost::program_options,
|
|
||||||
// so we do it by hand
|
|
||||||
//
|
|
||||||
// Currently, you can only specify the filenames and logging levels, which
|
|
||||||
// are all most users would want to change. At a later time, options can
|
|
||||||
// be added to control rotation intervals, compression, and other seldom-
|
|
||||||
// used features
|
|
||||||
void write_default_logging_config_to_stream(std::ostream& out)
|
|
||||||
{
|
|
||||||
out << "# declare an appender named \"stderr\" that writes messages to the console\n"
|
|
||||||
"[log.console_appender.stderr]\n"
|
|
||||||
"stream=std_error\n\n"
|
|
||||||
"# declare an appender named \"p2p\" that writes messages to p2p.log\n"
|
|
||||||
"[log.file_appender.p2p]\n"
|
|
||||||
"filename=logs/p2p/p2p.log\n"
|
|
||||||
"# filename can be absolute or relative to this config file\n\n"
|
|
||||||
"# route any messages logged to the default logger to the \"stderr\" logger we\n"
|
|
||||||
"# declared above, if they are info level are higher\n"
|
|
||||||
"[logger.default]\n"
|
|
||||||
"level=info\n"
|
|
||||||
"appenders=stderr\n\n"
|
|
||||||
"# route messages sent to the \"p2p\" logger to the p2p appender declared above\n"
|
|
||||||
"[logger.p2p]\n"
|
|
||||||
"level=info\n"
|
|
||||||
"appenders=p2p\n\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
fc::optional<fc::logging_config> load_logging_config_from_ini_file(const fc::path& config_ini_filename)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fc::logging_config logging_config;
|
|
||||||
bool found_logging_config = false;
|
|
||||||
|
|
||||||
boost::property_tree::ptree config_ini_tree;
|
|
||||||
boost::property_tree::ini_parser::read_ini(config_ini_filename.preferred_string().c_str(), config_ini_tree);
|
|
||||||
for (const auto& section : config_ini_tree)
|
|
||||||
{
|
|
||||||
const std::string& section_name = section.first;
|
|
||||||
const boost::property_tree::ptree& section_tree = section.second;
|
|
||||||
|
|
||||||
const std::string console_appender_section_prefix = "log.console_appender.";
|
|
||||||
const std::string file_appender_section_prefix = "log.file_appender.";
|
|
||||||
const std::string logger_section_prefix = "logger.";
|
|
||||||
|
|
||||||
if (boost::starts_with(section_name, console_appender_section_prefix))
|
|
||||||
{
|
|
||||||
std::string console_appender_name = section_name.substr(console_appender_section_prefix.length());
|
|
||||||
std::string stream_name = section_tree.get<std::string>("stream");
|
|
||||||
|
|
||||||
// construct a default console appender config here
|
|
||||||
// stdout/stderr will be taken from ini file, everything else hard-coded here
|
|
||||||
fc::console_appender::config console_appender_config;
|
|
||||||
console_appender_config.level_colors.emplace_back(
|
|
||||||
fc::console_appender::level_color(fc::log_level::debug,
|
|
||||||
fc::console_appender::color::green));
|
|
||||||
console_appender_config.level_colors.emplace_back(
|
|
||||||
fc::console_appender::level_color(fc::log_level::warn,
|
|
||||||
fc::console_appender::color::brown));
|
|
||||||
console_appender_config.level_colors.emplace_back(
|
|
||||||
fc::console_appender::level_color(fc::log_level::error,
|
|
||||||
fc::console_appender::color::cyan));
|
|
||||||
console_appender_config.stream = fc::variant(stream_name, 1).as<fc::console_appender::stream::type>(1);
|
|
||||||
logging_config.appenders.push_back(fc::appender_config(console_appender_name, "console", fc::variant(console_appender_config, GRAPHENE_MAX_NESTED_OBJECTS)));
|
|
||||||
found_logging_config = true;
|
|
||||||
}
|
|
||||||
else if (boost::starts_with(section_name, file_appender_section_prefix))
|
|
||||||
{
|
|
||||||
std::string file_appender_name = section_name.substr(file_appender_section_prefix.length());
|
|
||||||
fc::path file_name = section_tree.get<std::string>("filename");
|
|
||||||
if (file_name.is_relative())
|
|
||||||
file_name = fc::absolute(config_ini_filename).parent_path() / file_name;
|
|
||||||
|
|
||||||
|
|
||||||
// construct a default file appender config here
|
|
||||||
// filename will be taken from ini file, everything else hard-coded here
|
|
||||||
fc::file_appender::config file_appender_config;
|
|
||||||
file_appender_config.filename = file_name;
|
|
||||||
file_appender_config.flush = true;
|
|
||||||
file_appender_config.rotate = true;
|
|
||||||
file_appender_config.rotation_interval = fc::hours(1);
|
|
||||||
file_appender_config.rotation_limit = fc::days(1);
|
|
||||||
logging_config.appenders.push_back(fc::appender_config(file_appender_name, "file", fc::variant(file_appender_config, GRAPHENE_MAX_NESTED_OBJECTS)));
|
|
||||||
found_logging_config = true;
|
|
||||||
}
|
|
||||||
else if (boost::starts_with(section_name, logger_section_prefix))
|
|
||||||
{
|
|
||||||
std::string logger_name = section_name.substr(logger_section_prefix.length());
|
|
||||||
std::string level_string = section_tree.get<std::string>("level");
|
|
||||||
std::string appenders_string = section_tree.get<std::string>("appenders");
|
|
||||||
fc::logger_config logger_config(logger_name);
|
|
||||||
logger_config.level = fc::variant(level_string, 1).as<fc::log_level>(1);
|
|
||||||
boost::split(logger_config.appenders, appenders_string,
|
|
||||||
boost::is_any_of(" ,"),
|
|
||||||
boost::token_compress_on);
|
|
||||||
logging_config.loggers.push_back(logger_config);
|
|
||||||
found_logging_config = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found_logging_config)
|
|
||||||
return logging_config;
|
|
||||||
else
|
|
||||||
return fc::optional<fc::logging_config>();
|
|
||||||
}
|
|
||||||
FC_RETHROW_EXCEPTIONS(warn, "")
|
|
||||||
}
|
|
||||||
|
|
@ -11,7 +11,7 @@ endif()
|
||||||
|
|
||||||
# We have to link against graphene_debug_witness because deficiency in our API infrastructure doesn't allow plugins to be fully abstracted #246
|
# We have to link against graphene_debug_witness because deficiency in our API infrastructure doesn't allow plugins to be fully abstracted #246
|
||||||
target_link_libraries( witness_node
|
target_link_libraries( witness_node
|
||||||
PRIVATE graphene_app graphene_egenesis_full graphene_snapshot graphene_witness peerplays_sidechain ${PLATFORM_SPECIFIC_LIBS} )
|
PRIVATE graphene_app graphene_egenesis_full graphene_snapshot graphene_delayed_node graphene_witness peerplays_sidechain ${PLATFORM_SPECIFIC_LIBS} )
|
||||||
# also add dependencies to graphene_generate_genesis graphene_generate_uia_sharedrop_genesis if you want those plugins
|
# also add dependencies to graphene_generate_genesis graphene_generate_uia_sharedrop_genesis if you want those plugins
|
||||||
|
|
||||||
install( TARGETS
|
install( TARGETS
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
#include <graphene/affiliate_stats/affiliate_stats_plugin.hpp>
|
#include <graphene/affiliate_stats/affiliate_stats_plugin.hpp>
|
||||||
#include <graphene/bookie/bookie_plugin.hpp>
|
#include <graphene/bookie/bookie_plugin.hpp>
|
||||||
#include <graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp>
|
#include <graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp>
|
||||||
|
#include <graphene/delayed_node/delayed_node_plugin.hpp>
|
||||||
#include <graphene/utilities/git_revision.hpp>
|
#include <graphene/utilities/git_revision.hpp>
|
||||||
#include <graphene/snapshot/snapshot.hpp>
|
#include <graphene/snapshot/snapshot.hpp>
|
||||||
|
|
||||||
|
|
@ -90,6 +91,7 @@ int main(int argc, char** argv) {
|
||||||
auto bookie_plug = node->register_plugin<bookie::bookie_plugin>();
|
auto bookie_plug = node->register_plugin<bookie::bookie_plugin>();
|
||||||
auto peerplays_sidechain = node->register_plugin<peerplays_sidechain::peerplays_sidechain_plugin>();
|
auto peerplays_sidechain = node->register_plugin<peerplays_sidechain::peerplays_sidechain_plugin>();
|
||||||
auto snapshot_plug = node->register_plugin<snapshot_plugin::snapshot_plugin>();
|
auto snapshot_plug = node->register_plugin<snapshot_plugin::snapshot_plugin>();
|
||||||
|
auto delayed_plug = node->register_plugin<delayed_node::delayed_node_plugin>();
|
||||||
|
|
||||||
// add plugin options to config
|
// add plugin options to config
|
||||||
try
|
try
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue