diff --git a/libraries/chain/include/eosio/chain/resource_limits.hpp b/libraries/chain/include/eosio/chain/resource_limits.hpp index 4b0c58beeb0..08d1d1f7c3b 100644 --- a/libraries/chain/include/eosio/chain/resource_limits.hpp +++ b/libraries/chain/include/eosio/chain/resource_limits.hpp @@ -12,6 +12,14 @@ namespace eosio { namespace chain { namespace resource_limits { static_assert(std::is_integral::value, "ratios must have integral types"); T numerator; T denominator; + + friend inline bool operator ==( const ratio& lhs, const ratio& rhs ) { + return std::tie(lhs.numerator, lhs.denominator) == std::tie(rhs.numerator, rhs.denominator); + } + + friend inline bool operator !=( const ratio& lhs, const ratio& rhs ) { + return !(lhs == rhs); + } }; } @@ -27,6 +35,15 @@ namespace eosio { namespace chain { namespace resource_limits { ratio expand_rate; // the rate at which an uncongested resource expands its limits void validate()const; // throws if the parameters do not satisfy basic sanity checks + + friend inline bool operator ==( const elastic_limit_parameters& lhs, const elastic_limit_parameters& rhs ) { + return std::tie(lhs.target, lhs.max, lhs.periods, lhs.max_multiplier, lhs.contract_rate, lhs.expand_rate) + == std::tie(rhs.target, rhs.max, rhs.periods, rhs.max_multiplier, rhs.contract_rate, rhs.expand_rate); + } + + friend inline bool operator !=( const elastic_limit_parameters& lhs, const elastic_limit_parameters& rhs ) { + return !(lhs == rhs); + } }; struct account_resource_limit { diff --git a/libraries/chain/resource_limits.cpp b/libraries/chain/resource_limits.cpp index 43ced268542..d98ca79fbc8 100644 --- a/libraries/chain/resource_limits.cpp +++ b/libraries/chain/resource_limits.cpp @@ -102,6 +102,8 @@ void resource_limits_manager::set_block_parameters(const elastic_limit_parameter cpu_limit_parameters.validate(); net_limit_parameters.validate(); const auto& config = _db.get(); + if( config.cpu_limit_parameters == cpu_limit_parameters && config.net_limit_parameters == net_limit_parameters ) + return; _db.modify(config, [&](resource_limits_config_object& c){ c.cpu_limit_parameters = cpu_limit_parameters; c.net_limit_parameters = net_limit_parameters; diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp index e11b7e5f4f7..07b241aeec6 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp @@ -18,6 +18,8 @@ #include #include +#include + template struct history_serial_wrapper { const chainbase::database& db; @@ -25,7 +27,7 @@ struct history_serial_wrapper { }; template -history_serial_wrapper make_history_serial_wrapper(const chainbase::database& db, const T& obj) { +history_serial_wrapper> make_history_serial_wrapper(const chainbase::database& db, const T& obj) { return {db, obj}; } @@ -37,7 +39,8 @@ struct history_context_wrapper { }; template -history_context_wrapper make_history_context_wrapper(const chainbase::database& db, P& context, const T& obj) { +history_context_wrapper, std::decay_t> +make_history_context_wrapper(const chainbase::database& db, const P& context, const T& obj) { return {db, context, obj}; } @@ -67,6 +70,16 @@ datastream& history_serialize_container(datastream& ds, const chainbase: return ds; } +template +datastream& history_context_serialize_container(datastream& ds, const chainbase::database& db, const P& context, + const std::vector& v) { + fc::raw::pack(ds, unsigned_int(v.size())); + for (const auto& x : v) { + ds << make_history_context_wrapper(db, context, x); + } + return ds; +} + template datastream& operator<<(datastream& ds, const history_serial_big_vector_wrapper& obj) { FC_ASSERT(obj.obj.size() <= 1024 * 1024 * 1024); @@ -96,6 +109,11 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper +datastream& operator<<(datastream& ds, const history_context_wrapper>& obj) { + return history_context_serialize_container(ds, obj.db, obj.context, obj.obj); +} + template datastream& operator<<(datastream& ds, const history_serial_wrapper>& obj) { fc::raw::pack(ds, obj.obj.first); @@ -151,8 +169,8 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); fc::raw::pack(ds, as_type(obj.context.code.value)); fc::raw::pack(ds, as_type(obj.context.scope.value)); @@ -208,36 +226,36 @@ datastream& serialize_secondary_index(datastream& ds, const eosio::chain template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& operator<<( - datastream& ds, - const history_context_wrapper& obj) { + datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } @@ -516,8 +534,25 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper cap_error_code( const fc::optional& error_code ) { + fc::optional result; + + if (!error_code) return result; + + const uint64_t upper_limit = static_cast(eosio::chain::system_error_code::generic_system_error); + + if (*error_code >= upper_limit) { + result = upper_limit; + return result; + } + + result = error_code; + return result; +} + template -datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { +datastream& operator<<(datastream& ds, const history_context_wrapper& obj) { + bool debug_mode = obj.context; fc::raw::pack(ds, fc::unsigned_int(0)); fc::raw::pack(ds, as_type(obj.obj.action_ordinal)); fc::raw::pack(ds, as_type(obj.obj.creator_action_ordinal)); @@ -528,23 +563,33 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper(obj.obj.receiver.value)); fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.act))); fc::raw::pack(ds, as_type(obj.obj.context_free)); - fc::raw::pack(ds, as_type(obj.obj.elapsed.count())); - fc::raw::pack(ds, as_type(obj.obj.console)); + fc::raw::pack(ds, as_type(debug_mode ? obj.obj.elapsed.count() : 0)); + if (debug_mode) + fc::raw::pack(ds, as_type(obj.obj.console)); + else + fc::raw::pack(ds, std::string{}); history_serialize_container(ds, obj.db, as_type>(obj.obj.account_ram_deltas)); fc::optional e; - if (obj.obj.except) - e = obj.obj.except->to_string(); + if (obj.obj.except) { + if (debug_mode) + e = obj.obj.except->to_string(); + else + e = "Y"; + } fc::raw::pack(ds, as_type>(e)); - fc::raw::pack(ds, as_type>(obj.obj.error_code)); + fc::raw::pack(ds, as_type>(debug_mode ? obj.obj.error_code + : cap_error_code(obj.obj.error_code))); return ds; } template -datastream& operator<<(datastream& ds, - const history_context_wrapper& obj) { +datastream& operator<<(datastream& ds, + const history_context_wrapper, + eosio::augmented_transaction_trace>& obj) { auto& trace = *obj.obj.trace; + bool debug_mode = obj.context.second; fc::raw::pack(ds, fc::unsigned_int(0)); fc::raw::pack(ds, as_type(trace.id)); if (trace.receipt) { @@ -555,14 +600,15 @@ datastream& operator<<(datastream& fc::raw::pack(ds, as_type(trace.receipt->cpu_usage_us)); fc::raw::pack(ds, as_type(trace.receipt->net_usage_words)); } else { - fc::raw::pack(ds, uint8_t(obj.context)); + fc::raw::pack(ds, uint8_t(obj.context.first)); fc::raw::pack(ds, uint32_t(0)); fc::raw::pack(ds, fc::unsigned_int(0)); } - fc::raw::pack(ds, as_type(trace.elapsed.count())); + fc::raw::pack(ds, as_type(debug_mode ? trace.elapsed.count() : 0)); fc::raw::pack(ds, as_type(trace.net_usage)); fc::raw::pack(ds, as_type(trace.scheduled)); - history_serialize_container(ds, obj.db, as_type>(trace.action_traces)); + history_context_serialize_container(ds, obj.db, debug_mode, + as_type>(trace.action_traces)); fc::raw::pack(ds, bool(trace.account_ram_delta)); if (trace.account_ram_delta) { @@ -571,19 +617,25 @@ datastream& operator<<(datastream& } fc::optional e; - if (trace.except) - e = trace.except->to_string(); + if (trace.except) { + if (debug_mode) + e = trace.except->to_string(); + else + e = "Y"; + } fc::raw::pack(ds, as_type>(e)); - fc::raw::pack(ds, as_type>(trace.error_code)); + fc::raw::pack(ds, as_type>(debug_mode ? trace.error_code + : cap_error_code(trace.error_code))); fc::raw::pack(ds, bool(trace.failed_dtrx_trace)); if (trace.failed_dtrx_trace) { uint8_t stat = eosio::chain::transaction_receipt_header::hard_fail; if (trace.receipt && trace.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) stat = eosio::chain::transaction_receipt_header::soft_fail; + std::pair context = std::make_pair(stat, debug_mode); fc::raw::pack( // ds, make_history_context_wrapper( - obj.db, stat, eosio::augmented_transaction_trace{trace.failed_dtrx_trace, obj.obj.partial})); + obj.db, context, eosio::augmented_transaction_trace{trace.failed_dtrx_trace, obj.obj.partial})); } bool include_partial = obj.obj.partial && !trace.failed_dtrx_trace; @@ -606,9 +658,10 @@ datastream& operator<<(datastream& } template -datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - uint8_t stat = eosio::chain::transaction_receipt_header::hard_fail; - ds << make_history_context_wrapper(obj.db, stat, obj.obj); +datastream& operator<<(datastream& ds, + const history_context_wrapper& obj) { + std::pair context = std::make_pair(eosio::chain::transaction_receipt_header::hard_fail, obj.context); + ds << make_history_context_wrapper(obj.db, context, obj.obj); return ds; } diff --git a/plugins/state_history_plugin/state_history_plugin.cpp b/plugins/state_history_plugin/state_history_plugin.cpp index f0579891dee..0d6d33fb34a 100644 --- a/plugins/state_history_plugin/state_history_plugin.cpp +++ b/plugins/state_history_plugin/state_history_plugin.cpp @@ -109,6 +109,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this trace_log; fc::optional chain_state_log; + bool trace_debug_mode = false; bool stopping = false; fc::optional applied_transaction_connection; fc::optional accepted_block_connection; @@ -441,7 +442,7 @@ struct state_history_plugin_impl : std::enable_shared_from_thischain().db(); - auto traces_bin = zlib_compress_bytes(fc::raw::pack(make_history_serial_wrapper(db, traces))); + auto traces_bin = zlib_compress_bytes(fc::raw::pack(make_history_context_wrapper(db, trace_debug_mode, traces))); EOS_ASSERT(traces_bin.size() == (uint32_t)traces_bin.size(), plugin_exception, "traces is too big"); state_history_log_header header{.magic = ship_magic(ship_current_version), @@ -570,6 +571,8 @@ void state_history_plugin::set_program_options(options_description& cli, options options("state-history-endpoint", bpo::value()->default_value("127.0.0.1:8080"), "the endpoint upon which to listen for incoming connections. Caution: only expose this port to " "your internal network."); + options("trace-history-debug-mode", bpo::bool_switch()->default_value(false), + "enable debug mode for trace history"); } void state_history_plugin::plugin_initialize(const variables_map& options) { @@ -607,6 +610,10 @@ void state_history_plugin::plugin_initialize(const variables_map& options) { } boost::filesystem::create_directories(state_history_dir); + if (options.at("trace-history-debug-mode").as()) { + my->trace_debug_mode = true; + } + if (options.at("trace-history").as()) my->trace_log.emplace("trace_history", (state_history_dir / "trace_history.log").string(), (state_history_dir / "trace_history.index").string());