diff --git a/programs/cleos/CMakeLists.txt b/programs/cleos/CMakeLists.txt index 0787c5fe937..c8ca67a1b9d 100644 --- a/programs/cleos/CMakeLists.txt +++ b/programs/cleos/CMakeLists.txt @@ -1,5 +1,5 @@ configure_file(help_text.cpp.in help_text.cpp @ONLY) -add_executable( ${CLI_CLIENT_EXECUTABLE_NAME} main.cpp httpc.cpp ${CMAKE_CURRENT_BINARY_DIR}/help_text.cpp localize.hpp config.hpp CLI11.hpp) +add_executable( ${CLI_CLIENT_EXECUTABLE_NAME} main.cpp httpc.cpp helpers.cpp ${CMAKE_CURRENT_BINARY_DIR}/help_text.cpp localize.hpp config.hpp CLI11.hpp) if( UNIX AND NOT APPLE ) set(rt_library rt ) endif() @@ -37,7 +37,7 @@ target_include_directories(${CLI_CLIENT_EXECUTABLE_NAME} PUBLIC ${Intl_INCLUDE_D target_link_libraries( ${CLI_CLIENT_EXECUTABLE_NAME} PRIVATE appbase chain_api_plugin producer_plugin chain_plugin http_plugin eosio_chain fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ${Intl_LIBRARIES} ) - + copy_bin( ${CLI_CLIENT_EXECUTABLE_NAME} ) install( TARGETS diff --git a/programs/cleos/helpers.cpp b/programs/cleos/helpers.cpp new file mode 100644 index 00000000000..4520e07a9d3 --- /dev/null +++ b/programs/cleos/helpers.cpp @@ -0,0 +1,26 @@ + +#include +#include "helpers.hpp" + +namespace eosio { namespace client { namespace helpers { + + std::string& url_encode(std::string& str) { + + char hex[17] = "0123456789ABCDEF"; + + for(int i = 0; i < str.length(); i++) { + + char ch = str[i]; + + if (!(isalnum(ch) || ch == '-' || ch == '_' || ch == '.' || ch == '~') ) { + std::string rep = "%"; + rep += hex[(ch & 0xF0) >> 4]; + rep += hex[ch & 0x0F]; + str.replace(i, 1, rep); + i += 2; + } + } + return str; + } + +}}} diff --git a/programs/cleos/helpers.hpp b/programs/cleos/helpers.hpp new file mode 100644 index 00000000000..8eccb287cb2 --- /dev/null +++ b/programs/cleos/helpers.hpp @@ -0,0 +1,13 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#pragma once + +#include + +namespace eosio { namespace client { namespace helpers { + + std::string& url_encode(std::string& str); + +}}} diff --git a/programs/cleos/httpc.cpp b/programs/cleos/httpc.cpp index 7d9326b9ed7..1016d8f8c29 100644 --- a/programs/cleos/httpc.cpp +++ b/programs/cleos/httpc.cpp @@ -184,6 +184,7 @@ namespace eosio { namespace client { namespace http { } fc::variant do_http_call( const connection_param& cp, + const string& method, const fc::variant& postdata, bool print_request, bool print_response ) { @@ -197,7 +198,7 @@ namespace eosio { namespace client { namespace http { boost::asio::streambuf request; std::ostream request_stream(&request); auto host_header_value = format_host_header(url); - request_stream << "POST " << url.path << " HTTP/1.0\r\n"; + request_stream << method << " " << url.path << " HTTP/1.0\r\n"; request_stream << "Host: " << host_header_value << "\r\n"; request_stream << "content-length: " << postjson.size() << "\r\n"; request_stream << "Accept: */*\r\n"; diff --git a/programs/cleos/httpc.hpp b/programs/cleos/httpc.hpp old mode 100644 new mode 100755 index f90e58046c4..25f084b8502 --- a/programs/cleos/httpc.hpp +++ b/programs/cleos/httpc.hpp @@ -78,6 +78,7 @@ namespace eosio { namespace client { namespace http { fc::variant do_http_call( const connection_param& cp, + const string& method = "GET", const fc::variant& postdata = fc::variant(), bool print_request = false, bool print_response = false); @@ -110,6 +111,19 @@ namespace eosio { namespace client { namespace http { const string get_key_accounts_func = history_func_base + "/get_key_accounts"; const string get_controlled_accounts_func = history_func_base + "/get_controlled_accounts"; + // v2 + const string get_voters_func = "/v2/state/get_voters"; + const string get_key_accounts_v2_func = "/v2/state/get_key_accounts"; + const string get_deltas_func = "/v2/history/get_deltas"; + const string get_creator_func = "/v2/history/get_creator"; + const string get_created_accounts_func = "/v2/history/get_created_accounts"; + const string get_transaction_v2_func = "/v2/history/get_transaction"; + const string get_transacted_accounts_func = "/v2/history/get_transacted_accounts"; + const string get_abi_snapshot_func = "/v2/history/get_abi_snapshot"; + const string get_root_actions_func = "/v2/history/get_actions"; + const string get_transfers_func = "/v2/history/get_transfers"; + const string get_tokens_func = "/v2/state/get_tokens"; + const string net_func_base = "/v1/net"; const string net_connect = net_func_base + "/connect"; const string net_disconnect = net_func_base + "/disconnect"; diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 59fc67679e6..b57c12cb33f 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -124,6 +124,7 @@ Usage: ./cleos create account [OPTIONS] creator name OwnerKey ActiveKey #include "help_text.hpp" #include "localize.hpp" #include "config.hpp" +#include "helpers.hpp" #include "httpc.hpp" using namespace std; @@ -133,6 +134,7 @@ using namespace eosio::client::help; using namespace eosio::client::http; using namespace eosio::client::localize; using namespace eosio::client::config; +using namespace eosio::client::helpers; using namespace boost::filesystem; using auth_type = fc::static_variant; @@ -183,6 +185,7 @@ bool print_request = false; bool print_response = false; bool no_auto_keosd = false; bool verbose = false; +bool legacy_api = false; // If old api should be used. hyperion is used per default where available uint8_t tx_max_cpu_usage = 0; uint32_t tx_max_net_usage = 0; @@ -245,10 +248,11 @@ vector get_account_permissions(const vector& pe template fc::variant call( const std::string& url, const std::string& path, - const T& v ) { + const T& v, + bool is_get = false) { try { auto sp = std::make_unique(context, parse_url(url) + path, no_verify ? false : true, headers); - return eosio::client::http::do_http_call(*sp, fc::variant(v), print_request, print_response ); + return eosio::client::http::do_http_call(*sp, is_get ? "GET" : "POST", fc::variant(v), print_request, print_response ); } catch(boost::system::system_error& e) { if(url == ::url) @@ -259,6 +263,7 @@ fc::variant call( const std::string& url, } } +fc::variant call( const std::string& path) { return call( url, path, fc::variant(), true ); } template fc::variant call( const std::string& path, const T& v ) { return call( url, path, fc::variant(v) ); } @@ -2315,6 +2320,500 @@ void get_account( const string& accountName, const string& coresym, bool json_fo } } +struct get_account_creator_subcommand { + bool print_as_json; + string name; + + get_account_creator_subcommand(CLI::App* app) { + + auto cmd = app->add_subcommand("creator", localized("Retrieve the creator of an account from the blockchain (v2)"), false); + cmd->add_option("name", name, localized("The name of the account"))->required(); + cmd->add_flag("-j,--json", print_as_json, localized("print result as json")); + cmd->set_callback([this] { + + fc::variant json = call(get_creator_func + "?account=" + name); + + if ( print_as_json ) { + std::cout << fc::json::to_pretty_string(json) << std::endl; + } else { + std::cout << std::endl; + if ( !json["creator"].is_null() ) { + std::cout << " Creator: " << json["creator"].as_string() << std::endl; + std::cout << " Date: " << json["timestamp"].as_string() << std::endl; + } else { + std::cout << "Could not find creator" << std::endl; + } + std::cout << std::endl; + } + + }); + } +}; + +struct get_created_accounts_subcommand { + bool print_as_json; + string account; + + get_created_accounts_subcommand(CLI::App* app) { + auto cmd = app->add_subcommand("accounts", localized("get created accounts (v2)"), false); + cmd->add_option("account", account, localized("the account to show created accounts for"))->required(); + cmd->add_flag("-j,--json", print_as_json, localized("print result as json")); + + cmd->set_callback([this] { + + auto res = call(get_created_accounts_func + "?account=" + account).get_object(); + + if ( print_as_json ) { + std::cout << fc::json::to_pretty_string(res) << std::endl; + } else if ( res.find("accounts") != res.end() ) { + for ( const auto& row : res["accounts"].get_array() ) { + const auto& obj = row.get_object(); + std::cout << "---------------------------------" << std::endl; + std::cout << " Account: " << obj["name"].as_string() << std::endl; + std::cout << " Date: " << obj["timestamp"].as_string() << std::endl; + } + std::cout << "---------------------------------" << std::endl; + } + }); + } +}; + +struct get_root_actions_subcommand { + bool print_as_json; + string account; + string filter; + uint64_t offset = 0; + uint64_t limit = 0; + string sort; + string after; + string before; + + get_root_actions_subcommand(CLI::App* app) { + auto cmd = app->add_subcommand("root_actions", localized("get root actions (v2)"), false); + cmd->add_option("offset", offset, localized("skip [n] actions (pagination)")); + cmd->add_option("limit", limit, localized("limit of [n] actions per page")); + cmd->add_option("-a,--account", account, localized("notified account")); + cmd->add_option("-f,--filter", filter, localized("code::name filter")); + cmd->add_option("-s,--sort", sort, localized("sort direction (asc,desc,1,-1)")); + cmd->add_option("--before", before, localized("filter before specified date (ISO8601 ex: \"2019-03-06T14:23:06+00:00\")")); + cmd->add_option("--after", after, localized("filter after specified date (ISO8601 ex: \"2019-03-06T14:23:06+00:00\")")); + cmd->add_flag("-j,--json", print_as_json, localized("print result as json")); + + cmd->set_callback([this] { + + // Build query string. + string params; + + if ( account.length() > 0 ) { + params += "&account=" + account; + } + + if ( filter.length() > 0 ) { + params += "&filter=" + filter; + } + + if ( sort.length() > 0 ) { + params += "&sort=" + sort; + } + + if ( offset > 0 ) { + params += "&offset=" + std::to_string(offset); + } + + if ( limit > 0 ) { + params += "&limit=" + std::to_string(limit); + } + + if ( before.length() > 0 ) { + + params += "&before=" + url_encode(before); + } + + if ( after.length() > 0 ) { + params += "&after=" + url_encode(after); + } + + if ( params.length() > 0 ) { + params[0] = '?'; + } + + auto res = call(get_root_actions_func + params).get_object(); + + if ( print_as_json ) { + std::cout << fc::json::to_pretty_string(res) << std::endl; + } else if ( res.find("actions") != res.end() ) { + for ( const auto& row : res["actions"].get_array() ) { + const auto& obj = row.get_object(); + std::cout << "--- Block: " << obj["block_num"].as_string() << std::endl; + std::cout << fc::json::to_pretty_string(row) << std::endl; + } + } + }); + } +}; + +struct get_abi_subcommand { + string name; + string filename; + uint64_t block = 0; + + get_abi_subcommand(CLI::App* app) { + auto cmd = app->add_subcommand("abi", localized("Retrieve the ABI for an account"), false); + cmd->add_option("name", name, localized("contract account"))->required(); + cmd->add_option("-f,--file",filename, localized("The name of the file to save the contract .abi to instead of writing to console") ); + cmd->add_option("block", block, localized("fetch abi at a specific block (v2)")); + + cmd->set_callback([this] { + + string abi; + + // v2 if block is defined. + if ( block > 0 ) { + + string url = get_abi_snapshot_func + + "?contract=" + name + + "&block=" + std::to_string(block); + + // Just print the raw abi data. + // TODO: right now, the api returns a error message in non-json format if the + // abi could not be found, i consider that as a bug in the api for now. + // handle the error better when the api works as intended. + auto result = call(url); + abi = fc::json::to_pretty_string(result); + } + // v1 + else { + auto result = call(get_abi_func, fc::mutable_variant_object("account_name", name)); + abi = fc::json::to_pretty_string( result["abi"] ); + } + + if( filename.size() ) { + std::cerr << localized("saving abi to ${filename}", ("filename", filename)) << std::endl; + std::ofstream abiout( filename.c_str() ); + abiout << abi; + } else { + std::cout << abi << "\n"; + } + }); + } +}; + +struct get_transfers_subcommand { + bool print_as_json; + string from; + string to; + string symbol; + string contract; + string after; + string before; + + get_transfers_subcommand(CLI::App* app) { + auto cmd = app->add_subcommand("transfers", localized("get token transfers (v2)"), false); + cmd->add_option("from", from, localized("source account"))->required(); + cmd->add_option("to", to, localized("destination account")); + cmd->add_option("--symbol", symbol, localized("token symbol")); + cmd->add_option("--contract", contract, localized("token contract")); + cmd->add_option("--before", before, localized("filter before specified date (ISO8601 ex: \"2019-03-06T14:23:06+00:00\")")); + cmd->add_option("--after", after, localized("filter after specified date (ISO8601 ex: \"2019-03-06T14:23:06+00:00\")")); + cmd->add_flag("-j,--json", print_as_json, localized("print result as json")); + + cmd->set_callback([this] { + + // Build query string. + string params = "?from=" + from; + + if ( to.length() > 0 ) { + params += "&to=" + to; + } + + if ( symbol.length() > 0 ) { + params += "&symbol=" + symbol; + } + + if ( contract.length() > 0 ) { + params += "&contract=" + contract; + } + + if ( before.length() > 0 ) { + params += "&before=" + url_encode(before); + } + + if ( after.length() > 0 ) { + params += "&after=" + url_encode(after); + } + + auto res = call(get_transfers_func + params).get_object(); + + if ( print_as_json ) { + std::cout << fc::json::to_pretty_string(res) << std::endl; + } else { + for( auto& row : res["actions"].get_array() ) { + const auto& obj = row.get_object(); + + std::cout << obj["trx_id"].as_string() + << " - " << obj["@timestamp"].as_string() + << std::endl + << fc::json::to_pretty_string(obj["act"]) + << std::endl + << std::endl; + } + } + }); + } +}; + +static void print_transacted_accounts_table(string prefix, const fc::variants& table, const fc::variant& total) { + + std::cout << prefix << std::endl; + std::cout << "+---------------+------------+----------------------+----------------------+" << std::endl; + std::cout << "| Account | Transfers | Sum | Average |" << std::endl; + std::cout << "+---------------+------------+----------------------+----------------------+" << std::endl; + if ( !table.empty() ) { + for ( auto& row : table ) { + const auto& obj = row.get_object(); + + printf("| %-13.13s | %10li | %-20.4f | %-20.4f |\n", + obj["account"].as_string().c_str(), + obj["transfers"].as_int64(), + obj["sum"].as_double(), + obj["average"].as_double()); + } + } else { + std::cout << "| - | - | - | - |" << std::endl; + } + + std::cout << "+---------------+------------+----------------------+----------------------+" << std::endl; + std::cout << "Total: " << total.as_string() << std::endl; + + std::cout << std::endl; +} + +struct get_transacted_accounts_subcommand { + bool print_as_json; + string account; + string contract; + string symbol; + uint16_t min = 0; + uint16_t max = 1000; + uint16_t limit = 30; + string direction = "both"; + + get_transacted_accounts_subcommand(CLI::App* app) { + auto cmd = app->add_subcommand("accounts", localized("get all account that interacted with the source account provided (v2)"), false); + cmd->add_option("account", account, localized("source account"))->required(); + cmd->add_option("min", min, localized("minimum value")); + cmd->add_option("max", max, localized("maximum value")); + cmd->add_option("limit", limit, localized("query limit")); + cmd->add_option("direction", direction, localized("search direction (Allowed values: in, out, both)")); + cmd->add_option("-c,--contract", contract, localized("token contract")); + cmd->add_option("-s,--symbol", symbol, localized("token symbol")); + cmd->add_flag("-j,--json", print_as_json, localized("print result as json")); + + cmd->set_callback([this] { + + string url = get_transacted_accounts_func + + "?account=" + account + + "&min=" + std::to_string(min) + + "&max=" + std::to_string(max) + + "&limit=" + std::to_string(limit) + + "&direction=" + direction; + + if (contract.length() > 0) { + url += "&contract=" + contract; + } + + if (symbol.length() > 0) { + url += "&symbol=" + symbol; + } + + auto res = call(url).get_object(); + + if ( print_as_json ) { + std::cout << fc::json::to_pretty_string(res) << std::endl; + } else { + std::cout << std::endl; + std::cout << "Showing transacted accounts for acccount: " + res["account"].as_string(); + if ( res.find("contract") != res.end() ) { + std::cout << ", contract: " << res["contract"].as_string(); + } + if ( res.find("symbol") != res.end() ) { + std::cout << ", symbol: " << res["symbol"].as_string(); + } + std::cout << std::endl << std::endl; + + if ( res.find("inputs") != res.end() ) { + print_transacted_accounts_table("Inputs", res["inputs"].get_array(), res["total_in"]); + } + + if ( res.find("outputs") != res.end() ) { + print_transacted_accounts_table("Outputs", res["outputs"].get_array(), res["total_out"]); + } + + std::cout << std::endl; + } + }); + } +}; + +struct get_deltas_subcommand { + bool print_as_json; + string code; + string scope; + string table; + string payer; + + get_deltas_subcommand(CLI::App* app) { + auto cmd = app->add_subcommand("deltas", localized("Get state deltas (v2)"), false); + cmd->add_option("code", code, localized("Contract account"))->required(); + cmd->add_option("-s,--scope", scope, localized("table scope")); + cmd->add_option("-t,--table", table, localized("table name")); + cmd->add_option("-p,--payer", payer, localized("payer")); + cmd->add_flag("-j,--json", print_as_json, localized("print result as json")); + + cmd->set_callback([this] { + + string url = get_deltas_func + + "?code=" + code; + + if (scope.length() > 0) { + url += "&scope=" + scope; + } + + if (table.length() > 0) { + url += "&table=" + table; + } + + if (payer.length() > 0) { + url += "&payer=" + payer; + } + + auto res = call(url).get_object(); + + if ( print_as_json ) { + std::cout << fc::json::to_pretty_string(res) << std::endl; + } else { + for( auto& row : res["deltas"].get_array() ) { + const auto& obj = row.get_object(); + + std::cout << "-------------------" << std::endl; + std::cout << " Block: " << obj["block_num"].as_string() << std::endl; + std::cout << " Primary Key: " << obj["primary_key"].as_string() << std::endl; + std::cout << " Scope: " << obj["scope"].as_string() << std::endl; + std::cout << " Table: " << obj["table"].as_string() << std::endl; + std::cout << " Payer: " << obj["payer"].as_string() << std::endl; + } + + std::cout << "-------------------" << std::endl; + } + }); + } +}; + +struct get_tokens_subcommand { + bool print_as_json; + string account; + + get_tokens_subcommand(CLI::App* app) { + auto cmd = app->add_subcommand("tokens", localized("Get tokens from account (v2)"), false); + cmd->add_option("account", account, localized("Account"))->required(); + cmd->add_flag("-j,--json", print_as_json, localized("print result as json")); + + cmd->set_callback([this] { + + string url = get_tokens_func + "?account=" + account; + + auto res = call(url).get_object(); + + if ( print_as_json ) { + std::cout << fc::json::to_pretty_string(res) << std::endl; + } else { + for( auto& row : res["tokens"].get_array() ) { + const auto& obj = row.get_object(); + + std::cout << " " << obj["amount"].as_string() + << " " << obj["symbol"].as_string() << std::endl; + }; + } + }); + } +}; + +static void print_voters_table(const fc::variants& table) { + + std::cout << "+---------------+------------------------+-----------+" << std::endl; + std::cout << "| Account | Weight | Last Vote |" << std::endl; + std::cout << "+---------------+------------------------+-----------+" << std::endl; + if ( !table.empty() ) { + for ( auto& row : table ) { + const auto& obj = row.get_object(); + + printf("| %-13.13s | %-22.4f | %9li |\n", + obj["account"].as_string().c_str(), + obj["weight"].as_double(), + obj["last_vote"].as_int64()); + } + } else { + std::cout << "| | - | - |" << std::endl; + } + + std::cout << "+---------------+------------------------+-----------+" << std::endl; + std::cout << std::endl; +} + +struct get_voters_subcommand { + bool print_as_json; + string producer; + uint16_t skip = 0; + uint16_t limit = 0; + + get_voters_subcommand(CLI::App* app) { + auto cmd =app->add_subcommand("voters", localized("Retrieve voters for an producer"), false); + cmd->add_option("producer", producer, localized("filter by voted producer (comma separated)")); + cmd->add_option("skip", skip, localized("skip [n] actions (pagination)")); + cmd->add_option("limit", limit, localized("limit of [n] actions per page")); + cmd->add_flag("-j,--json", print_as_json, localized("print result as json")); + + cmd->set_callback([this] { + + string url = get_voters_func; + string params; + + if ( producer.length() > 0 ) { + params += "&producer=" + producer; + } + + if ( skip > 0 ) { + params += "&skip=" + std::to_string(skip); + } + + if ( limit > 0 ) { + params += "&limit=" + std::to_string(limit); + } + + if ( params.length() > 0 ) { + params[0] = '?'; + } + + auto res = call(url + params).get_object(); + + if ( print_as_json ) { + std::cout << fc::json::to_pretty_string(res) << std::endl; + } else { + print_voters_table(res["voters"].get_array()); + /* + for( auto& row : res["voters"].get_array() ) { + const auto& obj = row.get_object(); + + std::cout << obj["account"].as_string() + << "\t" << obj["weight"].as_string() + << "\t" << obj["last_vote"].as_string() + << std::endl; + } */ + } + }); + } +}; + CLI::callback_t header_opt_callback = [](CLI::results_t res) { vector::iterator itr; @@ -2347,6 +2846,7 @@ int main( int argc, char** argv ) { app.add_flag( "--no-auto-" + string(key_store_executable_name), no_auto_keosd, localized("don't automatically launch a ${k} if one is not currently running", ("k", key_store_executable_name))); app.set_callback([&app]{ ensure_keosd_running(&app);}); + app.add_flag( "--legacy-api", legacy_api, localized("If old api should be used, per default hyperion is used where available.")); app.add_flag( "-v,--verbose", verbose, localized("output verbose errors and action console output")); app.add_flag("--print-request", print_request, localized("print HTTP request to STDERR")); app.add_flag("--print-response", print_response, localized("print HTTP response to STDERR")); @@ -2509,6 +3009,24 @@ int main( int argc, char** argv ) { getAccount->add_flag("--json,-j", print_json, localized("Output in JSON format") ); getAccount->set_callback([&]() { get_account(accountName, coresym, print_json); }); + // get creator + auto getCreator = get_account_creator_subcommand(get); + + // get created accounts + auto created = get->add_subcommand("created", "", false); + created->require_subcommand(); + auto getCreatedAccounts = get_created_accounts_subcommand(created); + + // get transacted accounts + auto transacted = get->add_subcommand("transacted", "", false); + transacted->require_subcommand(); + auto getTransactedAccounts = get_transacted_accounts_subcommand(transacted); + + // get deltas + auto getDeltas = get_deltas_subcommand(get); + + auto getTokens = get_tokens_subcommand(get); + // get code string codeFilename; string abiFilename; @@ -2570,22 +3088,7 @@ int main( int argc, char** argv ) { }); // get abi - string filename; - auto getAbi = get->add_subcommand("abi", localized("Retrieve the ABI for an account"), false); - getAbi->add_option("name", accountName, localized("The name of the account whose abi should be retrieved"))->required(); - getAbi->add_option("-f,--file",filename, localized("The name of the file to save the contract .abi to instead of writing to console") ); - getAbi->set_callback([&] { - auto result = call(get_abi_func, fc::mutable_variant_object("account_name", accountName)); - - auto abi = fc::json::to_pretty_string( result["abi"] ); - if( filename.size() ) { - std::cerr << localized("saving abi to ${filename}", ("filename", filename)) << std::endl; - std::ofstream abiout( filename.c_str() ); - abiout << abi; - } else { - std::cout << abi << "\n"; - } - }); + auto getAbi = get_abi_subcommand(get); // get table string scope; @@ -2707,10 +3210,18 @@ int main( int argc, char** argv ) { try { public_key = public_key_type(public_key_str); } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid public key: ${public_key}", ("public_key", public_key_str)) - auto arg = fc::mutable_variant_object( "public_key", public_key); - std::cout << fc::json::to_pretty_string(call(get_key_accounts_func, arg)) << std::endl; + + if ( legacy_api ) { + auto arg = fc::mutable_variant_object( "public_key", public_key); + std::cout << fc::json::to_pretty_string(call(get_key_accounts_func, arg)) << std::endl; + } else { + auto res = call(get_key_accounts_v2_func + "?public_key=" + public_key_str); + std::cout << fc::json::to_pretty_string(res) << std::endl; + } }); + // get voters + auto getVoters = get_voters_subcommand(get); // get servants string controllingAccount; @@ -2728,13 +3239,21 @@ int main( int argc, char** argv ) { getTransaction->add_option("id", transaction_id_str, localized("ID of the transaction to retrieve"))->required(); getTransaction->add_option( "-b,--block-hint", block_num_hint, localized("the block number this transaction may be in") ); getTransaction->set_callback([&] { - auto arg= fc::mutable_variant_object( "id", transaction_id_str); - if ( block_num_hint > 0 ) { - arg = arg("block_num_hint", block_num_hint); - } - std::cout << fc::json::to_pretty_string(call(get_transaction_func, arg)) << std::endl; + + if ( legacy_api ) { + auto arg= fc::mutable_variant_object( "id", transaction_id_str); + if ( block_num_hint > 0 ) { + arg = arg("block_num_hint", block_num_hint); + } + std::cout << fc::json::to_pretty_string(call(get_transaction_func, arg)) << std::endl; + } else { + std::cout << fc::json::to_pretty_string(call(get_transaction_v2_func + "?id=" + transaction_id_str)) << std::endl; + } }); + // get transfers + auto getTransfers = get_transfers_subcommand(get); + // get actions string account_name; string skip_seq_str; @@ -2831,6 +3350,9 @@ int main( int argc, char** argv ) { } }); + // get root actions + auto getRootActions = get_root_actions_subcommand(get); + auto getSchedule = get_schedule_subcommand{get}; auto getTransactionId = get_transaction_id_subcommand{get};