From 4eed1d449c62e25cd2a2d2c24808c286f4d55be5 Mon Sep 17 00:00:00 2001 From: Aleksey Tyurnin Date: Fri, 22 Jun 2018 10:04:22 +0500 Subject: [PATCH 01/21] singleton fix --- contracts/eosiolib/singleton.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/eosiolib/singleton.hpp b/contracts/eosiolib/singleton.hpp index 4ef755e8d1b..b913d963a54 100644 --- a/contracts/eosiolib/singleton.hpp +++ b/contracts/eosiolib/singleton.hpp @@ -46,7 +46,7 @@ namespace eosio { T get_or_create( account_name bill_to_account, const T& def = T() ) { auto itr = _t.find( pk_value ); return itr != _t.end() ? itr->value - : _t.emplace(bill_to_account, [&](row& r) { r.value = def; }); + : _t.emplace(bill_to_account, [&](row& r) { r.value = def; })->value; } void set( const T& value, account_name bill_to_account ) { From 00308d1d1676a79b79913bdd335d56b0146a1a37 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Mon, 25 Jun 2018 12:34:01 -0400 Subject: [PATCH 02/21] Install libs and headers --- libraries/CMakeLists.txt | 3 +++ libraries/wasm-jit/CMakeLists.txt | 1 + libraries/wasm-jit/Source/IR/CMakeLists.txt | 5 +++++ libraries/wasm-jit/Source/Runtime/CMakeLists.txt | 5 +++++ libraries/wasm-jit/Source/WASM/CMakeLists.txt | 4 ++++ libraries/wasm-jit/Source/WAST/CMakeLists.txt | 4 ++++ 6 files changed, 22 insertions(+) diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index a36e79cf5d2..ce3fe3c6db0 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -8,3 +8,6 @@ add_subdirectory( appbase ) add_subdirectory( chain ) add_subdirectory( testing ) add_subdirectory( abi_generator ) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/chainbase/include/chainbase DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}) +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/softfloat/source/include DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/eosio/softfloat) diff --git a/libraries/wasm-jit/CMakeLists.txt b/libraries/wasm-jit/CMakeLists.txt index 97ddd6a81ba..826f90914a9 100644 --- a/libraries/wasm-jit/CMakeLists.txt +++ b/libraries/wasm-jit/CMakeLists.txt @@ -76,3 +76,4 @@ add_subdirectory(Source/WASM) add_subdirectory(Source/WAST) #add_subdirectory(Test/spec) +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Include DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/eosio/wasm-jit/) diff --git a/libraries/wasm-jit/Source/IR/CMakeLists.txt b/libraries/wasm-jit/Source/IR/CMakeLists.txt index 221296ec5af..1d97ab66019 100644 --- a/libraries/wasm-jit/Source/IR/CMakeLists.txt +++ b/libraries/wasm-jit/Source/IR/CMakeLists.txt @@ -16,3 +16,8 @@ include_directories(${WAVM_INCLUDE_DIR}/IR) add_library(IR STATIC ${Sources} ${PublicHeaders}) add_definitions(-DIR_API=DLL_EXPORT) target_link_libraries(IR Logging) + +install(TARGETS IR + LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) + diff --git a/libraries/wasm-jit/Source/Runtime/CMakeLists.txt b/libraries/wasm-jit/Source/Runtime/CMakeLists.txt index 9934865847a..34a14336a86 100644 --- a/libraries/wasm-jit/Source/Runtime/CMakeLists.txt +++ b/libraries/wasm-jit/Source/Runtime/CMakeLists.txt @@ -36,3 +36,8 @@ target_include_directories( Runtime PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../ # Link against the LLVM libraries llvm_map_components_to_libnames(LLVM_LIBS support core passes mcjit native DebugInfoDWARF) target_link_libraries(Runtime Platform Logging IR ${LLVM_LIBS}) + +install(TARGETS Runtime + LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) + diff --git a/libraries/wasm-jit/Source/WASM/CMakeLists.txt b/libraries/wasm-jit/Source/WASM/CMakeLists.txt index c9d27a0db98..d6b3da8458f 100644 --- a/libraries/wasm-jit/Source/WASM/CMakeLists.txt +++ b/libraries/wasm-jit/Source/WASM/CMakeLists.txt @@ -5,3 +5,7 @@ include_directories(${WAVM_INCLUDE_DIR}/WASM) add_library(WASM STATIC ${Sources} ${PublicHeaders}) add_definitions(-DWEBASSEMBLY_API=DLL_EXPORT) target_link_libraries(WASM Logging IR) + +install(TARGETS WASM + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/libraries/wasm-jit/Source/WAST/CMakeLists.txt b/libraries/wasm-jit/Source/WAST/CMakeLists.txt index 6bca142c99c..2ade0ee8626 100644 --- a/libraries/wasm-jit/Source/WAST/CMakeLists.txt +++ b/libraries/wasm-jit/Source/WAST/CMakeLists.txt @@ -20,3 +20,7 @@ include_directories(${WAVM_INCLUDE_DIR}/WAST) add_library(WAST STATIC ${Sources} ${PublicHeaders}) add_definitions(-DWAST_API=DLL_EXPORT) target_link_libraries(WAST Logging IR WASM) +install(TARGETS WAST + LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) + From 7d4e37d4ddae61f73420cac9f0cb9c3ce36c3339 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Tue, 26 Jun 2018 09:54:24 -0400 Subject: [PATCH 03/21] Update eosio_build.sh --- eosio_build.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/eosio_build.sh b/eosio_build.sh index 3beec255b02..bf89bec043a 100755 --- a/eosio_build.sh +++ b/eosio_build.sh @@ -208,8 +208,6 @@ OPENSSL_ROOT_DIR=/usr/local/opt/openssl fi - WASM_ROOT=/usr/local/ - . "$FILE" printf "\\n\\n>>>>>>>> ALL dependencies sucessfully found or installed . Installing EOSIO\\n\\n" From 9bcf93fab0a7c9e810384af6fa691d059c462a6b Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Tue, 26 Jun 2018 09:59:38 -0400 Subject: [PATCH 04/21] updated submodule --- eosio_build.sh | 2 -- externals/binaryen | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/eosio_build.sh b/eosio_build.sh index 3beec255b02..bf89bec043a 100755 --- a/eosio_build.sh +++ b/eosio_build.sh @@ -208,8 +208,6 @@ OPENSSL_ROOT_DIR=/usr/local/opt/openssl fi - WASM_ROOT=/usr/local/ - . "$FILE" printf "\\n\\n>>>>>>>> ALL dependencies sucessfully found or installed . Installing EOSIO\\n\\n" diff --git a/externals/binaryen b/externals/binaryen index a17f65531c6..82a2cccb99b 160000 --- a/externals/binaryen +++ b/externals/binaryen @@ -1 +1 @@ -Subproject commit a17f65531c6e0e346c08c18909d367c7308f9079 +Subproject commit 82a2cccb99b6f6b159a066707e5f58c4311914b9 From fb499c2417f027a05ed74469544d9906673a65e6 Mon Sep 17 00:00:00 2001 From: Krzysztof Szumny Date: Wed, 27 Jun 2018 00:09:38 +0200 Subject: [PATCH 05/21] more precise exception --- libraries/chain/eosio_contract.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/eosio_contract.cpp b/libraries/chain/eosio_contract.cpp index c128a0307ad..1952d3e9f7c 100644 --- a/libraries/chain/eosio_contract.cpp +++ b/libraries/chain/eosio_contract.cpp @@ -92,7 +92,7 @@ void apply_eosio_newaccount(apply_context& context) { } auto existing_account = db.find(create.name); - EOS_ASSERT(existing_account == nullptr, action_validate_exception, + EOS_ASSERT(existing_account == nullptr, account_name_exists_exception, "Cannot create account named ${name}, as that name is already taken", ("name", create.name)); From 92fec6a9a551dc7018b5f9180ffc3a20c4eff793 Mon Sep 17 00:00:00 2001 From: Andrianto Lie Date: Wed, 27 Jun 2018 11:31:25 +0800 Subject: [PATCH 06/21] Missing $ in inline action error message --- libraries/chain/apply_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index a88906ed4f1..e91e620f0f4 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -191,7 +191,7 @@ void apply_context::execute_inline( action&& a ) { EOS_ASSERT( actor != nullptr, action_validate_exception, "inline action's authorizing actor ${account} does not exist", ("account", auth.actor) ); EOS_ASSERT( control.get_authorization_manager().find_permission(auth) != nullptr, action_validate_exception, - "inline action's authorizations include a non-existent permission: {permission}", + "inline action's authorizations include a non-existent permission: ${permission}", ("permission", auth) ); } From 7a2f94e2119c8dfeb09038948013f584802d054a Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 27 Jun 2018 18:24:52 -0400 Subject: [PATCH 07/21] implement eosio.sudo contract and add related unit tests #4142 --- contracts/CMakeLists.txt | 1 + contracts/eosio.sudo/CMakeLists.txt | 9 + contracts/eosio.sudo/README.md | 16 + contracts/eosio.sudo/eosio.sudo.abi | 73 ++++ contracts/eosio.sudo/eosio.sudo.cpp | 37 ++ contracts/eosio.sudo/eosio.sudo.hpp | 15 + .../testing/include/eosio/testing/tester.hpp | 6 +- libraries/testing/tester.cpp | 2 +- unittests/eosio.sudo_tests.cpp | 367 ++++++++++++++++++ 9 files changed, 522 insertions(+), 4 deletions(-) create mode 100644 contracts/eosio.sudo/CMakeLists.txt create mode 100644 contracts/eosio.sudo/README.md create mode 100644 contracts/eosio.sudo/eosio.sudo.abi create mode 100644 contracts/eosio.sudo/eosio.sudo.cpp create mode 100644 contracts/eosio.sudo/eosio.sudo.hpp create mode 100644 unittests/eosio.sudo_tests.cpp diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index eb3693a238b..4b1e235715a 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -10,6 +10,7 @@ add_subdirectory(libc++) add_subdirectory(simple.token) add_subdirectory(eosio.token) add_subdirectory(eosio.msig) +add_subdirectory(eosio.sudo) add_subdirectory(multi_index_test) add_subdirectory(eosio.system) add_subdirectory(identity) diff --git a/contracts/eosio.sudo/CMakeLists.txt b/contracts/eosio.sudo/CMakeLists.txt new file mode 100644 index 00000000000..3760b6e82e2 --- /dev/null +++ b/contracts/eosio.sudo/CMakeLists.txt @@ -0,0 +1,9 @@ + +file(GLOB ABI_FILES "*.abi") +configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) + +add_wast_executable(TARGET eosio.sudo + INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" + LIBRARIES libc++ libc eosiolib + DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} +) diff --git a/contracts/eosio.sudo/README.md b/contracts/eosio.sudo/README.md new file mode 100644 index 00000000000..9c6873cafb4 --- /dev/null +++ b/contracts/eosio.sudo/README.md @@ -0,0 +1,16 @@ +eosio.sudo +-------- + +Actions: +The naming convention is codeaccount::actionname followed by a list of parameters. + +Execute a transaction while bypassing regular authorization checks (requires authorization of eosio.sudo which needs to be a privileged account) +## eosio.sudo::exec executer trx + - **executer** account executing the transaction + - **trx** transaction to execute + + Deferred transaction RAM usage is billed to 'executer' + +Cleos usage example. + +TODO: Fill in cleos usage example. diff --git a/contracts/eosio.sudo/eosio.sudo.abi b/contracts/eosio.sudo/eosio.sudo.abi new file mode 100644 index 00000000000..6f74921bc2a --- /dev/null +++ b/contracts/eosio.sudo/eosio.sudo.abi @@ -0,0 +1,73 @@ +{ + "version": "eosio::abi/1.0", + "types": [{ + "new_type_name": "account_name", + "type": "name" + },{ + "new_type_name": "permission_name", + "type": "name" + },{ + "new_type_name": "action_name", + "type": "name" + }], + "structs": [{ + "name": "permission_level", + "base": "", + "fields": [ + {"name": "actor", "type": "account_name"}, + {"name": "permission", "type": "permission_name"} + ] + },{ + "name": "action", + "base": "", + "fields": [ + {"name": "account", "type": "account_name"}, + {"name": "name", "type": "action_name"}, + {"name": "authorization", "type": "permission_level[]"}, + {"name": "data", "type": "bytes"} + ] + },{ + "name": "transaction_header", + "base": "", + "fields": [ + {"name": "expiration", "type": "time_point_sec"}, + {"name": "ref_block_num", "type": "uint16"}, + {"name": "ref_block_prefix", "type": "uint32"}, + {"name": "max_net_usage_words", "type": "varuint32"}, + {"name": "max_cpu_usage_ms", "type": "uint8"}, + {"name": "delay_sec", "type": "varuint32"} + ] + },{ + "name": "extension", + "base": "", + "fields": [ + {"name": "type", "type" : "uint16" }, + {"name": "data", "type": "bytes"} + ] + },{ + "name": "transaction", + "base": "transaction_header", + "fields": [ + {"name": "context_free_actions", "type": "action[]"}, + {"name": "actions", "type": "action[]"}, + {"name": "transaction_extensions", "type": "extension[]"} + ] + },{ + "name": "exec", + "base": "", + "fields": [ + {"name":"executer", "type":"account_name"}, + {"name":"trx", "type":"transaction"} + ] + } + ], + "actions": [{ + "name": "exec", + "type": "exec", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "abi_extensions": [] +} diff --git a/contracts/eosio.sudo/eosio.sudo.cpp b/contracts/eosio.sudo/eosio.sudo.cpp new file mode 100644 index 00000000000..10e501936f2 --- /dev/null +++ b/contracts/eosio.sudo/eosio.sudo.cpp @@ -0,0 +1,37 @@ +#include +#include + +namespace eosio { + +/* +exec function manually parses input data (instead of taking parsed arguments from dispatcher) +because parsing data in the dispatcher uses too much CPU if the included transaction is very big + +If we use dispatcher the function signature should be: + +void sudo::exec( account_name executer, + transaction trx ) +*/ + +void sudo::exec() { + require_auth( _self ); + + constexpr size_t max_stack_buffer_size = 512; + size_t size = action_data_size(); + char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) ); + read_action_data( buffer, size ); + + account_name executer; + + datastream ds( buffer, size ); + ds >> executer; + + require_auth( executer ); + + size_t trx_pos = ds.tellp(); + send_deferred( (uint128_t(executer) << 64) | current_time(), executer, buffer+trx_pos, size ); +} + +} /// namespace eosio + +EOSIO_ABI( eosio::sudo, (exec) ) diff --git a/contracts/eosio.sudo/eosio.sudo.hpp b/contracts/eosio.sudo/eosio.sudo.hpp new file mode 100644 index 00000000000..a96562121dc --- /dev/null +++ b/contracts/eosio.sudo/eosio.sudo.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace eosio { + + class sudo : public contract { + public: + sudo( account_name self ):contract(self){} + + void exec(); + + }; + +} /// namespace eosio diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 134f663bc1c..6c975bf5e85 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -121,9 +121,9 @@ namespace eosio { namespace testing { action get_action( account_name code, action_name acttype, vector auths, const variant_object& data )const; - void set_transaction_headers(signed_transaction& trx, - uint32_t expiration = DEFAULT_EXPIRATION_DELTA, - uint32_t delay_sec = 0)const; + void set_transaction_headers( transaction& trx, + uint32_t expiration = DEFAULT_EXPIRATION_DELTA, + uint32_t delay_sec = 0 )const; vector create_accounts( vector names, bool multisig = false, diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index ef4602d376c..9fdd5c32489 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -218,7 +218,7 @@ namespace eosio { namespace testing { } - void base_tester::set_transaction_headers( signed_transaction& trx, uint32_t expiration, uint32_t delay_sec ) const { + void base_tester::set_transaction_headers( transaction& trx, uint32_t expiration, uint32_t delay_sec ) const { trx.expiration = control->head_block_time() + fc::seconds(expiration); trx.set_reference_block( control->head_block_id() ); diff --git a/unittests/eosio.sudo_tests.cpp b/unittests/eosio.sudo_tests.cpp new file mode 100644 index 00000000000..1cbdf193458 --- /dev/null +++ b/unittests/eosio.sudo_tests.cpp @@ -0,0 +1,367 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include + +using namespace eosio::testing; +using namespace eosio; +using namespace eosio::chain; +using namespace eosio::testing; +using namespace fc; + +using mvo = fc::mutable_variant_object; + +class eosio_sudo_tester : public tester { +public: + + eosio_sudo_tester() { + create_accounts( { N(eosio.msig), N(prod1), N(prod2), N(prod3), N(prod4), N(prod5), N(alice), N(bob), N(carol) } ); + produce_block(); + + + base_tester::push_action(config::system_account_name, N(setpriv), + config::system_account_name, mutable_variant_object() + ("account", "eosio.msig") + ("is_priv", 1) + ); + + set_code( N(eosio.msig), eosio_msig_wast ); + set_abi( N(eosio.msig), eosio_msig_abi ); + + produce_blocks(); + + signed_transaction trx; + set_transaction_headers(trx); + authority auth( 1, {}, {{{config::system_account_name, config::active_name}, 1}} ); + trx.actions.emplace_back( vector{{config::system_account_name, config::active_name}}, + newaccount{ + .creator = config::system_account_name, + .name = N(eosio.sudo), + .owner = auth, + .active = auth, + }); + + set_transaction_headers(trx); + trx.sign( get_private_key( config::system_account_name, "active" ), control->get_chain_id() ); + push_transaction( trx ); + + base_tester::push_action(config::system_account_name, N(setpriv), + config::system_account_name, mutable_variant_object() + ("account", "eosio.sudo") + ("is_priv", 1) + ); + + auto system_private_key = get_private_key( config::system_account_name, "active" ); + set_code( N(eosio.sudo), eosio_sudo_wast, &system_private_key ); + set_abi( N(eosio.sudo), eosio_sudo_abi, &system_private_key ); + + produce_blocks(); + + set_authority( config::system_account_name, config::active_name, + authority( 1, {{get_public_key( config::system_account_name, "active" ), 1}}, + {{{config::producers_account_name, config::active_name}, 1}} ), + config::owner_name, + { { config::system_account_name, config::owner_name } }, + { get_private_key( config::system_account_name, "active" ) } + ); + + set_producers( {N(prod1), N(prod2), N(prod3), N(prod4), N(prod5)} ); + + produce_blocks(); + + const auto& accnt = control->db().get( N(eosio.sudo) ); + abi_def abi; + BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); + abi_ser.set_abi(abi); + + while( control->pending_block_state()->header.producer.to_string() == "eosio" ) { + produce_block(); + } + } + + void propose( name proposer, name proposal_name, vector requested_permissions, const transaction& trx ) { + push_action( N(eosio.msig), N(propose), proposer, mvo() + ("proposer", proposer) + ("proposal_name", proposal_name) + ("requested", requested_permissions) + ("trx", trx) + ); + } + + void approve( name proposer, name proposal_name, name approver ) { + push_action( N(eosio.msig), N(approve), approver, mvo() + ("proposer", proposer) + ("proposal_name", proposal_name) + ("level", permission_level{approver, config::active_name} ) + ); + } + + void unapprove( name proposer, name proposal_name, name unapprover ) { + push_action( N(eosio.msig), N(unapprove), unapprover, mvo() + ("proposer", proposer) + ("proposal_name", proposal_name) + ("level", permission_level{unapprover, config::active_name}) + ); + } + + transaction sudo_exec( account_name executer, const transaction& trx, uint32_t expiration = base_tester::DEFAULT_EXPIRATION_DELTA ); + + transaction reqauth( account_name from, const vector& auths, uint32_t expiration = base_tester::DEFAULT_EXPIRATION_DELTA ); + + abi_serializer abi_ser; +}; + +transaction eosio_sudo_tester::sudo_exec( account_name executer, const transaction& trx, uint32_t expiration ) { + fc::variants v; + v.push_back( fc::mutable_variant_object() + ("actor", executer) + ("permission", name{config::active_name}) + ); + v.push_back( fc::mutable_variant_object() + ("actor", "eosio.sudo") + ("permission", name{config::active_name}) + ); + auto act_obj = fc::mutable_variant_object() + ("account", "eosio.sudo") + ("name", "exec") + ("authorization", v) + ("data", fc::mutable_variant_object()("executer", executer)("trx", trx) ); + transaction trx2; + set_transaction_headers(trx2, expiration); + action act; + abi_serializer::from_variant( act_obj, act, get_resolver() ); + trx2.actions.push_back( std::move(act) ); + return trx2; +} + +transaction eosio_sudo_tester::reqauth( account_name from, const vector& auths, uint32_t expiration ) { + fc::variants v; + for ( auto& level : auths ) { + v.push_back(fc::mutable_variant_object() + ("actor", level.actor) + ("permission", level.permission) + ); + } + auto act_obj = fc::mutable_variant_object() + ("account", name{config::system_account_name}) + ("name", "reqauth") + ("authorization", v) + ("data", fc::mutable_variant_object() ("from", from) ); + transaction trx; + set_transaction_headers(trx, expiration); + action act; + abi_serializer::from_variant( act_obj, act, get_resolver() ); + trx.actions.push_back( std::move(act) ); + return trx; +} + +BOOST_AUTO_TEST_SUITE(eosio_sudo_tests) + +BOOST_FIXTURE_TEST_CASE( sudo_exec_direct, eosio_sudo_tester ) try { + auto trx = reqauth( N(bob), {permission_level{N(bob), config::active_name}} ); + + transaction_trace_ptr trace; + control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } ); + + { + signed_transaction sudo_trx( sudo_exec( N(alice), trx ), {}, {} ); + /* + set_transaction_headers( sudo_trx ); + sudo_trx.actions.emplace_back( get_action( N(eosio.sudo), N(exec), + {{N(alice), config::active_name}, {N(eosio.sudo), config::active_name}}, + mvo() + ("executer", "alice") + ("trx", trx) + ) ); + */ + sudo_trx.sign( get_private_key( N(alice), "active" ), control->get_chain_id() ); + for( const auto& actor : {"prod1", "prod2", "prod3", "prod4"} ) { + sudo_trx.sign( get_private_key( actor, "active" ), control->get_chain_id() ); + } + push_transaction( sudo_trx ); + } + + produce_block(); + + BOOST_REQUIRE( bool(trace) ); + BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); + BOOST_REQUIRE_EQUAL( "eosio", name{trace->action_traces[0].act.account} ); + BOOST_REQUIRE_EQUAL( "reqauth", name{trace->action_traces[0].act.name} ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( sudo_with_msig, eosio_sudo_tester ) try { + auto trx = reqauth( N(bob), {permission_level{N(bob), config::active_name}} ); + auto sudo_trx = sudo_exec( N(alice), trx ); + + propose( N(carol), N(first), + { {N(alice), N(active)}, + {N(prod1), N(active)}, {N(prod2), N(active)}, {N(prod3), N(active)}, {N(prod4), N(active)}, {N(prod5), N(active)} }, + sudo_trx ); + + approve( N(carol), N(first), N(alice) ); // alice must approve since she is the executer of the sudo::exec action + + // More than 2/3 of block producers approve + approve( N(carol), N(first), N(prod1) ); + approve( N(carol), N(first), N(prod2) ); + approve( N(carol), N(first), N(prod3) ); + approve( N(carol), N(first), N(prod4) ); + + vector traces; + control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { + if (t->scheduled) { + traces.push_back( t ); + } + } ); + + // Now the proposal should be ready to execute + push_action( N(eosio.msig), N(exec), N(alice), mvo() + ("proposer", "carol") + ("proposal_name", "first") + ("executer", "alice") + ); + + produce_block(); + + BOOST_REQUIRE_EQUAL( 2, traces.size() ); + + BOOST_REQUIRE_EQUAL( 1, traces[0]->action_traces.size() ); + BOOST_REQUIRE_EQUAL( "eosio.sudo", name{traces[0]->action_traces[0].act.account} ); + BOOST_REQUIRE_EQUAL( "exec", name{traces[0]->action_traces[0].act.name} ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[0]->receipt->status ); + + BOOST_REQUIRE_EQUAL( 1, traces[1]->action_traces.size() ); + BOOST_REQUIRE_EQUAL( "eosio", name{traces[1]->action_traces[0].act.account} ); + BOOST_REQUIRE_EQUAL( "reqauth", name{traces[1]->action_traces[0].act.name} ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[1]->receipt->status ); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( sudo_with_msig_unapprove, eosio_sudo_tester ) try { + auto trx = reqauth( N(bob), {permission_level{N(bob), config::active_name}} ); + auto sudo_trx = sudo_exec( N(alice), trx ); + + propose( N(carol), N(first), + { {N(alice), N(active)}, + {N(prod1), N(active)}, {N(prod2), N(active)}, {N(prod3), N(active)}, {N(prod4), N(active)}, {N(prod5), N(active)} }, + sudo_trx ); + + approve( N(carol), N(first), N(alice) ); // alice must approve since she is the executer of the sudo::exec action + + // 3 of the 4 needed producers approve + approve( N(carol), N(first), N(prod1) ); + approve( N(carol), N(first), N(prod2) ); + approve( N(carol), N(first), N(prod3) ); + + // first producer takes back approval + unapprove( N(carol), N(first), N(prod1) ); + + // fourth producer approves but the total number of approving producers is still 3 which is less than two-thirds of producers + approve( N(carol), N(first), N(prod4) ); + + produce_block(); + + // The proposal should not have sufficient approvals to pass the authorization checks of eosio.sudo::exec. + BOOST_REQUIRE_EXCEPTION( push_action( N(eosio.msig), N(exec), N(alice), mvo() + ("proposer", "carol") + ("proposal_name", "first") + ("executer", "alice") + ), eosio_assert_message_exception, + eosio_assert_message_is("transaction authorization failed") + ); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( sudo_with_msig_producers_change, eosio_sudo_tester ) try { + create_accounts( { N(newprod1) } ); + + auto trx = reqauth( N(bob), {permission_level{N(bob), config::active_name}} ); + auto sudo_trx = sudo_exec( N(alice), trx, 36000 ); + + propose( N(carol), N(first), + { {N(alice), N(active)}, + {N(prod1), N(active)}, {N(prod2), N(active)}, {N(prod3), N(active)}, {N(prod4), N(active)}, {N(prod5), N(active)} }, + sudo_trx ); + + approve( N(carol), N(first), N(alice) ); // alice must approve since she is the executer of the sudo::exec action + + // 2 of the 4 needed producers approve + approve( N(carol), N(first), N(prod1) ); + approve( N(carol), N(first), N(prod2) ); + + produce_block(); + + set_producers( {N(prod1), N(prod2), N(prod3), N(prod4), N(prod5), N(newprod1)} ); // With 6 producers, the 2/3+1 threshold becomes 5 + + while( control->pending_block_state()->active_schedule.producers.size() != 6 ) { + produce_block(); + } + + // Now two more block producers approve which would have been sufficient under the old schedule but not the new one. + approve( N(carol), N(first), N(prod3) ); + approve( N(carol), N(first), N(prod4) ); + + produce_block(); + + // The proposal has four of the five requested approvals but they are not sufficient to satisfy the authorization checks of eosio.sudo::exec. + BOOST_REQUIRE_EXCEPTION( push_action( N(eosio.msig), N(exec), N(alice), mvo() + ("proposer", "carol") + ("proposal_name", "first") + ("executer", "alice") + ), eosio_assert_message_exception, + eosio_assert_message_is("transaction authorization failed") + ); + + // Unfortunately the new producer cannot approve because they were not in the original requested approvals. + BOOST_REQUIRE_EXCEPTION( approve( N(carol), N(first), N(newprod1) ), + eosio_assert_message_exception, + eosio_assert_message_is("approval is not on the list of requested approvals") + ); + + // But prod5 still can provide the fifth approval necessary to satisfy the 2/3+1 threshold of the new producer set + approve( N(carol), N(first), N(prod5) ); + + vector traces; + control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { + if (t->scheduled) { + traces.push_back( t ); + } + } ); + + // Now the proposal should be ready to execute + push_action( N(eosio.msig), N(exec), N(alice), mvo() + ("proposer", "carol") + ("proposal_name", "first") + ("executer", "alice") + ); + + produce_block(); + + BOOST_REQUIRE_EQUAL( 2, traces.size() ); + + BOOST_REQUIRE_EQUAL( 1, traces[0]->action_traces.size() ); + BOOST_REQUIRE_EQUAL( "eosio.sudo", name{traces[0]->action_traces[0].act.account} ); + BOOST_REQUIRE_EQUAL( "exec", name{traces[0]->action_traces[0].act.name} ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[0]->receipt->status ); + + BOOST_REQUIRE_EQUAL( 1, traces[1]->action_traces.size() ); + BOOST_REQUIRE_EQUAL( "eosio", name{traces[1]->action_traces[0].act.account} ); + BOOST_REQUIRE_EQUAL( "reqauth", name{traces[1]->action_traces[0].act.name} ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[1]->receipt->status ); + +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() From 5c477a17182679a82ad128adcf90d4a3d8208264 Mon Sep 17 00:00:00 2001 From: Andrianto Lie Date: Thu, 28 Jun 2018 10:21:35 +0800 Subject: [PATCH 08/21] Show the linked action inside deleting linked authority error message --- libraries/chain/eosio_contract.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/chain/eosio_contract.cpp b/libraries/chain/eosio_contract.cpp index c128a0307ad..b2f2e0b7ceb 100644 --- a/libraries/chain/eosio_contract.cpp +++ b/libraries/chain/eosio_contract.cpp @@ -282,7 +282,8 @@ void apply_eosio_deleteauth(apply_context& context) { const auto& index = db.get_index(); auto range = index.equal_range(boost::make_tuple(remove.account, remove.permission)); EOS_ASSERT(range.first == range.second, action_validate_exception, - "Cannot delete a linked authority. Unlink the authority first"); + "Cannot delete a linked authority. Unlink the authority first. This authority is linked to ${code}::${type}.", + ("code", string(range.first->code))("type", string(range.first->message_type))); } const auto& permission = authorization.get_permission({remove.account, remove.permission}); From 2eb718fe286d08b9f85ffd42899fd1b0962919e5 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Thu, 28 Jun 2018 13:52:12 -0400 Subject: [PATCH 09/21] bios-boot-tutorial: fix --max-irreversible-block-age --- tutorials/bios-boot-tutorial/bios-boot-tutorial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/bios-boot-tutorial/bios-boot-tutorial.py b/tutorials/bios-boot-tutorial/bios-boot-tutorial.py index 40790e5ae2a..6f626b83ece 100755 --- a/tutorials/bios-boot-tutorial/bios-boot-tutorial.py +++ b/tutorials/bios-boot-tutorial/bios-boot-tutorial.py @@ -104,7 +104,7 @@ def startNode(nodeIndex, account): ) cmd = ( args.nodeos + - ' --max-irreversible-block-age 9999999' + ' --max-irreversible-block-age -1' ' --contracts-console' ' --genesis-json ' + os.path.abspath(args.genesis) + ' --blocks-dir ' + os.path.abspath(dir) + '/blocks' From 95fb08fe6c9ccf8140775ad86810ac1837e53d3d Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 28 Jun 2018 17:21:28 -0400 Subject: [PATCH 10/21] relax abi_serializer limit for cleos #4395 --- programs/cleos/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index f9ab266d1da..0267efedbff 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -1578,6 +1578,8 @@ int main( int argc, char** argv ) { textdomain(locale_domain); context = eosio::client::http::create_http_context(); + abi_serializer::set_max_serialization_time(fc::seconds(1)); // No risk to client side serialization taking a long time + CLI::App app{"Command Line Interface to EOSIO Client"}; app.require_subcommand(); app.add_option( "-H,--host", obsoleted_option_host_port, localized("the host where nodeos is running") )->group("hidden"); From a3cf1dec0bb50861cb22d546ac4c2c7d2d616645 Mon Sep 17 00:00:00 2001 From: Anton Perkov Date: Wed, 20 Jun 2018 13:38:45 -0400 Subject: [PATCH 11/21] cleos multisig transaction (bad naming, but allows keep cleos multisig propose), print diagnostic messages to stderr to get correct files when redirecting stdout #4247 --- programs/cleos/main.cpp | 71 ++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index f9ab266d1da..28cac7e735d 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -1674,10 +1674,10 @@ int main( int argc, char** argv ) { getCode->set_callback([&] { auto result = call(get_code_func, fc::mutable_variant_object("account_name", accountName)("code_as_wasm",code_as_wasm)); - std::cout << localized("code hash: ${code_hash}", ("code_hash", result["code_hash"].as_string())) << std::endl; + std::cerr << localized("code hash: ${code_hash}", ("code_hash", result["code_hash"].as_string())) << std::endl; if( codeFilename.size() ){ - std::cout << localized("saving ${type} to ${codeFilename}", ("type", (code_as_wasm ? "wasm" : "wast"))("codeFilename", codeFilename)) << std::endl; + std::cerr << localized("saving ${type} to ${codeFilename}", ("type", (code_as_wasm ? "wasm" : "wast"))("codeFilename", codeFilename)) << std::endl; string code; if(code_as_wasm) { @@ -1690,7 +1690,7 @@ int main( int argc, char** argv ) { out << code; } if( abiFilename.size() ) { - std::cout << localized("saving abi to ${abiFilename}", ("abiFilename", abiFilename)) << std::endl; + std::cerr << 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; @@ -1707,7 +1707,7 @@ int main( int argc, char** argv ) { auto abi = fc::json::to_pretty_string( result["abi"] ); if( filename.size() ) { - std::cout << localized("saving abi to ${filename}", ("filename", filename)) << std::endl; + std::cerr << localized("saving abi to ${filename}", ("filename", filename)) << std::endl; std::ofstream abiout( filename.c_str() ); abiout << abi; } else { @@ -2014,23 +2014,23 @@ int main( int argc, char** argv ) { wastPath = (cpath / (cpath.filename().generic_string()+".wast")).generic_string(); } - std::cout << localized(("Reading WAST/WASM from " + wastPath + "...").c_str()) << std::endl; + std::cerr << localized(("Reading WAST/WASM from " + wastPath + "...").c_str()) << std::endl; fc::read_file_contents(wastPath, wast); FC_ASSERT( !wast.empty(), "no wast file found ${f}", ("f", wastPath) ); vector wasm; const string binary_wasm_header("\x00\x61\x73\x6d", 4); if(wast.compare(0, 4, binary_wasm_header) == 0) { - std::cout << localized("Using already assembled WASM...") << std::endl; + std::cerr << localized("Using already assembled WASM...") << std::endl; wasm = vector(wast.begin(), wast.end()); } else { - std::cout << localized("Assembling WASM...") << std::endl; + std::cerr << localized("Assembling WASM...") << std::endl; wasm = wast_to_wasm(wast); } actions.emplace_back( create_setcode(account, bytes(wasm.begin(), wasm.end()) ) ); if ( shouldSend ) { - std::cout << localized("Setting Code...") << std::endl; + std::cerr << localized("Setting Code...") << std::endl; send_actions(std::move(actions), 10000, packed_transaction::zlib); } }; @@ -2050,7 +2050,7 @@ int main( int argc, char** argv ) { actions.emplace_back( create_setabi(account, fc::json::from_file(abiPath).as()) ); } EOS_RETHROW_EXCEPTIONS(abi_type_exception, "Fail to parse ABI JSON") if ( shouldSend ) { - std::cout << localized("Setting ABI...") << std::endl; + std::cerr << localized("Setting ABI...") << std::endl; send_actions(std::move(actions), 10000, packed_transaction::zlib); } }; @@ -2062,7 +2062,7 @@ int main( int argc, char** argv ) { shouldSend = false; set_code_callback(); set_abi_callback(); - std::cout << localized("Publishing contract...") << std::endl; + std::cerr << localized("Publishing contract...") << std::endl; send_actions(std::move(actions), 10000, packed_transaction::zlib); }); codeSubcommand->set_callback(set_code_callback); @@ -2423,8 +2423,7 @@ int main( int argc, char** argv ) { return true; }; - auto propose_action = msig->add_subcommand("propose", localized("Propose transaction")); - //auto propose_action = msig->add_subcommand("action", localized("Propose action")); + auto propose_action = msig->add_subcommand("propose", localized("Propose action")); add_standard_transaction_options(propose_action); propose_action->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); propose_action->add_option("requested_permissions", requested_perm, localized("The JSON string or filename defining requested permissions"))->required(); @@ -2450,13 +2449,12 @@ int main( int argc, char** argv ) { } EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse transaction JSON '${data}'", ("data",proposed_transaction)) transaction proposed_trx = trx_var.as(); - auto arg= fc::mutable_variant_object() + auto arg = fc::mutable_variant_object() ("code", proposed_contract) ("action", proposed_action) ("args", trx_var); auto result = call(json_to_bin_func, arg); - //std::cout << "Result: "; fc::json::to_stream(std::cout, result); std::cout << std::endl; bytes proposed_trx_serialized = result.get_object()["binargs"].as(); @@ -2519,9 +2517,52 @@ int main( int argc, char** argv ) { } }; + //multisige propose transaction + auto propose_trx = msig->add_subcommand("transaction", localized("Push an arbitrary JSON transaction")); + add_standard_transaction_options(propose_trx); + propose_trx->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); + propose_trx->add_option("requested_permissions", requested_perm, localized("The JSON string or filename defining requested permissions"))->required(); + propose_trx->add_option("transaction", trx_to_push, localized("The JSON string or filename defining the transaction to push"))->required(); + + propose_trx->set_callback([&] { + fc::variant requested_perm_var; + try { + requested_perm_var = json_from_file_or_string(requested_perm); + } EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse permissions JSON '${data}'", ("data",requested_perm)) + + fc::variant trx_var; + try { + trx_var = json_from_file_or_string(trx_to_push); + } EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse transaction JSON '${data}'", ("data",trx_to_push)) + + auto accountPermissions = get_account_permissions(tx_permission); + if (accountPermissions.empty()) { + if (!proposer.empty()) { + accountPermissions = vector{{proposer, config::active_name}}; + } else { + EOS_THROW(missing_auth_exception, "Authority is not provided (either by multisig parameter or -p)"); + } + } + if (proposer.empty()) { + proposer = name(accountPermissions.at(0).actor).to_string(); + } + + auto arg = fc::mutable_variant_object() + ("code", "eosio.msig") + ("action", "propose") + ("args", fc::mutable_variant_object() + ("proposer", proposer ) + ("proposal_name", proposal_name) + ("requested", requested_perm_var) + ("trx", trx_var) + ); + auto result = call(json_to_bin_func, arg); + send_actions({chain::action{accountPermissions, "eosio.msig", "propose", result.get_object()["binargs"].as()}}); + }); + + // multisig review auto review = msig->add_subcommand("review", localized("Review transaction")); - add_standard_transaction_options(review); review->add_option("proposer", proposer, localized("proposer name (string)"))->required(); review->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); From 722927bdad29b75fd62ddb35d592b67e147bc5f0 Mon Sep 17 00:00:00 2001 From: Anton Perkov Date: Wed, 20 Jun 2018 15:13:49 -0400 Subject: [PATCH 12/21] cleos: some messages changed to go back to stdout #4249 --- programs/cleos/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 28cac7e735d..e51489b0bc9 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -1674,10 +1674,10 @@ int main( int argc, char** argv ) { getCode->set_callback([&] { auto result = call(get_code_func, fc::mutable_variant_object("account_name", accountName)("code_as_wasm",code_as_wasm)); - std::cerr << localized("code hash: ${code_hash}", ("code_hash", result["code_hash"].as_string())) << std::endl; + std::cout << localized("code hash: ${code_hash}", ("code_hash", result["code_hash"].as_string())) << std::endl; if( codeFilename.size() ){ - std::cerr << localized("saving ${type} to ${codeFilename}", ("type", (code_as_wasm ? "wasm" : "wast"))("codeFilename", codeFilename)) << std::endl; + std::cout << localized("saving ${type} to ${codeFilename}", ("type", (code_as_wasm ? "wasm" : "wast"))("codeFilename", codeFilename)) << std::endl; string code; if(code_as_wasm) { @@ -1690,7 +1690,7 @@ int main( int argc, char** argv ) { out << code; } if( abiFilename.size() ) { - std::cerr << localized("saving abi to ${abiFilename}", ("abiFilename", abiFilename)) << std::endl; + 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; From 6837e4632d290e2efd57cf7681bcd5dda1f4a86d Mon Sep 17 00:00:00 2001 From: Anton Perkov Date: Wed, 20 Jun 2018 15:52:42 -0400 Subject: [PATCH 13/21] cleos: multisig transaction renamed to multisig proposer_trx, added optional parameter "proposer" #4249 --- 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 e51489b0bc9..734fc305b8d 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -2518,11 +2518,12 @@ int main( int argc, char** argv ) { }; //multisige propose transaction - auto propose_trx = msig->add_subcommand("transaction", localized("Push an arbitrary JSON transaction")); + auto propose_trx = msig->add_subcommand("propose_trx", localized("Propose transaction")); add_standard_transaction_options(propose_trx); propose_trx->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); propose_trx->add_option("requested_permissions", requested_perm, localized("The JSON string or filename defining requested permissions"))->required(); propose_trx->add_option("transaction", trx_to_push, localized("The JSON string or filename defining the transaction to push"))->required(); + propose_action->add_option("proposer", proposer, localized("Account proposing the transaction")); propose_trx->set_callback([&] { fc::variant requested_perm_var; From cbf379385872546acc483dd321ac0cec0b1f5953 Mon Sep 17 00:00:00 2001 From: Anton Perkov Date: Wed, 20 Jun 2018 16:20:18 -0400 Subject: [PATCH 14/21] cleos: small bugfix #4249 --- programs/cleos/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 734fc305b8d..f82c743f2fc 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -2523,7 +2523,7 @@ int main( int argc, char** argv ) { propose_trx->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); propose_trx->add_option("requested_permissions", requested_perm, localized("The JSON string or filename defining requested permissions"))->required(); propose_trx->add_option("transaction", trx_to_push, localized("The JSON string or filename defining the transaction to push"))->required(); - propose_action->add_option("proposer", proposer, localized("Account proposing the transaction")); + propose_trx->add_option("proposer", proposer, localized("Account proposing the transaction")); propose_trx->set_callback([&] { fc::variant requested_perm_var; From a53efe7c4663bcb2b34aa822c57e9c0befdd1dc3 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Fri, 29 Jun 2018 17:20:52 -0400 Subject: [PATCH 15/21] Update tester.hpp Added changes for sudo contract --- libraries/testing/include/eosio/testing/tester.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index c94cbfadbcd..bfdab58cd08 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -56,8 +56,8 @@ namespace boost { namespace test_tools { namespace tt_detail { namespace eosio { namespace testing { std::vector read_wasm( const char* fn ); - std::vector read_abi( const char* fn ); - + std::vector read_abi( const char* fn ); + std::string read_wast( const char* fn ); using namespace eosio::chain; fc::variant_object filter_fields(const fc::variant_object& filter, const fc::variant_object& value); @@ -123,9 +123,9 @@ namespace eosio { namespace testing { action get_action( account_name code, action_name acttype, vector auths, const variant_object& data )const; - void set_transaction_headers(signed_transaction& trx, + void set_transaction_headers( transaction& trx, uint32_t expiration = DEFAULT_EXPIRATION_DELTA, - uint32_t delay_sec = 0)const; + uint32_t delay_sec = 0 )const; vector create_accounts( vector names, bool multisig = false, From 740cece219298129d4c7ebd549f9b43fd91d8b83 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Fri, 29 Jun 2018 17:22:00 -0400 Subject: [PATCH 16/21] Update tester.cpp --- libraries/testing/tester.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index 447ed0c90c0..6e1ee03a24c 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -13,6 +13,20 @@ eosio::chain::asset core_from_string(const std::string& s) { } namespace eosio { namespace testing { + std::string read_wast( const char* fn ) { + std::ifstream wast_file(fn); + FC_ASSERT( wast_file.is_open(), "wast file cannot be found" ); + wast_file.seekg(0, std::ios::end); + std::vector wast; + int len = wast_file.tellg(); + FC_ASSERT( len >= 0, "wast file length is -1" ); + wast.resize(len+1); + wast_file.seekg(0, std::ios::beg); + wast_file.read(wast.data(), wast.size()); + wast[wast.size()-1] = '\0'; + wast_file.close(); + return {wast.data()}; + } std::vector read_wasm( const char* fn ) { std::ifstream wasm_file(fn, std::ios::binary); @@ -247,7 +261,7 @@ namespace eosio { namespace testing { } - void base_tester::set_transaction_headers( signed_transaction& trx, uint32_t expiration, uint32_t delay_sec ) const { + void base_tester::set_transaction_headers( transaction& trx, uint32_t expiration, uint32_t delay_sec ) const { trx.expiration = control->head_block_time() + fc::seconds(expiration); trx.set_reference_block( control->head_block_id() ); From d86b30b4c3a98bb6fc3c611f5afdba760d577c21 Mon Sep 17 00:00:00 2001 From: arhag Date: Fri, 29 Jun 2018 21:00:28 -0400 Subject: [PATCH 17/21] add guide to deploying and using eosio.sudo contract #4142 --- contracts/eosio.sudo/README.md | 884 ++++++++++++++++++++++++++++++++- 1 file changed, 877 insertions(+), 7 deletions(-) diff --git a/contracts/eosio.sudo/README.md b/contracts/eosio.sudo/README.md index 9c6873cafb4..af1031e0126 100644 --- a/contracts/eosio.sudo/README.md +++ b/contracts/eosio.sudo/README.md @@ -1,16 +1,886 @@ -eosio.sudo --------- +# eosio.sudo -Actions: +## 1. Actions: The naming convention is codeaccount::actionname followed by a list of parameters. -Execute a transaction while bypassing regular authorization checks (requires authorization of eosio.sudo which needs to be a privileged account) -## eosio.sudo::exec executer trx +Execute a transaction while bypassing regular authorization checks (requires authorization of eosio.sudo which needs to be a privileged account). + +### eosio.sudo::exec executer trx - **executer** account executing the transaction - **trx** transaction to execute Deferred transaction RAM usage is billed to 'executer' -Cleos usage example. -TODO: Fill in cleos usage example. +## 2. Installing the eosio.sudo contract + +The eosio.sudo contract needs to be installed on a privileged account to function. It is recommended to use the account `eosio.sudo`. + +First, the account `eosio.sudo` needs to be created. Since it has the restricted `eosio.` prefix, only a privileged account can create this account. So this guide will use the `eosio` account to create the `eosio.sudo` account. On typical live blockchain configurations, the `eosio` account can only be controlled by a supermajority of the current active block producers. So, this guide will use the `eosio.msig` contract to help coordinate the approvals of the proposed transaction that creates the `eosio.sudo` account. + +The `eosio.sudo` account also needs to have sufficient RAM to host the contract and sufficient CPU and network bandwidth to deploy the contract. This means that the creator of the account (`eosio`) needs to gift sufficient RAM to the new account and delegate (preferably with transfer) sufficient bandwidth to the new account. To pull this off the `eosio` account needs to have enough of the core system token (the `SYS` token will be used within this guide) in its liquid balance. So prior to continuing with the next steps of this guide, the active block producers of the chain who are coordinating this process need to ensure that a sufficient amount of core system tokens that they are authorized to spend is placed in the liquid balance of the `eosio` account. + +This guide will be using cleos to carry out the process. + +### 2.1 Create the eosio.sudo account + +#### 2.1.1 Generate the transaction to create the eosio.sudo account + +The transaction to create the `eosio.sudo` account will need to be proposed to get the necessary approvals from active block producers before executing it. This transaction needs to first be generated and stored as JSON into a file so that it can be used in the cleos command to propose the transaction to the eosio.msig contract. + +A simple way to generate a transaction to create a new account is to use the `cleos system newaccount`. However, that sub-command currently only accepts a single public key as the owner and active authority of the new account. However, the owner and active authorities of the new account should only be satisfied by the `active` permission of `eosio`. One option is to create the new account with the some newly generated key, and then later update the authorities of the new account using `cleos set account permission`. This guide will take an alternative approach which atomically creates the new account in its proper configuration. + +Three unsigned transactions will be generated using cleos and then the actions within those transactions will be appropriately stitched together into a single transaction which will later be proposed using the eosio.msig contract. + +First, generate a transaction to capture the necessary actions involved in creating a new account: +``` +$ cleos system newaccount -s -j -d --transfer --stake-net "1.000 SYS" --stake-cpu "1.000 SYS" --buy-ram-kbytes 50 eosio eosio.sudo EOS8MMUW11TAdTDxqdSwSqJodefSoZbFhcprndomgLi9MeR2o8MT4 > generated_account_creation_trx.json +726964ms thread-0 main.cpp:429 create_action ] result: {"binargs":"0000000000ea305500004d1a03ea305500c80000"} arg: {"code":"eosio","action":"buyrambytes","args":{"payer":"eosio","receiver":"eosio.sudo","bytes":51200}} +726967ms thread-0 main.cpp:429 create_action ] result: {"binargs":"0000000000ea305500004d1a03ea3055102700000000000004535953000000001027000000000000045359530000000001"} arg: {"code":"eosio","action":"delegatebw","args":{"from":"eosio","receiver":"eosio.sudo","stake_net_quantity":"1.0000 SYS","stake_cpu_quantity":"1.0000 SYS","transfer":true}} +$ cat generated_account_creation_trx.json +{ + "expiration": "2018-06-29T17:11:36", + "ref_block_num": 16349, + "ref_block_prefix": 3248946195, + "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": "0000000000ea305500004d1a03ea305501000000010003c8162ea04fed738bfd5470527fd1ae7454c2e9ad1acbadec9f9e35bab2f33c660100000001000000010003c8162ea04fed738bfd5470527fd1ae7454c2e9ad1acbadec9f9e35bab2f33c6601000000" + },{ + "account": "eosio", + "name": "buyrambytes", + "authorization": [{ + "actor": "eosio", + "permission": "active" + } + ], + "data": "0000000000ea305500004d1a03ea305500c80000" + },{ + "account": "eosio", + "name": "delegatebw", + "authorization": [{ + "actor": "eosio", + "permission": "active" + } + ], + "data": "0000000000ea305500004d1a03ea3055102700000000000004535953000000001027000000000000045359530000000001" + } + ], + "transaction_extensions": [], + "signatures": [], + "context_free_data": [] +} +``` +Adjust the amount of delegated tokens and the amount of RAM bytes to gift as necessary. +The actual public key used is not important since that data is only encoded into the `eosio::newaccount` action which will be replaced soon anyway. + +Second, create a file (e.g. newaccount_payload.json) with the JSON payload for the real `eosio::newaccount` action. It should look like: +``` +$ cat newaccount_payload.json +{ + "creator": "eosio", + "name": "eosio.sudo", + "owner": { + "threshold": 1, + "keys": [], + "accounts": [{ + "permission": {"actor": "eosio", "permission": "active"}, + "weight": 1 + }], + "waits": [] + }, + "active": { + "threshold": 1, + "keys": [], + "accounts": [{ + "permission": {"actor": "eosio", "permission": "active"}, + "weight": 1 + }], + "waits": [] + } +} +``` + +Third, generate a transaction containing the actual `eosio::newaccount` action that will be used in the final transaction: +``` +$ cleos push action -s -j -d eosio newaccount newaccount_payload.json -p eosio > generated_newaccount_trx.json +$ cat generated_newaccount_trx.json +{ + "expiration": "2018-06-29T17:11:36", + "ref_block_num": 16349, + "ref_block_prefix": 3248946195, + "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": "0000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed3232010000" + } + ], + "transaction_extensions": [], + "signatures": [], + "context_free_data": [] +} +``` + +Fourth, generate a transaction containing the `eosio::setpriv` action which will make the `eosio.sudo` account privileged: +``` +$ cleos push action -s -j -d eosio setpriv '{"account": "eosio.sudo", "is_priv": 1}' -p eosio > generated_setpriv_trx.json +$ cat generated_setpriv_trx.json +{ + "expiration": "2018-06-29T17:11:36", + "ref_block_num": 16349, + "ref_block_prefix": 3248946195, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ + "account": "eosio", + "name": "setpriv", + "authorization": [{ + "actor": "eosio", + "permission": "active" + } + ], + "data": "00004d1a03ea305501" + } + ], + "transaction_extensions": [], + "signatures": [], + "context_free_data": [] +} +``` + +Next, the action JSONs of the previously generated transactions will be used to construct a unified transaction which will eventually be proposed with the eosio.msig contract. A good way to get started is to make a copy of the generated_newaccount_trx.json file (call the copied file create_sudo_account_trx.json) and edit the first three fields so it looks something like the following: +``` +$ cat create_sudo_account_trx.json +{ + "expiration": "2018-07-06T12:00:00", + "ref_block_num": 0, + "ref_block_prefix": 0, + "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": "0000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed3232010000" + } + ], + "transaction_extensions": [], + "signatures": [], + "context_free_data": [] +} +``` + +The `ref_block_num` and `ref_block_prefix` values were set to 0. The proposed transaction does not need to have a valid TaPoS reference block because it will be reset anyway when scheduled as a deferred transaction during the `eosio.msig::exec` action. The `expiration` field, which was the only other field that was changed, will also be reset when the proposed transaction is scheduled as a deferred transaction during `eosio.msig::exec`. However, this field actually does matter during the propose-approve-exec lifecycle of the proposed transaction. If the present time passes the time in the `expiration` field of the proposed transaction, it will not be possible to execute the proposed transaction even if all necessary approvals are gathered. Therefore, it is important to set the expiration time to some point well enough in the future to give all necessary approvers enough time to review and approve the proposed transaction, but it is otherwise arbitrary. Generally, for reviewing/validation purposes it is important that all potential approvers of the transaction (i.e. the block producers) choose the exact same `expiration` time so that there is not any discrepancy in bytes of the serialized transaction if it was to later be included in payload data of some other action. + +Then, all but the first action JSON object of generated_account_creation_trx.json should be appended to the `actions` array of create_sudo_account_trx.json, and then the single action JSON object of generated_setpriv_trx.json should be appended to the `actions` array of create_sudo_account_trx.json. The final result is a create_sudo_account_trx.json file that looks like the following: +``` +$ cat create_sudo_account_trx.json +{ + "expiration": "2018-07-06T12:00:00", + "ref_block_num": 0, + "ref_block_prefix": 0, + "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": "0000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed3232010000" + },{ + "account": "eosio", + "name": "buyrambytes", + "authorization": [{ + "actor": "eosio", + "permission": "active" + } + ], + "data": "0000000000ea305500004d1a03ea305500c80000" + },{ + "account": "eosio", + "name": "delegatebw", + "authorization": [{ + "actor": "eosio", + "permission": "active" + } + ], + "data": "0000000000ea305500004d1a03ea3055102700000000000004535953000000001027000000000000045359530000000001" + },{ + "account": "eosio", + "name": "setpriv", + "authorization": [{ + "actor": "eosio", + "permission": "active" + } + ], + "data": "00004d1a03ea305501" + } + ], + "transaction_extensions": [], + "signatures": [], + "context_free_data": [] +} +``` + +The transaction in create_sudo_account_trx.json is now ready to be proposed. + +It will be useful to have a JSON of the active permissions of each of the active block producers for later when proposing transactions using the eosio.msig contract. + +This guide will assume that there are 21 active block producers on the chain with account names: `blkproducera`, `blkproducerb`, ..., `blkproduceru`. + +In that case, create a file producer_permissions.json with the content shown in the command below: +``` +$ cat producer_permissions.json +[ + {"actor": "blkproducera", "permission": "active"}, + {"actor": "blkproducerb", "permission": "active"}, + {"actor": "blkproducerc", "permission": "active"}, + {"actor": "blkproducerd", "permission": "active"}, + {"actor": "blkproducere", "permission": "active"}, + {"actor": "blkproducerf", "permission": "active"}, + {"actor": "blkproducerg", "permission": "active"}, + {"actor": "blkproducerh", "permission": "active"}, + {"actor": "blkproduceri", "permission": "active"}, + {"actor": "blkproducerj", "permission": "active"}, + {"actor": "blkproducerk", "permission": "active"}, + {"actor": "blkproducerl", "permission": "active"}, + {"actor": "blkproducerm", "permission": "active"}, + {"actor": "blkproducern", "permission": "active"}, + {"actor": "blkproducero", "permission": "active"}, + {"actor": "blkproducerp", "permission": "active"}, + {"actor": "blkproducerq", "permission": "active"}, + {"actor": "blkproducerr", "permission": "active"}, + {"actor": "blkproducers", "permission": "active"}, + {"actor": "blkproducert", "permission": "active"}, + {"actor": "blkproduceru", "permission": "active"} +] +``` + +#### 2.1.2 Propose the transaction to create the eosio.sudo account + +Only one of the potential approvers will need to propose the transaction that was created in the previous sub-section. All the other approvers should still follow the steps in the previous sub-section to generate the same create_sudo_account_trx.json file as all the other approvers. They will need this to compare to the actual proposed transaction prior to approving. + +The approvers are typically going to be the active block producers of the chain, so it makes sense that one of the block producers is elected as the leader to propose the actual transaction. Note that this lead block producer will need to incur the temporary RAM cost of proposing the transaction, but they will get the RAM back when the proposal has executed or has been canceled (which only the proposer can do prior to expiration). + +The guide will assume that `blkproducera` was chosen as the lead block producer to propose the transaction. + +The lead block producer (`blkproducera`) should propose the transaction stored in create_sudo_account_trx.json: +``` +$ cleos multisig propose_trx createsudo producer_permissions.json create_sudo_account_trx.json blkproducera +executed transaction: bf6aaa06b40e2a35491525cb11431efd2b5ac94e4a7a9c693c5bf0cfed942393 744 bytes 772 us +# eosio.msig <= eosio.msig::propose {"proposer":"blkproducera","proposal_name":"createsudo","requested":[{"actor":"blkproducera","permis... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +#### 2.1.3 Review and approve the transaction to create the eosio.sudo account + +Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. + +The proposed transaction can be reviewed using the `cleos multisig review` command: +``` +$ cleos multisig review blkproducera createsudo > create_sudo_account_trx_to_review.json +$ head -n 30 create_sudo_account_trx_to_review.json +{ + "proposal_name": "createsudo", + "packed_transaction": "c0593f5b00000000000000000000040000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232420000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed32320100000000000000ea305500b0cafe4873bd3e010000000000ea305500000000a8ed3232140000000000ea305500004d1a03ea3055002800000000000000ea305500003f2a1ba6a24a010000000000ea305500000000a8ed3232310000000000ea305500004d1a03ea30551027000000000000045359530000000010270000000000000453595300000000010000000000ea305500000060bb5bb3c2010000000000ea305500000000a8ed32320900004d1a03ea30550100", + "transaction": { + "expiration": "2018-07-06T12:00:00", + "ref_block_num": 0, + "ref_block_prefix": 0, + "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": "eosio.sudo", + "owner": { + "threshold": 1, + "keys": [], + "accounts": [{ + "permission": { + "actor": "eosio", + "permission": "active" + }, +``` + +The approvers should go through the full human-readable transaction output and make sure everything looks fine. But they can also use tools to automatically compare the proposed transaction to the one they generated to make sure there are absolutely no differences: +``` +$ cleos multisig propose_trx -j -s -d createsudo '[]' create_sudo_account_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_create_sudo_trx_serialized.hex +$ cat expected_create_sudo_trx_serialized.hex +c0593f5b00000000000000000000040000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232420000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed32320100000000000000ea305500b0cafe4873bd3e010000000000ea305500000000a8ed3232140000000000ea305500004d1a03ea3055002800000000000000ea305500003f2a1ba6a24a010000000000ea305500000000a8ed3232310000000000ea305500004d1a03ea30551027000000000000045359530000000010270000000000000453595300000000010000000000ea305500000060bb5bb3c2010000000000ea305500000000a8ed32320900004d1a03ea30550100 +$ cat create_sudo_account_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_create_sudo_trx_serialized.hex +$ cat proposed_create_sudo_trx_serialized.hex +c0593f5b00000000000000000000040000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232420000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed32320100000000000000ea305500b0cafe4873bd3e010000000000ea305500000000a8ed3232140000000000ea305500004d1a03ea3055002800000000000000ea305500003f2a1ba6a24a010000000000ea305500000000a8ed3232310000000000ea305500004d1a03ea30551027000000000000045359530000000010270000000000000453595300000000010000000000ea305500000060bb5bb3c2010000000000ea305500000000a8ed32320900004d1a03ea30550100 +$ diff expected_create_sudo_trx_serialized.hex proposed_create_sudo_trx_serialized.hex +``` + +When an approver (e.g. `blkproducerb`) is satisfied with the proposed transaction, they can simply approve it: +``` +$ cleos multisig approve blkproducera createsudo '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb +executed transaction: 03a907e2a3192aac0cd040c73db8273c9da7696dc7960de22b1a479ae5ee9f23 128 bytes 472 us +# eosio.msig <= eosio.msig::approve {"proposer":"blkproducera","proposal_name":"createsudo","level":{"actor":"blkproducerb","permission"... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +#### 2.1.4 Execute the transaction to create the eosio.sudo account + +When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). + +``` +$ cleos multisig exec blkproducera createsudo blkproducera +executed transaction: 7ecc183b99915cc411f96dde7c35c3fe0df6e732507f272af3a039b706482e5a 160 bytes 850 us +# eosio.msig <= eosio.msig::exec {"proposer":"blkproducera","proposal_name":"createsudo","executer":"blkproducera"} +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +Anyone can now verify that the `eosio.sudo` was created: +``` +$ cleos get account eosio.sudo +privileged: true +permissions: + owner 1: 1 eosio@active, + active 1: 1 eosio@active, +memory: + quota: 49.74 KiB used: 3.33 KiB + +net bandwidth: + staked: 1.0000 SYS (total stake delegated from account to self) + delegated: 0.0000 SYS (total staked delegated to account from others) + used: 0 bytes + available: 2.304 MiB + limit: 2.304 MiB + +cpu bandwidth: + staked: 1.0000 SYS (total stake delegated from account to self) + delegated: 0.0000 SYS (total staked delegated to account from others) + used: 0 us + available: 460.8 ms + limit: 460.8 ms + +producers: + +``` + +### 2.2 Deploy the eosio.sudo contract + +#### 2.2.1 Generate the transaction to deploy the eosio.sudo contract + +The transaction to deploy the contract to the `eosio.sudo` account will need to be proposed to get the necessary approvals from active block producers before executing it. This transaction needs to first be generated and stored as JSON into a file so that it can be used in the cleos command to propose the transaction to the eosio.msig contract. + +The easy way to generate this transaction is using cleos: +``` +$ cleos set contract -s -j -d eosio.sudo contracts/eosio.sudo/ > deploy_sudo_contract_trx.json +Reading WAST/WASM from contracts/eosio.sudo/eosio.sudo.wasm... +Using already assembled WASM... +Publishing contract... +$ cat deploy_sudo_contract_trx.json +{ + "expiration": "2018-06-29T19:55:26", + "ref_block_num": 18544, + "ref_block_prefix": 562790588, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ + "account": "eosio", + "name": "setcode", + "authorization": [{ + "actor": "eosio.sudo", + "permission": "active" + } + ], + "data": "00004d1a03ea30550000c8180061736d01000000013e0c60017f006000017e60027e7e0060017e006000017f60027f7f017f60027f7f0060037f7f7f017f60057f7e7f7f7f0060000060037e7e7e0060017f017f029d010803656e7610616374696f6e5f646174615f73697a65000403656e760c63757272656e745f74696d65000103656e760c656f73696f5f617373657274000603656e76066d656d637079000703656e7610726561645f616374696f6e5f64617461000503656e760c726571756972655f61757468000303656e760d726571756972655f6175746832000203656e760d73656e645f64656665727265640008030f0e0505050400000a05070b050b000904050170010202050301000107c7010b066d656d6f72790200165f5a6571524b3131636865636b73756d32353653315f0008165f5a6571524b3131636865636b73756d31363053315f0009165f5a6e65524b3131636865636b73756d31363053315f000a036e6f77000b305f5a4e35656f73696f3132726571756972655f6175746845524b4e535f31367065726d697373696f6e5f6c6576656c45000c155f5a4e35656f73696f347375646f34657865634576000d056170706c79000e066d656d636d700010066d616c6c6f630011046672656500140908010041000b02150d0a9a130e0b002000200141201010450b0b002000200141201010450b0d0020002001412010104100470b0a00100142c0843d80a70b0e002000290300200029030810060b9e0102017e027f410028020441206b2202210341002002360204200029030010050240024010002200418104490d002000101121020c010b410020022000410f6a4170716b22023602040b2002200010041a200041074b41101002200341186a2002410810031a2003290318100520032903182101200310013703002003200137030820032003290318200241086a2000410010074100200341206a3602040bfd0403027f047e017f4100410028020441206b220936020442002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b024020072002520d0042002106423b2105413021044200210703400240024002400240024020064204560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b200720015141c00010020b0240024020012000510d0042002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b20072002520d010b20092000370318200242808080808080a0aad700520d00200941003602142009410136021020092009290310370208200941186a200941086a100f1a0b4100200941206a3602040b8c0101047f4100280204220521042001280204210220012802002101024010002203450d00024020034180044d0d00200310112205200310041a200510140c010b410020052003410f6a4170716b22053602042005200310041a0b200020024101756a210302402002410171450d00200328020020016a28020021010b200320011100004100200436020441010b4901037f4100210502402002450d000240034020002d0000220320012d00002204470d01200141016a2101200041016a21002002417f6a22020d000c020b0b200320046b21050b20050b0900418001200010120bcd04010c7f02402001450d00024020002802c041220d0d004110210d200041c0c1006a41103602000b200141086a200141046a41077122026b200120021b210202400240024020002802c441220a200d4f0d002000200a410c6c6a4180c0006a21010240200a0d0020004184c0006a220d2802000d0020014180c000360200200d20003602000b200241046a210a034002402001280208220d200a6a20012802004b0d002001280204200d6a220d200d28020041808080807871200272360200200141086a22012001280200200a6a360200200d200d28020041808080807872360200200d41046a22010d030b2000101322010d000b0b41fcffffff0720026b2104200041c8c1006a210b200041c0c1006a210c20002802c8412203210d03402000200d410c6c6a22014188c0006a28020020014180c0006a22052802004641d0c200100220014184c0006a280200220641046a210d0340200620052802006a2107200d417c6a2208280200220941ffffffff07712101024020094100480d000240200120024f0d000340200d20016a220a20074f0d01200a280200220a4100480d012001200a41ffffffff07716a41046a22012002490d000b0b20082001200220012002491b200941808080807871723602000240200120024d0d00200d20026a200420016a41ffffffff07713602000b200120024f0d040b200d20016a41046a220d2007490d000b41002101200b4100200b28020041016a220d200d200c280200461b220d360200200d2003470d000b0b20010f0b2008200828020041808080807872360200200d0f0b41000b870501087f20002802c44121010240024041002d00a643450d0041002802a84321070c010b3f002107410041013a00a6434100200741107422073602a8430b200721030240024002400240200741ffff036a41107622023f0022084d0d00200220086b40001a4100210820023f00470d0141002802a84321030b41002108410020033602a84320074100480d0020002001410c6c6a210220074180800441808008200741ffff037122084181f8034922061b6a2008200741ffff077120061b6b20076b2107024041002d00a6430d003f002103410041013a00a6434100200341107422033602a8430b20024180c0006a210220074100480d01200321060240200741076a417871220520036a41ffff036a41107622083f0022044d0d00200820046b40001a20083f00470d0241002802a84321060b4100200620056a3602a8432003417f460d0120002001410c6c6a22014184c0006a2802002206200228020022086a2003460d020240200820014188c0006a22052802002201460d00200620016a2206200628020041808080807871417c20016b20086a72360200200520022802003602002006200628020041ffffffff07713602000b200041c4c1006a2202200228020041016a220236020020002002410c6c6a22004184c0006a200336020020004180c0006a220820073602000b20080f0b02402002280200220820002001410c6c6a22034188c0006a22012802002207460d0020034184c0006a28020020076a2203200328020041808080807871417c20076b20086a72360200200120022802003602002003200328020041ffffffff07713602000b2000200041c4c1006a220728020041016a22033602c0412007200336020041000f0b2002200820076a36020020020b7b01037f024002402000450d0041002802c04222024101480d004180c10021032002410c6c4180c1006a21010340200341046a2802002202450d010240200241046a20004b0d00200220032802006a20004b0d030b2003410c6a22032001490d000b0b0f0b2000417c6a2203200328020041ffffffff07713602000b0300000b0bcf01060041040b04b04900000041100b0572656164000041200b086f6e6572726f72000041300b06656f73696f000041c0000b406f6e6572726f7220616374696f6e277320617265206f6e6c792076616c69642066726f6d207468652022656f73696f222073797374656d206163636f756e74000041d0c2000b566d616c6c6f635f66726f6d5f6672656564207761732064657369676e656420746f206f6e6c792062652063616c6c6564206166746572205f686561702077617320636f6d706c6574656c7920616c6c6f636174656400" + },{ + "account": "eosio", + "name": "setabi", + "authorization": [{ + "actor": "eosio.sudo", + "permission": "active" + } + ], + "data": "00004d1a03ea3055df040e656f73696f3a3a6162692f312e30030c6163636f756e745f6e616d65046e616d650f7065726d697373696f6e5f6e616d65046e616d650b616374696f6e5f6e616d65046e616d6506107065726d697373696f6e5f6c6576656c0002056163746f720c6163636f756e745f6e616d650a7065726d697373696f6e0f7065726d697373696f6e5f6e616d6506616374696f6e0004076163636f756e740c6163636f756e745f6e616d65046e616d650b616374696f6e5f6e616d650d617574686f72697a6174696f6e127065726d697373696f6e5f6c6576656c5b5d0464617461056279746573127472616e73616374696f6e5f68656164657200060a65787069726174696f6e0e74696d655f706f696e745f7365630d7265665f626c6f636b5f6e756d0675696e743136107265665f626c6f636b5f7072656669780675696e743332136d61785f6e65745f75736167655f776f7264730976617275696e743332106d61785f6370755f75736167655f6d730575696e74380964656c61795f7365630976617275696e74333209657874656e73696f6e000204747970650675696e74313604646174610562797465730b7472616e73616374696f6e127472616e73616374696f6e5f6865616465720314636f6e746578745f667265655f616374696f6e7308616374696f6e5b5d07616374696f6e7308616374696f6e5b5d167472616e73616374696f6e5f657874656e73696f6e730b657874656e73696f6e5b5d046578656300020865786563757465720c6163636f756e745f6e616d65037472780b7472616e73616374696f6e01000000000080545704657865630000000000" + } + ], + "transaction_extensions": [], + "signatures": [], + "context_free_data": [] +} +``` + +Once again, as described in sub-section 2.1.1, edit the values of the `ref_block_num` and `ref_block_prefix` fields to be 0 and edit the time of the `expiration` field to some point in the future that provides enough time to approve and execute the proposed transaction. After editing deploy_sudo_contract_trx.json the first few lines of it may look something like the following: +``` +$ head -n 9 deploy_sudo_contract_trx.json +{ + "expiration": "2018-07-06T12:00:00", + "ref_block_num": 0, + "ref_block_prefix": 0, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ +``` + +This guide will assume that there are 21 active block producers on the chain with account names: `blkproducera`, `blkproducerb`, ..., `blkproduceru`. The end of sub-section 2.1.1 displayed what the JSON of the active permissions of each of the active block producers would look like given the assumptions about the active block producer set. That JSON was stored in the file producer_permissions.json; if the approvers (i.e. block producers) have not created that file already, they should create that file now as shown at the end of sub-section 2.1.1. + +#### 2.2.2 Propose the transaction to deploy the eosio.sudo contract + +Only one of the potential approvers will need to propose the transaction that was created in the previous sub-section. All the other approvers should still follow the steps in the previous sub-section to generate the same deploy_sudo_contract_trx.json file as all the other approvers. They will need this to compare to the actual proposed transaction prior to approving. + +The approvers are typically going to be the active block producers of the chain, so it makes sense that one of the block producers is elected as the leader to propose the actual transaction. Note that this lead block producer will need to incur the temporary RAM cost of proposing the transaction, but they will get the RAM back when the proposal has executed or has been canceled (which only the proposer can do prior to expiration). + +This guide will assume that `blkproducera` was chosen as the lead block producer to propose the transaction. + +The lead block producer (`blkproducera`) should propose the transaction stored in deploy_sudo_contract_trx.json: +``` +$ cleos multisig propose_trx deploysudo producer_permissions.json deploy_sudo_contract_trx.json blkproducera +executed transaction: 9e50dd40eba25583a657ee8114986a921d413b917002c8fb2d02e2d670f720a8 4312 bytes 871 us +# eosio.msig <= eosio.msig::propose {"proposer":"blkproducera","proposal_name":"deploysudo","requested":[{"actor":"blkproducera","permis... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +#### 2.2.3 Review and approve the transaction to deploy the eosio.sudo contract + +Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. + +The proposed transaction can be reviewed using the `cleos multisig review` command: +``` +$ cleos multisig review blkproducera deploysudo > deploy_sudo_contract_trx_to_review.json +$ cat deploy_sudo_contract_trx_to_review.json +{ + "proposal_name": "deploysudo", + "packed_transaction": "c0593f5b00000000000000000000020000000000ea305500000040258ab2c20100004d1a03ea305500000000a8ed3232d41800004d1a03ea30550000c8180061736d01000000013e0c60017f006000017e60027e7e0060017e006000017f60027f7f017f60027f7f0060037f7f7f017f60057f7e7f7f7f0060000060037e7e7e0060017f017f029d010803656e7610616374696f6e5f646174615f73697a65000403656e760c63757272656e745f74696d65000103656e760c656f73696f5f617373657274000603656e76066d656d637079000703656e7610726561645f616374696f6e5f64617461000503656e760c726571756972655f61757468000303656e760d726571756972655f6175746832000203656e760d73656e645f64656665727265640008030f0e0505050400000a05070b050b000904050170010202050301000107c7010b066d656d6f72790200165f5a6571524b3131636865636b73756d32353653315f0008165f5a6571524b3131636865636b73756d31363053315f0009165f5a6e65524b3131636865636b73756d31363053315f000a036e6f77000b305f5a4e35656f73696f3132726571756972655f6175746845524b4e535f31367065726d697373696f6e5f6c6576656c45000c155f5a4e35656f73696f347375646f34657865634576000d056170706c79000e066d656d636d700010066d616c6c6f630011046672656500140908010041000b02150d0a9a130e0b002000200141201010450b0b002000200141201010450b0d0020002001412010104100470b0a00100142c0843d80a70b0e002000290300200029030810060b9e0102017e027f410028020441206b2202210341002002360204200029030010050240024010002200418104490d002000101121020c010b410020022000410f6a4170716b22023602040b2002200010041a200041074b41101002200341186a2002410810031a2003290318100520032903182101200310013703002003200137030820032003290318200241086a2000410010074100200341206a3602040bfd0403027f047e017f4100410028020441206b220936020442002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b024020072002520d0042002106423b2105413021044200210703400240024002400240024020064204560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b200720015141c00010020b0240024020012000510d0042002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b20072002520d010b20092000370318200242808080808080a0aad700520d00200941003602142009410136021020092009290310370208200941186a200941086a100f1a0b4100200941206a3602040b8c0101047f4100280204220521042001280204210220012802002101024010002203450d00024020034180044d0d00200310112205200310041a200510140c010b410020052003410f6a4170716b22053602042005200310041a0b200020024101756a210302402002410171450d00200328020020016a28020021010b200320011100004100200436020441010b4901037f4100210502402002450d000240034020002d0000220320012d00002204470d01200141016a2101200041016a21002002417f6a22020d000c020b0b200320046b21050b20050b0900418001200010120bcd04010c7f02402001450d00024020002802c041220d0d004110210d200041c0c1006a41103602000b200141086a200141046a41077122026b200120021b210202400240024020002802c441220a200d4f0d002000200a410c6c6a4180c0006a21010240200a0d0020004184c0006a220d2802000d0020014180c000360200200d20003602000b200241046a210a034002402001280208220d200a6a20012802004b0d002001280204200d6a220d200d28020041808080807871200272360200200141086a22012001280200200a6a360200200d200d28020041808080807872360200200d41046a22010d030b2000101322010d000b0b41fcffffff0720026b2104200041c8c1006a210b200041c0c1006a210c20002802c8412203210d03402000200d410c6c6a22014188c0006a28020020014180c0006a22052802004641d0c200100220014184c0006a280200220641046a210d0340200620052802006a2107200d417c6a2208280200220941ffffffff07712101024020094100480d000240200120024f0d000340200d20016a220a20074f0d01200a280200220a4100480d012001200a41ffffffff07716a41046a22012002490d000b0b20082001200220012002491b200941808080807871723602000240200120024d0d00200d20026a200420016a41ffffffff07713602000b200120024f0d040b200d20016a41046a220d2007490d000b41002101200b4100200b28020041016a220d200d200c280200461b220d360200200d2003470d000b0b20010f0b2008200828020041808080807872360200200d0f0b41000b870501087f20002802c44121010240024041002d00a643450d0041002802a84321070c010b3f002107410041013a00a6434100200741107422073602a8430b200721030240024002400240200741ffff036a41107622023f0022084d0d00200220086b40001a4100210820023f00470d0141002802a84321030b41002108410020033602a84320074100480d0020002001410c6c6a210220074180800441808008200741ffff037122084181f8034922061b6a2008200741ffff077120061b6b20076b2107024041002d00a6430d003f002103410041013a00a6434100200341107422033602a8430b20024180c0006a210220074100480d01200321060240200741076a417871220520036a41ffff036a41107622083f0022044d0d00200820046b40001a20083f00470d0241002802a84321060b4100200620056a3602a8432003417f460d0120002001410c6c6a22014184c0006a2802002206200228020022086a2003460d020240200820014188c0006a22052802002201460d00200620016a2206200628020041808080807871417c20016b20086a72360200200520022802003602002006200628020041ffffffff07713602000b200041c4c1006a2202200228020041016a220236020020002002410c6c6a22004184c0006a200336020020004180c0006a220820073602000b20080f0b02402002280200220820002001410c6c6a22034188c0006a22012802002207460d0020034184c0006a28020020076a2203200328020041808080807871417c20076b20086a72360200200120022802003602002003200328020041ffffffff07713602000b2000200041c4c1006a220728020041016a22033602c0412007200336020041000f0b2002200820076a36020020020b7b01037f024002402000450d0041002802c04222024101480d004180c10021032002410c6c4180c1006a21010340200341046a2802002202450d010240200241046a20004b0d00200220032802006a20004b0d030b2003410c6a22032001490d000b0b0f0b2000417c6a2203200328020041ffffffff07713602000b0300000b0bcf01060041040b04b04900000041100b0572656164000041200b086f6e6572726f72000041300b06656f73696f000041c0000b406f6e6572726f7220616374696f6e277320617265206f6e6c792076616c69642066726f6d207468652022656f73696f222073797374656d206163636f756e74000041d0c2000b566d616c6c6f635f66726f6d5f6672656564207761732064657369676e656420746f206f6e6c792062652063616c6c6564206166746572205f686561702077617320636f6d706c6574656c7920616c6c6f6361746564000000000000ea305500000000b863b2c20100004d1a03ea305500000000a8ed3232e90400004d1a03ea3055df040e656f73696f3a3a6162692f312e30030c6163636f756e745f6e616d65046e616d650f7065726d697373696f6e5f6e616d65046e616d650b616374696f6e5f6e616d65046e616d6506107065726d697373696f6e5f6c6576656c0002056163746f720c6163636f756e745f6e616d650a7065726d697373696f6e0f7065726d697373696f6e5f6e616d6506616374696f6e0004076163636f756e740c6163636f756e745f6e616d65046e616d650b616374696f6e5f6e616d650d617574686f72697a6174696f6e127065726d697373696f6e5f6c6576656c5b5d0464617461056279746573127472616e73616374696f6e5f68656164657200060a65787069726174696f6e0e74696d655f706f696e745f7365630d7265665f626c6f636b5f6e756d0675696e743136107265665f626c6f636b5f7072656669780675696e743332136d61785f6e65745f75736167655f776f7264730976617275696e743332106d61785f6370755f75736167655f6d730575696e74380964656c61795f7365630976617275696e74333209657874656e73696f6e000204747970650675696e74313604646174610562797465730b7472616e73616374696f6e127472616e73616374696f6e5f6865616465720314636f6e746578745f667265655f616374696f6e7308616374696f6e5b5d07616374696f6e7308616374696f6e5b5d167472616e73616374696f6e5f657874656e73696f6e730b657874656e73696f6e5b5d046578656300020865786563757465720c6163636f756e745f6e616d65037472780b7472616e73616374696f6e0100000000008054570465786563000000000000", + "transaction": { + "expiration": "2018-07-06T12:00:00", + "ref_block_num": 0, + "ref_block_prefix": 0, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ + "account": "eosio", + "name": "setcode", + "authorization": [{ + "actor": "eosio.sudo", + "permission": "active" + } + ], + "data": { + "account": "eosio.sudo", + "vmtype": 0, + "vmversion": 0, + "code": "0061736d01000000013e0c60017f006000017e60027e7e0060017e006000017f60027f7f017f60027f7f0060037f7f7f017f60057f7e7f7f7f0060000060037e7e7e0060017f017f029d010803656e7610616374696f6e5f646174615f73697a65000403656e760c63757272656e745f74696d65000103656e760c656f73696f5f617373657274000603656e76066d656d637079000703656e7610726561645f616374696f6e5f64617461000503656e760c726571756972655f61757468000303656e760d726571756972655f6175746832000203656e760d73656e645f64656665727265640008030f0e0505050400000a05070b050b000904050170010202050301000107c7010b066d656d6f72790200165f5a6571524b3131636865636b73756d32353653315f0008165f5a6571524b3131636865636b73756d31363053315f0009165f5a6e65524b3131636865636b73756d31363053315f000a036e6f77000b305f5a4e35656f73696f3132726571756972655f6175746845524b4e535f31367065726d697373696f6e5f6c6576656c45000c155f5a4e35656f73696f347375646f34657865634576000d056170706c79000e066d656d636d700010066d616c6c6f630011046672656500140908010041000b02150d0a9a130e0b002000200141201010450b0b002000200141201010450b0d0020002001412010104100470b0a00100142c0843d80a70b0e002000290300200029030810060b9e0102017e027f410028020441206b2202210341002002360204200029030010050240024010002200418104490d002000101121020c010b410020022000410f6a4170716b22023602040b2002200010041a200041074b41101002200341186a2002410810031a2003290318100520032903182101200310013703002003200137030820032003290318200241086a2000410010074100200341206a3602040bfd0403027f047e017f4100410028020441206b220936020442002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b024020072002520d0042002106423b2105413021044200210703400240024002400240024020064204560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b200720015141c00010020b0240024020012000510d0042002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b20072002520d010b20092000370318200242808080808080a0aad700520d00200941003602142009410136021020092009290310370208200941186a200941086a100f1a0b4100200941206a3602040b8c0101047f4100280204220521042001280204210220012802002101024010002203450d00024020034180044d0d00200310112205200310041a200510140c010b410020052003410f6a4170716b22053602042005200310041a0b200020024101756a210302402002410171450d00200328020020016a28020021010b200320011100004100200436020441010b4901037f4100210502402002450d000240034020002d0000220320012d00002204470d01200141016a2101200041016a21002002417f6a22020d000c020b0b200320046b21050b20050b0900418001200010120bcd04010c7f02402001450d00024020002802c041220d0d004110210d200041c0c1006a41103602000b200141086a200141046a41077122026b200120021b210202400240024020002802c441220a200d4f0d002000200a410c6c6a4180c0006a21010240200a0d0020004184c0006a220d2802000d0020014180c000360200200d20003602000b200241046a210a034002402001280208220d200a6a20012802004b0d002001280204200d6a220d200d28020041808080807871200272360200200141086a22012001280200200a6a360200200d200d28020041808080807872360200200d41046a22010d030b2000101322010d000b0b41fcffffff0720026b2104200041c8c1006a210b200041c0c1006a210c20002802c8412203210d03402000200d410c6c6a22014188c0006a28020020014180c0006a22052802004641d0c200100220014184c0006a280200220641046a210d0340200620052802006a2107200d417c6a2208280200220941ffffffff07712101024020094100480d000240200120024f0d000340200d20016a220a20074f0d01200a280200220a4100480d012001200a41ffffffff07716a41046a22012002490d000b0b20082001200220012002491b200941808080807871723602000240200120024d0d00200d20026a200420016a41ffffffff07713602000b200120024f0d040b200d20016a41046a220d2007490d000b41002101200b4100200b28020041016a220d200d200c280200461b220d360200200d2003470d000b0b20010f0b2008200828020041808080807872360200200d0f0b41000b870501087f20002802c44121010240024041002d00a643450d0041002802a84321070c010b3f002107410041013a00a6434100200741107422073602a8430b200721030240024002400240200741ffff036a41107622023f0022084d0d00200220086b40001a4100210820023f00470d0141002802a84321030b41002108410020033602a84320074100480d0020002001410c6c6a210220074180800441808008200741ffff037122084181f8034922061b6a2008200741ffff077120061b6b20076b2107024041002d00a6430d003f002103410041013a00a6434100200341107422033602a8430b20024180c0006a210220074100480d01200321060240200741076a417871220520036a41ffff036a41107622083f0022044d0d00200820046b40001a20083f00470d0241002802a84321060b4100200620056a3602a8432003417f460d0120002001410c6c6a22014184c0006a2802002206200228020022086a2003460d020240200820014188c0006a22052802002201460d00200620016a2206200628020041808080807871417c20016b20086a72360200200520022802003602002006200628020041ffffffff07713602000b200041c4c1006a2202200228020041016a220236020020002002410c6c6a22004184c0006a200336020020004180c0006a220820073602000b20080f0b02402002280200220820002001410c6c6a22034188c0006a22012802002207460d0020034184c0006a28020020076a2203200328020041808080807871417c20076b20086a72360200200120022802003602002003200328020041ffffffff07713602000b2000200041c4c1006a220728020041016a22033602c0412007200336020041000f0b2002200820076a36020020020b7b01037f024002402000450d0041002802c04222024101480d004180c10021032002410c6c4180c1006a21010340200341046a2802002202450d010240200241046a20004b0d00200220032802006a20004b0d030b2003410c6a22032001490d000b0b0f0b2000417c6a2203200328020041ffffffff07713602000b0300000b0bcf01060041040b04b04900000041100b0572656164000041200b086f6e6572726f72000041300b06656f73696f000041c0000b406f6e6572726f7220616374696f6e277320617265206f6e6c792076616c69642066726f6d207468652022656f73696f222073797374656d206163636f756e74000041d0c2000b566d616c6c6f635f66726f6d5f6672656564207761732064657369676e656420746f206f6e6c792062652063616c6c6564206166746572205f686561702077617320636f6d706c6574656c7920616c6c6f636174656400" + }, + "hex_data": "00004d1a03ea30550000c8180061736d01000000013e0c60017f006000017e60027e7e0060017e006000017f60027f7f017f60027f7f0060037f7f7f017f60057f7e7f7f7f0060000060037e7e7e0060017f017f029d010803656e7610616374696f6e5f646174615f73697a65000403656e760c63757272656e745f74696d65000103656e760c656f73696f5f617373657274000603656e76066d656d637079000703656e7610726561645f616374696f6e5f64617461000503656e760c726571756972655f61757468000303656e760d726571756972655f6175746832000203656e760d73656e645f64656665727265640008030f0e0505050400000a05070b050b000904050170010202050301000107c7010b066d656d6f72790200165f5a6571524b3131636865636b73756d32353653315f0008165f5a6571524b3131636865636b73756d31363053315f0009165f5a6e65524b3131636865636b73756d31363053315f000a036e6f77000b305f5a4e35656f73696f3132726571756972655f6175746845524b4e535f31367065726d697373696f6e5f6c6576656c45000c155f5a4e35656f73696f347375646f34657865634576000d056170706c79000e066d656d636d700010066d616c6c6f630011046672656500140908010041000b02150d0a9a130e0b002000200141201010450b0b002000200141201010450b0d0020002001412010104100470b0a00100142c0843d80a70b0e002000290300200029030810060b9e0102017e027f410028020441206b2202210341002002360204200029030010050240024010002200418104490d002000101121020c010b410020022000410f6a4170716b22023602040b2002200010041a200041074b41101002200341186a2002410810031a2003290318100520032903182101200310013703002003200137030820032003290318200241086a2000410010074100200341206a3602040bfd0403027f047e017f4100410028020441206b220936020442002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b024020072002520d0042002106423b2105413021044200210703400240024002400240024020064204560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b200720015141c00010020b0240024020012000510d0042002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b20072002520d010b20092000370318200242808080808080a0aad700520d00200941003602142009410136021020092009290310370208200941186a200941086a100f1a0b4100200941206a3602040b8c0101047f4100280204220521042001280204210220012802002101024010002203450d00024020034180044d0d00200310112205200310041a200510140c010b410020052003410f6a4170716b22053602042005200310041a0b200020024101756a210302402002410171450d00200328020020016a28020021010b200320011100004100200436020441010b4901037f4100210502402002450d000240034020002d0000220320012d00002204470d01200141016a2101200041016a21002002417f6a22020d000c020b0b200320046b21050b20050b0900418001200010120bcd04010c7f02402001450d00024020002802c041220d0d004110210d200041c0c1006a41103602000b200141086a200141046a41077122026b200120021b210202400240024020002802c441220a200d4f0d002000200a410c6c6a4180c0006a21010240200a0d0020004184c0006a220d2802000d0020014180c000360200200d20003602000b200241046a210a034002402001280208220d200a6a20012802004b0d002001280204200d6a220d200d28020041808080807871200272360200200141086a22012001280200200a6a360200200d200d28020041808080807872360200200d41046a22010d030b2000101322010d000b0b41fcffffff0720026b2104200041c8c1006a210b200041c0c1006a210c20002802c8412203210d03402000200d410c6c6a22014188c0006a28020020014180c0006a22052802004641d0c200100220014184c0006a280200220641046a210d0340200620052802006a2107200d417c6a2208280200220941ffffffff07712101024020094100480d000240200120024f0d000340200d20016a220a20074f0d01200a280200220a4100480d012001200a41ffffffff07716a41046a22012002490d000b0b20082001200220012002491b200941808080807871723602000240200120024d0d00200d20026a200420016a41ffffffff07713602000b200120024f0d040b200d20016a41046a220d2007490d000b41002101200b4100200b28020041016a220d200d200c280200461b220d360200200d2003470d000b0b20010f0b2008200828020041808080807872360200200d0f0b41000b870501087f20002802c44121010240024041002d00a643450d0041002802a84321070c010b3f002107410041013a00a6434100200741107422073602a8430b200721030240024002400240200741ffff036a41107622023f0022084d0d00200220086b40001a4100210820023f00470d0141002802a84321030b41002108410020033602a84320074100480d0020002001410c6c6a210220074180800441808008200741ffff037122084181f8034922061b6a2008200741ffff077120061b6b20076b2107024041002d00a6430d003f002103410041013a00a6434100200341107422033602a8430b20024180c0006a210220074100480d01200321060240200741076a417871220520036a41ffff036a41107622083f0022044d0d00200820046b40001a20083f00470d0241002802a84321060b4100200620056a3602a8432003417f460d0120002001410c6c6a22014184c0006a2802002206200228020022086a2003460d020240200820014188c0006a22052802002201460d00200620016a2206200628020041808080807871417c20016b20086a72360200200520022802003602002006200628020041ffffffff07713602000b200041c4c1006a2202200228020041016a220236020020002002410c6c6a22004184c0006a200336020020004180c0006a220820073602000b20080f0b02402002280200220820002001410c6c6a22034188c0006a22012802002207460d0020034184c0006a28020020076a2203200328020041808080807871417c20076b20086a72360200200120022802003602002003200328020041ffffffff07713602000b2000200041c4c1006a220728020041016a22033602c0412007200336020041000f0b2002200820076a36020020020b7b01037f024002402000450d0041002802c04222024101480d004180c10021032002410c6c4180c1006a21010340200341046a2802002202450d010240200241046a20004b0d00200220032802006a20004b0d030b2003410c6a22032001490d000b0b0f0b2000417c6a2203200328020041ffffffff07713602000b0300000b0bcf01060041040b04b04900000041100b0572656164000041200b086f6e6572726f72000041300b06656f73696f000041c0000b406f6e6572726f7220616374696f6e277320617265206f6e6c792076616c69642066726f6d207468652022656f73696f222073797374656d206163636f756e74000041d0c2000b566d616c6c6f635f66726f6d5f6672656564207761732064657369676e656420746f206f6e6c792062652063616c6c6564206166746572205f686561702077617320636f6d706c6574656c7920616c6c6f636174656400" + },{ + "account": "eosio", + "name": "setabi", + "authorization": [{ + "actor": "eosio.sudo", + "permission": "active" + } + ], + "data": { + "account": "eosio.sudo", + "abi": "0e656f73696f3a3a6162692f312e30030c6163636f756e745f6e616d65046e616d650f7065726d697373696f6e5f6e616d65046e616d650b616374696f6e5f6e616d65046e616d6506107065726d697373696f6e5f6c6576656c0002056163746f720c6163636f756e745f6e616d650a7065726d697373696f6e0f7065726d697373696f6e5f6e616d6506616374696f6e0004076163636f756e740c6163636f756e745f6e616d65046e616d650b616374696f6e5f6e616d650d617574686f72697a6174696f6e127065726d697373696f6e5f6c6576656c5b5d0464617461056279746573127472616e73616374696f6e5f68656164657200060a65787069726174696f6e0e74696d655f706f696e745f7365630d7265665f626c6f636b5f6e756d0675696e743136107265665f626c6f636b5f7072656669780675696e743332136d61785f6e65745f75736167655f776f7264730976617275696e743332106d61785f6370755f75736167655f6d730575696e74380964656c61795f7365630976617275696e74333209657874656e73696f6e000204747970650675696e74313604646174610562797465730b7472616e73616374696f6e127472616e73616374696f6e5f6865616465720314636f6e746578745f667265655f616374696f6e7308616374696f6e5b5d07616374696f6e7308616374696f6e5b5d167472616e73616374696f6e5f657874656e73696f6e730b657874656e73696f6e5b5d046578656300020865786563757465720c6163636f756e745f6e616d65037472780b7472616e73616374696f6e01000000000080545704657865630000000000" + }, + "hex_data": "00004d1a03ea3055df040e656f73696f3a3a6162692f312e30030c6163636f756e745f6e616d65046e616d650f7065726d697373696f6e5f6e616d65046e616d650b616374696f6e5f6e616d65046e616d6506107065726d697373696f6e5f6c6576656c0002056163746f720c6163636f756e745f6e616d650a7065726d697373696f6e0f7065726d697373696f6e5f6e616d6506616374696f6e0004076163636f756e740c6163636f756e745f6e616d65046e616d650b616374696f6e5f6e616d650d617574686f72697a6174696f6e127065726d697373696f6e5f6c6576656c5b5d0464617461056279746573127472616e73616374696f6e5f68656164657200060a65787069726174696f6e0e74696d655f706f696e745f7365630d7265665f626c6f636b5f6e756d0675696e743136107265665f626c6f636b5f7072656669780675696e743332136d61785f6e65745f75736167655f776f7264730976617275696e743332106d61785f6370755f75736167655f6d730575696e74380964656c61795f7365630976617275696e74333209657874656e73696f6e000204747970650675696e74313604646174610562797465730b7472616e73616374696f6e127472616e73616374696f6e5f6865616465720314636f6e746578745f667265655f616374696f6e7308616374696f6e5b5d07616374696f6e7308616374696f6e5b5d167472616e73616374696f6e5f657874656e73696f6e730b657874656e73696f6e5b5d046578656300020865786563757465720c6163636f756e745f6e616d65037472780b7472616e73616374696f6e01000000000080545704657865630000000000" + } + ], + "transaction_extensions": [] + } +} +``` + +Each approver should be able to see that the proposed transaction is setting the code and ABI of the `eosio.sudo` contract. But the data is just hex data and therefore not very meaningful to the approver. And considering that `eosio.sudo` at this point should be a privileged contract, it would be very dangerous for block producers to just allow a contract to be deployed to a privileged account without knowing exactly which WebAssembly code they are deploying and also auditing the source code that generated that WebAssembly code to ensure it is safe to deploy. + +This guide assumes that each approver has already audited the source code of the contract to be deployed and has already compiled that code to generate the WebAssembly code that should be byte-for-byte identical to the code that every other approver following the same process should have generated. The guide also assumes that this generated code and its associated ABI were provided in the steps in sub-section 2.2.1 that generated the transaction in the deploy_sudo_contract_trx.json file. It then becomes quite simple to verify that the proposed transaction is identical to the one the potential approver could have proposed with the code and ABI that they already audited: +``` +$ cleos multisig propose_trx -j -s -d deploysudo '[]' deploy_sudo_contract_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_deploy_sudo_trx_serialized.hex +$ cat expected_deploy_sudo_trx_serialized.hex | cut -c -50 +c0593f5b00000000000000000000020000000000ea30550000 +$ cat deploy_sudo_account_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_deploy_sudo_trx_serialized.hex +$ cat proposed_deploy_sudo_trx_serialized.hex | cut -c -50 +c0593f5b00000000000000000000020000000000ea30550000 +$ diff expected_deploy_sudo_trx_serialized.hex proposed_deploy_sudo_trx_serialized.hex +``` + +When an approver (e.g. `blkproducerb`) is satisfied with the proposed transaction, they can simply approve it: +``` +$ cleos multisig approve blkproducera deploysudo '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb +executed transaction: d1e424e05ee4d96eb079fcd5190dd0bf35eca8c27dd7231b59df8e464881abfd 128 bytes 483 us +# eosio.msig <= eosio.msig::approve {"proposer":"blkproducera","proposal_name":"deploysudo","level":{"actor":"blkproducerb","permission"... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +#### 2.2.4 Execute the transaction to create the eosio.sudo account + +When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). + +``` +$ cleos multisig exec blkproducera deploysudo blkproducera +executed transaction: e8da14c6f1fdc3255b5413adccfd0d89b18f832a4cc18c4324ea2beec6abd483 160 bytes 1877 us +# eosio.msig <= eosio.msig::exec {"proposer":"blkproducera","proposal_name":"deploysudo","executer":"blkproducera"} +``` + +Anyone can now verify that the `eosio.sudo` contract was deployed correctly. + +``` +$ cleos get code -a retrieved-eosio.sudo.abi eosio.sudo +code hash: 1b3456a5eca28bcaca7a2a3360fbb2a72b9772a416c8e11a303bcb26bfe3263c +saving abi to retrieved-eosio.sudo.abi +$ sha256sum contracts/eosio.sudo/eosio.sudo.wasm +1b3456a5eca28bcaca7a2a3360fbb2a72b9772a416c8e11a303bcb26bfe3263c contracts/eosio.sudo/eosio.sudo.wasm +``` + +If the two hashes match then the local WebAssembly code is the one deployed on the blockchain. The retrieved ABI, which was stored in the file retrieved-eosio.sudo.abi, can then be compared to the original ABI of the contract (contracts/eosio.sudo/eosio.sudo.abi) to ensure they are semantically the same. + +## 3. Using the eosio.sudo contract + +### 3.1 Example: Updating owner authority of an arbitrary account + +This example will demonstrate how to use the deployed eosio.sudo contract together with the eosio.msig contract to allow a greater than two-thirds supermajority of block producers of an EOSIO blockchain to change the owner authority of an arbitrary account. The example will use cleos: in particular, the `cleos multisig` command, the `cleos set account permission` sub-command, and the `cleos sudo exec` sub-command. However, the guide also demonstrates what to do if the `cleos sudo exec` sub-command is not available. + +This guide assumes that there are 21 active block producers on the chain with account names: `blkproducera`, `blkproducerb`, ..., `blkproduceru`. Block producer `blkproducera` will act as the lead block producer handling the proposal of the transaction. + +The producer permissions will later come in handy when proposing a transaction that must be approved by a supermajority of the producers. So a file producer_permissions.json containing those permission (see contents below) should be created to be used later in this guide: +``` +$ cat producer_permissions.json +[ + {"actor": "blkproducera", "permission": "active"}, + {"actor": "blkproducerb", "permission": "active"}, + {"actor": "blkproducerc", "permission": "active"}, + {"actor": "blkproducerd", "permission": "active"}, + {"actor": "blkproducere", "permission": "active"}, + {"actor": "blkproducerf", "permission": "active"}, + {"actor": "blkproducerg", "permission": "active"}, + {"actor": "blkproducerh", "permission": "active"}, + {"actor": "blkproduceri", "permission": "active"}, + {"actor": "blkproducerj", "permission": "active"}, + {"actor": "blkproducerk", "permission": "active"}, + {"actor": "blkproducerl", "permission": "active"}, + {"actor": "blkproducerm", "permission": "active"}, + {"actor": "blkproducern", "permission": "active"}, + {"actor": "blkproducero", "permission": "active"}, + {"actor": "blkproducerp", "permission": "active"}, + {"actor": "blkproducerq", "permission": "active"}, + {"actor": "blkproducerr", "permission": "active"}, + {"actor": "blkproducers", "permission": "active"}, + {"actor": "blkproducert", "permission": "active"}, + {"actor": "blkproduceru", "permission": "active"} +] +``` + +#### 3.1.1 Generate the transaction to change the owner permission of an account + +The goal of this example is for the block producers to change the owner permission of the account `alice`. + +The initial status of the `alice` account might be: +``` +permissions: + owner 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV + active 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV +memory: + quota: 49.74 KiB used: 3.365 KiB + +net bandwidth: + staked: 1.0000 SYS (total stake delegated from account to self) + delegated: 0.0000 SYS (total staked delegated to account from others) + used: 0 bytes + available: 2.304 MiB + limit: 2.304 MiB + +cpu bandwidth: + staked: 1.0000 SYS (total stake delegated from account to self) + delegated: 0.0000 SYS (total staked delegated to account from others) + used: 0 us + available: 460.8 ms + limit: 460.8 ms + +producers: +``` + +Assume that none of the block producers know the private key corresponding to the public key `EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV` which, as can be seen above, is initially securing access to the `alice` account. + +The first step is to generate the transaction changing the owner permission of the `alice` account as if `alice` is authorizing the change: +``` +$ cleos set account permission -s -j -d alice owner '{"threshold": 1, "accounts": [{"permission": {"actor": "eosio", "permission": "active"}, "weight": 1}]}' > update_alice_owner_trx.json +``` + +Then modify update_alice_owner_trx.json so that the values for the `ref_block_num` and `ref_block_prefix` fields are both 0 and the value of the `expiration` field is `"1970-01-01T00:00:00"`: +``` +$ cat update_alice_owner_trx.json +{ + "expiration": "1970-01-01T00:00:00", + "ref_block_num": 0, + "ref_block_prefix": 0, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ + "account": "eosio", + "name": "updateauth", + "authorization": [{ + "actor": "alice", + "permission": "active" + } + ], + "data": "0000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed3232010000" + } + ], + "transaction_extensions": [], + "signatures": [], + "context_free_data": [] +} +``` + +The next step is to generate the transaction containing the `eosio.sudo::exec` action. This action will contain the transaction in update_alice_owner_trx.json as part of its action payload data. + +``` +$ cleos sudo exec -s -j -d blkproducera update_alice_owner_trx.json > sudo_update_alice_owner_trx.json +``` + +Once again modify sudo_update_alice_owner_trx.json so that the value for the `ref_block_num` and `ref_block_prefix` fields are both 0. However, instead of changing the value of the expiration field to `"1970-01-01T00:00:00"`, it should be changed to a time that is far enough in the future to allow enough time for the proposed transaction to be approved and executed. +``` +$ cat sudo_update_alice_owner_trx.json +{ + "expiration": "2018-07-06T12:00:00", + "ref_block_num": 0, + "ref_block_prefix": 0, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ + "account": "eosio.sudo", + "name": "exec", + "authorization": [{ + "actor": "blkproducera", + "permission": "active" + },{ + "actor": "eosio.sudo", + "permission": "active" + } + ], + "data": "60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed323201000000" + } + ], + "transaction_extensions": [], + "signatures": [], + "context_free_data": [] +} +``` + +If the `cleos sudo` command is not available, there is an alternative way to generate the above transaction. There is no need to continue reading the remaining of sub-section 3.1.1 if the sudo_update_alice_owner_trx.json file was already generated with content similar to the above using the `cleos sudo exec` sub-command method. + +First the hex encoding of the binary serialization of the transaction in update_alice_owner_trx.json must be obtained. One way of obtaining this data is through the following command: +``` +$ cleos multisig propose_trx -s -j -d nothing '[]' update_alice_owner_trx.json nothing | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > update_alice_owner_trx_serialized.hex +$ cat update_alice_owner_trx_serialized.hex +0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed323201000000 +``` + +Then generate the template for the transaction containing the `eosio.sudo::exec` action: +``` +$ cleos push action -s -j -d eosio.sudo exec '{"executer": "blkproducera", "trx": ""}' > sudo_update_alice_owner_trx.json +$ cat sudo_update_alice_owner_trx.json +{ + "expiration": "2018-06-29T23:34:01", + "ref_block_num": 23708, + "ref_block_prefix": 3605208482, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ + "account": "eosio.sudo", + "name": "exec", + "authorization": [], + "data": "60ae423ad15b613c" + } + ], + "transaction_extensions": [], + "signatures": [], + "context_free_data": [] +} +``` + +Then modify the transaction in sudo_update_alice_owner_trx.json as follows: + * replace the values of the `ref_block_num` and `ref_block_prefix` fields to 0; + * replace the time of the `expiration` field to the desired expiration time as described above (e.g. `"2018-07-06T12:00:00"`); + * append the hex data from update_alice_owner_trx_serialized.hex to the end of the existing hex data in the `data` field in sudo_update_alice_owner_trx.json. + + +#### 3.1.2 Propose the transaction to change the owner permission of an account + +The lead block producer (`blkproducera`) should propose the transaction stored in sudo_update_alice_owner_trx.json: +``` +$ cleos multisig propose_trx updatealice producer_permissions.json sudo_update_alice_owner_trx.json blkproducera +executed transaction: 10474f52c9e3fc8e729469a577cd2fc9e4330e25b3fd402fc738ddde26605c13 624 bytes 782 us +# eosio.msig <= eosio.msig::propose {"proposer":"blkproducera","proposal_name":"updatealice","requested":[{"actor":"blkproducera","permi... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +#### 3.1.3 Review and approve the transaction to change the owner permission of an account + +Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. +``` +$ cleos multisig review blkproducera updatealice > sudo_update_alice_owner_trx_to_review.json +$ cat sudo_update_alice_owner_trx_to_review.json +{ + "proposal_name": "updatealice", + "packed_transaction": "c0593f5b000000000000000000000100004d1a03ea305500000000008054570260ae423ad15b613c00000000a8ed323200004d1a03ea305500000000a8ed32326b60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed32320100000000", + "transaction": { + "expiration": "2018-07-06T12:00:00", + "ref_block_num": 0, + "ref_block_prefix": 0, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ + "account": "eosio.sudo", + "name": "exec", + "authorization": [{ + "actor": "blkproducera", + "permission": "active" + },{ + "actor": "eosio.sudo", + "permission": "active" + } + ], + "data": { + "executer": "blkproducera", + "trx": { + "expiration": "1970-01-01T00:00:00", + "ref_block_num": 0, + "ref_block_prefix": 0, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ + "account": "eosio", + "name": "updateauth", + "authorization": [{ + "actor": "alice", + "permission": "active" + } + ], + "data": "0000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed3232010000" + } + ], + "transaction_extensions": [] + } + }, + "hex_data": "60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed323201000000" + } + ], + "transaction_extensions": [] + } +} +``` + +The approvers should go through the human-readable transaction output and make sure everything looks fine. However, due to a current limitation of nodeos/cleos, the JSONification of action payload data does not occur recursively. So while both the `hex_data` and the human-readable JSON `data` of the payload of the `eosio.sudo::exec` action is available in the output of the `cleos multisig review` command, only the hex data is available of the payload of the inner `eosio::updateauth` action. So it is not clear what the `updateauth` will actually do. + +Furthermore, even if this usability issue was fixed in nodeos/cleos, there will still be cases where there is no sensible human-readable version of an action data payload within a transaction. An example of this is the proposed transaction in sub-section 2.2.3 which used the `eosio::setcode` action to set the contract code of the `eosio.sudo` account. The best thing to do in such situations is for the reviewer to compare the proposed transaction to one generated by them through a process they trust. + +Since each block producer generated a transaction in sub-section 3.1.1 (stored in the file sudo_update_alice_owner_trx.json) which should be identical to the transaction proposed by the lead block producer, they can each simply check to see if the two transactions are identical: +``` +$ cleos multisig propose_trx -j -s -d updatealice '[]' sudo_update_alice_owner_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_sudo_update_alice_owner_trx_serialized.hex +$ cat expected_sudo_update_alice_owner_trx_serialized.hex +c0593f5b000000000000000000000100004d1a03ea305500000000008054570260ae423ad15b613c00000000a8ed323200004d1a03ea305500000000a8ed32326b60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed32320100000000 +$ cat sudo_update_alice_owner_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_sudo_update_alice_owner_trx_serialized.hex +$ cat proposed_sudo_update_alice_owner_trx_serialized.hex +c0593f5b000000000000000000000100004d1a03ea305500000000008054570260ae423ad15b613c00000000a8ed323200004d1a03ea305500000000a8ed32326b60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed32320100000000 +$ diff expected_sudo_update_alice_owner_trx_serialized.hex proposed_sudo_update_alice_owner_trx_serialized.hex +``` + +When an approver (e.g. `blkproducerb`) is satisfied with the proposed transaction, they can simply approve it: +``` +$ cleos multisig approve blkproducera updatealice '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb +executed transaction: 2bddc7747e0660ba26babf95035225895b134bfb2ede32ba0a2bb6091c7dab56 128 bytes 543 us +# eosio.msig <= eosio.msig::approve {"proposer":"blkproducera","proposal_name":"updatealice","level":{"actor":"blkproducerb","permission... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +#### 3.1.4 Execute the transaction to change the owner permission of an account + +When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). + +``` +$ cleos multisig exec blkproducera updatealice blkproducera +executed transaction: 7127a66ae307fbef6415bf60c3e91a88b79bcb46030da983c683deb2a1a8e0d0 160 bytes 820 us +# eosio.msig <= eosio.msig::exec {"proposer":"blkproducera","proposal_name":"updatealice","executer":"blkproducera"} +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +Anyone can now verify that the owner authority of `alice` was successfully changed: +``` +$ cleos get account alice +permissions: + owner 1: 1 eosio@active, + active 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV +memory: + quota: 49.74 KiB used: 3.348 KiB + +net bandwidth: + staked: 1.0000 SYS (total stake delegated from account to self) + delegated: 0.0000 SYS (total staked delegated to account from others) + used: 0 bytes + available: 2.304 MiB + limit: 2.304 MiB + +cpu bandwidth: + staked: 1.0000 SYS (total stake delegated from account to self) + delegated: 0.0000 SYS (total staked delegated to account from others) + used: 413 us + available: 460.4 ms + limit: 460.8 ms + +producers: + +``` From a93debf19eff7879e67c7ec0005241ffc6e90de4 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Mon, 2 Jul 2018 17:27:58 -0400 Subject: [PATCH 18/21] fixed tests in light of new exception --- unittests/block_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/block_tests.cpp b/unittests/block_tests.cpp index 22dfce99c29..ebece74deca 100644 --- a/unittests/block_tests.cpp +++ b/unittests/block_tests.cpp @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(block_with_invalid_tx_test) validator.control->abort_block(); BOOST_REQUIRE_EXCEPTION(validator.control->push_block( copy_b ), fc::exception , [] (const fc::exception &e)->bool { - return e.code() == action_validate_exception::code_value ; + return e.code() == account_name_exists_exception::code_value ; }) ; } From 5906ce5eba4fc56f2495dbd1a72909e59a86d6d8 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 2 Jul 2018 19:00:01 -0400 Subject: [PATCH 19/21] fix mistake in eosio.sudo contract from @moskvanaft's review of #4429 --- contracts/eosio.sudo/eosio.sudo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/eosio.sudo/eosio.sudo.cpp b/contracts/eosio.sudo/eosio.sudo.cpp index 10e501936f2..c64ffa756aa 100644 --- a/contracts/eosio.sudo/eosio.sudo.cpp +++ b/contracts/eosio.sudo/eosio.sudo.cpp @@ -29,7 +29,7 @@ void sudo::exec() { require_auth( executer ); size_t trx_pos = ds.tellp(); - send_deferred( (uint128_t(executer) << 64) | current_time(), executer, buffer+trx_pos, size ); + send_deferred( (uint128_t(executer) << 64) | current_time(), executer, buffer+trx_pos, size-trx_pos ); } } /// namespace eosio From af02ebba5d5797b6dcc2f06befcfc584b07dc75f Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Tue, 3 Jul 2018 15:47:42 -0400 Subject: [PATCH 20/21] Consolidated Security Patches for 1.0.8 * Correct limit for function local size * Strip user (name) sections from get_code WASM->WAST conversion * Add deadline to abi_serializer validate. * catch bad_allocs and raise the appropriate SIGUSR1 from all points in producer plugin * add invariant that there is no pending block after the call even if some part of the commit fails to commit_block Co-authored-by: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Co-authored-by: Kevin Heifner Co-authored-by: Bart Wyatt --- libraries/chain/abi_serializer.cpp | 11 +- libraries/chain/controller.cpp | 43 ++-- .../include/eosio/chain/abi_serializer.hpp | 4 +- .../include/eosio/chain/wast_to_wasm.hpp | 4 +- libraries/chain/wast_to_wasm.cpp | 8 +- .../Source/WASM/WASMSerialization.cpp | 40 ++-- plugins/chain_plugin/chain_plugin.cpp | 2 +- plugins/producer_plugin/producer_plugin.cpp | 184 ++++++++++-------- 8 files changed, 165 insertions(+), 131 deletions(-) diff --git a/libraries/chain/abi_serializer.cpp b/libraries/chain/abi_serializer.cpp index 7262fdb495f..b3eca2b879c 100644 --- a/libraries/chain/abi_serializer.cpp +++ b/libraries/chain/abi_serializer.cpp @@ -177,11 +177,12 @@ namespace eosio { namespace chain { } } - bool abi_serializer::_is_type(const type_name& rtype, size_t recursion_depth)const { + bool abi_serializer::_is_type(const type_name& rtype, size_t recursion_depth, const fc::time_point& deadline)const { + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", max_serialization_time) ); if( ++recursion_depth > max_recursion_depth) return false; auto type = fundamental_type(rtype); if( built_in_types.find(type) != built_in_types.end() ) return true; - if( typedefs.find(type) != typedefs.end() ) return _is_type(typedefs.find(type)->second, recursion_depth); + if( typedefs.find(type) != typedefs.end() ) return _is_type(typedefs.find(type)->second, recursion_depth, deadline); if( structs.find(type) != structs.end() ) return true; return false; } @@ -193,10 +194,12 @@ namespace eosio { namespace chain { } void abi_serializer::validate()const { + const fc::time_point deadline = fc::time_point::now() + max_serialization_time; for( const auto& t : typedefs ) { try { vector types_seen{t.first, t.second}; auto itr = typedefs.find(t.second); while( itr != typedefs.end() ) { + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", max_serialization_time) ); FC_ASSERT( find(types_seen.begin(), types_seen.end(), itr->second) == types_seen.end(), "Circular reference in type ${type}", ("type",t.first) ); types_seen.emplace_back(itr->second); itr = typedefs.find(itr->second); @@ -210,6 +213,7 @@ namespace eosio { namespace chain { struct_def current = s.second; vector types_seen{current.name}; while( current.base != type_name() ) { + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", max_serialization_time) ); const auto& base = get_struct(current.base); //<-- force struct to inherit from another struct FC_ASSERT( find(types_seen.begin(), types_seen.end(), base.name) == types_seen.end(), "Circular reference in struct ${type}", ("type",s.second.name) ); types_seen.emplace_back(base.name); @@ -217,14 +221,17 @@ namespace eosio { namespace chain { } } for( const auto& field : s.second.fields ) { try { + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", max_serialization_time) ); FC_ASSERT(is_type(field.type) ); } FC_CAPTURE_AND_RETHROW( (field) ) } } FC_CAPTURE_AND_RETHROW( (s) ) } for( const auto& a : actions ) { try { + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", max_serialization_time) ); FC_ASSERT(is_type(a.second), "", ("type",a.second) ); } FC_CAPTURE_AND_RETHROW( (a) ) } for( const auto& t : tables ) { try { + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", max_serialization_time) ); FC_ASSERT(is_type(t.second), "", ("type",t.second) ); } FC_CAPTURE_AND_RETHROW( (t) ) } } diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index f7e943bdf81..3875ba9cac7 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -395,29 +395,40 @@ struct controller_impl { + /** + * @post regardless of the success of commit block there is no active pending block + */ void commit_block( bool add_to_fork_db ) { - if( add_to_fork_db ) { - pending->_pending_block_state->validated = true; - auto new_bsp = fork_db.add( pending->_pending_block_state ); - emit( self.accepted_block_header, pending->_pending_block_state ); - head = fork_db.head(); - FC_ASSERT( new_bsp == head, "committed block did not become the new head in fork database" ); + auto reset_pending_on_exit = fc::make_scoped_exit([this]{ + pending.reset(); + }); - } + try { + if (add_to_fork_db) { + pending->_pending_block_state->validated = true; + auto new_bsp = fork_db.add(pending->_pending_block_state); + emit(self.accepted_block_header, pending->_pending_block_state); + head = fork_db.head(); + FC_ASSERT(new_bsp == head, "committed block did not become the new head in fork database"); + } - // ilog((fc::json::to_pretty_string(*pending->_pending_block_state->block))); - emit( self.accepted_block, pending->_pending_block_state ); + if( !replaying ) { + reversible_blocks.create( [&]( auto& ubo ) { + ubo.blocknum = pending->_pending_block_state->block_num; + ubo.set_block( pending->_pending_block_state->block ); + }); + } - if( !replaying ) { - reversible_blocks.create( [&]( auto& ubo ) { - ubo.blocknum = pending->_pending_block_state->block_num; - ubo.set_block( pending->_pending_block_state->block ); - }); + emit( self.accepted_block, pending->_pending_block_state ); + } catch (...) { + // dont bother resetting pending, instead abort the block + reset_pending_on_exit.cancel(); + abort_block(); + throw; } + // push the state for pending. pending->push(); - pending.reset(); - } // The returned scoped_exit should not exceed the lifetime of the pending which existed when make_block_restore_point was called. diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index 875be1a2037..2169ff4d27e 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -43,7 +43,7 @@ struct abi_serializer { bool is_array(const type_name& type)const; bool is_optional(const type_name& type)const; bool is_type(const type_name& type)const { - return _is_type(type, 0); + return _is_type(type, 0, fc::time_point::now() + max_serialization_time); } bool is_builtin_type(const type_name& type)const; bool is_integer(const type_name& type) const; @@ -126,7 +126,7 @@ struct abi_serializer { void _binary_to_variant(const type_name& type, fc::datastream& stream, fc::mutable_variant_object& obj, size_t recursion_depth, const fc::time_point& deadline)const; - bool _is_type(const type_name& type, size_t recursion_depth)const; + bool _is_type(const type_name& type, size_t recursion_depth, const fc::time_point& deadline)const; friend struct impl::abi_from_variant; friend struct impl::abi_to_variant; diff --git a/libraries/chain/include/eosio/chain/wast_to_wasm.hpp b/libraries/chain/include/eosio/chain/wast_to_wasm.hpp index f5a8fb4e715..e77d23b1360 100644 --- a/libraries/chain/include/eosio/chain/wast_to_wasm.hpp +++ b/libraries/chain/include/eosio/chain/wast_to_wasm.hpp @@ -9,7 +9,7 @@ namespace eosio { namespace chain { std::vector wast_to_wasm( const std::string& wast ); -std::string wasm_to_wast( const std::vector& wasm ); -std::string wasm_to_wast( const uint8_t* data, uint64_t size ); +std::string wasm_to_wast( const std::vector& wasm, bool strip_names ); +std::string wasm_to_wast( const uint8_t* data, uint64_t size, bool strip_names ); } } /// eosio::chain diff --git a/libraries/chain/wast_to_wasm.cpp b/libraries/chain/wast_to_wasm.cpp index 489695631f3..19cceb75b7c 100644 --- a/libraries/chain/wast_to_wasm.cpp +++ b/libraries/chain/wast_to_wasm.cpp @@ -61,15 +61,17 @@ namespace eosio { namespace chain { } FC_CAPTURE_AND_RETHROW( (wast) ) } /// wast_to_wasm - std::string wasm_to_wast( const std::vector& wasm ) { - return wasm_to_wast( wasm.data(), wasm.size() ); + std::string wasm_to_wast( const std::vector& wasm, bool strip_names ) { + return wasm_to_wast( wasm.data(), wasm.size(), strip_names ); } /// wasm_to_wast - std::string wasm_to_wast( const uint8_t* data, uint64_t size ) + std::string wasm_to_wast( const uint8_t* data, uint64_t size, bool strip_names ) { try { IR::Module module; Serialization::MemoryInputStream stream((const U8*)data,size); WASM::serialize(stream,module); + if(strip_names) + module.userSections.clear(); // Print the module to WAST. return WAST::print(module); } FC_CAPTURE_AND_RETHROW() } /// wasm_to_wast diff --git a/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp b/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp index b74188b0c9c..f70fdbbb164 100644 --- a/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp +++ b/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp @@ -489,19 +489,19 @@ namespace WASM Uptr numLocalSets = 0; serializeVarUInt32(bodyStream,numLocalSets); - constexpr size_t max_size = eosio::chain::wasm_constraints::maximum_code_size; - if (numBodyBytes >= max_size) - throw FatalSerializationException(std::string("Function body too large")); - if (numLocalSets >= 1024) - throw FatalSerializationException(std::string("too many local sets")); - size_t locals_accum = numBodyBytes; + constexpr size_t max_size = eosio::chain::wasm_constraints::maximum_code_size; + if (numBodyBytes >= max_size) + throw FatalSerializationException(std::string("Function body too large")); + if (numLocalSets >= 1024) + throw FatalSerializationException(std::string("too many local sets")); + size_t locals_accum = 0; for(Uptr setIndex = 0;setIndex < numLocalSets;++setIndex) { LocalSet localSet; serialize(bodyStream,localSet); - locals_accum += localSet.num*4; - if( locals_accum >= max_size ) + locals_accum += localSet.num*4; + if( locals_accum > eosio::chain::wasm_constraints::maximum_func_local_bytes ) throw FatalSerializationException( "too many locals" ); for(Uptr index = 0;index < localSet.num;++index) { functionDef.nonParameterLocalTypes.push_back(localSet.type); } @@ -569,7 +569,7 @@ namespace WASM + module.memories.imports.size() + module.globals.imports.size(); serializeVarUInt32(sectionStream,size); - constexpr size_t max_size = eosio::chain::wasm_constraints::maximum_section_elements; + constexpr size_t max_size = eosio::chain::wasm_constraints::maximum_section_elements; if(Stream::isInput) { for(Uptr index = 0;index < size;++index) @@ -593,8 +593,8 @@ namespace WASM throw FatalSerializationException("invalid import function type index"); } module.functions.imports.push_back({{functionTypeIndex},std::move(moduleName),std::move(exportName)}); - if (module.functions.imports.size() >= max_size) - throw FatalSerializationException(std::string("Too many function imports")); + if (module.functions.imports.size() >= max_size) + throw FatalSerializationException(std::string("Too many function imports")); break; } case ObjectKind::table: @@ -602,8 +602,8 @@ namespace WASM TableType tableType; serialize(sectionStream,tableType); module.tables.imports.push_back({tableType,std::move(moduleName),std::move(exportName)}); - if (module.functions.imports.size() >= max_size) - throw FatalSerializationException(std::string("Too many table imports")); + if (module.functions.imports.size() >= max_size) + throw FatalSerializationException(std::string("Too many table imports")); break; } case ObjectKind::memory: @@ -611,8 +611,8 @@ namespace WASM MemoryType memoryType; serialize(sectionStream,memoryType); module.memories.imports.push_back({memoryType,std::move(moduleName),std::move(exportName)}); - if (module.functions.imports.size() >= max_size) - throw FatalSerializationException(std::string("Too many memory imports")); + if (module.functions.imports.size() >= max_size) + throw FatalSerializationException(std::string("Too many memory imports")); break; } case ObjectKind::global: @@ -620,8 +620,8 @@ namespace WASM GlobalType globalType; serialize(sectionStream,globalType); module.globals.imports.push_back({globalType,std::move(moduleName),std::move(exportName)}); - if (module.functions.imports.size() >= max_size) - throw FatalSerializationException(std::string("Too many global imports")); + if (module.functions.imports.size() >= max_size) + throw FatalSerializationException(std::string("Too many global imports")); break; } default: throw FatalSerializationException("invalid ObjectKind"); @@ -678,9 +678,9 @@ namespace WASM // Grow the vector one element at a time: // try to get a serialization exception before making a huge allocation for malformed input. module.functions.defs.clear(); - constexpr size_t max_size = eosio::chain::wasm_constraints::maximum_section_elements; - if ( numFunctions >= max_size ) - throw FatalSerializationException(std::string("Too many function defs")); + constexpr size_t max_size = eosio::chain::wasm_constraints::maximum_section_elements; + if ( numFunctions >= max_size ) + throw FatalSerializationException(std::string("Too many function defs")); for(Uptr functionIndex = 0;functionIndex < numFunctions;++functionIndex) { U32 functionTypeIndex = 0; diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 5a489106d84..cf10f806142 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -963,7 +963,7 @@ read_only::get_code_results read_only::get_code( const get_code_params& params ) if (params.code_as_wasm) { result.wasm = string(accnt.code.begin(), accnt.code.end()); } else { - result.wast = wasm_to_wast( (const uint8_t*)accnt.code.data(), accnt.code.size() ); + result.wast = wasm_to_wast( (const uint8_t*)accnt.code.data(), accnt.code.size(), true ); } result.code_hash = fc::sha256::hash( accnt.code.data(), accnt.code.size() ); } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 0242b5b9620..b44e9247999 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -273,7 +273,11 @@ class producer_plugin_impl : public std::enable_shared_from_this().publish( block ); return; @@ -289,7 +293,6 @@ class producer_plugin_impl : public std::enable_shared_from_thisid()))("t",block->timestamp) ("count",block->transactions.size())("lib",chain.last_irreversible_block_num())("confs", block->confirmed)("latency", (fc::time_point::now() - block->timestamp).count()/1000 ) ); } - } std::vector>> _pending_incoming_transactions; @@ -812,111 +815,118 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { persisted_by_expiry.erase(persisted_by_expiry.begin()); } - for (auto itr = unapplied_trxs.begin(); itr != unapplied_trxs.end(); ++itr) { - const auto& trx = *itr; - if(persisted_by_id.find(trx->id) != persisted_by_id.end()) { - // this is a persisted transaction, push it into the block (even if we are speculating) with - // no deadline as it has already passed the subjective deadlines once and we want to represent - // the state of the chain including this transaction - try { - chain.push_transaction(trx, fc::time_point::maximum()); - } FC_LOG_AND_DROP(); - - // remove it from further consideration as it is applied - *itr = nullptr; - } - } - - if (_pending_block_mode == pending_block_mode::producing) { - for (const auto& trx : unapplied_trxs) { - if (exhausted) { - break; - } - - if (!trx ) { - // nulled in the loop above, skip it - continue; + try { + for (auto itr = unapplied_trxs.begin(); itr != unapplied_trxs.end(); ++itr) { + const auto& trx = *itr; + if (persisted_by_id.find(trx->id) != persisted_by_id.end()) { + // this is a persisted transaction, push it into the block (even if we are speculating) with + // no deadline as it has already passed the subjective deadlines once and we want to represent + // the state of the chain including this transaction + try { + chain.push_transaction(trx, fc::time_point::maximum()); + } FC_LOG_AND_DROP(); + + // remove it from further consideration as it is applied + *itr = nullptr; } + } - if (trx->packed_trx.expiration() < pbs->header.timestamp.to_time_point()) { - // expired, drop it - chain.drop_unapplied_transaction(trx); - continue; - } + if (_pending_block_mode == pending_block_mode::producing) { + for (const auto& trx : unapplied_trxs) { + if (exhausted) { + break; + } - try { - auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); - bool deadline_is_subjective = false; - if (_max_transaction_time_ms < 0 || ( _pending_block_mode == pending_block_mode::producing && block_time < deadline ) ) { - deadline_is_subjective = true; - deadline = block_time; + if (!trx) { + // nulled in the loop above, skip it + continue; } - auto trace = chain.push_transaction(trx, deadline); - if (trace->except) { - if (failure_is_subjective(*trace->except, deadline_is_subjective)) { - exhausted = true; - } else { - // this failed our configured maximum transaction time, we don't want to replay it - chain.drop_unapplied_transaction(trx); - } + if (trx->packed_trx.expiration() < pbs->header.timestamp.to_time_point()) { + // expired, drop it + chain.drop_unapplied_transaction(trx); + continue; } - } FC_LOG_AND_DROP(); - } - auto& blacklist_by_id = _blacklisted_transactions.get(); - auto& blacklist_by_expiry = _blacklisted_transactions.get(); - auto now = fc::time_point::now(); - while(!blacklist_by_expiry.empty() && blacklist_by_expiry.begin()->expiry <= now) { - blacklist_by_expiry.erase(blacklist_by_expiry.begin()); - } + try { + auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); + bool deadline_is_subjective = false; + if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && block_time < deadline)) { + deadline_is_subjective = true; + deadline = block_time; + } - auto scheduled_trxs = chain.get_scheduled_transactions(); - for (const auto& trx : scheduled_trxs) { - if (exhausted) { - break; + auto trace = chain.push_transaction(trx, deadline); + if (trace->except) { + if (failure_is_subjective(*trace->except, deadline_is_subjective)) { + exhausted = true; + } else { + // this failed our configured maximum transaction time, we don't want to replay it + chain.drop_unapplied_transaction(trx); + } + } + } FC_LOG_AND_DROP(); } - if (blacklist_by_id.find(trx) != blacklist_by_id.end()) { - continue; + auto& blacklist_by_id = _blacklisted_transactions.get(); + auto& blacklist_by_expiry = _blacklisted_transactions.get(); + auto now = fc::time_point::now(); + while (!blacklist_by_expiry.empty() && blacklist_by_expiry.begin()->expiry <= now) { + blacklist_by_expiry.erase(blacklist_by_expiry.begin()); } - try { - auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); - bool deadline_is_subjective = false; - if (_max_transaction_time_ms < 0 || ( _pending_block_mode == pending_block_mode::producing && block_time < deadline ) ) { - deadline_is_subjective = true; - deadline = block_time; + auto scheduled_trxs = chain.get_scheduled_transactions(); + for (const auto& trx : scheduled_trxs) { + if (exhausted) { + break; } - auto trace = chain.push_scheduled_transaction(trx, deadline); - if (trace->except) { - if (failure_is_subjective(*trace->except, deadline_is_subjective)) { - exhausted = true; - } else { - auto expiration = fc::time_point::now() + fc::seconds(chain.get_global_properties().configuration.deferred_trx_expiration_window); - // this failed our configured maximum transaction time, we don't want to replay it add it to a blacklist - _blacklisted_transactions.insert(transaction_id_with_expiry{trx, expiration}); - } + if (blacklist_by_id.find(trx) != blacklist_by_id.end()) { + continue; } - } FC_LOG_AND_DROP(); + + try { + auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); + bool deadline_is_subjective = false; + if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && block_time < deadline)) { + deadline_is_subjective = true; + deadline = block_time; + } + + auto trace = chain.push_scheduled_transaction(trx, deadline); + if (trace->except) { + if (failure_is_subjective(*trace->except, deadline_is_subjective)) { + exhausted = true; + } else { + auto expiration = fc::time_point::now() + fc::seconds(chain.get_global_properties().configuration.deferred_trx_expiration_window); + // this failed our configured maximum transaction time, we don't want to replay it add it to a blacklist + _blacklisted_transactions.insert(transaction_id_with_expiry{trx, expiration}); + } + } + } FC_LOG_AND_DROP(); + } } - } - if (exhausted) { - return start_block_result::exhausted; - } else { - // attempt to apply any pending incoming transactions - if (!_pending_incoming_transactions.empty()) { - auto old_pending = std::move(_pending_incoming_transactions); - _pending_incoming_transactions.clear(); - for (auto& e: old_pending) { - on_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); + if (exhausted) { + return start_block_result::exhausted; + } else { + // attempt to apply any pending incoming transactions + if (!_pending_incoming_transactions.empty()) { + auto old_pending = std::move(_pending_incoming_transactions); + _pending_incoming_transactions.clear(); + for (auto& e: old_pending) { + on_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); + } } + + return start_block_result::succeeded; } - return start_block_result::succeeded; + } catch ( boost::interprocess::bad_alloc& ) { + raise(SIGUSR1); + return start_block_result::failed; } + } return start_block_result::failed; @@ -1003,6 +1013,9 @@ bool producer_plugin_impl::maybe_produce_block() { try { produce_block(); return true; + } catch ( boost::interprocess::bad_alloc& ) { + raise(SIGUSR1); + return false; } FC_LOG_AND_DROP(); fc_dlog(_log, "Aborting block due to produce_block error"); @@ -1043,6 +1056,7 @@ void producer_plugin_impl::produce_block() { auto debug_logger = maybe_make_debug_time_logger(); return signature_provider_itr->second(d); } ); + chain.commit_block(); auto hbt = chain.head_block_time(); //idump((fc::time_point::now() - hbt)); From dc9d41e3bc7027e6ea3c9b00718fe8613054b3fb Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Tue, 3 Jul 2018 16:58:42 -0400 Subject: [PATCH 21/21] bump version to 1.0.8 --- CMakeLists.txt | 2 +- Docker/README.md | 6 +++--- Docker/docker-compose-eosio1.0.yaml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70368b6d555..d3cee609e7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 1) set(VERSION_MINOR 0) -set(VERSION_PATCH 7) +set(VERSION_PATCH 8) set( CLI_CLIENT_EXECUTABLE_NAME cleos ) set( GUI_CLIENT_EXECUTABLE_NAME eosio ) diff --git a/Docker/README.md b/Docker/README.md index 74808ec6325..d7ccde53b17 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -20,10 +20,10 @@ cd eos/Docker docker build . -t eosio/eos ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v1.0.7 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v1.0.8 tag, you could do the following: ```bash -docker build -t eosio/eos:v1.0.7 --build-arg branch=v1.0.7 . +docker build -t eosio/eos:v1.0.8 --build-arg branch=v1.0.8 . ``` By default, the symbol in eosio.system is set to SYS. You can override this using the symbol argument while building the docker image. @@ -181,7 +181,7 @@ Note: if you want to use the mongo db plugin, you have to enable it in your `dat ``` # pull images -docker pull eosio/eos:v1.0.7 +docker pull eosio/eos:v1.0.8 # create volume docker volume create --name=nodeos-data-volume diff --git a/Docker/docker-compose-eosio1.0.yaml b/Docker/docker-compose-eosio1.0.yaml index 9df363c6010..0d398e2d77c 100644 --- a/Docker/docker-compose-eosio1.0.yaml +++ b/Docker/docker-compose-eosio1.0.yaml @@ -2,7 +2,7 @@ version: "3" services: nodeosd: - image: eosio/eos:v1.0.7 + image: eosio/eos:v1.0.8 command: /opt/eosio/bin/nodeosd.sh --data-dir /opt/eosio/bin/data-dir -e hostname: nodeosd ports: @@ -14,7 +14,7 @@ services: - nodeos-data-volume:/opt/eosio/bin/data-dir keosd: - image: eosio/eos:v1.0.7 + image: eosio/eos:v1.0.8 command: /opt/eosio/bin/keosd --wallet-dir /opt/eosio/bin/data-dir --http-server-address=127.0.0.1:8900 hostname: keosd links: