Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

DAWN 515 - Improving EOSIOC: error that is received from RPC API Call #1477

Merged
merged 2 commits into from
Feb 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions libraries/chain/name.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
namespace eosio { namespace chain {

void name::set( const char* str ) {
try {
const auto len = strnlen(str,14);
EOS_ASSERT( len <= 13, name_type_exception, "Name is longer than 13 characters (${name}) ", ("name",string(str)) );
const auto len = strnlen(str, 14);
EOS_ASSERT(len <= 13, name_type_exception, "Name is longer than 13 characters (${name}) ", ("name", string(str)));
value = string_to_name(str);
EOS_ASSERT( to_string() == string(str), name_type_exception, "Name not properly normalized (name: ${name}, normalized: ${normalized}) ", ("name",string(str))("normalized",to_string()) );
}FC_CAPTURE_AND_RETHROW( (str) ) }
EOS_ASSERT(to_string() == string(str), name_type_exception,
"Name not properly normalized (name: ${name}, normalized: ${normalized}) ",
("name", string(str))("normalized", to_string()));
}

name::operator string()const {
static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ void account_history_api_plugin::plugin_initialize(const variables_map&) {}
auto result = api_handle.call_name(fc::json::from_string(body).as<api_namespace::call_name ## _params>()); \
cb(200, fc::json::to_string(result)); \
} catch (fc::eof_exception& e) { \
error_results results{400, "Bad Request", e.to_string()}; \
error_results results{400, "Bad Request", e}; \
cb(400, fc::json::to_string(results)); \
elog("Unable to parse arguments: ${args}", ("args", body)); \
} catch (fc::exception& e) { \
error_results results{500, "Internal Service Error", e.to_detail_string()}; \
error_results results{500, "Internal Service Error", e}; \
cb(500, fc::json::to_string(results)); \
elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \
} \
Expand Down
10 changes: 5 additions & 5 deletions plugins/chain_api_plugin/chain_api_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,20 @@ void chain_api_plugin::plugin_initialize(const variables_map&) {}
auto result = api_handle.call_name(fc::json::from_string(body).as<api_namespace::call_name ## _params>()); \
cb(http_response_code, fc::json::to_string(result)); \
} catch (chain::tx_missing_sigs& e) { \
error_results results{401, "UnAuthorized", e.to_string()}; \
error_results results{401, "UnAuthorized", e}; \
cb(401, fc::json::to_string(results)); \
} catch (chain::tx_duplicate& e) { \
error_results results{409, "Conflict", e.to_string()}; \
error_results results{409, "Conflict", e}; \
cb(409, fc::json::to_string(results)); \
} catch (chain::transaction_exception& e) { \
error_results results{400, "Bad Request", e.to_string()}; \
error_results results{400, "Bad Request", e}; \
cb(400, fc::json::to_string(results)); \
} catch (fc::eof_exception& e) { \
error_results results{400, "Bad Request", e.to_string()}; \
error_results results{400, "Bad Request", e}; \
cb(400, fc::json::to_string(results)); \
elog("Unable to parse arguments: ${args}", ("args", body)); \
} catch (fc::exception& e) { \
error_results results{500, "Internal Service Error", e.to_detail_string()}; \
error_results results{500, "Internal Service Error", e}; \
cb(500, fc::json::to_string(results)); \
elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \
} \
Expand Down
4 changes: 2 additions & 2 deletions plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ using results_pair = std::pair<uint32_t,fc::variant>;
const auto result = api_handle->invoke_cb(body); \
response_cb(result.first, fc::json::to_string(result.second)); \
} catch (fc::eof_exception& e) { \
error_results results{400, "Bad Request", e.to_string()}; \
error_results results{400, "Bad Request", e}; \
response_cb(400, fc::json::to_string(results)); \
elog("Unable to parse arguments: ${args}", ("args", body)); \
} catch (fc::exception& e) { \
error_results results{500, "Internal Service Error", e.to_detail_string()}; \
error_results results{500, "Internal Service Error", e}; \
response_cb(500, fc::json::to_string(results)); \
elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \
} \
Expand Down
8 changes: 4 additions & 4 deletions plugins/http_plugin/http_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,25 +186,25 @@ namespace eosio {
} else {
wlog("404 - not found: ${ep}", ("ep",resource));
error_results results{websocketpp::http::status_code::not_found,
"Not Found", "Unknown Endpoint"};
"Not Found", fc::exception(FC_LOG_MESSAGE(error, "Unknown Endpoint"))};
con->set_body(fc::json::to_string(results));
con->set_status(websocketpp::http::status_code::not_found);
}
} catch( const fc::exception& e ) {
elog( "http: ${e}", ("e",e.to_detail_string()));
error_results results{websocketpp::http::status_code::internal_server_error,
"Internal Service Error", e.to_detail_string()};
"Internal Service Error", e};
con->set_body(fc::json::to_string(results));
con->set_status(websocketpp::http::status_code::internal_server_error);
} catch( const std::exception& e ) {
elog( "http: ${e}", ("e",e.what()));
error_results results{websocketpp::http::status_code::internal_server_error,
"Internal Service Error", e.what()};
"Internal Service Error", fc::exception(FC_LOG_MESSAGE(error, e.what()))};
con->set_body(fc::json::to_string(results));
con->set_status(websocketpp::http::status_code::internal_server_error);
} catch( ... ) {
error_results results{websocketpp::http::status_code::internal_server_error,
"Internal Service Error", "unknown exception"};
"Internal Service Error", fc::exception(FC_LOG_MESSAGE(error, "Unknown Exception"))};
con->set_body(fc::json::to_string(results));
con->set_status(websocketpp::http::status_code::internal_server_error);
}
Expand Down
35 changes: 31 additions & 4 deletions plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
#pragma once
#include <appbase/application.hpp>
#include <fc/exception/exception.hpp>

#include <fc/reflect/reflect.hpp>

Expand Down Expand Up @@ -80,10 +81,36 @@ namespace eosio {
* @brief Structure used to create JSON error responses
*/
struct error_results {
uint16_t code;
string message;
string details;
struct error_detail {
int64_t code;
string name;
string message;
string details;
vector<fc::log_context> stack_trace;

static const uint8_t stack_trace_limit = 10;

error_detail() {};

error_detail(const fc::exception& exc) {
code = exc.code();
name = exc.name();
message = exc.what();
details = exc.top_message();
for (auto itr = exc.get_log().begin(); itr != exc.get_log().end(); ++itr) {
// Prevent sending trace that are too big
if (stack_trace.size() >= stack_trace_limit) break;
// Append context
stack_trace.emplace_back(itr->get_context());
}
}
};

uint16_t code;
string message;
error_detail error;
};
}

FC_REFLECT(eosio::error_results, (code)(message)(details))
FC_REFLECT(eosio::error_results::error_detail, (code)(name)(message)(details)(stack_trace))
FC_REFLECT(eosio::error_results, (code)(message)(error))
4 changes: 2 additions & 2 deletions plugins/net_api_plugin/net_api_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ using namespace eosio;
INVOKE \
cb(http_response_code, fc::json::to_string(result)); \
} catch (fc::eof_exception& e) { \
error_results results{400, "Bad Request", e.to_string()}; \
error_results results{400, "Bad Request", e}; \
cb(400, fc::json::to_string(results)); \
elog("Unable to parse arguments: ${args}", ("args", body)); \
} catch (fc::exception& e) { \
error_results results{500, "Internal Service Error", e.to_detail_string()}; \
error_results results{500, "Internal Service Error", e}; \
cb(500, fc::json::to_string(results)); \
elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \
} \
Expand Down
4 changes: 2 additions & 2 deletions plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ using namespace eosio::chain;
INVOKE \
cb(http_response_code, fc::json::to_string(result)); \
} catch (fc::eof_exception& e) { \
error_results results{400, "Bad Request", e.to_string()}; \
error_results results{400, "Bad Request", e}; \
cb(400, fc::json::to_string(results)); \
elog("Unable to parse arguments: ${args}", ("args", body)); \
} catch (fc::exception& e) { \
error_results results{500, "Internal Service Error", e.to_detail_string()}; \
error_results results{500, "Internal Service Error", e}; \
cb(500, fc::json::to_string(results)); \
elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \
} \
Expand Down
4 changes: 2 additions & 2 deletions plugins/wallet_api_plugin/wallet_api_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ using namespace eosio;
INVOKE \
cb(http_response_code, fc::json::to_string(result)); \
} catch (fc::eof_exception& e) { \
error_results results{400, "Bad Request", e.to_string()}; \
error_results results{400, "Bad Request", e}; \
cb(400, fc::json::to_string(results)); \
elog("Unable to parse arguments: ${args}", ("args", body)); \
} catch (fc::exception& e) { \
error_results results{500, "Internal Service Error", e.to_detail_string()}; \
error_results results{500, "Internal Service Error", e}; \
cb(500, fc::json::to_string(results)); \
elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \
} \
Expand Down
30 changes: 24 additions & 6 deletions programs/eosioc/help_text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "help_text.hpp"
#include "localize.hpp"
#include <regex>
#include <fc/io/json.hpp>

using namespace eosio::client::localize;

Expand Down Expand Up @@ -182,22 +183,25 @@ e.g.
}]
})=====";

const char* error_advice_3030002 = R"=====(Ensure that you have the related private keys inside your wallet)=====";

const std::map<int64_t, std::string> error_advice = {
{ 3120001, error_advice_3120001 },
{ 3120002, error_advice_3120002 },
{ 3120003, error_advice_3120003 },
{ 3120004, error_advice_3120004 },
{ 3120005, error_advice_3120005 },
{ 3120006, error_advice_3120006 }
{ 3120006, error_advice_3120006 },
{ 3030002, error_advice_3030002 }
};


namespace eosio { namespace client { namespace help {
bool print_recognized_error_code(const fc::exception& e) {
bool print_recognized_error_code(const fc::exception& e, const bool verbose_errors) {
// eos recognized error code is from 3000000 to 3999999
// refer to libraries/chain/include/eosio/chain/exceptions.hpp
if (e.code() >= 3000000 && e.code() <= 3999999) {
std::string advice, explanation;
std::string advice, explanation, stack_trace;

// Get advice, if any
const auto advice_itr = error_advice.find(e.code());
Expand All @@ -209,21 +213,35 @@ bool print_recognized_error_code(const fc::exception& e) {
if (!log.get_format().empty()) {
// Localize the message as needed
explanation += "\n " + localized_with_variant(log.get_format().data(), log.get_data());
} else if (log.get_data().size() > 0 && verbose_errors) {
// Show data-only log only if verbose_errors option is enabled
explanation += "\n " + fc::json::to_string(log.get_data());
}
// Check if there's stack trace to be added
if (!log.get_context().get_method().empty() && verbose_errors) {
stack_trace += "\n " +
log.get_context().get_file() + ":" +
fc::to_string(log.get_context().get_line_number()) + " " +
log.get_context().get_method();
}
}
// Append header
if (!explanation.empty()) explanation = std::string("Error Details:") + explanation;
if (!stack_trace.empty()) stack_trace = std::string("Stack Trace:") + stack_trace;

std::cerr << "\033[31m" << "Error " << e.code() << ": " << e.what() << "\033[0m";
if (!advice.empty()) std::cerr << "\n" << "\033[32m" << advice << "\033[0m";
if (!explanation.empty()) std::cerr << "\n" << "\033[33m" << explanation << "\033[0m" << std::endl;
if (!explanation.empty()) std::cerr << "\n" << "\033[33m" << explanation << "\033[0m";
if (!stack_trace.empty()) std::cerr << "\n" << stack_trace;
std::cerr << std::endl;
return true;
}
return false;
}

bool print_help_text(const fc::exception& e) {
bool print_help_text(const fc::exception& e, const bool verbose_errors) {
// Check if the exception has recognized error code
if (print_recognized_error_code(e)) return true;
if (print_recognized_error_code(e, verbose_errors)) return true;
bool result = false;
// Large input strings to std::regex can cause SIGSEGV, this is a known bug in libstdc++.
// See https://stackoverflow.com/questions/36304204/%D0%A1-regex-segfault-on-long-sequences
Expand Down
2 changes: 1 addition & 1 deletion programs/eosioc/help_text.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
#include <fc/exception/exception.hpp>

namespace eosio { namespace client { namespace help {
bool print_help_text(const fc::exception& e);
bool print_help_text(const fc::exception& e, const bool verbose_errors);
}}}
27 changes: 25 additions & 2 deletions programs/eosioc/httpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <fc/variant.hpp>
#include <fc/io/json.hpp>
#include <fc/exception/exception.hpp>
#include <eosio/http_plugin/http_plugin.hpp>
#include <eosio/chain_plugin/chain_plugin.hpp>

using boost::asio::ip::tcp;

Expand Down Expand Up @@ -106,13 +108,34 @@ fc::variant call( const std::string& server, uint16_t port,
throw boost::system::system_error(error);

// std::cout << re.str() <<"\n";
const auto response_result = fc::json::from_string(re.str());
if( status_code == 200 || status_code == 201 || status_code == 202 ) {
return fc::json::from_string(re.str());
return response_result;
} else {
auto &&error = response_result.as<eosio::error_results>().error;

// eos recognized error code is from 3000000 to 3999999
// refer to libraries/chain/include/eosio/chain/exceptions.hpp
if (error.code >= 3000000 && error.code <= 3999999) {
// Construct fc exception from error
const auto &stack_trace = error.stack_trace;
fc::exception new_exception(error.code, error.name, error.message);
if (stack_trace.empty()) {
new_exception.append_log(FC_LOG_MESSAGE(error, error.details));
} else {
for (auto itr = stack_trace.begin(); itr != stack_trace.end(); itr++) {
const auto &error_message = itr == stack_trace.begin() ? error.details : std::string();
new_exception.append_log(fc::log_message(*itr, error_message));
}
}
throw new_exception;
}
}

FC_ASSERT( status_code == 200, "Error code ${c}\n: ${msg}\n", ("c", status_code)("msg", re.str()) );
}

FC_ASSERT( !"unable to connect" );
} FC_CAPTURE_AND_RETHROW( (server)(port)(path)(postdata) )
} FC_RETHROW_EXCEPTIONS( error, "Request Path: ${server}:${port}${path}\n Request Post Data: ${postdata}}" ,
("server", server)("port", port)("path", path)("postdata", postdata) )
}
2 changes: 1 addition & 1 deletion programs/eosioc/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,7 @@ int main( int argc, char** argv ) {
}
} else {
// attempt to extract the error code if one is present
if (verbose_errors || !print_help_text(e)) {
if (!print_help_text(e, verbose_errors) && verbose_errors) {
elog("Failed with error: ${e}", ("e", verbose_errors ? e.to_detail_string() : e.to_string()));
}
}
Expand Down