action.hpp 6.1 KB
Newer Older
1 2 3 4
/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
5
#pragma once
6 7 8
#include <eosiolib/action.h>
#include <eosiolib/datastream.hpp>
#include <eosiolib/serialize.hpp>
9

P
Pravin 已提交
10
namespace eosio {
11 12

   /**
13 14 15
    * @defgroup actioncppapi Action C++ API
    * @ingroup actionapi
    * @brief Type-safe C++ wrapers for Action C API
16
    *
17
    * @note There are some methods from the @ref actioncapi that can be used directly from C++
18
    *
19
    * @{
20 21 22
    */

   /**
23
    *
24 25
    *  This method attempts to reinterpret the action body as type T. This will only work
    *  if the action has no dynamic fields and the struct packing on type T is properly defined.
26
    *
27
    *  @brief Interpret the action body as type T
28 29
    *  
    *  Example:
30
    *  @code
31
    *  struct dummy_action {
32 33 34
    *    char a; //1
    *    unsigned long long b; //8
    *    int  c; //4
35
    *  };
36
    *  dummy_action msg = current_action_data<dummy_action>();
37
    *  @endcode
38 39
    */
   template<typename T>
40
   T current_action_data() {
41
      T value;
42
      auto read = read_action_data( &value, sizeof(value) );
43
      eosio_assert( read >= sizeof(value), "action shorter than expected" );
44 45 46
      return value;
   }

47
   template<typename T>
48 49 50
   T unpack_action_data() {
      char buffer[action_data_size()];
      read_action_data( buffer, sizeof(buffer) );
51
      return unpack<T>( buffer, sizeof(buffer) );
52 53
   }

54
   using ::require_auth;
55
   using ::require_recipient;
56 57

   /**
58
    *  All of the listed accounts will be added to the set of accounts to be notified
59
    *
60
    *  This helper method enables you to add multiple accounts to accounts to be notified list with a single
61 62
    *  call rather than having to call the similar C API multiple times.
    *
63
    *  @note action.code is also considered as part of the set of notified accounts
64 65
    *
    *  @brief Verify specified accounts exist in the set of notified accounts
66 67
    *
    *  Example:
68
    *  @code
69
    *  require_recipient(N(Account1), N(Account2), N(Account3)); // throws exception if any of them not in set.
70
    *  @endcode
71
    */
72
   template<typename... accounts>
73 74 75
   void require_recipient( account_name name, accounts... remaining_accounts ){
      require_recipient( name );
      require_recipient( remaining_accounts... );
76 77
   }

D
Daniel Larimer 已提交
78
   struct permission_level {
79 80 81
      permission_level( account_name a, permission_name p ):actor(a),permission(p){}
      permission_level(){}

D
Daniel Larimer 已提交
82 83
      account_name    actor;
      permission_name permission;
84

D
Daniel Larimer 已提交
85 86 87 88
      friend bool operator == ( const permission_level& a, const permission_level& b ) {
         return std::tie( a.actor, a.permission ) == std::tie( b.actor, b.permission );
      }

89
      EOSLIB_SERIALIZE( permission_level, (actor)(permission) )
D
Daniel Larimer 已提交
90
   };
91

92 93 94 95
   void require_auth(const permission_level& level) {
      require_auth2( level.actor, level.permission );
   }

D
Daniel Larimer 已提交
96 97 98 99
   /**
    * This is the packed representation of an action along with
    * meta-data about the authorization levels.
    */
D
Daniel Larimer 已提交
100
   struct action {
101
      account_name               account;
D
Daniel Larimer 已提交
102 103
      action_name                name;
      vector<permission_level>   authorization;
104 105 106
      bytes                      data;

      action() = default;
D
Daniel Larimer 已提交
107

D
Daniel Larimer 已提交
108 109
      /**
       *  @tparam Action - a type derived from action_meta<Scope,Name>
110
       *  @param value - will be serialized via pack into data
D
Daniel Larimer 已提交
111 112
       */
      template<typename Action>
113 114
      action( vector<permission_level>&& auth, const Action& value ) {
         account       = Action::get_account();
D
Daniel Larimer 已提交
115
         name          = Action::get_name();
D
Daniel Larimer 已提交
116
         authorization = move(auth);
117
         data          = pack(value);
D
Daniel Larimer 已提交
118
      }
119

120 121
      /**
       *  @tparam Action - a type derived from action_meta<Scope,Name>
122
       *  @param value - will be serialized via pack into data
123 124 125
       */
      template<typename Action>
      action( const permission_level& auth, const Action& value )
126
      :authorization(1,auth) {
127 128
         account       = Action::get_account();
         name          = Action::get_name();
129
         data          = pack(value);
130 131
      }

M
Matias Romeo 已提交
132 133 134 135 136 137 138 139 140 141 142
      /**
       *  @tparam Action - a type derived from action_meta<Scope,Name>
       *  @param value - will be serialized via pack into data
       */
      template<typename Action>
      action( const Action& value ) {
         account       = Action::get_account();
         name          = Action::get_name();
         data          = pack(value);
      }

D
Daniel Larimer 已提交
143 144 145 146 147 148 149 150 151 152 153 154
      /**
       *  @tparam Action - a type derived from action_meta<Scope,Name>
       *  @param value - will be serialized via pack into data
       */
      template<typename Action>
      action( const permission_level& auth, account_name a, action_name n, const Action& value )
      :authorization(1,auth) {
         account       = a;
         name          = n;
         data          = pack(value);
      }

155
      EOSLIB_SERIALIZE( action, (account)(name)(authorization)(data) )
156 157

      void send() const {
158
         auto serialize = pack(*this);
159
         ::send_inline(serialize.data(), serialize.size());
M
Matias Romeo 已提交
160 161 162 163 164 165
      }

      void send_context_free() const {
         eosio_assert( authorization.size() == 0, "context free actions cannot have authorizations");
         auto serialize = pack(*this);
         ::send_context_free_inline(serialize.data(), serialize.size());
166
      }
167 168 169 170 171 172 173 174

      /**
       * Retrieve the unpacked data as T
       * @tparam T expected type of data
       * @return the action data
       */
      template<typename T>
      T data_as() {
K
Kevin Heifner 已提交
175 176 177
         eosio_assert( name == T::get_name(), "Invalid name" );
         eosio_assert( account == T::get_account(), "Invalid account" );
         return unpack<T>( &data[0], data.size() );
178 179
      }

D
Daniel Larimer 已提交
180 181
   };

D
Daniel Larimer 已提交
182
   template<uint64_t Account, uint64_t Name>
D
Daniel Larimer 已提交
183
   struct action_meta {
D
Daniel Larimer 已提交
184 185
      static uint64_t get_account() { return Account; }
      static uint64_t get_name()  { return Name; }
D
Daniel Larimer 已提交
186 187
   };

D
Daniel Larimer 已提交
188

189 190 191 192 193 194 195 196
   template<typename T, typename... Args>
   void dispatch_inline( permission_level perm, 
                         account_name code, action_name act,
                         void (T::*)(Args...), std::tuple<Args...> args ) {
      action( perm, code, act, args ).send();
   }


197
 ///@} actioncpp api
198

D
Daniel Larimer 已提交
199 200
} // namespace eosio

201

202
#define ACTION( CODE, NAME ) struct NAME : ::eosio::action_meta<CODE, ::eosio::string_to_name(#NAME) >