From 269c16d411a2a99354f7a1591ce4ce19ac156834 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Thu, 5 Jul 2018 11:28:07 -0400 Subject: [PATCH] Add get_raw_code_and_abi chain api endpoint Provides: 1) Correct binary wasm of a contract (previous get_code endpoint butchered it) 2) Binary of abi (previously not available) cleos updated to use get_raw_code_and_abi for the "get code" operation --- plugins/chain_api_plugin/chain_api_plugin.cpp | 1 + plugins/chain_plugin/chain_plugin.cpp | 12 +++++ .../eosio/chain_plugin/chain_plugin.hpp | 13 +++++ programs/cleos/httpc.hpp | 1 + programs/cleos/main.cpp | 49 ++++++++++++++----- 5 files changed, 64 insertions(+), 12 deletions(-) diff --git a/plugins/chain_api_plugin/chain_api_plugin.cpp b/plugins/chain_api_plugin/chain_api_plugin.cpp index de8770f5ab7..54667c5512d 100644 --- a/plugins/chain_api_plugin/chain_api_plugin.cpp +++ b/plugins/chain_api_plugin/chain_api_plugin.cpp @@ -84,6 +84,7 @@ void chain_api_plugin::plugin_startup() { CHAIN_RO_CALL(get_account, 200), CHAIN_RO_CALL(get_code, 200), CHAIN_RO_CALL(get_abi, 200), + CHAIN_RO_CALL(get_raw_code_and_abi, 200), CHAIN_RO_CALL(get_table_rows, 200), CHAIN_RO_CALL(get_currency_balance, 200), CHAIN_RO_CALL(get_currency_stats, 200), diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index cf10f806142..68184a3fe6f 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -977,6 +977,18 @@ read_only::get_code_results read_only::get_code( const get_code_params& params ) return result; } +read_only::get_raw_code_and_abi_results read_only::get_raw_code_and_abi( const get_raw_code_and_abi_params& params)const { + get_raw_code_and_abi_results result; + result.account_name = params.account_name; + + const auto& d = db.db(); + const auto& accnt = d.get(params.account_name); + result.wasm = blob{{accnt.code.begin(), accnt.code.end()}}; + result.abi = blob{{accnt.abi.begin(), accnt.abi.end()}}; + + return result; +} + read_only::get_account_results read_only::get_account( const get_account_params& params )const { get_account_results result; result.account_name = params.account_name; 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 c74bfa0ddac..e0a632f5afc 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -150,9 +150,20 @@ class read_only { name account_name; }; + struct get_raw_code_and_abi_results { + name account_name; + chain::blob wasm; + chain::blob abi; + }; + + struct get_raw_code_and_abi_params { + name account_name; + }; + get_code_results get_code( const get_code_params& params )const; get_abi_results get_abi( const get_abi_params& params )const; + get_raw_code_and_abi_results get_raw_code_and_abi( const get_raw_code_and_abi_params& params)const; @@ -431,6 +442,8 @@ FC_REFLECT( eosio::chain_apis::read_only::get_abi_results, (account_name)(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)(code_as_wasm) ) FC_REFLECT( eosio::chain_apis::read_only::get_abi_params, (account_name) ) +FC_REFLECT( eosio::chain_apis::read_only::get_raw_code_and_abi_params, (account_name) ) +FC_REFLECT( eosio::chain_apis::read_only::get_raw_code_and_abi_results, (account_name)(wasm)(abi) ) FC_REFLECT( eosio::chain_apis::read_only::producer_info, (producer_name) ) FC_REFLECT( eosio::chain_apis::read_only::abi_json_to_bin_params, (code)(action)(args) ) FC_REFLECT( eosio::chain_apis::read_only::abi_json_to_bin_result, (binargs) ) diff --git a/programs/cleos/httpc.hpp b/programs/cleos/httpc.hpp index 3ad9aacf2e5..0b126a4b3de 100644 --- a/programs/cleos/httpc.hpp +++ b/programs/cleos/httpc.hpp @@ -88,6 +88,7 @@ namespace eosio { namespace client { namespace http { const string get_table_func = chain_func_base + "/get_table_rows"; const string get_code_func = chain_func_base + "/get_code"; const string get_abi_func = chain_func_base + "/get_abi"; + const string get_raw_code_and_abi_func = chain_func_base + "/get_raw_code_and_abi"; const string get_currency_balance_func = chain_func_base + "/get_currency_balance"; const string get_currency_stats_func = chain_func_base + "/get_currency_stats"; const string get_producers_func = chain_func_base + "/get_producers"; diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index b8e693ea7ee..a379eb2c5a9 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -1674,26 +1674,51 @@ int main( int argc, char** argv ) { getCode->add_option("-a,--abi",abiFilename, localized("The name of the file to save the contract .abi to") ); getCode->add_flag("--wasm", code_as_wasm, localized("Save contract as wasm")); getCode->set_callback([&] { - auto result = call(get_code_func, fc::mutable_variant_object("account_name", accountName)("code_as_wasm",code_as_wasm)); + string code_hash, wasm, wast, abi; + try { + const auto result = call(get_raw_code_and_abi_func, fc::mutable_variant_object("account_name", accountName)); + const std::vector wasm_v = result["wasm"].as_blob().data; + const std::vector abi_v = result["abi"].as_blob().data; + + fc::sha256 hash; + if(wasm_v.size()) + hash = fc::sha256::hash(wasm_v.data(), wasm_v.size()); + code_hash = (string)hash; + + wasm = string(wasm_v.begin(), wasm_v.end()); + if(!code_as_wasm && wasm_v.size()) + wast = wasm_to_wast((const uint8_t*)wasm_v.data(), wasm_v.size(), false); + + abi_def abi_d; + if(abi_serializer::to_abi(abi_v, abi_d)) + abi = fc::json::to_pretty_string(abi_d); + } + catch(chain::missing_chain_api_plugin_exception&) { + //see if this is an old nodeos that doesn't support get_raw_code_and_abi + const auto old_result = call(get_code_func, fc::mutable_variant_object("account_name", accountName)("code_as_wasm",code_as_wasm)); + code_hash = old_result["code_hash"].as_string(); + if(code_as_wasm) { + wasm = old_result["wasm"].as_string(); + std::cout << localized("Warning: communicating to older nodeos which returns malformed binary wasm") << std::endl; + } + else + wast = old_result["wast"].as_string(); + abi = fc::json::to_pretty_string(old_result["abi"]); + } - std::cout << localized("code hash: ${code_hash}", ("code_hash", result["code_hash"].as_string())) << std::endl; + std::cout << localized("code hash: ${code_hash}", ("code_hash", code_hash)) << std::endl; if( codeFilename.size() ){ std::cout << localized("saving ${type} to ${codeFilename}", ("type", (code_as_wasm ? "wasm" : "wast"))("codeFilename", codeFilename)) << std::endl; - string code; - - if(code_as_wasm) { - code = result["wasm"].as_string(); - } else { - code = result["wast"].as_string(); - } std::ofstream out( codeFilename.c_str() ); - out << code; + if(code_as_wasm) + out << wasm; + else + out << wast; } if( abiFilename.size() ) { std::cout << localized("saving abi to ${abiFilename}", ("abiFilename", abiFilename)) << std::endl; - auto abi = fc::json::to_pretty_string( result["abi"] ); std::ofstream abiout( abiFilename.c_str() ); abiout << abi; } @@ -2509,7 +2534,7 @@ int main( int argc, char** argv ) { //resolver for ABI serializer to decode actions in proposed transaction in multisig contract auto resolver = [](const name& code) -> optional { - auto result = call(get_code_func, fc::mutable_variant_object("account_name", code.to_string())); + auto result = call(get_abi_func, fc::mutable_variant_object("account_name", code.to_string())); if (result["abi"].is_object()) { //std::cout << "ABI: " << fc::json::to_pretty_string(result) << std::endl; return optional(abi_serializer(result["abi"].as()));