Merge branch '606-debug-node' into develop
Conflicts: libraries/app/CMakeLists.txt
This commit is contained in:
commit
006d548633
20 changed files with 1070 additions and 2 deletions
|
|
@ -11,7 +11,8 @@ add_library( graphene_app
|
|||
${EGENESIS_HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries( graphene_app graphene_market_history graphene_account_history graphene_chain fc graphene_db graphene_net graphene_time graphene_utilities )
|
||||
# need to link graphene_debug_witness because plugins aren't sufficiently isolated #246
|
||||
target_link_libraries( graphene_app graphene_market_history graphene_account_history graphene_chain fc graphene_db graphene_net graphene_time graphene_utilities graphene_debug_witness )
|
||||
target_include_directories( graphene_app
|
||||
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../egenesis/include" )
|
||||
|
|
|
|||
|
|
@ -95,6 +95,12 @@ namespace graphene { namespace app {
|
|||
{
|
||||
_crypto_api = std::make_shared< crypto_api >();
|
||||
}
|
||||
else if( api_name == "debug_api" )
|
||||
{
|
||||
// can only enable this API if the plugin was loaded
|
||||
if( _app.get_plugin( "debug_witness" ) )
|
||||
_debug_api = std::make_shared< graphene::debug_witness::debug_api >( std::ref(_app) );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -211,6 +217,12 @@ namespace graphene { namespace app {
|
|||
return *_crypto_api;
|
||||
}
|
||||
|
||||
fc::api<graphene::debug_witness::debug_api> login_api::debug() const
|
||||
{
|
||||
FC_ASSERT(_debug_api);
|
||||
return *_debug_api;
|
||||
}
|
||||
|
||||
vector<account_id_type> get_relevant_accounts( const object* obj )
|
||||
{
|
||||
vector<account_id_type> result;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include <graphene/market_history/market_history_plugin.hpp>
|
||||
|
||||
#include <graphene/debug_witness/debug_api.hpp>
|
||||
|
||||
#include <graphene/net/node.hpp>
|
||||
|
||||
#include <fc/api.hpp>
|
||||
|
|
@ -281,6 +283,8 @@ namespace graphene { namespace app {
|
|||
fc::api<network_node_api> network_node()const;
|
||||
/// @brief Retrieve the cryptography API
|
||||
fc::api<crypto_api> crypto()const;
|
||||
/// @brief Retrieve the debug API (if available)
|
||||
fc::api<graphene::debug_witness::debug_api> debug()const;
|
||||
|
||||
private:
|
||||
/// @brief Called to enable an API, not reflected.
|
||||
|
|
@ -292,6 +296,7 @@ namespace graphene { namespace app {
|
|||
optional< fc::api<network_node_api> > _network_node_api;
|
||||
optional< fc::api<history_api> > _history_api;
|
||||
optional< fc::api<crypto_api> > _crypto_api;
|
||||
optional< fc::api<graphene::debug_witness::debug_api> > _debug_api;
|
||||
};
|
||||
|
||||
}} // graphene::app
|
||||
|
|
@ -343,4 +348,5 @@ FC_API(graphene::app::login_api,
|
|||
(history)
|
||||
(network_node)
|
||||
(crypto)
|
||||
(debug)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -534,6 +534,8 @@ void database::_apply_block( const signed_block& next_block )
|
|||
// to be called for header validation?
|
||||
update_maintenance_flag( maint_needed );
|
||||
update_witness_schedule();
|
||||
if( !_node_property_object.debug_updates.empty() )
|
||||
apply_debug_updates();
|
||||
|
||||
// notify observers that the block has been applied
|
||||
applied_block( next_block ); //emit
|
||||
|
|
|
|||
|
|
@ -95,4 +95,107 @@ void database::debug_dump()
|
|||
*/
|
||||
}
|
||||
|
||||
void debug_apply_update( database& db, const fc::variant_object& vo )
|
||||
{
|
||||
static const uint8_t
|
||||
db_action_nil = 0,
|
||||
db_action_create = 1,
|
||||
db_action_write = 2,
|
||||
db_action_update = 3,
|
||||
db_action_delete = 4;
|
||||
|
||||
// "_action" : "create" object must not exist, unspecified fields take defaults
|
||||
// "_action" : "write" object may exist, is replaced entirely, unspecified fields take defaults
|
||||
// "_action" : "update" object must exist, unspecified fields don't change
|
||||
// "_action" : "delete" object must exist, will be deleted
|
||||
|
||||
// if _action is unspecified:
|
||||
// - delete if object contains only ID field
|
||||
// - otherwise, write
|
||||
|
||||
object_id_type oid;
|
||||
uint8_t action = db_action_nil;
|
||||
auto it_id = vo.find("id");
|
||||
FC_ASSERT( it_id != vo.end() );
|
||||
|
||||
from_variant( it_id->value(), oid );
|
||||
action = ( vo.size() == 1 ) ? db_action_delete : db_action_write;
|
||||
|
||||
from_variant( vo["id"], oid );
|
||||
if( vo.size() == 1 )
|
||||
action = db_action_delete;
|
||||
auto it_action = vo.find("_action" );
|
||||
if( it_action != vo.end() )
|
||||
{
|
||||
const std::string& str_action = it_action->value().get_string();
|
||||
if( str_action == "create" )
|
||||
action = db_action_create;
|
||||
else if( str_action == "write" )
|
||||
action = db_action_write;
|
||||
else if( str_action == "update" )
|
||||
action = db_action_update;
|
||||
else if( str_action == "delete" )
|
||||
action = db_action_delete;
|
||||
}
|
||||
|
||||
auto& idx = db.get_index( oid );
|
||||
|
||||
switch( action )
|
||||
{
|
||||
case db_action_create:
|
||||
/*
|
||||
idx.create( [&]( object& obj )
|
||||
{
|
||||
idx.object_from_variant( vo, obj );
|
||||
} );
|
||||
*/
|
||||
FC_ASSERT( false );
|
||||
break;
|
||||
case db_action_write:
|
||||
db.modify( db.get_object( oid ), [&]( object& obj )
|
||||
{
|
||||
idx.object_default( obj );
|
||||
idx.object_from_variant( vo, obj );
|
||||
} );
|
||||
break;
|
||||
case db_action_update:
|
||||
db.modify( db.get_object( oid ), [&]( object& obj )
|
||||
{
|
||||
idx.object_from_variant( vo, obj );
|
||||
} );
|
||||
break;
|
||||
case db_action_delete:
|
||||
db.remove( db.get_object( oid ) );
|
||||
break;
|
||||
default:
|
||||
FC_ASSERT( false );
|
||||
}
|
||||
}
|
||||
|
||||
void database::apply_debug_updates()
|
||||
{
|
||||
block_id_type head_id = head_block_id();
|
||||
auto it = _node_property_object.debug_updates.find( head_id );
|
||||
if( it == _node_property_object.debug_updates.end() )
|
||||
return;
|
||||
for( const fc::variant_object& update : it->second )
|
||||
debug_apply_update( *this, update );
|
||||
}
|
||||
|
||||
void database::debug_update( const fc::variant_object& update )
|
||||
{
|
||||
block_id_type head_id = head_block_id();
|
||||
auto it = _node_property_object.debug_updates.find( head_id );
|
||||
if( it == _node_property_object.debug_updates.end() )
|
||||
it = _node_property_object.debug_updates.emplace( head_id, std::vector< fc::variant_object >() ).first;
|
||||
it->second.emplace_back( update );
|
||||
|
||||
optional<signed_block> head_block = fetch_block_by_id( head_id );
|
||||
FC_ASSERT( head_block.valid() );
|
||||
|
||||
// What the last block does has been changed by adding to node_property_object, so we have to re-apply it
|
||||
pop_block();
|
||||
push_block( *head_block );
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -322,6 +322,8 @@ namespace graphene { namespace chain {
|
|||
//////////////////// db_debug.cpp ////////////////////
|
||||
|
||||
void debug_dump();
|
||||
void apply_debug_updates();
|
||||
void debug_update( const fc::variant_object& update );
|
||||
|
||||
//////////////////// db_market.cpp ////////////////////
|
||||
|
||||
|
|
|
|||
|
|
@ -43,5 +43,6 @@ namespace graphene { namespace chain {
|
|||
~node_property_object(){}
|
||||
|
||||
uint32_t skip_flags = 0;
|
||||
std::map< block_id_type, std::vector< fc::variant_object > > debug_updates;
|
||||
};
|
||||
} } // graphene::chain
|
||||
|
|
|
|||
|
|
@ -130,6 +130,8 @@ namespace graphene { namespace db {
|
|||
virtual fc::uint128 hash()const = 0;
|
||||
virtual void add_observer( const shared_ptr<index_observer>& ) = 0;
|
||||
|
||||
virtual void object_from_variant( const fc::variant& var, object& obj )const = 0;
|
||||
virtual void object_default( object& obj )const = 0;
|
||||
};
|
||||
|
||||
class secondary_index
|
||||
|
|
@ -298,6 +300,24 @@ namespace graphene { namespace db {
|
|||
_observers.emplace_back( o );
|
||||
}
|
||||
|
||||
virtual void object_from_variant( const fc::variant& var, object& obj )const override
|
||||
{
|
||||
object_id_type id = obj.id;
|
||||
object_type* result = dynamic_cast<object_type*>( &obj );
|
||||
FC_ASSERT( result != nullptr );
|
||||
fc::from_variant( var, *result );
|
||||
obj.id = id;
|
||||
}
|
||||
|
||||
virtual void object_default( object& obj )const override
|
||||
{
|
||||
object_id_type id = obj.id;
|
||||
object_type* result = dynamic_cast<object_type*>( &obj );
|
||||
FC_ASSERT( result != nullptr );
|
||||
(*result) = object_type();
|
||||
obj.id = id;
|
||||
}
|
||||
|
||||
private:
|
||||
object_id_type _next_id;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ add_subdirectory( witness )
|
|||
add_subdirectory( account_history )
|
||||
add_subdirectory( market_history )
|
||||
add_subdirectory( delayed_node )
|
||||
add_subdirectory( debug_witness )
|
||||
18
libraries/plugins/debug_witness/CMakeLists.txt
Normal file
18
libraries/plugins/debug_witness/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
file(GLOB HEADERS "include/graphene/debug_witness/*.hpp")
|
||||
|
||||
add_library( graphene_debug_witness
|
||||
debug_api.cpp
|
||||
debug_witness.cpp
|
||||
)
|
||||
|
||||
target_link_libraries( graphene_debug_witness graphene_chain graphene_app )
|
||||
target_include_directories( graphene_debug_witness
|
||||
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
|
||||
|
||||
install( TARGETS
|
||||
graphene_debug_witness
|
||||
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
157
libraries/plugins/debug_witness/debug_api.cpp
Normal file
157
libraries/plugins/debug_witness/debug_api.cpp
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
|
||||
#include <fc/filesystem.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
#include <fc/variant_object.hpp>
|
||||
|
||||
#include <graphene/app/application.hpp>
|
||||
|
||||
#include <graphene/chain/block_database.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
|
||||
#include <graphene/utilities/key_conversion.hpp>
|
||||
|
||||
#include <graphene/debug_witness/debug_api.hpp>
|
||||
#include <graphene/debug_witness/debug_witness.hpp>
|
||||
|
||||
namespace graphene { namespace debug_witness {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class debug_api_impl
|
||||
{
|
||||
public:
|
||||
debug_api_impl( graphene::app::application& _app );
|
||||
|
||||
void debug_push_blocks( const std::string& src_filename, uint32_t count );
|
||||
void debug_generate_blocks( const std::string& debug_key, uint32_t count );
|
||||
void debug_update_object( const fc::variant_object& update );
|
||||
//void debug_save_db( std::string db_path );
|
||||
void debug_stream_json_objects( const std::string& filename );
|
||||
void debug_stream_json_objects_flush();
|
||||
std::shared_ptr< graphene::debug_witness_plugin::debug_witness_plugin > get_plugin();
|
||||
|
||||
graphene::app::application& app;
|
||||
};
|
||||
|
||||
debug_api_impl::debug_api_impl( graphene::app::application& _app ) : app( _app )
|
||||
{}
|
||||
|
||||
|
||||
void debug_api_impl::debug_push_blocks( const std::string& src_filename, uint32_t count )
|
||||
{
|
||||
if( count == 0 )
|
||||
return;
|
||||
|
||||
std::shared_ptr< graphene::chain::database > db = app.chain_database();
|
||||
fc::path src_path = fc::path( src_filename );
|
||||
if( fc::is_directory( src_path ) )
|
||||
{
|
||||
ilog( "Loading ${n} from block_database ${fn}", ("n", count)("fn", src_filename) );
|
||||
graphene::chain::block_database bdb;
|
||||
bdb.open( src_path );
|
||||
uint32_t first_block = db->head_block_num()+1;
|
||||
for( uint32_t i=0; i<count; i++ )
|
||||
{
|
||||
fc::optional< graphene::chain::signed_block > block = bdb.fetch_by_number( first_block+i );
|
||||
if( !block.valid() )
|
||||
{
|
||||
wlog( "Block database ${fn} only contained ${i} of ${n} requested blocks", ("i", i)("n", count)("fn", src_filename) );
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
db->push_block( *block );
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
elog( "Got exception pushing block ${bn} : ${bid} (${i} of ${n})", ("bn", block->block_num())("bid", block->id())("i", i)("n", count) );
|
||||
elog( "Exception backtrace: ${bt}", ("bt", e.to_detail_string()) );
|
||||
}
|
||||
}
|
||||
ilog( "Completed loading block_database successfully" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void debug_api_impl::debug_generate_blocks( const std::string& debug_key, uint32_t count )
|
||||
{
|
||||
if( count == 0 )
|
||||
return;
|
||||
|
||||
fc::optional<fc::ecc::private_key> debug_private_key = graphene::utilities::wif_to_key( debug_key );
|
||||
FC_ASSERT( debug_private_key.valid() );
|
||||
graphene::chain::public_key_type debug_public_key = debug_private_key->get_public_key();
|
||||
|
||||
std::shared_ptr< graphene::chain::database > db = app.chain_database();
|
||||
for( uint32_t i=0; i<count; i++ )
|
||||
{
|
||||
graphene::chain::witness_id_type scheduled_witness = db->get_scheduled_witness( 1 );
|
||||
fc::time_point_sec scheduled_time = db->get_slot_time( 1 );
|
||||
graphene::chain::public_key_type scheduled_key = scheduled_witness( *db ).signing_key;
|
||||
if( scheduled_key != debug_public_key )
|
||||
{
|
||||
ilog( "Modified key for witness ${w}", ("w", scheduled_witness) );
|
||||
fc::mutable_variant_object update;
|
||||
update("_action", "update")("id", scheduled_witness)("signing_key", debug_public_key);
|
||||
db->debug_update( update );
|
||||
}
|
||||
db->generate_block( scheduled_time, scheduled_witness, *debug_private_key, graphene::chain::database::skip_nothing );
|
||||
}
|
||||
}
|
||||
|
||||
void debug_api_impl::debug_update_object( const fc::variant_object& update )
|
||||
{
|
||||
std::shared_ptr< graphene::chain::database > db = app.chain_database();
|
||||
db->debug_update( update );
|
||||
}
|
||||
|
||||
std::shared_ptr< graphene::debug_witness_plugin::debug_witness_plugin > debug_api_impl::get_plugin()
|
||||
{
|
||||
return app.get_plugin< graphene::debug_witness_plugin::debug_witness_plugin >( "debug_witness" );
|
||||
}
|
||||
|
||||
void debug_api_impl::debug_stream_json_objects( const std::string& filename )
|
||||
{
|
||||
get_plugin()->set_json_object_stream( filename );
|
||||
}
|
||||
|
||||
void debug_api_impl::debug_stream_json_objects_flush()
|
||||
{
|
||||
get_plugin()->flush_json_object_stream();
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
debug_api::debug_api( graphene::app::application& app )
|
||||
{
|
||||
my = std::make_shared< detail::debug_api_impl >(app);
|
||||
}
|
||||
|
||||
void debug_api::debug_push_blocks( std::string source_filename, uint32_t count )
|
||||
{
|
||||
my->debug_push_blocks( source_filename, count );
|
||||
}
|
||||
|
||||
void debug_api::debug_generate_blocks( std::string debug_key, uint32_t count )
|
||||
{
|
||||
my->debug_generate_blocks( debug_key, count );
|
||||
}
|
||||
|
||||
void debug_api::debug_update_object( fc::variant_object update )
|
||||
{
|
||||
my->debug_update_object( update );
|
||||
}
|
||||
|
||||
void debug_api::debug_stream_json_objects( std::string filename )
|
||||
{
|
||||
my->debug_stream_json_objects( filename );
|
||||
}
|
||||
|
||||
void debug_api::debug_stream_json_objects_flush()
|
||||
{
|
||||
my->debug_stream_json_objects_flush();
|
||||
}
|
||||
|
||||
|
||||
} } // graphene::debug_witness
|
||||
173
libraries/plugins/debug_witness/debug_witness.cpp
Normal file
173
libraries/plugins/debug_witness/debug_witness.cpp
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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/debug_witness/debug_witness.hpp>
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
#include <graphene/time/time.hpp>
|
||||
|
||||
#include <graphene/utilities/key_conversion.hpp>
|
||||
|
||||
#include <fc/smart_ref_impl.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace graphene::debug_witness_plugin;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
debug_witness_plugin::~debug_witness_plugin() {}
|
||||
|
||||
void debug_witness_plugin::plugin_set_program_options(
|
||||
boost::program_options::options_description& command_line_options,
|
||||
boost::program_options::options_description& config_file_options)
|
||||
{
|
||||
auto default_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("nathan")));
|
||||
command_line_options.add_options()
|
||||
("private-key", bpo::value<vector<string>>()->composing()->multitoken()->
|
||||
DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))),
|
||||
"Tuple of [PublicKey, WIF private key] (may specify multiple times)");
|
||||
config_file_options.add(command_line_options);
|
||||
}
|
||||
|
||||
std::string debug_witness_plugin::plugin_name()const
|
||||
{
|
||||
return "debug_witness";
|
||||
}
|
||||
|
||||
void debug_witness_plugin::plugin_initialize(const boost::program_options::variables_map& options)
|
||||
{ try {
|
||||
ilog("debug_witness plugin: plugin_initialize() begin");
|
||||
_options = &options;
|
||||
|
||||
if( options.count("private-key") )
|
||||
{
|
||||
const std::vector<std::string> key_id_to_wif_pair_strings = options["private-key"].as<std::vector<std::string>>();
|
||||
for (const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings)
|
||||
{
|
||||
auto key_id_to_wif_pair = graphene::app::dejsonify<std::pair<chain::public_key_type, std::string> >(key_id_to_wif_pair_string);
|
||||
idump((key_id_to_wif_pair));
|
||||
fc::optional<fc::ecc::private_key> private_key = graphene::utilities::wif_to_key(key_id_to_wif_pair.second);
|
||||
if (!private_key)
|
||||
{
|
||||
// the key isn't in WIF format; see if they are still passing the old native private key format. This is
|
||||
// just here to ease the transition, can be removed soon
|
||||
try
|
||||
{
|
||||
private_key = fc::variant(key_id_to_wif_pair.second).as<fc::ecc::private_key>();
|
||||
}
|
||||
catch (const fc::exception&)
|
||||
{
|
||||
FC_THROW("Invalid WIF-format private key ${key_string}", ("key_string", key_id_to_wif_pair.second));
|
||||
}
|
||||
}
|
||||
_private_keys[key_id_to_wif_pair.first] = *private_key;
|
||||
}
|
||||
}
|
||||
ilog("debug_witness plugin: plugin_initialize() end");
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
void debug_witness_plugin::plugin_startup()
|
||||
{
|
||||
ilog("debug_witness_plugin::plugin_startup() begin");
|
||||
chain::database& db = database();
|
||||
|
||||
// connect needed signals
|
||||
|
||||
_applied_block_conn = db.applied_block.connect([this](const graphene::chain::signed_block& b){ on_applied_block(b); });
|
||||
_changed_objects_conn = db.changed_objects.connect([this](const std::vector<graphene::db::object_id_type>& ids){ on_changed_objects(ids); });
|
||||
_removed_objects_conn = db.removed_objects.connect([this](const std::vector<const graphene::db::object*>& objs){ on_removed_objects(objs); });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void debug_witness_plugin::on_changed_objects( const std::vector<graphene::db::object_id_type>& ids )
|
||||
{
|
||||
if( _json_object_stream && (ids.size() > 0) )
|
||||
{
|
||||
const chain::database& db = database();
|
||||
for( const graphene::db::object_id_type& oid : ids )
|
||||
{
|
||||
const graphene::db::object* obj = db.find_object( oid );
|
||||
if( obj == nullptr )
|
||||
{
|
||||
(*_json_object_stream) << "{\"id\":" << fc::json::to_string( oid ) << "}\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
(*_json_object_stream) << fc::json::to_string( obj->to_variant() ) << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void debug_witness_plugin::on_removed_objects( const std::vector<const graphene::db::object*> objs )
|
||||
{
|
||||
/*
|
||||
if( _json_object_stream )
|
||||
{
|
||||
for( const graphene::db::object* obj : objs )
|
||||
{
|
||||
(*_json_object_stream) << "{\"id\":" << fc::json::to_string( obj->id ) << "}\n";
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void debug_witness_plugin::on_applied_block( const graphene::chain::signed_block& b )
|
||||
{
|
||||
if( _json_object_stream )
|
||||
{
|
||||
(*_json_object_stream) << "{\"bn\":" << fc::to_string( b.block_num() ) << "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
void debug_witness_plugin::set_json_object_stream( const std::string& filename )
|
||||
{
|
||||
if( _json_object_stream )
|
||||
{
|
||||
_json_object_stream->close();
|
||||
_json_object_stream.reset();
|
||||
}
|
||||
_json_object_stream = std::make_shared< std::ofstream >( filename );
|
||||
}
|
||||
|
||||
void debug_witness_plugin::flush_json_object_stream()
|
||||
{
|
||||
if( _json_object_stream )
|
||||
_json_object_stream->flush();
|
||||
}
|
||||
|
||||
void debug_witness_plugin::plugin_shutdown()
|
||||
{
|
||||
if( _json_object_stream )
|
||||
{
|
||||
_json_object_stream->close();
|
||||
_json_object_stream.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <fc/api.hpp>
|
||||
#include <fc/variant_object.hpp>
|
||||
|
||||
namespace graphene { namespace app {
|
||||
class application;
|
||||
} }
|
||||
|
||||
namespace graphene { namespace debug_witness {
|
||||
|
||||
namespace detail {
|
||||
class debug_api_impl;
|
||||
}
|
||||
|
||||
class debug_api
|
||||
{
|
||||
public:
|
||||
debug_api( graphene::app::application& app );
|
||||
|
||||
/**
|
||||
* Push blocks from existing database.
|
||||
*/
|
||||
void debug_push_blocks( std::string src_filename, uint32_t count );
|
||||
|
||||
/**
|
||||
* Generate blocks locally.
|
||||
*/
|
||||
void debug_generate_blocks( std::string debug_key, uint32_t count );
|
||||
|
||||
/**
|
||||
* Directly manipulate database objects (will undo and re-apply last block with new changes post-applied).
|
||||
*/
|
||||
void debug_update_object( fc::variant_object update );
|
||||
|
||||
/**
|
||||
* Start a node with given initial path.
|
||||
*/
|
||||
// not implemented
|
||||
//void start_node( std::string name, std::string initial_db_path );
|
||||
|
||||
/**
|
||||
* Save the database to disk.
|
||||
*/
|
||||
// not implemented
|
||||
//void save_db( std::string db_path );
|
||||
|
||||
/**
|
||||
* Stream objects to file. (Hint: Create with mkfifo and pipe it to a script)
|
||||
*/
|
||||
|
||||
void debug_stream_json_objects( std::string filename );
|
||||
|
||||
/**
|
||||
* Flush streaming file.
|
||||
*/
|
||||
void debug_stream_json_objects_flush();
|
||||
|
||||
std::shared_ptr< detail::debug_api_impl > my;
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
FC_API(graphene::debug_witness::debug_api,
|
||||
(debug_push_blocks)
|
||||
(debug_generate_blocks)
|
||||
(debug_update_object)
|
||||
(debug_stream_json_objects)
|
||||
(debug_stream_json_objects_flush)
|
||||
)
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/app/plugin.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <fc/thread/future.hpp>
|
||||
|
||||
namespace graphene { namespace debug_witness_plugin {
|
||||
|
||||
class debug_witness_plugin : public graphene::app::plugin {
|
||||
public:
|
||||
~debug_witness_plugin();
|
||||
|
||||
std::string plugin_name()const override;
|
||||
|
||||
virtual void plugin_set_program_options(
|
||||
boost::program_options::options_description &command_line_options,
|
||||
boost::program_options::options_description &config_file_options
|
||||
) override;
|
||||
|
||||
virtual void plugin_initialize( const boost::program_options::variables_map& options ) override;
|
||||
virtual void plugin_startup() override;
|
||||
virtual void plugin_shutdown() override;
|
||||
|
||||
void set_json_object_stream( const std::string& filename );
|
||||
void flush_json_object_stream();
|
||||
|
||||
private:
|
||||
|
||||
void on_changed_objects( const std::vector<graphene::db::object_id_type>& ids );
|
||||
void on_removed_objects( const std::vector<const graphene::db::object*> objs );
|
||||
void on_applied_block( const graphene::chain::signed_block& b );
|
||||
|
||||
boost::program_options::variables_map _options;
|
||||
|
||||
std::map<chain::public_key_type, fc::ecc::private_key> _private_keys;
|
||||
|
||||
std::shared_ptr< std::ofstream > _json_object_stream;
|
||||
boost::signals2::scoped_connection _applied_block_conn;
|
||||
boost::signals2::scoped_connection _changed_objects_conn;
|
||||
boost::signals2::scoped_connection _removed_objects_conn;
|
||||
};
|
||||
|
||||
} } //graphene::debug_witness_plugin
|
||||
|
|
@ -1451,6 +1451,11 @@ class wallet_api
|
|||
|
||||
void dbg_make_uia(string creator, string symbol);
|
||||
void dbg_make_mia(string creator, string symbol);
|
||||
void dbg_push_blocks( std::string src_filename, uint32_t count );
|
||||
void dbg_generate_blocks( std::string debug_wif_key, uint32_t count );
|
||||
void dbg_stream_json_objects( const std::string& filename );
|
||||
void dbg_update_object( fc::variant_object update );
|
||||
|
||||
void flood_network(string prefix, uint32_t number_of_transactions);
|
||||
|
||||
void network_add_nodes( const vector<string>& nodes );
|
||||
|
|
@ -1623,6 +1628,10 @@ FC_API( graphene::wallet::wallet_api,
|
|||
(approve_proposal)
|
||||
(dbg_make_uia)
|
||||
(dbg_make_mia)
|
||||
(dbg_push_blocks)
|
||||
(dbg_generate_blocks)
|
||||
(dbg_stream_json_objects)
|
||||
(dbg_update_object)
|
||||
(flood_network)
|
||||
(network_add_nodes)
|
||||
(network_get_connected_peers)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@
|
|||
#include <graphene/wallet/wallet.hpp>
|
||||
#include <graphene/wallet/api_documentation.hpp>
|
||||
#include <graphene/wallet/reflect_util.hpp>
|
||||
#include <graphene/debug_witness/debug_api.hpp>
|
||||
#include <fc/smart_ref_impl.hpp>
|
||||
|
||||
#ifndef WIN32
|
||||
|
|
@ -2422,6 +2423,34 @@ public:
|
|||
create_asset(get_account(creator).name, symbol, 2, opts, bopts, true);
|
||||
}
|
||||
|
||||
void dbg_push_blocks( const std::string& src_filename, uint32_t count )
|
||||
{
|
||||
use_debug_api();
|
||||
(*_remote_debug)->debug_push_blocks( src_filename, count );
|
||||
(*_remote_debug)->debug_stream_json_objects_flush();
|
||||
}
|
||||
|
||||
void dbg_generate_blocks( const std::string& debug_wif_key, uint32_t count )
|
||||
{
|
||||
use_debug_api();
|
||||
(*_remote_debug)->debug_generate_blocks( debug_wif_key, count );
|
||||
(*_remote_debug)->debug_stream_json_objects_flush();
|
||||
}
|
||||
|
||||
void dbg_stream_json_objects( const std::string& filename )
|
||||
{
|
||||
use_debug_api();
|
||||
(*_remote_debug)->debug_stream_json_objects( filename );
|
||||
(*_remote_debug)->debug_stream_json_objects_flush();
|
||||
}
|
||||
|
||||
void dbg_update_object( const fc::variant_object& update )
|
||||
{
|
||||
use_debug_api();
|
||||
(*_remote_debug)->debug_update_object( update );
|
||||
(*_remote_debug)->debug_stream_json_objects_flush();
|
||||
}
|
||||
|
||||
void use_network_node_api()
|
||||
{
|
||||
if( _remote_net_node )
|
||||
|
|
@ -2440,6 +2469,26 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void use_debug_api()
|
||||
{
|
||||
if( _remote_debug )
|
||||
return;
|
||||
try
|
||||
{
|
||||
_remote_debug = _remote_api->debug();
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
std::cerr << "\nCouldn't get debug node API. You probably are not configured\n"
|
||||
"to access the debug API on the node you are connecting to.\n"
|
||||
"\n"
|
||||
"To fix this problem:\n"
|
||||
"- Please ensure you are running debug_node, not witness_node.\n"
|
||||
"- Please follow the instructions in README.md to set up an apiaccess file.\n"
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
void network_add_nodes( const vector<string>& nodes )
|
||||
{
|
||||
use_network_node_api();
|
||||
|
|
@ -2533,6 +2582,7 @@ public:
|
|||
fc::api<network_broadcast_api> _remote_net_broadcast;
|
||||
fc::api<history_api> _remote_hist;
|
||||
optional< fc::api<network_node_api> > _remote_net_node;
|
||||
optional< fc::api<graphene::debug_witness::debug_api> > _remote_debug;
|
||||
|
||||
flat_map<string, operation> _prototype_ops;
|
||||
|
||||
|
|
@ -3298,6 +3348,26 @@ void wallet_api::dbg_make_mia(string creator, string symbol)
|
|||
my->dbg_make_mia(creator, symbol);
|
||||
}
|
||||
|
||||
void wallet_api::dbg_push_blocks( std::string src_filename, uint32_t count )
|
||||
{
|
||||
my->dbg_push_blocks( src_filename, count );
|
||||
}
|
||||
|
||||
void wallet_api::dbg_generate_blocks( std::string debug_wif_key, uint32_t count )
|
||||
{
|
||||
my->dbg_generate_blocks( debug_wif_key, count );
|
||||
}
|
||||
|
||||
void wallet_api::dbg_stream_json_objects( const std::string& filename )
|
||||
{
|
||||
my->dbg_stream_json_objects( filename );
|
||||
}
|
||||
|
||||
void wallet_api::dbg_update_object( fc::variant_object update )
|
||||
{
|
||||
my->dbg_update_object( update );
|
||||
}
|
||||
|
||||
void wallet_api::network_add_nodes( const vector<string>& nodes )
|
||||
{
|
||||
my->network_add_nodes( nodes );
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ add_subdirectory( build_helpers )
|
|||
add_subdirectory( cli_wallet )
|
||||
add_subdirectory( genesis_util )
|
||||
add_subdirectory( witness_node )
|
||||
add_subdirectory( debug_node )
|
||||
add_subdirectory( delayed_node )
|
||||
add_subdirectory( js_operation_serializer )
|
||||
add_subdirectory( size_checker )
|
||||
|
|
|
|||
21
programs/debug_node/CMakeLists.txt
Normal file
21
programs/debug_node/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
add_executable( debug_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 debug_node with TCMalloc")
|
||||
list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc )
|
||||
endif()
|
||||
|
||||
target_link_libraries( debug_node
|
||||
PRIVATE graphene_app graphene_account_history graphene_market_history graphene_witness graphene_debug_witness graphene_chain graphene_egenesis_full fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} )
|
||||
|
||||
install( TARGETS
|
||||
debug_node
|
||||
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
307
programs/debug_node/main.cpp
Normal file
307
programs/debug_node/main.cpp
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* 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/debug_witness/debug_witness.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) {
|
||||
app::application* node = new app::application();
|
||||
fc::oexception unhandled_exception;
|
||||
try {
|
||||
bpo::options_description app_options("Graphene Witness Node");
|
||||
bpo::options_description cfg_options("Graphene Witness Node");
|
||||
app_options.add_options()
|
||||
("help,h", "Print this help message and exit.")
|
||||
("data-dir,d", bpo::value<boost::filesystem::path>()->default_value("witness_node_data_dir"), "Directory containing databases, configuration file, etc.")
|
||||
;
|
||||
|
||||
bpo::variables_map options;
|
||||
|
||||
auto witness_plug = node->register_plugin<debug_witness_plugin::debug_witness_plugin>();
|
||||
auto history_plug = node->register_plugin<account_history::account_history_plugin>();
|
||||
auto market_history_plug = node->register_plugin<market_history::market_history_plugin>();
|
||||
|
||||
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";
|
||||
if( fc::exists(config_ini_path) )
|
||||
{
|
||||
// get the basic options
|
||||
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()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
bpo::notify(options);
|
||||
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) {
|
||||
elog( "Caught SIGINT attempting to exit cleanly" );
|
||||
exit_promise->set_value(signal);
|
||||
}, SIGINT);
|
||||
|
||||
fc::set_signal_handler([&exit_promise](int signal) {
|
||||
elog( "Caught SIGTERM attempting to exit cleanly" );
|
||||
exit_promise->set_value(signal);
|
||||
}, SIGTERM);
|
||||
|
||||
ilog("Started witness 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();
|
||||
node->shutdown();
|
||||
delete node;
|
||||
return 0;
|
||||
} catch( const fc::exception& e ) {
|
||||
// deleting the node can yield, so do this outside the exception handler
|
||||
unhandled_exception = e;
|
||||
}
|
||||
|
||||
if (unhandled_exception)
|
||||
{
|
||||
elog("Exiting with error:\n${e}", ("e", unhandled_exception->to_detail_string()));
|
||||
node->shutdown();
|
||||
delete node;
|
||||
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=debug\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).as<fc::console_appender::stream::type>();
|
||||
logging_config.appenders.push_back(fc::appender_config(console_appender_name, "console", fc::variant(console_appender_config)));
|
||||
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)));
|
||||
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).as<fc::log_level>();
|
||||
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, "")
|
||||
}
|
||||
|
|
@ -9,8 +9,9 @@ if( GPERFTOOLS_FOUND )
|
|||
list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc )
|
||||
endif()
|
||||
|
||||
# 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
|
||||
PRIVATE graphene_app graphene_account_history graphene_market_history graphene_witness graphene_chain graphene_egenesis_full fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} )
|
||||
PRIVATE graphene_app graphene_account_history graphene_market_history graphene_witness graphene_chain graphene_debug_witness graphene_egenesis_full fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} )
|
||||
|
||||
install( TARGETS
|
||||
witness_node
|
||||
|
|
|
|||
Loading…
Reference in a new issue