From ac6b604ce187b2f96e8458c51483d23a7df65510 Mon Sep 17 00:00:00 2001 From: Keke Li Date: Thu, 11 Feb 2021 16:10:39 -0800 Subject: [PATCH 1/7] Add cleos system activate subcommand to activate a system feature. such as: cleos system activate kv_database. don't need using digest. --- programs/cleos/main.cpp | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index de4e0364f4..2f0161f0e4 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -69,6 +69,8 @@ Usage: ./cleos create account [OPTIONS] creator name OwnerKey ActiveKey #include #include #include +#include +#include #include #include #include @@ -2247,6 +2249,58 @@ struct closerex_subcommand { } }; +struct activate_subcommand { + string feature_name_str; + + activate_subcommand(CLI::App* actionRoot) { + auto activate = actionRoot->add_subcommand("activate", localized("Activate system feature by feature name eg: KV_DATABASE")); + activate->add_option("feature", feature_name_str, localized("The system feature name to be activated, must be one of below(lowercase also works):\nPREACTIVATE_FEATURE\nONLY_LINK_TO_EXISTING_PERMISSION\nFORWARD_SETCODE\nKV_DATABASE\nWTMSIG_BLOCK_SIGNATURES\nREPLACE_DEFERRED\nNO_DUPLICATE_DEFERRED_ID\nRAM_RESTRICTIONS\nWEBAUTHN_KEY\nBLOCKCHAIN_PARAMETERS\nDISALLOW_EMPTY_PRODUCER_SCHEDULE\nONLY_BILL_FIRST_AUTHORIZER\nRESTRICT_ACTION_TO_SELF\nCONFIGURABLE_WASM_LIMITS\nACTION_RETURN_VALUE\nFIX_LINKAUTH_RESTRICTION\nGET_SENDER"))->required(); + activate->fallthrough(false); + activate->callback([this] { + /// map feature name to feature digest + std::unordered_map map_name_digest{ + {"PREACTIVATE_FEATURE", "0ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd"}, + {"ONLY_LINK_TO_EXISTING_PERMISSION", "1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241"}, + {"FORWARD_SETCODE", "2652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25"}, + {"KV_DATABASE", "825ee6288fb1373eab1b5187ec2f04f6eacb39cb3a97f356a07c91622dd61d16"}, + {"WTMSIG_BLOCK_SIGNATURES", "299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707"}, + {"REPLACE_DEFERRED", "ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99"}, + {"NO_DUPLICATE_DEFERRED_ID", "4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f"}, + {"RAM_RESTRICTIONS", "4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d67"}, + {"WEBAUTHN_KEY", "4fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2"}, + {"BLOCKCHAIN_PARAMETERS", "5443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4"}, + {"DISALLOW_EMPTY_PRODUCER_SCHEDULE", "68dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428"}, + {"ONLY_BILL_FIRST_AUTHORIZER", "8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a405"}, + {"RESTRICT_ACTION_TO_SELF", "ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43"}, + {"CONFIGURABLE_WASM_LIMITS", "bf61537fd21c61a60e542a5d66c3f6a78da0589336868307f94a82bccea84e88"}, + {"ACTION_RETURN_VALUE", "c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071"}, + {"FIX_LINKAUTH_RESTRICTION", "e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526"}, + {"GET_SENDER", "f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d"} + }; + // push system feature + string contract_account = "eosio"; + string action="activate"; + string data; + std::locale loc; + vector permissions = {"eosio"}; + for(auto & c : feature_name_str) c = std::toupper(c, loc); + if(map_name_digest.find(feature_name_str) != map_name_digest.end()){ + std::string feature_digest = map_name_digest[feature_name_str]; + data = "[\"" + feature_digest + "\"]"; + } else { + std::cout << "Can't find system feature : " << feature_name_str << std::endl; + } + fc::variant action_args_var; + if( !data.empty() ) { + action_args_var = json_from_file_or_string(data, fc::json::parse_type::relaxed_parser); + } + auto accountPermissions = get_account_permissions(permissions); + send_actions({chain::action{accountPermissions, name(contract_account), name(action), + variant_to_bin( name(contract_account), name(action), action_args_var ) }}, signing_keys_opt.get_keys()); + }); + } +}; + void get_account( const string& accountName, const string& coresym, bool json_format ) { fc::variant json; if (coresym.empty()) { @@ -4212,6 +4266,7 @@ int main( int argc, char** argv ) { auto unregProxy = unregproxy_subcommand(system); auto cancelDelay = canceldelay_subcommand(system); + auto activate = activate_subcommand(system); auto rex = system->add_subcommand("rex", localized("Actions related to REX (the resource exchange)")); rex->require_subcommand(); From e1f93acfca98a5724f86c42896650525f566a99d Mon Sep 17 00:00:00 2001 From: Keke Li Date: Fri, 12 Feb 2021 10:13:21 -0800 Subject: [PATCH 2/7] enhance error handling --- programs/cleos/main.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 2f0161f0e4..c1110fd5bc 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -2289,11 +2289,10 @@ struct activate_subcommand { data = "[\"" + feature_digest + "\"]"; } else { std::cout << "Can't find system feature : " << feature_name_str << std::endl; + return; } fc::variant action_args_var; - if( !data.empty() ) { - action_args_var = json_from_file_or_string(data, fc::json::parse_type::relaxed_parser); - } + action_args_var = json_from_file_or_string(data, fc::json::parse_type::relaxed_parser); auto accountPermissions = get_account_permissions(permissions); send_actions({chain::action{accountPermissions, name(contract_account), name(action), variant_to_bin( name(contract_account), name(action), action_args_var ) }}, signing_keys_opt.get_keys()); From 6236f47996511bf348eaa85871f105a8a139a4b1 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 12 Jul 2022 20:39:23 -0400 Subject: [PATCH 3/7] update protocol feature list to match Mandel, clean up help, and remove PREACTIVATE_FEATURE as it cannot be activated via activate action --- programs/cleos/main.cpp | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index c1110fd5bc..faa56a1e70 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -2253,16 +2253,32 @@ struct activate_subcommand { string feature_name_str; activate_subcommand(CLI::App* actionRoot) { - auto activate = actionRoot->add_subcommand("activate", localized("Activate system feature by feature name eg: KV_DATABASE")); - activate->add_option("feature", feature_name_str, localized("The system feature name to be activated, must be one of below(lowercase also works):\nPREACTIVATE_FEATURE\nONLY_LINK_TO_EXISTING_PERMISSION\nFORWARD_SETCODE\nKV_DATABASE\nWTMSIG_BLOCK_SIGNATURES\nREPLACE_DEFERRED\nNO_DUPLICATE_DEFERRED_ID\nRAM_RESTRICTIONS\nWEBAUTHN_KEY\nBLOCKCHAIN_PARAMETERS\nDISALLOW_EMPTY_PRODUCER_SCHEDULE\nONLY_BILL_FIRST_AUTHORIZER\nRESTRICT_ACTION_TO_SELF\nCONFIGURABLE_WASM_LIMITS\nACTION_RETURN_VALUE\nFIX_LINKAUTH_RESTRICTION\nGET_SENDER"))->required(); + auto activate = actionRoot->add_subcommand("activate", localized("Activate protocol feature by name")); + activate->add_option("feature", feature_name_str, localized("The name, one of below (lowercase also works):\n" + "ONLY_LINK_TO_EXISTING_PERMISSION\n" + "FORWARD_SETCODE\n" + "WTMSIG_BLOCK_SIGNATURES\n" + "CONFIGURABLE_WASM_LIMITS2\n" + "REPLACE_DEFERRED\n" + "NO_DUPLICATE_DEFERRED_ID\n" + "RAM_RESTRICTIONS\n" + "WEBAUTHN_KEY\n" + "DISALLOW_EMPTY_PRODUCER_SCHEDULE\n" + "ONLY_BILL_FIRST_AUTHORIZER\n" + "BLOCKCHAIN_PARAMETERS\n" + "GET_CODE_HASH\n" + "RESTRICT_ACTION_TO_SELF\n" + "ACTION_RETURN_VALUE\n" + "FIX_LINKAUTH_RESTRICTION\n" + "GET_SENDER\n" + "CRYPTO_PRIMITIVES\n" + "GET_BLOCK_NUM"))->required(); activate->fallthrough(false); activate->callback([this] { /// map feature name to feature digest std::unordered_map map_name_digest{ - {"PREACTIVATE_FEATURE", "0ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd"}, {"ONLY_LINK_TO_EXISTING_PERMISSION", "1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241"}, {"FORWARD_SETCODE", "2652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25"}, - {"KV_DATABASE", "825ee6288fb1373eab1b5187ec2f04f6eacb39cb3a97f356a07c91622dd61d16"}, {"WTMSIG_BLOCK_SIGNATURES", "299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707"}, {"REPLACE_DEFERRED", "ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99"}, {"NO_DUPLICATE_DEFERRED_ID", "4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f"}, @@ -2271,11 +2287,14 @@ struct activate_subcommand { {"BLOCKCHAIN_PARAMETERS", "5443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4"}, {"DISALLOW_EMPTY_PRODUCER_SCHEDULE", "68dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428"}, {"ONLY_BILL_FIRST_AUTHORIZER", "8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a405"}, + {"GET_CODE_HASH", "bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99"}, {"RESTRICT_ACTION_TO_SELF", "ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43"}, - {"CONFIGURABLE_WASM_LIMITS", "bf61537fd21c61a60e542a5d66c3f6a78da0589336868307f94a82bccea84e88"}, + {"CONFIGURABLE_WASM_LIMITS2", "d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40"}, {"ACTION_RETURN_VALUE", "c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071"}, {"FIX_LINKAUTH_RESTRICTION", "e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526"}, - {"GET_SENDER", "f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d"} + {"GET_SENDER", "f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d"}, + {"CRYPTO_PRIMITIVES", "6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc"}, + {"GET_BLOCK_NUM", "35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b"} }; // push system feature string contract_account = "eosio"; From 69711ea65a5c6c21b7b67b1e05259d9aa89b406f Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 14 Jul 2022 21:37:05 -0400 Subject: [PATCH 4/7] Remove hardcodied list of protocol features and their digests by using get_supported_protocol_features RPC; provide account and permission options --- programs/cleos/httpc.hpp | 3 + programs/cleos/main.cpp | 142 +++++++++++++++++++++++++-------------- 2 files changed, 96 insertions(+), 49 deletions(-) diff --git a/programs/cleos/httpc.hpp b/programs/cleos/httpc.hpp index 1acf8a67f9..705cdcb9ff 100644 --- a/programs/cleos/httpc.hpp +++ b/programs/cleos/httpc.hpp @@ -135,5 +135,8 @@ namespace eosio { namespace client { namespace http { const string wallet_sign_trx = wallet_func_base + "/sign_transaction"; const string keosd_stop = "/v1/" + string(client::config::key_store_executable_name) + "/stop"; + const string producer_func_base = "/v1/producer"; + const string producer_get_supported_protocol_features_func = producer_func_base + "/get_supported_protocol_features"; + FC_DECLARE_EXCEPTION( connection_exception, 1100000, "Connection Exception" ); }}} diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index faa56a1e70..5053458e77 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -2251,70 +2251,114 @@ struct closerex_subcommand { struct activate_subcommand { string feature_name_str; + std::string account_str = "eosio"; + std::string permission_str = "eosio"; + struct protocol_features_t { + std::string names; + std::unordered_map digests {}; // from name to digest + }; + protocol_features_t supported_features; activate_subcommand(CLI::App* actionRoot) { + auto get_supported_protocol_features = [&]() -> protocol_features_t { + protocol_features_t results; + + auto prot_features = call(producer_get_supported_protocol_features_func, fc::mutable_variant_object("exclude_disabled", true) + ("exclude_unactivatable", true) + ); + if ( !prot_features.is_array() ) { + std::cerr << "protocol features not an array" << endl; + return {}; + } + fc::variants& feature_variants = prot_features.get_array(); + + for( auto& feature_v : feature_variants ) { + if( !feature_v.is_object() ) { + std::cerr << "feature_v not an object" << endl; + return {}; + } + fc::variant_object& feature_vo = feature_v.get_object(); + if( !feature_vo.contains( "feature_digest" ) ) { + std::cerr << "feature_digest is missing" << std::endl; + return {}; + } + if( !feature_vo["feature_digest"].is_string() ) { + std::cerr << "feature_digest not a string" << std::endl; + return {}; + } + auto digest = feature_vo["feature_digest"].as_string(); + + if( !feature_vo.contains( "specification" ) ) { + std::cerr << "specification is missing" << std::endl; + return {}; + } + if( !feature_vo["specification"].is_array() ) { + std::cerr << "specification not an array" << std::endl; + return {}; + } + const fc::variants& spec_variants = feature_vo["specification"].get_array(); + if ( spec_variants.size() != 1 ) { + std::cerr << "specification array size " << spec_variants.size() << " not 1 " << std::endl; + return {}; + } + if ( !spec_variants[0].is_object() ) { + std::cerr << "spec_variants[0] not an object" << endl; + return {}; + } + const fc::variant_object& spec_vo = spec_variants[0].get_object(); + if ( !spec_vo.contains( "value" ) ) { + std::cerr << "value is missing" << endl; + return {}; + } + if ( !spec_vo["value"].is_string() ) { + std::cerr << "value not a string" << std::endl; + return {}; + } + auto name = spec_vo["value"].as_string(); + + if ( spec_vo["value"].as_string() == "PREACTIVATE_FEATURE" ) + { + // PREACTIVATE_FEATURE must be activated by schedule_protocol_feature_activations RPC, + // not by activate action + continue; + } + + results.names += name; + results.names += "\n"; + results.digests.emplace(name, digest); + } + + return results; + }; + + // Retrieve a list of the supported protocol features from the chain + supported_features = get_supported_protocol_features(); + + std::string description = "The name, one of below (lowercase also works):\n" + supported_features.names; auto activate = actionRoot->add_subcommand("activate", localized("Activate protocol feature by name")); - activate->add_option("feature", feature_name_str, localized("The name, one of below (lowercase also works):\n" - "ONLY_LINK_TO_EXISTING_PERMISSION\n" - "FORWARD_SETCODE\n" - "WTMSIG_BLOCK_SIGNATURES\n" - "CONFIGURABLE_WASM_LIMITS2\n" - "REPLACE_DEFERRED\n" - "NO_DUPLICATE_DEFERRED_ID\n" - "RAM_RESTRICTIONS\n" - "WEBAUTHN_KEY\n" - "DISALLOW_EMPTY_PRODUCER_SCHEDULE\n" - "ONLY_BILL_FIRST_AUTHORIZER\n" - "BLOCKCHAIN_PARAMETERS\n" - "GET_CODE_HASH\n" - "RESTRICT_ACTION_TO_SELF\n" - "ACTION_RETURN_VALUE\n" - "FIX_LINKAUTH_RESTRICTION\n" - "GET_SENDER\n" - "CRYPTO_PRIMITIVES\n" - "GET_BLOCK_NUM"))->required(); + activate->add_option("feature", feature_name_str, localized(description.c_str()))->required(); + activate->add_option("-a,--account", account_str, localized("The contract account name. default is eosio")); + activate->add_option("-p,--permission", permission_str, localized("The permission level to authorize, Default is eosio")); activate->fallthrough(false); + activate->callback([this] { - /// map feature name to feature digest - std::unordered_map map_name_digest{ - {"ONLY_LINK_TO_EXISTING_PERMISSION", "1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241"}, - {"FORWARD_SETCODE", "2652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25"}, - {"WTMSIG_BLOCK_SIGNATURES", "299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707"}, - {"REPLACE_DEFERRED", "ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99"}, - {"NO_DUPLICATE_DEFERRED_ID", "4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f"}, - {"RAM_RESTRICTIONS", "4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d67"}, - {"WEBAUTHN_KEY", "4fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2"}, - {"BLOCKCHAIN_PARAMETERS", "5443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4"}, - {"DISALLOW_EMPTY_PRODUCER_SCHEDULE", "68dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428"}, - {"ONLY_BILL_FIRST_AUTHORIZER", "8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a405"}, - {"GET_CODE_HASH", "bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99"}, - {"RESTRICT_ACTION_TO_SELF", "ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43"}, - {"CONFIGURABLE_WASM_LIMITS2", "d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40"}, - {"ACTION_RETURN_VALUE", "c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071"}, - {"FIX_LINKAUTH_RESTRICTION", "e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526"}, - {"GET_SENDER", "f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d"}, - {"CRYPTO_PRIMITIVES", "6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc"}, - {"GET_BLOCK_NUM", "35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b"} - }; - // push system feature - string contract_account = "eosio"; string action="activate"; string data; std::locale loc; - vector permissions = {"eosio"}; + vector permissions = { permission_str }; for(auto & c : feature_name_str) c = std::toupper(c, loc); - if(map_name_digest.find(feature_name_str) != map_name_digest.end()){ - std::string feature_digest = map_name_digest[feature_name_str]; - data = "[\"" + feature_digest + "\"]"; + if( supported_features.digests.find(feature_name_str) != supported_features.digests.end() ){ + std::string digest = supported_features.digests[feature_name_str]; + data = "[\"" + digest + "\"]"; } else { - std::cout << "Can't find system feature : " << feature_name_str << std::endl; + std::cout << feature_name_str << " not supported. Use -h to find out supported protocol features" << std::endl; return; } fc::variant action_args_var; action_args_var = json_from_file_or_string(data, fc::json::parse_type::relaxed_parser); auto accountPermissions = get_account_permissions(permissions); - send_actions({chain::action{accountPermissions, name(contract_account), name(action), - variant_to_bin( name(contract_account), name(action), action_args_var ) }}, signing_keys_opt.get_keys()); + send_actions({chain::action{accountPermissions, name(account_str), name(action), + variant_to_bin( name(account_str), name(action), action_args_var ) }}, signing_keys_opt.get_keys()); }); } }; From 3749a3c80c3b9bc80c25d3b414dbd60229834614 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 14 Jul 2022 21:51:30 -0400 Subject: [PATCH 5/7] Make descriptions of options account and permission consistent --- programs/cleos/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 5053458e77..41c43f3871 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -2337,8 +2337,8 @@ struct activate_subcommand { std::string description = "The name, one of below (lowercase also works):\n" + supported_features.names; auto activate = actionRoot->add_subcommand("activate", localized("Activate protocol feature by name")); activate->add_option("feature", feature_name_str, localized(description.c_str()))->required(); - activate->add_option("-a,--account", account_str, localized("The contract account name. default is eosio")); - activate->add_option("-p,--permission", permission_str, localized("The permission level to authorize, Default is eosio")); + activate->add_option("-a,--account", account_str, localized("The contract account name, default is eosio")); + activate->add_option("-p,--permission", permission_str, localized("The permission level to authorize, default is eosio")); activate->fallthrough(false); activate->callback([this] { From 0f12128ada884bbb163ce94ad0ce7576f0368c70 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 15 Jul 2022 21:29:25 -0400 Subject: [PATCH 6/7] Add "get supported_protocol_features" subcommand to remove the need to contact the chain in the constructor of activate_subcommand which causes problems for cleos problem initialzation when the chain is offline, and a seperate get supported_protocol_features is clearer --- programs/cleos/main.cpp | 166 +++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 80 deletions(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 41c43f3871..913210789e 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -2249,94 +2249,91 @@ struct closerex_subcommand { } }; -struct activate_subcommand { - string feature_name_str; - std::string account_str = "eosio"; - std::string permission_str = "eosio"; - struct protocol_features_t { - std::string names; - std::unordered_map digests {}; // from name to digest - }; - protocol_features_t supported_features; +struct protocol_features_t { + std::string names; + std::unordered_map digests {}; // from name to digest +}; - activate_subcommand(CLI::App* actionRoot) { - auto get_supported_protocol_features = [&]() -> protocol_features_t { - protocol_features_t results; - - auto prot_features = call(producer_get_supported_protocol_features_func, fc::mutable_variant_object("exclude_disabled", true) - ("exclude_unactivatable", true) - ); - if ( !prot_features.is_array() ) { - std::cerr << "protocol features not an array" << endl; - return {}; - } - fc::variants& feature_variants = prot_features.get_array(); +protocol_features_t get_supported_protocol_features() { + protocol_features_t results; - for( auto& feature_v : feature_variants ) { - if( !feature_v.is_object() ) { - std::cerr << "feature_v not an object" << endl; - return {}; - } - fc::variant_object& feature_vo = feature_v.get_object(); - if( !feature_vo.contains( "feature_digest" ) ) { - std::cerr << "feature_digest is missing" << std::endl; - return {}; - } - if( !feature_vo["feature_digest"].is_string() ) { - std::cerr << "feature_digest not a string" << std::endl; - return {}; - } - auto digest = feature_vo["feature_digest"].as_string(); + auto prot_features = call(producer_get_supported_protocol_features_func, fc::mutable_variant_object("exclude_disabled", true) + ("exclude_unactivatable", true) + ); - if( !feature_vo.contains( "specification" ) ) { - std::cerr << "specification is missing" << std::endl; - return {}; - } - if( !feature_vo["specification"].is_array() ) { - std::cerr << "specification not an array" << std::endl; - return {}; - } - const fc::variants& spec_variants = feature_vo["specification"].get_array(); - if ( spec_variants.size() != 1 ) { - std::cerr << "specification array size " << spec_variants.size() << " not 1 " << std::endl; - return {}; - } - if ( !spec_variants[0].is_object() ) { - std::cerr << "spec_variants[0] not an object" << endl; - return {}; - } - const fc::variant_object& spec_vo = spec_variants[0].get_object(); - if ( !spec_vo.contains( "value" ) ) { - std::cerr << "value is missing" << endl; - return {}; - } - if ( !spec_vo["value"].is_string() ) { - std::cerr << "value not a string" << std::endl; - return {}; - } - auto name = spec_vo["value"].as_string(); + if ( !prot_features.is_array() ) { + std::cerr << "protocol features not an array" << endl; + return {}; + } + fc::variants& feature_variants = prot_features.get_array(); - if ( spec_vo["value"].as_string() == "PREACTIVATE_FEATURE" ) - { - // PREACTIVATE_FEATURE must be activated by schedule_protocol_feature_activations RPC, - // not by activate action - continue; - } + for( auto& feature_v : feature_variants ) { + if( !feature_v.is_object() ) { + std::cerr << "feature_v not an object" << endl; + return {}; + } + fc::variant_object& feature_vo = feature_v.get_object(); + if( !feature_vo.contains( "feature_digest" ) ) { + std::cerr << "feature_digest is missing" << std::endl; + return {}; + } + if( !feature_vo["feature_digest"].is_string() ) { + std::cerr << "feature_digest not a string" << std::endl; + return {}; + } + auto digest = feature_vo["feature_digest"].as_string(); - results.names += name; - results.names += "\n"; - results.digests.emplace(name, digest); - } + if( !feature_vo.contains( "specification" ) ) { + std::cerr << "specification is missing" << std::endl; + return {}; + } + if( !feature_vo["specification"].is_array() ) { + std::cerr << "specification not an array" << std::endl; + return {}; + } + const fc::variants& spec_variants = feature_vo["specification"].get_array(); + if ( spec_variants.size() != 1 ) { + std::cerr << "specification array size " << spec_variants.size() << " not 1 " << std::endl; + return {}; + } + if ( !spec_variants[0].is_object() ) { + std::cerr << "spec_variants[0] not an object" << endl; + return {}; + } + const fc::variant_object& spec_vo = spec_variants[0].get_object(); + if ( !spec_vo.contains( "value" ) ) { + std::cerr << "value is missing" << endl; + return {}; + } + if ( !spec_vo["value"].is_string() ) { + std::cerr << "value not a string" << std::endl; + return {}; + } + auto name = spec_vo["value"].as_string(); - return results; - }; + if ( spec_vo["value"].as_string() == "PREACTIVATE_FEATURE" ) + { + // PREACTIVATE_FEATURE must be activated by schedule_protocol_feature_activations RPC, + // not by activate action + continue; + } - // Retrieve a list of the supported protocol features from the chain - supported_features = get_supported_protocol_features(); + results.names += name; + results.names += "\n"; + results.digests.emplace(name, digest); + } - std::string description = "The name, one of below (lowercase also works):\n" + supported_features.names; + return results; +}; + +struct activate_subcommand { + string feature_name_str; + std::string account_str = "eosio"; + std::string permission_str = "eosio"; + + activate_subcommand(CLI::App* actionRoot) { auto activate = actionRoot->add_subcommand("activate", localized("Activate protocol feature by name")); - activate->add_option("feature", feature_name_str, localized(description.c_str()))->required(); + activate->add_option("feature", feature_name_str, localized("The name, can be found from \"cleos get supported_protoctol_features\" command"))->required(); activate->add_option("-a,--account", account_str, localized("The contract account name, default is eosio")); activate->add_option("-p,--permission", permission_str, localized("The permission level to authorize, default is eosio")); activate->fallthrough(false); @@ -2347,11 +2344,13 @@ struct activate_subcommand { std::locale loc; vector permissions = { permission_str }; for(auto & c : feature_name_str) c = std::toupper(c, loc); + protocol_features_t supported_features; + supported_features = get_supported_protocol_features(); if( supported_features.digests.find(feature_name_str) != supported_features.digests.end() ){ std::string digest = supported_features.digests[feature_name_str]; data = "[\"" + digest + "\"]"; } else { - std::cout << feature_name_str << " not supported. Use -h to find out supported protocol features" << std::endl; + std::cout << feature_name_str << " not known. Use \"cleos get supported_protocol_features\" to find supported protocol features." << std::endl; return; } fc::variant action_args_var; @@ -3295,6 +3294,13 @@ int main( int argc, char** argv ) { get_schedule_subcommand{get}; auto getTransactionId = get_transaction_id_subcommand{get}; + // get supported_protocol_features + get->add_subcommand("supported_protocol_features", localized("Get supported protocol features"))->callback([] { + protocol_features_t supported_features; + supported_features = get_supported_protocol_features(); + std::cout << supported_features.names << std::endl; + }); + // set subcommand auto setSubcommand = app.add_subcommand("set", localized("Set or update blockchain state")); setSubcommand->require_subcommand(); From 26d02d53ef7d067d1b52b3ba03552006149ca950 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Sat, 16 Jul 2022 07:41:51 -0400 Subject: [PATCH 7/7] print out supported protocol features if the protocol feature to be activated is unknown --- programs/cleos/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 713541ae7a..6da6436c06 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -2350,7 +2350,8 @@ struct activate_subcommand { std::string digest = supported_features.digests[feature_name_str]; data = "[\"" + digest + "\"]"; } else { - std::cout << feature_name_str << " not known. Use \"cleos get supported_protocol_features\" to find supported protocol features." << std::endl; + std::cerr << feature_name_str << " is unknown. Following protocol features are supported" << std::endl << std::endl; + std::cerr << supported_features.names << std::endl; return; } fc::variant action_args_var;