wasm_interface.cpp 72.8 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 23
#include <boost/asio.hpp>
#include <boost/bind.hpp>
24
#include <fstream>
25

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

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

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

34 35
   void wasm_interface::validate(const bytes& code) {
      Module module;
36 37 38 39 40 41
      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 已提交
42

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

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

49 50 51
      //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
52
	   }
53

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

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

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

B
Bart Wyatt 已提交
65
class context_aware_api {
66
   public:
67 68
      context_aware_api(apply_context& ctx, bool context_free = false )
      :context(ctx)
D
Daniel Larimer 已提交
69 70 71 72 73
      {
         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;
      }
74

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

B
Bart Wyatt 已提交
78
};
79

D
Daniel Larimer 已提交
80 81
class context_free_api : public context_aware_api {
   public:
82 83
      context_free_api( apply_context& ctx )
      :context_aware_api(ctx, true) {
D
Daniel Larimer 已提交
84 85 86 87 88 89 90 91
         /* 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 );
      }
};
92

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

101 102 103 104 105 106 107 108 109 110
      /**
       * 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 已提交
111 112 113 114 115
      /**
       *  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.
       *
116
       *  Feature name should be base32 encoded name.
D
Daniel Larimer 已提交
117
       */
118
      void activate_feature( int64_t feature_name ) {
B
Bucky Kittinger 已提交
119
         FC_ASSERT( !"Unsupported Hardfork Detected" );
D
Daniel Larimer 已提交
120
      }
121

B
Bart Wyatt 已提交
122 123 124 125 126 127 128 129 130
      /**
       * 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
       */
131
      void set_resource_limits( account_name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight) {
132 133 134
         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]");
135 136 137
         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 已提交
138
      }
139

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

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

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

         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 );
167
            fc::raw::pack(ds, gpo.configuration);
168
            return s;
169
         }
170
         return 0;
171 172
      }

173 174 175 176
      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 已提交
177
         context.db.modify( context.control.get_global_properties(),
178 179 180 181 182
            [&]( auto& gprops ) {
                 gprops.configuration = cfg;
         });
      }

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

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

D
Daniel Larimer 已提交
194
};
B
Brian Johnson 已提交
195

196
/*
197 198
class checktime_api : public context_aware_api {
public:
199 200
   explicit checktime_api( apply_context& ctx )
   :context_aware_api(ctx,true){}
201

202 203
   void checktime(uint32_t instruction_count) {
      context.checktime(instruction_count);
B
Brian Johnson 已提交
204
   }
205
};
206
*/
207

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

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

357
      // float relops
358
      bool _eosio_f32_eq( float a, float b ) {  return f32_eq( to_softfloat32(a), to_softfloat32(b) ); }
359 360 361
      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) ); }
362
      bool _eosio_f32_gt( float af, float bf ) {
363 364 365 366 367 368
         float32_t a = to_softfloat32(af);
         float32_t b = to_softfloat32(bf);
         if (is_nan(a))
            return false;
         if (is_nan(b))
            return false;
369
         return !f32_le( a, b );
370 371 372 373 374 375 376 377
      }
      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;
378
         return !f32_lt( a, b );
379
      }
380 381

      // double binops
382 383 384
      double _eosio_f64_add( double a, double b ) {
         float64_t ret = f64_add( to_softfloat64(a), to_softfloat64(b) );
         return from_softfloat64(ret);
385
      }
386 387 388
      double _eosio_f64_sub( double a, double b ) {
         float64_t ret = f64_sub( to_softfloat64(a), to_softfloat64(b) );
         return from_softfloat64(ret);
389
      }
390 391 392
      double _eosio_f64_div( double a, double b ) {
         float64_t ret = f64_div( to_softfloat64(a), to_softfloat64(b) );
         return from_softfloat64(ret);
393
      }
394 395 396
      double _eosio_f64_mul( double a, double b ) {
         float64_t ret = f64_mul( to_softfloat64(a), to_softfloat64(b) );
         return from_softfloat64(ret);
397
      }
398
      double _eosio_f64_min( double af, double bf ) {
399 400 401 402 403 404 405 406 407
         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;
408 409
      }
      double _eosio_f64_max( double af, double bf ) {
410 411 412 413 414 415 416 417 418
         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;
419 420 421 422
      }
      double _eosio_f64_copysign( double af, double bf ) {
         float64_t a = to_softfloat64(af);
         float64_t b = to_softfloat64(bf);
423 424 425 426
         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
427
         return from_softfloat64(a);
428 429 430
      }

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

512
      double _eosio_f64_nearest( double af ) {
513
         float64_t a = to_softfloat64( af );
514 515 516 517
         int e = (a.v >> 52 & 0x7FF);
         int s = a.v >> 63;
         float64_t y;
         if ( e >= 0x3FF+52 )
518
            return af;
519
         if ( s )
B
Bucky Kittinger 已提交
520
            y = f64_add( f64_sub( a, float64_t{inv_double_eps} ), float64_t{inv_double_eps} );
521
         else
B
Bucky Kittinger 已提交
522
            y = f64_sub( f64_add( a, float64_t{inv_double_eps} ), float64_t{inv_double_eps} );
523
         if ( f64_eq( y, float64_t{0} ) )
524
            return s ? -0.0 : 0.0;
525
         return from_softfloat64(y);
526 527 528
      }

      // double relops
529 530 531 532
      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) ); }
533
      bool _eosio_f64_gt( double af, double bf ) {
534 535 536 537 538 539
         float64_t a = to_softfloat64(af);
         float64_t b = to_softfloat64(bf);
         if (is_nan(a))
            return false;
         if (is_nan(b))
            return false;
540
         return !f64_le( a, b );
541 542 543 544 545 546 547 548
      }
      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;
549
         return !f64_lt( a, b );
550 551 552
      }

      // float and double conversions
553 554
      double _eosio_f32_promote( float a ) {
         return from_softfloat64(f32_to_f64( to_softfloat32(a)) );
B
Bucky Kittinger 已提交
555
      }
556 557
      float _eosio_f64_demote( double a ) {
         return from_softfloat32(f64_to_f32( to_softfloat64(a)) );
B
Bucky Kittinger 已提交
558
      }
559
      int32_t _eosio_f32_trunc_i32s( float af ) {
B
Bucky Kittinger 已提交
560
         float32_t a = to_softfloat32(af);
561
         if (_eosio_f32_ge(af, 2147483648.0f) || _eosio_f32_lt(af, -2147483648.0f))
562 563
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_s/i32 overflow" );

B
Bucky Kittinger 已提交
564 565
         if (is_nan(a))
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_s/i32 unrepresentable");
566
         return f32_to_i32( to_softfloat32(_eosio_f32_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
567
      }
568
      int32_t _eosio_f64_trunc_i32s( double af ) {
B
Bucky Kittinger 已提交
569
         float64_t a = to_softfloat64(af);
570
         if (_eosio_f64_ge(af, 2147483648.0) || _eosio_f64_lt(af, -2147483648.0))
B
Bucky Kittinger 已提交
571 572 573
            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");
574
         return f64_to_i32( to_softfloat64(_eosio_f64_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
575
      }
576
      uint32_t _eosio_f32_trunc_i32u( float af ) {
B
Bucky Kittinger 已提交
577
         float32_t a = to_softfloat32(af);
578 579
         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 已提交
580
         if (is_nan(a))
581
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_u/i32 unrepresentable");
582
         return f32_to_ui32( to_softfloat32(_eosio_f32_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
583
      }
584
      uint32_t _eosio_f64_trunc_i32u( double af ) {
B
Bucky Kittinger 已提交
585
         float64_t a = to_softfloat64(af);
586 587
         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 已提交
588
         if (is_nan(a))
589
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_u/i32 unrepresentable");
590
         return f64_to_ui32( to_softfloat64(_eosio_f64_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
591
      }
592
      int64_t _eosio_f32_trunc_i64s( float af ) {
B
Bucky Kittinger 已提交
593
         float32_t a = to_softfloat32(af);
594
         if (_eosio_f32_ge(af, 9223372036854775808.0f) || _eosio_f32_lt(af, -9223372036854775808.0f))
595
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_s/i64 overflow");
B
Bucky Kittinger 已提交
596
         if (is_nan(a))
597
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_s/i64 unrepresentable");
598
         return f32_to_i64( to_softfloat32(_eosio_f32_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
599
      }
600
      int64_t _eosio_f64_trunc_i64s( double af ) {
B
Bucky Kittinger 已提交
601
         float64_t a = to_softfloat64(af);
602
         if (_eosio_f64_ge(af, 9223372036854775808.0) || _eosio_f64_lt(af, -9223372036854775808.0))
603
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_s/i64 overflow");
B
Bucky Kittinger 已提交
604
         if (is_nan(a))
605
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_s/i64 unrepresentable");
606 607

         return f64_to_i64( to_softfloat64(_eosio_f64_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
608
      }
609
      uint64_t _eosio_f32_trunc_i64u( float af ) {
B
Bucky Kittinger 已提交
610
         float32_t a = to_softfloat32(af);
611 612
         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 已提交
613
         if (is_nan(a))
614
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f32.convert_u/i64 unrepresentable");
615
         return f32_to_ui64( to_softfloat32(_eosio_f32_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
616
      }
617
      uint64_t _eosio_f64_trunc_i64u( double af ) {
B
Bucky Kittinger 已提交
618
         float64_t a = to_softfloat64(af);
619 620
         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 已提交
621
         if (is_nan(a))
622
            FC_THROW_EXCEPTION( eosio::chain::wasm_execution_error, "Error, f64.convert_u/i64 unrepresentable");
623
         return f64_to_ui64( to_softfloat64(_eosio_f64_trunc( af )), 0, false );
B
Bucky Kittinger 已提交
624
      }
625 626
      float _eosio_i32_to_f32( int32_t a )  {
         return from_softfloat32(i32_to_f32( a ));
B
Bucky Kittinger 已提交
627
      }
628 629
      float _eosio_i64_to_f32( int64_t a ) {
         return from_softfloat32(i64_to_f32( a ));
B
Bucky Kittinger 已提交
630
      }
631 632
      float _eosio_ui32_to_f32( uint32_t a ) {
         return from_softfloat32(ui32_to_f32( a ));
B
Bucky Kittinger 已提交
633
      }
634 635
      float _eosio_ui64_to_f32( uint64_t a ) {
         return from_softfloat32(ui64_to_f32( a ));
B
Bucky Kittinger 已提交
636
      }
637 638
      double _eosio_i32_to_f64( int32_t a ) {
         return from_softfloat64(i32_to_f64( a ));
B
Bucky Kittinger 已提交
639
      }
640 641
      double _eosio_i64_to_f64( int64_t a ) {
         return from_softfloat64(i64_to_f64( a ));
B
Bucky Kittinger 已提交
642
      }
643 644
      double _eosio_ui32_to_f64( uint32_t a ) {
         return from_softfloat64(ui32_to_f64( a ));
B
Bucky Kittinger 已提交
645 646
      }
      double _eosio_ui64_to_f64( uint64_t a ) {
647
         return from_softfloat64(ui64_to_f64( a ));
B
Bucky Kittinger 已提交
648
      }
649

650 651 652 653 654 655 656
      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 ) {
657
         return (((~(f.v[1]) & uint64_t( 0x7FFF000000000000 )) == 0) && (f.v[0] || ((f.v[1]) & uint64_t( 0x0000FFFFFFFFFFFF ))));
658 659
      }
      static float32_t to_softfloat32( float f ) {
660 661
         return *reinterpret_cast<float32_t*>(&f);
      }
662
      static float64_t to_softfloat64( double d ) {
663
         return *reinterpret_cast<float64_t*>(&d);
664
      }
665
      static float from_softfloat32( float32_t f ) {
666 667
         return *reinterpret_cast<float*>(&f);
      }
668
      static double from_softfloat64( float64_t d ) {
669
         return *reinterpret_cast<double*>(&d);
670
      }
671
      static constexpr uint32_t inv_float_eps = 0x4B000000;
B
Bucky Kittinger 已提交
672
      static constexpr uint64_t inv_double_eps = 0x4330000000000000;
673

B
Bucky Kittinger 已提交
674 675
      static bool sign_bit( float32_t f ) { return f.v >> 31; }
      static bool sign_bit( float64_t f ) { return f.v >> 63; }
676

677
};
678 679 680
class producer_api : public context_aware_api {
   public:
      using context_aware_api::context_aware_api;
681

682
      int get_active_producers(array_ptr<chain::account_name> producers, size_t buffer_size) {
683
         auto active_producers = context.get_active_producers();
684

685
         size_t len = active_producers.size();
686 687 688 689 690 691 692
         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;
693 694 695 696
      }
};

class crypto_api : public context_aware_api {
697
   public:
698 699
      explicit crypto_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
700 701
      /**
       * This method can be optimized out during replay as it has
702
       * no possible side effects other than "passing".
703
       */
K
Kevin Heifner 已提交
704
      void assert_recover_key( const fc::sha256& digest,
705 706 707 708 709 710 711 712
                        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 已提交
713
         fc::raw::unpack(pubds, p);
714 715 716 717 718

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

K
Kevin Heifner 已提交
719
      int recover_key( const fc::sha256& digest,
720 721 722 723 724 725 726 727 728 729 730
                        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();
      }

731 732 733 734 735
      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 已提交
736
      void assert_sha1(array_ptr<char> data, size_t datalen, const fc::sha1& hash_val) {
B
Bucky Kittinger 已提交
737 738 739 740
         auto result = fc::sha1::hash( data, datalen );
         FC_ASSERT( result == hash_val, "hash miss match" );
      }

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

B
Bucky Kittinger 已提交
746
      void assert_ripemd160(array_ptr<char> data, size_t datalen, const fc::ripemd160& hash_val) {
B
Bucky Kittinger 已提交
747 748 749 750
         auto result = fc::ripemd160::hash( data, datalen );
         FC_ASSERT( result == hash_val, "hash miss match" );
      }

751 752 753 754
      void sha1(array_ptr<char> data, size_t datalen, fc::sha1& hash_val) {
         hash_val = fc::sha1::hash( data, datalen );
      }

755 756 757
      void sha256(array_ptr<char> data, size_t datalen, fc::sha256& hash_val) {
         hash_val = fc::sha256::hash( data, datalen );
      }
758 759 760 761 762 763 764 765

      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 );
      }
766 767
};

M
Matias Romeo 已提交
768 769 770 771 772 773 774 775 776 777 778 779 780 781
class permission_api : public context_aware_api {
   public:
      using context_aware_api::context_aware_api;

      bool check_authorization( account_name account, permission_name permission, array_ptr<char> packed_pubkeys, size_t datalen) {

         vector<public_key_type> pub_keys;
         datastream<const char*> ds( packed_pubkeys, datalen );
         while(ds.remaining()) {
            public_key_type pub;
            fc::raw::unpack(ds, pub);
            pub_keys.emplace_back(pub);
         }

782
         return context.control.get_authorization_manager().check_authorization(
M
Matias Romeo 已提交
783 784 785 786 787 788 789
            account, permission,
            {pub_keys.begin(), pub_keys.end()},
            false
         );
      }
};

B
Bart Wyatt 已提交
790 791
class system_api : public context_aware_api {
   public:
792 793
      explicit system_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
B
Bart Wyatt 已提交
794

795 796
      void abort() {
         edump(("abort() called"));
797
         FC_ASSERT( false, "abort() called");
798 799
      }

800
      void eosio_assert(bool condition, null_terminated_ptr str) {
801 802 803 804 805
         if( !condition ) {
            std::string message( str );
            edump((message));
            FC_ASSERT( condition, "assertion failed: ${s}", ("s",message));
         }
B
Bart Wyatt 已提交
806
      }
807

808 809 810 811
      void eosio_exit(int32_t code) {
         throw wasm_exit{code};
      }

812 813
      uint64_t current_time() {
         return static_cast<uint64_t>( context.control.pending_block_time().time_since_epoch().count() );
814
      }
B
Bart Wyatt 已提交
815 816 817 818
};

class action_api : public context_aware_api {
   public:
819 820
   action_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
B
Bart Wyatt 已提交
821

822 823 824 825 826 827 828 829
      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;
830 831
      }

832
      int action_data_size() {
B
Bart Wyatt 已提交
833
         return context.act.data.size();
834 835
      }

836
      uint64_t publication_time() {
837
         return static_cast<uint64_t>( context.trx_context.published.time_since_epoch().count() );
838 839
      }

840 841 842
      name current_receiver() {
         return context.receiver;
      }
843
};
B
Brian Johnson 已提交
844

B
Bart Wyatt 已提交
845 846
class console_api : public context_aware_api {
   public:
847 848
      console_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
B
Bart Wyatt 已提交
849

850 851
      void prints(null_terminated_ptr str) {
         context.console_append<const char*>(str);
B
Bart Wyatt 已提交
852 853 854
      }

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

858
      void printi(int64_t val) {
D
Daniel Larimer 已提交
859 860 861
         context.console_append(val);
      }

862
      void printui(uint64_t val) {
863
         context.console_append(val);
B
Bart Wyatt 已提交
864 865
      }

866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
      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("-");
         }

881
         context.console_append(fc::variant(v).get_string());
B
Bart Wyatt 已提交
882 883
      }

884 885
      void printui128(const unsigned __int128& val) {
         fc::uint128_t v(val>>64, static_cast<uint64_t>(val) );
886
         context.console_append(fc::variant(v).get_string());
B
Bart Wyatt 已提交
887 888
      }

889 890 891 892 893 894
      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 );
895
         context.console_append(val);
896 897

         console.precision( orig_prec );
D
Daniel Larimer 已提交
898
      }
899

900 901 902 903 904 905
      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 );
906
         context.console_append(val);
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933

         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 已提交
934 935 936
      }

      void printn(const name& value) {
937
         context.console_append(value.to_string());
B
Bart Wyatt 已提交
938 939 940
      }

      void printhex(array_ptr<const char> data, size_t data_len ) {
941
         context.console_append(fc::to_hex(data, data_len));
B
Bart Wyatt 已提交
942 943 944
      }
};

A
arhag 已提交
945
#define DB_API_METHOD_WRAPPERS_SIMPLE_SECONDARY(IDX, TYPE)\
946 947 948 949 950 951 952 953 954
      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 已提交
955
      int db_##IDX##_find_secondary( uint64_t code, uint64_t scope, uint64_t table, const TYPE& secondary, uint64_t& primary ) {\
956 957 958
         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 已提交
959
         return context.IDX.find_primary(code, scope, table, secondary, primary);\
960 961 962 963 964 965 966
      }\
      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);\
      }\
967 968 969
      int db_##IDX##_end( uint64_t code, uint64_t scope, uint64_t table ) {\
         return context.IDX.end_secondary(code, scope, table);\
      }\
970 971 972 973 974 975 976
      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 已提交
977 978
#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 已提交
979 980 981 982 983
         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 已提交
984
      void db_##IDX##_update( int iterator, uint64_t payer, array_ptr<const ARR_ELEMENT_TYPE> data, size_t data_len ) {\
A
arhag 已提交
985 986 987 988 989 990 991 992
         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 已提交
993
      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 已提交
994 995 996 997 998
         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 已提交
999
      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 已提交
1000 1001 1002 1003 1004
         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 已提交
1005
      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 已提交
1006 1007 1008 1009 1010
         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 已提交
1011
      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 已提交
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
         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);\
      }

1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
#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 已提交
1063

D
Daniel Larimer 已提交
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
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 );
      }
1077 1078 1079
      int db_get_i64( int itr, array_ptr<char> buffer, size_t buffer_size ) {
         return context.db_get_i64( itr, buffer, buffer_size );
      }
1080 1081
      int db_next_i64( int itr, uint64_t& primary ) {
         return context.db_next_i64(itr, primary);
1082
      }
1083 1084
      int db_previous_i64( int itr, uint64_t& primary ) {
         return context.db_previous_i64(itr, primary);
D
Daniel Larimer 已提交
1085
      }
1086 1087
      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 已提交
1088
      }
1089 1090
      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 已提交
1091
      }
1092
      int db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) {
A
arhag 已提交
1093
         return context.db_upperbound_i64( code, scope, table, id );
D
Daniel Larimer 已提交
1094
      }
1095 1096 1097
      int db_end_i64( uint64_t code, uint64_t scope, uint64_t table ) {
         return context.db_end_i64( code, scope, table );
      }
1098

A
arhag 已提交
1099 1100
      DB_API_METHOD_WRAPPERS_SIMPLE_SECONDARY(idx64,  uint64_t)
      DB_API_METHOD_WRAPPERS_SIMPLE_SECONDARY(idx128, uint128_t)
A
arhag 已提交
1101
      DB_API_METHOD_WRAPPERS_ARRAY_SECONDARY(idx256, 2, uint128_t)
1102
      DB_API_METHOD_WRAPPERS_FLOAT_SECONDARY(idx_double, float64_t)
1103
      DB_API_METHOD_WRAPPERS_FLOAT_SECONDARY(idx_long_double, float128_t)
D
Daniel Larimer 已提交
1104 1105
};

1106
class memory_api : public context_aware_api {
1107
   public:
1108 1109
      memory_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
A
arhag 已提交
1110

1111 1112 1113 1114
      char* memcpy( array_ptr<char> dest, array_ptr<const char> src, size_t length) {
         return (char *)::memcpy(dest, src, length);
      }

1115 1116 1117 1118
      char* memmove( array_ptr<char> dest, array_ptr<const char> src, size_t length) {
         return (char *)::memmove(dest, src, length);
      }

1119 1120 1121 1122
      int memcmp( array_ptr<const char> dest, array_ptr<const char> src, size_t length) {
         return ::memcmp(dest, src, length);
      }

B
Bucky Kittinger 已提交
1123
      char* memset( array_ptr<char> dest, int value, size_t length ) {
B
Bucky Kittinger 已提交
1124
         return (char *)::memset( dest, value, length );
B
Bucky Kittinger 已提交
1125
      }
1126 1127
};

1128 1129 1130 1131
class transaction_api : public context_aware_api {
   public:
      using context_aware_api::context_aware_api;

D
Daniel Larimer 已提交
1132
      void send_inline( array_ptr<char> data, size_t data_len ) {
A
arhag 已提交
1133 1134 1135
         //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 已提交
1136 1137 1138 1139 1140 1141

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

1142
      void send_context_free_inline( array_ptr<char> data, size_t data_len ) {
A
arhag 已提交
1143 1144 1145
         //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" );
1146 1147 1148 1149 1150 1151

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

1152
      void send_deferred( const uint128_t& sender_id, account_name payer, array_ptr<char> data, size_t data_len ) {
D
Daniel Larimer 已提交
1153
         try {
1154 1155 1156
            transaction trx;
            fc::raw::unpack<transaction>(data, data_len, trx);
            context.schedule_deferred_transaction(sender_id, payer, std::move(trx));
D
Daniel Larimer 已提交
1157 1158
         } FC_CAPTURE_AND_RETHROW((fc::to_hex(data, data_len)));
      }
A
Anton Perkov 已提交
1159

1160 1161
      void cancel_deferred( const unsigned __int128& val ) {
         fc::uint128_t sender_id(val>>64, uint64_t(val) );
1162
         context.cancel_deferred_transaction( (unsigned __int128)sender_id );
A
Anton Perkov 已提交
1163
      }
D
Daniel Larimer 已提交
1164 1165 1166 1167 1168
};


class context_free_transaction_api : public context_aware_api {
   public:
1169 1170
      context_free_transaction_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
D
Daniel Larimer 已提交
1171

1172
      int read_transaction( array_ptr<char> data, size_t buffer_size ) {
1173
         bytes trx = context.get_packed_transaction();
1174 1175 1176 1177 1178 1179 1180 1181

         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;
1182 1183 1184 1185
      }

      int transaction_size() {
         return context.get_packed_transaction().size();
1186 1187 1188
      }

      int expiration() {
1189
        return context.trx_context.trx.expiration.sec_since_epoch();
1190 1191 1192
      }

      int tapos_block_num() {
1193
        return context.trx_context.trx.ref_block_num;
1194
      }
1195
      int tapos_block_prefix() {
1196
        return context.trx_context.trx.ref_block_prefix;
1197 1198
      }

D
Daniel Larimer 已提交
1199 1200
      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 );
1201 1202
      }

1203 1204 1205 1206
      void check_auth( array_ptr<char> trx_data, size_t trx_size, array_ptr<char> perm_data, size_t perm_size ) {
         transaction trx = fc::raw::unpack<transaction>( trx_data, trx_size );
         vector<permission_level> perm = fc::raw::unpack<vector<permission_level>>( perm_data, perm_size );
         return context.check_auth( trx, perm );
1207
      }
1208 1209
};

1210 1211 1212
class compiler_builtins : public context_aware_api {
   public:
      using context_aware_api::context_aware_api;
1213
      void __ashlti3(__int128& ret, uint64_t low, uint64_t high, uint32_t shift) {
1214 1215 1216
         fc::uint128_t i(high, low);
         i <<= shift;
         ret = (unsigned __int128)i;
1217 1218
      }

1219
      void __ashrti3(__int128& ret, uint64_t low, uint64_t high, uint32_t shift) {
B
oops  
Bucky Kittinger 已提交
1220 1221 1222 1223 1224
         // retain the signedness
         ret = high;
         ret <<= 64;
         ret |= low;
         ret >>= shift;
1225
      }
1226

1227 1228 1229 1230 1231
      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;
      }
1232

1233 1234 1235 1236 1237
      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 已提交
1238

1239
      void __divti3(__int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) {
B
oops  
Bucky Kittinger 已提交
1240 1241
         __int128 lhs = ha;
         __int128 rhs = hb;
A
arhag 已提交
1242

B
oops  
Bucky Kittinger 已提交
1243 1244
         lhs <<= 64;
         lhs |=  la;
1245

B
oops  
Bucky Kittinger 已提交
1246 1247
         rhs <<= 64;
         rhs |=  lb;
1248

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

A
arhag 已提交
1251
         lhs /= rhs;
1252

B
oops  
Bucky Kittinger 已提交
1253
         ret = lhs;
A
arhag 已提交
1254
      }
1255

B
oops  
Bucky Kittinger 已提交
1256 1257 1258
      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 已提交
1259

B
oops  
Bucky Kittinger 已提交
1260 1261 1262 1263 1264
         lhs <<= 64;
         lhs |=  la;

         rhs <<= 64;
         rhs |=  lb;
1265

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

A
arhag 已提交
1268
         lhs /= rhs;
B
oops  
Bucky Kittinger 已提交
1269 1270 1271 1272 1273 1274
         ret = lhs;
      }

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

B
oops  
Bucky Kittinger 已提交
1276 1277
         lhs <<= 64;
         lhs |=  la;
1278

B
oops  
Bucky Kittinger 已提交
1279 1280
         rhs <<= 64;
         rhs |=  lb;
1281

A
arhag 已提交
1282
         lhs *= rhs;
B
oops  
Bucky Kittinger 已提交
1283
         ret = lhs;
A
arhag 已提交
1284
      }
1285 1286

      void __modti3(__int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) {
B
oops  
Bucky Kittinger 已提交
1287 1288 1289 1290 1291
         __int128 lhs = ha;
         __int128 rhs = hb;

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

B
oops  
Bucky Kittinger 已提交
1293 1294
         rhs <<= 64;
         rhs |=  lb;
A
arhag 已提交
1295

B
oops  
Bucky Kittinger 已提交
1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
         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 已提交
1308

B
oops  
Bucky Kittinger 已提交
1309 1310
         rhs <<= 64;
         rhs |=  lb;
A
arhag 已提交
1311

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

B
oops  
Bucky Kittinger 已提交
1314 1315
         lhs %= rhs;
         ret = lhs;
1316
      }
1317 1318

      void __addtf3( float128_t& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1319 1320
         float128_t a = {{ la, ha }};
         float128_t b = {{ lb, hb }};
1321
         ret = f128_add( a, b );
1322
      }
1323
      void __subtf3( float128_t& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1324 1325
         float128_t a = {{ la, ha }};
         float128_t b = {{ lb, hb }};
1326
         ret = f128_sub( a, b );
1327
      }
1328
      void __multf3( float128_t& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1329 1330
         float128_t a = {{ la, ha }};
         float128_t b = {{ lb, hb }};
1331
         ret = f128_mul( a, b );
1332
      }
1333
      void __divtf3( float128_t& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1334 1335
         float128_t a = {{ la, ha }};
         float128_t b = {{ lb, hb }};
1336
         ret = f128_div( a, b );
1337
      }
1338
      void __negtf2( float128_t& ret, uint64_t la, uint64_t ha ) {
B
Bucky Kittinger 已提交
1339
         float128_t a = {{ la, (ha ^ ((uint64_t)1 << 63)) }};
1340 1341
         a = ret;
      }
1342
      int ___cmptf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb, int return_value_if_nan ) {
1343
         float128_t a = {{ la, ha }};
1344
         float128_t b = {{ lb, hb }};
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354
         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);
1355
      }
1356
      int __netf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1357
         return ___cmptf2(la, ha, lb, hb, 1);
1358
      }
1359
      int __getf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1360
         return ___cmptf2(la, ha, lb, hb, -1);
1361
      }
1362
      int __gttf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1363
         return ___cmptf2(la, ha, lb, hb, 0);
1364
      }
1365
      int __letf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1366
         return ___cmptf2(la, ha, lb, hb, 1);
1367
      }
1368
      int __lttf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1369
         return ___cmptf2(la, ha, lb, hb, 0);
1370
      }
1371
      int __cmptf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1372
         return ___cmptf2(la, ha, lb, hb, 1);
1373
      }
1374
      int __unordtf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ) {
1375
         float128_t a = {{ la, ha }};
1376
         float128_t b = {{ lb, hb }};
1377
         if ( softfloat_api::is_nan(a) || softfloat_api::is_nan(b) )
1378 1379 1380
            return 1;
         return 0;
      }
1381
      double __floatsidf( int32_t i ) {
D
Daniel Larimer 已提交
1382
         edump((i)( "warning returning float64") );
1383
         float64_t ret = i32_to_f64(i);
1384
         return *reinterpret_cast<double*>(&ret);
D
Daniel Larimer 已提交
1385 1386 1387 1388 1389 1390 1391
      }
      void __floatsitf( float128_t& ret, int32_t i ) {
         ret = i32_to_f128(i); /// TODO: should be 128
      }
      void __floatunsitf( float128_t& ret, uint32_t i ) {
         ret = ui32_to_f128(i); /// TODO: should be 128
      }
1392 1393 1394 1395 1396 1397
      void __floatditf( float128_t& ret, uint64_t a ) {
         ret = i64_to_f128( a );
      }
      void __floatunditf( float128_t& ret, uint64_t a ) {
         ret = ui64_to_f128( a );
      }
B
Bucky Kittinger 已提交
1398 1399 1400 1401 1402 1403 1404 1405
      double __floattidf( uint64_t l, uint64_t h ) {
         auto ret = i64_to_f64( l );
         return *(double*)&ret;
      }
      double __floatuntidf( uint64_t l, uint64_t h ) {
         auto ret = ui64_to_f64( l );
         return *(double*)&ret;
      }
1406
      void __extendsftf2( float128_t& ret, uint32_t f ) {
1407
         float32_t in = { f };
1408
         ret = f32_to_f128( in );
1409
      }
1410
      void __extenddftf2( float128_t& ret, double in ) {
D
Daniel Larimer 已提交
1411
         edump(("warning in flaot64..." ));
1412
         ret = f64_to_f128( float64_t{*(uint64_t*)&in} );
1413
      }
B
Bucky Kittinger 已提交
1414
      void __fixtfti( __int128& ret, uint64_t l, uint64_t h ) {
1415
         float128_t f = {{ l, h }};
B
Bucky Kittinger 已提交
1416
         ret = f128_to_i64( f, 0, false );
1417
      }
1418
      int64_t __fixtfdi( uint64_t l, uint64_t h ) {
1419
         float128_t f = {{ l, h }};
1420 1421 1422
         return f128_to_i64( f, 0, false );
      }
      int32_t __fixtfsi( uint64_t l, uint64_t h ) {
1423
         float128_t f = {{ l, h }};
1424 1425
         return f128_to_i32( f, 0, false );
      }
1426 1427
      void __fixunstfti( unsigned __int128& ret, uint64_t l, uint64_t h ) {
         float128_t f = {{ l, h }};
B
Bucky Kittinger 已提交
1428
         ret = f128_to_ui64( f, 0, false );
1429
      }
1430
      uint64_t __fixunstfdi( uint64_t l, uint64_t h ) {
1431
         float128_t f = {{ l, h }};
1432 1433 1434
         return f128_to_ui64( f, 0, false );
      }
      uint32_t __fixunstfsi( uint64_t l, uint64_t h ) {
1435
         float128_t f = {{ l, h }};
1436 1437
         return f128_to_ui32( f, 0, false );
      }
1438
      void __fixsfti( __int128& ret, float a ) {
B
Bucky Kittinger 已提交
1439 1440
         float32_t f = {*(uint32_t*)&a};
         ret = f32_to_i64( f, 0, false );
1441 1442
      }
      void __fixdfti( __int128& ret, double a ) {
B
Bucky Kittinger 已提交
1443 1444
         float64_t f = {*(uint64_t*)&a};
         ret = f64_to_i64( f, 0, false );
1445 1446
      }
      void __fixunssfti( unsigned __int128& ret, float a ) {
B
Bucky Kittinger 已提交
1447 1448
         float32_t f = {*(uint32_t*)&a};
         ret = f32_to_ui64( f, 0, false );
1449 1450
      }
      void __fixunsdfti( unsigned __int128& ret, double a ) {
B
Bucky Kittinger 已提交
1451 1452
         float64_t f = {*(uint64_t*)&a};
         ret = f64_to_ui64( f, 0, false );
1453
      }
1454
      uint64_t __trunctfdf2( uint64_t l, uint64_t h ) {
1455
         float128_t f = {{ l, h }};
1456 1457 1458
         return f128_to_f64( f ).v;
      }
      uint32_t __trunctfsf2( uint64_t l, uint64_t h ) {
1459
         float128_t f = {{ l, h }};
1460 1461
         return f128_to_f32( f ).v;
      }
1462

B
Bucky Kittinger 已提交
1463
      static constexpr uint32_t SHIFT_WIDTH = (sizeof(uint64_t)*8)-1;
1464 1465 1466 1467
};

class math_api : public context_aware_api {
   public:
1468 1469
      math_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
1470 1471 1472 1473 1474

      void diveq_i128(unsigned __int128* self, const unsigned __int128* other) {
         fc::uint128_t s(*self);
         const fc::uint128_t o(*other);
         FC_ASSERT( o != 0, "divide by zero" );
A
arhag 已提交
1475

1476 1477
         s = s/o;
         *self = (unsigned __int128)s;
1478 1479
      }

1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
      void multeq_i128(unsigned __int128* self, const unsigned __int128* other) {
         fc::uint128_t s(*self);
         const fc::uint128_t o(*other);
         s *= o;
         *self = (unsigned __int128)s;
      }

      uint64_t double_add(uint64_t a, uint64_t b) {
         using DOUBLE = boost::multiprecision::cpp_bin_float_50;
         DOUBLE c = DOUBLE(*reinterpret_cast<double *>(&a))
                  + DOUBLE(*reinterpret_cast<double *>(&b));
         double res = c.convert_to<double>();
         return *reinterpret_cast<uint64_t *>(&res);
      }

      uint64_t double_mult(uint64_t a, uint64_t b) {
         using DOUBLE = boost::multiprecision::cpp_bin_float_50;
         DOUBLE c = DOUBLE(*reinterpret_cast<double *>(&a))
                  * DOUBLE(*reinterpret_cast<double *>(&b));
         double res = c.convert_to<double>();
         return *reinterpret_cast<uint64_t *>(&res);
      }

      uint64_t double_div(uint64_t a, uint64_t b) {
         using DOUBLE = boost::multiprecision::cpp_bin_float_50;
         DOUBLE divisor = DOUBLE(*reinterpret_cast<double *>(&b));
         FC_ASSERT(divisor != 0, "divide by zero");
         DOUBLE c = DOUBLE(*reinterpret_cast<double *>(&a)) / divisor;
         double res = c.convert_to<double>();
         return *reinterpret_cast<uint64_t *>(&res);
      }

      uint32_t double_eq(uint64_t a, uint64_t b) {
         using DOUBLE = boost::multiprecision::cpp_bin_float_50;
         return DOUBLE(*reinterpret_cast<double *>(&a)) == DOUBLE(*reinterpret_cast<double *>(&b));
      }

      uint32_t double_lt(uint64_t a, uint64_t b) {
         using DOUBLE = boost::multiprecision::cpp_bin_float_50;
         return DOUBLE(*reinterpret_cast<double *>(&a)) < DOUBLE(*reinterpret_cast<double *>(&b));
      }

      uint32_t double_gt(uint64_t a, uint64_t b) {
         using DOUBLE = boost::multiprecision::cpp_bin_float_50;
         return DOUBLE(*reinterpret_cast<double *>(&a)) > DOUBLE(*reinterpret_cast<double *>(&b));
      }

      uint64_t double_to_i64(uint64_t n) {
         using DOUBLE = boost::multiprecision::cpp_bin_float_50;
B
Bucky Kittinger 已提交
1529
         return DOUBLE(*reinterpret_cast<double *>(&n)).convert_to<int64_t>();
1530 1531
      }

B
Bucky Kittinger 已提交
1532
      uint64_t i64_to_double(int64_t n) {
1533 1534 1535 1536
         using DOUBLE = boost::multiprecision::cpp_bin_float_50;
         double res = DOUBLE(n).convert_to<double>();
         return *reinterpret_cast<uint64_t *>(&res);
      }
1537 1538
};

1539 1540 1541
/*
 * This api will be removed with fix for `eos #2561`
 */
B
Bucky Kittinger 已提交
1542 1543 1544 1545
class call_depth_api : public context_aware_api {
   public:
      call_depth_api( apply_context& ctx )
      :context_aware_api(ctx,true){}
1546
      void call_depth_assert() {
1547 1548
         FC_THROW_EXCEPTION(wasm_execution_error, "Exceeded call depth maximum");
      }
B
Bucky Kittinger 已提交
1549 1550 1551
};

REGISTER_INJECTED_INTRINSICS(call_depth_api,
B
Bucky Kittinger 已提交
1552
   (call_depth_assert,  void()               )
B
Bucky Kittinger 已提交
1553 1554
);

1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566
REGISTER_INTRINSICS(math_api,
   (diveq_i128,    void(int, int)            )
   (multeq_i128,   void(int, int)            )
   (double_add,    int64_t(int64_t, int64_t) )
   (double_mult,   int64_t(int64_t, int64_t) )
   (double_div,    int64_t(int64_t, int64_t) )
   (double_eq,     int32_t(int64_t, int64_t) )
   (double_lt,     int32_t(int64_t, int64_t) )
   (double_gt,     int32_t(int64_t, int64_t) )
   (double_to_i64, int64_t(int64_t)          )
   (i64_to_double, int64_t(int64_t)          )
);
B
Bucky Kittinger 已提交
1567

1568
REGISTER_INTRINSICS(compiler_builtins,
B
Bucky Kittinger 已提交
1569 1570 1571 1572 1573 1574 1575 1576 1577
   (__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)  )
1578 1579 1580 1581 1582 1583 1584 1585 1586
   (__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)        )
1587
   (__letf2,       int(int64_t, int64_t, int64_t, int64_t)        )
1588 1589
   (__cmptf2,      int(int64_t, int64_t, int64_t, int64_t)        )
   (__unordtf2,    int(int64_t, int64_t, int64_t, int64_t)        )
1590
   (__negtf2,      void (int, int64_t, int64_t)                   )
D
Daniel Larimer 已提交
1591 1592
   (__floatsitf,   void (int, int)                                )
   (__floatunsitf, void (int, int)                                )
1593 1594
   (__floatditf,   void (int, int64_t)                            )
   (__floatunditf, void (int, int64_t)                            )
B
Bucky Kittinger 已提交
1595 1596
   (__floattidf,   double (int64_t, int64_t)                      )
   (__floatuntidf, double (int64_t, int64_t)                      )
1597
   (__floatsidf,   double(int)                                    )
1598
   (__extendsftf2, void(int, int)                                 )
1599
   (__extenddftf2, void(int, double)                              )
1600
   (__fixtfti,     void(int, int64_t, int64_t)                    )
1601 1602
   (__fixtfdi,     int64_t(int64_t, int64_t)                      )
   (__fixtfsi,     int(int64_t, int64_t)                          )
1603
   (__fixunstfti,  void(int, int64_t, int64_t)                    )
1604 1605
   (__fixunstfdi,  int64_t(int64_t, int64_t)                      )
   (__fixunstfsi,  int(int64_t, int64_t)                          )
1606 1607 1608 1609
   (__fixsfti,     void(int, float)                               )
   (__fixdfti,     void(int, double)                              )
   (__fixunssfti,     void(int, float)                            )
   (__fixunsdfti,     void(int, double)                           )
1610 1611
   (__trunctfdf2,  int64_t(int64_t, int64_t)                      )
   (__trunctfsf2,  int(int64_t, int64_t)                          )
B
Bucky Kittinger 已提交
1612
);
1613 1614

REGISTER_INTRINSICS(privileged_api,
1615 1616 1617 1618
   (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) )
1619
   (set_active_producers,             int(int,int)                          )
1620 1621 1622 1623
   (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)                    )
1624
);
1625

1626
REGISTER_INJECTED_INTRINSICS(apply_context,
1627
   (checktime,      void(int))
1628 1629
);

1630
REGISTER_INTRINSICS(producer_api,
B
Bucky Kittinger 已提交
1631
   (get_active_producers,      int(int, int) )
1632 1633
);

A
arhag 已提交
1634
#define DB_SECONDARY_INDEX_METHODS_SIMPLE(IDX) \
1635 1636 1637 1638 1639 1640 1641
   (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))\
1642
   (db_##IDX##_end,            int(int64_t,int64_t,int64_t))\
1643 1644 1645
   (db_##IDX##_next,           int(int, int))\
   (db_##IDX##_previous,       int(int, int))

A
arhag 已提交
1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657
#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 已提交
1658 1659 1660 1661
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))
1662
   (db_get_i64,          int(int, int, int))
1663 1664
   (db_next_i64,         int(int, int))
   (db_previous_i64,     int(int, int))
D
Daniel Larimer 已提交
1665 1666
   (db_find_i64,         int(int64_t,int64_t,int64_t,int64_t))
   (db_lowerbound_i64,   int(int64_t,int64_t,int64_t,int64_t))
1667
   (db_upperbound_i64,   int(int64_t,int64_t,int64_t,int64_t))
A
arhag 已提交
1668
   (db_end_i64,          int(int64_t,int64_t,int64_t))
1669

A
arhag 已提交
1670 1671 1672
   DB_SECONDARY_INDEX_METHODS_SIMPLE(idx64)
   DB_SECONDARY_INDEX_METHODS_SIMPLE(idx128)
   DB_SECONDARY_INDEX_METHODS_ARRAY(idx256)
A
arhag 已提交
1673
   DB_SECONDARY_INDEX_METHODS_SIMPLE(idx_double)
1674
   DB_SECONDARY_INDEX_METHODS_SIMPLE(idx_long_double)
1675
);
D
Daniel Larimer 已提交
1676

1677
REGISTER_INTRINSICS(crypto_api,
B
Bucky Kittinger 已提交
1678 1679
   (assert_recover_key,     void(int, int, int, int, int) )
   (recover_key,            int(int, int, int, int, int)  )
B
Bucky Kittinger 已提交
1680 1681 1682 1683
   (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 已提交
1684 1685 1686 1687
   (sha1,                   void(int, int, int)           )
   (sha256,                 void(int, int, int)           )
   (sha512,                 void(int, int, int)           )
   (ripemd160,              void(int, int, int)           )
1688 1689
);

M
Matias Romeo 已提交
1690 1691 1692 1693
REGISTER_INTRINSICS(permission_api,
   (check_authorization,  int(int64_t, int64_t, int, int))
);

B
Bart Wyatt 已提交
1694
REGISTER_INTRINSICS(system_api,
1695 1696 1697 1698
   (abort,        void()         )
   (eosio_assert, void(int, int) )
   (eosio_exit,   void(int)      )
   (current_time, int64_t()      )
B
Bart Wyatt 已提交
1699 1700 1701
);

REGISTER_INTRINSICS(action_api,
1702 1703
   (read_action_data,       int(int, int)  )
   (action_data_size,       int()          )
1704
   (publication_time,   int64_t()          )
1705
   (current_receiver,   int64_t()          )
B
Bart Wyatt 已提交
1706 1707 1708
);

REGISTER_INTRINSICS(apply_context,
B
Bucky Kittinger 已提交
1709
   (require_recipient,     void(int64_t)          )
1710
   (require_authorization, void(int64_t), "require_auth", void(apply_context::*)(const account_name&))
1711
   (require_authorization, void(int64_t, int64_t), "require_auth2", void(apply_context::*)(const account_name&, const permission_name& permission))
1712
   (has_authorization,     int(int64_t), "has_auth", bool(apply_context::*)(const account_name&)const)
B
Bucky Kittinger 已提交
1713
   (is_account,            int(int64_t)           )
B
Bart Wyatt 已提交
1714 1715 1716
);

REGISTER_INTRINSICS(console_api,
1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727
   (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 已提交
1728 1729
);

D
Daniel Larimer 已提交
1730
REGISTER_INTRINSICS(context_free_transaction_api,
1731 1732 1733 1734 1735
   (read_transaction,       int(int, int)            )
   (transaction_size,       int()                    )
   (expiration,             int()                    )
   (tapos_block_prefix,     int()                    )
   (tapos_block_num,        int()                    )
1736
   (get_action,             int (int, int, int, int) )
1737
   (check_auth,             void(int, int, int, int) )
D
Daniel Larimer 已提交
1738 1739 1740
);

REGISTER_INTRINSICS(transaction_api,
1741 1742 1743 1744
   (send_inline,               void(int, int)               )
   (send_context_free_inline,  void(int, int)               )
   (send_deferred,             void(int, int64_t, int, int) )
   (cancel_deferred,           void(int)                    )
1745 1746
);

D
Daniel Larimer 已提交
1747 1748 1749 1750
REGISTER_INTRINSICS(context_free_api,
   (get_context_free_data, int(int, int, int) )
)

1751
REGISTER_INTRINSICS(memory_api,
B
Bucky Kittinger 已提交
1752 1753 1754 1755
   (memcpy,                 int(int, int, int)  )
   (memmove,                int(int, int, int)  )
   (memcmp,                 int(int, int, int)  )
   (memset,                 int(int, int, int)  )
1756 1757
);

1758
REGISTER_INJECTED_INTRINSICS(softfloat_api,
B
Bucky Kittinger 已提交
1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778
      (_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)      )
1779 1780 1781 1782 1783 1784 1785
      (_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 已提交
1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816
      (_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)       )
1817
);
B
Bucky Kittinger 已提交
1818

1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
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 已提交
1830

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