action.hpp 5.8 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

85
      EOSLIB_SERIALIZE( permission_level, (actor)(permission) )
D
Daniel Larimer 已提交
86
   };
87

D
Daniel Larimer 已提交
88 89 90 91
   /**
    * This is the packed representation of an action along with
    * meta-data about the authorization levels.
    */
D
Daniel Larimer 已提交
92
   struct action {
93
      account_name               account;
D
Daniel Larimer 已提交
94 95
      action_name                name;
      vector<permission_level>   authorization;
96 97 98
      bytes                      data;

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

D
Daniel Larimer 已提交
100 101
      /**
       *  @tparam Action - a type derived from action_meta<Scope,Name>
102
       *  @param value - will be serialized via pack into data
D
Daniel Larimer 已提交
103 104
       */
      template<typename Action>
105 106
      action( vector<permission_level>&& auth, const Action& value ) {
         account       = Action::get_account();
D
Daniel Larimer 已提交
107
         name          = Action::get_name();
D
Daniel Larimer 已提交
108
         authorization = move(auth);
109
         data          = pack(value);
D
Daniel Larimer 已提交
110
      }
111

112 113
      /**
       *  @tparam Action - a type derived from action_meta<Scope,Name>
114
       *  @param value - will be serialized via pack into data
115 116 117
       */
      template<typename Action>
      action( const permission_level& auth, const Action& value )
118
      :authorization(1,auth) {
119 120
         account       = Action::get_account();
         name          = Action::get_name();
121
         data          = pack(value);
122 123
      }

M
Matias Romeo 已提交
124 125 126 127 128 129 130 131 132 133 134
      /**
       *  @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 已提交
135 136 137 138 139 140 141 142 143 144 145 146
      /**
       *  @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);
      }

147
      EOSLIB_SERIALIZE( action, (account)(name)(authorization)(data) )
148 149

      void send() const {
150
         auto serialize = pack(*this);
151
         ::send_inline(serialize.data(), serialize.size());
M
Matias Romeo 已提交
152 153 154 155 156 157
      }

      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());
158
      }
159 160 161 162 163 164 165 166

      /**
       * 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 已提交
167 168 169
         eosio_assert( name == T::get_name(), "Invalid name" );
         eosio_assert( account == T::get_account(), "Invalid account" );
         return unpack<T>( &data[0], data.size() );
170 171
      }

D
Daniel Larimer 已提交
172 173
   };

D
Daniel Larimer 已提交
174
   template<uint64_t Account, uint64_t Name>
D
Daniel Larimer 已提交
175
   struct action_meta {
D
Daniel Larimer 已提交
176 177
      static uint64_t get_account() { return Account; }
      static uint64_t get_name()  { return Name; }
D
Daniel Larimer 已提交
178 179
   };

D
Daniel Larimer 已提交
180

181 182 183 184 185 186 187 188
   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();
   }


189
 ///@} actioncpp api
190

D
Daniel Larimer 已提交
191 192
} // namespace eosio

193

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