提交 60a30466 编写于 作者: D Daniel Larimer

first smart contract coin created and tested with web assembly

上级 27b5b1ed
......@@ -635,30 +635,11 @@ void chain_controller::apply_message( apply_context& context )
return;
}
}
const auto& scope = _db.get<account_object,by_name>( context.scope );
const auto& recipient = _db.get<account_object,by_name>( context.msg.recipient );
auto handler = _db.find<action_code_object,by_processor_recipient_type>( boost::make_tuple(scope.id, recipient.id, context.msg.type) );
if( handler ) {
wasm_interface::get().load( handler->apply.data(), handler->apply.size() );
const auto& recipient = _db.get<account_object,by_name>( context.scope );
if( recipient.code.size() ) {
wasm_interface::get().apply( context );
/*
wdump((handler->apply.c_str()));
wrenpp::VM vm;
vm.executeString( R"(
foreign class ApplyContext {
foreign get(key)
foreign set(key,value)
}
)");
vm.executeString( handler->apply.c_str() );
auto apply_method = vm.method( "main", "Handler", "apply(_,_)" );
//apply_method( context, m.data );
//apply_method( "context", 1 );
apply_method( &context, 1 );
*/
}
/// TODO: dispatch to script if not handled above
} FC_CAPTURE_AND_RETHROW((context.msg)) }
......@@ -800,7 +781,6 @@ uint32_t chain_controller::last_irreversible_block_num() const {
void chain_controller::initialize_indexes() {
_db.add_index<account_index>();
_db.add_index<permission_index>();
_db.add_index<action_code_index>();
_db.add_index<action_permission_index>();
_db.add_index<type_index>();
_db.add_index<key_value_index>();
......
......@@ -57,10 +57,14 @@ namespace eos { namespace chain {
};
class account_object : public chainbase::object<account_object_type, account_object> {
OBJECT_CTOR(account_object)
OBJECT_CTOR(account_object,(code))
id_type id;
AccountName name;
uint8_t vm_type = 0;
uint8_t vm_version = 0;
uint16_t code_version = 0;
shared_vector<char> code;
Time creation_date;
};
using account_id_type = account_object::id_type;
......@@ -120,6 +124,6 @@ CHAINBASE_SET_INDEX_TYPE(eos::chain::permission_object, eos::chain::permission_i
FC_REFLECT(chainbase::oid<eos::chain::permission_object>, (_id))
FC_REFLECT(chainbase::oid<eos::chain::account_object>, (_id))
FC_REFLECT(eos::chain::account_object, (id)(name)(creation_date))
FC_REFLECT(eos::chain::account_object, (id)(name)(vm_type)(vm_version)(code_version)(code)(creation_date))
// TODO: Reflect permission_object::auth
FC_REFLECT(eos::chain::permission_object, (id)(owner)(parent)(name))
......@@ -29,46 +29,6 @@
namespace eos { namespace chain {
/**
* This table defines all of the event handlers for every contract. Every message is
* delivered TO a particular contract and also processed in parallel by several other contracts.
*
* Each account can define a custom handler based upon the tuple { processor, recipient, type } where
* processor is the account that is processing the message, recipient is the account specified by
* message::recipient and type is messagse::type.
*
*
*/
class action_code_object : public chainbase::object<action_code_object_type, action_code_object>
{
OBJECT_CTOR(action_code_object, (validate_action)(validate_precondition)(apply) )
id_type id;
account_id_type recipient;
account_id_type processor;
TypeName type; ///< the name of the action (defines serialization)
shared_string validate_action; ///< read only access to action
shared_string validate_precondition; ///< read only access to state
shared_string apply; ///< the code that executes the state transition
};
struct by_parent;
struct by_processor_recipient_type;
using action_code_index = chainbase::shared_multi_index_container<
action_code_object,
indexed_by<
ordered_unique<tag<by_id>, member<action_code_object, action_code_object::id_type, &action_code_object::id>>,
ordered_unique<tag<by_processor_recipient_type>,
composite_key< action_code_object,
member<action_code_object, account_id_type, &action_code_object::processor>,
member<action_code_object, account_id_type, &action_code_object::recipient>,
member<action_code_object, TypeName, &action_code_object::type>
>
>
>
>;
/**
* Maps the permission level on the code to the permission level specififed by owner, when specifying a contract the
* contract will specify 1 permission_object per action, and by default the parent of that permission object will be
......@@ -118,8 +78,6 @@ namespace eos { namespace chain {
} } // eos::chain
CHAINBASE_SET_INDEX_TYPE(eos::chain::action_code_object, eos::chain::action_code_index)
CHAINBASE_SET_INDEX_TYPE(eos::chain::action_permission_object, eos::chain::action_permission_index)
FC_REFLECT(eos::chain::action_code_object, (id)(recipient)(processor)(type)(validate_action)(validate_precondition)(apply) )
FC_REFLECT(eos::chain::action_permission_object, (id)(owner)(owner_permission)(scope_permission) )
......@@ -90,7 +90,7 @@ namespace eos { namespace chain {
}
/**
* The database can override any script handler with native code.
* The controller can override any script endpoint with native code.
*/
///@{
void set_validate_handler( const AccountName& contract, const AccountName& scope, const TypeName& action, message_validate_handler v );
......
......@@ -64,7 +64,7 @@
{ c(*this); }
#define OBJECT_CTOR(...) BOOST_PP_OVERLOAD(OBJECT_CTOR, __VA_ARGS__)(__VA_ARGS__)
#define EOS_SYSTEM_CONTRACT_FUNCTIONS (CreateAccount)(DefineStruct)(SetMessageHandler)
#define EOS_SYSTEM_CONTRACT_FUNCTIONS (CreateAccount)(DefineStruct)(SetCode)
#define EOS_CONTRACT_FUNCTIONS (Transfer)(TransferToLocked)
#define EOS_STAKED_BALANCE_CONTRACT_FUNCTIONS (CreateProducer)(UpdateProducer)(ApproveProducer)
......
......@@ -20,35 +20,39 @@ class wasm_interface {
public:
static wasm_interface& get();
enum database_access_type {
none,
read_only,
read_write
};
void load(const char* wasmbytes, size_t len );
void init( apply_context& c );
void apply( apply_context& c );
void validate( message_validate_context& c );
void precondition( precondition_validate_context& c );
apply_context* current_apply_context = nullptr;
message_validate_context* current_validate_context = nullptr;
precondition_validate_context* current_precondition_context = nullptr;
Runtime::MemoryInstance* current_memory = nullptr;
Runtime::ModuleInstance* current_module = nullptr;
chain_controller* current_chain = nullptr;
const AccountName* current_account = nullptr;
const Message* current_message = nullptr;
database_access_type current_access = none;
private:
void load( const AccountName& name, const chainbase::database& db );
char* vm_allocate( int bytes );
void vm_apply( const vector<char>& message );
void vm_apply();
void vm_onInit();
U32 vm_pointer_to_offset( char* );
struct ModuleState {
Runtime::ModuleInstance* instance = nullptr;
IR::Module* module = nullptr;
vector<char> init_memory;
uint16_t code_version = -1;
};
map<AccountName, ModuleState> instances;
wasm_interface();
};
......
......@@ -8,6 +8,7 @@
#include "IR/Operators.h"
#include "IR/Validate.h"
#include <eos/chain/key_value_object.hpp>
#include <eos/chain/account_object.hpp>
namespace eos { namespace chain {
using namespace IR;
......@@ -17,6 +18,7 @@ namespace eos { namespace chain {
}
DEFINE_INTRINSIC_FUNCTION4(env,store,store,none,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen ) {
ilog( "store" );
FC_ASSERT( keylen > 0 );
FC_ASSERT( valuelen >= 0 );
......@@ -31,6 +33,9 @@ DEFINE_INTRINSIC_FUNCTION4(env,store,store,none,i32,keyptr,i32,keylen,i32,valuep
char* value = &memoryRef<char>( mem, valueptr );
string keystr( key, key+keylen);
idump((keystr));
if( valuelen == 8 ) idump(( *((int64_t*)value)));
const auto* obj = db.find<key_value_object,by_scope_key>( boost::make_tuple(scope, keystr) );
if( obj ) {
......@@ -47,7 +52,84 @@ DEFINE_INTRINSIC_FUNCTION4(env,store,store,none,i32,keyptr,i32,keylen,i32,valuep
}
}
DEFINE_INTRINSIC_FUNCTION2(env,remove,remove,i32,i32,keyptr,i32,keylen) {
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;
char* key = &memoryRef<char>( mem, keyptr );
string keystr( key, key+keylen);
const auto* obj = db.find<key_value_object,by_scope_key>( boost::make_tuple(scope, keystr) );
if( obj ) {
db.remove( *obj );
return true;
}
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 );
char* dst_end = &memoryRef<char>( mem, dstp+uint32_t(len));
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 )
FC_ASSERT( dst < src_end && src < dst_end, "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
else
FC_ASSERT( src < dst_end && dst < src_end, "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
*/
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;
uint32_t* stream = &memoryRef<uint32_t>( mem, streamptr );
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;
}
DEFINE_INTRINSIC_FUNCTION2(env,AccountName_unpack,AccountName_unpack,none,i32,streamptr,i32,accountptr) {
auto& wasm = wasm_interface::get();
auto mem = wasm.current_memory;
uint32_t* stream = &memoryRef<uint32_t>( mem, streamptr );
const char* pos = &memoryRef<const char>( mem, stream[1] );
const char* end = &memoryRef<const char>( mem, stream[2] );
AccountName* name = &memoryRef<AccountName>( mem, accountptr );
fc::datastream<const char*> ds( pos, end - pos );
fc::raw::unpack( ds, *name );
stream[1] += ds.pos() - pos;
}
DEFINE_INTRINSIC_FUNCTION4(env,load,load,i32,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen ) {
ilog( "load" );
FC_ASSERT( keylen > 0 );
FC_ASSERT( valuelen >= 0 );
......@@ -61,20 +143,38 @@ DEFINE_INTRINSIC_FUNCTION4(env,load,load,i32,i32,keyptr,i32,keylen,i32,valueptr,
char* key = &memoryRef<char>( mem, keyptr );
char* value = &memoryRef<char>( mem, valueptr );
string keystr( key, key+keylen);
idump((keystr));
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 ) {
memcpy( value, obj->value.data(), copylen );
if( copylen == 8 ) idump(( *((int64_t*)value)));
}
return copylen;
}
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;
char* begin = &Runtime::memoryRef<char>( mem, destptr );
Runtime::memoryRef<char>( mem, destptr + destsize );
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;
}
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));
FC_ASSERT( test, "assertion failed: ${s}", ("s",message) );
FC_ASSERT( test, "assertion failed: ${s}", ("s",message)("ptr",msg) );
}
DEFINE_INTRINSIC_FUNCTION0(env,messageSize,messageSize,i32) {
return wasm_interface::get().current_validate_context->msg.data.size();
}
DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
......@@ -89,13 +189,16 @@ DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
DEFINE_INTRINSIC_FUNCTION1(env,printi,printi,none,i32,val) {
idump((val));
}
DEFINE_INTRINSIC_FUNCTION1(env,printi64,printi64,none,i64,val) {
idump((val));
}
DEFINE_INTRINSIC_FUNCTION2(env,print,print,none,i32,charptr,i32,size) {
FC_ASSERT( size > 0 );
char* str = &Runtime::memoryRef<char>( Runtime::getDefaultMemory(wasm_interface::get().current_module), charptr);
char* end = &Runtime::memoryRef<char>( Runtime::getDefaultMemory(wasm_interface::get().current_module), charptr+size);
const char* str = &Runtime::memoryRef<const char>( Runtime::getDefaultMemory(wasm_interface::get().current_module), charptr);
const char* end = &Runtime::memoryRef<const char>( Runtime::getDefaultMemory(wasm_interface::get().current_module), charptr+size);
edump((charptr)(size));
wlog( std::string( str, end ) );
wlog( std::string( str, size ) );
}
DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
......@@ -135,58 +238,6 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
// 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) );
// Then look for a named module.
auto namedResolverIt = moduleNameToResolverMap.find(moduleName);
if(namedResolverIt != moduleNameToResolverMap.end())
{
return namedResolverIt->second->resolve(moduleName,exportName,type,outObject);
}
// Finally, stub in missing function imports.
if(type.kind == ObjectKind::function)
{
// Generate a function body that just uses the unreachable op to fault if called.
Serialization::ArrayOutputStream codeStream;
OperatorEncoderStream encoder(codeStream);
encoder.unreachable();
encoder.end();
// Generate a module for the stub function.
Module stubModule;
DisassemblyNames stubModuleNames;
stubModule.types.push_back(asFunctionType(type));
stubModule.functions.defs.push_back({{0},{},std::move(codeStream.getBytes()),{}});
stubModule.exports.push_back({"importStub",ObjectKind::function,0});
stubModuleNames.functions.push_back({std::string(moduleName) + "." + exportName,{}});
IR::setDisassemblyNames(stubModule,stubModuleNames);
IR::validateDefinitions(stubModule);
// Instantiate the module and return the stub function instance.
auto stubModuleInstance = instantiateModule(stubModule,{});
outObject = getInstanceExport(stubModuleInstance,"importStub");
//Log::printf(Log::Category::error,"Generated stub for missing function import %s.%s : %s\n",moduleName.c_str(),exportName.c_str(),asString(type).c_str());
return true;
}
else if(type.kind == ObjectKind::memory)
{
outObject = asObject(Runtime::createMemory(asMemoryType(type)));
//Log::printf(Log::Category::error,"Generated stub for missing memory import %s.%s : %s\n",moduleName.c_str(),exportName.c_str(),asString(type).c_str());
return true;
}
else if(type.kind == ObjectKind::table)
{
outObject = asObject(Runtime::createTable(asTableType(type)));
//Log::printf(Log::Category::error,"Generated stub for missing table import %s.%s : %s\n",moduleName.c_str(),exportName.c_str(),asString(type).c_str());
return true;
}
else if(type.kind == ObjectKind::global)
{
outObject = asObject(Runtime::createGlobal(asGlobalType(type),Runtime::Value(asGlobalType(type).valueType,Runtime::UntaggedValue())));
//Log::printf(Log::Category::error,"Generated stub for missing global import %s.%s : %s\n",moduleName.c_str(),exportName.c_str(),asString(type).c_str());
return true;
}
return false;
}
};
......@@ -221,19 +272,44 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
return U32(ptr - &memoryRef<char>(current_memory,0));
}
void wasm_interface::vm_apply( const vector<char>& message )
void wasm_interface::vm_apply()
{ try {
try {
FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"apply"));
std::string mangledapply("onApply_");
mangledapply += std::string( current_validate_context->msg.type ) + "_";
mangledapply += std::string( current_validate_context->msg.recipient );
idump((mangledapply));
FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,mangledapply.c_str()));
if( !apply ) return; /// if not found then it is a no-op
const FunctionType* functionType = getFunctionType(apply);
FC_ASSERT( functionType->parameters.size() == 2 );
FC_ASSERT( functionType->parameters.size() == 0 );
std::vector<Value> args(0);
Runtime::invokeFunction(apply,args);
} catch( const Runtime::Exception& e ) {
edump((std::string(describeExceptionCause(e.cause))));
edump((e.callStack));
throw;
}
} FC_CAPTURE_AND_RETHROW() }
void wasm_interface::vm_onInit()
{ try {
try {
wlog( "onInit" );
FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"onInit"));
if( !apply ) {
wlog( "no onInit method found" );
return; /// if not found then it is a no-op
}
auto buffer = vm_allocate( message.size() );
memcpy( buffer, message.data(), message.size() );
const FunctionType* functionType = getFunctionType(apply);
FC_ASSERT( functionType->parameters.size() == 0 );
std::vector<Value> args(2);
args[0] = vm_pointer_to_offset(buffer);
args[1] = U32(message.size());
std::vector<Value> args(0);
Runtime::invokeFunction(apply,args);
} catch( const Runtime::Exception& e ) {
......@@ -241,25 +317,97 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
edump((e.callStack));
throw;
}
} FC_CAPTURE_AND_RETHROW( (message) ) }
} FC_CAPTURE_AND_RETHROW() }
void wasm_interface::apply( apply_context& c ) {
try {
load( c.scope, c.db );
current_validate_context = &c;
current_precondition_context = &c;
current_apply_context = &c;
vm_apply( current_validate_context->msg.data );
vm_apply();
} FC_CAPTURE_AND_RETHROW() }
void wasm_interface::init( apply_context& c ) {
try {
ilog( "WASM INTERFACE INIT" );
load( c.scope, c.db );
current_validate_context = &c;
current_precondition_context = &c;
current_apply_context = &c;
vm_onInit();
current_validate_context = nullptr;
current_precondition_context = nullptr;
current_apply_context = nullptr;
} FC_CAPTURE_AND_RETHROW() }
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;
state.code_version = -1;
}
state.module = new IR::Module();
try
{
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 );
state.init_memory.resize(1<<16); /// TODO: actually get memory size
memcpy( state.init_memory.data(), memstart, state.init_memory.size() );
std::cerr <<"INIT MEMORY: \n";
for( uint32_t i = 0; i < 10000; ++i )
if( memstart[i] )
std::cerr << (char)memstart[i];
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 );
char* memstart = &memoryRef<char>( current_memory, 0 );
memcpy( memstart, state.init_memory.data(), state.init_memory.size() );
}
/*
void wasm_interface::load(const char* bytes, size_t len)
{ try {
static vector<char> memory_backup;
......@@ -322,5 +470,6 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
throw;
}
} FC_CAPTURE_AND_RETHROW() }
*/
} }
......@@ -12,7 +12,7 @@ struct DefineStruct {
static void apply(chain::apply_context& context);
};
struct SetMessageHandler {
struct SetCode {
static void validate(chain::message_validate_context& context);
static void validate_preconditions(chain::precondition_validate_context& context);
static void apply(chain::apply_context& context);
......
#include <eos/native_contract/system_contract.hpp>
#include <eos/chain/message_handling_contexts.hpp>
#include <eos/chain/action_objects.hpp>
#include <eos/chain/account_object.hpp>
#include <eos/chain/type_object.hpp>
#include <eos/chain/exceptions.hpp>
#include <eos/chain/global_property_object.hpp>
#include <eos/chain/wasm_interface.hpp>
namespace eos {
using namespace chain;
......@@ -40,37 +41,34 @@ void DefineStruct::apply(apply_context& context) {
});
}
void SetMessageHandler::validate(message_validate_context& context) {
auto msg = context.msg.as<types::SetMessageHandler>();
void SetCode::validate(message_validate_context& context) {
auto msg = context.msg.as<types::SetCode>();
FC_ASSERT( msg.vmtype == 0 );
FC_ASSERT( msg.vmversion == 0 );
// TODO: verify code compiles and is properly sanitized
}
void SetMessageHandler::validate_preconditions(precondition_validate_context& context)
void SetCode::validate_preconditions(precondition_validate_context& context)
{ try {
auto& db = context.db;
auto msg = context.msg.as<types::SetMessageHandler>();
idump((msg.recipient)(msg.processor)(msg.type));
auto msg = context.msg.as<types::SetCode>();
// db.get<type_object,by_scope_name>( boost::make_tuple(msg.account, msg.type))
// TODO: verify code compiles
} FC_CAPTURE_AND_RETHROW() }
void SetMessageHandler::apply(apply_context& context) {
void SetCode::apply(apply_context& context) {
auto& db = context.mutable_db;
auto msg = context.msg.as<types::SetMessageHandler>();
const auto& processor_acnt = db.get<account_object,by_name>(msg.processor);
const auto& recipient_acnt = db.get<account_object,by_name>(msg.recipient);
db.create<action_code_object>( [&](auto& action){
action.processor = processor_acnt.id;
action.recipient = recipient_acnt.id;
action.type = msg.type;
action.validate_action = msg.validate.c_str(); ///TODO: fix this
action.validate_precondition = msg.precondition.c_str(); ///TODO: fix this
action.apply.resize(msg.apply.size());
memcpy( action.apply.data(), msg.apply.data(), msg.apply.size() );
auto msg = context.msg.as<types::SetCode>();
const auto& account = db.get<account_object,by_name>(msg.account);
wlog( "set code: ${size}", ("size",msg.code.size()));
db.modify( account, [&]( auto& a ) {
a.code_version++;
a.code.resize( msg.code.size() );
memcpy( a.code.data(), msg.code.data(), msg.code.size() );
});
idump((msg.apply));
apply_context init_context( context.mutable_db, chain::Message(), msg.account );
wasm_interface::get().init( init_context );
}
void CreateAccount::validate(message_validate_context& context) {
......
......@@ -76,13 +76,11 @@ struct CreateAccount
recovery Authority
deposit Asset
struct SetMessageHandler
processor AccountName # the account that is handling the message
recipient AccountName # the account the message was sent to
type TypeName # the type of message being processed (relative to to account)
validate String # the script to validate
precondition String # the pre condition validation
apply Bytes # the apply
struct SetCode
account AccountName # the account that is handling the message
vmtype UInt8 # the virtual machine type
vmversion UInt8 # the virtual machine version
code Bytes # the apply
struct CreateProducer
name AccountName
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册