wasm_interface.cpp 15.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
#include <eos/chain/wasm_interface.hpp>
#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>
11
#include <eos/chain/account_object.hpp>
12 13 14 15

namespace eos { namespace chain {
   using namespace IR;
   using namespace Runtime;
16

17 18 19 20
   wasm_interface::wasm_interface() {
   }

DEFINE_INTRINSIC_FUNCTION4(env,store,store,none,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen ) {
D
Daniel Larimer 已提交
21
//   ilog( "store ${keylen}  ${vallen}", ("keylen",keylen)("vallen",valuelen) );
D
Daniel Larimer 已提交
22
/*
23 24 25 26 27 28 29 30 31 32
   FC_ASSERT( keylen > 0 );
   FC_ASSERT( valuelen >= 0 );

   auto& wasm  = wasm_interface::get();

   FC_ASSERT( wasm.current_apply_context, "no apply context found" );

   auto& db    = wasm.current_apply_context->mutable_db;
   auto& scope = wasm.current_apply_context->scope;
   auto  mem   = wasm.current_memory;
33 34
   char* key   = memoryArrayPtr<char>( mem, keyptr, keylen);
   char* value = memoryArrayPtr<char>( mem, valueptr, valuelen);
35 36
   string keystr( key, key+keylen);

D
Daniel Larimer 已提交
37
//   if( valuelen == 8 ) idump(( *((int64_t*)value)));
38

39 40 41 42

   const auto* obj = db.find<key_value_object,by_scope_key>( boost::make_tuple(scope, keystr) );
   if( obj ) {
      db.modify( *obj, [&]( auto& o ) {
N
Nathan Hourt 已提交
43
         o.value.assign(value, valuelen);
44 45 46 47 48 49 50 51
      });
   } else {
      db.create<key_value_object>( [&](auto& o) {
         o.scope = scope;
         o.key.insert( 0, key, keylen );
         o.value.insert( 0, value, valuelen );
      });
   }
D
Daniel Larimer 已提交
52
*/
53
}
D
Daniel Larimer 已提交
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 81 82 83

DEFINE_INTRINSIC_FUNCTION4(env,load,load,i32,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen ) {
//   ilog( "load ${keylen}  ${vallen}", ("keylen",keylen)("vallen",valuelen) );
/**
   FC_ASSERT( keylen > 0 );
   FC_ASSERT( valuelen >= 0 );

   auto& wasm  = wasm_interface::get();

   FC_ASSERT( wasm.current_apply_context, "no apply context found" );

   auto& db    = wasm.current_apply_context->mutable_db;
   auto& scope = wasm.current_apply_context->scope;
   auto  mem   = wasm.current_memory;
   char* key   = memoryArrayPtr<char>( mem, keyptr, keylen );
   char* value = memoryArrayPtr<char>( mem, valueptr, valuelen );
   string keystr( key, key+keylen);

   const auto* obj = db.find<key_value_object,by_scope_key>( boost::make_tuple(scope, keystr) );
   if( obj == nullptr ) return -1;
   auto copylen =  std::min<size_t>(obj->value.size(),valuelen);
   if( copylen ) {
      obj->value.copy(value, copylen);
   }
   return copylen;
*/
   return 0;
}


84 85 86 87 88 89
DEFINE_INTRINSIC_FUNCTION1(env,name_to_int64,name_to_int64,i64,i32,cstr) {
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
   const char* str   = memoryArrayPtr<const char>( mem, cstr, 13);
   return Name(str).value;
}
90

91
DEFINE_INTRINSIC_FUNCTION2(env,remove,remove,i32,i32,keyptr,i32,keylen) {
D
Daniel Larimer 已提交
92
   /*
93 94 95 96 97 98 99 100 101
   FC_ASSERT( keylen > 0 );

   auto& wasm  = wasm_interface::get();

   FC_ASSERT( wasm.current_apply_context, "no apply context found" );

   auto& db    = wasm.current_apply_context->mutable_db;
   auto& scope = wasm.current_apply_context->scope;
   auto  mem   = wasm.current_memory;
102
   char* key   = memoryArrayPtr<char>( mem, keyptr, keylen);
103 104 105 106
   string keystr( key, key+keylen);

   const auto* obj = db.find<key_value_object,by_scope_key>( boost::make_tuple(scope, keystr) );
   if( obj ) {
107
      db.remove( *obj );
108 109
      return true;
   }
D
Daniel Larimer 已提交
110
   */
111 112 113 114 115 116 117 118
   return false;
}

DEFINE_INTRINSIC_FUNCTION3(env,memcpy,memcpy,i32,i32,dstp,i32,srcp,i32,len) {
   auto& wasm          = wasm_interface::get();
   auto  mem           = wasm.current_memory;
   char* dst           = &memoryRef<char>( mem, dstp);
   const char* src     = &memoryRef<const char>( mem, srcp );
119
   //char* dst_end       = &memoryRef<char>( mem, dstp+uint32_t(len));
120 121 122 123 124
   const char* src_end = &memoryRef<const char>( mem, srcp+uint32_t(len) );

#warning TODO: wasm memcpy has undefined behavior if memory ranges overlap
/*
   if( dst > src )
125
      FC_ASSERT( dst < src_end && src < dst_end, "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
126
   else
127
      FC_ASSERT( src < dst_end && dst < src_end, "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
128 129 130 131 132 133 134 135 136 137
*/
   memcpy( dst, src, uint32_t(len) );
   return dstp;
}


DEFINE_INTRINSIC_FUNCTION2(env,Varint_unpack,Varint_unpack,none,i32,streamptr,i32,valueptr) {
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;

138
   uint32_t* stream = memoryArrayPtr<uint32_t>( mem, streamptr, 3 );
139 140 141 142 143 144 145 146 147 148 149 150 151
   const char* pos = &memoryRef<const char>( mem, stream[1] );
   const char* end = &memoryRef<const char>( mem, stream[2] );
   uint32_t& value = memoryRef<uint32_t>( mem, valueptr );

   fc::unsigned_int vi;
   fc::datastream<const char*> ds(pos,end-pos);
   fc::raw::unpack( ds, vi );
   value = vi.value;

   stream[1] += ds.pos() - pos;
}


152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
DEFINE_INTRINSIC_FUNCTION2(env,send,send,i32,i32,trx_buffer, i32,trx_buffer_size ) {
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
   const char* buffer = &memoryRef<const char>( mem, trx_buffer );

   FC_ASSERT( trx_buffer_size > 0 );
   FC_ASSERT( wasm.current_apply_context, "not in apply context" );

   fc::datastream<const char*> ds(buffer, trx_buffer_size );
   eos::chain::generated_transaction gtrx;
   eos::chain::Transaction& trx = gtrx;
   fc::raw::unpack( ds, trx );

/**
 *  The code below this section provides sanity checks that the generated message is well formed
 *  before being accepted. These checks do not need to be applied during reindex.
 */
#warning TODO: reserve per-thread static memory for MAX TRX SIZE 
/** make sure that packing what we just unpacked produces expected output */
   auto test = fc::raw::pack( trx );
   FC_ASSERT( 0 == memcmp( buffer, test.data(), test.size() ) );

/** TODO: make sure that we can call validate() on the message and it passes, this is thread safe and
 *   ensures the type is properly registered and can be deserialized... one issue is that this could
 *   construct a RECURSIVE virtual machine state which means the wasm_interface state needs to be a STACK vs
 *   a per-thread global.
 **/

   wasm.current_apply_context->generated.emplace_back( std::move(gtrx) );
181

D
Daniel Larimer 已提交
182 183
   return 0;
}
184

185 186 187



188 189 190 191
DEFINE_INTRINSIC_FUNCTION2(env,readMessage,readMessage,i32,i32,destptr,i32,destsize) {
   FC_ASSERT( destsize > 0 );
   wasm_interface& wasm = wasm_interface::get();
   auto  mem   = wasm.current_memory;
192
   char* begin = memoryArrayPtr<char>( mem, destptr, destsize );
193 194 195 196 197 198

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

199 200 201
DEFINE_INTRINSIC_FUNCTION2(env,assert,assert,none,i32,test,i32,msg) {
  std::string message = &Runtime::memoryRef<char>( wasm_interface::get().current_memory, msg );
  if( !test ) edump((message));
202
  FC_ASSERT( test, "assertion failed: ${s}", ("s",message)("ptr",msg) );
203
}
204

205 206 207 208
DEFINE_INTRINSIC_FUNCTION0(env,messageSize,messageSize,i32) {
   return wasm_interface::get().current_validate_context->msg.data.size();
}

209
DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
210 211 212 213 214 215 216 217
   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;
}

218
DEFINE_INTRINSIC_FUNCTION1(env,printi,printi,none,i64,val) {
219
  std::cerr << uint64_t(val);
220
//  idump((val));
221
}
222

223
DEFINE_INTRINSIC_FUNCTION1(env,print,print,none,i32,charptr) {
224 225 226
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;

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

229 230
  std::cerr << std::string( str, strlen(str) );
//	wlog( std::string( str, strlen(size) ) );
231 232
}

233
DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
234 235
}

236
DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
237 238 239 240 241 242 243 244 245 246 247 248 249
   std::cerr << "TO UPPER CALLED\n";// << charptr << "\n";
//   std::cerr << "moduleInstance: " << moduleInstance << "\n";
  // /*U8* base = */Runtime::getMemoryBaseAddress( Runtime::getDefaultMemory(moduleInstance) );
   //std::cerr << "Base Address: " << (int64_t)base;
   //char* c = (char*)(base + charptr);
   char& c = Runtime::memoryRef<char>( Runtime::getDefaultMemory(wasm_interface::get().current_module), charptr );
//   std::cerr << "char: " << c <<"\n";
//   if( c > 'Z' ) c -= 32;
//   return 0;
}

   wasm_interface& wasm_interface::get() {
      static wasm_interface*  wasm = nullptr;
250
      if( !wasm )
251 252
      {
         wlog( "Runtime::init" );
253
         Runtime::init();
254 255 256 257 258 259 260 261 262 263 264 265 266
         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
     {
267 268 269 270
         // 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;
271 272 273 274 275
     }
   };


   char* wasm_interface::vm_allocate( int bytes ) {
276 277
      FunctionInstance* alloc_function = asFunctionNullable(getInstanceExport(current_module,"alloc"));
      const FunctionType* functionType = getFunctionType(alloc_function);
278
      FC_ASSERT( functionType->parameters.size() == 1 );
279
      std::vector<Value> invokeArgs(1);
280 281 282 283 284 285 286 287 288 289 290
      invokeArgs[0] = U32(bytes);

      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 已提交
291
   void  wasm_interface::vm_call( const char* name ) {
292
   try {
293
      try {
D
Daniel Larimer 已提交
294
         /*
295
         name += "_" + std::string( current_validate_context->msg.code ) + "_";
296
         name += std::string( current_validate_context->msg.type );
D
Daniel Larimer 已提交
297 298 299 300 301
         */
         /// TODO: cache this somehow
         FunctionInstance* call = asFunctionNullable(getInstanceExport(current_module,name) );
         if( !call )
         //FC_ASSERT( apply, "no entry point found for ${call}", ("call", std::string(name))  );
302

D
Daniel Larimer 已提交
303 304 305
         FC_ASSERT( getFunctionType(call)->parameters.size() == 2 );
         std::vector<Value> args = { Value(uint64_t(current_validate_context->msg.code)),
                                     Value(uint64_t(current_validate_context->msg.type)) };
306 307 308 309 310 311

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

D
Daniel Larimer 已提交
312
         Runtime::invokeFunction(call,args);
313 314
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
315 316
          edump((e.callStack));
          throw;
317
      }
318 319
   } FC_CAPTURE_AND_RETHROW( (name)(current_validate_context->msg.type) ) }

D
Daniel Larimer 已提交
320 321 322
   void  wasm_interface::vm_precondition() { vm_call("precondition" ); } 
   void  wasm_interface::vm_apply()        { vm_call("apply" );        }
   void  wasm_interface::vm_validate()     { vm_call("validate");       }
323

324
   void  wasm_interface::vm_onInit()
325 326
   { try {
      try {
327
         // wlog( "on_init" );
328 329 330 331
            FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"init"));
            if( !apply ) {
               wlog( "no onInit method found" );
               return; /// if not found then it is a no-op
332 333
         }

334 335
            const FunctionType* functionType = getFunctionType(apply);
            FC_ASSERT( functionType->parameters.size() == 0 );
336

337
            std::vector<Value> args(0);
338

339
            Runtime::invokeFunction(apply,args);
340 341
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
342 343
          edump((e.callStack));
          throw;
344
      }
345
   } FC_CAPTURE_AND_RETHROW() }
346

347 348 349 350 351 352
   void wasm_interface::validate( message_validate_context& c ) {

      current_validate_context       = &c;
      current_precondition_context   = nullptr;
      current_apply_context          = nullptr;

D
Daniel Larimer 已提交
353
      load( c.code, c.db );
354 355
      vm_validate();
   }
356 357 358 359 360 361
   void wasm_interface::precondition( precondition_validate_context& c ) {
   try {

      current_validate_context       = &c;
      current_precondition_context   = &c;

D
Daniel Larimer 已提交
362
      load( c.code, c.db );
363 364 365
      vm_precondition();

   } FC_CAPTURE_AND_RETHROW() }
366 367


368 369
   void wasm_interface::apply( apply_context& c ) {
    try {
370 371 372 373
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
374
      load( c.code, c.db );
375 376 377 378 379 380
      vm_apply();

   } FC_CAPTURE_AND_RETHROW() }

   void wasm_interface::init( apply_context& c ) {
    try {
381 382 383 384
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
385
      load( c.code, c.db );
386
      vm_onInit();
387 388 389

   } FC_CAPTURE_AND_RETHROW() }

390

391

392 393 394 395 396 397 398 399 400 401
   void wasm_interface::load( const AccountName& name, const chainbase::database& db ) {
      const auto& recipient = db.get<account_object,by_name>( name );

      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;
402
            state.code_version = fc::sha256();
403 404 405 406 407
         }
         state.module = new IR::Module();

        try
        {
408
          wlog( "LOADING CODE" );
409 410 411 412 413 414 415 416 417 418
          Serialization::MemoryInputStream stream((const U8*)recipient.code.data(),recipient.code.size());
          WASM::serialize(stream,*state.module);

          RootResolver rootResolver;
          LinkResult linkResult = linkModule(*state.module,rootResolver);
          state.instance = instantiateModule( *state.module, std::move(linkResult.resolvedImports) );
          FC_ASSERT( state.instance );
          current_memory = Runtime::getDefaultMemory(state.instance);

          char* memstart = &memoryRef<char>( current_memory, 0 );
419
         // state.init_memory.resize(1<<16); /// TODO: actually get memory size
420
          std::cerr <<"INIT MEMORY: \n";
421
          for( uint32_t i = 0; i < 10000; ++i )
422 423
              if( memstart[i] ) {
                   state.mem_end = i;
424
                   //std::cerr << (char)memstart[i];
425 426 427 428
              }

          state.init_memory.resize(state.mem_end);
          memcpy( state.init_memory.data(), memstart, state.mem_end ); //state.init_memory.size() );
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
          std::cerr <<"\n";
          state.code_version = recipient.code_version;
        }
        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 );
452
      current_state  = &state;
453
   }
454 455 456


} }