wasm_interface.cpp 34.2 KB
Newer Older
1 2 3 4
/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
5
#include <boost/function.hpp>
6
#include <boost/multiprecision/cpp_bin_float.hpp>
7
#include <eos/chain/wasm_interface.hpp>
8
#include <eos/chain/chain_controller.hpp>
9 10 11 12 13 14 15 16 17
#include "Platform/Platform.h"
#include "WAST/WAST.h"
#include "Runtime/Runtime.h"
#include "Runtime/Linker.h"
#include "Runtime/Intrinsics.h"
#include "IR/Module.h"
#include "IR/Operators.h"
#include "IR/Validate.h"
#include <eos/chain/key_value_object.hpp>
18
#include <eos/chain/account_object.hpp>
19
#include <eos/types/AbiSerializer.hpp>
20
#include <chrono>
21
#include <boost/lexical_cast.hpp>
22
#include <fc/utf8.hpp>
23

P
Pravin 已提交
24
namespace eosio { namespace chain {
25 26
   using namespace IR;
   using namespace Runtime;
27
   typedef boost::multiprecision::cpp_bin_float_50 DOUBLE;
28

B
Brian Johnson 已提交
29 30 31
   class wasm_memory
   {
   public:
B
Brian Johnson 已提交
32 33 34
      explicit wasm_memory(wasm_interface& interface);
      wasm_memory(const wasm_memory&) = delete;
      wasm_memory(wasm_memory&&) = delete;
B
Brian Johnson 已提交
35 36 37 38 39 40 41 42 43 44 45 46
      ~wasm_memory();
      U32 sbrk(I32 num_bytes);
   private:
      static U32 limit_32bit_address(Uptr address);

      static const U32 _max_memory = 1024 * 1024;
      wasm_interface& _wasm_interface;
      Uptr _num_pages;
      const U32 _min_bytes;
      U32 _num_bytes;
   };

47 48 49
   wasm_interface::wasm_interface() {
   }

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
   wasm_interface::key_type wasm_interface::to_key_type(const types::TypeName& type_name)
   {
      if ("str" == type_name)
         return str;
      if ("i64" == type_name)
         return i64;
      if ("i128i128" == type_name)
         return i128i128;
      if ("i64i64i64" == type_name)
         return i64i64i64;

      return invalid_key_type;
   }

   std::string wasm_interface::to_type_name(key_type key_type)
   {
      switch (key_type)
      {
      case str:
         return "str";
      case i64:
         return "i64";
      case i128i128:
         return "i128i128";
      case i64i64i64:
         return "i64i64i64";
      default:
         return std::string("<invalid key type - ") + boost::lexical_cast<std::string>(int(key_type)) + ">";
      }
   }

81
#ifdef NDEBUG
82
   const int CHECKTIME_LIMIT = 3000;
83
#else
84
   const int CHECKTIME_LIMIT = 18000;
85 86
#endif

87
   void checktime(int64_t duration, uint32_t checktime_limit)
B
Brian Johnson 已提交
88
   {
89
      if (duration > checktime_limit) {
B
Brian Johnson 已提交
90 91 92
         wlog("checktime called ${d}", ("d", duration));
         throw checktime_exceeded();
      }
93
   }
B
Brian Johnson 已提交
94 95

DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) {
96
   checktime(wasm_interface::get().current_execution_time(), wasm_interface::get().checktime_limit);
97
}
B
Brian Johnson 已提交
98

99 100
   template <typename Function, typename KeyType, int numberOfKeys>
   int32_t validate(int32_t valueptr, int32_t valuelen, Function func) {
M
Matias Romeo 已提交
101

102
      static const uint32_t keylen = numberOfKeys*sizeof(KeyType);
M
Matias Romeo 已提交
103

104 105 106
      FC_ASSERT( valuelen >= keylen, "insufficient data passed" );

      auto& wasm  = wasm_interface::get();
M
Matias Romeo 已提交
107
      FC_ASSERT( wasm.current_apply_context, "no apply context found" );
108 109

      char* value = memoryArrayPtr<char>( wasm.current_memory, valueptr, valuelen );
110
      KeyType*  keys = reinterpret_cast<KeyType*>(value);
111 112 113 114
      
      valuelen -= keylen;
      value    += keylen;

115
      return func(wasm.current_apply_context, keys, value, valuelen);
M
Matias Romeo 已提交
116 117
   }

M
Matias Romeo 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
   template <typename Function>
   int32_t validate_str(int32_t keyptr, int32_t keylen, int32_t valueptr, int32_t valuelen, Function func) {

      auto& wasm  = wasm_interface::get();
      FC_ASSERT( wasm.current_apply_context, "no apply context found" );

      char* key   = memoryArrayPtr<char>( wasm.current_memory, keyptr, keylen );
      char* value = memoryArrayPtr<char>( wasm.current_memory, valueptr, valuelen );

      std::string keys(key, keylen);

      return func(wasm.current_apply_context, &keys, value, valuelen);
   }


133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
#define VERIFY_TABLE(TYPE) \
   const auto table_name = Name(table); \
   auto& wasm  = wasm_interface::get(); \
   if (wasm.table_key_types) \
   { \
      auto table_key = wasm.table_key_types->find(table_name); \
      if (table_key == wasm.table_key_types->end()) \
      { \
         FC_ASSERT(!wasm.tables_fixed, "abi did not define table ${t}", ("t", table_name)); \
         wasm.table_key_types->emplace(std::make_pair(table_name,wasm_interface::TYPE)); \
      } \
      else \
      { \
         FC_ASSERT(wasm_interface::TYPE == table_key->second, "abi definition for ${table} expects \"${type}\", but code is requesting \"" #TYPE "\"", ("table",table_name)("type",wasm_interface::to_type_name(table_key->second))); \
      } \
   }

150 151
#define READ_RECORD(READFUNC, INDEX, SCOPE) \
   auto lambda = [&](apply_context* ctx, INDEX::value_type::key_type* keys, char *data, uint32_t datalen) -> int32_t { \
152
      auto res = ctx->READFUNC<INDEX, SCOPE>( Name(scope), Name(code), table_name, keys, data, datalen); \
153 154 155 156 157 158 159
      if (res >= 0) res += INDEX::value_type::number_of_keys*sizeof(INDEX::value_type::key_type); \
      return res; \
   }; \
   return validate<decltype(lambda), INDEX::value_type::key_type, INDEX::value_type::number_of_keys>(valueptr, valuelen, lambda);

#define UPDATE_RECORD(UPDATEFUNC, INDEX, DATASIZE) \
   auto lambda = [&](apply_context* ctx, INDEX::value_type::key_type* keys, char *data, uint32_t datalen) -> int32_t { \
160
      return ctx->UPDATEFUNC<INDEX::value_type>( Name(scope), Name(ctx->code.value), table_name, keys, data, datalen); \
161 162 163 164 165
   }; \
   return validate<decltype(lambda), INDEX::value_type::key_type, INDEX::value_type::number_of_keys>(valueptr, DATASIZE, lambda);

#define DEFINE_RECORD_UPDATE_FUNCTIONS(OBJTYPE, INDEX) \
   DEFINE_INTRINSIC_FUNCTION4(env,store_##OBJTYPE,store_##OBJTYPE,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { \
166
      VERIFY_TABLE(OBJTYPE) \
167 168 169
      UPDATE_RECORD(store_record, INDEX, valuelen); \
   } \
   DEFINE_INTRINSIC_FUNCTION4(env,update_##OBJTYPE,update_##OBJTYPE,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { \
170
      VERIFY_TABLE(OBJTYPE) \
171 172 173
      UPDATE_RECORD(update_record, INDEX, valuelen); \
   } \
   DEFINE_INTRINSIC_FUNCTION3(env,remove_##OBJTYPE,remove_##OBJTYPE,i32,i64,scope,i64,table,i32,valueptr) { \
174
      VERIFY_TABLE(OBJTYPE) \
175
      UPDATE_RECORD(remove_record, INDEX, sizeof(typename INDEX::value_type::key_type)*INDEX::value_type::number_of_keys); \
176
   }
M
Matias Romeo 已提交
177

178 179 180 181
#define DEFINE_RECORD_READ_FUNCTION(OBJTYPE, ACTION, FUNCPREFIX, INDEX, SCOPE) \
   DEFINE_INTRINSIC_FUNCTION5(env,ACTION##_##FUNCPREFIX##OBJTYPE,ACTION##_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      VERIFY_TABLE(OBJTYPE) \
      READ_RECORD(ACTION##_record, INDEX, SCOPE); \
182
   }
M
Matias Romeo 已提交
183

184 185 186 187 188 189 190 191 192
#define DEFINE_RECORD_READ_FUNCTIONS(OBJTYPE, FUNCPREFIX, INDEX, SCOPE) \
   DEFINE_RECORD_READ_FUNCTION(OBJTYPE, load, FUNCPREFIX, INDEX, SCOPE) \
   DEFINE_RECORD_READ_FUNCTION(OBJTYPE, front, FUNCPREFIX, INDEX, SCOPE) \
   DEFINE_RECORD_READ_FUNCTION(OBJTYPE, back, FUNCPREFIX, INDEX, SCOPE) \
   DEFINE_RECORD_READ_FUNCTION(OBJTYPE, next, FUNCPREFIX, INDEX, SCOPE) \
   DEFINE_RECORD_READ_FUNCTION(OBJTYPE, previous, FUNCPREFIX, INDEX, SCOPE) \
   DEFINE_RECORD_READ_FUNCTION(OBJTYPE, lower_bound, FUNCPREFIX, INDEX, SCOPE) \
   DEFINE_RECORD_READ_FUNCTION(OBJTYPE, upper_bound, FUNCPREFIX, INDEX, SCOPE)

193 194
DEFINE_RECORD_UPDATE_FUNCTIONS(i64, key_value_index);
DEFINE_RECORD_READ_FUNCTIONS(i64,,key_value_index, by_scope_primary);
M
Matias Romeo 已提交
195
      
196 197 198
DEFINE_RECORD_UPDATE_FUNCTIONS(i128i128, key128x128_value_index);
DEFINE_RECORD_READ_FUNCTIONS(i128i128, primary_,   key128x128_value_index, by_scope_primary);
DEFINE_RECORD_READ_FUNCTIONS(i128i128, secondary_, key128x128_value_index, by_scope_secondary);
M
Matias Romeo 已提交
199

200 201 202 203
DEFINE_RECORD_UPDATE_FUNCTIONS(i64i64i64, key64x64x64_value_index);
DEFINE_RECORD_READ_FUNCTIONS(i64i64i64, primary_,   key64x64x64_value_index, by_scope_primary);
DEFINE_RECORD_READ_FUNCTIONS(i64i64i64, secondary_, key64x64x64_value_index, by_scope_secondary);
DEFINE_RECORD_READ_FUNCTIONS(i64i64i64, tertiary_,  key64x64x64_value_index, by_scope_tertiary);
M
Matias Romeo 已提交
204

M
Matias Romeo 已提交
205 206

#define UPDATE_RECORD_STR(FUNCTION) \
207
  VERIFY_TABLE(str) \
M
Matias Romeo 已提交
208
  auto lambda = [&](apply_context* ctx, std::string* keys, char *data, uint32_t datalen) -> int32_t { \
209
    return ctx->FUNCTION<keystr_value_object>( Name(scope), Name(ctx->code.value), table_name, keys, data, datalen); \
M
Matias Romeo 已提交
210 211 212 213
  }; \
  return validate_str<decltype(lambda)>(keyptr, keylen, valueptr, valuelen, lambda);

#define READ_RECORD_STR(FUNCTION) \
214
  VERIFY_TABLE(str) \
M
Matias Romeo 已提交
215
  auto lambda = [&](apply_context* ctx, std::string* keys, char *data, uint32_t datalen) -> int32_t { \
216
    auto res = ctx->FUNCTION<keystr_value_index, by_scope_primary>( Name(scope), Name(code), table_name, keys, data, datalen); \
M
Matias Romeo 已提交
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
    return res; \
  }; \
  return validate_str<decltype(lambda)>(keyptr, keylen, valueptr, valuelen, lambda);

DEFINE_INTRINSIC_FUNCTION6(env,store_str,store_str,i32,i64,scope,i64,table,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen) {
  UPDATE_RECORD_STR(store_record)
}
DEFINE_INTRINSIC_FUNCTION6(env,update_str,update_str,i32,i64,scope,i64,table,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen) {
  UPDATE_RECORD_STR(update_record)
}
DEFINE_INTRINSIC_FUNCTION4(env,remove_str,remove_str,i32,i64,scope,i64,table,i32,keyptr,i32,keylen) {
  int32_t valueptr=0, valuelen=0;
  UPDATE_RECORD_STR(remove_record)
}

DEFINE_INTRINSIC_FUNCTION7(env,load_str,load_str,i32,i64,scope,i64,code,i64,table,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen) {
  READ_RECORD_STR(load_record)
}
235 236
DEFINE_INTRINSIC_FUNCTION5(env,front_str,front_str,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) {
  int32_t keyptr=0, keylen=0;
M
Matias Romeo 已提交
237 238
  READ_RECORD_STR(front_record)
}
239 240
DEFINE_INTRINSIC_FUNCTION5(env,back_str,back_str,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) {
  int32_t keyptr=0, keylen=0;
M
Matias Romeo 已提交
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
  READ_RECORD_STR(back_record)
}
DEFINE_INTRINSIC_FUNCTION7(env,next_str,next_str,i32,i64,scope,i64,code,i64,table,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen) {
  READ_RECORD_STR(next_record)
}
DEFINE_INTRINSIC_FUNCTION7(env,previous_str,previous_str,i32,i64,scope,i64,code,i64,table,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen) {
  READ_RECORD_STR(previous_record)
}
DEFINE_INTRINSIC_FUNCTION7(env,lower_bound_str,lower_bound_str,i32,i64,scope,i64,code,i64,table,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen) {
  READ_RECORD_STR(lower_bound_record)
}
DEFINE_INTRINSIC_FUNCTION7(env,upper_bound_str,upper_bound_str,i32,i64,scope,i64,code,i64,table,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen) {
  READ_RECORD_STR(upper_bound_record)
}

256 257 258 259 260 261 262 263 264 265
DEFINE_INTRINSIC_FUNCTION3(env, assert_is_utf8,assert_is_utf8,none,i32,dataptr,i32,datalen,i32,msg) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;

  const char* str = &memoryRef<const char>( mem, dataptr );
  const bool test = fc::is_utf8(std::string( str, datalen ));

  FC_ASSERT( test, "assertion failed: ${s}", ("s",msg) );
}

266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
DEFINE_INTRINSIC_FUNCTION3(env, assert_sha256,assert_sha256,none,i32,dataptr,i32,datalen,i32,hash) {
   FC_ASSERT( datalen > 0 );

   auto& wasm  = wasm_interface::get();
   auto  mem          = wasm.current_memory;

   char* data = memoryArrayPtr<char>( mem, dataptr, datalen );
   const auto& v = memoryRef<fc::sha256>( mem, hash );

   auto result = fc::sha256::hash( data, datalen );
   FC_ASSERT( result == v, "hash miss match" );
}

DEFINE_INTRINSIC_FUNCTION3(env,sha256,sha256,none,i32,dataptr,i32,datalen,i32,hash) {
   FC_ASSERT( datalen > 0 );

   auto& wasm  = wasm_interface::get();
   auto  mem          = wasm.current_memory;

   char* data = memoryArrayPtr<char>( mem, dataptr, datalen );
   auto& v = memoryRef<fc::sha256>( mem, hash );
   v  = fc::sha256::hash( data, datalen );
}
289

290 291 292
DEFINE_INTRINSIC_FUNCTION2(env,multeq_i128,multeq_i128,none,i32,self,i32,other) {
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
293 294
   auto& v = memoryRef<unsigned __int128>( mem, self );
   const auto& o = memoryRef<const unsigned __int128>( mem, other );
295 296
   v *= o;
}
297

298
DEFINE_INTRINSIC_FUNCTION2(env,diveq_i128,diveq_i128,none,i32,self,i32,other) {
299
   auto& wasm  = wasm_interface::get();
300
   auto  mem          = wasm.current_memory;
301 302
   auto& v = memoryRef<unsigned __int128>( mem, self );
   const auto& o = memoryRef<const unsigned __int128>( mem, other );
303 304 305
   FC_ASSERT( o != 0, "divide by zero" );
   v /= o;
}
306

M
Matias Romeo 已提交
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
DEFINE_INTRINSIC_FUNCTION2(env,double_add,double_add,i64,i64,a,i64,b) {
   DOUBLE c = DOUBLE(*reinterpret_cast<double *>(&a))
            + DOUBLE(*reinterpret_cast<double *>(&b));
   double res = c.convert_to<double>();
   return *reinterpret_cast<uint64_t *>(&res);
}

DEFINE_INTRINSIC_FUNCTION2(env,double_mult,double_mult,i64,i64,a,i64,b) {
   DOUBLE c = DOUBLE(*reinterpret_cast<double *>(&a))
            * DOUBLE(*reinterpret_cast<double *>(&b));
   double res = c.convert_to<double>();
   return *reinterpret_cast<uint64_t *>(&res);
}

DEFINE_INTRINSIC_FUNCTION2(env,double_div,double_div,i64,i64,a,i64,b) {
   auto 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);
}

DEFINE_INTRINSIC_FUNCTION2(env,double_lt,double_lt,i32,i64,a,i64,b) {
   return DOUBLE(*reinterpret_cast<double *>(&a))
        < DOUBLE(*reinterpret_cast<double *>(&b));
}

DEFINE_INTRINSIC_FUNCTION2(env,double_eq,double_eq,i32,i64,a,i64,b) {
   return DOUBLE(*reinterpret_cast<double *>(&a))
       == DOUBLE(*reinterpret_cast<double *>(&b));
}

DEFINE_INTRINSIC_FUNCTION2(env,double_gt,double_gt,i32,i64,a,i64,b) {
   return DOUBLE(*reinterpret_cast<double *>(&a))
        > DOUBLE(*reinterpret_cast<double *>(&b));
}

DEFINE_INTRINSIC_FUNCTION1(env,double_to_i64,double_to_i64,i64,i64,a) {
   return DOUBLE(*reinterpret_cast<double *>(&a))
          .convert_to<uint64_t>();
}

DEFINE_INTRINSIC_FUNCTION1(env,i64_to_double,i64_to_double,i64,i64,a) {
   double res = DOUBLE(a).convert_to<double>();
   return *reinterpret_cast<uint64_t *>(&res);
}

355
DEFINE_INTRINSIC_FUNCTION2(env,get_active_producers,get_active_producers,none,i32,producers,i32,datalen) {
M
Matias Romeo 已提交
356 357 358 359 360 361
   auto& wasm    = wasm_interface::get();
   auto  mem     = wasm.current_memory;
   types::AccountName* dst = memoryArrayPtr<types::AccountName>( mem, producers, datalen );
   return wasm_interface::get().current_validate_context->get_active_producers(dst, datalen);
}

362 363 364
DEFINE_INTRINSIC_FUNCTION0(env,now,now,i32) {
   return wasm_interface::get().current_validate_context->controller.head_block_time().sec_since_epoch();
}
365

366
DEFINE_INTRINSIC_FUNCTION0(env,current_code,current_code,i64) {
367 368 369 370
   auto& wasm  = wasm_interface::get();
   return wasm.current_validate_context->code.value;
}

371
DEFINE_INTRINSIC_FUNCTION1(env,require_auth,require_auth,none,i64,account) {
372
   wasm_interface::get().current_validate_context->require_authorization( Name(account) );
373
}
374

375
DEFINE_INTRINSIC_FUNCTION1(env,require_notice,require_notice,none,i64,account) {
376
   wasm_interface::get().current_apply_context->require_recipient( account );
377
}
378

379 380 381
DEFINE_INTRINSIC_FUNCTION3(env,memcpy,memcpy,i32,i32,dstp,i32,srcp,i32,len) {
   auto& wasm          = wasm_interface::get();
   auto  mem           = wasm.current_memory;
D
Daniel Larimer 已提交
382 383 384
   char* dst           = memoryArrayPtr<char>( mem, dstp, len);
   const char* src     = memoryArrayPtr<const char>( mem, srcp, len );
   FC_ASSERT( len > 0 );
385 386

   if( dst > src )
D
Daniel Larimer 已提交
387
      FC_ASSERT( dst >= (src + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
388
   else
D
Daniel Larimer 已提交
389 390
      FC_ASSERT( src >= (dst + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );

391 392 393 394
   memcpy( dst, src, uint32_t(len) );
   return dstp;
}

A
Andrianto Lie 已提交
395 396 397 398 399 400 401 402 403 404 405
DEFINE_INTRINSIC_FUNCTION3(env,memcmp,memcmp,i32,i32,dstp,i32,srcp,i32,len) {
   auto& wasm          = wasm_interface::get();
   auto  mem           = wasm.current_memory;
   char* dst           = memoryArrayPtr<char>( mem, dstp, len);
   const char* src     = memoryArrayPtr<const char>( mem, srcp, len );
   FC_ASSERT( len > 0 );

   return memcmp( dst, src, uint32_t(len) );
}


406 407 408 409 410 411 412 413 414 415
DEFINE_INTRINSIC_FUNCTION3(env,memset,memset,i32,i32,rel_ptr,i32,value,i32,len) {
   auto& wasm          = wasm_interface::get();
   auto  mem           = wasm.current_memory;
   char* ptr           = memoryArrayPtr<char>( mem, rel_ptr, len);
   FC_ASSERT( len > 0 );

   memset( ptr, value, len );
   return rel_ptr;
}

B
Brian Johnson 已提交
416 417 418 419 420 421
DEFINE_INTRINSIC_FUNCTION1(env,sbrk,sbrk,i32,i32,num_bytes) {
   auto& wasm          = wasm_interface::get();

   FC_ASSERT( num_bytes >= 0, "sbrk can only allocate memory, not reduce" );
   FC_ASSERT( wasm.current_memory_management != nullptr, "sbrk can only be called during the scope of wasm_interface::vm_call" );
   U32 previous_bytes_allocated = wasm.current_memory_management->sbrk(num_bytes);
422
   checktime(wasm.current_execution_time(), wasm_interface::get().checktime_limit);
B
Brian Johnson 已提交
423 424 425
   return previous_bytes_allocated;
}

426

427
/**
428
 * transaction C API implementation
429 430 431
 * @{
 */ 

432
DEFINE_INTRINSIC_FUNCTION0(env,transaction_create,transaction_create,i32) {
433 434 435 436
   auto& ptrx = wasm_interface::get().current_apply_context->create_pending_transaction();
   return ptrx.handle;
}

437 438 439 440 441 442 443
static void emplace_scope(const Name& scope, std::vector<Name>& scopes) {
   auto i = std::upper_bound( scopes.begin(), scopes.end(), scope);
   if (i == scopes.begin() || *(i - 1) != scope ) {
     scopes.insert(i, scope);
   }
}

444
DEFINE_INTRINSIC_FUNCTION3(env,transaction_require_scope,transaction_require_scope,none,i32,handle,i64,scope,i32,readOnly) {
445 446
   auto& ptrx = wasm_interface::get().current_apply_context->get_pending_transaction(handle);
   if(readOnly == 0) {
447
      emplace_scope(scope, ptrx.scope);
448
   } else {
449
      emplace_scope(scope, ptrx.readscope);
450 451 452 453 454
   }

   ptrx.check_size();
}

455
DEFINE_INTRINSIC_FUNCTION2(env,transaction_add_message,transaction_add_message,none,i32,handle,i32,msg_handle) {
456 457 458 459 460 461
   auto apply_context  = wasm_interface::get().current_apply_context;
   auto& ptrx = apply_context->get_pending_transaction(handle);
   auto& pmsg = apply_context->get_pending_message(msg_handle);
   ptrx.messages.emplace_back(pmsg);
   ptrx.check_size();
   apply_context->release_pending_message(msg_handle);
462 463
}

464
DEFINE_INTRINSIC_FUNCTION1(env,transaction_send,transaction_send,none,i32,handle) {
465 466 467 468 469 470 471 472 473 474
   auto apply_context  = wasm_interface::get().current_apply_context;
   auto& ptrx = apply_context->get_pending_transaction(handle);

   EOS_ASSERT(ptrx.messages.size() > 0, tx_unknown_argument,
      "Attempting to send a transaction with no messages");

   apply_context->deferred_transactions.emplace_back(ptrx);
   apply_context->release_pending_transaction(handle);
}

475
DEFINE_INTRINSIC_FUNCTION1(env,transaction_drop,transaction_drop,none,i32,handle) {
476
   wasm_interface::get().current_apply_context->release_pending_transaction(handle);
477 478
}

479
DEFINE_INTRINSIC_FUNCTION4(env,message_create,message_create,i32,i64,code,i64,type,i32,data,i32,length) {
480 481
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
482
   
483 484
   EOS_ASSERT( length >= 0, tx_unknown_argument,
      "Pushing a message with a negative length" );
485

486
   Bytes payload;
487 488 489 490 491 492 493 494 495 496
   if (length > 0) {
      try {
         // memoryArrayPtr checks that the entire array of bytes is valid and
         // within the bounds of the memory segment so that transactions cannot pass
         // bad values in attempts to read improper memory
         const char* buffer = memoryArrayPtr<const char>( mem, uint32_t(data), uint32_t(length) );
         payload.insert(payload.end(), buffer, buffer + length);
      } catch( const Runtime::Exception& e ) {
         FC_THROW_EXCEPTION(tx_unknown_argument, "Message data is not a valid memory range");
      }
497
   }
498

499
   auto& pmsg = wasm.current_apply_context->create_pending_message(Name(code), Name(type), payload);
500
   return pmsg.handle;
501 502
}

503
DEFINE_INTRINSIC_FUNCTION3(env,message_require_permission,message_require_permission,none,i32,handle,i64,account,i64,permission) {
504
   auto apply_context  = wasm_interface::get().current_apply_context;
505 506 507 508 509
   // if this is not sent from the code account with the permission of "code" then we must
   // presently have the permission to add it, otherwise its a failure
   if (!(account == apply_context->code.value && Name(permission) == Name("code"))) {
      apply_context->require_authorization(Name(account), Name(permission));
   }
510 511
   auto& pmsg = apply_context->get_pending_message(handle);
   pmsg.authorization.emplace_back(Name(account), Name(permission));
D
Daniel Larimer 已提交
512
}
513

514
DEFINE_INTRINSIC_FUNCTION1(env,message_send,message_send,none,i32,handle) {
515
   auto apply_context  = wasm_interface::get().current_apply_context;
516
   auto& pmsg = apply_context->get_pending_message(handle);
517

518 519
   apply_context->inline_messages.emplace_back(pmsg);
   apply_context->release_pending_message(handle);
520 521
}

522
DEFINE_INTRINSIC_FUNCTION1(env,message_drop,message_drop,none,i32,handle) {
523
   wasm_interface::get().current_apply_context->release_pending_message(handle);
524 525 526
}

/**
527
 * @} transaction C API implementation
528
 */ 
529 530 531



532
DEFINE_INTRINSIC_FUNCTION2(env,read_message,read_message,i32,i32,destptr,i32,destsize) {
533
   FC_ASSERT( destsize > 0 );
534

535 536
   wasm_interface& wasm = wasm_interface::get();
   auto  mem   = wasm.current_memory;
537
   char* begin = memoryArrayPtr<char>( mem, destptr, uint32_t(destsize) );
538 539

   int minlen = std::min<int>(wasm.current_validate_context->msg.data.size(), destsize);
540

D
Daniel Larimer 已提交
541
//   wdump((destsize)(wasm.current_validate_context->msg.data.size()));
542 543 544 545
   memcpy( begin, wasm.current_validate_context->msg.data.data(), minlen );
   return minlen;
}

546
DEFINE_INTRINSIC_FUNCTION2(env,assert,assert,none,i32,test,i32,msg) {
547 548
   const char* m = &Runtime::memoryRef<char>( wasm_interface::get().current_memory, msg );
  std::string message( m );
549
  if( !test ) edump((message));
550
  FC_ASSERT( test, "assertion failed: ${s}", ("s",message)("ptr",msg) );
551
}
552

553
DEFINE_INTRINSIC_FUNCTION0(env,message_size,message_size,i32) {
554 555 556
   return wasm_interface::get().current_validate_context->msg.data.size();
}

557
DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
558 559 560 561 562 563 564 565
   FC_ASSERT( size > 0 );
   int32_t& end = Runtime::memoryRef<int32_t>( Runtime::getDefaultMemory(wasm_interface::get().current_module), 0);
   int32_t old_end = end;
   end += 8*((size+7)/8);
   FC_ASSERT( end > old_end );
   return old_end;
}

566
DEFINE_INTRINSIC_FUNCTION1(env,printi,printi,none,i64,val) {
567
  std::cerr << uint64_t(val);
568
}
M
Matias Romeo 已提交
569 570 571
DEFINE_INTRINSIC_FUNCTION1(env,printd,printd,none,i64,val) {
  std::cerr << DOUBLE(*reinterpret_cast<double *>(&val));
}
572

573 574 575
DEFINE_INTRINSIC_FUNCTION1(env,printi128,printi128,none,i32,val) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;
576 577 578
  auto& value = memoryRef<unsigned __int128>( mem, val );
  fc::uint128_t v(value>>64, uint64_t(value) );
  std::cerr << fc::variant(v).get_string();
579 580 581
}
DEFINE_INTRINSIC_FUNCTION1(env,printn,printn,none,i64,val) {
  std::cerr << Name(val).toString();
582
}
583

584
DEFINE_INTRINSIC_FUNCTION1(env,prints,prints,none,i32,charptr) {
585 586 587
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;

588
  const char* str = &memoryRef<const char>( mem, charptr );
589

D
Daniel Larimer 已提交
590
  std::cerr << std::string( str, strnlen(str, wasm.current_state->mem_end-charptr) );
591 592
}

A
Andrianto Lie 已提交
593 594 595 596 597 598 599 600 601
DEFINE_INTRINSIC_FUNCTION2(env,prints_l,prints_l,none,i32,charptr,i32,len) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;

  const char* str = &memoryRef<const char>( mem, charptr );

  std::cerr << std::string( str, len );
}

M
Matias Romeo 已提交
602 603 604
DEFINE_INTRINSIC_FUNCTION2(env,printhex,printhex,none,i32,data,i32,datalen) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;
A
Andrianto Lie 已提交
605

M
Matias Romeo 已提交
606 607 608 609 610
  char* buff = memoryArrayPtr<char>(mem, data, datalen);
  std::cerr << fc::to_hex(buff, datalen) << std::endl;
}


611
DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
612 613 614 615
}

   wasm_interface& wasm_interface::get() {
      static wasm_interface*  wasm = nullptr;
616
      if( !wasm )
617 618
      {
         wlog( "Runtime::init" );
619
         Runtime::init();
620 621 622 623 624 625 626 627 628 629 630 631 632
         wasm = new wasm_interface();
      }
      return *wasm;
   }



   struct RootResolver : Runtime::Resolver
   {
      std::map<std::string,Resolver*> moduleNameToResolverMap;

     bool resolve(const std::string& moduleName,const std::string& exportName,ObjectType type,ObjectInstance*& outObject) override
     {
633 634 635 636
         // Try to resolve an intrinsic first.
         if(IntrinsicResolver::singleton.resolve(moduleName,exportName,type,outObject)) { return true; }
         FC_ASSERT( !"unresolvable", "${module}.${export}", ("module",moduleName)("export",exportName) );
         return false;
637 638 639
     }
   };

640 641 642 643 644
   int64_t wasm_interface::current_execution_time()
   {
      return (fc::time_point::now() - checktimeStart).count();
   }

645 646

   char* wasm_interface::vm_allocate( int bytes ) {
647 648
      FunctionInstance* alloc_function = asFunctionNullable(getInstanceExport(current_module,"alloc"));
      const FunctionType* functionType = getFunctionType(alloc_function);
649
      FC_ASSERT( functionType->parameters.size() == 1 );
650
      std::vector<Value> invokeArgs(1);
651 652
      invokeArgs[0] = U32(bytes);

653
      checktimeStart = fc::time_point::now();
654

655 656 657 658 659 660 661 662 663
      auto result = Runtime::invokeFunction(alloc_function,invokeArgs);

      return &memoryRef<char>( current_memory, result.i32 );
   }

   U32 wasm_interface::vm_pointer_to_offset( char* ptr ) {
      return U32(ptr - &memoryRef<char>(current_memory,0));
   }

D
Daniel Larimer 已提交
664
   void  wasm_interface::vm_call( const char* name ) {
665
   try {
B
Brian Johnson 已提交
666
      std::unique_ptr<wasm_memory> wasm_memory_mgmt;
667
      try {
D
Daniel Larimer 已提交
668
         /*
669
         name += "_" + std::string( current_validate_context->msg.code ) + "_";
670
         name += std::string( current_validate_context->msg.type );
D
Daniel Larimer 已提交
671 672 673
         */
         /// TODO: cache this somehow
         FunctionInstance* call = asFunctionNullable(getInstanceExport(current_module,name) );
674 675 676 677
         if( !call ) {
            //wlog( "unable to find call ${name}", ("name",name));
            return;
         }
D
Daniel Larimer 已提交
678
         //FC_ASSERT( apply, "no entry point found for ${call}", ("call", std::string(name))  );
679

D
Daniel Larimer 已提交
680
         FC_ASSERT( getFunctionType(call)->parameters.size() == 2 );
681

D
Daniel Larimer 已提交
682
  //       idump((current_validate_context->msg.code)(current_validate_context->msg.type)(current_validate_context->code));
683
         std::vector<Value> args = { Value(uint64_t(current_validate_context->msg.code)),
D
Daniel Larimer 已提交
684
                                     Value(uint64_t(current_validate_context->msg.type)) };
685 686 687 688 689 690

         auto& state = *current_state;
         char* memstart = &memoryRef<char>( current_memory, 0 );
         memset( memstart + state.mem_end, 0, ((1<<16) - state.mem_end) );
         memcpy( memstart, state.init_memory.data(), state.mem_end);

691
         checktimeStart = fc::time_point::now();
B
Brian Johnson 已提交
692
         wasm_memory_mgmt.reset(new wasm_memory(*this));
693

D
Daniel Larimer 已提交
694
         Runtime::invokeFunction(call,args);
B
Brian Johnson 已提交
695
         wasm_memory_mgmt.reset();
696
         checktime(current_execution_time(), checktime_limit);
697 698
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
699 700
          edump((e.callStack));
          throw;
701
      }
702 703
   } FC_CAPTURE_AND_RETHROW( (name)(current_validate_context->msg.type) ) }

D
Daniel Larimer 已提交
704
   void  wasm_interface::vm_apply()        { vm_call("apply" );          }
705

706
   void  wasm_interface::vm_onInit()
707 708
   { try {
      try {
709 710
            FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"init"));
            if( !apply ) {
711
               elog( "no onInit method found" );
712
               return; /// if not found then it is a no-op
713
            }
714

715
         checktimeStart = fc::time_point::now();
716

717 718
            const FunctionType* functionType = getFunctionType(apply);
            FC_ASSERT( functionType->parameters.size() == 0 );
719

720
            std::vector<Value> args(0);
721

722
            Runtime::invokeFunction(apply,args);
723 724
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
725 726
          edump((e.callStack));
          throw;
727
      }
728
   } FC_CAPTURE_AND_RETHROW() }
729

730
   void wasm_interface::validate( apply_context& c ) {
D
Daniel Larimer 已提交
731
      /*
732 733 734 735
      current_validate_context       = &c;
      current_precondition_context   = nullptr;
      current_apply_context          = nullptr;

D
Daniel Larimer 已提交
736
      load( c.code, c.db );
737
      vm_validate();
D
Daniel Larimer 已提交
738
      */
739
   }
740
   void wasm_interface::precondition( apply_context& c ) {
741 742
   try {

D
Daniel Larimer 已提交
743
      /*
744 745 746
      current_validate_context       = &c;
      current_precondition_context   = &c;

D
Daniel Larimer 已提交
747
      load( c.code, c.db );
748
      vm_precondition();
D
Daniel Larimer 已提交
749
      */
750 751

   } FC_CAPTURE_AND_RETHROW() }
752 753


754
   void wasm_interface::apply( apply_context& c, uint32_t execution_time, bool received_block ) {
755
    try {
756 757 758
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;
759
      checktime_limit                = execution_time;
760

D
Daniel Larimer 已提交
761
      load( c.code, c.db );
762 763 764 765
      // if this is a received_block, then ignore the table_key_types
      if (received_block)
         table_key_types = nullptr;

766 767 768 769 770 771
      vm_apply();

   } FC_CAPTURE_AND_RETHROW() }

   void wasm_interface::init( apply_context& c ) {
    try {
772 773 774
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;
775
      checktime_limit                = CHECKTIME_LIMIT;
776

D
Daniel Larimer 已提交
777
      load( c.code, c.db );
778
      vm_onInit();
779 780 781

   } FC_CAPTURE_AND_RETHROW() }

782

783

784 785
   void wasm_interface::load( const AccountName& name, const chainbase::database& db ) {
      const auto& recipient = db.get<account_object,by_name>( name );
786
  //    idump(("recipient")(Name(name))(recipient.code_version));
787 788 789

      auto& state = instances[name];
      if( state.code_version != recipient.code_version ) {
790 791
        if( state.instance ) {
           /// TODO: free existing instance and module
792
#warning TODO: free existing module if the code has been updated, currently leak memory
793 794 795 796 797 798
           state.instance     = nullptr;
           state.module       = nullptr;
           state.code_version = fc::sha256();
        }
        state.module = new IR::Module();
        state.table_key_types.clear();
799 800 801

        try
        {
802 803
//          wlog( "LOADING CODE" );
 //         auto start = fc::time_point::now();
804
          Serialization::MemoryInputStream stream((const U8*)recipient.code.data(),recipient.code.size());
805
          WASM::serializeWithInjection(stream,*state.module);
806 807 808 809 810

          RootResolver rootResolver;
          LinkResult linkResult = linkModule(*state.module,rootResolver);
          state.instance = instantiateModule( *state.module, std::move(linkResult.resolvedImports) );
          FC_ASSERT( state.instance );
811 812
  //        auto end = fc::time_point::now();
 //         idump(( (end-start).count()/1000000.0) );
813

814
          current_memory = Runtime::getDefaultMemory(state.instance);
815
            
816
          char* memstart = &memoryRef<char>( current_memory, 0 );
817
         // state.init_memory.resize(1<<16); /// TODO: actually get memory size
818 819 820 821 822 823 824 825
          const auto allocated_memory = Runtime::getDefaultMemorySize(state.instance);
          for( uint64_t i = 0; i < allocated_memory; ++i )
          {
             if( memstart[i] )
             {
                state.mem_end = i+1;
             }
          }
826
          //ilog( "INIT MEMORY: ${size}", ("size", state.mem_end) );
827 828 829

          state.init_memory.resize(state.mem_end);
          memcpy( state.init_memory.data(), memstart, state.mem_end ); //state.init_memory.size() );
830
          //std::cerr <<"\n";
831
          state.code_version = recipient.code_version;
832
//          idump((state.code_version));
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847

          types::Abi abi;
          if( types::AbiSerializer::to_abi(recipient.abi, abi) )
          {
             state.tables_fixed = true;
             for(auto& table : abi.tables)
             {
                const auto key_type = to_key_type(table.indextype);
                if (key_type == invalid_key_type)
                   throw Serialization::FatalSerializationException("For code \"" + (std::string)name + "\" indextype of \"" +
                                                                    table.indextype + "\" referenced but not supported");

                state.table_key_types.emplace(std::make_pair(table.table, key_type));
             }
          }
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
        }
        catch(Serialization::FatalSerializationException exception)
        {
          std::cerr << "Error deserializing WebAssembly binary file:" << std::endl;
          std::cerr << exception.message << std::endl;
          throw;
        }
        catch(IR::ValidationException exception)
        {
          std::cerr << "Error validating WebAssembly binary file:" << std::endl;
          std::cerr << exception.message << std::endl;
          throw;
        }
        catch(std::bad_alloc)
        {
          std::cerr << "Memory allocation failed: input is likely malformed" << std::endl;
          throw;
        }
      }
867 868 869 870 871
      current_module  = state.instance;
      current_memory  = getDefaultMemory( current_module );
      current_state   = &state;
      table_key_types = &state.table_key_types;
      tables_fixed    = state.tables_fixed;
872
   }
873

B
Brian Johnson 已提交
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
   wasm_memory::wasm_memory(wasm_interface& interface)
   : _wasm_interface(interface)
   , _num_pages(Runtime::getMemoryNumPages(interface.current_memory))
   , _min_bytes(limit_32bit_address(_num_pages << numBytesPerPageLog2))
   {
      _wasm_interface.current_memory_management = this;
      _num_bytes = _min_bytes;
   }

   wasm_memory::~wasm_memory()
   {
      if (_num_bytes > _min_bytes)
         sbrk((I32)_min_bytes - (I32)_num_bytes);

      _wasm_interface.current_memory_management = nullptr;
   }

   U32 wasm_memory::sbrk(I32 num_bytes)
   {
      const U32 previous_num_bytes = _num_bytes;
      if(Runtime::getMemoryNumPages(_wasm_interface.current_memory) != _num_pages)
P
Pravin 已提交
895
         throw eosio::chain::page_memory_error();
B
Brian Johnson 已提交
896 897 898 899

      // Round the absolute value of num_bytes to an alignment boundary, and ensure it won't allocate too much or too little memory.
      num_bytes = (num_bytes + 7) & ~7;
      if(num_bytes > 0 && previous_num_bytes > _max_memory - num_bytes)
P
Pravin 已提交
900
         throw eosio::chain::page_memory_error();
B
Brian Johnson 已提交
901
      else if(num_bytes < 0 && previous_num_bytes < _min_bytes - num_bytes)
P
Pravin 已提交
902
         throw eosio::chain::page_memory_error();
B
Brian Johnson 已提交
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923

      // Update the number of bytes allocated, and compute the number of pages needed for it.
      _num_bytes += num_bytes;
      const Uptr num_desired_pages = (_num_bytes + IR::numBytesPerPage - 1) >> IR::numBytesPerPageLog2;

      // Grow or shrink the memory object to the desired number of pages.
      if(num_desired_pages > _num_pages)
         Runtime::growMemory(_wasm_interface.current_memory, num_desired_pages - _num_pages);
      else if(num_desired_pages < _num_pages)
         Runtime::shrinkMemory(_wasm_interface.current_memory, _num_pages - num_desired_pages);

      _num_pages = num_desired_pages;

      return previous_num_bytes;
   }

   U32 wasm_memory::limit_32bit_address(Uptr address)
   {
      return (U32)(address > UINT32_MAX ? UINT32_MAX : address);
   }

924
} }