wasm_interface.cpp 34.3 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 24 25 26

namespace eos { namespace chain {
   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);
}

A
Andrianto Lie 已提交
355

M
Matias Romeo 已提交
356 357 358 359 360 361 362
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);
}

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

367 368 369 370 371 372
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) {
373
   wasm_interface::get().current_validate_context->require_authorization( Name(account) );
374
}
375

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

380
DEFINE_INTRINSIC_FUNCTION1(env,requireScope,requireScope,none,i64,scope) {
381
   wasm_interface::get().current_validate_context->require_scope( scope );
382 383 384 385 386
}

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 已提交
387 388 389
   char* dst           = memoryArrayPtr<char>( mem, dstp, len);
   const char* src     = memoryArrayPtr<const char>( mem, srcp, len );
   FC_ASSERT( len > 0 );
390 391

   if( dst > src )
D
Daniel Larimer 已提交
392
      FC_ASSERT( dst >= (src + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
393
   else
D
Daniel Larimer 已提交
394 395
      FC_ASSERT( src >= (dst + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );

396 397 398 399
   memcpy( dst, src, uint32_t(len) );
   return dstp;
}

A
Andrianto Lie 已提交
400 401 402 403 404 405 406 407 408 409 410
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) );
}


411 412 413 414 415 416 417 418 419 420
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 已提交
421 422 423 424 425 426
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);
427
   checktime(wasm.current_execution_time(), wasm_interface::get().checktime_limit);
B
Brian Johnson 已提交
428 429 430
   return previous_bytes_allocated;
}

431

432 433 434 435 436 437 438 439 440 441
/**
 * 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;
}

442 443 444 445 446 447 448
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);
   }
}

449
DEFINE_INTRINSIC_FUNCTION3(env,transactionRequireScope,transactionRequireScope,none,i32,handle,i64,scope,i32,readOnly) {
450 451
   auto& ptrx = wasm_interface::get().current_apply_context->get_pending_transaction(handle);
   if(readOnly == 0) {
452
      emplace_scope(scope, ptrx.scope);
453
   } else {
454
      emplace_scope(scope, ptrx.readscope);
455 456 457 458 459
   }

   ptrx.check_size();
}

460 461 462 463 464 465 466
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);
467 468
}

469 470 471 472 473 474 475 476 477 478 479 480 481
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);
482 483
}

484
DEFINE_INTRINSIC_FUNCTION4(env,messageCreate,messageCreate,i32,i64,code,i64,type,i32,data,i32,length) {
485 486
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
487
   
488 489
   EOS_ASSERT( length >= 0, tx_unknown_argument,
      "Pushing a message with a negative length" );
490

491
   Bytes payload;
492 493 494 495 496 497 498 499 500 501
   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");
      }
502
   }
503

504
   auto& pmsg = wasm.current_apply_context->create_pending_message(Name(code), Name(type), payload);
505
   return pmsg.handle;
506 507
}

508 509
DEFINE_INTRINSIC_FUNCTION3(env,messageRequirePermission,messageRequirePermission,none,i32,handle,i64,account,i64,permission) {
   auto apply_context  = wasm_interface::get().current_apply_context;
510 511 512 513 514
   // 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));
   }
515 516
   auto& pmsg = apply_context->get_pending_message(handle);
   pmsg.authorization.emplace_back(Name(account), Name(permission));
D
Daniel Larimer 已提交
517
}
518

519
DEFINE_INTRINSIC_FUNCTION1(env,messageSend,messageSend,none,i32,handle) {
520
   auto apply_context  = wasm_interface::get().current_apply_context;
521
   auto& pmsg = apply_context->get_pending_message(handle);
522

523 524
   apply_context->inline_messages.emplace_back(pmsg);
   apply_context->release_pending_message(handle);
525 526
}

527 528
DEFINE_INTRINSIC_FUNCTION1(env,messageDrop,messageDrop,none,i32,handle) {
   wasm_interface::get().current_apply_context->release_pending_message(handle);
529 530 531 532 533
}

/**
 * @} Transaction C API implementation
 */ 
534 535 536



537 538
DEFINE_INTRINSIC_FUNCTION2(env,readMessage,readMessage,i32,i32,destptr,i32,destsize) {
   FC_ASSERT( destsize > 0 );
539

540 541
   wasm_interface& wasm = wasm_interface::get();
   auto  mem   = wasm.current_memory;
542
   char* begin = memoryArrayPtr<char>( mem, destptr, uint32_t(destsize) );
543 544

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

D
Daniel Larimer 已提交
546
//   wdump((destsize)(wasm.current_validate_context->msg.data.size()));
547 548 549 550
   memcpy( begin, wasm.current_validate_context->msg.data.data(), minlen );
   return minlen;
}

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

558 559 560 561
DEFINE_INTRINSIC_FUNCTION0(env,messageSize,messageSize,i32) {
   return wasm_interface::get().current_validate_context->msg.data.size();
}

562
DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
563 564 565 566 567 568 569 570
   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;
}

571
DEFINE_INTRINSIC_FUNCTION1(env,printi,printi,none,i64,val) {
572
  std::cerr << uint64_t(val);
573
}
M
Matias Romeo 已提交
574 575 576
DEFINE_INTRINSIC_FUNCTION1(env,printd,printd,none,i64,val) {
  std::cerr << DOUBLE(*reinterpret_cast<double *>(&val));
}
577

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

589
DEFINE_INTRINSIC_FUNCTION1(env,prints,prints,none,i32,charptr) {
590 591 592
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;

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

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

A
Andrianto Lie 已提交
598 599 600 601 602 603 604 605 606
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 已提交
607 608 609
DEFINE_INTRINSIC_FUNCTION2(env,printhex,printhex,none,i32,data,i32,datalen) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;
A
Andrianto Lie 已提交
610

M
Matias Romeo 已提交
611 612 613 614 615
  char* buff = memoryArrayPtr<char>(mem, data, datalen);
  std::cerr << fc::to_hex(buff, datalen) << std::endl;
}


616
DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
617 618 619 620
}

   wasm_interface& wasm_interface::get() {
      static wasm_interface*  wasm = nullptr;
621
      if( !wasm )
622 623
      {
         wlog( "Runtime::init" );
624
         Runtime::init();
625 626 627 628 629 630 631 632 633 634 635 636 637
         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
     {
638 639 640 641
         // 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;
642 643 644
     }
   };

645 646 647 648 649
   int64_t wasm_interface::current_execution_time()
   {
      return (fc::time_point::now() - checktimeStart).count();
   }

650 651

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

658
      checktimeStart = fc::time_point::now();
659

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

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

D
Daniel Larimer 已提交
687
  //       idump((current_validate_context->msg.code)(current_validate_context->msg.type)(current_validate_context->code));
688
         std::vector<Value> args = { Value(uint64_t(current_validate_context->msg.code)),
D
Daniel Larimer 已提交
689
                                     Value(uint64_t(current_validate_context->msg.type)) };
690 691 692 693 694 695

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

696
         checktimeStart = fc::time_point::now();
B
Brian Johnson 已提交
697
         wasm_memory_mgmt.reset(new wasm_memory(*this));
698

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

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

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

720
         checktimeStart = fc::time_point::now();
721

722 723
            const FunctionType* functionType = getFunctionType(apply);
            FC_ASSERT( functionType->parameters.size() == 0 );
724

725
            std::vector<Value> args(0);
726

727
            Runtime::invokeFunction(apply,args);
728 729
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
730 731
          edump((e.callStack));
          throw;
732
      }
733
   } FC_CAPTURE_AND_RETHROW() }
734

735
   void wasm_interface::validate( apply_context& c ) {
D
Daniel Larimer 已提交
736
      /*
737 738 739 740
      current_validate_context       = &c;
      current_precondition_context   = nullptr;
      current_apply_context          = nullptr;

D
Daniel Larimer 已提交
741
      load( c.code, c.db );
742
      vm_validate();
D
Daniel Larimer 已提交
743
      */
744
   }
745
   void wasm_interface::precondition( apply_context& c ) {
746 747
   try {

D
Daniel Larimer 已提交
748
      /*
749 750 751
      current_validate_context       = &c;
      current_precondition_context   = &c;

D
Daniel Larimer 已提交
752
      load( c.code, c.db );
753
      vm_precondition();
D
Daniel Larimer 已提交
754
      */
755 756

   } FC_CAPTURE_AND_RETHROW() }
757 758


759
   void wasm_interface::apply( apply_context& c, uint32_t execution_time, bool received_block ) {
760
    try {
761 762 763
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;
764
      checktime_limit                = execution_time;
765

D
Daniel Larimer 已提交
766
      load( c.code, c.db );
767 768 769 770
      // if this is a received_block, then ignore the table_key_types
      if (received_block)
         table_key_types = nullptr;

771 772 773 774 775 776
      vm_apply();

   } FC_CAPTURE_AND_RETHROW() }

   void wasm_interface::init( apply_context& c ) {
    try {
777 778 779
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;
780
      checktime_limit                = CHECKTIME_LIMIT;
781

D
Daniel Larimer 已提交
782
      load( c.code, c.db );
783
      vm_onInit();
784 785 786

   } FC_CAPTURE_AND_RETHROW() }

787

788

789 790
   void wasm_interface::load( const AccountName& name, const chainbase::database& db ) {
      const auto& recipient = db.get<account_object,by_name>( name );
791
  //    idump(("recipient")(Name(name))(recipient.code_version));
792 793 794

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

        try
        {
807 808
//          wlog( "LOADING CODE" );
 //         auto start = fc::time_point::now();
809
          Serialization::MemoryInputStream stream((const U8*)recipient.code.data(),recipient.code.size());
810
          WASM::serializeWithInjection(stream,*state.module);
811 812 813 814 815

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

819
          current_memory = Runtime::getDefaultMemory(state.instance);
820
            
821
          char* memstart = &memoryRef<char>( current_memory, 0 );
822
         // state.init_memory.resize(1<<16); /// TODO: actually get memory size
823 824 825 826 827 828 829 830
          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;
             }
          }
831
          //ilog( "INIT MEMORY: ${size}", ("size", state.mem_end) );
832 833 834

          state.init_memory.resize(state.mem_end);
          memcpy( state.init_memory.data(), memstart, state.mem_end ); //state.init_memory.size() );
835
          //std::cerr <<"\n";
836
          state.code_version = recipient.code_version;
837
//          idump((state.code_version));
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852

          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));
             }
          }
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
        }
        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;
        }
      }
872 873 874 875 876
      current_module  = state.instance;
      current_memory  = getDefaultMemory( current_module );
      current_state   = &state;
      table_key_types = &state.table_key_types;
      tables_fixed    = state.tables_fixed;
877
   }
878

B
Brian Johnson 已提交
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
   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)
         throw eos::chain::page_memory_error();

      // 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)
         throw eos::chain::page_memory_error();
      else if(num_bytes < 0 && previous_num_bytes < _min_bytes - num_bytes)
         throw eos::chain::page_memory_error();

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

929
} }