提交 0cb05fe3 编写于 作者: D Daniel Larimer

Update create_script test to use contracts/currency

上级 2bd46dae
......@@ -159,6 +159,7 @@ if(ENABLE_COVERAGE_TESTING)
SET(CMAKE_CXX_FLAGS "--coverage ${CMAKE_CXX_FLAGS}")
endif()
add_subdirectory( contracts )
add_subdirectory( libraries )
add_subdirectory( programs )
add_subdirectory( plugins )
......
......@@ -103,3 +103,19 @@ docker-compose -f docker-compose.yml up
Done
### How to Build LLVM and clang for WASM
By default LLVM and clang do not include the WASM build target, so you will have to build it yourself. Note that following these instructions will create a version of LLVM that can only build WASM targets.
```
git clone --depth 1 --single-branch --branch release_40 git@github.com:llvm-mirror/llvm.git
cd llvm/tools
git clone --depth 1 --single-branch --branch release_40 git@github.com:llvm-mirror/clang.git
mkdir build
cd build
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=.. -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../
```
currency.wast: currency.cpp Makefile eos.hpp currency.hpp
/usr/local/Cellar/llvm/4.0.0_1/bin/clang-4.0 -emit-llvm -O3 --std=c++14 --target=wasm32 -nostdinc -c currency.cpp -I.. -fno-threadsafe-statics -fno-rtti -fno-exceptions
/Users/dlarimer/Downloads/llvm/build/bin/llc -asm-verbose=false currency.bc
/Users/dlarimer/eos/libraries/binaryen/bin/s2wasm -s 1024 currency.s > currency.wast
cat currency.wast
/usr/local/Cellar/llvm/4.0.0_1/bin/clang-4.0 -emit-llvm -O3 --std=c++14 --target=wasm32 -nostdinc -c currency.cpp -I.. -fno-threadsafe-statics -fno-rtti -fno-exceptions -o .currency.bc
/Users/dlarimer/Downloads/llvm/build/bin/llc -asm-verbose=false .currency.bc
/Users/dlarimer/eos/libraries/binaryen/bin/s2wasm -s 1024 .currency.s > currency.wast
wc -l currency.wast
echo '#pragma once ' > currency.wast.hpp
echo 'const char* currency_wast = R"=====(' >> currency.wast.hpp
cat currency.wast >> currency.wast.hpp
echo ')=====";' >> currency.wast.hpp
test.wast: test.cpp Makefile eos.hpp
......
......@@ -53,7 +53,7 @@ extern "C"
* The apply method implements the dispatch of events to this contract
*/
void apply( uint64_t code, uint64_t action ) {
assert( code == currentCode(), "invalid notice given" );
//assert( code == currentCode(), "invalid notice given" );
if( action == NAME("transfer") ) apply_currency_transfer();
}
}
......
......@@ -5,8 +5,8 @@
* accounts notified and that the sender has provided authorization.
*/
struct Transfer {
AccountName to;
AccountName from;
AccountName to;
uint64_t amount = 0;
char memo[]; /// extra bytes are treated as a memo and ignored by logic
};
#pragma once
const char* currency_wast = R"=====(
(module
(type $FUNCSIG$vj (func (param i64)))
(type $FUNCSIG$vii (func (param i32 i32)))
(type $FUNCSIG$iii (func (param i32 i32) (result i32)))
(type $FUNCSIG$j (func (result i64)))
(type $FUNCSIG$ijjjjii (func (param i64 i64 i64 i64 i32 i32) (result i32)))
(type $FUNCSIG$ijjj (func (param i64 i64 i64) (result i32)))
(type $FUNCSIG$ijjjii (func (param i64 i64 i64 i32 i32) (result i32)))
(import "env" "assert" (func $assert (param i32 i32)))
(import "env" "currentCode" (func $currentCode (result i64)))
(import "env" "load_i64" (func $load_i64 (param i64 i64 i64 i64 i32 i32) (result i32)))
(import "env" "readMessage" (func $readMessage (param i32 i32) (result i32)))
(import "env" "remove_i64" (func $remove_i64 (param i64 i64 i64) (result i32)))
(import "env" "requireAuth" (func $requireAuth (param i64)))
(import "env" "requireNotice" (func $requireNotice (param i64)))
(import "env" "store_i64" (func $store_i64 (param i64 i64 i64 i32 i32) (result i32)))
(table 0 anyfunc)
(memory $0 1)
(data (i32.const 4) "P\04\00\00")
(data (i32.const 48) "insufficient funds\00")
(export "memory" (memory $0))
(export "_Z23apply_currency_transferv" (func $_Z23apply_currency_transferv))
(export "init" (func $init))
(export "apply" (func $apply))
(func $_Z23apply_currency_transferv
(local $0 i64)
(local $1 i32)
(local $2 i64)
(local $3 i32)
(i32.store offset=4
(i32.const 0)
(tee_local $3
(i32.sub
(i32.load offset=4
(i32.const 0)
)
(i32.const 32)
)
)
)
(i64.store offset=24
(get_local $3)
(i64.const 0)
)
(drop
(call $readMessage
(i32.add
(get_local $3)
(i32.const 8)
)
(i32.const 24)
)
)
(set_local $0
(i64.load offset=8
(get_local $3)
)
)
(call $requireNotice
(i64.load offset=16
(get_local $3)
)
)
(call $requireNotice
(get_local $0)
)
(call $requireAuth
(i64.load offset=8
(get_local $3)
)
)
(block $label$0
(br_if $label$0
(i32.load8_u offset=24
(i32.const 0)
)
)
(i32.store8 offset=24
(i32.const 0)
(i32.const 1)
)
(i64.store offset=16
(i32.const 0)
(i64.const 0)
)
)
(block $label$1
(br_if $label$1
(i32.load8_u offset=40
(i32.const 0)
)
)
(i32.store8 offset=40
(i32.const 0)
(i32.const 1)
)
(i64.store offset=32
(i32.const 0)
(i64.const 0)
)
)
(drop
(call $load_i64
(i64.load offset=8
(get_local $3)
)
(call $currentCode)
(i64.const 497826380083)
(i64.const 21967113313)
(i32.const 16)
(i32.const 8)
)
)
(drop
(call $load_i64
(i64.load
(i32.add
(i32.add
(get_local $3)
(i32.const 8)
)
(i32.const 8)
)
)
(call $currentCode)
(i64.const 497826380083)
(i64.const 21967113313)
(i32.const 32)
(i32.const 8)
)
)
(call $assert
(i64.ge_u
(i64.load offset=16
(i32.const 0)
)
(i64.load
(tee_local $1
(i32.add
(get_local $3)
(i32.const 24)
)
)
)
)
(i32.const 48)
)
(i64.store offset=16
(i32.const 0)
(tee_local $2
(i64.sub
(i64.load offset=16
(i32.const 0)
)
(tee_local $0
(i64.load
(get_local $1)
)
)
)
)
)
(i64.store offset=32
(i32.const 0)
(i64.add
(get_local $0)
(i64.load offset=32
(i32.const 0)
)
)
)
(set_local $0
(i64.load offset=8
(get_local $3)
)
)
(block $label$2
(block $label$3
(br_if $label$3
(i64.eq
(get_local $2)
(i64.const 0)
)
)
(drop
(call $store_i64
(get_local $0)
(i64.const 497826380083)
(i64.const 21967113313)
(i32.const 16)
(i32.const 8)
)
)
(br $label$2)
)
(drop
(call $remove_i64
(get_local $0)
(i64.const 497826380083)
(i64.const 21967113313)
)
)
)
(drop
(call $store_i64
(i64.load
(i32.add
(i32.add
(get_local $3)
(i32.const 8)
)
(i32.const 8)
)
)
(i64.const 497826380083)
(i64.const 21967113313)
(i32.const 32)
(i32.const 8)
)
)
(i32.store offset=4
(i32.const 0)
(i32.add
(get_local $3)
(i32.const 32)
)
)
)
(func $init
(local $0 i32)
(i32.store offset=4
(i32.const 0)
(tee_local $0
(i32.sub
(i32.load offset=4
(i32.const 0)
)
(i32.const 16)
)
)
)
(i64.store offset=8
(get_local $0)
(i64.const 1000000000)
)
(drop
(call $store_i64
(i64.const 862690298531)
(i64.const 497826380083)
(i64.const 21967113313)
(i32.add
(get_local $0)
(i32.const 8)
)
(i32.const 8)
)
)
(i32.store offset=4
(i32.const 0)
(i32.add
(get_local $0)
(i32.const 16)
)
)
)
(func $apply (param $0 i64) (param $1 i64)
(block $label$0
(br_if $label$0
(i64.ne
(get_local $1)
(i64.const 624065709652)
)
)
(call $_Z23apply_currency_transferv)
)
)
)
)=====";
......@@ -42,10 +42,8 @@ int32_t store_i64( AccountName scope, TableName table, uint64_t key, const void*
int32_t load_i64( AccountName scope, AccountName code, TableName table, uint64_t key, void* data, uint32_t datalen );
int32_t remove_i64( AccountName scope, TableName table, uint64_t key );
/**
* @return the current account scope within which the currentCode() is being applied.
*/
AccountName currentContext();
void print( const char* cstr );
void printi( uint64_t value );
/**
* @return the account which specifes the code that is being run
......@@ -203,7 +201,7 @@ struct Db
template<typename T>
T currentMessage() {
static T value;
T value;
readMessage( &value, sizeof(value) );
return value;
}
......
......@@ -568,9 +568,6 @@ void chain_controller::validate_referenced_accounts(const SignedTransaction& trx
"Message recipient accounts out of order. Possibly a bug in the wallet?",
("current", current_recipient.value)("previous", previous_recipient->value));
}
EOS_ASSERT(current_recipient != msg.code, message_validate_exception,
"Code account is listed among recipients. Possibly a bug in the wallet?");
previous_recipient = &current_recipient;
}
}
......
......@@ -17,6 +17,10 @@ namespace eos { namespace chain {
wasm_interface::wasm_interface() {
}
DEFINE_INTRINSIC_FUNCTION0(env,currentCode,currentCode,i64) {
auto& wasm = wasm_interface::get();
return wasm.current_validate_context->code.value;
}
DEFINE_INTRINSIC_FUNCTION4(env,store,store,none,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen ) {
// ilog( "store ${keylen} ${vallen}", ("keylen",keylen)("vallen",valuelen) );
/*
......@@ -51,11 +55,19 @@ DEFINE_INTRINSIC_FUNCTION4(env,store,store,none,i32,keyptr,i32,keylen,i32,valuep
}
*/
}
DEFINE_INTRINSIC_FUNCTION1(env,requireAuth,requireAuth,none,i64,account) {
}
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 );
DEFINE_INTRINSIC_FUNCTION1(env,requireNotice,requireNotice,none,i64,account) {
}
DEFINE_INTRINSIC_FUNCTION3(env,remove_i64,remove_i64,i32,i64,scope,i64,table,i64,key)
{
return 0;
}
DEFINE_INTRINSIC_FUNCTION5(env,store_i64,store_i64,i32,i64,scope,i64,table,i64,key,i32,valueptr,i32,valuelen)
{
FC_ASSERT( valuelen >= 0 );
auto& wasm = wasm_interface::get();
......@@ -63,21 +75,61 @@ DEFINE_INTRINSIC_FUNCTION4(env,load,load,i32,i32,keyptr,i32,keylen,i32,valueptr,
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& code = wasm.current_apply_context->code;
auto mem = wasm.current_memory;
char* key = memoryArrayPtr<char>( mem, keyptr, keylen );
char* value = memoryArrayPtr<char>( mem, valueptr, valuelen );
string keystr( key, key+keylen);
char* value = memoryArrayPtr<char>( mem, valueptr, valuelen);
const auto* obj = db.find<key_value_object,by_scope_key>( boost::make_tuple(scope, keystr) );
if( obj == nullptr ) return -1;
//idump((Name(scope))(Name(code))(Name(table))(Name(key))(valuelen) );
const auto* obj = db.find<key_value_object,by_scope_key>( boost::make_tuple(
AccountName(scope),
AccountName(code),
AccountName(table),
AccountName(key) ) );
if( obj ) {
db.modify( *obj, [&]( auto& o ) {
o.value.assign(value, valuelen);
});
} else {
db.create<key_value_object>( [&](auto& o) {
o.scope = scope;
o.code = code;
o.table = table;
o.key = key;
o.value.insert( 0, value, valuelen );
});
}
return 0;
}
DEFINE_INTRINSIC_FUNCTION6(env,load_i64,load_i64,i32,i64,scope,i64,code,i64,table,i64,key,i32,valueptr,i32,valuelen)
{
//idump((Name(scope))(Name(code))(Name(table))(Name(key))(valuelen) );
FC_ASSERT( valuelen >= 0 );
auto& wasm = wasm_interface::get();
FC_ASSERT( wasm.current_validate_context, "no apply context found" );
auto& db = wasm.current_apply_context->mutable_db;
auto mem = wasm.current_memory;
char* value = memoryArrayPtr<char>( mem, valueptr, valuelen);
const auto* obj = db.find<key_value_object,by_scope_key>( boost::make_tuple(
AccountName(scope),
AccountName(code),
AccountName(table),
AccountName(key) ) );
if( obj == nullptr ) {
wlog( "not found" );
return -1;
}
auto copylen = std::min<size_t>(obj->value.size(),valuelen);
if( copylen ) {
obj->value.copy(value, copylen);
}
return copylen;
*/
return 0;
}
......@@ -216,8 +268,8 @@ DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
}
DEFINE_INTRINSIC_FUNCTION1(env,printi,printi,none,i64,val) {
std::cerr << uint64_t(val);
// idump((val));
std::cerr << uint64_t(val) << " " << Name(val).toString();
//idump((val)(Name(val)));
}
DEFINE_INTRINSIC_FUNCTION1(env,print,print,none,i32,charptr) {
......@@ -227,7 +279,7 @@ DEFINE_INTRINSIC_FUNCTION1(env,print,print,none,i32,charptr) {
const char* str = &memoryRef<const char>( mem, charptr );
std::cerr << std::string( str, strlen(str) );
// wlog( std::string( str, strlen(size) ) );
wdump( (std::string( str, strlen(str) )) );
}
DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
......@@ -297,7 +349,10 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
*/
/// TODO: cache this somehow
FunctionInstance* call = asFunctionNullable(getInstanceExport(current_module,name) );
if( !call )
if( !call ) {
//wlog( "unable to find call ${name}", ("name",name));
return;
}
//FC_ASSERT( apply, "no entry point found for ${call}", ("call", std::string(name)) );
FC_ASSERT( getFunctionType(call)->parameters.size() == 2 );
......@@ -324,10 +379,10 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
void wasm_interface::vm_onInit()
{ try {
try {
// wlog( "on_init" );
wlog( "on_init" );
FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"init"));
if( !apply ) {
wlog( "no onInit method found" );
elog( "no onInit method found" );
return; /// if not found then it is a no-op
}
......@@ -406,6 +461,7 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
try
{
wlog( "LOADING CODE" );
auto start = fc::time_point::now();
Serialization::MemoryInputStream stream((const U8*)recipient.code.data(),recipient.code.size());
WASM::serialize(stream,*state.module);
......@@ -413,6 +469,9 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
LinkResult linkResult = linkModule(*state.module,rootResolver);
state.instance = instantiateModule( *state.module, std::move(linkResult.resolvedImports) );
FC_ASSERT( state.instance );
auto end = fc::time_point::now();
idump(( (end-start).count()/1000000.0) );
current_memory = Runtime::getDefaultMemory(state.instance);
char* memstart = &memoryRef<char>( current_memory, 0 );
......
......@@ -144,6 +144,11 @@ namespace NativeTypes
static Intrinsics::Function cName##returnType##arg0Type##arg1Type##arg2Type##arg3Type##arg4Type##Function(#module "." #name,IR::FunctionType::get(IR::ResultType::returnType,{IR::ValueType::arg0Type,IR::ValueType::arg1Type,IR::ValueType::arg2Type,IR::ValueType::arg3Type,IR::ValueType::arg4Type}),(void*)&cName##returnType##arg0Type##arg1Type##arg2Type##arg3Type##arg4Type); \
NativeTypes::returnType cName##returnType##arg0Type##arg1Type##arg2Type##arg3Type##arg4Type(NativeTypes::arg0Type arg0Name,NativeTypes::arg1Type arg1Name,NativeTypes::arg2Type arg2Name,NativeTypes::arg3Type arg3Name,NativeTypes::arg4Type arg4Name)
#define DEFINE_INTRINSIC_FUNCTION6(module,cName,name,returnType,arg0Type,arg0Name,arg1Type,arg1Name,arg2Type,arg2Name,arg3Type,arg3Name,arg4Type,arg4Name,arg5Type,arg5Name) \
NativeTypes::returnType cName##returnType##arg0Type##arg1Type##arg2Type##arg3Type##arg4Type##arg5Type(NativeTypes::arg0Type,NativeTypes::arg1Type,NativeTypes::arg2Type,NativeTypes::arg3Type,NativeTypes::arg4Type,NativeTypes::arg5Type); \
static Intrinsics::Function cName##returnType##arg0Type##arg1Type##arg2Type##arg3Type##arg4Type##arg5Type##Function(#module "." #name,IR::FunctionType::get(IR::ResultType::returnType,{IR::ValueType::arg0Type,IR::ValueType::arg1Type,IR::ValueType::arg2Type,IR::ValueType::arg3Type,IR::ValueType::arg4Type,IR::ValueType::arg5Type}),(void*)&cName##returnType##arg0Type##arg1Type##arg2Type##arg3Type##arg4Type##arg5Type); \
NativeTypes::returnType cName##returnType##arg0Type##arg1Type##arg2Type##arg3Type##arg4Type##arg5Type(NativeTypes::arg0Type arg0Name,NativeTypes::arg1Type arg1Name,NativeTypes::arg2Type arg2Name,NativeTypes::arg3Type arg3Name,NativeTypes::arg4Type arg4Name,NativeTypes::arg5Type arg5Name )
// Macros for defining intrinsic globals, memories, and tables.
#define DEFINE_INTRINSIC_GLOBAL(module,cName,name,valueType,isMutable,initializer) \
static Intrinsics::GenericGlobal<IR::ValueType::valueType,isMutable> \
......
......@@ -13,3 +13,4 @@ target_link_libraries( chain_test eos_native_contract eos_chain chainbase eos_ut
file(GLOB SLOW_TESTS "slow_tests/*.cpp")
add_executable( slow_test ${SLOW_TESTS} ${COMMON_SOURCES} )
target_link_libraries( slow_test eos_native_contract eos_chain chainbase eos_utilities eos_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
target_include_directories( slow_test PUBLIC ${CMAKE_SOURCE_DIR}/contracts )
......@@ -162,15 +162,15 @@ BOOST_FIXTURE_TEST_CASE(create_script, testing_fixture)
{ try {
Make_Blockchain(chain);
chain.produce_blocks(10);
Make_Account(chain, simplecoin);
Make_Account(chain, currency);
chain.produce_blocks(1);
#include "wast/simplecoin.wast"
#include <currency/currency.wast.hpp>
types::setcode handler;
handler.account = "simplecoin";
handler.account = "currency";
auto wasm = assemble_wast( simplecoin_wast );
auto wasm = assemble_wast( currency_wast );
handler.code.resize(wasm.size());
memcpy( handler.code.data(), wasm.data(), wasm.size() );
......@@ -178,7 +178,7 @@ BOOST_FIXTURE_TEST_CASE(create_script, testing_fixture)
eos::chain::SignedTransaction trx;
trx.messages.resize(1);
trx.messages[0].code = config::SystemContractName;
trx.messages[0].recipients = {"simplecoin"};
trx.messages[0].recipients = {"currency"};
trx.setMessage(0, "setcode", handler);
trx.expiration = chain.head_block_time() + 100;
trx.set_reference_block(chain.head_block_id());
......@@ -188,18 +188,18 @@ BOOST_FIXTURE_TEST_CASE(create_script, testing_fixture)
auto start = fc::time_point::now();
for (uint32_t i = 0; i < 100000; ++i)
for (uint32_t i = 0; i < 10000; ++i)
{
eos::chain::SignedTransaction trx;
trx.emplaceMessage("simplecoin", vector<AccountName>{"inita"},
trx.emplaceMessage("currency", vector<AccountName>{"inita","currency"},
vector<types::AccountPermission>{},
"transfer", types::transfer{"simplecoin", "inita", 1+i, "hello"});
"transfer", types::transfer{"currency", "inita", 1+i, "hello"});
trx.expiration = chain.head_block_time() + 100;
trx.set_reference_block(chain.head_block_id());
chain.push_transaction(trx);
}
auto end = fc::time_point::now();
idump((100000*1000000.0 / (end-start).count()));
idump((10000*1000000.0 / (end-start).count()));
chain.produce_blocks(10);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册