From fb4ed919a1d39f28f6d5ffc44efec542751307b3 Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 19 Apr 2018 20:17:11 -0400 Subject: [PATCH] generalize sending inline actions through templates and macros --- contracts/eosio.system/delegate_bandwidth.hpp | 12 ++-- contracts/eosio.system/eosio.system.hpp | 8 +-- contracts/eosio.system/voting.hpp | 4 +- contracts/eosio.token/eosio.token.cpp | 12 ++-- contracts/eosio.token/eosio.token.hpp | 14 ---- contracts/eosiolib/action.hpp | 68 +++++++++++++++---- contracts/eosiolib/contract.hpp | 11 ++- contracts/eosiolib/datastream.hpp | 38 +++++++++++ contracts/test.inline/test.inline.hpp | 4 +- 9 files changed, 120 insertions(+), 51 deletions(-) diff --git a/contracts/eosio.system/delegate_bandwidth.hpp b/contracts/eosio.system/delegate_bandwidth.hpp index ff1b60032..be0235492 100644 --- a/contracts/eosio.system/delegate_bandwidth.hpp +++ b/contracts/eosio.system/delegate_bandwidth.hpp @@ -39,7 +39,7 @@ namespace eosiosystem { account_name owner; asset net_weight; asset cpu_weight; - asset storage_stake; + asset storage_stake; uint64_t storage_bytes = 0; uint64_t primary_key()const { return owner; } @@ -183,9 +183,9 @@ namespace eosiosystem { } //set_resource_limits( tot_itr->owner, tot_itr->storage_bytes, tot_itr->net_weight.quantity, tot_itr->cpu_weight.quantity ); - - eosio::inline_transfer(eosio::permission_level{del.from,N(active)}, N(eosio.token), - { del.from, N(eosio), total_stake, std::string("stake bandwidth") } ); + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {del.from,N(active)}, + { del.from, N(eosio), total_stake, std::string("stake bandwidth") } ); if ( asset(0) < del.stake_net_quantity + del.stake_cpu_quantity ) { voting::increase_voting_power( del.from, del.stake_net_quantity + del.stake_cpu_quantity ); @@ -282,8 +282,8 @@ namespace eosiosystem { // allow people to get their tokens earlier than the 3 day delay if the unstake happened immediately after many // consecutive missed blocks. - eosio::inline_transfer( eosio::permission_level{N(eosio),N(active)}, N(eosio.token), - { N(eosio), req->owner, req->amount, std::string("unstake") }); + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, + { N(eosio), req->owner, req->amount, std::string("unstake") } ); refunds_tbl.erase( req ); } diff --git a/contracts/eosio.system/eosio.system.hpp b/contracts/eosio.system/eosio.system.hpp index eeed12b9f..d03f810ec 100644 --- a/contracts/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/eosio.system.hpp @@ -29,8 +29,8 @@ namespace eosiosystem { template class contract : eosio::contract, public delegate_bandwidth, public native { public: - - contract(account_name self = SystemAccount): + + contract(account_name self = SystemAccount): eosio::contract(self) { } @@ -164,8 +164,8 @@ namespace eosiosystem { p.per_block_payments.amount = 0; }); - eosio::inline_transfer(eosio::permission_level{N(eosio),N(active)}, N(eosio.token), - { N(eosio), cr.owner, rewards, std::string("producer claiming rewards") } ); + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, + { N(eosio), cr.owner, rewards, std::string("producer claiming rewards") } ); } static void apply( account_name receiver, account_name code, action_name act ) { diff --git a/contracts/eosio.system/voting.hpp b/contracts/eosio.system/voting.hpp index a1a20d85e..d04d81e15 100644 --- a/contracts/eosio.system/voting.hpp +++ b/contracts/eosio.system/voting.hpp @@ -376,8 +376,8 @@ namespace eosiosystem { } auto issue_quantity = parameters.blocks_per_cycle * (parameters.payment_per_block + parameters.payment_to_eos_bucket); - eosio::inline_issue(eosio::permission_level{N(eosio),N(active)}, N(eosio.token), - { N(eosio), issue_quantity, std::string("producer pay") }); + INLINE_ACTION_SENDER(eosio::token, issue)( N(eosio.token), {{N(eosio),N(active)}}, + {N(eosio), issue_quantity, std::string("producer pay")} ); set_blockchain_parameters(parameters); global_state_singleton::set(parameters); diff --git a/contracts/eosio.token/eosio.token.cpp b/contracts/eosio.token/eosio.token.cpp index 0295901c4..eadaa1494 100644 --- a/contracts/eosio.token/eosio.token.cpp +++ b/contracts/eosio.token/eosio.token.cpp @@ -10,8 +10,8 @@ namespace eosio { void token::create( account_name issuer, asset maximum_supply, uint8_t issuer_can_freeze, - uint8_t issuer_can_recall, - uint8_t issuer_can_whitelist ) + uint8_t issuer_can_recall, + uint8_t issuer_can_whitelist ) { require_auth( _self ); @@ -35,7 +35,7 @@ void token::create( account_name issuer, } -void token::issue( account_name to, asset quantity, string memo ) +void token::issue( account_name to, asset quantity, string memo ) { print( "issue" ); auto sym = quantity.symbol.name(); @@ -55,14 +55,14 @@ void token::issue( account_name to, asset quantity, string memo ) if( to != st.issuer ) { - dispatch_inline( permission_level{st.issuer,N(active)}, _self, N(transfer), &token::transfer, { st.issuer, to, quantity, memo } ); + SEND_INLINE_ACTION( *this, transfer, {st.issuer,N(active)}, {st.issuer, to, quantity, memo} ); } } -void token::transfer( account_name from, +void token::transfer( account_name from, account_name to, asset quantity, - string /*memo*/ ) + string /*memo*/ ) { print( "transfer" ); require_auth( from ); diff --git a/contracts/eosio.token/eosio.token.hpp b/contracts/eosio.token/eosio.token.hpp index aa0713395..cd014bbe1 100644 --- a/contracts/eosio.token/eosio.token.hpp +++ b/contracts/eosio.token/eosio.token.hpp @@ -74,18 +74,4 @@ namespace eosio { account_name ram_payer ); }; - typedef std::tuple transfer_args; - void inline_transfer( permission_level permissions, account_name code, transfer_args args ) - { - action act( permissions, code, N(transfer), args ); - act.send(); - } - - typedef std::tuple issue_args; - void inline_issue( permission_level permissions, account_name code, issue_args args ) - { - action act( permissions, code, N(issue), args ); - act.send(); - } - } /// namespace eosio diff --git a/contracts/eosiolib/action.hpp b/contracts/eosiolib/action.hpp index 20de85a2c..b30c26b17 100644 --- a/contracts/eosiolib/action.hpp +++ b/contracts/eosiolib/action.hpp @@ -7,6 +7,11 @@ #include #include +#include +#include +#include +#include + namespace eosio { /** @@ -24,7 +29,7 @@ namespace eosio { * This method unpacks the current action at type T. * * @brief Interpret the action body as type T - * + * * Example: * @code * struct dummy_action { @@ -134,16 +139,26 @@ namespace eosio { } /** - * @tparam Action - a type derived from action_meta + * @tparam T - the type of the action data + * @param auth - a single permission_level to be used as the authorization of the action + * @param a - name of the contract account + * @param n - name of the action * @param value - will be serialized via pack into data */ - template - action( const permission_level& auth, account_name a, action_name n, const Action& value ) - :authorization(1,auth) { - account = a; - name = n; - data = pack(value); - } + template + action( const permission_level& auth, account_name a, action_name n, T&& value ) + :account(a), name(n), authorization(1,auth), data(pack(std::forward(value))) {} + + /** + * @tparam T - the type of the action data + * @param auths - vector permission_levels defining the authorizations of the action + * @param a - name of the contract account + * @param n - name of the action + * @param value - will be serialized via pack into data + */ + template + action( vector auths, account_name a, action_name n, T&& value ) + :account(a), name(n), authorization(std::move(auths)), data(pack(std::forward(value))) {} EOSLIB_SERIALIZE( action, (account)(name)(authorization)(data) ) @@ -178,18 +193,41 @@ namespace eosio { static uint64_t get_name() { return Name; } }; - - template - void dispatch_inline( permission_level perm, - account_name code, action_name act, - void (T::*)(Args...), std::tuple args ) { - action( perm, code, act, args ).send(); + template + void dispatch_inline( account_name code, action_name act, + vector perms, + std::tuple args ) { + action( perms, code, act, std::move(args) ).send(); } + template + struct inline_dispatcher; + + template + struct inline_dispatcher { + static void call(account_name code, const permission_level& perm, std::tuple args) { + dispatch_inline(code, Name, vector(1, perm), std::move(args)); + } + static void call(account_name code, vector perms, std::tuple args) { + dispatch_inline(code, Name, std::move(perms), std::move(args)); + } + }; ///@} actioncpp api } // namespace eosio +#define INLINE_ACTION_SENDER3( CONTRACT_CLASS, FUNCTION_NAME, ACTION_NAME )\ +::eosio::inline_dispatcher::call + +#define INLINE_ACTION_SENDER2( CONTRACT_CLASS, NAME )\ +INLINE_ACTION_SENDER3( CONTRACT_CLASS, NAME, ::eosio::string_to_name(#NAME) ) + +#define INLINE_ACTION_SENDER(...) BOOST_PP_OVERLOAD(INLINE_ACTION_SENDER,__VA_ARGS__)(__VA_ARGS__) + +#define SEND_INLINE_ACTION( CONTRACT, NAME, ... )\ +INLINE_ACTION_SENDER(std::decay_t, NAME)( (CONTRACT).get_self(),\ +BOOST_PP_TUPLE_ENUM(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__)) ); + #define ACTION( CODE, NAME ) struct NAME : ::eosio::action_meta diff --git a/contracts/eosiolib/contract.hpp b/contracts/eosiolib/contract.hpp index aee67f3b8..4e88dae34 100644 --- a/contracts/eosiolib/contract.hpp +++ b/contracts/eosiolib/contract.hpp @@ -2,9 +2,14 @@ namespace eosio { -struct contract { - contract( account_name n ):_self(n){} - account_name _self; +class contract { + public: + contract( account_name n ):_self(n){} + + inline account_name get_self()const { return _self; } + + protected: + account_name _self; }; } /// namespace eosio diff --git a/contracts/eosiolib/datastream.hpp b/contracts/eosiolib/datastream.hpp index fd5ce7341..5027d8744 100644 --- a/contracts/eosiolib/datastream.hpp +++ b/contracts/eosiolib/datastream.hpp @@ -466,6 +466,44 @@ bytes pack( const T& value ) { return result; } +template +size_t _pack_size( T&& a ) { + return pack_size(std::forward(a)); +} + +template +size_t _pack_size( Arg&& a, Args&&... args ) { + return pack_size(std::forward(a)) + _pack_size(std::forward(args)...); +} + +template +size_t __pack( char* result, size_t size, const T& a ) { + datastream ds( result, size ); + auto start = ds.tellp(); + ds << a; + return ds.tellp() - start; +} + +template +void _pack( char* result, size_t size, Arg&& a ) { + __pack(result, size, std::forward(a)); +} + +template +void _pack( char* result, size_t size, Arg&& a, Args&&... args ) { + auto size_of_a = __pack(result, size, std::forward(a)); + _pack(result + size_of_a, size, std::forward(args)...); +} + +template +bytes pack( Args&&... args ) { + bytes result; + auto size = _pack_size(std::forward(args)...); + result.resize(size); + _pack(result.data(), size, std::forward(args)...); + return result; +} + template inline datastream& operator<<(datastream& ds, const checksum160& cs) { ds.write((const char*)&cs, sizeof(cs)); diff --git a/contracts/test.inline/test.inline.hpp b/contracts/test.inline/test.inline.hpp index 5396cff5a..967881079 100644 --- a/contracts/test.inline/test.inline.hpp +++ b/contracts/test.inline/test.inline.hpp @@ -14,7 +14,9 @@ namespace eosio { void forward( action_name reqauth, account_name forward_code, account_name forward_auth ) { require_auth( reqauth ); - dispatch_inline( permission_level{forward_auth,N(active)}, forward_code, N(reqauth), &testinline::reqauth, { forward_auth } ); + INLINE_ACTION_SENDER(testinline, reqauth)( forward_code, {forward_auth,N(active)}, {forward_auth} ); + //SEND_INLINE_ACTION( testinline(forward_code), reqauth, {forward_auth,N(active)}, {forward_auth} ); + //eosio::dispatch_inline( N(forward_code), N(reqauth), {{forward_auth, N(active)}}, {forward_auth} ); } }; -- GitLab