From 727bd4420dd5570ba9e6d4e18d8bf6ea8380e3a5 Mon Sep 17 00:00:00 2001 From: Jingjun Zhao Date: Tue, 14 Dec 2021 11:26:40 -0500 Subject: [PATCH 01/18] Add test cases for cleos new option --abi-file --- tests/cli_test.py | 269 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 263 insertions(+), 6 deletions(-) diff --git a/tests/cli_test.py b/tests/cli_test.py index bed27a34ae..5f304caa8c 100755 --- a/tests/cli_test.py +++ b/tests/cli_test.py @@ -6,7 +6,10 @@ import subprocess import re - +import os +import time +import shutil +import signal def nodeos_help_test(): """Test that nodeos help contains option descriptions""" @@ -38,7 +41,7 @@ def cli11_bugfix_test(): # Make sure that the command failed because of the connection error, # not the command line parsing error. - assert(b'Failed http request to nodeos' in completed_process.stderr) + assert(b'Failed to connect to nodeos' in completed_process.stderr) def cli11_optional_option_arg_test(): @@ -56,7 +59,6 @@ def cli11_optional_option_arg_test(): '-c', chain, '-k', key, '{}']) assert(b'signatures' in output) - def cleos_sign_test(): """Test that sign can on both regular and packed transactions""" chain = 'cf057bbfb72640471fd910bcb67639c22df9f92470936cddc1ade0e2f2e7dc4f' @@ -87,7 +89,7 @@ def cleos_sign_test(): '"context_free_data": []' '}') - output = subprocess.check_output(['./programs/cleos/cleos', '--no-auto-keosd', 'sign', + output = subprocess.check_output(['./programs/cleos/cleos', 'sign', '-c', chain, '-k', key, trx]) # make sure it is signed assert(b'signatures' in output) @@ -105,7 +107,7 @@ def cleos_sign_test(): # Test packed transaction is unpacked. Only with options --print-request and --public-key # the sign request is dumped to stderr. - cmd = ['./programs/cleos/cleos', '--print-request', '--no-auto-keosd', 'sign', '-c', chain, '--public-key', 'EOS8Dq1KosJ9PMn1vKQK3TbiihgfUiDBUsz471xaCE6eYUssPB1KY', packed_trx] + cmd = ['./programs/cleos/cleos', '--print-request', 'sign', '-c', chain, '--public-key', 'EOS8Dq1KosJ9PMn1vKQK3TbiihgfUiDBUsz471xaCE6eYUssPB1KY', packed_trx] outs=None errs=None try: @@ -125,12 +127,267 @@ def cleos_sign_test(): assert(b'"data": "000000000000a6690000000000ea305501000000000000000453595300000000016d"' in errs) # Test packed transaction is signed. - output = subprocess.check_output(['./programs/cleos/cleos', '--no-auto-keosd', 'sign', + output = subprocess.check_output(['./programs/cleos/cleos', 'sign', '-c', chain, '-k', key, packed_trx]) # Make sure signatures not empty assert(b'signatures' in output) assert(b'"signatures": []' not in output) +def processCleosCommand(cmd): + outs = None + errs = None + try: + popen=subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + outs, errs = popen.communicate() + popen.wait() + except subprocess.CalledProcessError as ex: + print(ex.output) + return outs, errs + +def cleos_abi_file_test(): + """Test option --abi-file """ + token_abi_path = os.path.abspath(os.getcwd() + '/../unittests/contracts/eosio.token/eosio.token.abi') + system_abi_path = os.path.abspath(os.getcwd() + '/../unittests/contracts/eosio.system/eosio.system.abi') + token_abi_file_arg = 'eosio.token' + ':' + token_abi_path + system_abi_file_arg = 'eosio' + ':' + system_abi_path + + # no option --abi-file + account = 'eosio.token' + action = 'transfer' + unpacked_action_data = '{"from":"aaa","to":"bbb","quantity":"10.0000 SYS","memo":"hello"}' + # use URL http://127.0.0.1:12345 to make sure cleos not to connect to any running nodeos + cmd = ['./programs/cleos/cleos', '-u', 'http://127.0.0.1:12345', 'convert', 'pack_action_data', account, action, unpacked_action_data] + outs, errs = processCleosCommand(cmd) + assert(b'Failed to connect to nodeos' in errs) + + # invalid option --abi-file + invalid_abi_arg = 'eosio.token' + ' ' + token_abi_path + cmd = ['./programs/cleos/cleos', '-u', 'http://127.0.0.1:12345', '--abi-file', invalid_abi_arg, 'convert', 'pack_action_data', account, action, unpacked_action_data] + outs, errs = processCleosCommand(cmd) + assert(b'please specify --abi-file in form of :.' in errs) + + # pack token transfer data + account = 'eosio.token' + action = 'transfer' + unpacked_action_data = '{"from":"aaa","to":"bbb","quantity":"10.0000 SYS","memo":"hello"}' + packed_action_data = '0000000000008c31000000000000ce39a08601000000000004535953000000000568656c6c6f' + cmd = ['./programs/cleos/cleos', '-u','http://127.0.0.1:12345', '--abi-file', token_abi_file_arg, 'convert', 'pack_action_data', account, action, unpacked_action_data] + outs, errs = processCleosCommand(cmd) + actual = outs.strip() + assert(actual.decode('utf-8') == packed_action_data) + + # unpack token transfer data + cmd = ['./programs/cleos/cleos', '-u','http://127.0.0.1:12345', '--abi-file', token_abi_file_arg, 'convert', 'unpack_action_data', account, action, packed_action_data] + outs, errs = processCleosCommand(cmd) + assert(b'"from": "aaa"' in outs) + assert(b'"to": "bbb"' in outs) + assert(b'"quantity": "10.0000 SYS"' in outs) + assert(b'"memo": "hello"' in outs) + + # pack account create data + account = 'eosio' + action = 'newaccount' + + unpacked_action_data = """{ + "creator": "eosio", + "name": "bob", + "owner": { + "threshold": 1, + "keys": [{ + "key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + }, + "active": { + "threshold": 1, + "keys": [{ + "key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + } + }""" + + cmd = ['./programs/cleos/cleos', '-u','http://127.0.0.1:12345', '--abi-file', system_abi_file_arg, 'convert', 'pack_action_data', account, action, unpacked_action_data] + packed_action_data = '0000000000ea30550000000000000e3d01000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf0100000001000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf01000000' + outs, errs = processCleosCommand(cmd) + actual = outs.strip() + assert(actual.decode('utf-8') == packed_action_data) + + # unpack account create data + cmd = ['./programs/cleos/cleos', '-u','http://127.0.0.1:12345', '--abi-file', system_abi_file_arg, 'convert', 'unpack_action_data', account, action, packed_action_data] + outs, errs = processCleosCommand(cmd) + assert(b'"creator": "eosio"' in outs) + assert(b'"name": "bob"' in outs) + + # pack transaction + unpacked_trx = """{ + "expiration": "2021-07-18T04:21:14", + "ref_block_num": 494, + "ref_block_prefix": 2118878731, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ + "account": "eosio", + "name": "newaccount", + "authorization": [{ + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "creator": "eosio", + "name": "bob", + "owner": { + "threshold": 1, + "keys": [{ + "key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + }, + "active": { + "threshold": 1, + "keys": [{ + "key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + } + }, + "hex_data": "0000000000ea30550000000000000e3d01000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf0100000001000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf01000000" + }, + { + "account": "eosio.token", + "name": "transfer", + "authorization": [{ + "actor": "aaa", + "permission": "active" + } + ], + "data": { + "from": "aaa", + "to": "bbb", + "quantity": "10.0000 SYS", + "memo": "hello" + }, + "hex_data": "0000000000008c31000000000000ce39a08601000000000004535953000000000568656c6c6f" + } + ], + "signatures": [ + "SIG_K1_K3LfbB7ZV2DNBu67iSn3yUMseTdiwoT49gAcwSZVT1QTvGXVHjkcvKqhentCW4FJngZJ1H9gBRSWgo9UPiWEXWHyKpXNCZ" + ], + "context_free_data": [] + }""" + + expected_output = b'3aacf360ee010b864b7e00000000020000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232660000000000ea30550000000000000e3d01000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf0100000001000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf0100000000a6823403ea3055000000572d3ccdcd010000000000008c3100000000a8ed3232260000000000008c31000000000000ce39a08601000000000004535953000000000568656c6c6f00' + cmd = ['./programs/cleos/cleos', '-u','http://127.0.0.1:12345', '--abi-file', system_abi_file_arg, token_abi_file_arg, 'convert', 'pack_transaction', '--pack-action-data', unpacked_trx] + outs, errs = processCleosCommand(cmd) + assert(expected_output in outs) + + # unpack transaction + packed_trx = """{ + "signatures": [ + "SIG_K1_K3LfbB7ZV2DNBu67iSn3yUMseTdiwoT49gAcwSZVT1QTvGXVHjkcvKqhentCW4FJngZJ1H9gBRSWgo9UPiWEXWHyKpXNCZ" + ], + "compression": "none", + "packed_context_free_data": "", + "packed_trx": "3aacf360ee010b864b7e00000000020000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232660000000000ea30550000000000000e3d01000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf0100000001000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf0100000000a6823403ea3055000000572d3ccdcd010000000000008c3100000000a8ed3232260000000000008c31000000000000ce39a08601000000000004535953000000000568656c6c6f00" + }""" + cmd = ['./programs/cleos/cleos', '-u','http://127.0.0.1:12345', '--abi-file', system_abi_file_arg, token_abi_file_arg, 'convert', 'unpack_transaction', '--unpack-action-data', packed_trx] + outs, errs = processCleosCommand(cmd) + assert(b'"creator": "eosio"' in outs) + assert(b'"name": "bob"' in outs) + + assert(b'"from": "aaa"' in outs) + assert(b'"to": "bbb"' in outs) + assert(b'"quantity": "10.0000 SYS"' in outs) + assert(b'"memo": "hello"' in outs) + + # push action token transfer with option `--abi-file` + try: + data_dir = "./taf_data" + cmd = "./programs/nodeos/nodeos -e -p eosio --plugin eosio::producer_plugin --plugin eosio::producer_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::chain_plugin --plugin eosio::http_plugin --access-control-allow-origin=* --http-validate-host=false " + "--data-dir " + data_dir + pNodeos = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + time.sleep(10) + + PUBLIC_KEY = "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" + PRIVATE_KEY = "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3" + + wallet_name = "taf_wallet" + cmd = "./programs/cleos/cleos wallet create --name " + wallet_name + " --to-console" + pWallet = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) + cmd = "./programs/cleos/cleos wallet import --name " + wallet_name + " --private-key " + PRIVATE_KEY + processCleosCommand(cmd.split()) + + accounts = ["eosio.token", "alice", "bob"] + for account in accounts: + cmd = "./programs/cleos/cleos get account -j " + account + outs, errs = processCleosCommand(cmd.split()) + str = '"account_name"' + ': ' + '"' + account + '"' + if str not in outs.decode('utf-8'): + cmd = "./programs/cleos/cleos -u http://127.0.0.1:8888 create account eosio " + account + " " + PUBLIC_KEY + outs, errs = processCleosCommand(cmd.split()) + + cmd = "./programs/cleos/cleos set contract eosio.token " + os.path.abspath(os.getcwd() + "/../unittests/contracts/eosio.token") + " " + "--abi " + "eosio.token.abi -p eosio.token@active" + processCleosCommand(cmd.split()) + cmd = ['./programs/cleos/cleos', 'push', 'action', 'eosio.token', 'create', '[ "alice", "1000000000.0000 SYS" ]', '-p', 'eosio.token'] + processCleosCommand(cmd) + cmd = ['./programs/cleos/cleos', 'push', 'action', 'eosio.token', 'issue', '[ "alice", "100.0000 SYS", "memo" ]', '-p', 'alice'] + processCleosCommand(cmd) + + # make a malicious abi file by switching 'from' and 'to' in eosio.token.abi + malicious_token_abi_path = os.path.abspath(os.getcwd() + '/../unittests/contracts/eosio.token/malicious.eosio.token.abi') + shutil.copyfile(token_abi_path, malicious_token_abi_path) + replaces = [["from", "malicious"], ["to", "from"], ["malicious", "to"]] + for replace in replaces: + with open(malicious_token_abi_path, 'r+') as f: + abi = f.read() + abi = re.sub(replace[0], replace[1], abi) + f.seek(0) + f.write(abi) + f.truncate() + + # set the malicious abi + cmd = "./programs/cleos/cleos set abi eosio.token " + malicious_token_abi_path + processCleosCommand(cmd.split()) + + # option '--abi-file' makes token still be transferred from alice to bob after setting the malicious abi + cmd = ['./programs/cleos/cleos', '-u', 'http://127.0.0.1:8888', '--print-request', '--abi-file', token_abi_file_arg, 'push', 'action', 'eosio.token', 'transfer', '{ "from":"alice", "to":"bob", "quantity":"25.0000 SYS", "memo":"m" }', '-p', 'alice'] + outs, errs = processCleosCommand(cmd) + assert(b'"/v1/chain/get_raw_abi"' not in errs) + cmd = "./programs/cleos/cleos get currency balance eosio.token alice SYS" + outs, errs = processCleosCommand(cmd.split()) + assert(outs.strip().decode('utf-8') == "75.0000 SYS") + + finally: + + if pNodeos.pid: + os.kill(pNodeos.pid, signal.SIGKILL) + shutil.rmtree(data_dir) + + if pWallet.pid: + os.kill(pWallet.pid, signal.SIGKILL) + subprocess.call(("pkill -9 keosd").split()) + wallet_file = os.path.expanduser('~') + "/eosio-wallet/" + wallet_name + ".wallet" + if os.path.exists(wallet_file): + os.remove(wallet_file) + + if os.path.exists(malicious_token_abi_path): + os.remove(malicious_token_abi_path) + nodeos_help_test() cleos_help_test(['--help']) From a39dcb92ea920966e8009c1413c97e8b1758ec9c Mon Sep 17 00:00:00 2001 From: DU Jiaen <37097018+taokayan@users.noreply.github.com> Date: Thu, 21 Oct 2021 10:02:26 +0800 Subject: [PATCH 02/18] Merge pull request #10821 from EOSIO/kayan_cleos_local_abi_file Add ability to specify one or more local abi files for cleos for serialzation/deserialization offline --- programs/cleos/main.cpp | 77 ++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index de4e0364f4..d0ef24b50f 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -94,22 +94,12 @@ Usage: ./cleos create account [OPTIONS] creator name OwnerKey ActiveKey #include #include #include -#include -#include #include #include -#include #include -#include #pragma pop_macro("N") -#include -#include -#include -#include -#include - #include #define CLI11_HAS_FILESYSTEM 0 @@ -162,9 +152,10 @@ std::string clean_output( std::string str ) { return fc::escape_string( str, nullptr, escape_control_chars ); } -string url = "http://127.0.0.1:8888/"; +string default_url = "http://127.0.0.1:8888/"; string default_wallet_url = "unix://" + (determine_home_directory() / "eosio-wallet" / (string(key_store_executable_name) + ".sock")).string(); string wallet_url; //to be set to default_wallet_url in main +std::map abi_files_override; bool no_verify = false; vector headers; @@ -280,7 +271,8 @@ class signing_keys_option { try { std::vector keys = json_keys.template as>(); signing_keys = std::move(keys); - } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid public key array format '${data}'", ("data", fc::json::to_string(json_keys, fc::time_point::maximum()))) + } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid public key array format '${data}'", + ("data", fc::json::to_string(json_keys, fc::time_point::maximum()))) } } return signing_keys; @@ -326,7 +318,7 @@ fc::variant call( const std::string& url, } catch(boost::system::system_error& e) { std::string exec_name; - if(url == ::url) { + if(url == ::default_url) { exec_name = node_executable_name; } else if(url == ::wallet_url) { exec_name = key_store_executable_name; @@ -340,14 +332,14 @@ fc::variant call( const std::string& url, template fc::variant call( const std::string& path, - const T& v ) { return call( url, path, fc::variant(v) ); } + const T& v ) { return call( default_url, path, fc::variant( v) ); } template<> fc::variant call( const std::string& url, const std::string& path) { return call( url, path, fc::variant() ); } eosio::chain_apis::read_only::get_info_results get_info() { - return call(url, get_info_func).as(); + return call(default_url, get_info_func).as(); } string generate_nonce_string() { @@ -358,30 +350,34 @@ chain::action generate_nonce_action() { return chain::action( {}, config::null_account_name, name("nonce"), fc::raw::pack(fc::time_point::now().time_since_epoch().count())); } -auto abi_serializer_resolver_empty = [](const name& account) -> std::optional { - return std::optional(); -}; - //resolver for ABI serializer to decode actions in proposed transaction in multisig contract auto abi_serializer_resolver = [](const name& account) -> std::optional { - static unordered_map > abi_cache; - auto it = abi_cache.find( account ); - if ( it == abi_cache.end() ) { + static unordered_map > abi_cache; + auto it = abi_cache.find( account ); + if ( it == abi_cache.end() ) { + + std::optional abis; + if (abi_files_override.find(account) != abi_files_override.end()) { + abis.emplace( fc::json::from_file(abi_files_override[account]).as(), abi_serializer::create_yield_function( abi_serializer_max_time )); + } else { const auto raw_abi_result = call(get_raw_abi_func, fc::mutable_variant_object("account_name", account)); const auto raw_abi_blob = raw_abi_result["abi"].as_blob().data; - - std::optional abis; if (raw_abi_blob.size() != 0) { - abis.emplace(fc::raw::unpack(raw_abi_blob), abi_serializer_max_time); + abis.emplace(fc::raw::unpack(raw_abi_blob), abi_serializer::create_yield_function( abi_serializer_max_time )); } else { - std::cerr << "ABI for contract " << account.to_string() << " not found. Action data will be shown in hex only." << std::endl; + std::cerr << "ABI for contract " << account.to_string() << " not found. Action data will be shown in hex only." << std::endl; } - abi_cache.emplace( account, abis ); + } + abi_cache.emplace( account, abis ); - return abis; - } + return abis; + } + + return it->second; +}; - return it->second; +auto abi_serializer_resolver_empty = [](const name& account) -> std::optional { + return std::optional(); }; void prompt_for_wallet_password(string& pw, const string& name) { @@ -1011,7 +1007,7 @@ struct set_action_permission_subcommand { string requirementStr; set_action_permission_subcommand(CLI::App* actionRoot) { - auto permissions = actionRoot->add_subcommand("permission", localized("set parmaters dealing with account permissions")); + auto permissions = actionRoot->add_subcommand("permission", localized("Set paramaters dealing with account permissions")); permissions->add_option("account", accountStr, localized("The account to set/delete a permission authority for"))->required(); permissions->add_option("code", codeStr, localized("The account that owns the code for the action"))->required(); permissions->add_option("type", typeStr, localized("The type of the action"))->required(); @@ -1213,7 +1209,7 @@ struct create_account_subcommand { if( active_key_str.empty() ) { active = owner; - } else if ( active_key_str.find('{') != string::npos ) { + } else if ( active_key_str.find('{') != string::npos ) { try{ active = parse_json_authority_or_key(active_key_str); } EOS_RETHROW_EXCEPTIONS( explained_exception, "Invalid active authority: ${authority}", ("authority", owner_key_str) ) @@ -2583,7 +2579,9 @@ CLI::callback_t header_opt_callback = [](CLI::results_t res) { return true; }; + int main( int argc, char** argv ) { + fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::debug); context = eosio::client::http::create_http_context(); wallet_url = default_wallet_url; @@ -2596,7 +2594,7 @@ int main( int argc, char** argv ) { app.add_option( "--wallet-host", obsoleted_option_host_port, localized("The host where ${k} is running", ("k", key_store_executable_name)) )->group(""); app.add_option( "--wallet-port", obsoleted_option_host_port, localized("The port where ${k} is running", ("k", key_store_executable_name)) )->group(""); - app.add_option( "-u,--url", url, localized("The http/https URL where ${n} is running", ("n", node_executable_name)), true ); + app.add_option( "-u,--url", default_url, localized( "The http/https URL where ${n} is running", ("n", node_executable_name)), true ); app.add_option( "--wallet-url", wallet_url, localized("The http/https URL where ${k} is running", ("k", key_store_executable_name)), true ); app.add_option( "-r,--header", header_opt_callback, localized("Pass specific HTTP header; repeat this option to pass multiple headers")); @@ -2737,7 +2735,7 @@ int main( int argc, char** argv ) { }); // validate subcommand - auto validate = app.add_subcommand("validate", localized("Validate transactions")); + auto validate = app.add_subcommand("validate", localized("Validate transactions")); validate->require_subcommand(); // validate signatures @@ -3363,6 +3361,7 @@ int main( int argc, char** argv ) { string amount; string memo; bool pay_ram = false; + auto transfer = app.add_subcommand("transfer", localized("Transfer tokens from account to account")); transfer->add_option("sender", sender, localized("The account sending tokens"))->required(); transfer->add_option("recipient", recipient, localized("The account receiving tokens"))->required(); @@ -3396,27 +3395,27 @@ int main( int argc, char** argv ) { auto connect = net->add_subcommand("connect", localized("Start a new connection to a peer")); connect->add_option("host", new_host, localized("The hostname:port to connect to."))->required(); connect->callback([&] { - const auto& v = call(url, net_connect, new_host); + const auto& v = call(default_url, net_connect, new_host); std::cout << fc::json::to_pretty_string(v) << std::endl; }); auto disconnect = net->add_subcommand("disconnect", localized("Close an existing connection")); disconnect->add_option("host", new_host, localized("The hostname:port to disconnect from."))->required(); disconnect->callback([&] { - const auto& v = call(url, net_disconnect, new_host); + const auto& v = call(default_url, net_disconnect, new_host); std::cout << fc::json::to_pretty_string(v) << std::endl; }); auto status = net->add_subcommand("status", localized("Status of existing connection")); status->add_option("host", new_host, localized("The hostname:port to query status of connection"))->required(); status->callback([&] { - const auto& v = call(url, net_status, new_host); + const auto& v = call(default_url, net_status, new_host); std::cout << fc::json::to_pretty_string(v) << std::endl; }); auto connections = net->add_subcommand("peers", localized("Status of all existing peers")); connections->callback([&] { - const auto& v = call(url, net_connections); + const auto& v = call(default_url, net_connections); std::cout << fc::json::to_pretty_string(v) << std::endl; }); @@ -4099,7 +4098,7 @@ int main( int argc, char** argv ) { auto cancel = msig->add_subcommand("cancel", localized("Cancel proposed transaction")); add_standard_transaction_options_plus_signing(cancel, "canceler@active"); cancel->add_option("proposer", proposer, localized("The proposer name (string)"))->required(); - cancel->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); + cancel->add_option("proposal_name", proposal_name, localized("The proposal name (string)"))->required(); cancel->add_option("canceler", canceler, localized("The canceler name (string)")); cancel->callback([&]() { auto accountPermissions = get_account_permissions(tx_permission); From 38f46a6f29025c5bdf416a6c6867ca2dc34c815e Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Wed, 20 Jul 2022 21:04:27 -0500 Subject: [PATCH 03/18] Fix merge problem. --- tests/cli_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cli_test.py b/tests/cli_test.py index 5f304caa8c..f65190a8f6 100755 --- a/tests/cli_test.py +++ b/tests/cli_test.py @@ -89,7 +89,7 @@ def cleos_sign_test(): '"context_free_data": []' '}') - output = subprocess.check_output(['./programs/cleos/cleos', 'sign', + output = subprocess.check_output(['./programs/cleos/cleos', '--no-auto-keosd', 'sign', '-c', chain, '-k', key, trx]) # make sure it is signed assert(b'signatures' in output) From a0f59c37abbff8f9c1263e0a5c5e0488719f54ba Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Wed, 20 Jul 2022 22:50:43 -0500 Subject: [PATCH 04/18] Fix whitespace and scoping. --- programs/cleos/main.cpp | 50 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index d0ef24b50f..3e4082a60a 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -332,14 +332,14 @@ fc::variant call( const std::string& url, template fc::variant call( const std::string& path, - const T& v ) { return call( default_url, path, fc::variant( v) ); } + const T& v ) { return call( ::default_url, path, fc::variant( v) ); } template<> fc::variant call( const std::string& url, const std::string& path) { return call( url, path, fc::variant() ); } eosio::chain_apis::read_only::get_info_results get_info() { - return call(default_url, get_info_func).as(); + return call(::default_url, get_info_func).as(); } string generate_nonce_string() { @@ -352,28 +352,26 @@ chain::action generate_nonce_action() { //resolver for ABI serializer to decode actions in proposed transaction in multisig contract auto abi_serializer_resolver = [](const name& account) -> std::optional { - static unordered_map > abi_cache; - auto it = abi_cache.find( account ); - if ( it == abi_cache.end() ) { - - std::optional abis; - if (abi_files_override.find(account) != abi_files_override.end()) { - abis.emplace( fc::json::from_file(abi_files_override[account]).as(), abi_serializer::create_yield_function( abi_serializer_max_time )); - } else { - const auto raw_abi_result = call(get_raw_abi_func, fc::mutable_variant_object("account_name", account)); - const auto raw_abi_blob = raw_abi_result["abi"].as_blob().data; - if (raw_abi_blob.size() != 0) { - abis.emplace(fc::raw::unpack(raw_abi_blob), abi_serializer::create_yield_function( abi_serializer_max_time )); + static unordered_map > abi_cache; + auto it = abi_cache.find( account ); + if ( it == abi_cache.end() ) { + std::optional abis; + if (abi_files_override.find(account) != abi_files_override.end()) { + abis.emplace( fc::json::from_file(abi_files_override[account]).as(), abi_serializer::create_yield_function( abi_serializer_max_time )); } else { - std::cerr << "ABI for contract " << account.to_string() << " not found. Action data will be shown in hex only." << std::endl; + const auto raw_abi_result = call(get_raw_abi_func, fc::mutable_variant_object("account_name", account)); + const auto raw_abi_blob = raw_abi_result["abi"].as_blob().data; + if (raw_abi_blob.size() != 0) { + abis.emplace(fc::raw::unpack(raw_abi_blob), abi_serializer::create_yield_function( abi_serializer_max_time )); + } else { + std::cerr << "ABI for contract " << account.to_string() << " not found. Action data will be shown in hex only." << std::endl; + } } - } - abi_cache.emplace( account, abis ); + abi_cache.emplace( account, abis ); - return abis; - } - - return it->second; + return abis; + } + return it->second; }; auto abi_serializer_resolver_empty = [](const name& account) -> std::optional { @@ -2594,7 +2592,7 @@ int main( int argc, char** argv ) { app.add_option( "--wallet-host", obsoleted_option_host_port, localized("The host where ${k} is running", ("k", key_store_executable_name)) )->group(""); app.add_option( "--wallet-port", obsoleted_option_host_port, localized("The port where ${k} is running", ("k", key_store_executable_name)) )->group(""); - app.add_option( "-u,--url", default_url, localized( "The http/https URL where ${n} is running", ("n", node_executable_name)), true ); + app.add_option( "-u,--url", ::default_url, localized( "The http/https URL where ${n} is running", ("n", node_executable_name)), true ); app.add_option( "--wallet-url", wallet_url, localized("The http/https URL where ${k} is running", ("k", key_store_executable_name)), true ); app.add_option( "-r,--header", header_opt_callback, localized("Pass specific HTTP header; repeat this option to pass multiple headers")); @@ -3395,27 +3393,27 @@ int main( int argc, char** argv ) { auto connect = net->add_subcommand("connect", localized("Start a new connection to a peer")); connect->add_option("host", new_host, localized("The hostname:port to connect to."))->required(); connect->callback([&] { - const auto& v = call(default_url, net_connect, new_host); + const auto& v = call(::default_url, net_connect, new_host); std::cout << fc::json::to_pretty_string(v) << std::endl; }); auto disconnect = net->add_subcommand("disconnect", localized("Close an existing connection")); disconnect->add_option("host", new_host, localized("The hostname:port to disconnect from."))->required(); disconnect->callback([&] { - const auto& v = call(default_url, net_disconnect, new_host); + const auto& v = call(::default_url, net_disconnect, new_host); std::cout << fc::json::to_pretty_string(v) << std::endl; }); auto status = net->add_subcommand("status", localized("Status of existing connection")); status->add_option("host", new_host, localized("The hostname:port to query status of connection"))->required(); status->callback([&] { - const auto& v = call(default_url, net_status, new_host); + const auto& v = call(::default_url, net_status, new_host); std::cout << fc::json::to_pretty_string(v) << std::endl; }); auto connections = net->add_subcommand("peers", localized("Status of all existing peers")); connections->callback([&] { - const auto& v = call(default_url, net_connections); + const auto& v = call(::default_url, net_connections); std::cout << fc::json::to_pretty_string(v) << std::endl; }); From 014fe70c10c95ef97212df5963ce3157b39e3671 Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Thu, 21 Jul 2022 15:08:39 -0500 Subject: [PATCH 05/18] Fix merge problem. --- programs/cleos/main.cpp | 2 +- tests/cli_test.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 9071bc76ee..0d71ea55c5 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -341,7 +341,7 @@ fc::variant call( const std::string& url, const std::string& path) { return call( url, path, fc::variant() ); } eosio::chain_apis::read_only::get_consensus_parameters_results get_consensus_parameters() { - return call(url, get_consensus_parameters_func).as(); + return call(::default_url, get_consensus_parameters_func).as(); } eosio::chain_apis::read_only::get_info_results get_info() { diff --git a/tests/cli_test.py b/tests/cli_test.py index f65190a8f6..5e6ff584ee 100755 --- a/tests/cli_test.py +++ b/tests/cli_test.py @@ -107,7 +107,7 @@ def cleos_sign_test(): # Test packed transaction is unpacked. Only with options --print-request and --public-key # the sign request is dumped to stderr. - cmd = ['./programs/cleos/cleos', '--print-request', 'sign', '-c', chain, '--public-key', 'EOS8Dq1KosJ9PMn1vKQK3TbiihgfUiDBUsz471xaCE6eYUssPB1KY', packed_trx] + cmd = ['./programs/cleos/cleos', '--print-request', '--no-auto-keosd', 'sign', '-c', chain, '--public-key', 'EOS8Dq1KosJ9PMn1vKQK3TbiihgfUiDBUsz471xaCE6eYUssPB1KY', packed_trx] outs=None errs=None try: @@ -127,7 +127,7 @@ def cleos_sign_test(): assert(b'"data": "000000000000a6690000000000ea305501000000000000000453595300000000016d"' in errs) # Test packed transaction is signed. - output = subprocess.check_output(['./programs/cleos/cleos', 'sign', + output = subprocess.check_output(['./programs/cleos/cleos', '--no-auto-keosd', 'sign', '-c', chain, '-k', key, packed_trx]) # Make sure signatures not empty assert(b'signatures' in output) From 5e7b64230e19821ee5600c6010a02a6a02876456 Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Thu, 21 Jul 2022 15:14:47 -0500 Subject: [PATCH 06/18] Add optional no ccache Github workflow. Use [no-ccache] in PR text. --- .github/workflows/ubuntu-2004.yml | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/.github/workflows/ubuntu-2004.yml b/.github/workflows/ubuntu-2004.yml index 13ca5bcf84..2368811ca3 100644 --- a/.github/workflows/ubuntu-2004.yml +++ b/.github/workflows/ubuntu-2004.yml @@ -15,6 +15,13 @@ jobs: name: Ubuntu 20.04 | Build runs-on: ubuntu-latest steps: + - name: no-ccache + id: no-ccache + uses: saulmaldonado/skip-workflow@v1 + with: + search: '["pull_request"]' + pr-message: 'body' + phrase: '[no-ccache]' - name: Timestamp id: ccache_cache_timestamp shell: cmake -P {0} @@ -27,6 +34,7 @@ jobs: submodules: recursive fetch-depth: 0 - name: Preserve ccache + if: ${{ !steps.no-ccache.outputs.skip }} uses: actions/cache@v1.1.0 with: path: .ccache @@ -34,6 +42,7 @@ jobs: restore-keys: | $ubuntu-20.04-ccache_make- - name: Build + if: ${{ !steps.no-ccache.outputs.skip }} run: | set -e export CCACHE_DIR=${GITHUB_WORKSPACE}/.ccache @@ -63,6 +72,29 @@ jobs: echo ===== tar -pczf build.tar.gz build tar -pczf usr_local.tar.gz installed + - name: Build without ccache + if: ${{ steps.no-ccache.outputs.skip }} + run: | + set -e + export DOCKER="docker run --rm -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} -w ${GITHUB_WORKSPACE} --user $(id -u):$(id -g) ${UBUNTU_2004_IMAGE}" + export DOCKER_ROOT="docker run --rm -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} -w ${GITHUB_WORKSPACE} ${UBUNTU_2004_IMAGE}" + docker pull ${UBUNTU_2004_IMAGE} + echo ===== + mkdir build + ${DOCKER} bash -c "cd build && cmake -DCMAKE_BUILD_TYPE=Release .." + echo ===== + ${DOCKER} bash -c "cd build && make -j $(nproc)" + echo ===== + mkdir install + ${DOCKER_ROOT} bash -c "cd build && DESTDIR=${GITHUB_WORKSPACE}/installed make -j $(nproc) dev-install" + echo ===== + ls -la ${GITHUB_WORKSPACE} + echo ===== + ${DOCKER} build/bin/nodeos --version + ${DOCKER} build/bin/nodeos --full-version + echo ===== + tar -pczf build.tar.gz build + tar -pczf usr_local.tar.gz installed - name: Upload build uses: actions/upload-artifact@v1 with: From a225514e09d37e196783d140eb4c00d0b8a5aa88 Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Thu, 21 Jul 2022 15:18:20 -0500 Subject: [PATCH 07/18] Add required token to search PR text in Github workflow. --- .github/workflows/ubuntu-2004.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ubuntu-2004.yml b/.github/workflows/ubuntu-2004.yml index 2368811ca3..76f653d032 100644 --- a/.github/workflows/ubuntu-2004.yml +++ b/.github/workflows/ubuntu-2004.yml @@ -19,6 +19,7 @@ jobs: id: no-ccache uses: saulmaldonado/skip-workflow@v1 with: + github-token: ${{ secrets.GITHUB_TOKEN }} search: '["pull_request"]' pr-message: 'body' phrase: '[no-ccache]' From 592c440c035b2c0e410a0b9aa0bbfcc5c41ea9f7 Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Thu, 21 Jul 2022 15:46:39 -0500 Subject: [PATCH 08/18] Forcefully uncache CMAKE_C[XX]_COMPILER_LAUNCHER cmake variables. --- .github/workflows/ubuntu-2004.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ubuntu-2004.yml b/.github/workflows/ubuntu-2004.yml index 76f653d032..8d10d86a8f 100644 --- a/.github/workflows/ubuntu-2004.yml +++ b/.github/workflows/ubuntu-2004.yml @@ -82,7 +82,7 @@ jobs: docker pull ${UBUNTU_2004_IMAGE} echo ===== mkdir build - ${DOCKER} bash -c "cd build && cmake -DCMAKE_BUILD_TYPE=Release .." + ${DOCKER} bash -c "cd build && cmake -DCMAKE_BUILD_TYPE=Release -UCMAKE_CXX_COMPILER_LAUNCHER -UCMAKE_C_COMPILER_LAUNCHER .." echo ===== ${DOCKER} bash -c "cd build && make -j $(nproc)" echo ===== From b034c5652e695504c76fe148cb4ebc23ceebcc07 Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Thu, 21 Jul 2022 17:40:03 -0500 Subject: [PATCH 09/18] Fixes to disabling ccache. --- .github/workflows/ubuntu-2004.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ubuntu-2004.yml b/.github/workflows/ubuntu-2004.yml index 8d10d86a8f..3d4412c594 100644 --- a/.github/workflows/ubuntu-2004.yml +++ b/.github/workflows/ubuntu-2004.yml @@ -77,6 +77,7 @@ jobs: if: ${{ steps.no-ccache.outputs.skip }} run: | set -e + export CCACHE_DISABLE=1 export DOCKER="docker run --rm -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} -w ${GITHUB_WORKSPACE} --user $(id -u):$(id -g) ${UBUNTU_2004_IMAGE}" export DOCKER_ROOT="docker run --rm -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} -w ${GITHUB_WORKSPACE} ${UBUNTU_2004_IMAGE}" docker pull ${UBUNTU_2004_IMAGE} From 02fce4905e930993c20ab0453a4e62badb5c34ba Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Fri, 22 Jul 2022 14:22:56 -0500 Subject: [PATCH 10/18] Make CCACHE_DISABLE visible to docker. --- .github/workflows/ubuntu-2004.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ubuntu-2004.yml b/.github/workflows/ubuntu-2004.yml index 3d4412c594..aacba03607 100644 --- a/.github/workflows/ubuntu-2004.yml +++ b/.github/workflows/ubuntu-2004.yml @@ -78,8 +78,8 @@ jobs: run: | set -e export CCACHE_DISABLE=1 - export DOCKER="docker run --rm -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} -w ${GITHUB_WORKSPACE} --user $(id -u):$(id -g) ${UBUNTU_2004_IMAGE}" - export DOCKER_ROOT="docker run --rm -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} -w ${GITHUB_WORKSPACE} ${UBUNTU_2004_IMAGE}" + export DOCKER="docker run --rm -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} -w ${GITHUB_WORKSPACE} -e CCACHE_DISABLE --user $(id -u):$(id -g) ${UBUNTU_2004_IMAGE}" + export DOCKER_ROOT="docker run --rm -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} -e CCACHE_DISABLE -w ${GITHUB_WORKSPACE} ${UBUNTU_2004_IMAGE}" docker pull ${UBUNTU_2004_IMAGE} echo ===== mkdir build From 0a553b989692603ab18c47e4ba84eff24285086e Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Mon, 25 Jul 2022 14:04:54 -0500 Subject: [PATCH 11/18] Change workflow step label to something human readable. --- .github/workflows/ubuntu-2004.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ubuntu-2004.yml b/.github/workflows/ubuntu-2004.yml index aacba03607..d9c71d22a2 100644 --- a/.github/workflows/ubuntu-2004.yml +++ b/.github/workflows/ubuntu-2004.yml @@ -15,7 +15,7 @@ jobs: name: Ubuntu 20.04 | Build runs-on: ubuntu-latest steps: - - name: no-ccache + - name: Check for ccache disable id: no-ccache uses: saulmaldonado/skip-workflow@v1 with: From c62fa0329bce8058ff348b86085886f8717e7a9d Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Tue, 26 Jul 2022 17:53:39 -0500 Subject: [PATCH 12/18] Update expected error text from cleos in cli_test. --- tests/cli_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cli_test.py b/tests/cli_test.py index 5e6ff584ee..c66cff3a67 100755 --- a/tests/cli_test.py +++ b/tests/cli_test.py @@ -41,7 +41,7 @@ def cli11_bugfix_test(): # Make sure that the command failed because of the connection error, # not the command line parsing error. - assert(b'Failed to connect to nodeos' in completed_process.stderr) + assert(b'Connection refused' in completed_process.stderr) def cli11_optional_option_arg_test(): From 7b47eba942f99683bf4d000b50c7696eba7fb3ee Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Tue, 26 Jul 2022 19:47:22 -0500 Subject: [PATCH 13/18] Fix merge problems. (Which lost the entire point of the change in the confusion.) --- programs/cleos/main.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 0d71ea55c5..3d73abf31c 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -2698,6 +2698,23 @@ CLI::callback_t header_opt_callback = [](CLI::results_t res) { return true; }; +CLI::callback_t abi_files_overide_callback = [](CLI::results_t account_abis) { + for (vector::iterator itr = account_abis.begin(); itr != account_abis.end(); ++itr) { + size_t delim = itr->find(":"); + std::string acct_name, abi_path; + if (delim != std::string::npos) { + acct_name = itr->substr(0, delim); + abi_path = itr->substr(delim + 1); + } + if (acct_name.length() == 0 || abi_path.length() == 0) { + std::cerr << "please specify --abi-file in form of :.\n"; + return false; + } + abi_files_override[name(acct_name)] = abi_path; + } + return true; +}; + int main( int argc, char** argv ) { @@ -2716,6 +2733,7 @@ int main( int argc, char** argv ) { app.add_option( "-u,--url", ::default_url, localized( "The http/https URL where ${n} is running", ("n", node_executable_name)), true ); app.add_option( "--wallet-url", wallet_url, localized("The http/https URL where ${k} is running", ("k", key_store_executable_name)), true ); + app.add_option( "--abi-file", abi_files_overide_callback, localized("In form of :, use a local abi file for serialization and deserialization instead of getting the abi data from the blockchain; repeat this option to pass multiple abi files for different contracts"))->type_size(0, 1000); app.add_option( "-r,--header", header_opt_callback, localized("Pass specific HTTP header; repeat this option to pass multiple headers")); app.add_flag( "-n,--no-verify", no_verify, localized("Don't verify peer certificate when using HTTPS")); app.add_flag( "--no-auto-" + string(key_store_executable_name), no_auto_keosd, localized("Don't automatically launch a ${k} if one is not currently running", ("k", key_store_executable_name))); From e5c026a7bb0eee53d17edbf76b0f941158e687b3 Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Sun, 31 Jul 2022 15:56:20 -0500 Subject: [PATCH 14/18] Replace cleos local abi file test with test harness version. --- tests/cli_test.py | 146 ++++++++++++++++++++++++++++++---------------- 1 file changed, 95 insertions(+), 51 deletions(-) diff --git a/tests/cli_test.py b/tests/cli_test.py index c66cff3a67..8a254fc9c3 100755 --- a/tests/cli_test.py +++ b/tests/cli_test.py @@ -11,6 +11,15 @@ import shutil import signal +from testUtils import Account +from testUtils import Utils +from Cluster import Cluster +from Node import Node +from Node import ReturnType +from WalletMgr import WalletMgr + +testSuccessful=False + def nodeos_help_test(): """Test that nodeos help contains option descriptions""" help_text = subprocess.check_output(["./programs/nodeos/nodeos", "--help"]) @@ -158,12 +167,13 @@ def cleos_abi_file_test(): # use URL http://127.0.0.1:12345 to make sure cleos not to connect to any running nodeos cmd = ['./programs/cleos/cleos', '-u', 'http://127.0.0.1:12345', 'convert', 'pack_action_data', account, action, unpacked_action_data] outs, errs = processCleosCommand(cmd) - assert(b'Failed to connect to nodeos' in errs) + assert(b'Connection refused' in errs) # invalid option --abi-file invalid_abi_arg = 'eosio.token' + ' ' + token_abi_path cmd = ['./programs/cleos/cleos', '-u', 'http://127.0.0.1:12345', '--abi-file', invalid_abi_arg, 'convert', 'pack_action_data', account, action, unpacked_action_data] outs, errs = processCleosCommand(cmd) + print(errs) assert(b'please specify --abi-file in form of :.' in errs) # pack token transfer data @@ -315,40 +325,14 @@ def cleos_abi_file_test(): assert(b'"quantity": "10.0000 SYS"' in outs) assert(b'"memo": "hello"' in outs) +def abi_file_with_nodeos_test(): # push action token transfer with option `--abi-file` + global testSuccessful try: - data_dir = "./taf_data" - cmd = "./programs/nodeos/nodeos -e -p eosio --plugin eosio::producer_plugin --plugin eosio::producer_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::chain_plugin --plugin eosio::http_plugin --access-control-allow-origin=* --http-validate-host=false " + "--data-dir " + data_dir - pNodeos = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - time.sleep(10) - - PUBLIC_KEY = "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - PRIVATE_KEY = "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3" - - wallet_name = "taf_wallet" - cmd = "./programs/cleos/cleos wallet create --name " + wallet_name + " --to-console" - pWallet = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) - cmd = "./programs/cleos/cleos wallet import --name " + wallet_name + " --private-key " + PRIVATE_KEY - processCleosCommand(cmd.split()) - - accounts = ["eosio.token", "alice", "bob"] - for account in accounts: - cmd = "./programs/cleos/cleos get account -j " + account - outs, errs = processCleosCommand(cmd.split()) - str = '"account_name"' + ': ' + '"' + account + '"' - if str not in outs.decode('utf-8'): - cmd = "./programs/cleos/cleos -u http://127.0.0.1:8888 create account eosio " + account + " " + PUBLIC_KEY - outs, errs = processCleosCommand(cmd.split()) - - cmd = "./programs/cleos/cleos set contract eosio.token " + os.path.abspath(os.getcwd() + "/../unittests/contracts/eosio.token") + " " + "--abi " + "eosio.token.abi -p eosio.token@active" - processCleosCommand(cmd.split()) - cmd = ['./programs/cleos/cleos', 'push', 'action', 'eosio.token', 'create', '[ "alice", "1000000000.0000 SYS" ]', '-p', 'eosio.token'] - processCleosCommand(cmd) - cmd = ['./programs/cleos/cleos', 'push', 'action', 'eosio.token', 'issue', '[ "alice", "100.0000 SYS", "memo" ]', '-p', 'alice'] - processCleosCommand(cmd) - + contractDir = os.path.abspath(os.getcwd() + "/../unittests/contracts/eosio.token") # make a malicious abi file by switching 'from' and 'to' in eosio.token.abi + token_abi_path = os.path.abspath(os.getcwd() + '/../unittests/contracts/eosio.token/eosio.token.abi') + token_abi_file_arg = 'eosio.token' + ':' + token_abi_path malicious_token_abi_path = os.path.abspath(os.getcwd() + '/../unittests/contracts/eosio.token/malicious.eosio.token.abi') shutil.copyfile(token_abi_path, malicious_token_abi_path) replaces = [["from", "malicious"], ["to", "from"], ["malicious", "to"]] @@ -360,33 +344,87 @@ def cleos_abi_file_test(): f.write(abi) f.truncate() - # set the malicious abi - cmd = "./programs/cleos/cleos set abi eosio.token " + malicious_token_abi_path - processCleosCommand(cmd.split()) - - # option '--abi-file' makes token still be transferred from alice to bob after setting the malicious abi - cmd = ['./programs/cleos/cleos', '-u', 'http://127.0.0.1:8888', '--print-request', '--abi-file', token_abi_file_arg, 'push', 'action', 'eosio.token', 'transfer', '{ "from":"alice", "to":"bob", "quantity":"25.0000 SYS", "memo":"m" }', '-p', 'alice'] - outs, errs = processCleosCommand(cmd) - assert(b'"/v1/chain/get_raw_abi"' not in errs) - cmd = "./programs/cleos/cleos get currency balance eosio.token alice SYS" - outs, errs = processCleosCommand(cmd.split()) - assert(outs.strip().decode('utf-8') == "75.0000 SYS") - + tries = 30 + while not Utils.arePortsAvailable(set(range(8888, 8889))): + Utils.Print("ERROR: Another process is listening on nodeos test port 8888. wait...") + if tries == 0: + assert False + tries -= 1 + time.sleep(2) + nodeId = 'bios' + data_dir = Utils.getNodeDataDir(nodeId) + assert not os.path.exists(data_dir), 'data_dir exists' + os.mkdir(data_dir) + walletMgr = WalletMgr(True) + walletMgr.launch() + node = Node('localhost', 8888, nodeId, cmd="./programs/nodeos/nodeos -e -p eosio --plugin eosio::trace_api_plugin --trace-no-abis --plugin eosio::producer_plugin --plugin eosio::producer_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::chain_plugin --plugin eosio::http_plugin --access-control-allow-origin=* --http-validate-host=false " + "--data-dir " + data_dir + " --config-dir " + data_dir, walletMgr=walletMgr) + node.verifyAlive() # Setting node state to not alive + node.relaunch(newChain=True, cachePopen=True) + accountNames = ["eosio", "eosio.token", "alice", "bob"] + accounts = [] + for name in accountNames: + account = Account(name) + account.ownerPrivateKey = account.activePrivateKey = "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3" + account.ownerPublicKey = account.activePublicKey = "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" + accounts.append(account) + walletMgr.create('eosio', [accounts[0]]) + node.createAccount(accounts[1], accounts[0], stakedDeposit=0) + node.publishContract(accounts[1], contractDir, 'eosio.token.wasm', 'eosio.token.abi') + account = 'eosio.token' + action = 'create' + data = '{"issuer":"eosio.token","maximum_supply":"100000.0000 SYS","can_freeze":"0","can_recall":"0","can_whitelist":"0"}' + permission = '--permission eosio.token@active' + node.pushMessage(account, action, data, permission) + action = 'issue' + data = '{"from":"eosio.token","to":"eosio.token","quantity":"100000.0000 SYS","memo":"issue"}' + node.pushMessage(account, action, data, permission) + node.createAccount(accounts[2], accounts[0], stakedDeposit=0) + node.createAccount(accounts[3], accounts[0], stakedDeposit=0) + + node.transferFunds(accounts[1], accounts[2], '100.0000 SYS') + + node.processCleosCmd('set abi eosio.token ' + malicious_token_abi_path, 'set malicious eosio.token abi', returnType=ReturnType.raw) + + cmdArr = node._Node__transferFundsCmdArr(accounts[2], accounts[3], '25.0000 SYS', 'm', False, None, False, False, 90, False) + cmdArr.insert(6, '--print-request') + cmdArr.insert(7, '--abi-file') + cmdArr.insert(8, token_abi_file_arg) + Utils.runCmdArrReturnStr(cmdArr) + balance = node.getCurrencyBalance('eosio.token', 'alice') + assert balance == '75.0000 SYS\n' + testSuccessful=True + except Exception as e: + testSuccessful=False + Utils.Print(e.args) finally: - - if pNodeos.pid: - os.kill(pNodeos.pid, signal.SIGKILL) - shutil.rmtree(data_dir) - + if testSuccessful: + Utils.Print("Test succeeded.") + else: + Utils.Print("Test failed.") + if node: + if not node.killed: + if node.pid: + os.kill(node.pid, signal.SIGKILL) + if testSuccessful: + Utils.Print("Cleanup nodeos data.") + shutil.rmtree(data_dir) + + ''' if pWallet.pid: os.kill(pWallet.pid, signal.SIGKILL) subprocess.call(("pkill -9 keosd").split()) wallet_file = os.path.expanduser('~') + "/eosio-wallet/" + wallet_name + ".wallet" if os.path.exists(wallet_file): os.remove(wallet_file) + ''' + if malicious_token_abi_path: + if os.path.exists(malicious_token_abi_path): + os.remove(malicious_token_abi_path) - if os.path.exists(malicious_token_abi_path): - os.remove(malicious_token_abi_path) + walletMgr.killall() + if testSuccessful: + Utils.Print("Cleanup wallet data.") + walletMgr.cleanup() nodeos_help_test() @@ -399,3 +437,9 @@ def cleos_abi_file_test(): cli11_optional_option_arg_test() cleos_sign_test() + +cleos_abi_file_test() +abi_file_with_nodeos_test() + +errorCode = 0 if testSuccessful else 1 +exit(errorCode) From ffc369e561fe606f141df712eb795d53063f9754 Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Mon, 1 Aug 2022 14:44:58 -0500 Subject: [PATCH 15/18] Move cli_test to nonparallelizable_tests. --- tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3f088c0d3b..4eb6ea09b9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -206,6 +206,7 @@ set_property(TEST nodeos_retry_transaction_lr_test PROPERTY LABELS long_running_ add_test(NAME cli_test COMMAND tests/cli_test.py WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +set_property(TEST cli_test PROPERTY LABELS nonparallelizable_tests) add_test(NAME larger_lib_test COMMAND tests/large-lib-test.py WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST larger_lib_test PROPERTY LABELS nonparallelizable_tests) From 86d596ed647e28d5817f25bc8e2516330f5ea3cb Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Wed, 3 Aug 2022 14:42:14 -0500 Subject: [PATCH 16/18] Remove commented code. --- tests/cli_test.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/cli_test.py b/tests/cli_test.py index 8a254fc9c3..b77e3f9b30 100755 --- a/tests/cli_test.py +++ b/tests/cli_test.py @@ -409,14 +409,6 @@ def abi_file_with_nodeos_test(): Utils.Print("Cleanup nodeos data.") shutil.rmtree(data_dir) - ''' - if pWallet.pid: - os.kill(pWallet.pid, signal.SIGKILL) - subprocess.call(("pkill -9 keosd").split()) - wallet_file = os.path.expanduser('~') + "/eosio-wallet/" + wallet_name + ".wallet" - if os.path.exists(wallet_file): - os.remove(wallet_file) - ''' if malicious_token_abi_path: if os.path.exists(malicious_token_abi_path): os.remove(malicious_token_abi_path) From 12dc0492f6d9509ddc2d5cab18e38fa572e26a2c Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Wed, 3 Aug 2022 14:47:26 -0500 Subject: [PATCH 17/18] Add flag to prevent inadvertent resource monitor shutdown during test. --- tests/cli_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cli_test.py b/tests/cli_test.py index b77e3f9b30..ceb231824c 100755 --- a/tests/cli_test.py +++ b/tests/cli_test.py @@ -357,7 +357,7 @@ def abi_file_with_nodeos_test(): os.mkdir(data_dir) walletMgr = WalletMgr(True) walletMgr.launch() - node = Node('localhost', 8888, nodeId, cmd="./programs/nodeos/nodeos -e -p eosio --plugin eosio::trace_api_plugin --trace-no-abis --plugin eosio::producer_plugin --plugin eosio::producer_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::chain_plugin --plugin eosio::http_plugin --access-control-allow-origin=* --http-validate-host=false " + "--data-dir " + data_dir + " --config-dir " + data_dir, walletMgr=walletMgr) + node = Node('localhost', 8888, nodeId, cmd="./programs/nodeos/nodeos -e -p eosio --plugin eosio::trace_api_plugin --trace-no-abis --plugin eosio::producer_plugin --plugin eosio::producer_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::chain_plugin --plugin eosio::http_plugin --access-control-allow-origin=* --http-validate-host=false --resource-monitor-not-shutdown-on-threshold-exceeded " + "--data-dir " + data_dir + " --config-dir " + data_dir, walletMgr=walletMgr) node.verifyAlive() # Setting node state to not alive node.relaunch(newChain=True, cachePopen=True) accountNames = ["eosio", "eosio.token", "alice", "bob"] From 5e660e6a198225c2ab4fbbe19a373fc9fa2d49ae Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Mon, 8 Aug 2022 13:27:15 -0500 Subject: [PATCH 18/18] Pin Github action skip-workflow at current v1.1.1 tag's commit hash. --- .github/workflows/ubuntu-2004.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ubuntu-2004.yml b/.github/workflows/ubuntu-2004.yml index d9c71d22a2..ce94a058d3 100644 --- a/.github/workflows/ubuntu-2004.yml +++ b/.github/workflows/ubuntu-2004.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Check for ccache disable id: no-ccache - uses: saulmaldonado/skip-workflow@v1 + uses: saulmaldonado/skip-workflow@b934401f1ef10783ab5e7f25a78a31959a4fbad3 with: github-token: ${{ secrets.GITHUB_TOKEN }} search: '["pull_request"]'