wasm_interface.cpp 27.9 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) {
M
Matias Romeo 已提交
40

41
      static const uint32_t keylen = numberOfKeys*sizeof(KeyType);
M
Matias Romeo 已提交
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
   }

M
Matias Romeo 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
   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);
   }


72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
#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); \
95
   }
M
Matias Romeo 已提交
96

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
#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 已提交
119

120 121
DEFINE_RECORD_UPDATE_FUNCTIONS(i64, key_value_index);
DEFINE_RECORD_READ_FUNCTIONS(i64,,key_value_index, by_scope_primary);
M
Matias Romeo 已提交
122
      
123 124 125
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 已提交
126

127 128 129 130
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 已提交
131

M
Matias Romeo 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

#define UPDATE_RECORD_STR(FUNCTION) \
  auto lambda = [&](apply_context* ctx, std::string* keys, char *data, uint32_t datalen) -> int32_t { \
    return ctx->FUNCTION<keystr_value_object>( Name(scope), Name(ctx->code.value), Name(table), keys, data, datalen); \
  }; \
  return validate_str<decltype(lambda)>(keyptr, keylen, valueptr, valuelen, lambda);

#define READ_RECORD_STR(FUNCTION) \
  auto lambda = [&](apply_context* ctx, std::string* keys, char *data, uint32_t datalen) -> int32_t { \
    auto res = ctx->FUNCTION<keystr_value_index, by_scope_primary>( Name(scope), Name(code), Name(table), keys, data, datalen); \
    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)
}
160 161
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 已提交
162 163
  READ_RECORD_STR(front_record)
}
164 165
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 已提交
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
  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)
}

181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
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 );
}
204

205 206 207
DEFINE_INTRINSIC_FUNCTION2(env,multeq_i128,multeq_i128,none,i32,self,i32,other) {
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
208 209
   auto& v = memoryRef<unsigned __int128>( mem, self );
   const auto& o = memoryRef<const unsigned __int128>( mem, other );
210 211
   v *= o;
}
212

213
DEFINE_INTRINSIC_FUNCTION2(env,diveq_i128,diveq_i128,none,i32,self,i32,other) {
214
   auto& wasm  = wasm_interface::get();
215
   auto  mem          = wasm.current_memory;
216 217
   auto& v = memoryRef<unsigned __int128>( mem, self );
   const auto& o = memoryRef<const unsigned __int128>( mem, other );
218 219 220
   FC_ASSERT( o != 0, "divide by zero" );
   v /= o;
}
221

M
Matias Romeo 已提交
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
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);
}

M
Matias Romeo 已提交
270 271 272 273 274 275 276
DEFINE_INTRINSIC_FUNCTION2(env,getActiveProducers,getActiveProducers,none,i32,producers,i32,datalen) {
   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);
}

277 278 279
DEFINE_INTRINSIC_FUNCTION0(env,now,now,i32) {
   return wasm_interface::get().current_validate_context->controller.head_block_time().sec_since_epoch();
}
280

281 282 283 284 285 286
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) {
287
   wasm_interface::get().current_validate_context->require_authorization( Name(account) );
288
}
289

290
DEFINE_INTRINSIC_FUNCTION1(env,requireNotice,requireNotice,none,i64,account) {
291
   wasm_interface::get().current_apply_context->require_recipient( account );
292
}
293

294
DEFINE_INTRINSIC_FUNCTION1(env,requireScope,requireScope,none,i64,scope) {
295
   wasm_interface::get().current_validate_context->require_scope( scope );
296 297 298 299 300
}

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 已提交
301 302 303
   char* dst           = memoryArrayPtr<char>( mem, dstp, len);
   const char* src     = memoryArrayPtr<const char>( mem, srcp, len );
   FC_ASSERT( len > 0 );
304 305

   if( dst > src )
D
Daniel Larimer 已提交
306
      FC_ASSERT( dst >= (src + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
307
   else
D
Daniel Larimer 已提交
308 309
      FC_ASSERT( src >= (dst + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );

310 311 312 313
   memcpy( dst, src, uint32_t(len) );
   return dstp;
}

314 315 316 317 318 319 320 321 322 323
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;
}

324

325 326 327 328 329 330 331 332 333 334
/**
 * 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;
}

335 336 337 338 339 340 341
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);
   }
}

342
DEFINE_INTRINSIC_FUNCTION3(env,transactionRequireScope,transactionRequireScope,none,i32,handle,i64,scope,i32,readOnly) {
343 344
   auto& ptrx = wasm_interface::get().current_apply_context->get_pending_transaction(handle);
   if(readOnly == 0) {
345
      emplace_scope(scope, ptrx.scope);
346
   } else {
347
      emplace_scope(scope, ptrx.readscope);
348 349 350 351 352
   }

   ptrx.check_size();
}

353 354 355 356 357 358 359
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);
360 361
}

362 363 364 365 366 367 368 369 370 371 372 373 374
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);
375 376
}

377
DEFINE_INTRINSIC_FUNCTION4(env,messageCreate,messageCreate,i32,i64,code,i64,type,i32,data,i32,length) {
378 379
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
380
   
381 382
   EOS_ASSERT( length >= 0, tx_unknown_argument,
      "Pushing a message with a negative length" );
383

384
   Bytes payload;
385 386 387 388 389 390 391 392 393 394
   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");
      }
395
   }
396

397
   auto& pmsg = wasm.current_apply_context->create_pending_message(Name(code), Name(type), payload);
398
   return pmsg.handle;
399 400
}

401 402
DEFINE_INTRINSIC_FUNCTION3(env,messageRequirePermission,messageRequirePermission,none,i32,handle,i64,account,i64,permission) {
   auto apply_context  = wasm_interface::get().current_apply_context;
403 404 405 406 407
   // 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));
   }
408 409
   auto& pmsg = apply_context->get_pending_message(handle);
   pmsg.authorization.emplace_back(Name(account), Name(permission));
D
Daniel Larimer 已提交
410
}
411

412
DEFINE_INTRINSIC_FUNCTION1(env,messageSend,messageSend,none,i32,handle) {
413
   auto apply_context  = wasm_interface::get().current_apply_context;
414
   auto& pmsg = apply_context->get_pending_message(handle);
415

416 417
   apply_context->inline_messages.emplace_back(pmsg);
   apply_context->release_pending_message(handle);
418 419
}

420 421
DEFINE_INTRINSIC_FUNCTION1(env,messageDrop,messageDrop,none,i32,handle) {
   wasm_interface::get().current_apply_context->release_pending_message(handle);
422 423 424 425 426
}

/**
 * @} Transaction C API implementation
 */ 
427 428 429



430 431
DEFINE_INTRINSIC_FUNCTION2(env,readMessage,readMessage,i32,i32,destptr,i32,destsize) {
   FC_ASSERT( destsize > 0 );
432

433 434
   wasm_interface& wasm = wasm_interface::get();
   auto  mem   = wasm.current_memory;
435
   char* begin = memoryArrayPtr<char>( mem, destptr, uint32_t(destsize) );
436 437

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

D
Daniel Larimer 已提交
439
//   wdump((destsize)(wasm.current_validate_context->msg.data.size()));
440 441 442 443
   memcpy( begin, wasm.current_validate_context->msg.data.data(), minlen );
   return minlen;
}

444
DEFINE_INTRINSIC_FUNCTION2(env,assert,assert,none,i32,test,i32,msg) {
445 446
   const char* m = &Runtime::memoryRef<char>( wasm_interface::get().current_memory, msg );
  std::string message( m );
447
  if( !test ) edump((message));
448
  FC_ASSERT( test, "assertion failed: ${s}", ("s",message)("ptr",msg) );
449
}
450

451 452 453 454
DEFINE_INTRINSIC_FUNCTION0(env,messageSize,messageSize,i32) {
   return wasm_interface::get().current_validate_context->msg.data.size();
}

455
DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
456 457 458 459 460 461 462 463
   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;
}

464
DEFINE_INTRINSIC_FUNCTION1(env,printi,printi,none,i64,val) {
465
  std::cerr << uint64_t(val);
466
}
M
Matias Romeo 已提交
467 468 469
DEFINE_INTRINSIC_FUNCTION1(env,printd,printd,none,i64,val) {
  std::cerr << DOUBLE(*reinterpret_cast<double *>(&val));
}
470

471 472 473
DEFINE_INTRINSIC_FUNCTION1(env,printi128,printi128,none,i32,val) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;
474 475 476
  auto& value = memoryRef<unsigned __int128>( mem, val );
  fc::uint128_t v(value>>64, uint64_t(value) );
  std::cerr << fc::variant(v).get_string();
477 478 479
}
DEFINE_INTRINSIC_FUNCTION1(env,printn,printn,none,i64,val) {
  std::cerr << Name(val).toString();
480
}
481

482
DEFINE_INTRINSIC_FUNCTION1(env,prints,prints,none,i32,charptr) {
483 484 485
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;

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

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

M
Matias Romeo 已提交
491 492 493 494 495 496 497 498 499
DEFINE_INTRINSIC_FUNCTION2(env,printhex,printhex,none,i32,data,i32,datalen) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;
  
  char* buff = memoryArrayPtr<char>(mem, data, datalen);
  std::cerr << fc::to_hex(buff, datalen) << std::endl;
}


500
DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
501 502 503 504
}

   wasm_interface& wasm_interface::get() {
      static wasm_interface*  wasm = nullptr;
505
      if( !wasm )
506 507
      {
         wlog( "Runtime::init" );
508
         Runtime::init();
509 510 511 512 513 514 515 516 517 518 519 520 521
         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
     {
522 523 524 525
         // 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;
526 527 528
     }
   };

529 530 531 532 533
   int64_t wasm_interface::current_execution_time()
   {
      return (fc::time_point::now() - checktimeStart).count();
   }

534 535

   char* wasm_interface::vm_allocate( int bytes ) {
536 537
      FunctionInstance* alloc_function = asFunctionNullable(getInstanceExport(current_module,"alloc"));
      const FunctionType* functionType = getFunctionType(alloc_function);
538
      FC_ASSERT( functionType->parameters.size() == 1 );
539
      std::vector<Value> invokeArgs(1);
540 541
      invokeArgs[0] = U32(bytes);

542
      checktimeStart = fc::time_point::now();
543

544 545 546 547 548 549 550 551 552
      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 已提交
553
   void  wasm_interface::vm_call( const char* name ) {
554
   try {
555
      try {
D
Daniel Larimer 已提交
556
         /*
557
         name += "_" + std::string( current_validate_context->msg.code ) + "_";
558
         name += std::string( current_validate_context->msg.type );
D
Daniel Larimer 已提交
559 560 561
         */
         /// TODO: cache this somehow
         FunctionInstance* call = asFunctionNullable(getInstanceExport(current_module,name) );
562 563 564 565
         if( !call ) {
            //wlog( "unable to find call ${name}", ("name",name));
            return;
         }
D
Daniel Larimer 已提交
566
         //FC_ASSERT( apply, "no entry point found for ${call}", ("call", std::string(name))  );
567

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

D
Daniel Larimer 已提交
570
  //       idump((current_validate_context->msg.code)(current_validate_context->msg.type)(current_validate_context->code));
571
         std::vector<Value> args = { Value(uint64_t(current_validate_context->msg.code)),
D
Daniel Larimer 已提交
572
                                     Value(uint64_t(current_validate_context->msg.type)) };
573 574 575 576 577 578

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

579
         checktimeStart = fc::time_point::now();
580

D
Daniel Larimer 已提交
581
         Runtime::invokeFunction(call,args);
582 583
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
584 585
          edump((e.callStack));
          throw;
586
      }
587 588
   } FC_CAPTURE_AND_RETHROW( (name)(current_validate_context->msg.type) ) }

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

591
   void  wasm_interface::vm_onInit()
592 593
   { try {
      try {
594 595
            FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"init"));
            if( !apply ) {
596
               elog( "no onInit method found" );
597
               return; /// if not found then it is a no-op
598
            }
599

600
         checktimeStart = fc::time_point::now();
601

602 603
            const FunctionType* functionType = getFunctionType(apply);
            FC_ASSERT( functionType->parameters.size() == 0 );
604

605
            std::vector<Value> args(0);
606

607
            Runtime::invokeFunction(apply,args);
608 609
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
610 611
          edump((e.callStack));
          throw;
612
      }
613
   } FC_CAPTURE_AND_RETHROW() }
614

615
   void wasm_interface::validate( apply_context& c ) {
D
Daniel Larimer 已提交
616
      /*
617 618 619 620
      current_validate_context       = &c;
      current_precondition_context   = nullptr;
      current_apply_context          = nullptr;

D
Daniel Larimer 已提交
621
      load( c.code, c.db );
622
      vm_validate();
D
Daniel Larimer 已提交
623
      */
624
   }
625
   void wasm_interface::precondition( apply_context& c ) {
626 627
   try {

D
Daniel Larimer 已提交
628
      /*
629 630 631
      current_validate_context       = &c;
      current_precondition_context   = &c;

D
Daniel Larimer 已提交
632
      load( c.code, c.db );
633
      vm_precondition();
D
Daniel Larimer 已提交
634
      */
635 636

   } FC_CAPTURE_AND_RETHROW() }
637 638


639 640
   void wasm_interface::apply( apply_context& c ) {
    try {
641 642 643 644
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
645
      load( c.code, c.db );
646 647 648 649 650 651
      vm_apply();

   } FC_CAPTURE_AND_RETHROW() }

   void wasm_interface::init( apply_context& c ) {
    try {
652 653 654 655
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
656
      load( c.code, c.db );
657
      vm_onInit();
658 659 660

   } FC_CAPTURE_AND_RETHROW() }

661

662

663 664
   void wasm_interface::load( const AccountName& name, const chainbase::database& db ) {
      const auto& recipient = db.get<account_object,by_name>( name );
665
  //    idump(("recipient")(Name(name))(recipient.code_version));
666 667 668 669 670 671 672 673

      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;
674
            state.code_version = fc::sha256();
675 676 677 678 679
         }
         state.module = new IR::Module();

        try
        {
680 681
//          wlog( "LOADING CODE" );
 //         auto start = fc::time_point::now();
682
          Serialization::MemoryInputStream stream((const U8*)recipient.code.data(),recipient.code.size());
683
          WASM::serializeWithInjection(stream,*state.module);
684 685 686 687 688

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

692
          current_memory = Runtime::getDefaultMemory(state.instance);
693
            
694
          char* memstart = &memoryRef<char>( current_memory, 0 );
695
         // state.init_memory.resize(1<<16); /// TODO: actually get memory size
696
          for( uint32_t i = 0; i < 10000; ++i )
697
              if( memstart[i] ) {
698
                   state.mem_end = i+1;
699
                   //std::cerr << (char)memstart[i];
700
              }
701
          //ilog( "INIT MEMORY: ${size}", ("size", state.mem_end) );
702 703 704

          state.init_memory.resize(state.mem_end);
          memcpy( state.init_memory.data(), memstart, state.mem_end ); //state.init_memory.size() );
705
          //std::cerr <<"\n";
706
          state.code_version = recipient.code_version;
707
//          idump((state.code_version));
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
        }
        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 );
729
      current_state  = &state;
730
   }
731 732

} }