wasm_interface.cpp 73.7 KB
Newer Older
B
Bart Wyatt 已提交
1 2
#include <eosio/chain/wasm_interface.hpp>
#include <eosio/chain/apply_context.hpp>
D
Daniel Larimer 已提交
3
#include <eosio/chain/controller.hpp>
4
#include <eosio/chain/transaction_context.hpp>
5
#include <eosio/chain/producer_schedule.hpp>
6
#include <eosio/chain/exceptions.hpp>
D
Daniel Larimer 已提交
7
#include <boost/core/ignore_unused.hpp>
8
#include <boost/multiprecision/cpp_bin_float.hpp>
9
#include <eosio/chain/authorization_manager.hpp>
10
#include <eosio/chain/resource_limits.hpp>
11
#include <eosio/chain/wasm_interface_private.hpp>
12
#include <eosio/chain/wasm_eosio_validation.hpp>
13
#include <eosio/chain/wasm_eosio_injection.hpp>
D
Daniel Larimer 已提交
14 15
#include <eosio/chain/global_property_object.hpp>
#include <eosio/chain/account_object.hpp>
16
#include <fc/exception/exception.hpp>
17
#include <fc/crypto/sha256.hpp>
18
#include <fc/crypto/sha1.hpp>
19
#include <fc/io/raw.hpp>
D
Daniel Larimer 已提交
20

21
#include <softfloat.hpp>
22
#include <compiler_builtins.hpp>
23 24
#include <boost/asio.hpp>
#include <boost/bind.hpp>
25
#include <fstream>
26

27
namespace eosio { namespace chain {
28 29
   using namespace webassembly;
   using namespace webassembly::common;
M
Matias Romeo 已提交
30

31
   wasm_interface::wasm_interface(vm_type vm) : my( new wasm_interface_impl(vm) ) {}
B
Bart Wyatt 已提交
32

33
   wasm_interface::~wasm_interface() {}
B
Bart Wyatt 已提交
34

35 36
   void wasm_interface::validate(const bytes& code) {
      Module module;
37 38 39 40 41 42
      try {
         Serialization::MemoryInputStream stream((U8*)code.data(), code.size());
         WASM::serialize(stream, module);
      } catch(Serialization::FatalSerializationException& e) {
         EOS_ASSERT(false, wasm_serialization_error, e.message.c_str());
      }
M
Matias Romeo 已提交
43

44
      wasm_validations::wasm_binary_validation validator(module);
45
      validator.validate();
M
Matias Romeo 已提交
46

47
      root_resolver resolver(true);
48
      LinkResult link_result = linkModule(module, resolver);
49

50 51 52
      //there are a couple opportunties for improvement here--
      //Easy: Cache the Module created here so it can be reused for instantiaion
      //Hard: Kick off instantiation in a separate thread at this location
53
	   }
54

55
   void wasm_interface::apply( const digest_type& code_id, const shared_string& code, apply_context& context ) {
56
      my->get_instantiated_module(code_id, code)->apply(context);
57 58
   }

59
   wasm_instantiated_module_interface::~wasm_instantiated_module_interface() {}
60
   wasm_runtime_interface::~wasm_runtime_interface() {}
61

62
#if defined(assert)
63
   #undef assert
64
#endif
65

B
Bart Wyatt 已提交
66
class context_aware_api {
67
   public:
68 69
      context_aware_api(apply_context& ctx, bool context_free = false )
      :context(ctx)
D
Daniel Larimer 已提交
70 71 72 73 74
      {
         if( context.context_free )
            FC_ASSERT( context_free, "only context free api's can be used in this context" );
         context.used_context_free_api |= !context_free;
      }
75

B
Bart Wyatt 已提交
76
   protected:
77
      apply_context&             context;
B
Bart Wyatt 已提交
78

B
Bart Wyatt 已提交
79
};
80

D
Daniel Larimer 已提交
81 82
class context_free_api : public context_aware_api {
   public:
83 84
      context_free_api( apply_context& ctx )
      :context_aware_api(ctx, true) {
D
Daniel Larimer 已提交
85 86 87 88 89 90 91 92
         /* the context_free_data is not available during normal application because it is prunable */
         FC_ASSERT( context.context_free, "this API may only be called from context_free apply" );
      }

      int get_context_free_data( uint32_t index, array_ptr<char> buffer, size_t buffer_size )const {
         return context.get_context_free_data( index, buffer, buffer_size );
      }
};
93

D
Daniel Larimer 已提交
94 95
class privileged_api : public context_aware_api {
   public:
96 97
      privileged_api( apply_context& ctx )
      :context_aware_api(ctx)
98 99 100
      {
         FC_ASSERT( context.privileged, "${code} does not have permission to call this API", ("code",context.receiver) );
      }
101

102 103 104 105 106 107 108 109 110 111
      /**
       * This should return true if a feature is active and irreversible, false if not.
       *
       * Irreversiblity by fork-database is not consensus safe, therefore, this defines
       * irreversiblity only by block headers not by BFT short-cut.
       */
      int is_feature_active( int64_t feature_name ) {
         return false;
      }

D
Daniel Larimer 已提交
112 113 114 115 116
      /**
       *  This should schedule the feature to be activated once the
       *  block that includes this call is irreversible. It should
       *  fail if the feature is already pending.
       *
117
       *  Feature name should be base32 encoded name.
D
Daniel Larimer 已提交
118
       */
119
      void activate_feature( int64_t feature_name ) {
B
Bucky Kittinger 已提交
120
         FC_ASSERT( !"Unsupported Hardfork Detected" );
D
Daniel Larimer 已提交
121
      }
122

B
Bart Wyatt 已提交
123 124 125 126 127 128 129 130 131
      /**
       * update the resource limits associated with an account.  Note these new values will not take effect until the
       * next resource "tick" which is currently defined as a cycle boundary inside a block.
       *
       * @param account - the account whose limits are being modified
       * @param ram_bytes - the limit for ram bytes
       * @param net_weight - the weight for determining share of network capacity
       * @param cpu_weight - the weight for determining share of compute capacity
       */
132
      void set_resource_limits( account_name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight) {
133 134 135
         EOS_ASSERT(ram_bytes >= -1, wasm_execution_error, "invalid value for ram resource limit expected [-1,INT64_MAX]");
         EOS_ASSERT(net_weight >= -1, wasm_execution_error, "invalid value for net resource weight expected [-1,INT64_MAX]");
         EOS_ASSERT(cpu_weight >= -1, wasm_execution_error, "invalid value for cpu resource weight expected [-1,INT64_MAX]");
136 137 138
         if( context.control.get_mutable_resource_limits_manager().set_account_limits(account, ram_bytes, net_weight, cpu_weight) ) {
            context.trx_context.validate_ram_usage.insert( account );
         }
D
Daniel Larimer 已提交
139
      }
140

141
      void get_resource_limits( account_name account, int64_t& ram_bytes, int64_t& net_weight, int64_t& cpu_weight ) {
D
Daniel Larimer 已提交
142
         context.control.get_resource_limits_manager().get_account_limits( account, ram_bytes, net_weight, cpu_weight);
D
Daniel Larimer 已提交
143
      }
144

145
      bool set_active_producers( array_ptr<char> packed_producer_schedule, size_t datalen) {
146
         datastream<const char*> ds( packed_producer_schedule, datalen );
147 148
         vector<producer_key> producers;
         fc::raw::unpack(ds, producers);
B
Bart Wyatt 已提交
149
         EOS_ASSERT(producers.size() <= config::max_producers, wasm_execution_error, "Producer schedule exceeds the maximum producer count for this chain");
150 151
         // check that producers are unique
         std::set<account_name> unique_producers;
152 153
         for (const auto& p: producers) {
            EOS_ASSERT( context.is_account(p.producer_name), wasm_execution_error, "producer schedule includes a nonexisting account" );
154
            EOS_ASSERT( p.block_signing_key.valid(), wasm_execution_error, "producer schedule includes an invalid key" );
155 156
            unique_producers.insert(p.producer_name);
         }
157
         EOS_ASSERT( producers.size() == unique_producers.size(), wasm_execution_error, "duplicate producer name in producer schedule" );
158
         return context.control.set_proposed_producers( std::move(producers) );
D
Daniel Larimer 已提交
159
      }
160

161
      uint32_t get_blockchain_parameters_packed( array_ptr<char> packed_blockchain_parameters, size_t buffer_size) {
D
Daniel Larimer 已提交
162
         auto& gpo = context.control.get_global_properties();
163 164 165 166 167 168

         auto s = fc::raw::pack_size( gpo.configuration );
         if( buffer_size == 0 ) return s;

         if ( s <= buffer_size ) {
            datastream<char*> ds( packed_blockchain_parameters, s );
169
            fc::raw::pack(ds, gpo.configuration);
170
            return s;
171
         }
172
         return 0;
173 174
      }

175 176 177 178
      void set_blockchain_parameters_packed( array_ptr<char> packed_blockchain_parameters, size_t datalen) {
         datastream<const char*> ds( packed_blockchain_parameters, datalen );
         chain::chain_config cfg;
         fc::raw::unpack(ds, cfg);
D
Daniel Larimer 已提交
179
         context.db.modify( context.control.get_global_properties(),
180 181 182 183 184
            [&]( auto& gprops ) {
                 gprops.configuration = cfg;
         });
      }

185 186 187
      bool is_privileged( account_name n )const {
         return context.db.get<account_object, by_name>( n ).privileged;
      }
D
Daniel Larimer 已提交
188

189 190
      void set_privileged( account_name n, bool is_priv ) {
         const auto& a = context.db.get<account_object, by_name>( n );
D
Daniel Larimer 已提交
191
         context.db.modify( a, [&]( auto& ma ){
192 193
            ma.privileged = is_priv;
         });
D
Daniel Larimer 已提交
194
      }
195

D
Daniel Larimer 已提交
196
};
B
Brian Johnson 已提交
197

198 199 200
class softfloat_api : public context_aware_api {
   public:
      // TODO add traps on truncations for special cases (NaN or outside the range which rounds to an integer)
201 202 203
      softfloat_api( apply_context& ctx )
      :context_aware_api(ctx, true) {}

204
      // float binops
205
      float _eosio_f32_add( float a, float b ) {
206 207 208
         float32_t ret = f32_add( to_softfloat32(a), to_softfloat32(b) );
         return *reinterpret_cast<float*>(&ret);
      }
209
      float _eosio_f32_sub( float a, float b ) {
210 211 212
         float32_t ret = f32_sub( to_softfloat32(a), to_softfloat32(b) );
         return *reinterpret_cast<float*>(&ret);
      }
213
      float _eosio_f32_div( float a, float b ) {
214 215 216
         float32_t ret = f32_div( to_softfloat32(a), to_softfloat32(b) );
         return *reinterpret_cast<float*>(&ret);
      }
217
      float _eosio_f32_mul( float a, float b ) {
218 219 220
         float32_t ret = f32_mul( to_softfloat32(a), to_softfloat32(b) );
         return *reinterpret_cast<float*>(&ret);
      }
221
      float _eosio_f32_min( float af, float bf ) {
222 223
         float32_t a = to_softfloat32(af);
         float32_t b = to_softfloat32(bf);
224
         if (is_nan(a)) {
225
            return af;
226
         }
227
         if (is_nan(b)) {
228
            return bf;
229
         }
230 231
         if ( sign_bit(a) != sign_bit(b) ) {
            return sign_bit(a) ? af : bf;
232
         }
233
         return f32_lt(a,b) ? af : bf;
234
      }
235
      float _eosio_f32_max( float af, float bf ) {
236 237
         float32_t a = to_softfloat32(af);
         float32_t b = to_softfloat32(bf);
238
         if (is_nan(a)) {
239
            return af;
240
         }
241 242
         if (is_nan(b)) {
            return bf;
243
         }
244 245
         if ( sign_bit(a) != sign_bit(b) ) {
            return sign_bit(a) ? bf : af;
246
         }
247
         return f32_lt( a, b ) ? bf : af;
248
      }
249
      float _eosio_f32_copysign( float af, float bf ) {
250 251
         float32_t a = to_softfloat32(af);
         float32_t b = to_softfloat32(bf);
252 253 254 255
         uint32_t sign_of_a = a.v >> 31;
         uint32_t sign_of_b = b.v >> 31;
         a.v &= ~(1 << 31);             // clear the sign bit
         a.v = a.v | (sign_of_b << 31); // add the sign of b
256
         return from_softfloat32(a);
257 258
      }
      // float unops
259
      float _eosio_f32_abs( float af ) {
260
         float32_t a = to_softfloat32(af);
261
         a.v &= ~(1 << 31);
262
         return from_softfloat32(a);
263
      }
264
      float _eosio_f32_neg( float af ) {
265
         float32_t a = to_softfloat32(af);
266
         uint32_t sign = a.v >> 31;
267
         a.v &= ~(1 << 31);
268
         a.v |= (!sign << 31);
269
         return from_softfloat32(a);
270
      }
271 272 273
      float _eosio_f32_sqrt( float a ) {
         float32_t ret = f32_sqrt( to_softfloat32(a) );
         return from_softfloat32(ret);
274 275
      }
      // ceil, floor, trunc and nearest are lifted from libc
276 277
      float _eosio_f32_ceil( float af ) {
         float32_t a = to_softfloat32(af);
278
         int e = (int)(a.v >> 23 & 0xFF) - 0X7F;
279 280
         uint32_t m;
         if (e >= 23)
281
            return af;
282
         if (e >= 0) {
283
            m = 0x007FFFFF >> e;
284
            if ((a.v & m) == 0)
285
               return af;
286 287 288 289 290 291 292 293 294
            if (a.v >> 31 == 0)
               a.v += m;
            a.v &= ~m;
         } else {
            if (a.v >> 31)
               a.v = 0x80000000; // return -0.0f
            else if (a.v << 1)
               a.v = 0x3F800000; // return 1.0f
         }
295

296
         return from_softfloat32(a);
297
      }
298 299
      float _eosio_f32_floor( float af ) {
         float32_t a = to_softfloat32(af);
300
         int e = (int)(a.v >> 23 & 0xFF) - 0X7F;
301 302
         uint32_t m;
         if (e >= 23)
303
            return af;
304
         if (e >= 0) {
305
            m = 0x007FFFFF >> e;
306
            if ((a.v & m) == 0)
307
               return af;
308 309 310 311 312 313 314
            if (a.v >> 31)
               a.v += m;
            a.v &= ~m;
         } else {
            if (a.v >> 31 == 0)
               a.v = 0;
            else if (a.v << 1)
315
               a.v = 0xBF800000; // return -1.0f
316
         }
317
         return from_softfloat32(a);
318
      }
319 320
      float _eosio_f32_trunc( float af ) {
         float32_t a = to_softfloat32(af);
321 322 323
         int e = (int)(a.v >> 23 & 0xff) - 0x7f + 9;
         uint32_t m;
         if (e >= 23 + 9)
324
            return af;
325 326 327 328
         if (e < 9)
            e = 1;
         m = -1U >> e;
         if ((a.v & m) == 0)
329
            return af;
330
         a.v &= ~m;
331
         return from_softfloat32(a);
332
      }
333 334
      float _eosio_f32_nearest( float af ) {
         float32_t a = to_softfloat32(af);
335 336 337 338
         int e = a.v>>23 & 0xff;
         int s = a.v>>31;
         float32_t y;
         if (e >= 0x7f+23)
339
            return af;
340
         if (s)
B
Bucky Kittinger 已提交
341
            y = f32_add( f32_sub( a, float32_t{inv_float_eps} ), float32_t{inv_float_eps} );
342
         else
B
Bucky Kittinger 已提交
343
            y = f32_sub( f32_add( a, float32_t{inv_float_eps} ), float32_t{inv_float_eps} );
344
         if (f32_eq( y, {0} ) )
345 346
            return s ? -0.0f : 0.0f;
         return from_softfloat32(y);
347
      }
348

349
      // float relops
350
      bool _eosio_f32_eq( float a, float b ) {  return f32_eq( to_softfloat32(a), to_softfloat32(b) ); }
351 352 353
      bool _eosio_f32_ne( float a, float b ) { return !f32_eq( to_softfloat32(a), to_softfloat32(b) ); }
      bool _eosio_f32_lt( float a, float b ) { return f32_lt( to_softfloat32(a), to_softfloat32(b) ); }
      bool _eosio_f32_le( float a, float b ) { return f32_le( to_softfloat32(a), to_softfloat32(b) ); }
354
      bool _eosio_f32_gt( float af, float bf ) {
355 356 357 358 359 360
         float32_t a = to_softfloat32(af);
         float32_t b = to_softfloat32(bf);
         if (is_nan(a))
            return false;
         if (is_nan(b))
            return false;
361
         return !f32_le( a, b );
362 363 364 365 366 367 368 369
      }
      bool _eosio_f32_ge( float af, float bf ) {
         float32_t a = to_softfloat32(af);
         float32_t b = to_softfloat32(bf);
         if (is_nan(a))
            return false;
         if (is_nan(b))
            return false;
370
         return !f32_lt( a, b );
371
      }
372 373

      // double binops
374 375 376
      double _eosio_f64_add( double a, double b ) {
         float64_t ret = f64_add( to_softfloat64(a), to_softfloat64(b) );
         return from_softfloat64(ret);
377
      }
378 379 380
      double _eosio_f64_sub( double a, double b ) {
         float64_t ret = f64_sub( to_softfloat64(a), to_softfloat64(b) );
         return from_softfloat64(ret);
381
      }
382 383 384
      double _eosio_f64_div( double a, double b ) {
         float64_t ret = f64_div( to_softfloat64(a), to_softfloat64(b) );
         return from_softfloat64(ret);
385
      }
386 387 388
      double _eosio_f64_mul( double a, double b ) {
         float64_t ret = f64_mul( to_softfloat64(a), to_softfloat64(b) );
         return from_softfloat64(ret);
389
      }
390
      double _eosio_f64_min( double af, double bf ) {
391 392 393 394 395 396 397 398 399
         float64_t a = to_softfloat64(af);
         float64_t b = to_softfloat64(bf);
         if (is_nan(a))
            return af;
         if (is_nan(b))
            return bf;
         if (sign_bit(a) != sign_bit(b))
            return sign_bit(a) ? af : bf;
         return f64_lt( a, b ) ? af : bf;
400 401
      }
      double _eosio_f64_max( double af, double bf ) {
402 403 404 405 406 407 408 409 410
         float64_t a = to_softfloat64(af);
         float64_t b = to_softfloat64(bf);
         if (is_nan(a))
            return af;
         if (is_nan(b))
            return bf;
         if (sign_bit(a) != sign_bit(b))
            return sign_bit(a) ? bf : af;
         return f64_lt( a, b ) ? bf : af;
411 412 413 414
      }
      double _eosio_f64_copysign( double af, double bf ) {
         float64_t a = to_softfloat64(af);
         float64_t b = to_softfloat64(bf);
415 416 417 418
         uint64_t sign_of_a = a.v >> 63;
         uint64_t sign_of_b = b.v >> 63;
         a.v &= ~(uint64_t(1) << 63);             // clear the sign bit
         a.v = a.v | (sign_of_b << 63); // add the sign of b
419
         return from_softfloat64(a);
420 421 422
      }

      // double unops
423
      double _eosio_f64_abs( double af ) {
424
         float64_t a = to_softfloat64(af);
425
         a.v &= ~(uint64_t(1) << 63);
426
         return from_softfloat64(a);
427
      }
428
      double _eosio_f64_neg( double af ) {
429
         float64_t a = to_softfloat64(af);
430
         uint64_t sign = a.v >> 63;
431
         a.v &= ~(uint64_t(1) << 63);
432
         a.v |= (uint64_t(!sign) << 63);
433
         return from_softfloat64(a);
434
      }
435
      double _eosio_f64_sqrt( double a ) {
436
         float64_t ret = f64_sqrt( to_softfloat64(a) );
437
         return from_softfloat64(ret);
438 439
      }
      // ceil, floor, trunc and nearest are lifted from libc
440
      double _eosio_f64_ceil( double af ) {
441
         float64_t a = to_softfloat64( af );
442
         float64_t ret;
443 444 445
         int e = a.v >> 52 & 0x7ff;
         float64_t y;
         if (e >= 0x3ff+52 || f64_eq( a, { 0 } ))
446
            return af;
447 448
         /* y = int(x) - x, where int(x) is an integer neighbor of x */
         if (a.v >> 63)
B
Bucky Kittinger 已提交
449
            y = f64_sub( f64_add( f64_sub( a, float64_t{inv_double_eps} ), float64_t{inv_double_eps} ), a );
450
         else
B
Bucky Kittinger 已提交
451
            y = f64_sub( f64_sub( f64_add( a, float64_t{inv_double_eps} ), float64_t{inv_double_eps} ), a );
452 453
         /* special case because of non-nearest rounding modes */
         if (e <= 0x3ff-1) {
454 455
            return a.v >> 63 ? -0.0 : 1.0; //float64_t{0x8000000000000000} : float64_t{0xBE99999A3F800000}; //either -0.0 or 1
         }
456 457
         if (f64_lt( y, to_softfloat64(0) )) {
            ret = f64_add( f64_add( a, y ), to_softfloat64(1) ); // 0xBE99999A3F800000 } ); // plus 1
458
            return from_softfloat64(ret);
459
         }
460
         ret = f64_add( a, y );
461
         return from_softfloat64(ret);
462
      }
463
      double _eosio_f64_floor( double af ) {
464
         float64_t a = to_softfloat64( af );
465
         float64_t ret;
466 467
         int e = a.v >> 52 & 0x7FF;
         float64_t y;
468 469
         double de = 1/DBL_EPSILON;
         if ( a.v == 0x8000000000000000) {
470
            return af;
471 472 473 474
         }
         if (e >= 0x3FF+52 || a.v == 0) {
            return af;
         }
475
         if (a.v >> 63)
B
Bucky Kittinger 已提交
476
            y = f64_sub( f64_add( f64_sub( a, float64_t{inv_double_eps} ), float64_t{inv_double_eps} ), a );
477
         else
B
Bucky Kittinger 已提交
478
            y = f64_sub( f64_sub( f64_add( a, float64_t{inv_double_eps} ), float64_t{inv_double_eps} ), a );
479
         if (e <= 0x3FF-1) {
480
            return a.v>>63 ? -1.0 : 0.0; //float64_t{0xBFF0000000000000} : float64_t{0}; // -1 or 0
481
         }
482
         if ( !f64_le( y, float64_t{0} ) ) {
483
            ret = f64_sub( f64_add(a,y), to_softfloat64(1.0));
484
            return from_softfloat64(ret);
485 486
         }
         ret = f64_add( a, y );
487
         return from_softfloat64(ret);
488
      }
489
      double _eosio_f64_trunc( double af ) {
490
         float64_t a = to_softfloat64( af );
491 492 493
         int e = (int)(a.v >> 52 & 0x7ff) - 0x3ff + 12;
         uint64_t m;
         if (e >= 52 + 12)
494
            return af;
495 496 497 498
         if (e < 12)
            e = 1;
         m = -1ULL >> e;
         if ((a.v & m) == 0)
499
            return af;
500
         a.v &= ~m;
501
         return from_softfloat64(a);
502 503
      }

504
      double _eosio_f64_nearest( double af ) {
505
         float64_t a = to_softfloat64( af );
506 507 508 509
         int e = (a.v >> 52 & 0x7FF);
         int s = a.v >> 63;
         float64_t y;
         if ( e >= 0x3FF+52 )
510
            return af;
511
         if ( s )
B
Bucky Kittinger 已提交
512
            y = f64_add( f64_sub( a, float64_t{inv_double_eps} ), float64_t{inv_double_eps} );
513
         else
B
Bucky Kittinger 已提交
514
            y = f64_sub( f64_add( a, float64_t{inv_double_eps} ), float64_t{inv_double_eps} );
515
         if ( f64_eq( y, float64_t{0} ) )
516
            return s ? -0.0 : 0.0;
517
         return from_softfloat64(y);
518 519 520
      }

      // double relops
521 522 523 524
      bool _eosio_f64_eq( double a, double b ) { return f64_eq( to_softfloat64(a), to_softfloat64(b) ); }
      bool _eosio_f64_ne( double a, double b ) { return !f64_eq( to_softfloat64(a), to_softfloat64(b) ); }
      bool _eosio_f64_lt( double a, double b ) { return f64_lt( to_softfloat64(a), to_softfloat64(b) ); }
      bool _eosio_f64_le( double a, double b ) { return f64_le( to_softfloat64(a), to_softfloat64(b) ); }
525
      bool _eosio_f64_gt( double af, double bf ) {
526 527 528 529 530 531
         float64_t a = to_softfloat64(af);
         float64_t b = to_softfloat64(bf);
         if (is_nan(a))
            return false;
         if (is_nan(b))
            return false;
532
         return !f64_le( a, b );
533 534 535 536 537 538 539 540
      }
      bool _eosio_f64_ge( double af, double bf ) {
         float64_t a = to_softfloat64(af);
         float64_t b = to_softfloat64(bf);
         if (is_nan(a))
            return false;
         if (is_nan(b))
            return false;
541
         return !f64_lt( a, b );
542 543 544
      }

      // float and double conversions
545 546
      double _eosio_f32_promote( float a ) {
         return from_softfloat64(f32_to_f64( to_softfloat32(a)) );
B
Bucky Kittinger 已提交
547
      }
548 549
      float _eosio_f64_demote( double a ) {
         return from_softfloat32(f64_to_f32( to_softfloat64(a)) );
B
Bucky Kittinger 已提交
550
      }
551
      int32_t _eosio_f32_trunc_i32s( float af ) {
B
Bucky Kittinger 已提交
552
         float32_t a = to_softfloat32(af);
553
         if (_eosio_f32_ge(af, 2147483648.0f) || _eosio_f32_lt(af, -2147483648.0f))
554 555
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_s/i32 overflow" );

B
Bucky Kittinger 已提交
556 557
         if (is_nan(a))
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_s/i32 unrepresentable");
558
         return f32_to_i32( to_softfloat32(_eosio_f32_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
559
      }
560
      int32_t _eosio_f64_trunc_i32s( double af ) {
B
Bucky Kittinger 已提交
561
         float64_t a = to_softfloat64(af);
562
         if (_eosio_f64_ge(af, 2147483648.0) || _eosio_f64_lt(af, -2147483648.0))
B
Bucky Kittinger 已提交
563 564 565
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_s/i32 overflow");
         if (is_nan(a))
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_s/i32 unrepresentable");
566
         return f64_to_i32( to_softfloat64(_eosio_f64_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
567
      }
568
      uint32_t _eosio_f32_trunc_i32u( float af ) {
B
Bucky Kittinger 已提交
569
         float32_t a = to_softfloat32(af);
570 571
         if (_eosio_f32_ge(af, 4294967296.0f) || _eosio_f32_le(af, -1.0f))
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_u/i32 overflow");
B
Bucky Kittinger 已提交
572
         if (is_nan(a))
573
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_u/i32 unrepresentable");
574
         return f32_to_ui32( to_softfloat32(_eosio_f32_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
575
      }
576
      uint32_t _eosio_f64_trunc_i32u( double af ) {
B
Bucky Kittinger 已提交
577
         float64_t a = to_softfloat64(af);
578 579
         if (_eosio_f64_ge(af, 4294967296.0) || _eosio_f64_le(af, -1.0))
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_u/i32 overflow");
B
Bucky Kittinger 已提交
580
         if (is_nan(a))
581
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_u/i32 unrepresentable");
582
         return f64_to_ui32( to_softfloat64(_eosio_f64_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
583
      }
584
      int64_t _eosio_f32_trunc_i64s( float af ) {
B
Bucky Kittinger 已提交
585
         float32_t a = to_softfloat32(af);
586
         if (_eosio_f32_ge(af, 9223372036854775808.0f) || _eosio_f32_lt(af, -9223372036854775808.0f))
587
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_s/i64 overflow");
B
Bucky Kittinger 已提交
588
         if (is_nan(a))
589
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_s/i64 unrepresentable");
590
         return f32_to_i64( to_softfloat32(_eosio_f32_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
591
      }
592
      int64_t _eosio_f64_trunc_i64s( double af ) {
B
Bucky Kittinger 已提交
593
         float64_t a = to_softfloat64(af);
594
         if (_eosio_f64_ge(af, 9223372036854775808.0) || _eosio_f64_lt(af, -9223372036854775808.0))
595
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_s/i64 overflow");
B
Bucky Kittinger 已提交
596
         if (is_nan(a))
597
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_s/i64 unrepresentable");
598 599

         return f64_to_i64( to_softfloat64(_eosio_f64_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
600
      }
601
      uint64_t _eosio_f32_trunc_i64u( float af ) {
B
Bucky Kittinger 已提交
602
         float32_t a = to_softfloat32(af);
603 604
         if (_eosio_f32_ge(af, 18446744073709551616.0f) || _eosio_f32_le(af, -1.0f))
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_u/i64 overflow");
B
Bucky Kittinger 已提交
605
         if (is_nan(a))
606
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_u/i64 unrepresentable");
607
         return f32_to_ui64( to_softfloat32(_eosio_f32_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
608
      }
609
      uint64_t _eosio_f64_trunc_i64u( double af ) {
B
Bucky Kittinger 已提交
610
         float64_t a = to_softfloat64(af);
611 612
         if (_eosio_f64_ge(af, 18446744073709551616.0) || _eosio_f64_le(af, -1.0))
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_u/i64 overflow");
B
Bucky Kittinger 已提交
613
         if (is_nan(a))
614
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_u/i64 unrepresentable");
615
         return f64_to_ui64( to_softfloat64(_eosio_f64_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
616
      }
617 618
      float _eosio_i32_to_f32( int32_t a )  {
         return from_softfloat32(i32_to_f32( a ));
B
Bucky Kittinger 已提交
619
      }
620 621
      float _eosio_i64_to_f32( int64_t a ) {
         return from_softfloat32(i64_to_f32( a ));
B
Bucky Kittinger 已提交
622
      }
623 624
      float _eosio_ui32_to_f32( uint32_t a ) {
         return from_softfloat32(ui32_to_f32( a ));
B
Bucky Kittinger 已提交
625
      }
626 627
      float _eosio_ui64_to_f32( uint64_t a ) {
         return from_softfloat32(ui64_to_f32( a ));
B
Bucky Kittinger 已提交
628
      }
629 630
      double _eosio_i32_to_f64( int32_t a ) {
         return from_softfloat64(i32_to_f64( a ));
B
Bucky Kittinger 已提交
631
      }
632 633
      double _eosio_i64_to_f64( int64_t a ) {
         return from_softfloat64(i64_to_f64( a ));
B
Bucky Kittinger 已提交
634
      }
635 636
      double _eosio_ui32_to_f64( uint32_t a ) {
         return from_softfloat64(ui32_to_f64( a ));
B
Bucky Kittinger 已提交
637 638
      }
      double _eosio_ui64_to_f64( uint64_t a ) {
639
         return from_softfloat64(ui64_to_f64( a ));
B
Bucky Kittinger 已提交
640
      }
641

642 643 644 645 646 647 648
      static bool is_nan( const float32_t f ) {
         return ((f.v & 0x7FFFFFFF) > 0x7F800000);
      }
      static bool is_nan( const float64_t f ) {
         return ((f.v & 0x7FFFFFFFFFFFFFFF) > 0x7FF0000000000000);
      }
      static bool is_nan( const float128_t& f ) {
649
         return (((~(f.v[1]) & uint64_t( 0x7FFF000000000000 )) == 0) && (f.v[0] || ((f.v[1]) & uint64_t( 0x0000FFFFFFFFFFFF ))));
650 651
      }
      static float32_t to_softfloat32( float f ) {
652 653
         return *reinterpret_cast<float32_t*>(&f);
      }
654
      static float64_t to_softfloat64( double d ) {
655
         return *reinterpret_cast<float64_t*>(&d);
656
      }
657
      static float from_softfloat32( float32_t f ) {
658 659
         return *reinterpret_cast<float*>(&f);
      }
660
      static double from_softfloat64( float64_t d ) {
661
         return *reinterpret_cast<double*>(&d);
662
      }
663
      static constexpr uint32_t inv_float_eps = 0x4B000000;
B
Bucky Kittinger 已提交
664
      static constexpr uint64_t inv_double_eps = 0x4330000000000000;
665

B
Bucky Kittinger 已提交
666 667
      static bool sign_bit( float32_t f ) { return f.v >> 31; }
      static bool sign_bit( float64_t f ) { return f.v >> 63; }
668

669
};
670

671 672 673
class producer_api : public context_aware_api {
   public:
      using context_aware_api::context_aware_api;
674

675
      int get_active_producers(array_ptr<chain::account_name> producers, size_t buffer_size) {
676
         auto active_producers = context.get_active_producers();
677

678
         size_t len = active_producers.size();
679 680 681 682 683 684 685
         auto s = len * sizeof(chain::account_name);
         if( buffer_size == 0 ) return s;

         auto copy_size = std::min( buffer_size, s );
         memcpy( producers, active_producers.data(), copy_size );

         return copy_size;
686 687 688 689
      }
};

class crypto_api : public context_aware_api {
690
   public:
691 692
      explicit crypto_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
693 694
      /**
       * This method can be optimized out during replay as it has
695
       * no possible side effects other than "passing".
696
       */
K
Kevin Heifner 已提交
697
      void assert_recover_key( const fc::sha256& digest,
698 699 700 701 702 703 704 705
                        array_ptr<char> sig, size_t siglen,
                        array_ptr<char> pub, size_t publen ) {
         fc::crypto::signature s;
         fc::crypto::public_key p;
         datastream<const char*> ds( sig, siglen );
         datastream<const char*> pubds( pub, publen );

         fc::raw::unpack(ds, s);
B
Bucky Kittinger 已提交
706
         fc::raw::unpack(pubds, p);
707 708 709 710 711

         auto check = fc::crypto::public_key( s, digest, false );
         FC_ASSERT( check == p, "Error expected key different than recovered key" );
      }

K
Kevin Heifner 已提交
712
      int recover_key( const fc::sha256& digest,
713 714 715 716 717 718 719 720 721 722 723
                        array_ptr<char> sig, size_t siglen,
                        array_ptr<char> pub, size_t publen ) {
         fc::crypto::signature s;
         datastream<const char*> ds( sig, siglen );
         datastream<char*> pubds( pub, publen );

         fc::raw::unpack(ds, s);
         fc::raw::pack( pubds, fc::crypto::public_key( s, digest, false ) );
         return pubds.tellp();
      }

724 725 726 727 728
      void assert_sha256(array_ptr<char> data, size_t datalen, const fc::sha256& hash_val) {
         auto result = fc::sha256::hash( data, datalen );
         FC_ASSERT( result == hash_val, "hash miss match" );
      }

B
Bucky Kittinger 已提交
729
      void assert_sha1(array_ptr<char> data, size_t datalen, const fc::sha1& hash_val) {
B
Bucky Kittinger 已提交
730 731 732 733
         auto result = fc::sha1::hash( data, datalen );
         FC_ASSERT( result == hash_val, "hash miss match" );
      }

B
Bucky Kittinger 已提交
734
      void assert_sha512(array_ptr<char> data, size_t datalen, const fc::sha512& hash_val) {
B
Bucky Kittinger 已提交
735 736 737 738
         auto result = fc::sha512::hash( data, datalen );
         FC_ASSERT( result == hash_val, "hash miss match" );
      }

B
Bucky Kittinger 已提交
739
      void assert_ripemd160(array_ptr<char> data, size_t datalen, const fc::ripemd160& hash_val) {
B
Bucky Kittinger 已提交
740 741 742 743
         auto result = fc::ripemd160::hash( data, datalen );
         FC_ASSERT( result == hash_val, "hash miss match" );
      }

744 745 746 747
      void sha1(array_ptr<char> data, size_t datalen, fc::sha1& hash_val) {
         hash_val = fc::sha1::hash( data, datalen );
      }

748 749 750
      void sha256(array_ptr<char> data, size_t datalen, fc::sha256& hash_val) {
         hash_val = fc::sha256::hash( data, datalen );
      }
751 752 753 754 755 756 757 758

      void sha512(array_ptr<char> data, size_t datalen, fc::sha512& hash_val) {
         hash_val = fc::sha512::hash( data, datalen );
      }

      void ripemd160(array_ptr<char> data, size_t datalen, fc::ripemd160& hash_val) {
         hash_val = fc::ripemd160::hash( data, datalen );
      }
759 760
};

M
Matias Romeo 已提交
761 762 763 764
class permission_api : public context_aware_api {
   public:
      using context_aware_api::context_aware_api;

765 766 767 768
      bool check_transaction_authorization( array_ptr<char> trx_data,     size_t trx_size,
                                            array_ptr<char> pubkeys_data, size_t pubkeys_size,
                                            array_ptr<char> perms_data,   size_t perms_size
                                          )
A
arhag 已提交
769 770 771 772 773 774 775 776 777 778
      {
         transaction trx = fc::raw::unpack<transaction>( trx_data, trx_size );

         flat_set<public_key_type> provided_keys;
         unpack_provided_keys( provided_keys, pubkeys_data, pubkeys_size );

         flat_set<permission_level> provided_permissions;
         unpack_provided_permissions( provided_permissions, perms_data, perms_size );

         try {
779 780 781 782 783 784 785 786 787 788
            context.control
                   .get_authorization_manager()
                   .check_authorization( trx.actions,
                                         provided_keys,
                                         provided_permissions,
                                         fc::seconds(trx.delay_sec),
                                         std::bind(&apply_context::checktime, &context, std::placeholders::_1),
                                         false
                                       );
            return true;
A
arhag 已提交
789 790
         } catch( const authorization_exception& e ) {}

791
         return false;
A
arhag 已提交
792 793
      }

794 795 796 797 798
      bool check_permission_authorization( account_name account, permission_name permission,
                                           array_ptr<char> pubkeys_data, size_t pubkeys_size,
                                           array_ptr<char> perms_data,   size_t perms_size,
                                           uint64_t delay_us
                                         )
A
arhag 已提交
799 800 801 802 803 804 805 806 807 808 809
      {
         EOS_ASSERT( delay_us <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max()),
                     action_validate_exception, "provided delay is too large" );

         flat_set<public_key_type> provided_keys;
         unpack_provided_keys( provided_keys, pubkeys_data, pubkeys_size );

         flat_set<permission_level> provided_permissions;
         unpack_provided_permissions( provided_permissions, perms_data, perms_size );

         try {
810 811 812 813 814 815 816 817 818 819 820
            context.control
                   .get_authorization_manager()
                   .check_authorization( account,
                                         permission,
                                         provided_keys,
                                         provided_permissions,
                                         fc::microseconds(delay_us),
                                         std::bind(&apply_context::checktime, &context, std::placeholders::_1),
                                         false
                                       );
            return true;
A
arhag 已提交
821 822
         } catch( const authorization_exception& e ) {}

823
         return false;
M
Matias Romeo 已提交
824 825
      }

826
      int64_t get_permission_last_used( account_name account, permission_name permission) {
827 828
         const auto& am = context.control.get_authorization_manager();
         return am.get_permission_last_used( am.get_permission({account, permission}) ).time_since_epoch().count();
829
      };
B
Bart Wyatt 已提交
830

831
      int64_t get_account_creation_date( account_name account ) {
832 833 834 835
         auto* acct = context.db.find<account_object, by_name>(account);
         EOS_ASSERT( acct != nullptr, action_validate_exception,
                     "account '${account}' does not exist", ("account", account) );
         return time_point(acct->creation_date).time_since_epoch().count();
836 837
      }

838

839 840 841 842 843 844
   private:
      void unpack_provided_keys( flat_set<public_key_type>& keys, const char* pubkeys_data, size_t pubkeys_size ) {
         keys.clear();
         if( pubkeys_size == 0 ) return;

         keys = fc::raw::unpack<flat_set<public_key_type>>( pubkeys_data, pubkeys_size );
B
Bart Wyatt 已提交
845
      }
846

847 848 849 850 851
      void unpack_provided_permissions( flat_set<permission_level>& permissions, const char* perms_data, size_t perms_size ) {
         permissions.clear();
         if( perms_size == 0 ) return;

         permissions = fc::raw::unpack<flat_set<permission_level>>( perms_data, perms_size );
852 853
      }

854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
};

class authorization_api : public context_aware_api {
   public:
      using context_aware_api::context_aware_api;

   void require_authorization( const account_name& account ) {
      context.require_authorization( account );
   }

   bool has_authorization( const account_name& account )const {
      return context.has_authorization( account );
   }

   void require_authorization(const account_name& account,
                                                 const permission_name& permission) {
      context.require_authorization( account, permission );
   }

   void require_recipient( account_name recipient ) {
      context.require_recipient( recipient );
   }

   bool is_account( const account_name& account )const {
      return context.is_account( account );
   }

M
Matias Romeo 已提交
881 882
};

B
Bart Wyatt 已提交
883 884
class system_api : public context_aware_api {
   public:
885
      using context_aware_api::context_aware_api;
B
Bart Wyatt 已提交
886

887 888
      uint64_t current_time() {
         return static_cast<uint64_t>( context.control.pending_block_time().time_since_epoch().count() );
889
      }
890

891 892
      uint64_t publication_time() {
         return static_cast<uint64_t>( context.trx_context.published.time_since_epoch().count() );
B
Bart Wyatt 已提交
893
      }
894

895
};
896

897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
class context_free_system_api :  public context_aware_api {
public:
   explicit context_free_system_api( apply_context& ctx )
   :context_aware_api(ctx,true){}

   void abort() {
      edump(("abort() called"));
      FC_ASSERT( false, "abort() called");
   }

   void eosio_assert(bool condition, null_terminated_ptr str) {
      if( !condition ) {
         std::string message( str );
         edump((message));
         FC_ASSERT( condition, "assertion failed: ${s}", ("s",message));
912
      }
913 914 915 916 917 918
   }

   void eosio_exit(int32_t code) {
      throw wasm_exit{code};
   }

B
Bart Wyatt 已提交
919 920 921 922
};

class action_api : public context_aware_api {
   public:
923 924
   action_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
B
Bart Wyatt 已提交
925

926 927 928 929 930 931 932 933
      int read_action_data(array_ptr<char> memory, size_t buffer_size) {
         auto s = context.act.data.size();
         if( buffer_size == 0 ) return s;

         auto copy_size = std::min( buffer_size, s );
         memcpy( memory, context.act.data.data(), copy_size );

         return copy_size;
934 935
      }

936
      int action_data_size() {
B
Bart Wyatt 已提交
937
         return context.act.data.size();
938 939
      }

940 941 942
      name current_receiver() {
         return context.receiver;
      }
943
};
B
Brian Johnson 已提交
944

B
Bart Wyatt 已提交
945 946
class console_api : public context_aware_api {
   public:
947 948
      console_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
B
Bart Wyatt 已提交
949

950 951
      void prints(null_terminated_ptr str) {
         context.console_append<const char*>(str);
B
Bart Wyatt 已提交
952 953 954
      }

      void prints_l(array_ptr<const char> str, size_t str_len ) {
955
         context.console_append(string(str, str_len));
B
Bart Wyatt 已提交
956 957
      }

958
      void printi(int64_t val) {
D
Daniel Larimer 已提交
959 960 961
         context.console_append(val);
      }

962
      void printui(uint64_t val) {
963
         context.console_append(val);
B
Bart Wyatt 已提交
964 965
      }

966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
      void printi128(const __int128& val) {
         bool is_negative = (val < 0);
         unsigned __int128 val_magnitude;

         if( is_negative )
            val_magnitude = static_cast<unsigned __int128>(-val); // Works even if val is at the lowest possible value of a int128_t
         else
            val_magnitude = static_cast<unsigned __int128>(val);

         fc::uint128_t v(val_magnitude>>64, static_cast<uint64_t>(val_magnitude) );

         if( is_negative ) {
            context.console_append("-");
         }

981
         context.console_append(fc::variant(v).get_string());
B
Bart Wyatt 已提交
982 983
      }

984 985
      void printui128(const unsigned __int128& val) {
         fc::uint128_t v(val>>64, static_cast<uint64_t>(val) );
986
         context.console_append(fc::variant(v).get_string());
B
Bart Wyatt 已提交
987 988
      }

989 990 991 992 993 994
      void printsf( float val ) {
         // Assumes float representation on native side is the same as on the WASM side
         auto& console = context.get_console_stream();
         auto orig_prec = console.precision();

         console.precision( std::numeric_limits<float>::digits10 );
995
         context.console_append(val);
996 997

         console.precision( orig_prec );
D
Daniel Larimer 已提交
998
      }
999

1000 1001 1002 1003 1004 1005
      void printdf( double val ) {
         // Assumes double representation on native side is the same as on the WASM side
         auto& console = context.get_console_stream();
         auto orig_prec = console.precision();

         console.precision( std::numeric_limits<double>::digits10 );
1006
         context.console_append(val);
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033

         console.precision( orig_prec );
      }

      void printqf( const float128_t& val ) {
         /*
          * Native-side long double uses an 80-bit extended-precision floating-point number.
          * The easiest solution for now was to use the Berkeley softfloat library to round the 128-bit
          * quadruple-precision floating-point number to an 80-bit extended-precision floating-point number
          * (losing precision) which then allows us to simply cast it into a long double for printing purposes.
          *
          * Later we might find a better solution to print the full quadruple-precision floating-point number.
          * Maybe with some compilation flag that turns long double into a quadruple-precision floating-point number,
          * or maybe with some library that allows us to print out quadruple-precision floating-point numbers without
          * having to deal with long doubles at all.
          */

         auto& console = context.get_console_stream();
         auto orig_prec = console.precision();

         console.precision( std::numeric_limits<long double>::digits10 );

         extFloat80_t val_approx;
         f128M_to_extF80M(&val, &val_approx);
         context.console_append( *(long double*)(&val_approx) );

         console.precision( orig_prec );
B
Bart Wyatt 已提交
1034 1035 1036
      }

      void printn(const name& value) {
1037
         context.console_append(value.to_string());
B
Bart Wyatt 已提交
1038 1039 1040
      }

      void printhex(array_ptr<const char> data, size_t data_len ) {
1041
         context.console_append(fc::to_hex(data, data_len));
B
Bart Wyatt 已提交
1042 1043 1044
      }
};

A
arhag 已提交
1045
#define DB_API_METHOD_WRAPPERS_SIMPLE_SECONDARY(IDX, TYPE)\
1046 1047 1048 1049 1050 1051 1052 1053 1054
      int db_##IDX##_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const TYPE& secondary ) {\
         return context.IDX.store( scope, table, payer, id, secondary );\
      }\
      void db_##IDX##_update( int iterator, uint64_t payer, const TYPE& secondary ) {\
         return context.IDX.update( iterator, payer, secondary );\
      }\
      void db_##IDX##_remove( int iterator ) {\
         return context.IDX.remove( iterator );\
      }\
A
arhag 已提交
1055
      int db_##IDX##_find_secondary( uint64_t code, uint64_t scope, uint64_t table, const TYPE& secondary, uint64_t& primary ) {\
1056 1057 1058
         return context.IDX.find_secondary(code, scope, table, secondary, primary);\
      }\
      int db_##IDX##_find_primary( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t primary ) {\
A
arhag 已提交
1059
         return context.IDX.find_primary(code, scope, table, secondary, primary);\
1060 1061 1062 1063 1064 1065 1066
      }\
      int db_##IDX##_lowerbound( uint64_t code, uint64_t scope, uint64_t table,  TYPE& secondary, uint64_t& primary ) {\
         return context.IDX.lowerbound_secondary(code, scope, table, secondary, primary);\
      }\
      int db_##IDX##_upperbound( uint64_t code, uint64_t scope, uint64_t table,  TYPE& secondary, uint64_t& primary ) {\
         return context.IDX.upperbound_secondary(code, scope, table, secondary, primary);\
      }\
1067 1068 1069
      int db_##IDX##_end( uint64_t code, uint64_t scope, uint64_t table ) {\
         return context.IDX.end_secondary(code, scope, table);\
      }\
1070 1071 1072 1073 1074 1075 1076
      int db_##IDX##_next( int iterator, uint64_t& primary  ) {\
         return context.IDX.next_secondary(iterator, primary);\
      }\
      int db_##IDX##_previous( int iterator, uint64_t& primary ) {\
         return context.IDX.previous_secondary(iterator, primary);\
      }

A
arhag 已提交
1077 1078
#define DB_API_METHOD_WRAPPERS_ARRAY_SECONDARY(IDX, ARR_SIZE, ARR_ELEMENT_TYPE)\
      int db_##IDX##_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, array_ptr<const ARR_ELEMENT_TYPE> data, size_t data_len) {\
A
arhag 已提交
1079 1080 1081 1082 1083
         FC_ASSERT( data_len == ARR_SIZE,\
                    "invalid size of secondary key array for " #IDX ": given ${given} bytes but expected ${expected} bytes",\
                    ("given",data_len)("expected",ARR_SIZE) );\
         return context.IDX.store(scope, table, payer, id, data.value);\
      }\
A
arhag 已提交
1084
      void db_##IDX##_update( int iterator, uint64_t payer, array_ptr<const ARR_ELEMENT_TYPE> data, size_t data_len ) {\
A
arhag 已提交
1085 1086 1087 1088 1089 1090 1091 1092
         FC_ASSERT( data_len == ARR_SIZE,\
                    "invalid size of secondary key array for " #IDX ": given ${given} bytes but expected ${expected} bytes",\
                    ("given",data_len)("expected",ARR_SIZE) );\
         return context.IDX.update(iterator, payer, data.value);\
      }\
      void db_##IDX##_remove( int iterator ) {\
         return context.IDX.remove(iterator);\
      }\
A
arhag 已提交
1093
      int db_##IDX##_find_secondary( uint64_t code, uint64_t scope, uint64_t table, array_ptr<const ARR_ELEMENT_TYPE> data, size_t data_len, uint64_t& primary ) {\
A
arhag 已提交
1094 1095 1096 1097 1098
         FC_ASSERT( data_len == ARR_SIZE,\
                    "invalid size of secondary key array for " #IDX ": given ${given} bytes but expected ${expected} bytes",\
                    ("given",data_len)("expected",ARR_SIZE) );\
         return context.IDX.find_secondary(code, scope, table, data, primary);\
      }\
A
arhag 已提交
1099
      int db_##IDX##_find_primary( uint64_t code, uint64_t scope, uint64_t table, array_ptr<ARR_ELEMENT_TYPE> data, size_t data_len, uint64_t primary ) {\
A
arhag 已提交
1100 1101 1102 1103 1104
         FC_ASSERT( data_len == ARR_SIZE,\
                    "invalid size of secondary key array for " #IDX ": given ${given} bytes but expected ${expected} bytes",\
                    ("given",data_len)("expected",ARR_SIZE) );\
         return context.IDX.find_primary(code, scope, table, data.value, primary);\
      }\
A
arhag 已提交
1105
      int db_##IDX##_lowerbound( uint64_t code, uint64_t scope, uint64_t table, array_ptr<ARR_ELEMENT_TYPE> data, size_t data_len, uint64_t& primary ) {\
A
arhag 已提交
1106 1107 1108 1109 1110
         FC_ASSERT( data_len == ARR_SIZE,\
                    "invalid size of secondary key array for " #IDX ": given ${given} bytes but expected ${expected} bytes",\
                    ("given",data_len)("expected",ARR_SIZE) );\
         return context.IDX.lowerbound_secondary(code, scope, table, data.value, primary);\
      }\
A
arhag 已提交
1111
      int db_##IDX##_upperbound( uint64_t code, uint64_t scope, uint64_t table, array_ptr<ARR_ELEMENT_TYPE> data, size_t data_len, uint64_t& primary ) {\
A
arhag 已提交
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
         FC_ASSERT( data_len == ARR_SIZE,\
                    "invalid size of secondary key array for " #IDX ": given ${given} bytes but expected ${expected} bytes",\
                    ("given",data_len)("expected",ARR_SIZE) );\
         return context.IDX.upperbound_secondary(code, scope, table, data.value, primary);\
      }\
      int db_##IDX##_end( uint64_t code, uint64_t scope, uint64_t table ) {\
         return context.IDX.end_secondary(code, scope, table);\
      }\
      int db_##IDX##_next( int iterator, uint64_t& primary  ) {\
         return context.IDX.next_secondary(iterator, primary);\
      }\
      int db_##IDX##_previous( int iterator, uint64_t& primary ) {\
         return context.IDX.previous_secondary(iterator, primary);\
      }

1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
#define DB_API_METHOD_WRAPPERS_FLOAT_SECONDARY(IDX, TYPE)\
      int db_##IDX##_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const TYPE& secondary ) {\
         EOS_ASSERT( !softfloat_api::is_nan( secondary ), transaction_exception, "NaN is not an allowed value for a secondary key" );\
         return context.IDX.store( scope, table, payer, id, secondary );\
      }\
      void db_##IDX##_update( int iterator, uint64_t payer, const TYPE& secondary ) {\
         EOS_ASSERT( !softfloat_api::is_nan( secondary ), transaction_exception, "NaN is not an allowed value for a secondary key" );\
         return context.IDX.update( iterator, payer, secondary );\
      }\
      void db_##IDX##_remove( int iterator ) {\
         return context.IDX.remove( iterator );\
      }\
      int db_##IDX##_find_secondary( uint64_t code, uint64_t scope, uint64_t table, const TYPE& secondary, uint64_t& primary ) {\
         EOS_ASSERT( !softfloat_api::is_nan( secondary ), transaction_exception, "NaN is not an allowed value for a secondary key" );\
         return context.IDX.find_secondary(code, scope, table, secondary, primary);\
      }\
      int db_##IDX##_find_primary( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t primary ) {\
         return context.IDX.find_primary(code, scope, table, secondary, primary);\
      }\
      int db_##IDX##_lowerbound( uint64_t code, uint64_t scope, uint64_t table,  TYPE& secondary, uint64_t& primary ) {\
         EOS_ASSERT( !softfloat_api::is_nan( secondary ), transaction_exception, "NaN is not an allowed value for a secondary key" );\
         return context.IDX.lowerbound_secondary(code, scope, table, secondary, primary);\
      }\
      int db_##IDX##_upperbound( uint64_t code, uint64_t scope, uint64_t table,  TYPE& secondary, uint64_t& primary ) {\
         EOS_ASSERT( !softfloat_api::is_nan( secondary ), transaction_exception, "NaN is not an allowed value for a secondary key" );\
         return context.IDX.upperbound_secondary(code, scope, table, secondary, primary);\
      }\
      int db_##IDX##_end( uint64_t code, uint64_t scope, uint64_t table ) {\
         return context.IDX.end_secondary(code, scope, table);\
      }\
      int db_##IDX##_next( int iterator, uint64_t& primary  ) {\
         return context.IDX.next_secondary(iterator, primary);\
      }\
      int db_##IDX##_previous( int iterator, uint64_t& primary ) {\
         return context.IDX.previous_secondary(iterator, primary);\
      }
A
arhag 已提交
1163

D
Daniel Larimer 已提交
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
class database_api : public context_aware_api {
   public:
      using context_aware_api::context_aware_api;

      int db_store_i64( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, array_ptr<const char> buffer, size_t buffer_size ) {
         return context.db_store_i64( scope, table, payer, id, buffer, buffer_size );
      }
      void db_update_i64( int itr, uint64_t payer, array_ptr<const char> buffer, size_t buffer_size ) {
         context.db_update_i64( itr, payer, buffer, buffer_size );
      }
      void db_remove_i64( int itr ) {
         context.db_remove_i64( itr );
      }
1177 1178 1179
      int db_get_i64( int itr, array_ptr<char> buffer, size_t buffer_size ) {
         return context.db_get_i64( itr, buffer, buffer_size );
      }
1180 1181
      int db_next_i64( int itr, uint64_t& primary ) {
         return context.db_next_i64(itr, primary);
1182
      }
1183 1184
      int db_previous_i64( int itr, uint64_t& primary ) {
         return context.db_previous_i64(itr, primary);
D
Daniel Larimer 已提交
1185
      }
1186 1187
      int db_find_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) {
         return context.db_find_i64( code, scope, table, id );
D
Daniel Larimer 已提交
1188
      }
1189 1190
      int db_lowerbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) {
         return context.db_lowerbound_i64( code, scope, table, id );
D
Daniel Larimer 已提交
1191
      }
1192
      int db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) {
A
arhag 已提交
1193
         return context.db_upperbound_i64( code, scope, table, id );
D
Daniel Larimer 已提交
1194
      }
1195 1196 1197
      int db_end_i64( uint64_t code, uint64_t scope, uint64_t table ) {
         return context.db_end_i64( code, scope, table );
      }
1198

A
arhag 已提交
1199 1200
      DB_API_METHOD_WRAPPERS_SIMPLE_SECONDARY(idx64,  uint64_t)
      DB_API_METHOD_WRAPPERS_SIMPLE_SECONDARY(idx128, uint128_t)
A
arhag 已提交
1201
      DB_API_METHOD_WRAPPERS_ARRAY_SECONDARY(idx256, 2, uint128_t)
1202
      DB_API_METHOD_WRAPPERS_FLOAT_SECONDARY(idx_double, float64_t)
1203
      DB_API_METHOD_WRAPPERS_FLOAT_SECONDARY(idx_long_double, float128_t)
D
Daniel Larimer 已提交
1204 1205
};

1206
class memory_api : public context_aware_api {
1207
   public:
1208 1209
      memory_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
A
arhag 已提交
1210

1211 1212 1213 1214
      char* memcpy( array_ptr<char> dest, array_ptr<const char> src, size_t length) {
         return (char *)::memcpy(dest, src, length);
      }

1215 1216 1217 1218
      char* memmove( array_ptr<char> dest, array_ptr<const char> src, size_t length) {
         return (char *)::memmove(dest, src, length);
      }

1219 1220 1221 1222
      int memcmp( array_ptr<const char> dest, array_ptr<const char> src, size_t length) {
         return ::memcmp(dest, src, length);
      }

B
Bucky Kittinger 已提交
1223
      char* memset( array_ptr<char> dest, int value, size_t length ) {
B
Bucky Kittinger 已提交
1224
         return (char *)::memset( dest, value, length );
B
Bucky Kittinger 已提交
1225
      }
1226 1227
};

1228 1229 1230 1231
class transaction_api : public context_aware_api {
   public:
      using context_aware_api::context_aware_api;

D
Daniel Larimer 已提交
1232
      void send_inline( array_ptr<char> data, size_t data_len ) {
A
arhag 已提交
1233 1234 1235
         //TODO: Why is this limit even needed? And why is it not consistently checked on actions in input or deferred transactions
         FC_ASSERT( data_len < context.control.get_global_properties().configuration.max_inline_action_size,
                    "inline action too big" );
D
Daniel Larimer 已提交
1236 1237 1238 1239 1240 1241

         action act;
         fc::raw::unpack<action>(data, data_len, act);
         context.execute_inline(std::move(act));
      }

1242
      void send_context_free_inline( array_ptr<char> data, size_t data_len ) {
A
arhag 已提交
1243 1244 1245
         //TODO: Why is this limit even needed? And why is it not consistently checked on actions in input or deferred transactions
         FC_ASSERT( data_len < context.control.get_global_properties().configuration.max_inline_action_size,
                   "inline action too big" );
1246 1247 1248 1249 1250 1251

         action act;
         fc::raw::unpack<action>(data, data_len, act);
         context.execute_context_free_inline(std::move(act));
      }

1252
      void send_deferred( const uint128_t& sender_id, account_name payer, array_ptr<char> data, size_t data_len ) {
D
Daniel Larimer 已提交
1253
         try {
1254 1255 1256
            transaction trx;
            fc::raw::unpack<transaction>(data, data_len, trx);
            context.schedule_deferred_transaction(sender_id, payer, std::move(trx));
D
Daniel Larimer 已提交
1257 1258
         } FC_CAPTURE_AND_RETHROW((fc::to_hex(data, data_len)));
      }
A
Anton Perkov 已提交
1259

1260 1261
      void cancel_deferred( const unsigned __int128& val ) {
         fc::uint128_t sender_id(val>>64, uint64_t(val) );
1262
         context.cancel_deferred_transaction( (unsigned __int128)sender_id );
A
Anton Perkov 已提交
1263
      }
D
Daniel Larimer 已提交
1264 1265 1266 1267 1268
};


class context_free_transaction_api : public context_aware_api {
   public:
1269 1270
      context_free_transaction_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
D
Daniel Larimer 已提交
1271

1272
      int read_transaction( array_ptr<char> data, size_t buffer_size ) {
1273
         bytes trx = context.get_packed_transaction();
1274 1275 1276 1277 1278 1279 1280 1281

         auto s = trx.size();
         if( buffer_size == 0) return s;

         auto copy_size = std::min( buffer_size, s );
         memcpy( data, trx.data(), copy_size );

         return copy_size;
1282 1283 1284 1285
      }

      int transaction_size() {
         return context.get_packed_transaction().size();
1286 1287 1288
      }

      int expiration() {
1289
        return context.trx_context.trx.expiration.sec_since_epoch();
1290 1291 1292
      }

      int tapos_block_num() {
1293
        return context.trx_context.trx.ref_block_num;
1294
      }
1295
      int tapos_block_prefix() {
1296
        return context.trx_context.trx.ref_block_prefix;
1297 1298
      }

D
Daniel Larimer 已提交
1299 1300
      int get_action( uint32_t type, uint32_t index, array_ptr<char> buffer, size_t buffer_size )const {
         return context.get_action( type, index, buffer, buffer_size );
1301 1302 1303
      }
};

1304 1305
class compiler_builtins : public context_aware_api {
   public:
1306 1307 1308
      compiler_builtins( apply_context& ctx )
      :context_aware_api(ctx,true){}

1309
      void __ashlti3(__int128& ret, uint64_t low, uint64_t high, uint32_t shift) {
1310 1311 1312
         fc::uint128_t i(high, low);
         i <<= shift;
         ret = (unsigned __int128)i;
1313 1314
      }

1315
      void __ashrti3(__int128& ret, uint64_t low, uint64_t high, uint32_t shift) {
B
oops  
Bucky Kittinger 已提交
1316 1317 1318 1319 1320
         // retain the signedness
         ret = high;
         ret <<= 64;
         ret |= low;
         ret >>= shift;
1321
      }
1322

1323 1324 1325 1326 1327
      void __lshlti3(__int128& ret, uint64_t low, uint64_t high, uint32_t shift) {
         fc::uint128_t i(high, low);
         i <<= shift;
         ret = (unsigned __int128)i;
      }
1328

1329 1330 1331 1332 1333
      void __lshrti3(__int128& ret, uint64_t low, uint64_t high, uint32_t shift) {
         fc::uint128_t i(high, low);
         i >>= shift;
         ret = (unsigned __int128)i;
      }
A
arhag 已提交
1334

1335
      void __divti3(__int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) {
B
oops  
Bucky Kittinger 已提交
1336 1337
         __int128 lhs = ha;
         __int128 rhs = hb;
A
arhag 已提交
1338

B
oops  
Bucky Kittinger 已提交
1339 1340
         lhs <<= 64;
         lhs |=  la;
1341

B
oops  
Bucky Kittinger 已提交
1342 1343
         rhs <<= 64;
         rhs |=  lb;
1344

A
arhag 已提交
1345
         FC_ASSERT(rhs != 0, "divide by zero");
1346

A
arhag 已提交
1347
         lhs /= rhs;
1348

B
oops  
Bucky Kittinger 已提交
1349
         ret = lhs;
A
arhag 已提交
1350
      }
1351

B
oops  
Bucky Kittinger 已提交
1352 1353 1354
      void __udivti3(unsigned __int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) {
         unsigned __int128 lhs = ha;
         unsigned __int128 rhs = hb;
A
arhag 已提交
1355

B
oops  
Bucky Kittinger 已提交
1356 1357 1358 1359 1360
         lhs <<= 64;
         lhs |=  la;

         rhs <<= 64;
         rhs |=  lb;
1361

A
arhag 已提交
1362
         FC_ASSERT(rhs != 0, "divide by zero");
1363

A
arhag 已提交
1364
         lhs /= rhs;
B
oops  
Bucky Kittinger 已提交
1365 1366 1367 1368 1369 1370
         ret = lhs;
      }

      void __multi3(__int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) {
         __int128 lhs = ha;
         __int128 rhs = hb;
1371

B
oops  
Bucky Kittinger 已提交
1372 1373
         lhs <<= 64;
         lhs |=  la;
1374

B
oops  
Bucky Kittinger 已提交
1375 1376
         rhs <<= 64;
         rhs |=  lb;
1377

A
arhag 已提交
1378
         lhs *= rhs;
B
oops  
Bucky Kittinger 已提交
1379
         ret = lhs;
A
arhag 已提交
1380
      }
1381 1382

      void __modti3(__int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) {
B
oops  
Bucky Kittinger 已提交
1383 1384 1385 1386 1387
         __int128 lhs = ha;
         __int128 rhs = hb;

         lhs <<= 64;
         lhs |=  la;
A
arhag 已提交
1388

B
oops  
Bucky Kittinger 已提交
1389 1390
         rhs <<= 64;
         rhs |=  lb;
A
arhag 已提交
1391

B
oops  
Bucky Kittinger 已提交
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403
         FC_ASSERT(rhs != 0, "divide by zero");

         lhs %= rhs;
         ret = lhs;
      }

      void __umodti3(unsigned __int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) {
         unsigned __int128 lhs = ha;
         unsigned __int128 rhs = hb;

         lhs <<= 64;
         lhs |=  la;
A
arhag 已提交
1404

B
oops  
Bucky Kittinger 已提交
1405 1406
         rhs <<= 64;
         rhs |=  lb;
A
arhag 已提交
1407

B
oops  
Bucky Kittinger 已提交
1408
         FC_ASSERT(rhs != 0, "divide by zero");
1409

B
oops  
Bucky Kittinger 已提交
1410 1411
         lhs %= rhs;
         ret = lhs;
1412
      }
1413

1414
      // arithmetic long double
1415
      void __addtf3( float128_t& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1416 1417
         float128_t a = {{ la, ha }};
         float128_t b = {{ lb, hb }};
1418
         ret = f128_add( a, b );
1419
      }
1420
      void __subtf3( float128_t& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1421 1422
         float128_t a = {{ la, ha }};
         float128_t b = {{ lb, hb }};
1423
         ret = f128_sub( a, b );
1424
      }
1425
      void __multf3( float128_t& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1426 1427
         float128_t a = {{ la, ha }};
         float128_t b = {{ lb, hb }};
1428
         ret = f128_mul( a, b );
1429
      }
1430
      void __divtf3( float128_t& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1431 1432
         float128_t a = {{ la, ha }};
         float128_t b = {{ lb, hb }};
1433
         ret = f128_div( a, b );
1434
      }
1435
      void __negtf2( float128_t& ret, uint64_t la, uint64_t ha ) {
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
         ret = {{ la, (ha ^ (uint64_t)1 << 63) }};
      }

      // conversion long double
      void __extendsftf2( float128_t& ret, float f ) {
         ret = f32_to_f128( softfloat_api::to_softfloat32(f) );
      }
      void __extenddftf2( float128_t& ret, double d ) {
         ret = f64_to_f128( softfloat_api::to_softfloat64(d) );
      }
      double __trunctfdf2( uint64_t l, uint64_t h ) {
         float128_t f = {{ l, h }};
         return softfloat_api::from_softfloat64(f128_to_f64( f ));
      }
      float __trunctfsf2( uint64_t l, uint64_t h ) {
         float128_t f = {{ l, h }};
         return softfloat_api::from_softfloat32(f128_to_f32( f ));
      }
      int32_t __fixtfsi( uint64_t l, uint64_t h ) {
         float128_t f = {{ l, h }};
         return f128_to_i32( f, 0, false );
      }
      int64_t __fixtfdi( uint64_t l, uint64_t h ) {
         float128_t f = {{ l, h }};
         return f128_to_i64( f, 0, false );
      }
      void __fixtfti( __int128& ret, uint64_t l, uint64_t h ) {
         float128_t f = {{ l, h }};
         ret = ___fixtfti( f );
      }
      uint32_t __fixunstfsi( uint64_t l, uint64_t h ) {
         float128_t f = {{ l, h }};
         return f128_to_ui32( f, 0, false );
      }
      uint64_t __fixunstfdi( uint64_t l, uint64_t h ) {
         float128_t f = {{ l, h }};
         return f128_to_ui64( f, 0, false );
      }
      void __fixunstfti( unsigned __int128& ret, uint64_t l, uint64_t h ) {
         float128_t f = {{ l, h }};
         ret = ___fixunstfti( f );
      }
      void __fixsfti( __int128& ret, float a ) {
         ret = ___fixsfti( softfloat_api::to_softfloat32(a).v );
      }
      void __fixdfti( __int128& ret, double a ) {
         ret = ___fixdfti( softfloat_api::to_softfloat64(a).v );
      }
      void __fixunssfti( unsigned __int128& ret, float a ) {
         ret = ___fixunssfti( softfloat_api::to_softfloat32(a).v );
      }
      void __fixunsdfti( unsigned __int128& ret, double a ) {
         ret = ___fixunsdfti( softfloat_api::to_softfloat64(a).v );
      }
      double __floatsidf( int32_t i ) {
         return softfloat_api::from_softfloat64(i32_to_f64(i));
      }
      void __floatsitf( float128_t& ret, int32_t i ) {
1494
         ret = i32_to_f128(i);
1495 1496 1497 1498 1499
      }
      void __floatditf( float128_t& ret, uint64_t a ) {
         ret = i64_to_f128( a );
      }
      void __floatunsitf( float128_t& ret, uint32_t i ) {
1500
         ret = ui32_to_f128(i);
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
      }
      void __floatunditf( float128_t& ret, uint64_t a ) {
         ret = ui64_to_f128( a );
      }
      double __floattidf( uint64_t l, uint64_t h ) {
         fc::uint128_t v(h, l);
         unsigned __int128 val = (unsigned __int128)v;
         return ___floattidf( *(__int128*)&val );
      }
      double __floatuntidf( uint64_t l, uint64_t h ) {
         fc::uint128_t v(h, l);
         return ___floatuntidf( (unsigned __int128)v );
1513
      }
1514
      int ___cmptf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb, int return_value_if_nan ) {
1515
         float128_t a = {{ la, ha }};
1516
         float128_t b = {{ lb, hb }};
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526
         if ( __unordtf2(la, ha, lb, hb) )
            return return_value_if_nan;
         if ( f128_lt( a, b ) )
            return -1;
         if ( f128_eq( a, b ) )
            return 0;
         return 1;
      }
      int __eqtf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
         return ___cmptf2(la, ha, lb, hb, 1);
1527
      }
1528
      int __netf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1529
         return ___cmptf2(la, ha, lb, hb, 1);
1530
      }
1531
      int __getf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1532
         return ___cmptf2(la, ha, lb, hb, -1);
1533
      }
1534
      int __gttf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1535
         return ___cmptf2(la, ha, lb, hb, 0);
1536
      }
1537
      int __letf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1538
         return ___cmptf2(la, ha, lb, hb, 1);
1539
      }
1540
      int __lttf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1541
         return ___cmptf2(la, ha, lb, hb, 0);
1542
      }
1543
      int __cmptf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1544
         return ___cmptf2(la, ha, lb, hb, 1);
1545
      }
1546
      int __unordtf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1547
         float128_t a = {{ la, ha }};
1548
         float128_t b = {{ lb, hb }};
1549
         if ( softfloat_api::is_nan(a) || softfloat_api::is_nan(b) )
1550 1551 1552
            return 1;
         return 0;
      }
1553

B
Bucky Kittinger 已提交
1554
      static constexpr uint32_t SHIFT_WIDTH = (sizeof(uint64_t)*8)-1;
1555 1556
};

1557

1558 1559 1560
/*
 * This api will be removed with fix for `eos #2561`
 */
B
Bucky Kittinger 已提交
1561 1562 1563 1564
class call_depth_api : public context_aware_api {
   public:
      call_depth_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
1565
      void call_depth_assert() {
1566 1567
         FC_THROW_EXCEPTION(wasm_execution_error, "Exceeded call depth maximum");
      }
B
Bucky Kittinger 已提交
1568 1569 1570
};

REGISTER_INJECTED_INTRINSICS(call_depth_api,
B
Bucky Kittinger 已提交
1571
   (call_depth_assert,  void()               )
B
Bucky Kittinger 已提交
1572 1573
);

1574
REGISTER_INTRINSICS(compiler_builtins,
B
Bucky Kittinger 已提交
1575 1576 1577 1578 1579 1580 1581 1582 1583
   (__ashlti3,     void(int, int64_t, int64_t, int)               )
   (__ashrti3,     void(int, int64_t, int64_t, int)               )
   (__lshlti3,     void(int, int64_t, int64_t, int)               )
   (__lshrti3,     void(int, int64_t, int64_t, int)               )
   (__divti3,      void(int, int64_t, int64_t, int64_t, int64_t)  )
   (__udivti3,     void(int, int64_t, int64_t, int64_t, int64_t)  )
   (__modti3,      void(int, int64_t, int64_t, int64_t, int64_t)  )
   (__umodti3,     void(int, int64_t, int64_t, int64_t, int64_t)  )
   (__multi3,      void(int, int64_t, int64_t, int64_t, int64_t)  )
1584 1585 1586 1587 1588 1589 1590 1591 1592
   (__addtf3,      void(int, int64_t, int64_t, int64_t, int64_t)  )
   (__subtf3,      void(int, int64_t, int64_t, int64_t, int64_t)  )
   (__multf3,      void(int, int64_t, int64_t, int64_t, int64_t)  )
   (__divtf3,      void(int, int64_t, int64_t, int64_t, int64_t)  )
   (__eqtf2,       int(int64_t, int64_t, int64_t, int64_t)        )
   (__netf2,       int(int64_t, int64_t, int64_t, int64_t)        )
   (__getf2,       int(int64_t, int64_t, int64_t, int64_t)        )
   (__gttf2,       int(int64_t, int64_t, int64_t, int64_t)        )
   (__lttf2,       int(int64_t, int64_t, int64_t, int64_t)        )
1593
   (__letf2,       int(int64_t, int64_t, int64_t, int64_t)        )
1594 1595
   (__cmptf2,      int(int64_t, int64_t, int64_t, int64_t)        )
   (__unordtf2,    int(int64_t, int64_t, int64_t, int64_t)        )
1596
   (__negtf2,      void (int, int64_t, int64_t)                   )
D
Daniel Larimer 已提交
1597 1598
   (__floatsitf,   void (int, int)                                )
   (__floatunsitf, void (int, int)                                )
1599 1600
   (__floatditf,   void (int, int64_t)                            )
   (__floatunditf, void (int, int64_t)                            )
B
Bucky Kittinger 已提交
1601 1602
   (__floattidf,   double (int64_t, int64_t)                      )
   (__floatuntidf, double (int64_t, int64_t)                      )
1603
   (__floatsidf,   double(int)                                    )
1604
   (__extendsftf2, void(int, float)                               )
1605
   (__extenddftf2, void(int, double)                              )
1606
   (__fixtfti,     void(int, int64_t, int64_t)                    )
1607 1608
   (__fixtfdi,     int64_t(int64_t, int64_t)                      )
   (__fixtfsi,     int(int64_t, int64_t)                          )
1609
   (__fixunstfti,  void(int, int64_t, int64_t)                    )
1610 1611
   (__fixunstfdi,  int64_t(int64_t, int64_t)                      )
   (__fixunstfsi,  int(int64_t, int64_t)                          )
1612 1613
   (__fixsfti,     void(int, float)                               )
   (__fixdfti,     void(int, double)                              )
1614 1615 1616 1617
   (__fixunssfti,  void(int, float)                               )
   (__fixunsdfti,  void(int, double)                              )
   (__trunctfdf2,  double(int64_t, int64_t)                       )
   (__trunctfsf2,  float(int64_t, int64_t)                        )
B
Bucky Kittinger 已提交
1618
);
1619 1620

REGISTER_INTRINSICS(privileged_api,
1621 1622 1623 1624
   (is_feature_active,                int(int64_t)                          )
   (activate_feature,                 void(int64_t)                         )
   (get_resource_limits,              void(int64_t,int,int,int)             )
   (set_resource_limits,              void(int64_t,int64_t,int64_t,int64_t) )
1625
   (set_active_producers,             int(int,int)                          )
1626 1627 1628 1629
   (get_blockchain_parameters_packed, int(int, int)                         )
   (set_blockchain_parameters_packed, void(int,int)                         )
   (is_privileged,                    int(int64_t)                          )
   (set_privileged,                   void(int64_t, int)                    )
1630
);
1631

1632
REGISTER_INJECTED_INTRINSICS(apply_context,
1633
   (checktime,      void(int))
1634 1635
);

1636
REGISTER_INTRINSICS(producer_api,
B
Bucky Kittinger 已提交
1637
   (get_active_producers,      int(int, int) )
1638 1639
);

A
arhag 已提交
1640
#define DB_SECONDARY_INDEX_METHODS_SIMPLE(IDX) \
1641 1642 1643 1644 1645 1646 1647
   (db_##IDX##_store,          int(int64_t,int64_t,int64_t,int64_t,int))\
   (db_##IDX##_remove,         void(int))\
   (db_##IDX##_update,         void(int,int64_t,int))\
   (db_##IDX##_find_primary,   int(int64_t,int64_t,int64_t,int,int64_t))\
   (db_##IDX##_find_secondary, int(int64_t,int64_t,int64_t,int,int))\
   (db_##IDX##_lowerbound,     int(int64_t,int64_t,int64_t,int,int))\
   (db_##IDX##_upperbound,     int(int64_t,int64_t,int64_t,int,int))\
1648
   (db_##IDX##_end,            int(int64_t,int64_t,int64_t))\
1649 1650 1651
   (db_##IDX##_next,           int(int, int))\
   (db_##IDX##_previous,       int(int, int))

A
arhag 已提交
1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663
#define DB_SECONDARY_INDEX_METHODS_ARRAY(IDX) \
      (db_##IDX##_store,          int(int64_t,int64_t,int64_t,int64_t,int,int))\
      (db_##IDX##_remove,         void(int))\
      (db_##IDX##_update,         void(int,int64_t,int,int))\
      (db_##IDX##_find_primary,   int(int64_t,int64_t,int64_t,int,int,int64_t))\
      (db_##IDX##_find_secondary, int(int64_t,int64_t,int64_t,int,int,int))\
      (db_##IDX##_lowerbound,     int(int64_t,int64_t,int64_t,int,int,int))\
      (db_##IDX##_upperbound,     int(int64_t,int64_t,int64_t,int,int,int))\
      (db_##IDX##_end,            int(int64_t,int64_t,int64_t))\
      (db_##IDX##_next,           int(int, int))\
      (db_##IDX##_previous,       int(int, int))

D
Daniel Larimer 已提交
1664 1665 1666 1667
REGISTER_INTRINSICS( database_api,
   (db_store_i64,        int(int64_t,int64_t,int64_t,int64_t,int,int))
   (db_update_i64,       void(int,int64_t,int,int))
   (db_remove_i64,       void(int))
1668
   (db_get_i64,          int(int, int, int))
1669 1670
   (db_next_i64,         int(int, int))
   (db_previous_i64,     int(int, int))
D
Daniel Larimer 已提交
1671 1672
   (db_find_i64,         int(int64_t,int64_t,int64_t,int64_t))
   (db_lowerbound_i64,   int(int64_t,int64_t,int64_t,int64_t))
1673
   (db_upperbound_i64,   int(int64_t,int64_t,int64_t,int64_t))
A
arhag 已提交
1674
   (db_end_i64,          int(int64_t,int64_t,int64_t))
1675

A
arhag 已提交
1676 1677 1678
   DB_SECONDARY_INDEX_METHODS_SIMPLE(idx64)
   DB_SECONDARY_INDEX_METHODS_SIMPLE(idx128)
   DB_SECONDARY_INDEX_METHODS_ARRAY(idx256)
A
arhag 已提交
1679
   DB_SECONDARY_INDEX_METHODS_SIMPLE(idx_double)
1680
   DB_SECONDARY_INDEX_METHODS_SIMPLE(idx_long_double)
1681
);
D
Daniel Larimer 已提交
1682

1683
REGISTER_INTRINSICS(crypto_api,
B
Bucky Kittinger 已提交
1684 1685
   (assert_recover_key,     void(int, int, int, int, int) )
   (recover_key,            int(int, int, int, int, int)  )
B
Bucky Kittinger 已提交
1686 1687 1688 1689
   (assert_sha256,          void(int, int, int)           )
   (assert_sha1,            void(int, int, int)           )
   (assert_sha512,          void(int, int, int)           )
   (assert_ripemd160,       void(int, int, int)           )
B
Bucky Kittinger 已提交
1690 1691 1692 1693
   (sha1,                   void(int, int, int)           )
   (sha256,                 void(int, int, int)           )
   (sha512,                 void(int, int, int)           )
   (ripemd160,              void(int, int, int)           )
1694 1695
);

A
arhag 已提交
1696

M
Matias Romeo 已提交
1697
REGISTER_INTRINSICS(permission_api,
1698 1699
   (check_transaction_authorization, int(int, int, int, int, int, int)                  )
   (check_permission_authorization,  int(int64_t, int64_t, int, int, int, int, int64_t) )
1700 1701
   (get_permission_last_used,        int64_t(int64_t, int64_t) )
   (get_account_creation_date,       int64_t(int64_t) )
M
Matias Romeo 已提交
1702 1703
);

A
arhag 已提交
1704

B
Bart Wyatt 已提交
1705
REGISTER_INTRINSICS(system_api,
1706 1707 1708 1709 1710
   (current_time, int64_t()       )
   (publication_time,   int64_t() )
);

REGISTER_INTRINSICS(context_free_system_api,
1711 1712 1713
   (abort,        void()         )
   (eosio_assert, void(int, int) )
   (eosio_exit,   void(int)      )
B
Bart Wyatt 已提交
1714 1715 1716
);

REGISTER_INTRINSICS(action_api,
1717 1718
   (read_action_data,       int(int, int)  )
   (action_data_size,       int()          )
1719
   (current_receiver,   int64_t()          )
B
Bart Wyatt 已提交
1720 1721
);

1722
REGISTER_INTRINSICS(authorization_api,
B
Bucky Kittinger 已提交
1723
   (require_recipient,     void(int64_t)          )
1724 1725 1726
   (require_authorization, void(int64_t), "require_auth", void(authorization_api::*)(const account_name&) )
   (require_authorization, void(int64_t, int64_t), "require_auth2", void(authorization_api::*)(const account_name&, const permission_name& permission) )
   (has_authorization,     int(int64_t), "has_auth", bool(authorization_api::*)(const account_name&)const )
B
Bucky Kittinger 已提交
1727
   (is_account,            int(int64_t)           )
B
Bart Wyatt 已提交
1728 1729 1730
);

REGISTER_INTRINSICS(console_api,
1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741
   (prints,                void(int)      )
   (prints_l,              void(int, int) )
   (printi,                void(int64_t)  )
   (printui,               void(int64_t)  )
   (printi128,             void(int)      )
   (printui128,            void(int)      )
   (printsf,               void(float)    )
   (printdf,               void(double)   )
   (printqf,               void(int)      )
   (printn,                void(int64_t)  )
   (printhex,              void(int, int) )
B
Bart Wyatt 已提交
1742 1743
);

D
Daniel Larimer 已提交
1744
REGISTER_INTRINSICS(context_free_transaction_api,
1745 1746 1747 1748 1749
   (read_transaction,       int(int, int)            )
   (transaction_size,       int()                    )
   (expiration,             int()                    )
   (tapos_block_prefix,     int()                    )
   (tapos_block_num,        int()                    )
1750
   (get_action,             int (int, int, int, int) )
D
Daniel Larimer 已提交
1751 1752 1753
);

REGISTER_INTRINSICS(transaction_api,
1754 1755 1756 1757
   (send_inline,               void(int, int)               )
   (send_context_free_inline,  void(int, int)               )
   (send_deferred,             void(int, int64_t, int, int) )
   (cancel_deferred,           void(int)                    )
1758 1759
);

D
Daniel Larimer 已提交
1760 1761 1762 1763
REGISTER_INTRINSICS(context_free_api,
   (get_context_free_data, int(int, int, int) )
)

1764
REGISTER_INTRINSICS(memory_api,
B
Bucky Kittinger 已提交
1765 1766 1767 1768
   (memcpy,                 int(int, int, int)  )
   (memmove,                int(int, int, int)  )
   (memcmp,                 int(int, int, int)  )
   (memset,                 int(int, int, int)  )
1769 1770
);

1771
REGISTER_INJECTED_INTRINSICS(softfloat_api,
B
Bucky Kittinger 已提交
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791
      (_eosio_f32_add,       float(float, float)    )
      (_eosio_f32_sub,       float(float, float)    )
      (_eosio_f32_mul,       float(float, float)    )
      (_eosio_f32_div,       float(float, float)    )
      (_eosio_f32_min,       float(float, float)    )
      (_eosio_f32_max,       float(float, float)    )
      (_eosio_f32_copysign,  float(float, float)    )
      (_eosio_f32_abs,       float(float)           )
      (_eosio_f32_neg,       float(float)           )
      (_eosio_f32_sqrt,      float(float)           )
      (_eosio_f32_ceil,      float(float)           )
      (_eosio_f32_floor,     float(float)           )
      (_eosio_f32_trunc,     float(float)           )
      (_eosio_f32_nearest,   float(float)           )
      (_eosio_f32_eq,        int(float, float)      )
      (_eosio_f32_ne,        int(float, float)      )
      (_eosio_f32_lt,        int(float, float)      )
      (_eosio_f32_le,        int(float, float)      )
      (_eosio_f32_gt,        int(float, float)      )
      (_eosio_f32_ge,        int(float, float)      )
1792 1793 1794 1795 1796 1797 1798
      (_eosio_f64_add,       double(double, double) )
      (_eosio_f64_sub,       double(double, double) )
      (_eosio_f64_mul,       double(double, double) )
      (_eosio_f64_div,       double(double, double) )
      (_eosio_f64_min,       double(double, double) )
      (_eosio_f64_max,       double(double, double) )
      (_eosio_f64_copysign,  double(double, double) )
B
Bucky Kittinger 已提交
1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
      (_eosio_f64_abs,       double(double)         )
      (_eosio_f64_neg,       double(double)         )
      (_eosio_f64_sqrt,      double(double)         )
      (_eosio_f64_ceil,      double(double)         )
      (_eosio_f64_floor,     double(double)         )
      (_eosio_f64_trunc,     double(double)         )
      (_eosio_f64_nearest,   double(double)         )
      (_eosio_f64_eq,        int(double, double)    )
      (_eosio_f64_ne,        int(double, double)    )
      (_eosio_f64_lt,        int(double, double)    )
      (_eosio_f64_le,        int(double, double)    )
      (_eosio_f64_gt,        int(double, double)    )
      (_eosio_f64_ge,        int(double, double)    )
      (_eosio_f32_promote,    double(float)         )
      (_eosio_f64_demote,     float(double)         )
      (_eosio_f32_trunc_i32s, int(float)            )
      (_eosio_f64_trunc_i32s, int(double)           )
      (_eosio_f32_trunc_i32u, int(float)            )
      (_eosio_f64_trunc_i32u, int(double)           )
      (_eosio_f32_trunc_i64s, int64_t(float)        )
      (_eosio_f64_trunc_i64s, int64_t(double)       )
      (_eosio_f32_trunc_i64u, int64_t(float)        )
      (_eosio_f64_trunc_i64u, int64_t(double)       )
      (_eosio_i32_to_f32,     float(int32_t)        )
      (_eosio_i64_to_f32,     float(int64_t)        )
      (_eosio_ui32_to_f32,    float(int32_t)        )
      (_eosio_ui64_to_f32,    float(int64_t)        )
      (_eosio_i32_to_f64,     double(int32_t)       )
      (_eosio_i64_to_f64,     double(int64_t)       )
      (_eosio_ui32_to_f64,    double(int32_t)       )
      (_eosio_ui64_to_f64,    double(int64_t)       )
1830
);
B
Bucky Kittinger 已提交
1831

1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842
std::istream& operator>>(std::istream& in, wasm_interface::vm_type& runtime) {
   std::string s;
   in >> s;
   if (s == "wavm")
      runtime = eosio::chain::wasm_interface::vm_type::wavm;
   else if (s == "binaryen")
      runtime = eosio::chain::wasm_interface::vm_type::binaryen;
   else
      in.setstate(std::ios_base::failbit);
   return in;
}
B
Brian Johnson 已提交
1843

D
Daniel Larimer 已提交
1844
} } /// eosio::chain