12#include <boost/signals2/connection.hpp>
16using boost::signals2::scoped_connection;
24 std::string to_detail_string(
const std::exception_ptr& e) {
26 std::rethrow_exception(e);
29 }
catch (
const std::exception& e) {
31 FC_LOG_MESSAGE(warn,
"std::exception: ${what}: ", (
"what", e.what())),
33 BOOST_CORE_TYPEID(e).
name(),
35 return fce.to_detail_string();
39 std::current_exception());
40 return ue.to_detail_string();
46 auto detail_string = to_detail_string(std::get<0>(e));
63 void emit_killer(F&&
f) {
67 SYS_THROW(chain::controller_emit_signal_exception,
"Trace API encountered an Error which it cannot recover from. Please resolve the error and relaunch the process")
71 template<
typename Store>
72 struct shared_store_provider {
73 shared_store_provider(
const std::shared_ptr<Store>& store)
77 template <
typename BlockTrace>
78 void append(
const BlockTrace& trace ) {
82 void append_lib(
uint32_t new_lib ) {
83 store->append_lib(new_lib);
87 return store->get_block(height, yield);
91 store->append_trx_ids(std::move(tt));
94 std::shared_ptr<Store> store;
105 auto cfg_options = cfg.add_options();
106 cfg_options(
"trace-dir", bpo::value<bfs::path>()->default_value(
"traces"),
107 "the location of the trace directory (absolute path or relative to application data dir)");
108 cfg_options(
"trace-slice-stride", bpo::value<uint32_t>()->default_value(10'000),
109 "the number of blocks each \"slice\" of trace data will contain on the filesystem");
110 cfg_options(
"trace-minimum-irreversible-history-blocks", boost::program_options::value<int32_t>()->default_value(-1),
111 "Number of blocks to ensure are kept past LIB for retrieval before \"slice\" files can be automatically removed.\n"
112 "A value of -1 indicates that automatic removal of \"slice\" files will be turned off.");
113 cfg_options(
"trace-minimum-uncompressed-irreversible-history-blocks", boost::program_options::value<int32_t>()->default_value(-1),
114 "Number of blocks to ensure are uncompressed past LIB. Compressed \"slice\" files are still accessible but may carry a performance loss on retrieval\n"
115 "A value of -1 indicates that automatic compression of \"slice\" files will be turned off.");
119 auto dir_option = options.at(
"trace-dir").as<bfs::path>();
120 if (dir_option.is_relative())
124 if (
auto resmon_plugin =
app().find_plugin<resource_monitor_plugin>())
125 resmon_plugin->monitor_directory(
trace_dir);
129 const int32_t blocks = options.at(
"trace-minimum-irreversible-history-blocks").as<
int32_t>();
130 SYS_ASSERT(blocks >= -1, chain::plugin_config_exception,
131 "\"trace-minimum-irreversible-history-blocks\" must be greater to or equal to -1.");
136 const int32_t uncompressed_blocks = options.at(
"trace-minimum-uncompressed-irreversible-history-blocks").as<
int32_t>();
137 SYS_ASSERT(uncompressed_blocks >= -1, chain::plugin_config_exception,
138 "\"trace-minimum-uncompressed-irreversible-history-blocks\" must be greater to or equal to -1.");
144 store = std::make_shared<store_provider>(
154 store->start_maintenance_thread([](
const std::string& msg ){
160 store->stop_maintenance_thread();
173 std::shared_ptr<store_provider>
store;
185 auto cfg_options = cfg.add_options();
186 cfg_options(
"trace-rpc-abi", bpo::value<
vector<string>>()->composing(),
187 "ABIs used when decoding trace RPC responses.\n"
188 "There must be at least one ABI specified OR the flag trace-no-abis must be used.\n"
189 "ABIs are specified as \"Key=Value\" pairs in the form <account-name>=<abi-def>\n"
190 "Where <abi-def> can be:\n"
191 " an absolute path to a file containing a valid JSON-encoded ABI\n"
192 " a relative path from `data-dir` to a file containing a valid JSON-encoded ABI\n"
194 cfg_options(
"trace-no-abis",
195 "Use to indicate that the RPC responses will not use ABIs.\n"
196 "Failure to specify this option when there are no trace-rpc-abi configuations will result in an Error.\n"
197 "This option is mutually exclusive with trace-rpc-api"
202 ilog(
"initializing trace api rpc plugin");
203 std::shared_ptr<abi_data_handler> data_handler = std::make_shared<abi_data_handler>([](
const exception_with_context& e){
207 if( options.count(
"trace-rpc-abi") ) {
208 SYS_ASSERT(options.count(
"trace-no-abis") == 0, chain::plugin_config_exception,
209 "Trace API is configured with ABIs however trace-no-abis is set");
210 const std::vector<std::string> key_value_pairs = options[
"trace-rpc-abi"].as<std::vector<std::string>>();
211 for (
const auto& entry : key_value_pairs) {
216 data_handler->add_abi(account, abi);
218 elog(
"Malformed trace-rpc-abi provider: \"${val}\"", (
"val", entry));
223 SYS_ASSERT(options.count(
"trace-no-abis") != 0, chain::plugin_config_exception,
224 "Trace API is not configured with ABIs and trace-no-abis is not set");
228 shared_store_provider<store_provider>(
common->store),
230 [](
const std::string& msg ) {
231 fc_dlog( _log, msg );
241 deadline += max_serialization_time;
250 http.add_async_handler(
"/v1/trace_api/get_block",
253 auto that = wthis.lock();
258 auto block_number = ([&body]() -> std::optional<uint32_t> {
265 auto block_num = input.get_object()[
"block_num"].as_uint64();
266 if (block_num > std::numeric_limits<uint32_t>::max()) {
283 const auto deadline = that->calc_deadline( max_response_time );
284 auto resp = that->req_handler->get_block_trace(*block_number, [deadline]() {
FC_CHECK_DEADLINE(deadline); });
285 if (resp.is_null()) {
289 cb( 200, std::move(resp) );
297 http.add_async_handler(
"/v1/trace_api/get_transaction_trace",
298 [wthis=weak_from_this(), max_response_time,
this](std::string, std::string body,
url_response_callback cb)
300 auto that = wthis.lock();
305 auto trx_id = ([&body]() -> std::optional<transaction_id_type> {
311 auto trxid = input.get_object()[
"id"].as_string();
312 if (trxid.size() < 8 || trxid.size() > 64) {
328 const auto deadline = that->calc_deadline( max_response_time );
330 get_block_n blk_num =
common->store->get_trx_block_number(*trx_id,
common->minimum_irreversible_history_blocks, [deadline]() { FC_CHECK_DEADLINE(deadline); });
331 if (!blk_num.has_value()){
332 error_results results{404,
"Trace API: transaction id missing in the transaction id log files"};
335 auto resp = that->req_handler->get_transaction_trace(*trx_id, *blk_num, [deadline]() {
FC_CHECK_DEADLINE(deadline); });
336 if (resp.is_null()) {
340 cb( 200, std::move(resp) );
352 std::shared_ptr<trace_api_common_impl>
common;
366 ilog(
"initializing trace api plugin");
372 extraction = std::make_shared<chain_extraction_t>(shared_store_provider<store_provider>(
common->store), log_exceptions_and_shutdown);
377 chain.applied_transaction.connect([
this](std::tuple<const chain::transaction_trace_ptr&, const chain::packed_transaction_ptr&> t) {
379 extraction->signal_applied_transaction(std::get<0>(t), std::get<1>(t));
384 chain.block_start.connect([
this](
uint32_t block_num) {
386 extraction->signal_block_start(block_num);
390 accepted_block_connection.emplace(
393 extraction->signal_accepted_block(
p);
397 irreversible_block_connection.emplace(
400 extraction->signal_irreversible_block(
p);
407 common->plugin_startup();
411 common->plugin_shutdown();
414 std::shared_ptr<trace_api_common_impl>
common;
425trace_api_plugin::trace_api_plugin()
438 auto common = std::make_shared<trace_api_common_impl>();
439 common->plugin_initialize(options);
441 my = std::make_shared<trace_api_plugin_impl>(common);
442 my->plugin_initialize(options);
444 rpc = std::make_shared<trace_api_rpc_plugin_impl>(common);
445 rpc->plugin_initialize(options);
451 my->plugin_startup();
452 rpc->plugin_startup();
456 my->plugin_shutdown();
457 rpc->plugin_shutdown();
477 auto common = std::make_shared<trace_api_common_impl>();
478 common->plugin_initialize(options);
480 rpc = std::make_shared<trace_api_rpc_plugin_impl>(common);
481 rpc->plugin_initialize(options);
485 rpc->plugin_startup();
489 rpc->plugin_shutdown();
#define SYS_THROW(exc_type, FORMAT,...)
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
abstract_plugin * find_plugin(const string &name) const
abstract_plugin & get_plugin(const string &name) const
bfs::path data_dir() const
Get data directory.
Used to generate a useful error report when an exception is thrown.
std::string to_detail_string(log_level ll=log_level::all) const
static variant from_string(const string &utf8_str, const parse_type ptype=parse_type::legacy_parser, uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
provides information about where and when a log message was generated.
aggregates a message along with the context and associated meta-information.
static void update(const fc::string &name, logger &log)
bool is_enabled(log_level e) const
static constexpr microseconds maximum()
static constexpr time_point maximum()
re-thrown whenever an unhandled exception is caught.Any exceptions thrown by 3rd party libraries that...
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
static void handle_exception(const char *api_name, const char *call_name, const string &body, url_response_callback cb)
void plugin_initialize(const appbase::variables_map &options)
virtual void set_program_options(appbase::options_description &cli, appbase::options_description &cfg) override
virtual ~trace_api_plugin()
void handle_sighup() override
void plugin_initialize(const appbase::variables_map &options)
virtual ~trace_api_rpc_plugin()
virtual void set_program_options(appbase::options_description &cli, appbase::options_description &cfg) override
void handle_sighup() override
#define FC_CHECK_DEADLINE(DEADLINE,...)
#define FC_LOG_MESSAGE(LOG_LEVEL, FORMAT,...)
A helper method for generating log messages.
#define fc_ilog(LOGGER, FORMAT,...)
#define fc_dlog(LOGGER, FORMAT,...)
checksum_type transaction_id_type
std::shared_ptr< block_state > block_state_ptr
std::pair< std::string, std::string > parse_kv_pairs(const std::string &input)
chain::abi_def abi_def_from_file(const std::string &file_name, const fc::path &data_dir)
std::tuple< const std::exception_ptr &, char const *, uint64_t, char const * > exception_with_context
std::optional< std::tuple< data_log_entry, bool > > get_block_t
std::optional< uint32_t > get_block_n
std::function< void(int, fc::variant)> url_response_callback
A callback function provided to a URL handler to allow it to specify the HTTP response code and body.
const fc::string logger_name("net_plugin_impl")
Immutable except for fc::from_variant.
Structure used to create JSON error responses.
static constexpr int32_t manual_slice_file_value
boost::filesystem::path trace_dir
std::optional< uint32_t > minimum_irreversible_history_blocks
static void set_program_options(appbase::options_description &cli, appbase::options_description &cfg)
static constexpr uint32_t compression_seek_point_stride
void plugin_initialize(const appbase::variables_map &options)
std::shared_ptr< store_provider > store
std::optional< uint32_t > minimum_uncompressed_irreversible_history_blocks
void plugin_initialize(const appbase::variables_map &options)
std::optional< scoped_connection > applied_transaction_connection
std::optional< scoped_connection > block_start_connection
static void set_program_options(appbase::options_description &cli, appbase::options_description &cfg)
std::optional< scoped_connection > irreversible_block_connection
std::shared_ptr< trace_api_common_impl > common
std::optional< scoped_connection > accepted_block_connection
trace_api_plugin_impl(const std::shared_ptr< trace_api_common_impl > &common)
std::shared_ptr< chain_extraction_t > extraction
static void set_program_options(appbase::options_description &cli, appbase::options_description &cfg)
fc::time_point calc_deadline(const fc::microseconds &max_serialization_time)
trace_api_rpc_plugin_impl(const std::shared_ptr< trace_api_common_impl > &common)
std::shared_ptr< trace_api_common_impl > common
std::shared_ptr< request_handler_t > req_handler
void plugin_initialize(const appbase::variables_map &options)