wasm_interface.cpp 24.3 KB
Newer Older
1
#include <boost/function.hpp>
2
#include <boost/multiprecision/cpp_bin_float.hpp>
3
#include <eos/chain/wasm_interface.hpp>
4
#include <eos/chain/chain_controller.hpp>
5 6 7 8 9 10 11 12 13
#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>
14
#include <eos/chain/account_object.hpp>
15
#include <chrono>
16 17 18 19

namespace eos { namespace chain {
   using namespace IR;
   using namespace Runtime;
20
   typedef boost::multiprecision::cpp_bin_float_50 DOUBLE;
21

22 23 24
   wasm_interface::wasm_interface() {
   }

25
#ifdef NDEBUG
26
   const int CHECKTIME_LIMIT = 3000;
27
#else
28
   const int CHECKTIME_LIMIT = 18000;
29 30
#endif

31
DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) {
32 33 34
   auto dur = wasm_interface::get().current_execution_time();
   if (dur > CHECKTIME_LIMIT) {
      wlog("checktime called ${d}", ("d", dur));
35 36 37
      throw checktime_exceeded();
   }
}
38 39
   template <typename Function, typename KeyType, int numberOfKeys>
   int32_t validate(int32_t valueptr, int32_t valuelen, Function func) {
40
      
41
      static const uint32_t keylen = numberOfKeys*sizeof(KeyType);
42 43 44 45
      
      FC_ASSERT( valuelen >= keylen, "insufficient data passed" );

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

      char* value = memoryArrayPtr<char>( wasm.current_memory, valueptr, valuelen );
49
      KeyType*  keys = reinterpret_cast<KeyType*>(value);
50 51 52 53
      
      valuelen -= keylen;
      value    += keylen;

54
      return func(wasm.current_apply_context, keys, value, valuelen);
M
Matias Romeo 已提交
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
#define READ_RECORD(READFUNC, INDEX, SCOPE) \
   auto lambda = [&](apply_context* ctx, INDEX::value_type::key_type* keys, char *data, uint32_t datalen) -> int32_t { \
      auto res = ctx->READFUNC<INDEX, SCOPE>( Name(scope), Name(code), Name(table), keys, data, datalen); \
      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 { \
      return ctx->UPDATEFUNC<INDEX::value_type>( Name(scope), Name(ctx->code.value), Name(table), keys, data, datalen); \
   }; \
   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) { \
      UPDATE_RECORD(store_record, INDEX, valuelen); \
   } \
   DEFINE_INTRINSIC_FUNCTION4(env,update_##OBJTYPE,update_##OBJTYPE,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { \
      UPDATE_RECORD(update_record, INDEX, valuelen); \
   } \
   DEFINE_INTRINSIC_FUNCTION3(env,remove_##OBJTYPE,remove_##OBJTYPE,i32,i64,scope,i64,table,i32,valueptr) { \
      UPDATE_RECORD(remove_record, INDEX, sizeof(typename INDEX::value_type::key_type)*INDEX::value_type::number_of_keys); \
80
   }
M
Matias Romeo 已提交
81

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
#define DEFINE_RECORD_READ_FUNCTIONS(OBJTYPE, FUNCPREFIX, INDEX, SCOPE) \
   DEFINE_INTRINSIC_FUNCTION5(env,load_##FUNCPREFIX##OBJTYPE,load_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(load_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,front_##FUNCPREFIX##OBJTYPE,front_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(front_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,back_##FUNCPREFIX##OBJTYPE,back_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(back_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,next_##FUNCPREFIX##OBJTYPE,next_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(next_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,previous_##FUNCPREFIX##OBJTYPE,previous_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(previous_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,lower_bound_##FUNCPREFIX##OBJTYPE,lower_bound_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(lower_bound_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,upper_bound_##FUNCPREFIX##OBJTYPE,upper_bound_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(upper_bound_record, INDEX, SCOPE); \
   }
M
Matias Romeo 已提交
104

105 106
DEFINE_RECORD_UPDATE_FUNCTIONS(i64, key_value_index);
DEFINE_RECORD_READ_FUNCTIONS(i64,,key_value_index, by_scope_primary);
M
Matias Romeo 已提交
107

108 109 110
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 已提交
111

112 113 114 115
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 已提交
116

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
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 );
}
140

141 142 143
DEFINE_INTRINSIC_FUNCTION2(env,multeq_i128,multeq_i128,none,i32,self,i32,other) {
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
144 145
   auto& v = memoryRef<unsigned __int128>( mem, self );
   const auto& o = memoryRef<const unsigned __int128>( mem, other );
146 147
   v *= o;
}
148

149
DEFINE_INTRINSIC_FUNCTION2(env,diveq_i128,diveq_i128,none,i32,self,i32,other) {
150
   auto& wasm  = wasm_interface::get();
151
   auto  mem          = wasm.current_memory;
152 153
   auto& v = memoryRef<unsigned __int128>( mem, self );
   const auto& o = memoryRef<const unsigned __int128>( mem, other );
154 155 156
   FC_ASSERT( o != 0, "divide by zero" );
   v /= o;
}
157

M
Matias Romeo 已提交
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
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);
}

206 207 208
DEFINE_INTRINSIC_FUNCTION0(env,now,now,i32) {
   return wasm_interface::get().current_validate_context->controller.head_block_time().sec_since_epoch();
}
209

210 211 212 213 214 215
DEFINE_INTRINSIC_FUNCTION0(env,currentCode,currentCode,i64) {
   auto& wasm  = wasm_interface::get();
   return wasm.current_validate_context->code.value;
}

DEFINE_INTRINSIC_FUNCTION1(env,requireAuth,requireAuth,none,i64,account) {
216
   wasm_interface::get().current_validate_context->require_authorization( Name(account) );
217
}
218

219
DEFINE_INTRINSIC_FUNCTION1(env,requireNotice,requireNotice,none,i64,account) {
220
   wasm_interface::get().current_apply_context->require_recipient( account );
221
}
222

223
DEFINE_INTRINSIC_FUNCTION1(env,requireScope,requireScope,none,i64,scope) {
224
   wasm_interface::get().current_validate_context->require_scope( scope );
225 226 227 228 229
}

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 已提交
230 231 232
   char* dst           = memoryArrayPtr<char>( mem, dstp, len);
   const char* src     = memoryArrayPtr<const char>( mem, srcp, len );
   FC_ASSERT( len > 0 );
233 234

   if( dst > src )
D
Daniel Larimer 已提交
235
      FC_ASSERT( dst >= (src + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
236
   else
D
Daniel Larimer 已提交
237 238
      FC_ASSERT( src >= (dst + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );

239 240 241 242
   memcpy( dst, src, uint32_t(len) );
   return dstp;
}

243 244 245 246 247 248 249 250 251 252
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;
}

253

254 255 256 257 258 259 260 261 262 263
/**
 * Transaction C API implementation
 * @{
 */ 

DEFINE_INTRINSIC_FUNCTION0(env,transactionCreate,transactionCreate,i32) {
   auto& ptrx = wasm_interface::get().current_apply_context->create_pending_transaction();
   return ptrx.handle;
}

264 265 266 267 268 269 270
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);
   }
}

271
DEFINE_INTRINSIC_FUNCTION3(env,transactionRequireScope,transactionRequireScope,none,i32,handle,i64,scope,i32,readOnly) {
272 273
   auto& ptrx = wasm_interface::get().current_apply_context->get_pending_transaction(handle);
   if(readOnly == 0) {
274
      emplace_scope(scope, ptrx.scope);
275
   } else {
276
      emplace_scope(scope, ptrx.readscope);
277 278 279 280 281
   }

   ptrx.check_size();
}

282 283 284 285 286 287 288
DEFINE_INTRINSIC_FUNCTION2(env,transactionAddMessage,transactionAddMessage,none,i32,handle,i32,msg_handle) {
   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);
289 290
}

291 292 293 294 295 296 297 298 299 300 301 302 303
DEFINE_INTRINSIC_FUNCTION1(env,transactionSend,transactionSend,none,i32,handle) {
   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);
}

DEFINE_INTRINSIC_FUNCTION1(env,transactionDrop,transactionDrop,none,i32,handle) {
   wasm_interface::get().current_apply_context->release_pending_transaction(handle);
304 305
}

306
DEFINE_INTRINSIC_FUNCTION4(env,messageCreate,messageCreate,i32,i64,code,i64,type,i32,data,i32,length) {
307 308
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
309
   
310 311
   EOS_ASSERT( length >= 0, tx_unknown_argument,
      "Pushing a message with a negative length" );
312

313
   Bytes payload;
314 315 316 317 318 319 320 321 322 323
   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");
      }
324
   }
325

326
   auto& pmsg = wasm.current_apply_context->create_pending_message(Name(code), Name(type), payload);
327
   return pmsg.handle;
328 329
}

330 331
DEFINE_INTRINSIC_FUNCTION3(env,messageRequirePermission,messageRequirePermission,none,i32,handle,i64,account,i64,permission) {
   auto apply_context  = wasm_interface::get().current_apply_context;
332 333 334 335 336
   // 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));
   }
337 338
   auto& pmsg = apply_context->get_pending_message(handle);
   pmsg.authorization.emplace_back(Name(account), Name(permission));
D
Daniel Larimer 已提交
339
}
340

341
DEFINE_INTRINSIC_FUNCTION1(env,messageSend,messageSend,none,i32,handle) {
342
   auto apply_context  = wasm_interface::get().current_apply_context;
343
   auto& pmsg = apply_context->get_pending_message(handle);
344

345 346
   apply_context->inline_messages.emplace_back(pmsg);
   apply_context->release_pending_message(handle);
347 348
}

349 350
DEFINE_INTRINSIC_FUNCTION1(env,messageDrop,messageDrop,none,i32,handle) {
   wasm_interface::get().current_apply_context->release_pending_message(handle);
351 352 353 354 355
}

/**
 * @} Transaction C API implementation
 */ 
356 357 358



359 360
DEFINE_INTRINSIC_FUNCTION2(env,readMessage,readMessage,i32,i32,destptr,i32,destsize) {
   FC_ASSERT( destsize > 0 );
361

362 363
   wasm_interface& wasm = wasm_interface::get();
   auto  mem   = wasm.current_memory;
364
   char* begin = memoryArrayPtr<char>( mem, destptr, uint32_t(destsize) );
365 366

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

D
Daniel Larimer 已提交
368
//   wdump((destsize)(wasm.current_validate_context->msg.data.size()));
369 370 371 372
   memcpy( begin, wasm.current_validate_context->msg.data.data(), minlen );
   return minlen;
}

373
DEFINE_INTRINSIC_FUNCTION2(env,assert,assert,none,i32,test,i32,msg) {
374 375
   const char* m = &Runtime::memoryRef<char>( wasm_interface::get().current_memory, msg );
  std::string message( m );
376
  if( !test ) edump((message));
377
  FC_ASSERT( test, "assertion failed: ${s}", ("s",message)("ptr",msg) );
378
}
379

380 381 382 383
DEFINE_INTRINSIC_FUNCTION0(env,messageSize,messageSize,i32) {
   return wasm_interface::get().current_validate_context->msg.data.size();
}

384
DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
385 386 387 388 389 390 391 392
   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;
}

393
DEFINE_INTRINSIC_FUNCTION1(env,printi,printi,none,i64,val) {
394
  std::cerr << uint64_t(val);
395
}
M
Matias Romeo 已提交
396 397 398
DEFINE_INTRINSIC_FUNCTION1(env,printd,printd,none,i64,val) {
  std::cerr << DOUBLE(*reinterpret_cast<double *>(&val));
}
399

400 401 402
DEFINE_INTRINSIC_FUNCTION1(env,printi128,printi128,none,i32,val) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;
403 404 405
  auto& value = memoryRef<unsigned __int128>( mem, val );
  fc::uint128_t v(value>>64, uint64_t(value) );
  std::cerr << fc::variant(v).get_string();
406 407 408
}
DEFINE_INTRINSIC_FUNCTION1(env,printn,printn,none,i64,val) {
  std::cerr << Name(val).toString();
409
}
410

411
DEFINE_INTRINSIC_FUNCTION1(env,prints,prints,none,i32,charptr) {
412 413 414
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;

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

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

420
DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
421 422 423 424
}

   wasm_interface& wasm_interface::get() {
      static wasm_interface*  wasm = nullptr;
425
      if( !wasm )
426 427
      {
         wlog( "Runtime::init" );
428
         Runtime::init();
429 430 431 432 433 434 435 436 437 438 439 440 441
         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
     {
442 443 444 445
         // 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;
446 447 448
     }
   };

449 450 451 452 453
   int64_t wasm_interface::current_execution_time()
   {
      return (fc::time_point::now() - checktimeStart).count();
   }

454 455

   char* wasm_interface::vm_allocate( int bytes ) {
456 457
      FunctionInstance* alloc_function = asFunctionNullable(getInstanceExport(current_module,"alloc"));
      const FunctionType* functionType = getFunctionType(alloc_function);
458
      FC_ASSERT( functionType->parameters.size() == 1 );
459
      std::vector<Value> invokeArgs(1);
460 461
      invokeArgs[0] = U32(bytes);

462
      checktimeStart = fc::time_point::now();
463

464 465 466 467 468 469 470 471 472
      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 已提交
473
   void  wasm_interface::vm_call( const char* name ) {
474
   try {
475
      try {
D
Daniel Larimer 已提交
476
         /*
477
         name += "_" + std::string( current_validate_context->msg.code ) + "_";
478
         name += std::string( current_validate_context->msg.type );
D
Daniel Larimer 已提交
479 480 481
         */
         /// TODO: cache this somehow
         FunctionInstance* call = asFunctionNullable(getInstanceExport(current_module,name) );
482 483 484 485
         if( !call ) {
            //wlog( "unable to find call ${name}", ("name",name));
            return;
         }
D
Daniel Larimer 已提交
486
         //FC_ASSERT( apply, "no entry point found for ${call}", ("call", std::string(name))  );
487

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

D
Daniel Larimer 已提交
490
  //       idump((current_validate_context->msg.code)(current_validate_context->msg.type)(current_validate_context->code));
491
         std::vector<Value> args = { Value(uint64_t(current_validate_context->msg.code)),
D
Daniel Larimer 已提交
492
                                     Value(uint64_t(current_validate_context->msg.type)) };
493 494 495 496 497 498

         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);

499
         checktimeStart = fc::time_point::now();
500

D
Daniel Larimer 已提交
501
         Runtime::invokeFunction(call,args);
502 503
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
504 505
          edump((e.callStack));
          throw;
506
      }
507 508
   } FC_CAPTURE_AND_RETHROW( (name)(current_validate_context->msg.type) ) }

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

511
   void  wasm_interface::vm_onInit()
512 513
   { try {
      try {
514 515
            FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"init"));
            if( !apply ) {
516
               elog( "no onInit method found" );
517
               return; /// if not found then it is a no-op
518
            }
519

520
         checktimeStart = fc::time_point::now();
521

522 523
            const FunctionType* functionType = getFunctionType(apply);
            FC_ASSERT( functionType->parameters.size() == 0 );
524

525
            std::vector<Value> args(0);
526

527
            Runtime::invokeFunction(apply,args);
528 529
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
530 531
          edump((e.callStack));
          throw;
532
      }
533
   } FC_CAPTURE_AND_RETHROW() }
534

535
   void wasm_interface::validate( apply_context& c ) {
D
Daniel Larimer 已提交
536
      /*
537 538 539 540
      current_validate_context       = &c;
      current_precondition_context   = nullptr;
      current_apply_context          = nullptr;

D
Daniel Larimer 已提交
541
      load( c.code, c.db );
542
      vm_validate();
D
Daniel Larimer 已提交
543
      */
544
   }
545
   void wasm_interface::precondition( apply_context& c ) {
546 547
   try {

D
Daniel Larimer 已提交
548
      /*
549 550 551
      current_validate_context       = &c;
      current_precondition_context   = &c;

D
Daniel Larimer 已提交
552
      load( c.code, c.db );
553
      vm_precondition();
D
Daniel Larimer 已提交
554
      */
555 556

   } FC_CAPTURE_AND_RETHROW() }
557 558


559 560
   void wasm_interface::apply( apply_context& c ) {
    try {
561 562 563 564
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
565
      load( c.code, c.db );
566 567 568 569 570 571
      vm_apply();

   } FC_CAPTURE_AND_RETHROW() }

   void wasm_interface::init( apply_context& c ) {
    try {
572 573 574 575
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
576
      load( c.code, c.db );
577
      vm_onInit();
578 579 580

   } FC_CAPTURE_AND_RETHROW() }

581

582

583 584
   void wasm_interface::load( const AccountName& name, const chainbase::database& db ) {
      const auto& recipient = db.get<account_object,by_name>( name );
585
  //    idump(("recipient")(Name(name))(recipient.code_version));
586 587 588 589 590 591 592 593

      auto& state = instances[name];
      if( state.code_version != recipient.code_version ) {
         if( state.instance ) {
            /// TODO: free existing instance and module
#warning TODO: free existing module if the code has been updated, currently leak memory
            state.instance     = nullptr;
            state.module       = nullptr;
594
            state.code_version = fc::sha256();
595 596 597 598 599
         }
         state.module = new IR::Module();

        try
        {
600 601
//          wlog( "LOADING CODE" );
 //         auto start = fc::time_point::now();
602
          Serialization::MemoryInputStream stream((const U8*)recipient.code.data(),recipient.code.size());
603
          WASM::serializeWithInjection(stream,*state.module);
604 605 606 607 608

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

612
          current_memory = Runtime::getDefaultMemory(state.instance);
613
            
614
          char* memstart = &memoryRef<char>( current_memory, 0 );
615
         // state.init_memory.resize(1<<16); /// TODO: actually get memory size
616
          for( uint32_t i = 0; i < 10000; ++i )
617
              if( memstart[i] ) {
618
                   state.mem_end = i+1;
619
                   //std::cerr << (char)memstart[i];
620
              }
621
          //ilog( "INIT MEMORY: ${size}", ("size", state.mem_end) );
622 623 624

          state.init_memory.resize(state.mem_end);
          memcpy( state.init_memory.data(), memstart, state.mem_end ); //state.init_memory.size() );
625
          //std::cerr <<"\n";
626
          state.code_version = recipient.code_version;
627
//          idump((state.code_version));
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
        }
        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;
        }
      }
      current_module = state.instance;
      current_memory = getDefaultMemory( current_module );
649
      current_state  = &state;
650
   }
651 652

} }