2211void get_account(
const string& accountName,
const string& coresym,
bool json_format ) {
2213 if (coresym.empty()) {
2225 if( res.core_liquid_balance ) {
2226 unstaking =
asset( 0, res.core_liquid_balance->get_symbol() );
2227 staked =
asset( 0, res.core_liquid_balance->get_symbol() );
2230 std::cout <<
"created: " <<
string(res.created) << std::endl;
2232 if(res.privileged) std::cout <<
"privileged: true" << std::endl;
2234 constexpr size_t indent_size = 5;
2235 const string indent(indent_size,
' ');
2237 std::cout <<
"permissions: " << std::endl;
2238 unordered_map<name, vector<name>> tree;
2240 unordered_map<name, sysio::chain_apis::permission> cache;
2241 for (
auto& perm : res.permissions ) {
2242 if ( perm.parent ) {
2243 tree[perm.parent].push_back( perm.perm_name );
2245 roots.push_back( perm.perm_name );
2247 auto name = perm.perm_name;
2249 cache.insert( std::make_pair(
name, std::move(perm)) );
2254 auto&
p = cache.at(
name);
2257 auto it = tree.find(
name );
2258 if (it != tree.end()) {
2259 auto& children = it->second;
2260 sort( children.begin(), children.end() );
2261 for (
auto& n : children ) {
2263 dfs_exec( n, depth+1,
f );
2269 std::cout << indent << std::string(depth*3,
' ') <<
p.perm_name <<
' ' << std::setw(5) <<
p.required_auth.threshold <<
": ";
2271 const char *sep =
"";
2272 for (
auto it =
p.required_auth.keys.begin(); it !=
p.required_auth.keys.end(); ++it ) {
2273 std::cout << sep << it->weight <<
' ' << it->key.to_string();
2276 for (
auto& acc :
p.required_auth.accounts ) {
2277 std::cout << sep << acc.weight <<
' ' << acc.permission.actor.to_string() <<
'@' << acc.permission.permission.to_string();
2280 std::cout << std::endl;
2282 std::sort(roots.begin(), roots.end());
2283 for (
auto r : roots ) {
2284 dfs_exec(
r, 0, print_auth );
2286 std::cout << std::endl;
2288 std::cout <<
"permission links: " << std::endl;
2290 if (
p.linked_actions) {
2291 if (!
p.linked_actions->empty()) {
2292 std::cout << indent <<
p.perm_name.to_string() +
":" << std::endl;
2293 for (
auto it =
p.linked_actions->begin(); it !=
p.linked_actions->end(); ++it ) {
2294 auto action_value = it->action ? it->action->to_string() : std::string(
"*");
2295 std::cout << indent << indent << it->account <<
"::" << action_value << std::endl;
2301 for (
auto r : roots ) {
2302 dfs_exec(
r, 0, print_links);
2306 std::cout << indent <<
"sysio.any: " << std::endl;
2307 for (
const auto& it : res.sysio_any_linked_actions) {
2308 auto action_value = it.action ? it.action->to_string() : std::string(
"*");
2309 std::cout << indent << indent << it.account <<
"::" << action_value << std::endl;
2312 std::cout << std::endl;
2314 auto to_pretty_net = [](
int64_t nbytes,
uint8_t width_for_units = 5 ) {
2317 return std::string(
"unlimited");
2320 string unit =
"bytes";
2321 double bytes =
static_cast<double> (nbytes);
2322 if (
bytes >= 1024 * 1024 * 1024 * 1024ll) {
2324 bytes /= 1024 * 1024 * 1024 * 1024ll;
2325 }
else if (
bytes >= 1024 * 1024 * 1024) {
2327 bytes /= 1024 * 1024 * 1024;
2328 }
else if (
bytes >= 1024 * 1024) {
2330 bytes /= 1024 * 1024;
2331 }
else if (
bytes >= 1024) {
2335 std::stringstream ss;
2336 ss << setprecision(4);
2338 if( width_for_units > 0 )
2339 ss << std::left << setw( width_for_units );
2346 std::cout <<
"memory: " << std::endl
2347 << indent <<
"quota: " << std::setw(15) << to_pretty_net(res.ram_quota) <<
" used: " << std::setw(15) << to_pretty_net(res.ram_usage) << std::endl << std::endl;
2349 std::cout <<
"net bandwidth: " << std::endl;
2350 if ( res.total_resources.is_object() ) {
2351 auto net_total =
to_asset(res.total_resources.get_object()[
"net_weight"].as_string());
2353 if( net_total.get_symbol() != unstaking.
get_symbol() ) {
2355 unstaking =
asset( 0, net_total.get_symbol() );
2356 staked =
asset( 0, net_total.get_symbol() );
2359 if( res.self_delegated_bandwidth.is_object() ) {
2363 auto net_others = net_total - net_own;
2365 std::cout << indent <<
"staked:" << std::setw(20) << net_own
2366 << std::string(11,
' ') <<
"(total stake delegated from account to self)" << std::endl
2367 << indent <<
"delegated:" << std::setw(17) << net_others
2368 << std::string(11,
' ') <<
"(total staked delegated to account from others)" << std::endl;
2371 auto net_others = net_total;
2372 std::cout << indent <<
"delegated:" << std::setw(17) << net_others
2373 << std::string(11,
' ') <<
"(total staked delegated to account from others)" << std::endl;
2378 auto to_pretty_time = [](
int64_t nmicro,
uint8_t width_for_units = 5 ) {
2381 return std::string(
"unlimited");
2384 double micro =
static_cast<double>(nmicro);
2386 if( micro > 1000000*60*60ll ) {
2387 micro /= 1000000*60*60ll;
2390 else if( micro > 1000000*60 ) {
2391 micro /= 1000000*60;
2394 else if( micro > 1000000 ) {
2398 else if( micro > 1000 ) {
2402 std::stringstream ss;
2403 ss << setprecision(4);
2405 if( width_for_units > 0 )
2406 ss << std::left << setw( width_for_units );
2412 std::cout << std::fixed << setprecision(3);
2413 std::cout << indent << std::left << std::setw(11) <<
"used:" << std::right << std::setw(18) << to_pretty_net( res.net_limit.used ) <<
"\n";
2414 std::cout << indent << std::left << std::setw(11) <<
"available:" << std::right << std::setw(18) << to_pretty_net( res.net_limit.available ) <<
"\n";
2415 std::cout << indent << std::left << std::setw(11) <<
"limit:" << std::right << std::setw(18) << to_pretty_net( res.net_limit.max ) <<
"\n";
2416 std::cout << std::endl;
2418 std::cout <<
"cpu bandwidth:" << std::endl;
2420 if ( res.total_resources.is_object() ) {
2421 auto cpu_total =
to_asset(res.total_resources.get_object()[
"cpu_weight"].as_string());
2423 if( res.self_delegated_bandwidth.is_object() ) {
2427 auto cpu_others = cpu_total - cpu_own;
2429 std::cout << indent <<
"staked:" << std::setw(20) << cpu_own
2430 << std::string(11,
' ') <<
"(total stake delegated from account to self)" << std::endl
2431 << indent <<
"delegated:" << std::setw(17) << cpu_others
2432 << std::string(11,
' ') <<
"(total staked delegated to account from others)" << std::endl;
2434 auto cpu_others = cpu_total;
2435 std::cout << indent <<
"delegated:" << std::setw(17) << cpu_others
2436 << std::string(11,
' ') <<
"(total staked delegated to account from others)" << std::endl;
2440 std::cout << std::fixed << setprecision(3);
2441 std::cout << indent << std::left << std::setw(11) <<
"used:" << std::right << std::setw(18) << to_pretty_time( res.cpu_limit.used ) <<
"\n";
2442 std::cout << indent << std::left << std::setw(11) <<
"available:" << std::right << std::setw(18) << to_pretty_time( res.cpu_limit.available ) <<
"\n";
2443 std::cout << indent << std::left << std::setw(11) <<
"limit:" << std::right << std::setw(18) << to_pretty_time( res.cpu_limit.max ) <<
"\n";
2444 std::cout << std::endl;
2446 if( res.subjective_cpu_bill_limit ) {
2447 std::cout <<
"subjective cpu bandwidth:" << std::endl;
2448 std::cout << indent << std::left << std::setw(11) <<
"used:" << std::right << std::setw(18) << to_pretty_time( (res.subjective_cpu_bill_limit)->used ) <<
"\n";
2449 std::cout << std::endl;
2452 if( res.refund_request.is_object() ) {
2453 auto obj = res.refund_request.get_object();
2456 auto now = res.head_block_time;
2459 unstaking = net + cpu;
2462 std::cout << std::fixed << setprecision(3);
2463 std::cout <<
"unstaking tokens:" << std::endl;
2464 std::cout << indent << std::left << std::setw(25) <<
"time of unstake request:" << std::right << std::setw(20) <<
string(request_time);
2465 if( now >= refund_time ) {
2466 std::cout <<
" (available to claim now with 'sysio::refund' action)\n";
2468 std::cout <<
" (funds will be available in " << to_pretty_time( (refund_time - now).
count(), 0 ) <<
")\n";
2470 std::cout << indent << std::left << std::setw(25) <<
"from net bandwidth:" << std::right << std::setw(18) << net << std::endl;
2471 std::cout << indent << std::left << std::setw(25) <<
"from cpu bandwidth:" << std::right << std::setw(18) << cpu << std::endl;
2472 std::cout << indent << std::left << std::setw(25) <<
"total:" << std::right << std::setw(18) << unstaking << std::endl;
2473 std::cout << std::endl;
2477 if( res.core_liquid_balance ) {
2478 std::cout << res.core_liquid_balance->get_symbol().name() <<
" balances: " << std::endl;
2479 std::cout << indent << std::left << std::setw(11)
2480 <<
"liquid:" << std::right << std::setw(18) << *res.core_liquid_balance << std::endl;
2481 std::cout << indent << std::left << std::setw(11)
2482 <<
"staked:" << std::right << std::setw(18) << staked << std::endl;
2483 std::cout << indent << std::left << std::setw(11)
2484 <<
"unstaking:" << std::right << std::setw(18) << unstaking << std::endl;
2485 std::cout << indent << std::left << std::setw(11) <<
"total:" << std::right << std::setw(18) << (*res.core_liquid_balance + staked + unstaking) << std::endl;
2486 std::cout << std::endl;
2489 if( res.rex_info.is_object() ) {
2490 auto& obj = res.rex_info.get_object();
2493 std::cout << rex_balance.
get_symbol().
name() <<
" balances: " << std::endl;
2494 std::cout << indent << std::left << std::setw(11)
2495 <<
"balance:" << std::right << std::setw(18) << rex_balance << std::endl;
2496 std::cout << indent << std::left << std::setw(11)
2497 <<
"staked:" << std::right << std::setw(18) << vote_stake << std::endl;
2498 std::cout << std::endl;
2501 if ( res.voter_info.is_object() ) {
2502 auto& obj = res.voter_info.get_object();
2503 string proxy = obj[
"proxy"].as_string();
2504 if ( proxy.empty() ) {
2505 auto& prods = obj[
"producers"].get_array();
2506 std::cout <<
"producers:";
2507 if ( !prods.empty() ) {
2508 for (
size_t i = 0; i < prods.size(); ++i ) {
2510 std::cout << std::endl << indent;
2512 std::cout << std::setw(16) << std::left << prods[i].as_string();
2514 std::cout << std::endl;
2516 std::cout << indent <<
"<not voted>" << std::endl;
2519 std::cout <<
"proxy:" << indent << proxy << std::endl;
2522 std::cout << std::endl;
2543 CLI::App app{
"Command Line Interface to SYSIO Client"};
2544 app.require_subcommand();
2551 app.add_option(
"-u,--url",
url,
localized(
"The http/https URL where ${n} is running", (
"n", node_executable_name)),
true );
2552 app.add_option(
"--wallet-url",
wallet_url,
localized(
"The http/https URL where ${k} is running", (
"k", key_store_executable_name)),
true );
2555 app.add_flag(
"-n,--no-verify",
no_verify,
localized(
"Don't verify peer certificate when using HTTPS"));
2556 app.add_flag(
"--no-auto-" +
string(key_store_executable_name),
no_auto_kiod,
localized(
"Don't automatically launch a ${k} if one is not currently running", (
"k", key_store_executable_name)));
2559 app.add_flag(
"-v,--verbose", verbose,
localized(
"Output verbose errors and action console output"));
2563 auto version =
app.add_subcommand(
"version",
localized(
"Retrieve version information"));
2564 version->require_subcommand();
2566 version->add_subcommand(
"client",
localized(
"Retrieve basic version information of the client"))->callback([] {
2570 version->add_subcommand(
"full",
localized(
"Retrieve full version information of the client"))->callback([] {
2575 auto create =
app.add_subcommand(
"create",
localized(
"Create various items, on and off the blockchain"));
2576 create->require_subcommand();
2580 bool print_console =
false;
2582 auto create_key = create->add_subcommand(
"key",
localized(
"Create a new keypair and print the public and private keys"))->callback( [&r1, &key_file, &print_console](){
2583 if (key_file.empty() && !print_console) {
2584 std::cerr <<
"ERROR: Either indicate a file using \"--file\" or pass \"--to-console\"" << std::endl;
2589 auto privs = pk.to_string();
2590 auto pubs = pk.get_public_key().to_string();
2591 if (print_console) {
2592 std::cout <<
localized(
"Private key: ${key}", (
"key", privs) ) << std::endl;
2593 std::cout <<
localized(
"Public key: ${key}", (
"key", pubs ) ) << std::endl;
2595 std::cerr <<
localized(
"saving keys to ${filename}", (
"filename", key_file)) << std::endl;
2596 std::ofstream out( key_file.c_str() );
2597 out <<
localized(
"Private key: ${key}", (
"key", privs) ) << std::endl;
2598 out <<
localized(
"Public key: ${key}", (
"key", pubs ) ) << std::endl;
2601 create_key->add_flag(
"--r1", r1,
"Generate a key using the R1 curve (iPhone), instead of the K1 curve (Bitcoin)" );
2602 create_key->add_option(
"-f,--file", key_file,
localized(
"Name of file to write private/public key output to. (Must be set, unless \"--to-console\" is passed"));
2603 create_key->add_flag(
"--to-console", print_console,
localized(
"Print private/public keys to console."));
2609 auto convert =
app.add_subcommand(
"convert",
localized(
"Pack and unpack transactions"));
2610 convert->require_subcommand();
2613 string plain_signed_transaction_json;
2614 bool pack_action_data_flag =
false;
2615 auto pack_transaction = convert->add_subcommand(
"pack_transaction",
localized(
"From plain signed JSON to packed form"));
2616 pack_transaction->add_option(
"transaction", plain_signed_transaction_json,
localized(
"The plain signed JSON (string)"))->required();
2617 pack_transaction->add_flag(
"--pack-action-data", pack_action_data_flag,
localized(
"Pack all action data within transaction, needs interaction with ${n}", (
"n", node_executable_name)));
2618 pack_transaction->callback([&] {
2620 if( pack_action_data_flag ) {
2631 }
SYS_RETHROW_EXCEPTIONS( transaction_type_exception,
"Fail to convert transaction, --pack-action-data likely needed" )
2636 string packed_transaction_json;
2637 bool unpack_action_data_flag =
false;
2638 auto unpack_transaction = convert->add_subcommand(
"unpack_transaction",
localized(
"From packed to plain signed JSON form"));
2639 unpack_transaction->add_option(
"transaction", packed_transaction_json,
localized(
"The packed transaction JSON (string containing packed_trx and optionally compression fields)"))->required();
2640 unpack_transaction->add_flag(
"--unpack-action-data", unpack_action_data_flag,
localized(
"Unpack all action data within transaction, needs interaction with ${n}", (
"n", node_executable_name)));
2641 unpack_transaction->callback([&] {
2650 if( unpack_action_data_flag ) {
2659 string unpacked_action_data_account_string;
2660 string unpacked_action_data_name_string;
2661 string unpacked_action_data_string;
2662 auto pack_action_data = convert->add_subcommand(
"pack_action_data",
localized(
"From JSON action data to packed form"));
2663 pack_action_data->add_option(
"account", unpacked_action_data_account_string,
localized(
"The name of the account hosting the contract"))->required();
2664 pack_action_data->add_option(
"name", unpacked_action_data_name_string,
localized(
"The name of the function called by this action"))->required();
2665 pack_action_data->add_option(
"unpacked_action_data", unpacked_action_data_string,
localized(
"The action data expressed as JSON"))->required();
2666 pack_action_data->callback([&] {
2668 bytes packed_action_data_string;
2670 packed_action_data_string =
variant_to_bin(
name(unpacked_action_data_account_string),
name(unpacked_action_data_name_string), unpacked_action_data_json);
2672 std::cout <<
fc::to_hex(packed_action_data_string.data(), packed_action_data_string.size()) << std::endl;
2676 string packed_action_data_account_string;
2677 string packed_action_data_name_string;
2678 string packed_action_data_string;
2679 auto unpack_action_data = convert->add_subcommand(
"unpack_action_data",
localized(
"From packed to JSON action data form"));
2680 unpack_action_data->add_option(
"account", packed_action_data_account_string,
localized(
"The name of the account that hosts the contract"))->required();
2681 unpack_action_data->add_option(
"name", packed_action_data_name_string,
localized(
"The name of the function that's called by this action"))->required();
2682 unpack_action_data->add_option(
"packed_action_data", packed_action_data_string,
localized(
"The action data expressed as packed hex string"))->required();
2683 unpack_action_data->callback([&] {
2684 SYS_ASSERT( packed_action_data_string.size() >= 2, transaction_type_exception,
"No packed_action_data found" );
2685 vector<char> packed_action_data_blob(packed_action_data_string.size()/2);
2686 fc::from_hex(packed_action_data_string, packed_action_data_blob.data(), packed_action_data_blob.size());
2692 auto get =
app.add_subcommand(
"get",
localized(
"Retrieve various items and information from the blockchain"));
2693 get->require_subcommand();
2696 get->add_subcommand(
"info",
localized(
"Get current blockchain information"))->callback([] {
2701 string status_transaction_id;
2702 auto getTransactionStatus = get->add_subcommand(
"transaction-status",
localized(
"Get transaction status information"));
2703 getTransactionStatus->add_option(
"id", status_transaction_id,
localized(
"ID of the transaction to retrieve"))->required();
2704 getTransactionStatus->callback([&status_transaction_id] {
2708 std::cerr <<
"Unable to convert " << status_transaction_id <<
" to transaction id." << std::endl;
2717 bool get_bhs =
false;
2718 bool get_binfo =
false;
2719 auto getBlock = get->add_subcommand(
"block",
localized(
"Retrieve a full block from the blockchain"));
2720 getBlock->add_option(
"block", blockArg,
localized(
"The number or ID of the block to retrieve"))->required();
2721 getBlock->add_flag(
"--header-state", get_bhs,
localized(
"Get block header state from fork database instead") );
2722 getBlock->add_flag(
"--info", get_binfo,
localized(
"Get block info from the blockchain by block num only") );
2723 getBlock->callback([&blockArg, &get_bhs, &get_binfo] {
2724 SYSC_ASSERT( !(get_bhs && get_binfo),
"ERROR: Either --header-state or --info can be set" );
2726 std::optional<int64_t> block_num;
2732 SYSC_ASSERT( block_num.has_value() && (*block_num > 0),
"Invalid block num: ${block_num}", (
"block_num", blockArg) );
2748 bool print_json =
false;
2749 auto getAccount = get->add_subcommand(
"account",
localized(
"Retrieve an account from the blockchain"));
2750 getAccount->add_option(
"name", accountName,
localized(
"The name of the account to retrieve"))->required();
2751 getAccount->add_option(
"core-symbol", coresym,
localized(
"The expected core symbol of the chain you are querying"));
2752 getAccount->add_flag(
"--json,-j", print_json,
localized(
"Output in JSON format") );
2753 getAccount->callback([&]() {
get_account(accountName, coresym, print_json); });
2756 string codeFilename;
2758 bool code_as_wasm =
true;
2759 auto getCode = get->add_subcommand(
"code",
localized(
"Retrieve the code and ABI for an account"));
2760 getCode->add_option(
"name", accountName,
localized(
"The name of the account whose code should be retrieved"))->required();
2761 getCode->add_option(
"-c,--code",codeFilename,
localized(
"The name of the file to save the contract wasm to") );
2762 getCode->add_option(
"-a,--abi",abiFilename,
localized(
"The name of the file to save the contract .abi to") );
2763 getCode->add_flag(
"--wasm", code_as_wasm,
localized(
"Save contract as wasm (ignored, default)"));
2764 getCode->callback([&] {
2765 string code_hash, wasm, abi;
2768 const std::vector<char> wasm_v = result[
"wasm"].as_blob().data;
2769 const std::vector<char> abi_v = result[
"abi"].as_blob().data;
2774 code_hash = (
string)hash;
2776 wasm =
string(wasm_v.begin(), wasm_v.end());
2782 catch(chain::missing_chain_api_plugin_exception&) {
2785 code_hash = old_result[
"code_hash"].as_string();
2786 wasm = old_result[
"wasm"].as_string();
2787 std::cout <<
localized(
"Warning: communicating to older ${n} which returns malformed binary wasm", (
"n", node_executable_name)) << std::endl;
2791 std::cout <<
localized(
"code hash: ${code_hash}", (
"code_hash", code_hash)) << std::endl;
2793 if( codeFilename.size() ){
2794 std::cout <<
localized(
"saving wasm to ${codeFilename}", (
"codeFilename", codeFilename)) << std::endl;
2796 std::ofstream out( codeFilename.c_str() );
2799 if( abiFilename.size() ) {
2800 std::cout <<
localized(
"saving abi to ${abiFilename}", (
"abiFilename", abiFilename)) << std::endl;
2801 std::ofstream abiout( abiFilename.c_str() );
2808 auto getAbi = get->add_subcommand(
"abi",
localized(
"Retrieve the ABI for an account"));
2809 getAbi->add_option(
"name", accountName,
localized(
"The name of the account whose abi should be retrieved"))->required();
2810 getAbi->add_option(
"-f,--file",filename,
localized(
"The name of the file to save the contract .abi to instead of writing to console") );
2811 getAbi->callback([&] {
2815 if( filename.size() ) {
2816 std::cerr <<
localized(
"saving abi to ${filename}", (
"filename", filename)) << std::endl;
2817 std::ofstream abiout( filename.c_str() );
2820 std::cout << abi <<
"\n";
2832 string encode_type{
"dec"};
2833 bool binary =
false;
2835 string index_position;
2836 bool reverse =
false;
2837 bool show_payer =
false;
2838 auto getTable = get->add_subcommand(
"table",
localized(
"Retrieve the contents of a database table"));
2839 getTable->add_option(
"account", code,
localized(
"The account who owns the table") )->required();
2840 getTable->add_option(
"scope", scope,
localized(
"The scope within the contract in which the table is found") )->required();
2841 getTable->add_option(
"table", table,
localized(
"The name of the table as specified by the contract abi") )->required();
2842 getTable->add_option(
"-l,--limit", limit,
localized(
"The maximum number of rows to return") );
2843 getTable->add_option(
"-k,--key", table_key,
localized(
"Deprecated") );
2844 getTable->add_option(
"-L,--lower", lower,
localized(
"JSON representation of lower bound value of key, defaults to first") );
2845 getTable->add_option(
"-U,--upper", upper,
localized(
"JSON representation of upper bound value of key, defaults to last") );
2846 getTable->add_option(
"--index", index_position,
2847 localized(
"Index number, 1 - primary (first), 2 - secondary index (in order defined by multi_index), 3 - third index, etc.\n"
2848 "\t\t\t\tNumber or name of index can be specified, e.g. 'secondary' or '2'."));
2849 getTable->add_option(
"--key-type",
key_type,
2850 localized(
"The key type of --index, primary only supports (i64), all others support (i64, i128, i256, float64, float128, ripemd160, sha256).\n"
2851 "\t\t\t\tSpecial type 'name' indicates an account name."));
2852 getTable->add_option(
"--encode-type", encode_type,
2853 localized(
"The encoding type of key_type (i64 , i128 , float64, float128) only support decimal encoding e.g. 'dec'"
2854 "i256 - supports both 'dec' and 'hex', ripemd160 and sha256 is 'hex' only"));
2855 getTable->add_flag(
"-b,--binary", binary,
localized(
"Return the value as BINARY rather than using abi to interpret as JSON"));
2856 getTable->add_flag(
"-r,--reverse", reverse,
localized(
"Iterate in reverse order"));
2857 getTable->add_flag(
"--show-payer", show_payer,
localized(
"Show RAM payer"));
2860 getTable->callback([&] {
2865 (
"table_key",table_key)
2866 (
"lower_bound",lower)
2867 (
"upper_bound",upper)
2870 (
"index_position", index_position)
2871 (
"encode_type", encode_type)
2872 (
"reverse", reverse)
2873 (
"show_payer", show_payer)
2880 auto getScope = get->add_subcommand(
"scope",
localized(
"Retrieve a list of scopes and tables owned by a contract"));
2881 getScope->add_option(
"contract", code,
localized(
"The contract who owns the table") )->required();
2882 getScope->add_option(
"-t,--table", table,
localized(
"The name of the table as filter") );
2883 getScope->add_option(
"-l,--limit", limit,
localized(
"The maximum number of rows to return") );
2884 getScope->add_option(
"-L,--lower", lower,
localized(
"Lower bound of scope") );
2885 getScope->add_option(
"-U,--upper", upper,
localized(
"Upper bound of scope") );
2886 getScope->add_flag(
"-r,--reverse", reverse,
localized(
"Iterate in reverse order"));
2887 getScope->callback([&] {
2890 (
"lower_bound",lower)
2891 (
"upper_bound",upper)
2893 (
"reverse", reverse)
2902 bool currency_balance_print_json =
false;
2903 auto get_currency = get->add_subcommand(
"currency",
localized(
"Retrieve information related to standard currencies"));
2904 get_currency->require_subcommand();
2905 auto get_balance = get_currency->add_subcommand(
"balance",
localized(
"Retrieve the balance of an account for a given currency"));
2906 get_balance->add_option(
"contract", code,
localized(
"The contract that operates the currency") )->required();
2907 get_balance->add_option(
"account", accountName,
localized(
"The account to query balances for") )->required();
2908 get_balance->add_option(
"symbol",
symbol,
localized(
"The symbol for the currency if the contract operates multiple currencies") );
2909 get_balance->add_flag(
"--json,-j", currency_balance_print_json,
localized(
"Output in JSON format") );
2910 get_balance->callback([&] {
2912 (
"account", accountName)
2916 if (!currency_balance_print_json) {
2917 const auto& rows = result.get_array();
2918 for(
const auto&
r : rows ) {
2926 auto get_currency_stats = get_currency->add_subcommand(
"stats",
localized(
"Retrieve the stats of for a given currency"));
2927 get_currency_stats->add_option(
"contract", code,
localized(
"The contract that operates the currency") )->required();
2928 get_currency_stats->add_option(
"symbol",
symbol,
localized(
"The symbol for the currency if the contract operates multiple currencies") )->required();
2929 get_currency_stats->callback([&] {
2940 string public_key_str;
2941 auto getAccounts = get->add_subcommand(
"accounts",
localized(
"Retrieve accounts associated with a public key"));
2942 getAccounts->add_option(
"public_key", public_key_str,
localized(
"The public key to retrieve accounts for"))->required();
2943 getAccounts->callback([&] {
2947 }
SYS_RETHROW_EXCEPTIONS(public_key_type_exception,
"Invalid public key: ${public_key}", (
"public_key", public_key_str))
2954 string controllingAccount;
2955 auto getServants = get->add_subcommand(
"servants",
localized(
"Retrieve accounts which are servants of a given account "));
2956 getServants->add_option(
"account", controllingAccount,
localized(
"The name of the controlling account"))->required();
2957 getServants->callback([&] {
2963 string transaction_id_str;
2965 auto getTransaction = get->add_subcommand(
"transaction",
localized(
"Retrieve a transaction from the blockchain"));
2966 getTransaction->add_option(
"id", transaction_id_str,
localized(
"ID of the transaction to retrieve"))->required();
2967 getTransaction->add_option(
"-b,--block-hint", block_num_hint,
localized(
"The block number this transaction may be in") );
2968 getTransaction->callback([&] {
2970 if ( block_num_hint > 0 ) {
2971 arg = arg(
"block_num_hint", block_num_hint);
2977 auto getTransactionTrace = get->add_subcommand(
"transaction_trace",
localized(
"Retrieve a transaction from trace logs"));
2978 getTransactionTrace->add_option(
"id", transaction_id_str,
localized(
"ID of the transaction to retrieve"))->required();
2979 getTransactionTrace->callback([&] {
2986 auto getBlockTrace = get->add_subcommand(
"block_trace",
localized(
"Retrieve a block from trace logs"));
2987 getBlockTrace->add_option(
"block", blockNum,
localized(
"The number of the block to retrieve"))->required();
2989 getBlockTrace->callback([&] {
2996 string skip_seq_str;
2998 bool printjson =
false;
2999 bool fullact =
false;
3000 bool prettyact =
false;
3001 bool printconsole =
false;
3005 auto getActions = get->add_subcommand(
"actions",
localized(
"Retrieve all actions with specific account name referenced in authorization or receiver"));
3006 getActions->add_option(
"account_name",
account_name,
localized(
"Name of account to query on"))->required();
3007 getActions->add_option(
"pos", pos_seq,
localized(
"Sequence number of action for this account, -1 for last"));
3008 getActions->add_option(
"offset", offset,
localized(
"Get actions [pos,pos+offset] for positive offset or [pos-offset,pos) for negative offset"));
3009 getActions->add_flag(
"--json,-j", printjson,
localized(
"Print full JSON"));
3010 getActions->add_flag(
"--full", fullact,
localized(
"Don't truncate action output"));
3011 getActions->add_flag(
"--pretty", prettyact,
localized(
"Pretty print full action JSON"));
3012 getActions->add_flag(
"--console", printconsole,
localized(
"Print console output generated by action "));
3013 getActions->callback([&] {
3016 arg(
"pos", pos_seq );
3017 arg(
"offset", offset);
3025 auto& traces = result[
"actions"].get_array();
3026 uint32_t lib = result[
"last_irreversible_block"].as_uint64();
3029 cout <<
"#" << setw(5) <<
"seq" <<
" " << setw( 24 ) << left <<
"when"<<
" " << setw(24) << right <<
"contract::action" <<
" => " << setw(13) << left <<
"receiver" <<
" " << setw(11) << left <<
"trx id..." <<
" args\n";
3030 cout <<
"================================================================================================================\n";
3031 for(
const auto& trace: traces ) {
3032 std::stringstream out;
3033 if( trace[
"block_num"].as_uint64() <= lib )
3038 out << setw(5) << trace[
"account_action_seq"].as_uint64() <<
" ";
3039 out << setw(24) << trace[
"block_time"].as_string() <<
" ";
3041 const auto& at = trace[
"action_trace"].get_object();
3043 auto id = at[
"trx_id"].as_string();
3044 const auto& receipt = at[
"receipt"];
3045 auto receiver = receipt[
"receiver"].as_string();
3046 const auto& act = at[
"act"].get_object();
3047 auto code = act[
"account"].as_string();
3048 auto func = act[
"name"].as_string();
3056 args = args.substr(0,60) +
"...";
3059 out << std::setw(24) << std::right<< (code +
"::" + func) <<
" => " << left << std::setw(13) << receiver;
3061 out <<
" " << setw(11) << (
id.substr(0,8) +
"...");
3063 if( fullact || prettyact ) out <<
"\n";
3068 if( trace[
"block_num"].as_uint64() <= lib ) {
3069 dlog(
"\r${m}", (
"m",out.str()) );
3071 wlog(
"\r${m}", (
"m",out.str()) );
3073 if( printconsole ) {
3074 auto console = at[
"console"].as_string();
3075 if( console.size() ) {
3077 std::stringstream ss(console);
3079 while( std::getline( ss, line ) ) {
3080 sout <<
">> " <<
clean_output( std::move( line ) ) <<
"\n";
3081 if( !fullact )
break;
3095 auto setSubcommand =
app.add_subcommand(
"set",
localized(
"Set or update blockchain state"));
3096 setSubcommand->require_subcommand();
3100 string contractPath;
3103 bool shouldSend =
true;
3104 bool contract_clear =
false;
3105 bool suppress_duplicate_check =
false;
3106 auto codeSubcommand = setSubcommand->add_subcommand(
"code",
localized(
"Create or update the code on an account"));
3107 codeSubcommand->add_option(
"account", account,
localized(
"The account to set code for"))->required();
3108 codeSubcommand->add_option(
"code-file", wasmPath,
localized(
"The path containing the contract WASM"));
3109 codeSubcommand->add_flag(
"-c,--clear", contract_clear,
localized(
"Remove code on an account"));
3110 codeSubcommand->add_flag(
"--suppress-duplicate-check", suppress_duplicate_check,
localized(
"Don't check for duplicate"));
3112 auto abiSubcommand = setSubcommand->add_subcommand(
"abi",
localized(
"Create or update the abi on an account"));
3113 abiSubcommand->add_option(
"account", account,
localized(
"The account to set the ABI for"))->required();
3114 abiSubcommand->add_option(
"abi-file", abiPath,
localized(
"The path containing the contract ABI"));
3115 abiSubcommand->add_flag(
"-c,--clear", contract_clear,
localized(
"Remove abi on an account"));
3116 abiSubcommand->add_flag(
"--suppress-duplicate-check", suppress_duplicate_check,
localized(
"Don't check for duplicate"));
3118 auto contractSubcommand = setSubcommand->add_subcommand(
"contract",
localized(
"Create or update the contract on an account"));
3119 contractSubcommand->add_option(
"account", account,
localized(
"The account to publish a contract for"))
3121 contractSubcommand->add_option(
"contract-dir", contractPath,
localized(
"The path containing the .wasm and .abi"));
3123 contractSubcommand->add_option(
"wasm-file", wasmPath,
localized(
"The file containing the contract WASM relative to contract-dir"));
3125 contractSubcommand->add_option(
"abi-file,-a,--abi", abiPath,
localized(
"The ABI for the contract relative to contract-dir"));
3127 contractSubcommand->add_flag(
"-c,--clear", contract_clear,
localized(
"Remove contract on an account"));
3128 contractSubcommand->add_flag(
"--suppress-duplicate-check", suppress_duplicate_check,
localized(
"Don't check for duplicate"));
3130 std::vector<chain::action> actions;
3131 auto set_code_callback = [&]() {
3133 std::vector<char> old_wasm;
3136 if (!suppress_duplicate_check) {
3139 old_hash =
fc::sha256(result[
"code_hash"].as_string());
3141 std::cerr <<
"Failed to get existing code hash, continue without duplicate check..." << std::endl;
3142 suppress_duplicate_check =
true;
3147 if(!contract_clear){
3151 if( wasmPath.empty() ) {
3152 wasmPath = (cpath / (cpath.
filename().generic_string()+
".wasm")).generic_string();
3153 }
else if ( boost::filesystem::path(wasmPath).is_relative() ) {
3154 wasmPath = (cpath / wasmPath).generic_string();
3157 std::cerr <<
localized((
"Reading WASM from " + wasmPath +
"...").c_str()) << std::endl;
3159 SYS_ASSERT( !wasm.empty(), wasm_file_not_found,
"no wasm file found ${f}", (
"f", wasmPath) );
3161 const string binary_wasm_header(
"\x00\x61\x73\x6d\x01\x00\x00\x00", 8);
3162 if(wasm.compare(0, 8, binary_wasm_header))
3163 std::cerr <<
localized(
"WARNING: ") << wasmPath <<
localized(
" doesn't look like a binary WASM file. Is it something else, like WAST? Trying anyway...") << std::endl;
3164 code_bytes =
bytes(wasm.begin(), wasm.end());
3166 code_bytes =
bytes();
3169 if (!suppress_duplicate_check) {
3170 if (code_bytes.size()) {
3179 std::cerr <<
localized(
"Setting Code...") << std::endl;
3183 std::cerr <<
localized(
"Skipping set code because the new code is the same as the existing code") << std::endl;
3187 auto set_abi_callback = [&]() {
3191 if (!suppress_duplicate_check) {
3194 old_abi = result[
"abi"].as_blob().data;
3196 std::cerr <<
"Failed to get existing raw abi, continue without duplicate check..." << std::endl;
3197 suppress_duplicate_check =
true;
3202 if(!contract_clear){
3205 if( abiPath.empty() ) {
3206 abiPath = (cpath / (cpath.
filename().generic_string()+
".abi")).generic_string();
3207 }
else if ( boost::filesystem::path(abiPath).is_relative() ) {
3208 abiPath = (cpath / abiPath).generic_string();
3211 SYS_ASSERT(
fc::exists( abiPath ), abi_file_not_found,
"no abi file found ${f}", (
"f", abiPath) );
3215 abi_bytes =
bytes();
3218 if (!suppress_duplicate_check) {
3219 duplicate = (old_abi.size() == abi_bytes.size() && std::equal(old_abi.begin(), old_abi.end(), abi_bytes.begin()));
3227 std::cerr <<
localized(
"Setting ABI...") << std::endl;
3231 std::cerr <<
localized(
"Skipping set abi because the new abi is the same as the existing abi") << std::endl;
3238 contractSubcommand->callback([&] {
3239 if(!contract_clear)
SYS_ASSERT( !contractPath.empty(), contract_exception,
" contract-dir is null ", (
"f", contractPath) );
3241 set_code_callback();
3243 if (actions.size()) {
3244 std::cerr <<
localized(
"Publishing contract...") << std::endl;
3247 std::cout <<
"no transaction is sent" << std::endl;
3250 codeSubcommand->callback(set_code_callback);
3251 abiSubcommand->callback(set_abi_callback);
3254 auto setAccount = setSubcommand->add_subcommand(
"account",
localized(
"Set or update blockchain account state"))->require_subcommand();
3260 auto setAction = setSubcommand->add_subcommand(
"action",
localized(
"Set or update blockchain action state"))->require_subcommand();
3266 string con =
"sysio.token";
3271 bool pay_ram =
false;
3272 auto transfer =
app.add_subcommand(
"transfer",
localized(
"Transfer tokens from account to account"));
3273 transfer->add_option(
"sender", sender,
localized(
"The account sending tokens"))->required();
3274 transfer->add_option(
"recipient", recipient,
localized(
"The account receiving tokens"))->required();
3275 transfer->add_option(
"amount", amount,
localized(
"The amount of tokens to send"))->required();
3276 transfer->add_option(
"memo", memo,
localized(
"The memo for the transfer"));
3277 transfer->add_option(
"--contract,-c", con,
localized(
"The contract that controls the token"));
3278 transfer->add_flag(
"--pay-ram-to-open", pay_ram,
localized(
"Pay RAM to open recipient's token balance row"));
3281 transfer->callback([&] {
3293 auto open_ =
create_open(con,
name(recipient), transfer_amount.get_symbol(),
name(sender));
3300 auto net =
app.add_subcommand(
"net",
localized(
"Interact with local p2p network connections"));
3301 net->require_subcommand();
3302 auto connect = net->add_subcommand(
"connect",
localized(
"Start a new connection to a peer"));
3303 connect->add_option(
"host", new_host,
localized(
"The hostname:port to connect to."))->required();
3304 connect->callback([&] {
3309 auto disconnect = net->add_subcommand(
"disconnect",
localized(
"Close an existing connection"));
3310 disconnect->add_option(
"host", new_host,
localized(
"The hostname:port to disconnect from."))->required();
3311 disconnect->callback([&] {
3316 auto status = net->add_subcommand(
"status",
localized(
"Status of existing connection"));
3317 status->add_option(
"host", new_host,
localized(
"The hostname:port to query status of connection"))->required();
3318 status->callback([&] {
3323 auto connections = net->add_subcommand(
"peers",
localized(
"Status of all existing peers"));
3324 connections->callback([&] {
3332 auto wallet =
app.add_subcommand(
"wallet",
localized(
"Interact with local wallet"));
3333 wallet->require_subcommand();
3335 string wallet_name =
"default";
3336 string password_file;
3337 auto createWallet = wallet->add_subcommand(
"create",
localized(
"Create a new wallet locally"));
3338 createWallet->add_option(
"-n,--name", wallet_name,
localized(
"The name of the new wallet"),
true);
3339 createWallet->add_option(
"-f,--file", password_file,
localized(
"Name of file to write wallet password output to. (Must be set, unless \"--to-console\" is passed"));
3340 createWallet->add_flag(
"--to-console", print_console,
localized(
"Print password to console."));
3341 createWallet->callback([&wallet_name, &password_file, &print_console] {
3342 SYSC_ASSERT( !password_file.empty() ^ print_console,
"ERROR: Either indicate a file using \"--file\" or pass \"--to-console\"" );
3343 SYSC_ASSERT( password_file.empty() || !std::ofstream(password_file.c_str()).fail(),
"ERROR: Failed to create file in specified path" );
3346 std::cout <<
localized(
"Creating wallet: ${wallet_name}", (
"wallet_name", wallet_name)) << std::endl;
3347 std::cout <<
localized(
"Save password to use in the future to unlock this wallet.") << std::endl;
3348 std::cout <<
localized(
"Without password imported keys will not be retrievable.") << std::endl;
3349 if (print_console) {
3352 std::cerr <<
localized(
"saving password to ${filename}", (
"filename", password_file)) << std::endl;
3354 boost::replace_all(password_str,
"\"",
"");
3355 std::ofstream out( password_file.c_str() );
3356 out << password_str;
3361 auto openWallet = wallet->add_subcommand(
"open",
localized(
"Open an existing wallet"));
3362 openWallet->add_option(
"-n,--name", wallet_name,
localized(
"The name of the wallet to open"));
3363 openWallet->callback([&wallet_name] {
3365 std::cout <<
localized(
"Opened: ${wallet_name}", (
"wallet_name", wallet_name)) << std::endl;
3369 auto lockWallet = wallet->add_subcommand(
"lock",
localized(
"Lock wallet"));
3370 lockWallet->add_option(
"-n,--name", wallet_name,
localized(
"The name of the wallet to lock"));
3371 lockWallet->callback([&wallet_name] {
3373 std::cout <<
localized(
"Locked: ${wallet_name}", (
"wallet_name", wallet_name)) << std::endl;
3377 auto locakAllWallets = wallet->add_subcommand(
"lock_all",
localized(
"Lock all unlocked wallets"));
3378 locakAllWallets->callback([] {
3380 std::cout <<
localized(
"Locked All Wallets") << std::endl;
3385 auto unlockWallet = wallet->add_subcommand(
"unlock",
localized(
"Unlock wallet"));
3386 unlockWallet->add_option(
"-n,--name", wallet_name,
localized(
"The name of the wallet to unlock"));
3387 unlockWallet->add_option(
"--password", wallet_pw,
localized(
"The password returned by wallet create"))->expected(0, 1);
3388 unlockWallet->callback([&wallet_name, &wallet_pw] {
3393 std::cout <<
localized(
"Unlocked: ${wallet_name}", (
"wallet_name", wallet_name)) << std::endl;
3397 string wallet_key_str;
3398 auto importWallet = wallet->add_subcommand(
"import",
localized(
"Import private key into wallet"));
3399 importWallet->add_option(
"-n,--name", wallet_name,
localized(
"The name of the wallet to import key into"));
3400 importWallet->add_option(
"--private-key", wallet_key_str,
localized(
"Private key in WIF format to import"))->expected(0, 1);
3401 importWallet->callback([&wallet_name, &wallet_key_str] {
3402 if( wallet_key_str.size() == 0 ) {
3403 std::cout <<
localized(
"private key: ");
3405 std::getline( std::cin, wallet_key_str,
'\n' );
3413 SYS_THROW(private_key_type_exception,
"Invalid private key")
3419 std::cout <<
localized(
"imported private key for: ${pubkey}", (
"pubkey",
pubkey.to_string())) << std::endl;
3423 string wallet_rm_key_str;
3424 auto removeKeyWallet = wallet->add_subcommand(
"remove_key",
localized(
"Remove key from wallet"));
3425 removeKeyWallet->add_option(
"-n,--name", wallet_name,
localized(
"The name of the wallet to remove key from"));
3426 removeKeyWallet->add_option(
"key", wallet_rm_key_str,
localized(
"Public key in WIF format to remove"))->required();
3427 removeKeyWallet->add_option(
"--password", wallet_pw,
localized(
"The password returned by wallet create"))->expected(0, 1);
3428 removeKeyWallet->callback([&wallet_name, &wallet_pw, &wallet_rm_key_str] {
3434 SYS_THROW(public_key_type_exception,
"Invalid public key: ${public_key}", (
"public_key", wallet_rm_key_str))
3438 std::cout <<
localized(
"removed private key for: ${pubkey}", (
"pubkey", wallet_rm_key_str)) << std::endl;
3442 string wallet_create_key_type;
3443 auto createKeyInWallet = wallet->add_subcommand(
"create_key",
localized(
"Create private key within wallet"));
3444 createKeyInWallet->add_option(
"-n,--name", wallet_name,
localized(
"The name of the wallet to create key into"),
true);
3445 createKeyInWallet->add_option(
"key_type", wallet_create_key_type,
localized(
"Key type to create (K1/R1)"),
true)->type_name(
"K1/R1");
3446 createKeyInWallet->callback([&wallet_name, &wallet_create_key_type] {
3454 auto listWallet = wallet->add_subcommand(
"list",
localized(
"List opened wallets, * = unlocked"));
3455 listWallet->callback([] {
3456 std::cout <<
localized(
"Wallets:") << std::endl;
3462 auto listKeys = wallet->add_subcommand(
"keys",
localized(
"List of public keys from all unlocked wallets."));
3463 listKeys->callback([] {
3469 auto listPrivKeys = wallet->add_subcommand(
"private_keys",
localized(
"List of private keys from an unlocked wallet in wif or PVT_R1 format."));
3470 listPrivKeys->add_option(
"-n,--name", wallet_name,
localized(
"The name of the wallet to list keys from"),
true);
3471 listPrivKeys->add_option(
"--password", wallet_pw,
localized(
"The password returned by wallet create"))->expected(0, 1);
3472 listPrivKeys->callback([&wallet_name, &wallet_pw] {
3479 auto stopKiod = wallet->add_subcommand(
"stop",
localized(
"Stop ${k}.", (
"k", key_store_executable_name)));
3480 stopKiod->callback([] {
3482 if ( !v.is_object() || v.get_object().size() != 0 ) {
3485 std::cout <<
"OK" << std::endl;
3490 string trx_json_to_sign;
3491 string str_private_key;
3492 string str_chain_id;
3493 string str_private_key_file;
3494 string str_public_key;
3495 bool push_trx =
false;
3497 auto sign =
app.add_subcommand(
"sign",
localized(
"Sign a transaction"));
3498 sign->add_option(
"transaction", trx_json_to_sign,
3499 localized(
"The JSON string or filename defining the transaction to sign"),
true)->required();
3500 sign->add_option(
"-k,--private-key", str_private_key,
localized(
"The private key that will be used to sign the transaction"))->expected(0, 1);
3501 sign->add_option(
"--public-key", str_public_key,
localized(
"Ask ${exec} to sign with the corresponding private key of the given public key", (
"exec", key_store_executable_name)));
3502 sign->add_option(
"-c,--chain-id", str_chain_id,
localized(
"The chain id that will be used to sign the transaction"));
3503 sign->add_flag(
"-p,--push-transaction", push_trx,
localized(
"Push transaction after signing"));
3505 sign->callback([&] {
3507 SYSC_ASSERT( str_private_key.empty() || str_public_key.empty(),
"ERROR: Either -k/--private-key or --public-key or none of them can be set" );
3511 bool was_packed_trx =
false;
3522 was_packed_trx =
true;
3532 std::optional<chain_id_type> chain_id;
3534 if( str_chain_id.size() == 0 ) {
3535 ilog(
"grabbing chain_id from ${n}", (
"n", node_executable_name) );
3537 chain_id = info.chain_id;
3542 if( str_public_key.size() > 0 ) {
3546 }
SYS_RETHROW_EXCEPTIONS(public_key_type_exception,
"Invalid public key: ${public_key}", (
"public_key", str_public_key))
3547 fc::variant keys_var(flat_set<public_key_type>{ pub_key });
3550 if( str_private_key.size() == 0 ) {
3551 std::cerr <<
localized(
"private key: ");
3553 std::getline( std::cin, str_private_key,
'\n' );
3560 trx.
sign(priv_key, *chain_id);
3567 if ( was_packed_trx ) {
3576 auto push =
app.add_subcommand(
"push",
localized(
"Push arbitrary transactions to the blockchain"));
3577 push->require_subcommand();
3580 string contract_account;
3584 auto actionsSubcommand = push->add_subcommand(
"action",
localized(
"Push a transaction with a single action"));
3585 actionsSubcommand->fallthrough(
false);
3586 actionsSubcommand->add_option(
"account", contract_account,
3587 localized(
"The account providing the contract to execute"),
true)->required();
3588 actionsSubcommand->add_option(
"action",
action,
3589 localized(
"A JSON string or filename defining the action to execute on the contract"),
true)->required();
3590 actionsSubcommand->add_option(
"data", data,
localized(
"The arguments to the contract"))->required();
3593 actionsSubcommand->callback([&] {
3595 if( !data.empty() ) {
3606 auto trxSubcommand = push->add_subcommand(
"transaction",
localized(
"Push an arbitrary JSON transaction"));
3607 trxSubcommand->add_option(
"transaction", trx_to_push,
localized(
"The JSON string or filename defining the transaction to push"))->required();
3609 trxSubcommand->add_flag(
"-o,--read-only",
tx_read_only,
localized(
"Specify a transaction is read-only"));
3611 trxSubcommand->callback([&] {
3616 }
catch(
const std::exception& ) {
3626 auto trxsSubcommand = push->add_subcommand(
"transactions",
localized(
"Push an array of arbitrary JSON transactions"));
3627 trxsSubcommand->add_option(
"transactions", trxsJson,
localized(
"The JSON string or filename defining the array of the transactions to push"))->required();
3628 trxsSubcommand->callback([&] {
3636 auto msig =
app.add_subcommand(
"multisig",
localized(
"Multisig contract commands"));
3637 msig->require_subcommand();
3640 string proposal_name;
3641 string requested_perm;
3642 string transaction_perm;
3643 string proposed_transaction;
3644 string proposed_contract;
3645 string proposed_action;
3647 unsigned int proposal_expiration_hours = 24;
3649 unsigned int value_s;
3650 if (res.size() == 0 || !CLI::detail::lexical_cast(res[0], value_s)) {
3654 proposal_expiration_hours =
static_cast<uint64_t>(value_s);
3658 auto propose_action = msig->add_subcommand(
"propose",
localized(
"Propose action"));
3660 propose_action->add_option(
"proposal_name", proposal_name,
localized(
"The proposal name (string)"))->required();
3661 propose_action->add_option(
"requested_permissions", requested_perm,
localized(
"The JSON string or filename defining requested permissions"))->required();
3662 propose_action->add_option(
"trx_permissions", transaction_perm,
localized(
"The JSON string or filename defining transaction permissions"))->required();
3663 propose_action->add_option(
"contract", proposed_contract,
localized(
"The contract to which deferred transaction should be delivered"))->required();
3664 propose_action->add_option(
"action", proposed_action,
localized(
"The action of deferred transaction"))->required();
3665 propose_action->add_option(
"data", proposed_transaction,
localized(
"The JSON string or filename defining the action to propose"))->required();
3666 propose_action->add_option(
"proposer", proposer,
localized(
"Account proposing the transaction"));
3667 propose_action->add_option(
"proposal_expiration", parse_expiration_hours,
localized(
"Proposal expiration interval in hours"));
3669 propose_action->callback([&] {
3683 }
SYS_RETHROW_EXCEPTIONS(transaction_type_exception,
"Wrong requested permissions format: '${data}'", (
"data",requested_perm_var));
3688 }
SYS_RETHROW_EXCEPTIONS(transaction_type_exception,
"Wrong transaction permissions format: '${data}'", (
"data",transaction_perm_var));
3691 if (accountPermissions.empty()) {
3692 if (!proposer.empty()) {
3695 SYS_THROW(missing_auth_exception,
"Authority is not provided (either by multisig parameter <proposer> or -p)");
3698 if (proposer.empty()) {
3699 proposer =
name(accountPermissions.at(0).actor).to_string();
3715 (
"proposer", proposer )
3716 (
"proposal_name", proposal_name)
3717 (
"requested", requested_perm_var)
3724 auto propose_trx = msig->add_subcommand(
"propose_trx",
localized(
"Propose transaction"));
3726 propose_trx->add_option(
"proposal_name", proposal_name,
localized(
"The proposal name (string)"))->required();
3727 propose_trx->add_option(
"requested_permissions", requested_perm,
localized(
"The JSON string or filename defining requested permissions"))->required();
3728 propose_trx->add_option(
"transaction", trx_to_push,
localized(
"The JSON string or filename defining the transaction to push"))->required();
3729 propose_trx->add_option(
"proposer", proposer,
localized(
"Account proposing the transaction"));
3731 propose_trx->callback([&] {
3736 if (accountPermissions.empty()) {
3737 if (!proposer.empty()) {
3740 SYS_THROW(missing_auth_exception,
"Authority is not provided (either by multisig parameter <proposer> or -p)");
3743 if (proposer.empty()) {
3744 proposer =
name(accountPermissions.at(0).actor).to_string();
3748 (
"proposer", proposer )
3749 (
"proposal_name", proposal_name)
3750 (
"requested", requested_perm_var)
3758 bool show_approvals_in_multisig_review =
false;
3759 auto review = msig->add_subcommand(
"review",
localized(
"Review transaction"));
3760 review->add_option(
"proposer", proposer,
localized(
"The proposer name (string)"))->required();
3761 review->add_option(
"proposal_name", proposal_name,
localized(
"The proposal name (string)"))->required();
3762 review->add_flag(
"--show-approvals", show_approvals_in_multisig_review,
localized(
"Show the status of the approvals requested within the proposal") );
3764 review->callback([&] {
3766 (
"code",
"sysio.msig")
3768 (
"table",
"proposal")
3770 (
"lower_bound",
name(proposal_name).to_uint64_t())
3771 (
"upper_bound",
name(proposal_name).to_uint64_t() + 1)
3778 const auto& rows1 = result1.get_object()[
"rows"].get_array();
3780 if( rows1.empty() || rows1[0].get_object()[
"proposal_name"] != proposal_name ) {
3781 std::cerr <<
"Proposal not found" << std::endl;
3785 const auto& proposal_object = rows1[0].get_object();
3787 enum class approval_status {
3793 std::map<permission_level, std::pair<fc::time_point, approval_status>> all_approvals;
3796 bool new_multisig =
true;
3797 if( show_approvals_in_multisig_review ) {
3802 (
"code",
"sysio.msig")
3804 (
"table",
"approvals2")
3806 (
"lower_bound",
name(proposal_name).to_uint64_t())
3807 (
"upper_bound",
name(proposal_name).to_uint64_t() + 1)
3812 rows2 = result2.get_object()[
"rows"].get_array();
3814 new_multisig =
false;
3817 if( !rows2.empty() && rows2[0].get_object()[
"proposal_name"] == proposal_name ) {
3818 const auto& approvals_object = rows2[0].get_object();
3820 for(
const auto& ra : approvals_object[
"requested_approvals"].get_array() ) {
3822 all_approvals.emplace( pl, std::make_pair(ra[
"time"].as<fc::time_point>(), approval_status::unapproved) );
3825 for(
const auto& pa : approvals_object[
"provided_approvals"].get_array() ) {
3827 auto res = all_approvals.emplace( pl, std::make_pair(pa[
"time"].as<fc::time_point>(), approval_status::approved) );
3828 provided_approvers[pl.actor].second.push_back( res.first );
3832 (
"code",
"sysio.msig")
3834 (
"table",
"approvals")
3836 (
"lower_bound",
name(proposal_name).to_uint64_t())
3837 (
"upper_bound",
name(proposal_name).to_uint64_t() + 1)
3842 const auto& rows3 = result3.get_object()[
"rows"].get_array();
3843 if( rows3.empty() || rows3[0].get_object()[
"proposal_name"] != proposal_name ) {
3844 std::cerr <<
"Proposal not found" << std::endl;
3848 const auto& approvals_object = rows3[0].get_object();
3850 for(
const auto& ra : approvals_object[
"requested_approvals"].get_array() ) {
3852 all_approvals.emplace( pl, std::make_pair(
fc::time_point{}, approval_status::unapproved) );
3855 for(
const auto& pa : approvals_object[
"provided_approvals"].get_array() ) {
3857 auto res = all_approvals.emplace( pl, std::make_pair(
fc::time_point{}, approval_status::approved) );
3858 provided_approvers[pl.actor].second.push_back( res.first );
3862 if( new_multisig ) {
3863 for(
auto&
a : provided_approvers ) {
3865 (
"code",
"sysio.msig")
3866 (
"scope",
"sysio.msig")
3869 (
"lower_bound",
a.first.to_uint64_t())
3870 (
"upper_bound",
a.first.to_uint64_t() + 1)
3875 const auto& rows4 = result4.get_object()[
"rows"].get_array();
3876 if( rows4.empty() || rows4[0].get_object()[
"account"].as<
sysio::name>() !=
a.first ) {
3880 auto invalidation_time = rows4[0].get_object()[
"last_invalidation_time"].as<
fc::time_point>();
3881 a.second.first = invalidation_time;
3883 for(
auto& itr :
a.second.second ) {
3884 if( invalidation_time >= itr->second.first ) {
3885 itr->second.second = approval_status::invalidated;
3892 auto trx_hex = proposal_object[
"packed_transaction"].as_string();
3894 fc::from_hex(trx_hex, trx_blob.data(), trx_blob.size());
3898 obj[
"proposer"] = proposer;
3899 obj[
"proposal_name"] = proposal_object[
"proposal_name"];
3900 obj[
"transaction_id"] = trx.
id();
3902 for(
const auto& entry : proposal_object ) {
3903 if( entry.key() ==
"proposal_name" )
continue;
3904 obj.
set( entry.key(), entry.value() );
3910 obj[
"transaction"] = trx_var;
3912 if( show_approvals_in_multisig_review ) {
3915 for(
const auto& approval : all_approvals ) {
3917 approval_obj[
"level"] = approval.first;
3918 switch( approval.second.second ) {
3919 case approval_status::unapproved:
3921 approval_obj[
"status"] =
"unapproved";
3923 approval_obj[
"last_unapproval_time"] = approval.second.first;
3927 case approval_status::approved:
3929 approval_obj[
"status"] =
"approved";
3930 if( new_multisig ) {
3931 approval_obj[
"last_approval_time"] = approval.second.first;
3935 case approval_status::invalidated:
3937 approval_obj[
"status"] =
"invalidated";
3938 approval_obj[
"last_approval_time"] = approval.second.first;
3939 approval_obj[
"invalidation_time"] = provided_approvers[approval.first.actor].first;
3944 approvals.push_back( std::move(approval_obj) );
3947 obj[
"approvals"] = std::move(approvals);
3954 string proposal_hash;
3955 auto approve_or_unapprove = [&](
const string&
action) {
3959 (
"proposer", proposer)
3960 (
"proposal_name", proposal_name)
3961 (
"level", perm_var);
3963 if( proposal_hash.size() ) {
3964 args(
"proposal_hash", proposal_hash);
3972 auto approve = msig->add_subcommand(
"approve",
localized(
"Approve proposed transaction"));
3974 approve->add_option(
"proposer", proposer,
localized(
"The proposer name (string)"))->required();
3975 approve->add_option(
"proposal_name", proposal_name,
localized(
"The proposal name (string)"))->required();
3976 approve->add_option(
"permissions", perm,
localized(
"The JSON string of filename defining approving permissions"))->required();
3977 approve->add_option(
"proposal_hash", proposal_hash,
localized(
"Hash of proposed transaction (i.e. transaction ID) to optionally enforce as a condition of the approval"));
3978 approve->callback([&] { approve_or_unapprove(
"approve"); });
3981 auto unapprove = msig->add_subcommand(
"unapprove",
localized(
"Unapprove proposed transaction"));
3983 unapprove->add_option(
"proposer", proposer,
localized(
"The proposer name (string)"))->required();
3984 unapprove->add_option(
"proposal_name", proposal_name,
localized(
"The proposal name (string)"))->required();
3985 unapprove->add_option(
"permissions", perm,
localized(
"The JSON string of filename defining approving permissions"))->required();
3986 unapprove->callback([&] { approve_or_unapprove(
"unapprove"); });
3990 auto invalidate = msig->add_subcommand(
"invalidate",
localized(
"Invalidate all multisig approvals of an account"));
3992 invalidate->add_option(
"invalidator", invalidator,
localized(
"invalidator name (string)"))->required();
3993 invalidate->callback([&] {
3995 (
"account", invalidator);
4003 auto cancel = msig->add_subcommand(
"cancel",
localized(
"Cancel proposed transaction"));
4005 cancel->add_option(
"proposer", proposer,
localized(
"The proposer name (string)"))->required();
4006 cancel->add_option(
"proposal_name", proposal_name,
localized(
"proposal name (string)"))->required();
4007 cancel->add_option(
"canceler", canceler,
localized(
"The canceler name (string)"));
4008 cancel->callback([&]() {
4010 if (accountPermissions.empty()) {
4011 if (!canceler.empty()) {
4014 SYS_THROW(missing_auth_exception,
"Authority is not provided (either by multisig parameter <canceler> or -p)");
4017 if (canceler.empty()) {
4018 canceler =
name(accountPermissions.at(0).actor).to_string();
4021 (
"proposer", proposer)
4022 (
"proposal_name", proposal_name)
4023 (
"canceler", canceler);
4031 auto exec = msig->add_subcommand(
"exec",
localized(
"Execute proposed transaction"));
4033 exec->add_option(
"proposer", proposer,
localized(
"The proposer name (string)"))->required();
4034 exec->add_option(
"proposal_name", proposal_name,
localized(
"The proposal name (string)"))->required();
4035 exec->add_option(
"executer", executer,
localized(
"The account paying for execution (string)"));
4036 exec->callback([&] {
4038 if (accountPermissions.empty()) {
4039 if (!executer.empty()) {
4042 SYS_THROW(missing_auth_exception,
"Authority is not provided (either by multisig parameter <executer> or -p)");
4045 if (executer.empty()) {
4046 executer =
name(accountPermissions.at(0).actor).to_string();
4050 (
"proposer", proposer )
4051 (
"proposal_name", proposal_name)
4052 (
"executer", executer);
4059 auto wrap =
app.add_subcommand(
"wrap",
localized(
"Wrap contract commands"));
4060 wrap->require_subcommand();
4063 string wrap_con =
"sysio.wrap";
4066 auto wrap_exec =
wrap->add_subcommand(
"exec",
localized(
"Execute a transaction while bypassing authorization checks"));
4068 wrap_exec->add_option(
"executer", executer,
localized(
"Account executing the transaction and paying for the deferred transaction RAM"))->required();
4069 wrap_exec->add_option(
"transaction", trx_to_exec,
localized(
"The JSON string or filename defining the transaction to execute"))->required();
4070 wrap_exec->add_option(
"--contract,-c", wrap_con,
localized(
"The account which controls the wrap contract"));
4072 wrap_exec->callback([&] {
4076 if( accountPermissions.empty() ) {
4081 (
"executer", executer )
4088 auto system =
app.add_subcommand(
"system",
localized(
"Send sysio.system contract action to the blockchain."));
4089 system->require_subcommand();
4095 auto voteProducer = system->add_subcommand(
"voteproducer",
localized(
"Vote for a producer"));
4096 voteProducer->require_subcommand();
4120 auto rex = system->add_subcommand(
"rex",
localized(
"Actions related to REX (the resource exchange)"));
4121 rex->require_subcommand();
4142 auto handle_error = [&](
const auto& e)
4148 elog(
"Failed with error: ${e}", (
"e", verbose ? e.to_detail_string() : e.to_string()));
4158 }
catch (
const explained_exception& e) {
4160 }
catch (connection_exception& e) {
4162 elog(
"connect error: ${e}", (
"e", e.to_detail_string()));
4165 }
catch (
const std::bad_alloc& ) {
4168 }
catch(
const boost::interprocess::bad_alloc& ) {
4172 return handle_error(e);
4173 }
catch (
const std::exception& e) {