diff --git a/contracts/eosio.system/eosio.system.abi b/contracts/eosio.system/eosio.system.abi index d83738654ceb3d881a0e5737eb7bb4b598b800eb..5f2f28220a6a8e57e6bf81ea5f7c26e817977b2e 100644 --- a/contracts/eosio.system/eosio.system.abi +++ b/contracts/eosio.system/eosio.system.abi @@ -57,6 +57,15 @@ {"name":"cpu_weight", "type":"uint64"}, {"name":"storage_bytes", "type":"uint64"} ] + },{ + "name": "user_resources", + "base": "", + "fields": [ + {"name":"owner", "type":"account_name"}, + {"name":"net_weight", "type":"asset"}, + {"name":"cpu_weight", "type":"asset"}, + {"name":"storage_bytes", "type":"uint64"} + ] },{ "name": "total_resources", "base": "", @@ -257,6 +266,12 @@ "index_type": "i64", "key_names" : ["owner"], "key_types" : ["account_name"] + },{ + "name": "userres", + "type": "user_resources", + "index_type": "i64", + "key_names" : ["owner"], + "key_types" : ["uint64"] },{ "name": "totalband", "type": "total_resources", diff --git a/libraries/chain/include/eosio/chain/name.hpp b/libraries/chain/include/eosio/chain/name.hpp index c3117d5398b595f4dbbc5d02dc79c853543fe22b..af5af89ec2367a828eadbe7fa64e015044181db8 100644 --- a/libraries/chain/include/eosio/chain/name.hpp +++ b/libraries/chain/include/eosio/chain/name.hpp @@ -99,6 +99,17 @@ namespace eosio { namespace chain { } } // eosio::chain +namespace std { + template<> struct hash : private hash { + typedef eosio::chain::name argument_type; + typedef typename hash::result_type result_type; + result_type operator()(const argument_type& name) const noexcept + { + return hash::operator()(name.value); + } + }; +}; + namespace fc { class variant; void to_variant(const eosio::chain::name& c, fc::variant& v); diff --git a/libraries/chain/include/eosio/chain/resource_limits.hpp b/libraries/chain/include/eosio/chain/resource_limits.hpp index b2a4cf81dcf18e42a3dfc56af7e2f169eae500b7..71c9f42820047c2b0910e9ade00abe737004037e 100644 --- a/libraries/chain/include/eosio/chain/resource_limits.hpp +++ b/libraries/chain/include/eosio/chain/resource_limits.hpp @@ -26,6 +26,12 @@ namespace eosio { namespace chain { namespace resource_limits { void validate()const; // throws if the parameters do not satisfy basic sanity checks }; + struct account_resource_limit { + int64_t current_per_block = 0; + int64_t max_per_block = 0; + int64_t guaranteed_per_day = 0; + }; + class resource_limits_manager { public: explicit resource_limits_manager(chainbase::database& db) @@ -59,9 +65,15 @@ namespace eosio { namespace chain { namespace resource_limits { int64_t get_account_cpu_limit( const account_name& name ) const; int64_t get_account_net_limit( const account_name& name ) const; + + account_resource_limit get_account_cpu_limit_ex( const account_name& name ) const; + account_resource_limit get_account_net_limit_ex( const account_name& name ) const; + int64_t get_account_ram_usage( const account_name& name ) const; private: chainbase::database& _db; }; } } } /// eosio::chain + +FC_REFLECT( eosio::chain::resource_limits::account_resource_limit, (current_per_block)(max_per_block)(guaranteed_per_day) ) diff --git a/libraries/chain/resource_limits.cpp b/libraries/chain/resource_limits.cpp index dbd8d2bec3eb4ac29b02c243ca17422c114a2bfd..d35cc504df9114f9a5006f4522d2f4d8b0ec0caf 100644 --- a/libraries/chain/resource_limits.cpp +++ b/libraries/chain/resource_limits.cpp @@ -325,6 +325,7 @@ int64_t resource_limits_manager::get_account_cpu_limit( const account_name& name uint128_t consumed_ex = (uint128_t)usage.cpu_usage.consumed * (uint128_t)config::rate_limiting_precision; uint128_t virtual_capacity_ex = (uint128_t)state.virtual_cpu_limit * (uint128_t)config::rate_limiting_precision; + uint128_t usable_capacity_ex = (uint128_t)(virtual_capacity_ex * limits.cpu_weight) / (uint128_t)total_cpu_weight; if (usable_capacity_ex < consumed_ex) { @@ -334,6 +335,37 @@ int64_t resource_limits_manager::get_account_cpu_limit( const account_name& name return (int64_t)((usable_capacity_ex - consumed_ex) / (uint128_t)config::rate_limiting_precision); } +account_resource_limit resource_limits_manager::get_account_cpu_limit_ex( const account_name& name ) const { + const auto& cfg = _db.get(); + const auto& state = _db.get(); + const auto& usage = _db.get(name); + const auto& limits = _db.get(boost::make_tuple(false, name)); + if (limits.cpu_weight < 0) { + return { -1, -1, -1 }; + } + + auto total_cpu_weight = state.total_cpu_weight; + if( total_cpu_weight == 0 ) total_cpu_weight = 1; + + uint128_t consumed_ex = (uint128_t)usage.cpu_usage.consumed * (uint128_t)config::rate_limiting_precision; + uint128_t virtual_capacity_ex = (uint128_t)state.virtual_cpu_limit * (uint128_t)config::rate_limiting_precision; + + uint128_t usable_capacity_ex = (uint128_t)(virtual_capacity_ex * limits.cpu_weight) / (uint128_t)total_cpu_weight; + + uint128_t real_capacity_ex = (uint128_t)cfg.cpu_limit_parameters.target * (uint128_t)config::rate_limiting_precision; + uint128_t guaranteed_capacity_ex = (uint128_t)(real_capacity_ex * limits.cpu_weight) / (uint128_t)total_cpu_weight; + + uint128_t blocks_per_day = 86400 * 1000 / config::block_interval_ms; + + if (usable_capacity_ex < consumed_ex) { + consumed_ex = usable_capacity_ex; + } + return { (int64_t)(std::min(usable_capacity_ex - consumed_ex, real_capacity_ex) / (uint128_t)config::rate_limiting_precision), + (int64_t)(std::min(usable_capacity_ex, real_capacity_ex) / (uint128_t)config::rate_limiting_precision), + (int64_t)(guaranteed_capacity_ex * blocks_per_day / cfg.cpu_limit_parameters.periods / (uint128_t)config::rate_limiting_precision) + }; +} + int64_t resource_limits_manager::get_account_net_limit( const account_name& name ) const { const auto& state = _db.get(); const auto& usage = _db.get(name); @@ -348,7 +380,7 @@ int64_t resource_limits_manager::get_account_net_limit( const account_name& name auto total_net_weight = state.total_net_weight; if( total_net_weight == 0 ) total_net_weight = 1; - uint128_t usable_capacity_ex = (uint128_t)(virtual_capacity_ex * limits.net_weight) / (uint128_t)total_net_weight; + uint128_t usable_capacity_ex = (uint128_t)(virtual_capacity_ex * limits.net_weight) / (uint128_t)total_net_weight; // max if (usable_capacity_ex < consumed_ex) { return 0; @@ -358,5 +390,36 @@ int64_t resource_limits_manager::get_account_net_limit( const account_name& name } +account_resource_limit resource_limits_manager::get_account_net_limit_ex( const account_name& name ) const { + const auto& cfg = _db.get(); + const auto& state = _db.get(); + const auto& usage = _db.get(name); + const auto& limits = _db.get(boost::make_tuple(false, name)); + if (limits.net_weight < 0) { + return { -1, -1, -1 }; + } + + auto total_net_weight = state.total_net_weight; + if( total_net_weight == 0 ) total_net_weight = 1; + + uint128_t consumed_ex = (uint128_t)usage.net_usage.consumed * (uint128_t)config::rate_limiting_precision; + uint128_t virtual_capacity_ex = (uint128_t)state.virtual_net_limit * (uint128_t)config::rate_limiting_precision; + + uint128_t usable_capacity_ex = (uint128_t)(virtual_capacity_ex * limits.net_weight) / (uint128_t)total_net_weight; // max + + uint128_t real_capacity_ex = (uint128_t)cfg.net_limit_parameters.target * (uint128_t)config::rate_limiting_precision; + uint128_t guaranteed_capacity_ex = (uint128_t)(real_capacity_ex * limits.net_weight) / (uint128_t)total_net_weight; + + uint128_t blocks_per_day = 86400 * 1000 / config::block_interval_ms; + + if (usable_capacity_ex < consumed_ex) { + consumed_ex = usable_capacity_ex; + } + return { (int64_t)(std::min(usable_capacity_ex - consumed_ex, real_capacity_ex) / (uint128_t)config::rate_limiting_precision), + (int64_t)(std::min(usable_capacity_ex, real_capacity_ex) / (uint128_t)config::rate_limiting_precision), + (int64_t)(guaranteed_capacity_ex * blocks_per_day / cfg.net_limit_parameters.periods / (uint128_t)config::rate_limiting_precision) + }; +} + } } } /// eosio::chain::resource_limits diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index ae1a9fcb3d7595380377d4f7288ff81e659195f7..1c383a6f30438aae74974888da61101aded1c691 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -515,8 +515,8 @@ read_only::get_account_results read_only::get_account( const get_account_params& result.last_code_update = a.last_code_update; result.created = a.creation_date; - result.net_limit = rm.get_account_net_limit( result.account_name ); - result.cpu_limit = rm.get_account_cpu_limit( result.account_name ); + result.net_limit = rm.get_account_net_limit_ex( result.account_name ); + result.cpu_limit = rm.get_account_cpu_limit_ex( result.account_name ); result.ram_usage = rm.get_account_ram_usage( result.account_name ); const auto& permissions = d.get_index(); @@ -538,7 +538,45 @@ read_only::get_account_results read_only::get_account( const get_account_params& ++perm; } + const auto& code_account = db.db().get( N(eosio) ); + //const abi_def abi = get_abi( db, N(eosio) ); + abi_def abi; + if( abi_serializer::to_abi(code_account.abi, abi) ) { + abi_serializer abis( abi ); + //get_table_rows_ex(p,abi); + const auto* t_id = d.find(boost::make_tuple( config::system_account_name, params.account_name, N(userres) )); + if (t_id != nullptr) { + const auto &idx = d.get_index(); + auto it = idx.lower_bound(boost::make_tuple( t_id->id, params.account_name )); + if ( it != idx.end() ) { + vector data; + copy_inline_row(*it, data); + result.total_resources = abis.binary_to_variant( "user_resources", data ); + } + } + t_id = d.find(boost::make_tuple( config::system_account_name, params.account_name, N(delband) )); + if (t_id != nullptr) { + const auto &idx = d.get_index(); + auto it = idx.lower_bound(boost::make_tuple( t_id->id, params.account_name )); + if ( it != idx.end() ) { + vector data; + copy_inline_row(*it, data); + result.delegated_bandwidth = abis.binary_to_variant( "delegated_bandwidth", data ); + } + } + + t_id = d.find(boost::make_tuple( config::system_account_name, config::system_account_name, N(voters) )); + if (t_id != nullptr) { + const auto &idx = d.get_index(); + auto it = idx.lower_bound(boost::make_tuple( t_id->id, params.account_name )); + if ( it != idx.end() ) { + vector data; + copy_inline_row(*it, data); + result.voter_info = abis.binary_to_variant( "voter_info", data ); + } + } + } return result; } diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 4ab1a323a0148db8cd09e413244f1f668af73a52..8d21dff814026823f6f2762ecc0a8a27456b0577 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,7 @@ public: name producer_name; }; + using account_resource_limit = chain::resource_limits::account_resource_limit; struct get_account_results { name account_name; @@ -91,11 +93,15 @@ public: int64_t net_weight = 0; int64_t cpu_weight = 0; - int64_t net_limit = 0; - int64_t cpu_limit = 0; + account_resource_limit net_limit; + account_resource_limit cpu_limit; int64_t ram_usage = 0; vector permissions; + + fc::variant total_resources; + fc::variant delegated_bandwidth; + fc::variant voter_info; }; struct get_account_params { @@ -365,7 +371,7 @@ private: FC_REFLECT( eosio::chain_apis::permission, (perm_name)(parent)(required_auth) ) FC_REFLECT(eosio::chain_apis::empty, ) FC_REFLECT(eosio::chain_apis::read_only::get_info_results, - (server_version)(head_block_num)(last_irreversible_block_num)(last_irreversible_block_id)(head_block_id)(head_block_time)(head_block_producer)(virtual_block_cpu_limit)(virtual_block_net_limit)(block_cpu_limit)(block_net_limit) ) +(server_version)(head_block_num)(last_irreversible_block_num)(last_irreversible_block_id)(head_block_id)(head_block_time)(head_block_producer)(virtual_block_cpu_limit)(virtual_block_net_limit)(block_cpu_limit)(block_net_limit) ) FC_REFLECT(eosio::chain_apis::read_only::get_block_params, (block_num_or_id)) FC_REFLECT( eosio::chain_apis::read_write::push_transaction_results, (transaction_id)(processed) ) @@ -377,7 +383,7 @@ FC_REFLECT( eosio::chain_apis::read_only::get_currency_balance_params, (code)(ac FC_REFLECT( eosio::chain_apis::read_only::get_currency_stats_params, (code)(symbol)); FC_REFLECT( eosio::chain_apis::read_only::get_currency_stats_result, (supply)(max_supply)(issuer)); -FC_REFLECT( eosio::chain_apis::read_only::get_account_results, (account_name)(privileged)(last_code_update)(created)(ram_quota)(net_weight)(cpu_weight)(net_limit)(cpu_limit)(ram_usage)(permissions) ) +FC_REFLECT( eosio::chain_apis::read_only::get_account_results, (account_name)(privileged)(last_code_update)(created)(ram_quota)(net_weight)(cpu_weight)(net_limit)(cpu_limit)(ram_usage)(permissions)(total_resources)(delegated_bandwidth)(voter_info) ) FC_REFLECT( eosio::chain_apis::read_only::get_code_results, (account_name)(code_hash)(wast)(abi) ) FC_REFLECT( eosio::chain_apis::read_only::get_account_params, (account_name) ) FC_REFLECT( eosio::chain_apis::read_only::get_code_params, (account_name) ) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index b65adf45b7809cf12a68ceaa1c33d8b26f4b29a9..1a7e2ea95fada66b1f84461507941fd47cae9b42 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -408,6 +408,16 @@ chain::action create_buyrambytes(const name& creator, const name& newaccount, ui config::system_account_name, N(buyrambytes), act_payload); } +chain::action create_delegate(const name& from, const name& receiver, const asset& net, const asset& cpu) { + fc::variant act_payload = fc::mutable_variant_object() + ("from", from.to_string()) + ("receiver", receiver.to_string()) + ("stake_net_quantity", net.to_string()) + ("stake_cpu_quantity", cpu.to_string()); + return create_action(tx_permission.empty() ? vector{{from,config::active_name}} : get_account_permissions(tx_permission), + config::system_account_name, N(delegatebw), act_payload); +} + fc::variant regproducer_variant(const account_name& producer, public_key_type key, string url) { @@ -656,6 +666,58 @@ struct register_producer_subcommand { } }; +struct create_account_subcommand { + string creator; + string account_name; + string owner_key_str; + string active_key_str; + string stake_net; + string stake_cpu; + uint32_t buy_ram_bytes_in_kbytes = 8; + string buy_ram_eos; + bool simple; + + create_account_subcommand(CLI::App* actionRoot, bool s) : simple(s) { + auto createAccount = actionRoot->add_subcommand( (simple ? "account" : "newaccount"), localized("Create an account, buy ram, stake for bandwidth for the account")); + createAccount->add_option("creator", creator, localized("The name of the account creating the new account"))->required(); + createAccount->add_option("name", account_name, localized("The name of the new account"))->required(); + createAccount->add_option("OwnerKey", owner_key_str, localized("The owner public key for the new account"))->required(); + createAccount->add_option("ActiveKey", active_key_str, localized("The active public key for the new account"))->required(); + + if (!simple) { + createAccount->add_option("--stake-net", stake_net, + (localized("The amount of EOS delegated for net bandwidth")))->required(); + createAccount->add_option("--stake-cpu", stake_cpu, + (localized("The amount of EOS delegated for CPU bandwidth")))->required(); + createAccount->add_option("--buy-ram-bytes", buy_ram_bytes_in_kbytes, + (localized("The amount of RAM bytes to purchase for the new account in kilobytes KiB, default is 8 KiB"))); + createAccount->add_option("--buy-ram-EOS", buy_ram_eos, + (localized("The amount of RAM bytes to purchase for the new account in EOS"))); + } + + add_standard_transaction_options(createAccount); + + createAccount->set_callback([this] { + public_key_type owner_key, active_key; + try { + owner_key = public_key_type(owner_key_str); + } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid owner public key: ${public_key}", ("public_key", owner_key_str)); + try { + active_key = public_key_type(active_key_str); + } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid active public key: ${public_key}", ("public_key", active_key_str)); + auto create = create_newaccount(creator, account_name, owner_key, active_key); + if (!simple) { + action buyram = !buy_ram_eos.empty() ? create_buyram(creator, account_name, asset::from_string(buy_ram_eos)) + : create_buyrambytes(creator, account_name, buy_ram_bytes_in_kbytes * 1024); + action delegate = create_delegate( creator, account_name, asset::from_string(stake_net), asset::from_string(stake_cpu) ); + send_actions( { create, buyram, delegate } ); + } else { + send_actions( { create } ); + } + }); + } +}; + struct unregister_producer_subcommand { string producer_str; @@ -729,7 +791,6 @@ struct delegate_bandwidth_subcommand { delegate_bandwidth->add_option("receiver", receiver_str, localized("The account to receive the delegated bandwidth"))->required(); delegate_bandwidth->add_option("stake_net_quantity", stake_net_amount, localized("The amount of EOS to stake for network bandwidth"))->required(); delegate_bandwidth->add_option("stake_cpu_quantity", stake_cpu_amount, localized("The amount of EOS to stake for CPU bandwidth"))->required(); - delegate_bandwidth->add_option("stake_storage_quantity", stake_storage_amount, localized("The amount of EOS to stake for storage"))->required(); add_standard_transaction_options(delegate_bandwidth); delegate_bandwidth->set_callback([this] { @@ -737,8 +798,7 @@ struct delegate_bandwidth_subcommand { ("from", from_str) ("receiver", receiver_str) ("stake_net_quantity", stake_net_amount + " EOS") - ("stake_cpu_quantity", stake_cpu_amount + " EOS") - ("stake_storage_quantity", stake_storage_amount + " EOS"); + ("stake_cpu_quantity", stake_cpu_amount + " EOS"); wdump((act_payload)); send_actions({create_action({permission_level{from_str,config::active_name}}, config::system_account_name, N(delegatebw), act_payload)}); }); @@ -758,7 +818,6 @@ struct undelegate_bandwidth_subcommand { undelegate_bandwidth->add_option("receiver", receiver_str, localized("The account to undelegate bandwidth from"))->required(); undelegate_bandwidth->add_option("unstake_net_quantity", unstake_net_amount, localized("The amount of EOS to undelegate for network bandwidth"))->required(); undelegate_bandwidth->add_option("unstake_cpu_quantity", unstake_cpu_amount, localized("The amount of EOS to undelegate for CPU bandwidth"))->required(); - undelegate_bandwidth->add_option("unstake_storage_bytes", unstake_storage_bytes, localized("The amount of byte storage to undelegate"))->required(); add_standard_transaction_options(undelegate_bandwidth); undelegate_bandwidth->set_callback([this] { @@ -766,13 +825,53 @@ struct undelegate_bandwidth_subcommand { ("from", from_str) ("receiver", receiver_str) ("unstake_net_quantity", unstake_net_amount + " EOS") - ("unstake_cpu_quantity", unstake_cpu_amount + " EOS") - ("unstake_storage_bytes", unstake_storage_bytes); + ("unstake_cpu_quantity", unstake_cpu_amount + " EOS"); send_actions({create_action({permission_level{from_str,config::active_name}}, config::system_account_name, N(undelegatebw), act_payload)}); }); } }; +struct buyram_subcommand { + string from_str; + string receiver_str; + string amount; + + buyram_subcommand(CLI::App* actionRoot) { + auto buyram = actionRoot->add_subcommand("buyram", localized("Buy RAM")); + buyram->add_option("payer", from_str, localized("The account paying for RAM"))->required(); + buyram->add_option("receiver", receiver_str, localized("The account receiving bought RAM"))->required(); + buyram->add_option("tokens", amount, localized("The amount of EOS to pay for RAM"))->required(); + add_standard_transaction_options(buyram); + buyram->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("payer", from_str) + ("receiver", receiver_str) + ("quant", asset::from_string(amount)); + send_actions({create_action({permission_level{from_str,config::active_name}}, config::system_account_name, N(buyram), act_payload)}); + }); + } +}; + +struct sellram_subcommand { + string from_str; + string receiver_str; + uint64_t amount; + + sellram_subcommand(CLI::App* actionRoot) { + auto sellram = actionRoot->add_subcommand("sellram", localized("Sell RAM")); + sellram->add_option("account", receiver_str, localized("The account to receive EOS for sold RAM"))->required(); + sellram->add_option("bytes", amount, localized("Number of RAM bytes to sell"))->required(); + add_standard_transaction_options(sellram); + + sellram->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("account", receiver_str) + ("bytes", amount); + send_actions({create_action({permission_level{from_str,config::active_name}}, config::system_account_name, N(sellram), act_payload)}); + }); + } +}; + struct claimrewards_subcommand { string owner; @@ -882,6 +981,124 @@ struct canceldelay_subcommand { } }; +void get_account( const string& accountName, bool json_format ) { + auto json = call(get_account_func, fc::mutable_variant_object("account_name", accountName)); + auto res = json.as(); + + if (!json_format) { + std::cout << "privileged: " << ( res.privileged ? "true" : "false") << std::endl; + + constexpr size_t indent_size = 5; + const string indent(indent_size, ' '); + + std::cout << "permissions: " << std::endl; + unordered_map/*children*/> tree; + vector roots; //we don't have multiple roots, but we can easily handle them here, so let's do it just in case + unordered_map cache; + for ( auto& perm : res.permissions ) { + if ( perm.parent ) { + tree[perm.parent].push_back( perm.perm_name ); + } else { + roots.push_back( perm.perm_name ); + } + auto name = perm.perm_name; //keep copy before moving `perm`, since thirst argument of emplace can be evaluated first + // looks a little crazy, but should be efficient + cache.insert( std::make_pair(name, std::move(perm)) ); + } + std::function dfs_print = [&]( account_name name, int depth ) -> void { + auto& p = cache.at(name); + std::cout << indent << std::string(depth*3, ' ') << name << ' ' << std::setw(5) << p.required_auth.threshold << ": "; + for ( auto it = p.required_auth.keys.begin(); it != p.required_auth.keys.end(); ++it ) { + if ( it != p.required_auth.keys.begin() ) { + std::cout << ", "; + } + std::cout << it->weight << ' ' << string(it->key); + } + for ( auto& acc : p.required_auth.accounts ) { + std::cout << acc.weight << ' ' << string(acc.permission.actor) << '@' << string(acc.permission.permission) << ", "; + } + std::cout << std::endl; + auto it = tree.find( name ); + if (it != tree.end()) { + auto& children = it->second; + sort( children.begin(), children.end() ); + for ( auto& n : children ) { + // we have a tree, not a graph, so no need to check for already visited nodes + dfs_print( n, depth+1 ); + } + } // else it's a leaf node + }; + std::sort(roots.begin(), roots.end()); + for ( auto r : roots ) { + dfs_print( r, 0 ); + } + + std::cout << "memory: " << std::endl + << indent << "quota: " << std::setw(15) << res.ram_quota << " bytes used: " << std::setw(15) << res.ram_usage << " bytes" << std::endl << std::endl; + + std::cout << "net bandwidth:" << std::endl; + if ( res.total_resources.is_object() && res.delegated_bandwidth.is_object() ) { + asset net_own( stoll( res.delegated_bandwidth.get_object()["net_weight"].as_string() ) ); + auto net_others = asset::from_string(res.total_resources.get_object()["net_weight"].as_string()) - net_own; + std::cout << indent << "staked:" << std::setw(20) << net_own + << std::string(11, ' ') << "(total stake delegated from account to self)" << std::endl + << indent << "delegated:" << std::setw(17) << net_others + << std::string(11, ' ') << "(total staked delegated to account from others)" << std::endl; + } + std::cout << indent << "current:" << std::setw(15) << ("~"+std::to_string(res.net_limit.current_per_block)) << " bytes/block" + << std::string(3, ' ') << "(assuming current congestion and current usage)" << std::endl + << indent << "max:" << std::setw(19) << ("~"+std::to_string(res.net_limit.max_per_block)) << " bytes/block" + << std::string(3, ' ') << "(assuming current congestion and 0 usage in current window)" << std::endl + << indent << "guaranteed: " << std::setw(11) << res.net_limit.guaranteed_per_day << " bytes/day" + << std::string(5, ' ') << "(assuming 100% congestion and 0 usage in current window)" << std::endl + << std::endl; + + + std::cout << "cpu bandwidth:" << std::endl; + if ( res.total_resources.is_object() && res.delegated_bandwidth.is_object() ) { + asset cpu_own( stoll( res.delegated_bandwidth.get_object()["cpu_weight"].as_string() ) ); + auto cpu_others = asset::from_string(res.total_resources.get_object()["cpu_weight"].as_string()) - cpu_own; + std::cout << indent << "staked:" << std::setw(20) << cpu_own + << std::string(11, ' ') << "(total stake delegated from account to self)" << std::endl + << indent << "delegated:" << std::setw(17) << cpu_others + << std::string(11, ' ') << "(total staked delegated to account from others)" << std::endl; + } + + std::cout << indent << "current:" << std::setw(15) << ("~"+std::to_string(res.cpu_limit.current_per_block/1024)) << " kcycle/block" + << std::string(2, ' ') << "(assuming current congestion and current usage)" << std::endl + << indent << "max:" << std::setw(19) << ("~"+std::to_string(res.cpu_limit.max_per_block/1024)) << " kcycle/block" + << std::string(2, ' ') << "(assuming current congestion and 0 usage in current window)" << std::endl + << indent << "guaranteed:" << std::setw(12) << res.cpu_limit.guaranteed_per_day/1024 << " kcycle/day" + << std::string(4, ' ') << "(assuming 100% congestion and 0 usage in current window)" << std::endl + << std::endl; + + if ( res.voter_info.is_object() ) { + auto& obj = res.voter_info.get_object(); + string proxy = obj["proxy"].as_string(); + if ( proxy.empty() ) { + auto& prods = obj["producers"].get_array(); + std::cout << "producers:"; + if ( !prods.empty() ) { + for ( int i = 0; i < prods.size(); ++i ) { + if ( i%3 == 0 ) { + std::cout << std::endl << indent; + } + std::cout << std::setw(16) << std::left << prods[i].as_string(); + } + std::cout << std::endl; + } else { + std::cout << indent << "" << std::endl; + } + } else { + std::cout << "proxy:" << indent << proxy << std::endl; + } + } + std::cout << std::endl; + } else { + std::cout << fc::json::to_pretty_string(json) << std::endl; + } +} + int main( int argc, char** argv ) { fc::path binPath = argv[0]; if (binPath.is_relative()) { @@ -926,41 +1143,7 @@ int main( int argc, char** argv ) { }); // create account - string creator; - string account_name; - string owner_key_str; - string active_key_str; - uint32_t buy_ram_bytes_in_kbytes = 8; - string buy_ram_eos; - - auto createAccount = create->add_subcommand("account", localized("Create a new account on the blockchain"), false); - createAccount->add_option("creator", creator, localized("The name of the account creating the new account"))->required(); - createAccount->add_option("name", account_name, localized("The name of the new account"))->required(); - createAccount->add_option("OwnerKey", owner_key_str, localized("The owner public key for the new account"))->required(); - createAccount->add_option("ActiveKey", active_key_str, localized("The active public key for the new account"))->required(); - createAccount->add_option("--buy-ram-bytes", buy_ram_bytes_in_kbytes, - (localized("The amount of RAM bytes to purchase for the new account in kilobytes KiB, default is 8 KiB"))); - createAccount->add_option("--buy-ram-EOS", buy_ram_eos, - (localized("The amount of RAM bytes to purchase for the new account in EOS"))); - add_standard_transaction_options(createAccount, "creator@active"); - createAccount->set_callback([&] { - public_key_type owner_key, active_key; - try { - owner_key = public_key_type(owner_key_str); - } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid owner public key: ${public_key}", ("public_key", owner_key_str)) - try { - active_key = public_key_type(active_key_str); - } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid active public key: ${public_key}", ("public_key", active_key_str)) - if( !buy_ram_eos.empty() ) { - action buyact = create_buyram(creator, account_name, asset::from_string(buy_ram_eos)); - send_actions({create_newaccount(creator, account_name, owner_key, active_key), buyact}); - } else if( buy_ram_bytes_in_kbytes > 0 ){ - action buyact = create_buyrambytes(creator, account_name, buy_ram_bytes_in_kbytes * 1024 * 1024); - send_actions({create_newaccount(creator, account_name, owner_key, active_key), buyact}); - } else { - send_actions({create_newaccount(creator, account_name, owner_key, active_key)}); - } - }); + auto createAccount = create_account_subcommand( create, true /*simple*/ ); // Get subcommand auto get = app.add_subcommand("get", localized("Retrieve various items and information from the blockchain"), false); @@ -982,13 +1165,11 @@ int main( int argc, char** argv ) { // get account string accountName; + bool print_json; auto getAccount = get->add_subcommand("account", localized("Retrieve an account from the blockchain"), false); getAccount->add_option("name", accountName, localized("The name of the account to retrieve"))->required(); - getAccount->set_callback([&] { - std::cout << fc::json::to_pretty_string(call(get_account_func, - fc::mutable_variant_object("account_name", accountName))) - << std::endl; - }); + getAccount->add_flag("--json,-j", print_json, localized("Output in JSON format") ); + getAccount->set_callback([&]() { get_account(accountName, print_json); }); // get code string codeFilename; @@ -1124,6 +1305,7 @@ int main( int argc, char** argv ) { }); // get actions + string account_name; string skip_seq_str; string num_seq_str; bool printjson = false; @@ -1867,6 +2049,7 @@ int main( int argc, char** argv ) { auto system = app.add_subcommand("system", localized("Send eosio.system contract action to the blockchain."), false); system->require_subcommand(); + auto createAccountSystem = create_account_subcommand( system, false /*simple*/ ); auto registerProducer = register_producer_subcommand(system); auto unregisterProducer = unregister_producer_subcommand(system); @@ -1878,6 +2061,9 @@ int main( int argc, char** argv ) { auto delegateBandWidth = delegate_bandwidth_subcommand(system); auto undelegateBandWidth = undelegate_bandwidth_subcommand(system); + auto biyram = buyram_subcommand(system); + auto sellram = sellram_subcommand(system); + auto claimRewards = claimrewards_subcommand(system); auto regProxy = regproxy_subcommand(system); diff --git a/tests/testUtils.py b/tests/testUtils.py index 1c7824da0949094ce7921daf2892127f53807553..7c09cc40e9473362713c184c48f9a44097961d3e 100755 --- a/tests/testUtils.py +++ b/tests/testUtils.py @@ -488,7 +488,7 @@ class Node(object): # Create account and return creation transactions. Return transaction json object # waitForTransBlock: wait on creation transaction id to appear in a block def createAccount(self, account, creatorAccount, stakedDeposit=1000, waitForTransBlock=False): - cmd="%s %s create account -j --buy-ram-bytes 0 %s %s %s %s" % ( + cmd="%s %s create account -j %s %s %s %s" % ( Utils.EosClientPath, self.endpointArgs, creatorAccount.name, account.name, account.ownerPublicKey, account.activePublicKey) @@ -513,7 +513,7 @@ class Node(object): return trans def getEosAccount(self, name): - cmd="%s %s get account %s" % (Utils.EosClientPath, self.endpointArgs, name) + cmd="%s %s get account -j %s" % (Utils.EosClientPath, self.endpointArgs, name) Utils.Debug and Utils.Print("cmd: %s" % (cmd)) try: trans=Node.runCmdReturnJson(cmd)