diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 00c20e7999a..eaa351a513f 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -17,6 +17,7 @@ add_library( eos_chain types.cpp chain_administration_interface.cpp + message_handling_contexts.cpp ${HEADERS} ) diff --git a/libraries/chain/chain_controller.cpp b/libraries/chain/chain_controller.cpp index 79899fa1803..3e5f1a31c23 100644 --- a/libraries/chain/chain_controller.cpp +++ b/libraries/chain/chain_controller.cpp @@ -552,21 +552,18 @@ void chain_controller::validate_referenced_accounts(const SignedTransaction& trx require_account(auth.account); } for(const auto& msg : trx.messages) { - require_account(msg.sender); - require_account(msg.recipient); - const AccountName* previous_notify_account = nullptr; - for(const auto& current_notify_account : msg.notify) { - require_account(current_notify_account); - if(previous_notify_account) { - EOS_ASSERT(current_notify_account < *previous_notify_account, message_validate_exception, + require_account(msg.code); + const AccountName* previous_recipient = nullptr; + for(const auto& current_recipient : msg.recipients) { + require_account(current_recipient); + if(previous_recipient) { + EOS_ASSERT(current_recipient < *previous_recipient, message_validate_exception, "Message notify accounts out of order. Possibly a bug in the wallet?"); } - EOS_ASSERT(current_notify_account != msg.sender, message_validate_exception, - "Message sender is listed in accounts to notify. Possibly a bug in the wallet?"); - EOS_ASSERT(current_notify_account != msg.recipient, message_validate_exception, - "Message recipient is listed in accounts to notify. Possibly a bug in the wallet?"); - previous_notify_account = ¤t_notify_account; + EOS_ASSERT(current_recipient != msg.code, message_validate_exception, + "Code account is listed among recipients. Possibly a bug in the wallet?"); + previous_recipient = ¤t_recipient; } } } @@ -588,22 +585,22 @@ void chain_controller::validate_expiration(const SignedTransaction& trx) const void chain_controller::validate_message_precondition( precondition_validate_context& context )const { try { const auto& m = context.msg; - auto contract_handlers_itr = precondition_validate_handlers.find( context.scope ); - if( contract_handlers_itr != precondition_validate_handlers.end() ) { - auto message_handler_itr = contract_handlers_itr->second.find( {m.recipient, m.type} ); - if( message_handler_itr != contract_handlers_itr->second.end() ) { + auto contract_handlers_itr = precondition_validate_handlers.find(context.scope); + if (contract_handlers_itr != precondition_validate_handlers.end()) { + auto message_handler_itr = contract_handlers_itr->second.find({m.code, m.type}); + if (message_handler_itr != contract_handlers_itr->second.end()) { message_handler_itr->second(context); return; } } - const auto& recipient = _db.get( context.scope ); - if( recipient.code.size() ) { - wasm_interface::get().precondition( context ); + const auto& recipient = _db.get(context.scope); + if (recipient.code.size()) { + wasm_interface::get().precondition(context); } } FC_CAPTURE_AND_RETHROW() } void chain_controller::process_message(Message message) { - apply_context apply_ctx(_db, message, message.recipient); + apply_context apply_ctx(_db, message, message.code); /** TODO: pre condition validation and application can occur in parallel */ /** TODO: verify that message is fully authorized @@ -611,30 +608,29 @@ void chain_controller::process_message(Message message) { validate_message_precondition(apply_ctx); apply_message(apply_ctx); - for (const auto& notify_account : message.notify) { + for (const auto& recipient : message.recipients) { try { - apply_context notify_ctx(_db, message, notify_account); - validate_message_precondition(notify_ctx); - apply_message(notify_ctx); - } FC_CAPTURE_AND_RETHROW((notify_account)(message)) + apply_context recipient_ctx(_db, message, recipient); + validate_message_precondition(recipient_ctx); + apply_message(recipient_ctx); + } FC_CAPTURE_AND_RETHROW((recipient)(message)) } } -void chain_controller::apply_message( apply_context& context ) +void chain_controller::apply_message(apply_context& context) { try { const auto& m = context.msg; - auto contract_handlers_itr = apply_handlers.find( context.scope ); - if( contract_handlers_itr != apply_handlers.end() ) { - auto message_handler_itr = contract_handlers_itr->second.find( {m.recipient, m.type} ); - if( message_handler_itr != contract_handlers_itr->second.end() ) { + auto contract_handlers_itr = apply_handlers.find(context.scope); + if (contract_handlers_itr != apply_handlers.end()) { + auto message_handler_itr = contract_handlers_itr->second.find({m.code, m.type}); + if (message_handler_itr != contract_handlers_itr->second.end()) { message_handler_itr->second(context); return; } } - //ilog( "no native handler found" ); - const auto& recipient = _db.get( context.scope ); - if( recipient.code.size() ) { - wasm_interface::get().apply( context ); + const auto& recipient = _db.get(context.scope); + if (recipient.code.size()) { + wasm_interface::get().apply(context); } } FC_CAPTURE_AND_RETHROW((context.msg)) } diff --git a/libraries/chain/include/eos/chain/authority.hpp b/libraries/chain/include/eos/chain/authority.hpp index 6cbc7fe649c..20e1d660deb 100644 --- a/libraries/chain/include/eos/chain/authority.hpp +++ b/libraries/chain/include/eos/chain/authority.hpp @@ -62,7 +62,7 @@ class AuthorityChecker { return true; } for (const auto& apw : authority.accounts) -#warning TODO: Recursion limit? +#warning TODO: Recursion limit? Yes: implement as producer-configurable parameter if (satisfied(apw.permission)) { weight += apw.weight; if (weight >= authority.threshold) diff --git a/libraries/chain/include/eos/chain/message.hpp b/libraries/chain/include/eos/chain/message.hpp index bee67985d40..199288847e4 100644 --- a/libraries/chain/include/eos/chain/message.hpp +++ b/libraries/chain/include/eos/chain/message.hpp @@ -20,12 +20,10 @@ namespace eos { namespace chain { */ struct Message : public types::Message { Message() = default; - Message(const AccountName& sender, const AccountName& recipient, const vector& notify) - : types::Message(sender, recipient, notify, "", {}) {} template - Message(const AccountName& sender, const AccountName& recipient, const vector& notify, - const TypeName& type, T&& value) - : Message(sender, recipient, notify) { + Message(const AccountName& code, const vector& recipients, + const vector& authorization, const TypeName& type, T&& value) + : types::Message(code, recipients, authorization, {}, {}) { set(type, std::forward(value)); } Message(const types::Message& m) : types::Message(m) {} @@ -40,17 +38,22 @@ struct Message : public types::Message { return fc::raw::unpack(data); } bool has_notify(const AccountName& n)const { - for(const auto& no : notify) + for(const auto& no : recipients) if(no == n) return true; return false; } template - void for_each_handler( Lambda&& l )const { - l( sender ); - l( recipient ); - for( const auto& notice : notify ) - l(notice); + void for_each_handler(Lambda&& l)const { + l(code); + for(const auto& recipient : recipients) + l(recipient); + } + + types::AccountName recipient(UInt8 index) const { + FC_ASSERT(index < recipients.size(), "Invalid recipient index: ${index}/${size}", + ("index", index)("size", recipients.size())); + return recipients.at(int(index)); } }; diff --git a/libraries/chain/include/eos/chain/message_handling_contexts.hpp b/libraries/chain/include/eos/chain/message_handling_contexts.hpp index c046cb85f2d..2dcbf55c032 100644 --- a/libraries/chain/include/eos/chain/message_handling_contexts.hpp +++ b/libraries/chain/include/eos/chain/message_handling_contexts.hpp @@ -11,11 +11,25 @@ namespace eos { namespace chain { class message_validate_context { public: explicit message_validate_context(const chainbase::database& d, const chain::Message& m, types::AccountName s) - :msg(m),db(d),scope(s){} + :msg(m),db(d),scope(s),used_authorizations(msg.authorization.size(), false){} + + /** + * @brief Require @ref account to have approved of this message + * @param account The account whose approval is required + * + * This method will check that @ref account is listed in the message's declared authorizations, and marks the + * authorization as used. Note that all authorizations on a message must be used, or the message is invalid. + * + * @throws tx_missing_auth If no sufficient permission was found + */ + void require_authorization(const types::AccountName& account); + bool all_authorizations_used() const; const chain::Message& msg; - const chainbase::database& db; /// required only for loading the contract code - types::AccountName scope; /// the contract that is being called + const chainbase::database& db; + types::AccountName scope; + ///< Parallel to msg.authorization; tracks which permissions have been used while processing the message + vector used_authorizations; }; class precondition_validate_context : public message_validate_context { diff --git a/libraries/chain/message_handling_contexts.cpp b/libraries/chain/message_handling_contexts.cpp new file mode 100644 index 00000000000..fc996ddf5f4 --- /dev/null +++ b/libraries/chain/message_handling_contexts.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include +#include + +namespace eos { namespace chain { + +void message_validate_context::require_authorization(const types::AccountName& account) { + auto itr = boost::find_if(msg.authorization, [&account](const types::AccountPermission& ap) { + return ap.account == account; + }); + EOS_ASSERT(itr != msg.authorization.end(), tx_missing_auth, + "Required authorization ${auth} not found", ("auth", account)); + + used_authorizations[itr - msg.authorization.begin()] = true; +} + +bool message_validate_context::all_authorizations_used() const { + return boost::algorithm::all_of_equal(used_authorizations, true); +} + +} } // namespace eos::chain diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 7cc5ab01955..310e28ce649 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -71,7 +71,7 @@ DEFINE_INTRINSIC_FUNCTION2(env,remove,remove,i32,i32,keyptr,i32,keylen) { const auto* obj = db.find( boost::make_tuple(scope, keystr) ); if( obj ) { - db.remove( *obj ); + db.remove( *obj ); return true; } return false; @@ -88,9 +88,9 @@ DEFINE_INTRINSIC_FUNCTION3(env,memcpy,memcpy,i32,i32,dstp,i32,srcp,i32,len) { #warning TODO: wasm memcpy has undefined behavior if memory ranges overlap /* if( dst > src ) - FC_ASSERT( dst < src_end && src < dst_end, "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) ); + FC_ASSERT( dst < src_end && src < dst_end, "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) ); else - FC_ASSERT( src < dst_end && dst < src_end, "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) ); + FC_ASSERT( src < dst_end && dst < src_end, "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) ); */ memcpy( dst, src, uint32_t(len) ); return dstp; @@ -254,7 +254,7 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) { if( !wasm ) { wlog( "Runtime::init" ); - Runtime::init(); + Runtime::init(); wasm = new wasm_interface(); } return *wasm; @@ -277,10 +277,10 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) { char* wasm_interface::vm_allocate( int bytes ) { - FunctionInstance* alloc_function = asFunctionNullable(getInstanceExport(current_module,"alloc")); - const FunctionType* functionType = getFunctionType(alloc_function); + FunctionInstance* alloc_function = asFunctionNullable(getInstanceExport(current_module,"alloc")); + const FunctionType* functionType = getFunctionType(alloc_function); FC_ASSERT( functionType->parameters.size() == 1 ); - std::vector invokeArgs(1); + std::vector invokeArgs(1); invokeArgs[0] = U32(bytes); auto result = Runtime::invokeFunction(alloc_function,invokeArgs); @@ -295,28 +295,28 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) { void wasm_interface::vm_call( std::string name ) { try { try { - name += "_" + std::string( current_validate_context->msg.recipient ) + "_"; + name += "_" + std::string( current_validate_context->msg.code ) + "_"; name += std::string( current_validate_context->msg.type ); - FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,name.c_str())); - if( !apply ) { + FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,name.c_str())); + if( !apply ) { return; /// if not found then it is a no-op } - const FunctionType* functionType = getFunctionType(apply); - FC_ASSERT( functionType->parameters.size() == 0 ); - std::vector args(0); + const FunctionType* functionType = getFunctionType(apply); + FC_ASSERT( functionType->parameters.size() == 0 ); + std::vector args(0); auto& state = *current_state; char* memstart = &memoryRef( current_memory, 0 ); memset( memstart + state.mem_end, 0, ((1<<16) - state.mem_end) ); memcpy( memstart, state.init_memory.data(), state.mem_end); - Runtime::invokeFunction(apply,args); + Runtime::invokeFunction(apply,args); } catch( const Runtime::Exception& e ) { edump((std::string(describeExceptionCause(e.cause)))); - edump((e.callStack)); - throw; + edump((e.callStack)); + throw; } } FC_CAPTURE_AND_RETHROW( (name)(current_validate_context->msg.type) ) } @@ -328,22 +328,22 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) { { try { try { // wlog( "on_init" ); - FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"init")); - if( !apply ) { - wlog( "no onInit method found" ); - return; /// if not found then it is a no-op + FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"init")); + if( !apply ) { + wlog( "no onInit method found" ); + return; /// if not found then it is a no-op } - const FunctionType* functionType = getFunctionType(apply); - FC_ASSERT( functionType->parameters.size() == 0 ); + const FunctionType* functionType = getFunctionType(apply); + FC_ASSERT( functionType->parameters.size() == 0 ); - std::vector args(0); + std::vector args(0); - Runtime::invokeFunction(apply,args); + Runtime::invokeFunction(apply,args); } catch( const Runtime::Exception& e ) { edump((std::string(describeExceptionCause(e.cause)))); - edump((e.callStack)); - throw; + edump((e.callStack)); + throw; } } FC_CAPTURE_AND_RETHROW() } @@ -425,7 +425,7 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) { for( uint32_t i = 0; i < 10000; ++i ) if( memstart[i] ) { state.mem_end = i; - // std::cerr << (char)memstart[i]; + //std::cerr << (char)memstart[i]; } state.init_memory.resize(state.mem_end); diff --git a/libraries/native_contract/include/eos/native_contract/staked_balance_contract.hpp b/libraries/native_contract/include/eos/native_contract/staked_balance_contract.hpp index 03b3e83701e..b6a057805de 100644 --- a/libraries/native_contract/include/eos/native_contract/staked_balance_contract.hpp +++ b/libraries/native_contract/include/eos/native_contract/staked_balance_contract.hpp @@ -47,7 +47,7 @@ void validate_staked_okproducer(chain::message_validate_context& context); void precondition_staked_okproducer(chain::precondition_validate_context& context); void apply_staked_okproducer(chain::apply_context& context); -//void validate_staked_setproxy(chain::message_validate_context&) {} +void validate_staked_setproxy(chain::message_validate_context&context); void precondition_staked_setproxy(chain::precondition_validate_context& context); void apply_staked_setproxy(chain::apply_context& context); ///@} diff --git a/libraries/native_contract/native_contract_chain_initializer.cpp b/libraries/native_contract/native_contract_chain_initializer.cpp index 0230582beb1..b0f906b7d69 100644 --- a/libraries/native_contract/native_contract_chain_initializer.cpp +++ b/libraries/native_contract/native_contract_chain_initializer.cpp @@ -117,16 +117,18 @@ std::vector native_contract_chain_initializer::prepare_database( return types::Authority(1, {{k, 1}}, {}); }; for (const auto& acct : genesis.initial_accounts) { - chain::Message message(config::SystemContractName, config::SystemContractName, - {config::EosContractName, config::StakedBalanceContractName}, + chain::Message message(config::SystemContractName, + vector{config::EosContractName, config::StakedBalanceContractName}, + vector{}, "newaccount", types::newaccount(config::SystemContractName, acct.name, - KeyAuthority(acct.owner_key), - KeyAuthority(acct.active_key), - KeyAuthority(acct.owner_key), - acct.staking_balance)); + KeyAuthority(acct.owner_key), + KeyAuthority(acct.active_key), + KeyAuthority(acct.owner_key), + acct.staking_balance)); messages_to_process.emplace_back(std::move(message)); if (acct.liquid_balance > 0) { - message = chain::Message(config::SystemContractName, config::EosContractName, {}, + message = chain::Message(config::SystemContractName, vector{config::EosContractName}, + vector{}, "transfer", types::transfer(config::SystemContractName, acct.name, acct.liquid_balance, "Genesis Allocation")); messages_to_process.emplace_back(std::move(message)); @@ -135,7 +137,8 @@ std::vector native_contract_chain_initializer::prepare_database( // Create initial producers auto CreateProducer = boost::adaptors::transformed([config = genesis.initial_configuration](const auto& p) { - return chain::Message(config::SystemContractName, config::StakedBalanceContractName, vector{}, + return chain::Message(config::SystemContractName, {config::StakedBalanceContractName}, + vector{}, "setproducer", types::setproducer(p.owner_name, p.block_signing_key, config)); }); boost::copy(genesis.initial_producers | CreateProducer, std::back_inserter(messages_to_process)); diff --git a/libraries/native_contract/staked_balance_contract.cpp b/libraries/native_contract/staked_balance_contract.cpp index 7183cbbbaab..be70219bd2d 100644 --- a/libraries/native_contract/staked_balance_contract.cpp +++ b/libraries/native_contract/staked_balance_contract.cpp @@ -122,20 +122,20 @@ void validate_staked_okproducer(message_validate_context& context) { auto approve = context.msg.as(); EOS_ASSERT(approve.approve == 0 || approve.approve == 1, message_validate_exception, "Unknown approval value: ${val}; must be either 0 or 1", ("val", approve.approve)); - EOS_ASSERT(approve.producer.good(), message_validate_exception, - "Approved producer's name cannot be empty"); + context.msg.recipient(approve.voter); + context.msg.recipient(approve.producer); } void precondition_staked_okproducer(precondition_validate_context& context) { const auto& db = context.db; auto approve = context.msg.as(); - auto producer = db.find(approve.producer); - auto voter = db.find(context.msg.sender); + auto producer = db.find(context.msg.recipient(approve.producer)); + auto voter = db.find(context.msg.recipient(approve.voter)); EOS_ASSERT(producer != nullptr, message_precondition_exception, - "Could not approve producer '${name}'; no such producer found", ("name", approve.producer)); + "Could not approve producer '${name}'; no such producer found", ("name", producer->ownerName)); EOS_ASSERT(voter != nullptr, message_precondition_exception, - "Could not find balance for '${name}'", ("name", context.msg.sender)); + "Could not find balance for '${name}'", ("name", voter->ownerName)); EOS_ASSERT(voter->producerVotes.contains(), message_precondition_exception, "Cannot approve producer; approving account '${name}' proxies its votes to '${proxy}'", ("name", voter->ownerName)("proxy", voter->producerVotes.get())); @@ -145,20 +145,20 @@ void precondition_staked_okproducer(precondition_validate_context& context) { EOS_ASSERT(slate.size < config::MaxProducerVotes, message_precondition_exception, "Cannot approve producer; approved producer count is already at maximum"); if (approve.approve) - EOS_ASSERT(!slate.contains(approve.producer), message_precondition_exception, + EOS_ASSERT(!slate.contains(producer->ownerName), message_precondition_exception, "Cannot add approval to producer '${name}'; producer is already approved", - ("name", approve.producer)); + ("name", producer->ownerName)); else - EOS_ASSERT(slate.contains(approve.producer), message_precondition_exception, + EOS_ASSERT(slate.contains(producer->ownerName), message_precondition_exception, "Cannot remove approval from producer '${name}'; producer is not approved", - ("name", approve.producer)); + ("name", producer->ownerName)); } void apply_staked_okproducer(apply_context& context) { auto& db = context.mutable_db; auto approve = context.msg.as(); - const auto& producer = db.get(approve.producer); - const auto& voter = db.get(context.msg.sender); + const auto& producer = db.get(context.msg.recipient(approve.producer)); + const auto& voter = db.get(context.msg.recipient(approve.voter)); auto raceTime = ProducerScheduleObject::get(db).currentRaceTime; auto totalVotingStake = voter.stakedBalance; @@ -174,51 +174,57 @@ void apply_staked_okproducer(apply_context& context) { pvo.updateVotes(-totalVotingStake, raceTime); }); // Add/remove producer from voter's approved producer list - db.modify(voter, [&approve](StakedBalanceObject& sbo) { + db.modify(voter, [&approve, producer = producer.ownerName](StakedBalanceObject& sbo) { auto& slate = sbo.producerVotes.get(); if (approve.approve) - slate.add(approve.producer); + slate.add(producer); else - slate.remove(approve.producer); + slate.remove(producer); }); } +void validate_staked_setproxy(message_validate_context& context) { + auto svp = context.msg.as(); + context.msg.recipient(svp.stakeholder); + context.msg.recipient(svp.proxy); +} void precondition_staked_setproxy(precondition_validate_context& context) { auto svp = context.msg.as(); const auto& db = context.db; - auto proxy = db.find(context.msg.sender); + auto proxy = db.find(context.msg.recipient(svp.proxy)); EOS_ASSERT(proxy == nullptr, message_precondition_exception, "Account '${src}' cannot proxy its votes, since it allows other accounts to proxy to it", - ("src", context.msg.sender)); + ("src", context.msg.recipient(svp.stakeholder))); - if (svp.proxy != context.msg.sender) { - // We are trying to enable proxying to svp.proxy - auto proxy = db.find(svp.proxy); + if (svp.proxy != svp.stakeholder) { + // We are trying to enable proxying from svp.stakeholder to svp.proxy + auto proxy = db.find(context.msg.recipient(svp.proxy)); EOS_ASSERT(proxy != nullptr, message_precondition_exception, - "Proxy target '${target}' does not allow votes to be proxied to it", ("target", svp.proxy)); + "Proxy target '${target}' does not allow votes to be proxied to it", ("target", proxy->proxyTarget)); } else { // We are trying to disable proxying to sender.producerVotes.get() - const auto& sender = db.get(context.msg.sender); + const auto& sender = db.get(context.msg.recipient(svp.stakeholder)); EOS_ASSERT(sender.producerVotes.contains(), message_precondition_exception, - "Account '${name}' does not currently proxy its votes to any account", ("name", context.msg.sender)); + "Account '${name}' does not currently proxy its votes to any account", + ("name", context.msg.recipient(svp.stakeholder))); } } void apply_staked_setproxy(apply_context& context) { auto svp = context.msg.as(); auto& db = context.mutable_db; - const auto& proxy = db.get(svp.proxy); - const auto& balance = db.get(context.msg.sender); + const auto& proxy = db.get(context.msg.recipient(svp.proxy)); + const auto& balance = db.get(context.msg.recipient(svp.stakeholder)); - if (svp.proxy != context.msg.sender) { + if (svp.proxy != svp.stakeholder) { // We are enabling proxying to svp.proxy - proxy.addProxySource(context.msg.sender, balance.stakedBalance, db); - db.modify(balance, [target = svp.proxy](StakedBalanceObject& sbo) { sbo.producerVotes = target; }); + proxy.addProxySource(context.msg.recipient(svp.stakeholder), balance.stakedBalance, db); + db.modify(balance, [target = proxy.proxyTarget](StakedBalanceObject& sbo) { sbo.producerVotes = target; }); } else { // We are disabling proxying to balance.producerVotes.get() - proxy.removeProxySource(context.msg.sender, balance.stakedBalance, db); + proxy.removeProxySource(context.msg.recipient(svp.stakeholder), balance.stakedBalance, db); db.modify(balance, [](StakedBalanceObject& sbo) { sbo.producerVotes = ProducerSlate{}; }); } } diff --git a/libraries/types/types.eos b/libraries/types/types.eos index 7744c83ec72..ee34d6bd0f7 100644 --- a/libraries/types/types.eos +++ b/libraries/types/types.eos @@ -3,6 +3,7 @@ typedef Name PermissionName typedef Name FuncName typedef FixedString32 MessageName typedef FixedString32 TypeName +typedef UInt8 NameIndex # Index to an AccountName in Message::recipients # import account type as localtype @@ -91,14 +92,13 @@ struct setproducer # implies message.sender account struct okproducer - producer AccountName - approve Int8 # 0 or 1 + voter NameIndex # The account casting a vote + producer NameIndex # The producer being voted on + approve Int8 # 1 to approve, or 0 to disapprove -# implies message.sender account - -# implies message.sender account struct setproxy - proxy AccountName + stakeholder NameIndex # The account with stake to be proxied + proxy NameIndex # The account to cast votes with stakeholder's stake weight struct UpdatePermission diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 871255fcd47..1ac060ae8f1 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -417,11 +417,12 @@ class testing_network { #define Set_Proxy(chain, stakeholder, proxy) \ { \ eos::chain::SignedTransaction trx; \ - vector notifies; \ - if (std::string(#stakeholder) == std::string(#proxy)) \ - notifies.emplace_back(#proxy); \ - trx.emplaceMessage(#stakeholder, config::StakedBalanceContractName, notifies, "setproxy", \ - types::setproxy{#proxy}); \ + if (std::string(#stakeholder) != std::string(#proxy)) \ + trx.emplaceMessage(config::StakedBalanceContractName, vector{#stakeholder, #proxy}, \ + vector{}, "setproxy", types::setproxy{0, 1}); \ + else \ + trx.emplaceMessage(config::StakedBalanceContractName, vector{#stakeholder}, \ + vector{}, "setproxy", types::setproxy{0, 0}); \ trx.expiration = chain.head_block_time() + 100; \ trx.set_reference_block(chain.head_block_id()); \ chain.push_transaction(trx); \ diff --git a/tests/common/macro_support.hpp b/tests/common/macro_support.hpp index 8865f86945f..09b71ab954d 100644 --- a/tests/common/macro_support.hpp +++ b/tests/common/macro_support.hpp @@ -26,10 +26,10 @@ #define MKACCT_IMPL(chain, name, creator, active, owner, recovery, deposit) \ { \ eos::chain::SignedTransaction trx; \ - trx.emplaceMessage(#creator, config::SystemContractName, \ - vector{config::StakedBalanceContractName, \ - config::EosContractName}, "newaccount", \ - types::newaccount{#creator, #name, owner, active, recovery, deposit}); \ + trx.emplaceMessage(config::SystemContractName, \ + vector{#creator, config::StakedBalanceContractName, config::EosContractName}, \ + vector{}, \ + "newaccount", types::newaccount{#creator, #name, owner, active, recovery, deposit}); \ trx.expiration = chain.head_block_time() + 100; \ trx.set_reference_block(chain.head_block_id()); \ chain.push_transaction(trx); \ @@ -58,8 +58,9 @@ #define XFER5(chain, sender, recipient, amount, memo) \ { \ eos::chain::SignedTransaction trx; \ - trx.emplaceMessage(#sender, config::EosContractName, vector{#recipient}, "transfer", \ - types::transfer{#sender, #recipient, amount, memo}); \ + trx.emplaceMessage(config::EosContractName, vector{#sender, #recipient}, \ + vector{}, \ + "transfer", types::transfer{#sender, #recipient, amount, memo}); \ trx.expiration = chain.head_block_time() + 100; \ trx.set_reference_block(chain.head_block_id()); \ chain.push_transaction(trx); \ @@ -70,11 +71,11 @@ #define STAKE4(chain, sender, recipient, amount) \ { \ eos::chain::SignedTransaction trx; \ - trx.emplaceMessage(#sender, config::EosContractName, vector{config::StakedBalanceContractName}, \ - "lock", types::lock{#sender, #recipient, amount}); \ + trx.emplaceMessage(config::EosContractName, vector{#sender, config::StakedBalanceContractName}, \ + vector{}, "lock", types::lock{#sender, #recipient, amount}); \ if (std::string(#sender) != std::string(#recipient)) { \ - trx.messages.front().notify.emplace_back(#recipient); \ - boost::sort(trx.messages.front().notify); \ + trx.messages.front().recipients.emplace_back(#recipient); \ + boost::sort(trx.messages.front().recipients); \ } \ trx.expiration = chain.head_block_time() + 100; \ trx.set_reference_block(chain.head_block_id()); \ @@ -86,7 +87,8 @@ #define BEGIN_UNSTAKE3(chain, account, amount) \ { \ eos::chain::SignedTransaction trx; \ - trx.emplaceMessage(#account, config::StakedBalanceContractName, vector{}, \ + trx.emplaceMessage(config::StakedBalanceContractName, vector{#account}, \ + vector{}, \ "unlock", types::unlock{#account, amount}); \ trx.expiration = chain.head_block_time() + 100; \ trx.set_reference_block(chain.head_block_id()); \ @@ -97,8 +99,8 @@ #define FINISH_UNSTAKE3(chain, account, amount) \ { \ eos::chain::SignedTransaction trx; \ - trx.emplaceMessage(#account, config::StakedBalanceContractName, vector{config::EosContractName}, \ - "claim", types::claim{#account, amount}); \ + trx.emplaceMessage(config::StakedBalanceContractName, vector{#account, config::EosContractName}, \ + vector{}, "claim", types::claim{#account, amount}); \ trx.expiration = chain.head_block_time() + 100; \ trx.set_reference_block(chain.head_block_id()); \ chain.push_transaction(trx); \ @@ -108,8 +110,9 @@ #define MKPDCR4(chain, owner, key, cfg) \ { \ eos::chain::SignedTransaction trx; \ - trx.emplaceMessage(#owner, config::StakedBalanceContractName, vector{}, "setproducer", \ - types::setproducer{#owner, key, cfg}); \ + trx.emplaceMessage(config::StakedBalanceContractName, vector{#owner}, \ + vector{}, \ + "setproducer", types::setproducer{#owner, key, cfg}); \ trx.expiration = chain.head_block_time() + 100; \ trx.set_reference_block(chain.head_block_id()); \ chain.push_transaction(trx); \ @@ -123,8 +126,9 @@ #define APPDCR4(chain, voter, producer, approved) \ { \ eos::chain::SignedTransaction trx; \ - trx.emplaceMessage(#voter, config::StakedBalanceContractName, vector{}, "okproducer", \ - types::okproducer{#producer, approved? 1 : 0}); \ + trx.emplaceMessage(config::StakedBalanceContractName, vector{#voter, #producer}, \ + vector{}, \ + "okproducer", types::okproducer{0, 1, approved? 1 : 0}); \ trx.expiration = chain.head_block_time() + 100; \ trx.set_reference_block(chain.head_block_id()); \ chain.push_transaction(trx); \ @@ -134,8 +138,9 @@ #define UPPDCR4(chain, owner, key, cfg) \ { \ eos::chain::SignedTransaction trx; \ - trx.emplaceMessage(owner, config::StakedBalanceContractName, vector{}, "setproducer", \ - types::setproducer{owner, key, cfg}); \ + trx.emplaceMessage(config::StakedBalanceContractName, vector{#owner}, \ + vector{}, \ + "setproducer", types::setproducer{owner, key, cfg}); \ trx.expiration = chain.head_block_time() + 100; \ trx.set_reference_block(chain.head_block_id()); \ chain.push_transaction(trx); \ diff --git a/tests/slow_tests/slow_tests.cpp b/tests/slow_tests/slow_tests.cpp index 759071ce6cc..e4011ca35e3 100644 --- a/tests/slow_tests/slow_tests.cpp +++ b/tests/slow_tests/slow_tests.cpp @@ -177,8 +177,7 @@ BOOST_FIXTURE_TEST_CASE(create_script, testing_fixture) { eos::chain::SignedTransaction trx; trx.messages.resize(1); - trx.messages[0].sender = "simplecoin"; - trx.messages[0].recipient = config::SystemContractName; + trx.messages[0].recipients = {"simplecoin", config::SystemContractName}; trx.setMessage(0, "setcode", handler); trx.expiration = chain.head_block_time() + 100; trx.set_reference_block(chain.head_block_id()); @@ -191,8 +190,9 @@ BOOST_FIXTURE_TEST_CASE(create_script, testing_fixture) for (uint32_t i = 0; i < 100000; ++i) { eos::chain::SignedTransaction trx; - trx.emplaceMessage("simplecoin", "simplecoin", vector{"inita"}, "transfer", - types::transfer{"simplecoin", "inita", 1+i, "hello"} ); + trx.emplaceMessage("simplecoin", vector{"simplecoin", "inita"}, + vector{}, + "transfer", types::transfer{"simplecoin", "inita", 1+i, "hello"}); trx.expiration = chain.head_block_time() + 100; trx.set_reference_block(chain.head_block_id()); chain.push_transaction(trx); @@ -971,8 +971,7 @@ R"( eos::chain::SignedTransaction trx; trx.messages.resize(1); - trx.messages[0].sender = "simplecoin"; - trx.messages[0].recipient = config::SystemContractName; + trx.messages[0].recipients = {"simplecoin", config::SystemContractName}; trx.setMessage(0, "setcode", handler); trx.expiration = chain.head_block_time() + 100; trx.set_reference_block(chain.head_block_id()); diff --git a/tests/tests/native_contract_tests.cpp b/tests/tests/native_contract_tests.cpp index 4e7b8e0da4f..fe028e09987 100644 --- a/tests/tests/native_contract_tests.cpp +++ b/tests/tests/native_contract_tests.cpp @@ -90,8 +90,7 @@ BOOST_FIXTURE_TEST_CASE(transfer, testing_fixture) trx.messages.resize(1); trx.set_reference_block(chain.head_block_id()); trx.expiration = chain.head_block_time() + 100; - trx.messages[0].sender = "inita"; - trx.messages[0].recipient = config::EosContractName; + trx.messages[0].recipients = {"inita", config::EosContractName}; types::transfer trans = { "inita", "initb", Asset(100), "transfer 100" }; @@ -105,7 +104,7 @@ BOOST_FIXTURE_TEST_CASE(transfer, testing_fixture) auto unpack_trans = trx.messageAs(0); BOOST_REQUIRE_THROW(chain.push_transaction(trx), message_validate_exception); // "fail to notify receiver, initb" - trx.messages[0].notify = {"initb"}; + trx.messages[0].recipients = {"inita", "initb"}; trx.setMessage(0, "transfer", trans); chain.push_transaction(trx);