diff --git a/Jenkinsfile b/Jenkinsfile index 3a61e3a96288686efcd268b8c34d1d60326f29a5..4839c726c9511ee4fb3e9ab698c9ad1617a377fd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -39,7 +39,6 @@ pipeline { steps { sh ''' . $HOME/.bash_profile - export EOSLIB=$(pwd)/contracts cd build printf "Waiting for testing to be available..." while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done @@ -53,7 +52,6 @@ pipeline { steps { sh ''' . $HOME/.bash_profile - export EOSLIB=$(pwd)/contracts cd build printf "Waiting for testing to be available..." while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done @@ -67,7 +65,6 @@ pipeline { steps { sh ''' . $HOME/.bash_profile - export EOSLIB=$(pwd)/contracts cd build printf "Waiting for testing to be available..." while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done @@ -94,4 +91,4 @@ pipeline { } } } -} \ No newline at end of file +} diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index 06390f40ae292d6850ecdfca0f64ca6481519aef..c4f3e37824cee59e54d754a16c12bd14ec152e91 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -22,11 +22,13 @@ add_subdirectory(proxy) add_subdirectory(test_api) add_subdirectory(test_api_mem) add_subdirectory(test_api_db) -#add_subdirectory(simpledb) +add_subdirectory(simpledb) #add_subdirectory(storage) #add_subdirectory(social) add_subdirectory(test.system) add_subdirectory(noop) install( DIRECTORY eosiolib DESTINATION include/ ) +install( DIRECTORY musl DESTINATION include/ ) +install( DIRECTORY libc++ DESTINATION include/ ) install( DIRECTORY skeleton DESTINATION share/ ) diff --git a/contracts/simpledb/simpledb.abi b/contracts/simpledb/simpledb.abi index f5fc5aaac208c3fd5d4c3e36b9987260b64661a6..9b8ae3ec89415ec884790c06efb4c474cb203d76 100644 --- a/contracts/simpledb/simpledb.abi +++ b/contracts/simpledb/simpledb.abi @@ -3,73 +3,211 @@ "structs": [{ "name": "record1", "base": "", - "fields": [ - {"name":"key", "type":"uint64"}, - {"name":"u256", "type":"uint256"}, - {"name":"u128", "type":"uint128"}, - {"name":"u64", "type":"uint64"}, - {"name":"u32", "type":"uint32"}, - {"name":"u16", "type":"uint16"}, - {"name":"u8", "type":"uint8"}, - {"name":"i64", "type":"int64"}, - {"name":"i32", "type":"int32"}, - {"name":"i16", "type":"int16"}, - {"name":"i8", "type":"int8"}, - {"name":"price", "type":"price"} + "fields": [{ + "name": "key", + "type": "uint64" + },{ + "name": "u256", + "type": "uint256" + },{ + "name": "u128", + "type": "uint128" + },{ + "name": "u64", + "type": "uint64" + },{ + "name": "u32", + "type": "uint32" + },{ + "name": "u16", + "type": "uint16" + },{ + "name": "u8", + "type": "uint8" + },{ + "name": "i64", + "type": "int64" + },{ + "name": "i32", + "type": "int32" + },{ + "name": "i16", + "type": "int16" + },{ + "name": "i8", + "type": "int8" + } + ] + },{ + "name": "insert_record1", + "base": "", + "fields": [{ + "name": "r1", + "type": "record1" + } + ] + },{ + "name": "remove_record1", + "base": "", + "fields": [{ + "name": "key", + "type": "uint64" + } ] },{ "name": "record2", "base": "", - "fields": [ - {"name":"key1", "type":"uint128"}, - {"name":"key2", "type":"uint128"} + "fields": [{ + "name": "key1", + "type": "uint128" + },{ + "name": "key2", + "type": "uint128" + } + ] + },{ + "name": "insert_record2", + "base": "", + "fields": [{ + "name": "r2", + "type": "record2" + } + ] + },{ + "name": "remove_record2", + "base": "", + "fields": [{ + "name": "key", + "type": "record2" + } ] },{ "name": "record3", "base": "", - "fields": [ - {"name":"key1", "type":"uint64"}, - {"name":"key2", "type":"uint64"}, - {"name":"key3", "type":"uint64"} + "fields": [{ + "name": "key1", + "type": "uint64" + },{ + "name": "key2", + "type": "uint64" + },{ + "name": "key3", + "type": "uint64" + } + ] + },{ + "name": "insert_record3", + "base": "", + "fields": [{ + "name": "r3", + "type": "record3" + } + ] + },{ + "name": "remove_record3", + "base": "", + "fields": [{ + "name": "key", + "type": "record3" + } ] },{ "name": "key_value1", "base": "", - "fields": [ - {"name":"key", "type":"string"}, - {"name":"value", "type":"string"} + "fields": [{ + "name": "key", + "type": "string" + },{ + "name": "value", + "type": "string" + } + ] + },{ + "name": "insert_keyvalue1", + "base": "", + "fields": [{ + "name": "kv1", + "type": "key_value1" + } + ] + },{ + "name": "remove_keyvalue1", + "base": "", + "fields": [{ + "name": "key", + "type": "string" + } ] },{ "name": "complex_type", "base": "", - "fields": [ - {"name":"name", "type":"string"}, - {"name":"age", "type":"uint64"} + "fields": [{ + "name": "name", + "type": "string" + },{ + "name": "age", + "type": "uint64" + } ] },{ "name": "key_value2", "base": "", - "fields": [ - {"name":"key", "type":"string"}, - {"name":"value", "type":"complex_type"} + "fields": [{ + "name": "key", + "type": "string" + },{ + "name": "value", + "type": "complex_type" + } + ] + },{ + "name": "insert_keyvalue2", + "base": "", + "fields": [{ + "name": "kv2", + "type": "key_value2" + } + ] + },{ + "name": "remove_keyvalue2", + "base": "", + "fields": [{ + "name": "key", + "type": "string" + } ] } ], "actions": [{ "name": "insert1", - "type": "record1" + "type": "insert_record1" + },{ + "name": "remove1", + "type": "remove_record1" },{ "name": "insert2", - "type": "record2" + "type": "insert_record2" + },{ + "name": "remove2", + "type": "remove_record2" },{ "name": "insert3", - "type": "record3" + "type": "insert_record3" + },{ + "name": "remove3", + "type": "remove_record3" },{ "name": "insertkv1", - "type": "key_value1" + "type": "insert_keyvalue1" + },{ + "name": "removekv1", + "type": "remove_keyvalue1" },{ "name": "insertkv2", - "type": "key_value2" + "type": "insert_keyvalue2" + },{ + "name": "removekv2", + "type": "remove_keyvalue2" } ], "tables": [{ diff --git a/contracts/simpledb/simpledb.cpp b/contracts/simpledb/simpledb.cpp index 0415a8dea3f3dd2c0914ea43773a140c2ee131e6..568e043e481d6d6e88889cea3b35220c9a985472 100644 --- a/contracts/simpledb/simpledb.cpp +++ b/contracts/simpledb/simpledb.cpp @@ -2,60 +2,225 @@ * @file * @copyright defined in eos/LICENSE.txt */ -#include "simpledb.hpp" -#include "simpledb.gen.hpp" - -#include +#include +#include #include -#include +#include +#include +#include -extern "C" { +using namespace eosio; + +namespace simpledb { - void apply( uint64_t code, uint64_t action ) { - if( code == N(simpledb) ) { - if( action == N(insertkv1) ) { - // eosioc push message simpledb insertkv1 '{"key":"a", "value":"aa"}' -S simpledb - // eosioc get table simpledb simpledb keyvalue1 - auto kv1 = eosio::current_action(); - eosio::print("Inserting key_value1\n"); - eosio::dump(kv1); - bytes b = eosio::raw::pack(kv1.value); - uint32_t err = store_str( N(simpledb), N(keyvalue1), (char *)kv1.key.get_data(), kv1.key.get_size(), (char*)b.data, b.len); - } else if( action == N(insertkv2) ) { - // eosioc push message simpledb insertkv2 '{"key":"a", "value":{"name":"aaa", "age":10}}' -S simpledb - // eosioc get table simpledb simpledb keyvalue2 - auto kv2 = eosio::current_action(); - eosio::print("Inserting key_value2\n"); - eosio::dump(kv2); - bytes b = eosio::raw::pack(kv2.value); - uint32_t err = store_str( N(simpledb), N(keyvalue2), (char *)kv2.key.get_data(), kv2.key.get_size(), (char*)b.data, b.len); - } else if( action == N(insert1) ) { - // eosioc push message simpledb insert1 '{"key":75}' -S simpledb - // eosioc get table simpledb simpledb record1 - auto tmp = eosio::current_action(); - eosio::print("Inserting record1\n"); - eosio::dump(tmp); - auto bytes = eosio::raw::pack(tmp); - store_i64( N(simpledb), N(record1), bytes.data, bytes.len); - } else if(action == N(insert2)) { - // eosioc push message simpledb insert2 '{"key1":"75", "key2":"77"}' -S simpledb - // eosioc get table simpledb simpledb record2 - auto tmp = eosio::current_action(); - eosio::print("Inserting record2\n"); - eosio::dump(tmp); - auto bytes = eosio::raw::pack(tmp); - store_i128i128( N(simpledb), N(record2), bytes.data, bytes.len); - } else if(action == N(insert3)) { - // eosioc push message simpledb insert3 '{"key1":75, "key2":77, "key3":79}' -S simpledb - // eosioc get table simpledb simpledb record3 - auto tmp = eosio::current_action(); - eosio::print("Inserting record3\n"); - eosio::dump(tmp); - auto bytes = eosio::raw::pack(tmp); - store_i64i64i64( N(simpledb), N(record3), bytes.data, bytes.len); - } else { - eosio_assert(0, "unknown message"); + template + struct dispatchable { + constexpr static uint64_t action_name = Val; + }; + + //@abi table + struct record1 { + + uint64_t key; + + uint256 u256; + uint128_t u128; + uint64_t u64; + uint32_t u32; + uint16_t u16; + uint8_t u8; + + int64_t i64; + int32_t i32; + int16_t i16; + int8_t i8; + + EOSLIB_SERIALIZE( record1, (key)(u256)(u128)(u64)(u32)(u16)(u8)(i64)(i32)(i16)(i8) ); + }; + + //@abi action insert1 + struct insert_record1 : dispatchable { + record1 r1; + void process() { + bytes b = eosio::pack(r1); + store_i64( N(simpledb), N(record1), N(simpledb), b.data(), b.size()); + } + + EOSLIB_SERIALIZE( insert_record1, (r1) ); + }; + + //@abi action remove1 + struct remove_record1 : dispatchable { + uint64_t key; + void process() { + remove_i64( N(simpledb), N(record1), (char *)this); + } + + EOSLIB_SERIALIZE( remove_record1, (key) ); + }; + + //@abi table + struct record2 { + uint128_t key1; + uint128_t key2; + + EOSLIB_SERIALIZE( record2, (key1)(key2) ); + }; + + //@abi action insert2 + struct insert_record2 : dispatchable { + record2 r2; + void process() { + bytes b = eosio::pack(r2); + store_i128i128( N(simpledb), N(record2), N(simpledb), b.data(), b.size()); + } + + EOSLIB_SERIALIZE( insert_record2, (r2) ); + }; + + //@abi action remove2 + struct remove_record2 : dispatchable { + record2 key; + void process() { + bytes b = eosio::pack(key); + remove_i128i128( N(simpledb), N(record2), b.data()); + } + + EOSLIB_SERIALIZE( remove_record2, (key) ); + }; + + //@abi table + struct record3 { + uint64_t key1; + uint64_t key2; + uint64_t key3; + + EOSLIB_SERIALIZE( record3, (key1)(key2)(key3) ); + }; + + //@abi action insert3 + struct insert_record3 : dispatchable { + record3 r3; + void process() { + bytes b = eosio::pack(r3); + store_i128i128( N(simpledb), N(record3), N(simpledb), b.data(), b.size()); + } + + EOSLIB_SERIALIZE( insert_record3, (r3) ); + }; + + //@abi action remove3 + struct remove_record3 : dispatchable { + record3 key; + void process() { + bytes b = eosio::pack(key); + remove_i64i64i64( N(simpledb), N(record2), b.data()); + } + + EOSLIB_SERIALIZE( remove_record3, (key) ); + }; + + //@abi table + struct key_value1 { + std::string key; + std::string value; + + EOSLIB_SERIALIZE( key_value1, (key)(value) ); + }; + + //@abi action insertkv1 + struct insert_keyvalue1 : dispatchable { + key_value1 kv1; + void process() { + eosio_assert(false, "not implemented"); + // bytes b = eosio::pack(kv1.value); + // store_str( N(simpledb), N(keyvalue1), N(simpledb), (char *)kv1.key.data(), kv1.key.size(), b.data(), b.size()); + } + + EOSLIB_SERIALIZE( insert_keyvalue1, (kv1) ); + }; + + //@abi action removekv1 + struct remove_keyvalue1 : dispatchable { + std::string key; + void process() { + eosio_assert(false, "not implemented"); + //remove_str( N(simpledb), N(keyvalue1), (char *)key.data(), key.size() ); + } + + EOSLIB_SERIALIZE( remove_keyvalue1, (key) ); + }; + + struct complex_type { + std::string name; + uint64_t age; + + EOSLIB_SERIALIZE( complex_type, (name)(age) ); + }; + + //@abi table + struct key_value2 { + std::string key; + complex_type value; + + EOSLIB_SERIALIZE( key_value2, (key)(value) ); + }; + + //@abi action insertkv2 + struct insert_keyvalue2 : dispatchable { + key_value2 kv2; + void process() { + eosio_assert(false, "not implemented"); + // bytes b = eosio::pack(kv2.value); + // store_str( N(simpledb), N(keyvalue2), N(simpledb), (char *)kv2.key.data(), kv2.key.size(), b.data(), b.size()); + } + + EOSLIB_SERIALIZE( insert_keyvalue2, (kv2) ); + }; + + //@abi action removekv2 + struct remove_keyvalue2 : dispatchable { + std::string key; + void process() { + remove_str( N(simpledb), N(keyvalue2), (char *)key.data(), key.size() ); + } + + EOSLIB_SERIALIZE( remove_keyvalue2, (key) ); + }; + + template + struct dispatcher_impl; + + template + struct dispatcher_impl { + static bool dispatch(uint64_t action) { + if (action == T::action_name) { + unpack_action().process(); + return true; } + + return false; } - } + }; + + template + struct dispatcher_impl { + static bool dispatch(uint64_t action) { + return dispatcher_impl::dispatch(action) || dispatcher_impl::dispatch(action); + } + }; + + using dispatcher = dispatcher_impl; } + +extern "C" { + + /// The apply method implements the dispatch of events to this contract + void apply( uint64_t code, uint64_t act ) { + if (code == current_receiver()) { + auto action_processed = simpledb::dispatcher::dispatch(act); + eosio_assert(action_processed, "unknown action"); + } + } + +} \ No newline at end of file diff --git a/contracts/simpledb/simpledb.gen.hpp b/contracts/simpledb/simpledb.gen.hpp deleted file mode 100644 index eb6544cb6553b6a1c8b76a6f22e4ade8b9c516f6..0000000000000000000000000000000000000000 --- a/contracts/simpledb/simpledb.gen.hpp +++ /dev/null @@ -1,152 +0,0 @@ -#pragma once -#include -#include -#include - -namespace eosio { namespace raw { - template inline void pack( Stream& s, const record1& value ) { - raw::pack(s, value.key); - raw::pack(s, value.u256); - raw::pack(s, value.u128); - raw::pack(s, value.u64); - raw::pack(s, value.u32); - raw::pack(s, value.u16); - raw::pack(s, value.u8); - raw::pack(s, value.i64); - raw::pack(s, value.i32); - raw::pack(s, value.i16); - raw::pack(s, value.i8); - raw::pack(s, value.price); - } - template inline void unpack( Stream& s, record1& value ) { - raw::unpack(s, value.key); - raw::unpack(s, value.u256); - raw::unpack(s, value.u128); - raw::unpack(s, value.u64); - raw::unpack(s, value.u32); - raw::unpack(s, value.u16); - raw::unpack(s, value.u8); - raw::unpack(s, value.i64); - raw::unpack(s, value.i32); - raw::unpack(s, value.i16); - raw::unpack(s, value.i8); - raw::unpack(s, value.price); - } - template inline void pack( Stream& s, const record2& value ) { - raw::pack(s, value.key1); - raw::pack(s, value.key2); - } - template inline void unpack( Stream& s, record2& value ) { - raw::unpack(s, value.key1); - raw::unpack(s, value.key2); - } - template inline void pack( Stream& s, const record3& value ) { - raw::pack(s, value.key1); - raw::pack(s, value.key2); - raw::pack(s, value.key3); - } - template inline void unpack( Stream& s, record3& value ) { - raw::unpack(s, value.key1); - raw::unpack(s, value.key2); - raw::unpack(s, value.key3); - } - template inline void pack( Stream& s, const key_value1& value ) { - raw::pack(s, value.key); - raw::pack(s, value.value); - } - template inline void unpack( Stream& s, key_value1& value ) { - raw::unpack(s, value.key); - raw::unpack(s, value.value); - } - template inline void pack( Stream& s, const complex_type& value ) { - raw::pack(s, value.name); - raw::pack(s, value.age); - } - template inline void unpack( Stream& s, complex_type& value ) { - raw::unpack(s, value.name); - raw::unpack(s, value.age); - } - template inline void pack( Stream& s, const key_value2& value ) { - raw::pack(s, value.key); - raw::pack(s, value.value); - } - template inline void unpack( Stream& s, key_value2& value ) { - raw::unpack(s, value.key); - raw::unpack(s, value.value); - } -} } - -#include -namespace eosio { - void print_ident(int n){while(n-->0){print(" ");}}; - template - Type current_message_ex() { - uint32_t size = action_size(); - char* data = (char *)eosio::malloc(size); - eos_assert(data && read_action(data, size) == size, "error reading message"); - Type value; - eosio::raw::unpack(data, size, value); - eosio::free(data); - return value; - } - void dump(const record1& value, int tab=0) { - print_ident(tab);print("key:[");printi(uint64_t(value.key));print("]\n"); - print_ident(tab);print("u256:[");printhex((void*)&value.u256, sizeof(value.u256));print("]\n"); - print_ident(tab);print("u128:[");printi128(&value.u128);print("]\n"); - print_ident(tab);print("u64:[");printi(uint64_t(value.u64));print("]\n"); - print_ident(tab);print("u32:[");printi(uint64_t(value.u32));print("]\n"); - print_ident(tab);print("u16:[");printi(uint64_t(value.u16));print("]\n"); - print_ident(tab);print("u8:[");printi(uint64_t(value.u8));print("]\n"); - print_ident(tab);print("i64:[");printi(uint64_t(value.i64));print("]\n"); - print_ident(tab);print("i32:[");printi(uint64_t(value.i32));print("]\n"); - print_ident(tab);print("i16:[");printi(uint64_t(value.i16));print("]\n"); - print_ident(tab);print("i8:[");printi(uint64_t(value.i8));print("]\n"); - print_ident(tab);print("price:[");print("]\n"); - } - template<> - record1 current_action() { - return current_message_ex(); - } - void dump(const record2& value, int tab=0) { - print_ident(tab);print("key1:[");printi128(&value.key1);print("]\n"); - print_ident(tab);print("key2:[");printi128(&value.key2);print("]\n"); - } - template<> - record2 current_action() { - return current_message_ex(); - } - void dump(const record3& value, int tab=0) { - print_ident(tab);print("key1:[");printi(uint64_t(value.key1));print("]\n"); - print_ident(tab);print("key2:[");printi(uint64_t(value.key2));print("]\n"); - print_ident(tab);print("key3:[");printi(uint64_t(value.key3));print("]\n"); - } - template<> - record3 current_action() { - return current_message_ex(); - } - void dump(const key_value1& value, int tab=0) { - print_ident(tab);print("key:[");print("]\n"); - print_ident(tab);print("value:[");print("]\n"); - } - template<> - key_value1 current_action() { - return current_message_ex(); - } - void dump(const complex_type& value, int tab=0) { - print_ident(tab);print("name:[");print("]\n"); - print_ident(tab);print("age:[");printi(uint64_t(value.age));print("]\n"); - } - template<> - complex_type current_action() { - return current_message_ex(); - } - void dump(const key_value2& value, int tab=0) { - print_ident(tab);print("key:[");print("]\n"); - print_ident(tab);print("value:[");print("\n"); eosio::dump(value.value, tab+1);print_ident(tab);print("]\n"); - } - template<> - key_value2 current_action() { - return current_message_ex(); - } -} //eosio - diff --git a/contracts/simpledb/simpledb.hpp b/contracts/simpledb/simpledb.hpp deleted file mode 100644 index f8c02c6a1051645084bfd96f4890248fa81c0df2..0000000000000000000000000000000000000000 --- a/contracts/simpledb/simpledb.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include -#include - -/* @abi action insert1 - * @abi table -*/ -struct record1 { - uint64_t key; - - uint256 u256; - uint128_t u128; - uint64_t u64; - uint32_t u32; - uint16_t u16; - uint8_t u8; - - int64_t i64; - int32_t i32; - int16_t i16; - int8_t i8; - - price price; -}; - -/* @abi action insert2 - * @abi table -*/ -struct record2 { - uint128_t key1; - uint128_t key2; -}; - -/* @abi action insert3 - * @abi table -*/ -struct record3 { - uint64_t key1; - uint64_t key2; - uint64_t key3; -}; - -/* @abi action insertkv1 - * @abi table -*/ -struct key_value1 { - eosio::string key; - eosio::string value; -}; - -struct complex_type { - eosio::string name; - uint64_t age; -}; - - -/* @abi action insertkv2 - * @abi table -*/ -struct key_value2 { - eosio::string key; - complex_type value; -}; diff --git a/libraries/abi_generator/abi_generator.cpp b/libraries/abi_generator/abi_generator.cpp index 7306f10b9184a8897d6a9cd52ba93dfa9e5b6620..40291074fdad9a8156bb4db3f9430a67d6e7e5e0 100644 --- a/libraries/abi_generator/abi_generator.cpp +++ b/libraries/abi_generator/abi_generator.cpp @@ -27,18 +27,29 @@ void abi_generator::set_compiler_instance(CompilerInstance& compiler_instance) { } void abi_generator::handle_tagdecl_definition(TagDecl* tag_decl) { - ASTContext& ctx = tag_decl->getASTContext(); - auto decl_location = tag_decl->getLocation().printToString(ctx.getSourceManager()); + ast_context = &tag_decl->getASTContext(); + auto decl_location = tag_decl->getLocation().printToString(ast_context->getSourceManager()); try { handle_decl(tag_decl); } FC_CAPTURE_AND_RETHROW((decl_location)) } string abi_generator::remove_namespace(const string& full_name) { - string type_name = full_name; - auto pos = type_name.find_last_of("::"); - if(pos != string::npos) - type_name = type_name.substr(pos+1); - return type_name; + int i = full_name.size(); + int on_spec = 0; + int colons = 0; + while( --i >= 0 ) { + if( full_name[i] == '>' ) { + ++on_spec; colons=0; + } else if( full_name[i] == '<' ) { + --on_spec; colons=0; + } else if( full_name[i] == ':' && !on_spec) { + if (++colons == 2) + return full_name.substr(i+2); + } else { + colons = 0; + } + } + return full_name; } bool abi_generator::is_builtin_type(const string& type_name) { @@ -70,13 +81,14 @@ void abi_generator::handle_decl(const Decl* decl) { try { ABI_ASSERT(decl != nullptr); ABI_ASSERT(output != nullptr); + ABI_ASSERT(ast_context != nullptr); - ASTContext& ctx = decl->getASTContext(); - const RawComment* raw_comment = ctx.getRawCommentForDeclNoCache(decl); + //ASTContext& ctx = decl->getASTContext(); + const RawComment* raw_comment = ast_context->getRawCommentForDeclNoCache(decl); if(!raw_comment) return; - SourceManager& source_manager = ctx.getSourceManager(); + SourceManager& source_manager = ast_context->getSourceManager(); auto file_name = source_manager.getFilename(raw_comment->getLocStart()); if ( !abi_context.empty() && !file_name.startswith(abi_context) ) { return; @@ -105,7 +117,7 @@ void abi_generator::handle_decl(const Decl* decl) { try { auto qt = action_decl->getTypeForDecl()->getCanonicalTypeInternal(); - auto type_name = remove_namespace(add_struct(qt)); + auto type_name = add_struct(qt); ABI_ASSERT(!is_builtin_type(type_name), "A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name)); @@ -128,7 +140,7 @@ void abi_generator::handle_decl(const Decl* decl) { try { ABI_ASSERT(table_decl != nullptr); auto qt = table_decl->getTypeForDecl()->getCanonicalTypeInternal(); - auto type_name = remove_namespace(add_struct(qt)); + auto type_name = add_struct(qt); ABI_ASSERT(!is_builtin_type(type_name), "A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name)); @@ -140,16 +152,16 @@ void abi_generator::handle_decl(const Decl* decl) { try { table.name = boost::algorithm::to_lower_copy(boost::erase_all_copy(type_name, "_")); table.type = type_name; - if(params.size() >= 1) - table.index_type = params[0]; + if(params.size() >= 1) { + table.name = params[0]; + } + + if(params.size() >= 2) + table.index_type = params[1]; else { try { guess_index_type(table, *s); } FC_CAPTURE_AND_RETHROW( (type_name) ) } - if(params.size() >= 2) { - table.name = params[1]; - } - try { guess_key_names(table, *s); } FC_CAPTURE_AND_RETHROW( (type_name) ) @@ -181,9 +193,11 @@ bool abi_generator::is_string(const string& type) { void abi_generator::get_all_fields(const struct_def& s, vector& fields) { abi_serializer abis(*output); + for(const auto& field : s.fields) { fields.push_back(field); } + if(s.base.size()) { const auto* base = find_struct(s.base); ABI_ASSERT(base, "Unable to find base type ${type}",("type",s.base)); @@ -211,7 +225,7 @@ void abi_generator::guess_index_type(table_def& table, const struct_def s) { vector fields; get_all_fields(s, fields); - + if( is_str_index(fields) ) { table.index_type = "str"; } else if ( is_i64i64i64_index(fields) ) { @@ -230,15 +244,28 @@ void abi_generator::guess_key_names(table_def& table, const struct_def s) { vector fields; get_all_fields(s, fields); - if( table.index_type == "i64i64i64" && is_i64i64i64_index(fields) ) { - table.key_names = vector{fields[0].name, fields[1].name, fields[2].name}; - table.key_types = vector{fields[0].type, fields[1].type, fields[2].type}; - } else if( table.index_type == "i128i128" && is_i128i128_index(fields) ) { - table.key_names = vector{fields[0].name, fields[1].name}; - table.key_types = vector{fields[0].type, fields[1].type}; - } else if( table.index_type == "i64" && is_i64_index(fields) ) { - table.key_names = vector{fields[0].name}; - table.key_types = vector{fields[0].type}; + if( table.index_type == "i64i64i64" || table.index_type == "i128i128" + || table.index_type == "i64") { + + table.key_names.clear(); + table.key_types.clear(); + + unsigned int key_size = 0; + bool valid_key = false; + for(auto& f : fields) { + table.key_names.emplace_back(f.name); + table.key_types.emplace_back(f.type); + key_size += type_size[f.type]/8; + + if((table.index_type == "i64i64i64" && key_size >= sizeof(uint64_t)*3) || + (table.index_type == "i64" && key_size >= sizeof(uint64_t)) || + (table.index_type == "i128i128" && key_size >= sizeof(__int128)*2)) { + valid_key = true; + break; + } + } + + ABI_ASSERT(valid_key, "Unable to guess key names"); } else if( table.index_type == "str" && is_str_index(fields) ) { table.key_names = vector{fields[0].name}; table.key_types = vector{fields[0].type}; @@ -298,95 +325,196 @@ bool abi_generator::is_one_filed_no_base(const string& type_name) { } string abi_generator::decl_to_string(clang::Decl* d) { - ASTContext& ctx = d->getASTContext(); - const auto& sm = ctx.getSourceManager(); + //ASTContext& ctx = d->getASTContext(); + const auto& sm = ast_context->getSourceManager(); clang::SourceLocation b(d->getLocStart()), _e(d->getLocEnd()); clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, sm, compiler_instance->getLangOpts())); return string(sm.getCharacterData(b), sm.getCharacterData(e)-sm.getCharacterData(b)); } -void abi_generator::add_typedef(const clang::TypedefType* typeDef) { +bool abi_generator::is_typedef(const clang::QualType& qt) { + return isa(qt.getTypePtr()); +} - vector types_to_add; - while(typeDef != nullptr) { - const auto* typedef_decl = typeDef->getDecl(); - auto qt = typedef_decl->getUnderlyingType().getUnqualifiedType(); +bool abi_generator::is_elaborated(const clang::QualType& qt) { + return isa(qt.getTypePtr()); +} - auto full_name = translate_type(qt.getAsString(compiler_instance->getLangOpts())); +bool abi_generator::is_vector(const clang::QualType& vqt) { + + QualType qt(vqt); - //HACK: We need to think another way to stop importing the "typedef chain" - if( full_name.find("<") != string::npos ) { - break; - } + if ( is_elaborated(qt) ) + qt = qt->getAs()->getNamedType(); - auto new_type_name = translate_type(typedef_decl->getName().str()); - if(is_builtin_type(new_type_name)) { - break; - } + return isa(qt.getTypePtr()) \ + && boost::starts_with( get_type_name(qt, false), "vector"); +} + +bool abi_generator::is_vector(const string& type_name) { + return boost::ends_with(type_name, "[]"); +} - //TODO: ABI_ASSERT TypeName length for typedef - type_def abi_typedef; - abi_typedef.new_type_name = new_type_name; - abi_typedef.type = remove_namespace( full_name ); +bool abi_generator::is_struct_specialization(const clang::QualType& qt) { + return is_struct(qt) && isa(qt.getTypePtr()); +} - const auto* td = find_type(abi_typedef.new_type_name); - if( td ) { - ABI_ASSERT(abi_typedef.type == td->type); - typeDef = qt->getAs(); - continue; - } +bool abi_generator::is_struct(const clang::QualType& sqt) { + clang::QualType qt(sqt); + const auto* type = qt.getTypePtr(); + return !is_vector(qt) && (type->isStructureType() || type->isClassType()); +} + +clang::QualType abi_generator::get_vector_element_type(const clang::QualType& qt) { + const auto* tst = clang::dyn_cast(qt.getTypePtr()); + ABI_ASSERT(tst != nullptr); + const clang::TemplateArgument& arg0 = tst->getArg(0); + return arg0.getAsType(); +} + +string abi_generator::get_vector_element_type(const string& type_name) { + if( is_vector(type_name) ) + return type_name.substr(0, type_name.size()-2); + return type_name; +} + +string abi_generator::get_type_name(const clang::QualType& qt, bool with_namespace=false) { + auto name = clang::TypeName::getFullyQualifiedName(qt, *ast_context); + if(!with_namespace) + name = remove_namespace(name); + return name; +} + +clang::QualType abi_generator::add_typedef(const clang::QualType& tqt) { - //ilog("addTypeDef => ${a} ${b} [${c}]", ("a",abi_typedef.new_type_name)("b",abi_typedef.type)("c",getFullScope(qt))); - ABI_ASSERT(abi_typedef.new_type_name != abi_typedef.type, - "Unable to export typedef `${td}` at ${at}", - ("td",decl_to_string(typeDef->getDecl())) - ("at",typeDef->getDecl()->getLocation().printToString(typeDef->getDecl()->getASTContext().getSourceManager())) - ); + clang::QualType qt(get_named_type_if_elaborated(tqt)); - types_to_add.push_back(abi_typedef); - typeDef = qt->getAs(); + const auto* td_decl = qt->getAs()->getDecl(); + auto underlying_type = td_decl->getUnderlyingType().getUnqualifiedType(); + + auto new_type_name = td_decl->getName().str(); + auto underlying_type_name = get_type_name(underlying_type); + + if ( is_vector(underlying_type) ) { + underlying_type_name = add_vector(underlying_type); + } + + type_def abi_typedef; + abi_typedef.new_type_name = new_type_name; + abi_typedef.type = translate_type(underlying_type_name); + const auto* td = find_type(abi_typedef.new_type_name); + + if(!td && !is_struct_specialization(underlying_type) ) { + output->types.push_back(abi_typedef); + } else { + if(td) ABI_ASSERT(abi_typedef.type == td->type); } - std::reverse(types_to_add.begin(), types_to_add.end()); - output->types.insert(output->types.end(), types_to_add.begin(), types_to_add.end()); + if( is_typedef(underlying_type) && !is_builtin_type(get_type_name(underlying_type)) ) + return add_typedef(underlying_type); + + return underlying_type; } -string abi_generator::get_name_to_add(const clang::QualType& qual_type) { +clang::CXXRecordDecl::base_class_range abi_generator::get_struct_bases(const clang::QualType& sqt) { - auto type_name = qual_type.getAsString(compiler_instance->getLangOpts()); - const auto* typedef_type = qual_type->getAs(); - if( !is_builtin_type(type_name) && typedef_type != nullptr) { - add_typedef(typedef_type); - } + clang::QualType qt(sqt); + if(is_typedef(qt)) { + const auto* td_decl = qt->getAs()->getDecl(); + qt = td_decl->getUnderlyingType().getUnqualifiedType(); + } + + const auto* record_type = qt->getAs(); + ABI_ASSERT(record_type != nullptr); + auto cxxrecord_decl = clang::dyn_cast(record_type->getDecl()); + ABI_ASSERT(cxxrecord_decl != nullptr); + //record_type->getCanonicalTypeInternal().dump(); - return type_name; + auto bases = cxxrecord_decl->bases(); + + return bases; } -string abi_generator::add_struct(const clang::QualType& qual_type) { +const clang::RecordDecl::field_range abi_generator::get_struct_fields(const clang::QualType& sqt) { + clang::QualType qt(sqt); - ABI_ASSERT(output != nullptr); + if(is_typedef(qt)) { + const auto* td_decl = qt->getAs()->getDecl(); + qt = td_decl->getUnderlyingType().getUnqualifiedType(); + } - const auto* record_type = qual_type->getAs(); + const auto* record_type = qt->getAs(); ABI_ASSERT(record_type != nullptr); + return record_type->getDecl()->fields(); +} + +string abi_generator::add_vector(const clang::QualType& vqt) { + + clang::QualType qt(get_named_type_if_elaborated(vqt)); + + auto vector_element_type = get_vector_element_type(qt); + ABI_ASSERT(!is_vector(vector_element_type), "Only one-dimensional arrays are supported"); - const auto* record_decl = clang::cast_or_null(record_type->getDecl()->getDefinition()); - ABI_ASSERT(record_decl != nullptr); + add_type(vector_element_type); + + auto vector_element_type_str = translate_type(get_type_name(vector_element_type)); + vector_element_type_str += "[]"; - ASTContext& ctx = record_decl->getASTContext(); + return vector_element_type_str; +} - auto full_name = get_name_to_add(qual_type); +string abi_generator::add_type(const clang::QualType& tqt) { - auto name = remove_namespace(full_name); + clang::QualType qt(get_named_type_if_elaborated(tqt)); - //Only export user defined types - if( is_builtin_type(name) ) { - return name; + string full_type_name = translate_type(get_type_name(qt, true)); + string type_name = translate_type(get_type_name(qt)); + bool is_type_def = false; + + if( is_builtin_type(type_name) ) { + return type_name; + } + + if( is_typedef(qt) ) { + qt = add_typedef(qt); + if( is_builtin_type(translate_type(get_type_name(qt))) ) { + return type_name; + } + is_type_def = true; + } + + if( is_vector(qt) ) { + auto vector_type_name = add_vector(qt); + return is_type_def ? type_name : vector_type_name; + } + + if( is_struct(qt) ) { + return add_struct(qt, full_type_name); + } + + ABI_ASSERT(false, "types can only be: vector, struct, class or a built-in type. (${type}) ", ("type",get_type_name(qt))); + return type_name; +} + +clang::QualType abi_generator::get_named_type_if_elaborated(const clang::QualType& qt) { + if( is_elaborated(qt) ) { + return qt->getAs()->getNamedType(); } + return qt; +} - const auto* type = qual_type.getTypePtr(); +string abi_generator::add_struct(const clang::QualType& sqt, string full_name) { + + clang::QualType qt(get_named_type_if_elaborated(sqt)); + + if( full_name.empty() ) { + full_name = get_type_name(qt, true); + } - ABI_ASSERT(type->isStructureType() || type->isClassType(), "Only struct and class are supported. ${full_name}",("full_name",full_name)); + auto name = remove_namespace(full_name); + + ABI_ASSERT(is_struct(qt), "Only struct and class are supported. ${full_name}",("full_name",full_name)); ABI_ASSERT(name.size() <= sizeof(type_name), "Type name > ${maxsize}, ${name}", @@ -400,58 +528,52 @@ string abi_generator::add_struct(const clang::QualType& qual_type) { return name; } - auto bases = record_decl->bases(); - auto total_bases = distance(bases.begin(), bases.end()); - if( total_bases > 1 ) { - ABI_ASSERT(false, "Multiple inheritance not supported - ${type}", ("type",full_name)); - } + auto bases = get_struct_bases(qt); + auto bitr = bases.begin(); + int total_bases = 0; string base_name; - if( total_bases == 1 ) { - auto qt = bases.begin()->getType(); - base_name = add_struct(qt); + while( bitr != bases.end() ) { + auto base_qt = bitr->getType(); + const auto* record_type = base_qt->getAs(); + if( record_type && is_struct(base_qt) && !record_type->getDecl()->field_empty() ) { + ABI_ASSERT(total_bases == 0, "Multiple inheritance not supported - ${type}", ("type",full_name)); + base_name = add_type(base_qt); + ++total_bases; + } + ++bitr; } struct_def abi_struct; - for (const auto& field : record_decl->fields()) { - - field_def struct_field; - + for (const clang::FieldDecl* field : get_struct_fields(qt) ) { clang::QualType qt = field->getType(); + + string field_name = field->getNameAsString(); + string field_type_name = add_type(qt); - auto field_type = translate_type(remove_namespace(get_name_to_add(qt.getUnqualifiedType()))); - - ABI_ASSERT(field_type.size() <= sizeof(decltype(struct_field.type)), - "Type name > ${maxsize}, ${type}::${name}", ("type",full_name)("name",field_type)("maxsize",sizeof(decltype(struct_field.type)))); + field_def struct_field{field_name, field_type_name}; + ABI_ASSERT(is_builtin_type(get_vector_element_type(struct_field.type)) + || find_struct(get_vector_element_type(struct_field.type)) + || find_type(get_vector_element_type(struct_field.type)) + , "Unknown type ${type} [${abi}]",("type",struct_field.type)("abi",*output)); - ABI_ASSERT(field->getNameAsString().size() <= sizeof(decltype(struct_field.name)) , - "Field name > ${maxsize}, ${type}::${name}", ("type",full_name)("name",field->getNameAsString())("maxsize", sizeof(decltype(struct_field.name)))); - - if( qt->getAs() ) { - add_struct(qt); - //TODO: simplify if OPT_SINGLE_FIELD_STRUCT is enabled - } - - struct_field.name = field->getNameAsString(); - struct_field.type = field_type; + ABI_ASSERT(struct_field.type.size() <= sizeof(decltype(struct_field.type)), + "Type name > ${maxsize}, ${type}::${name}", ("type",struct_field.type)("name",struct_field.name)("maxsize",sizeof(decltype(struct_field.type)))); - ABI_ASSERT(is_builtin_type(struct_field.type) || find_struct(struct_field.type), "Unknown type ${type} ${name} ${ttt} ${sss}", ("type",struct_field.type)("name",struct_field.name)("types", output->types)("structs",output->structs)); + ABI_ASSERT(field->getNameAsString().size() <= sizeof(decltype(struct_field.name)) , + "Field name > ${maxsize}, ${type}::${name}", ("type",struct_field.type)("name",struct_field.name)("maxsize",sizeof(decltype(struct_field.type)))); - type_size[string(struct_field.type)] = ctx.getTypeSize(qt); + type_size[string(struct_field.type)] = is_vector(struct_field.type) ? 0 : ast_context->getTypeSize(qt); abi_struct.fields.push_back(struct_field); } abi_struct.name = resolve_type(name); - abi_struct.base = remove_namespace(base_name); - - output->structs.push_back(abi_struct); - - if(verbose) { - cerr << "Adding type " << resolve_type(name) << " (" << full_name << ")\n"; - } + abi_struct.base = base_name; + output->structs.push_back(abi_struct); + full_types[name] = full_name; - return full_name; + return name; } } \ No newline at end of file diff --git a/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp b/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp index ac962ebafbe1726943dabba6861eb1e0810c1c83..f21af91d4b69d0c6603dbafdd426e1cc1f30f12f 100644 --- a/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp +++ b/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp @@ -19,6 +19,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Tooling/Tooling.h" #include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Core/QualTypeNames.h" #include "llvm/Support/raw_ostream.h" #include @@ -60,7 +61,7 @@ namespace eosio { map type_size; map full_types; string abi_context; - + clang::ASTContext* ast_context; public: enum optimization { @@ -70,7 +71,8 @@ namespace eosio { abi_generator() :optimizations(0) , output(nullptr) - , compiler_instance(nullptr) + , compiler_instance(nullptr) + , ast_context(nullptr) {} ~abi_generator() {} @@ -161,11 +163,29 @@ namespace eosio { string decl_to_string(clang::Decl* d); - void add_typedef(const clang::TypedefType* typeDef); + bool is_typedef(const clang::QualType& qt); + QualType add_typedef(const clang::QualType& qt); + + bool is_vector(const clang::QualType& qt); + bool is_vector(const string& type_name); + string add_vector(const clang::QualType& qt); + + bool is_struct(const clang::QualType& qt); + string add_struct(const clang::QualType& qt, string full_type_name=""); + + string get_type_name(const clang::QualType& qt, bool no_namespace); + string add_type(const clang::QualType& tqt); + + bool is_elaborated(const clang::QualType& qt); + bool is_struct_specialization(const clang::QualType& qt); - string get_name_to_add(const clang::QualType& qual_type); + QualType get_vector_element_type(const clang::QualType& qt); + string get_vector_element_type(const string& type_name); + + clang::QualType get_named_type_if_elaborated(const clang::QualType& qt); - string add_struct(const clang::QualType& qual_type); + const clang::RecordDecl::field_range get_struct_fields(const clang::QualType& qt); + clang::CXXRecordDecl::base_class_range get_struct_bases(const clang::QualType& qt); }; struct abi_generator_astconsumer : public ASTConsumer { diff --git a/libraries/chain/contracts/eosio_contract.cpp b/libraries/chain/contracts/eosio_contract.cpp index ea0339ac40095ca1eb1edbdbf2fb994464e5cc29..09b982cecd179c000f8634249786983db5888204 100644 --- a/libraries/chain/contracts/eosio_contract.cpp +++ b/libraries/chain/contracts/eosio_contract.cpp @@ -181,14 +181,19 @@ void apply_eosio_updateauth(apply_context& context) { if (act_auth.permission == config::owner_name || act_auth.permission == update.permission) { return true; } - - auto current = db.get(boost::make_tuple(update.account, update.permission)); - while(current.name != config::owner_name) { - if (current.name == act_auth.permission) { + const permission_object *current = db.find(boost::make_tuple(update.account, update.permission)); + // Permission doesn't exist yet, check parent permission + if (current == nullptr) current = db.find(boost::make_tuple(update.account, update.parent)); + // Ensure either the permission or parent's permission exists + EOS_ASSERT(current != nullptr, permission_query_exception, + "Fail to retrieve permission for: {\"actor\": \"${actor}\", \"permission\": \"${permission}\" }", + ("actor", update.account)("permission", update.parent)); + + while(current->name != config::owner_name) { + if (current->name == act_auth.permission) { return true; } - - current = db.get(current.parent); + current = &db.get(current->parent); } return false; diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 3b74deb3a325dc6c6d6d11222a87683115acc3aa..a3a252e51737b84ad789f78ae4001110b4e2d5f6 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -21,6 +21,9 @@ namespace eosio { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( black_swan_exception, eosio::chain::chain_exception, 3100000, "black swan" ) FC_DECLARE_DERIVED_EXCEPTION( unknown_block_exception, eosio::chain::chain_exception, 3110000, "unknown block" ) FC_DECLARE_DERIVED_EXCEPTION( chain_type_exception, eosio::chain::chain_exception, 3120000, "chain type exception" ) + FC_DECLARE_DERIVED_EXCEPTION( missing_plugin_exception, eosio::chain::chain_exception, 3130000, "missing plugin exception" ) + + FC_DECLARE_DERIVED_EXCEPTION( permission_query_exception, eosio::chain::database_query_exception, 3010001, "permission query exception" ) FC_DECLARE_DERIVED_EXCEPTION( block_tx_output_exception, eosio::chain::block_validate_exception, 3020001, "transaction outputs in block do not match transaction outputs from applying block" ) FC_DECLARE_DERIVED_EXCEPTION( block_concurrency_exception, eosio::chain::block_validate_exception, 3020002, "block does not guarantee concurrent exection without conflicts" ) @@ -60,6 +63,11 @@ namespace eosio { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( transaction_type_exception, eosio::chain::chain_type_exception, 3120005, "Invalid transaction" ) FC_DECLARE_DERIVED_EXCEPTION( abi_type_exception, eosio::chain::chain_type_exception, 3120006, "Invalid ABI" ) + FC_DECLARE_DERIVED_EXCEPTION( missing_chain_api_plugin_exception, eosio::chain::missing_plugin_exception, 3130001, "Missing Chain API Plugin" ) + FC_DECLARE_DERIVED_EXCEPTION( missing_wallet_api_plugin_exception, eosio::chain::missing_plugin_exception, 3130002, "Missing Wallet API Plugin" ) + FC_DECLARE_DERIVED_EXCEPTION( missing_account_history_api_plugin_exception, eosio::chain::missing_plugin_exception, 3130003, "Missing Account History API Plugin" ) + FC_DECLARE_DERIVED_EXCEPTION( missing_net_api_plugin_exception, eosio::chain::missing_plugin_exception, 3130003, "Missing Net API Plugin" ) + #define EOS_RECODE_EXC( cause_type, effect_type ) \ catch( const cause_type& e ) \ diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index 886826aa12a6109e98d9a9f40531cc33bd1284cd..338254a37421be53f4e049627c8607b1da83d250 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -2,6 +2,5 @@ add_subdirectory( eosiod ) add_subdirectory( eosioc ) add_subdirectory( eosiowd ) add_subdirectory( eosio-launcher ) -add_subdirectory( eosio-codegen ) add_subdirectory( eosio-applesedemo ) add_subdirectory( eosio-abigen ) diff --git a/programs/eosio-abigen/main.cpp b/programs/eosio-abigen/main.cpp index 6636e0d0c7810ab4b58404cb1810e73d6f0cef91..f45747fc1947ce46bb96fb99071a38b32df6ba96 100644 --- a/programs/eosio-abigen/main.cpp +++ b/programs/eosio-abigen/main.cpp @@ -42,16 +42,14 @@ static cl::opt abi_opt_sfs( cl::desc("Optimize single field struct"), cl::cat(abi_generator_category)); -int main(int argc, const char **argv) { try { +int main(int argc, const char **argv) { abi_def output; try { CommonOptionsParser op(argc, argv, abi_generator_category); ClangTool Tool(op.getCompilations(), op.getSourcePathList()); - abi_def abi; - - int result = Tool.run(create_factory(abi_verbose, abi_opt_sfs, abi_context, abi).get()); + int result = Tool.run(create_factory(abi_verbose, abi_opt_sfs, abi_context, output).get()); if(!result) { - abi_serializer(abi).validate(); - fc::json::save_to_file(abi, abi_destination, true); + abi_serializer(output).validate(); + fc::json::save_to_file(output, abi_destination, true); } return result; -} FC_CAPTURE_AND_LOG(()); return -1; } +} FC_CAPTURE_AND_LOG((output)); return -1; } diff --git a/programs/eosio-codegen/CMakeLists.txt b/programs/eosio-codegen/CMakeLists.txt deleted file mode 100644 index 12d8b124a8d90b57d59271a75f02b05cb7f234c6..0000000000000000000000000000000000000000 --- a/programs/eosio-codegen/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -add_executable( eosio-codegen main.cpp ) -if( UNIX AND NOT APPLE ) - set(rt_library rt ) -endif() - -find_package( Gperftools QUIET ) -if( GPERFTOOLS_FOUND ) - message( STATUS "Found gperftools; compiling steemd with TCMalloc") - list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc ) -endif() - -target_link_libraries( eosio-codegen - PRIVATE fc eosio_chain ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) - -install( TARGETS - eosio-codegen - - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib -) diff --git a/programs/eosio-codegen/main.cpp b/programs/eosio-codegen/main.cpp deleted file mode 100644 index db5c60f30e469c232ea289ae1bd509e36cd3785c..0000000000000000000000000000000000000000 --- a/programs/eosio-codegen/main.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - * @brief generates serialization/deserialization functions for contracts types - **/ -#include -#include -#include - -#include -#include -#include - -#include - - -using namespace std; -using namespace eosio::chain::contracts; - -const string tab = " "; - -struct codegen { - - abi_def abi; - abi_serializer abis; - codegen(const abi_def& abi) - :abi(abi) - { - abis.set_abi(abi); - } - - void generate_ident(ostringstream& output) { - output << tab << "void print_ident(int n){while(n-->0){print(\" \");}};" << endl; - } - - void generate_dump(ostringstream& output, const struct_def& type) { - output << tab << "void dump(const " << type.name << "& value, int tab=0) {" << endl; - for(const auto& field : type.fields ) { - auto field_type = abis.resolve_type(field.type); - output << tab << tab << "print_ident(tab);"; - output << "print(\"" << field.name << ":[\");"; - if( abis.is_struct(field_type) ) { - output << "print(\"\\n\"); eosio::dump(value."<< field.name <<", tab+1);"; - output << "print_ident(tab);"; - } else if( field_type == "string" ) { - output << "prints_l(value."<< field.name <<".get_data(), value."<< field.name <<".get_size());"; - } else if( field_type == "fixed_string32" || field_type == "fixed_string16" ) { - output << "prints_l(value."<< field.name <<".str, value."<< field.name <<".len);"; - } else if( field_type == "Bytes" ) { - output << "printhex(value."<< field.name <<".data, value."<< field.name <<".len);"; - } else if( abis.is_integer(field_type) ) { - auto size = abis.get_integer_size(field_type); - if(size <= 64) { - output << "printi(uint64_t(value."<< field.name <<"));"; - } else if (size == 128) { - output << "printi128(&value."<< field.name <<");"; - } else if (size == 256) { - output << "printhex((void*)&value."<< field.name <<", sizeof(value."<< field.name <<"));"; - } - - } else if( field_type == "bytes" ) { - output << "printhex(value."<< field.name <<".data, value."<< field.name <<".len);"; - } else if( field_type == "name" || field_type == "account_name" || field_type == "permission_name" ||\ - field_type == "token_name" || field_type == "table_name" || field_type == "func_name" ) { - output << "printn(value."<< field.name <<");"; - } else if( field_type == "public_key" ) { - output << "printhex((void*)value."<< field.name <<".data, 33);"; - } else if( field_type == "time" ) { - output << "printi(value."<< field.name <<");"; - } else if( field_type == "price" ) { - output << "printi(value."<< field.name <<".base.amount);print(\"/\");printi(value."<< field.name <<".quote.amount);"; - } else { - - } - output << "print(\"]\\n\");" << endl; - } - output << tab << "}" << endl; - } - - void generate_current_message_ex(ostringstream& output) { - output << tab << "template" << endl; - output << tab << "Type current_message_ex() {" << endl; - output << tab << tab << "uint32_t size = message_size();" << endl; - output << tab << tab << "char* data = (char *)eosio::malloc(size);" << endl; - output << tab << tab << "assert(data && read_message(data, size) == size, \"error reading message\");" << endl; - output << tab << tab << "Type value;" << endl; - output << tab << tab << "eosio::raw::unpack(data, size, value);" << endl; - output << tab << tab << "eosio::free(data);" << endl; - output << tab << tab << "return value;" << endl; - output << tab << "}" << endl; - } - - void generate_current_message(ostringstream& output, const struct_def& type) { - output << tab << "template<>" << endl; - output << tab << type.name << " current_message<" << type.name << ">() {" << endl; - output << tab << tab << "return current_message_ex<" << type.name << ">();" << endl; - output << tab << "}" << endl; - } - - void generate_pack(ostringstream& output, const struct_def& type) { - output << tab << "template inline void pack( Stream& s, const " << type.name << "& value ) {" << endl; - for(const auto& field : type.fields ) { - output << tab << tab << "raw::pack(s, value." << field.name << ");" << endl; - } - if( type.base != type_name() ) - output << tab << tab << "raw::pack(s, static_cast(value));" << endl; - output << tab << "}" << endl; - } - - void generate_unpack(ostringstream& output, const struct_def& type) { - output << tab << "template inline void unpack( Stream& s, " << type.name << "& value ) {" << endl; - for(const auto& field : type.fields ) { - output << tab << tab << "raw::unpack(s, value." << field.name << ");" << endl; - } - if( type.base != type_name() ) - output << tab << tab << "raw::unpack(s, static_cast<" << type.base << "&>(value));" << endl; - output << tab << "}" << endl; - } - - void generate() { - ostringstream output; - output << "#pragma once" << endl; - output << "#include " << endl; - output << "#include " << endl; - output << "#include " << endl; - output << "#include " << endl; - - output << endl; - - //Generate serialization/deserialization for every cotract type - output << "namespace eosio { namespace raw {" << endl; - for(const auto& type : abi.structs) { - generate_pack(output, type); - generate_unpack(output, type); - } - output << "} }" << endl << endl; - - output << "#include " << endl; - - output << "namespace eosio {" << endl; - - generate_ident(output); - generate_current_message_ex(output); - - for(const auto& type : abi.structs) { - generate_dump(output, type); - generate_current_message(output, type); - } - - output << "} //eosio" << endl; - - cout << output.str() << endl; - } - -}; - - -//------------------------------------------------------------ - -int main (int argc, char *argv[]) { - - if( argc < 2 ) - return 1; - - auto abi = fc::json::from_file(argv[1]); - codegen generator(abi); - generator.generate(); - - return 0; -} diff --git a/programs/eosioc/help_text.cpp b/programs/eosioc/help_text.cpp index d05192b62195539311c982bd003b94c1e3a5937c..62a39ba5d3ede610fd2ff15144f55fbe5da00639 100644 --- a/programs/eosioc/help_text.cpp +++ b/programs/eosioc/help_text.cpp @@ -183,7 +183,13 @@ e.g. }] })====="; -const char* error_advice_3030002 = R"=====(Ensure that you have the related private keys inside your wallet)====="; +const char* error_advice_3030002 = "Ensure that you have the related private keys inside your wallet."; + +const char* error_advice_3130001 = "Ensure that you have \033[2meosio::chain_api_plugin\033[0m\033[32m added to your node's configuration."; +const char* error_advice_3130002 = "Ensure that you have \033[2meosio::wallet_api_plugin\033[0m\033[32m added to your node's configuration.\n"\ + "Otherwise specify your wallet location with \033[2m--wallet-host\033[0m\033[32m and \033[2m--wallet_port\033[0m\033[32m arguments."; +const char* error_advice_3130003 = "Ensure that you have \033[2meosio::account_history_api_plugin\033[0m\033[32m added to your node's configuration."; +const char* error_advice_3130004 = "Ensure that you have \033[2meosio::net_api_plugin\033[0m\033[32m added to your node's configuration"; const std::map error_advice = { { 3120001, error_advice_3120001 }, @@ -192,6 +198,10 @@ const std::map error_advice = { { 3120004, error_advice_3120004 }, { 3120005, error_advice_3120005 }, { 3120006, error_advice_3120006 }, + { 3130001, error_advice_3130001 }, + { 3130002, error_advice_3130002 }, + { 3130003, error_advice_3130003 }, + { 3130004, error_advice_3130004 }, { 3030002, error_advice_3030002 } }; diff --git a/programs/eosioc/httpc.cpp b/programs/eosioc/httpc.cpp index b5a7d226e3d3f657dfd4ddbfd0c85b950ae494b9..9cc55df55dbc188a7555f7f28adb7a919007db05 100644 --- a/programs/eosioc/httpc.cpp +++ b/programs/eosioc/httpc.cpp @@ -15,127 +15,135 @@ #include #include #include -#include +#include #include #include +#include "httpc.hpp" using boost::asio::ip::tcp; - -fc::variant call( const std::string& server, uint16_t port, - const std::string& path, - const fc::variant& postdata ) -{ try { - std::string postjson; - if( !postdata.is_null() ) - postjson = fc::json::to_string( postdata ); - - boost::asio::io_service io_service; - - // Get a list of endpoints corresponding to the server name. - tcp::resolver resolver(io_service); - tcp::resolver::query query(server, std::to_string(port) ); - tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); - tcp::resolver::iterator end; - - while( endpoint_iterator != end ) { - // Try each endpoint until we successfully establish a connection. - tcp::socket socket(io_service); - try { - boost::asio::connect(socket, endpoint_iterator); - endpoint_iterator = end; - } catch( std::exception& e ) { - ++endpoint_iterator; - if( endpoint_iterator != end ) - continue; - else throw; - } - - // Form the request. We specify the "Connection: close" header so that the - // server will close the socket after transmitting the response. This will - // allow us to treat all data up until the EOF as the content. - boost::asio::streambuf request; - std::ostream request_stream(&request); - request_stream << "POST " << path << " HTTP/1.0\r\n"; - request_stream << "Host: " << server << "\r\n"; - request_stream << "content-length: " << postjson.size() << "\r\n"; - request_stream << "Accept: */*\r\n"; - request_stream << "Connection: close\r\n\r\n"; - request_stream << postjson; - - // Send the request. - boost::asio::write(socket, request); - - // Read the response status line. The response streambuf will automatically - // grow to accommodate the entire line. The growth may be limited by passing - // a maximum size to the streambuf constructor. - boost::asio::streambuf response; - boost::asio::read_until(socket, response, "\r\n"); - - // Check that response is OK. - std::istream response_stream(&response); - std::string http_version; - response_stream >> http_version; - unsigned int status_code; - response_stream >> status_code; - std::string status_message; - std::getline(response_stream, status_message); - FC_ASSERT( !(!response_stream || http_version.substr(0, 5) != "HTTP/"), "Invalid Response" ); - - // Read the response headers, which are terminated by a blank line. - boost::asio::read_until(socket, response, "\r\n\r\n"); - - // Process the response headers. - std::string header; - while (std::getline(response_stream, header) && header != "\r") - { -// std::cout << header << "\n"; - } - // std::cout << "\n"; - - std::stringstream re; - // Write whatever content we already have to output. - if (response.size() > 0) - // std::cout << &response; - re << &response; - - // Read until EOF, writing data to output as we go. - boost::system::error_code error; - while (boost::asio::read(socket, response, - boost::asio::transfer_at_least(1), error)) - re << &response; - - if (error != boost::asio::error::eof) - throw boost::system::system_error(error); - - // std::cout << re.str() <<"\n"; - const auto response_result = fc::json::from_string(re.str()); - if( status_code == 200 || status_code == 201 || status_code == 202 ) { - return response_result; - } else { - auto &&error = response_result.as().error; - - // eos recognized error code is from 3000000 to 3999999 - // refer to libraries/chain/include/eosio/chain/exceptions.hpp - if (error.code >= 3000000 && error.code <= 3999999) { - // Construct fc exception from error - const auto &stack_trace = error.stack_trace; - fc::exception new_exception(error.code, error.name, error.message); - if (stack_trace.empty()) { - new_exception.append_log(FC_LOG_MESSAGE(error, error.details)); - } else { - for (auto itr = stack_trace.begin(); itr != stack_trace.end(); itr++) { - const auto &error_message = itr == stack_trace.begin() ? error.details : std::string(); - new_exception.append_log(fc::log_message(*itr, error_message)); - } - } - throw new_exception; - } - } - - FC_ASSERT( status_code == 200, "Error code ${c}\n: ${msg}\n", ("c", status_code)("msg", re.str()) ); - } - - FC_ASSERT( !"unable to connect" ); - } FC_RETHROW_EXCEPTIONS( error, "Request Path: ${server}:${port}${path}, Request Post Data: ${postdata}" , - ("server", server)("port", port)("path", path)("postdata", postdata) ) -} +namespace eosio { namespace client { namespace http { + fc::variant call( const std::string& server, uint16_t port, + const std::string& path, + const fc::variant& postdata ) { + try { + std::string postjson; + if( !postdata.is_null() ) + postjson = fc::json::to_string( postdata ); + + boost::asio::io_service io_service; + + // Get a list of endpoints corresponding to the server name. + tcp::resolver resolver(io_service); + tcp::resolver::query query(server, std::to_string(port) ); + tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); + tcp::resolver::iterator end; + + while( endpoint_iterator != end ) { + // Try each endpoint until we successfully establish a connection. + tcp::socket socket(io_service); + try { + boost::asio::connect(socket, endpoint_iterator); + endpoint_iterator = end; + } catch( std::exception& e ) { + ++endpoint_iterator; + if( endpoint_iterator != end ) + continue; + else throw; + } + + // Form the request. We specify the "Connection: close" header so that the + // server will close the socket after transmitting the response. This will + // allow us to treat all data up until the EOF as the content. + boost::asio::streambuf request; + std::ostream request_stream(&request); + request_stream << "POST " << path << " HTTP/1.0\r\n"; + request_stream << "Host: " << server << "\r\n"; + request_stream << "content-length: " << postjson.size() << "\r\n"; + request_stream << "Accept: */*\r\n"; + request_stream << "Connection: close\r\n\r\n"; + request_stream << postjson; + + // Send the request. + boost::asio::write(socket, request); + + // Read the response status line. The response streambuf will automatically + // grow to accommodate the entire line. The growth may be limited by passing + // a maximum size to the streambuf constructor. + boost::asio::streambuf response; + boost::asio::read_until(socket, response, "\r\n"); + + // Check that response is OK. + std::istream response_stream(&response); + std::string http_version; + response_stream >> http_version; + unsigned int status_code; + response_stream >> status_code; + std::string status_message; + std::getline(response_stream, status_message); + FC_ASSERT( !(!response_stream || http_version.substr(0, 5) != "HTTP/"), "Invalid Response" ); + + // Read the response headers, which are terminated by a blank line. + boost::asio::read_until(socket, response, "\r\n\r\n"); + + // Process the response headers. + std::string header; + while (std::getline(response_stream, header) && header != "\r") + { + // std::cout << header << "\n"; + } + // std::cout << "\n"; + + std::stringstream re; + // Write whatever content we already have to output. + if (response.size() > 0) + // std::cout << &response; + re << &response; + + // Read until EOF, writing data to output as we go. + boost::system::error_code error; + while (boost::asio::read(socket, response, + boost::asio::transfer_at_least(1), error)) + re << &response; + + if (error != boost::asio::error::eof) + throw boost::system::system_error(error); + + // std::cout << re.str() <<"\n"; + const auto response_result = fc::json::from_string(re.str()); + if( status_code == 200 || status_code == 201 || status_code == 202 ) { + return response_result; + } else if( status_code == 404 ) { + // Unknown endpoint + if (path.compare(0, chain_func_base.size(), chain_func_base) == 0) { + throw chain::missing_chain_api_plugin_exception(FC_LOG_MESSAGE(error, "Chain API plugin is not enabled")); + } else if (path.compare(0, wallet_func_base.size(), wallet_func_base) == 0) { + throw chain::missing_wallet_api_plugin_exception(FC_LOG_MESSAGE(error, "Wallet is not available")); + } else if (path.compare(0, account_history_func_base.size(), account_history_func_base) == 0) { + throw chain::missing_account_history_api_plugin_exception(FC_LOG_MESSAGE(error, "Account History API plugin is not enabled")); + } else if (path.compare(0, net_func_base.size(), net_func_base) == 0) { + throw chain::missing_net_api_plugin_exception(FC_LOG_MESSAGE(error, "Net API plugin is not enabled")); + } + } else { + auto &&error = response_result.as().error; + // Construct fc exception from error + const auto &stack_trace = error.stack_trace; + fc::exception new_exception(error.code, error.name, error.message); + if (stack_trace.empty()) { + new_exception.append_log(FC_LOG_MESSAGE(error, error.details)); + } else { + for (auto itr = stack_trace.begin(); itr != stack_trace.end(); itr++) { + const auto &error_message = itr == stack_trace.begin() ? error.details : std::string(); + new_exception.append_log(fc::log_message(*itr, error_message)); + } + } + throw new_exception; + } + + FC_ASSERT( status_code == 200, "Error code ${c}\n: ${msg}\n", ("c", status_code)("msg", re.str()) ); + } + + FC_ASSERT( !"unable to connect" ); + } FC_RETHROW_EXCEPTIONS( error, "Request Path: ${server}:${port}${path}, Request Post Data: ${postdata}" , + ("server", server)("port", port)("path", path)("postdata", postdata) ) + } +}}} \ No newline at end of file diff --git a/programs/eosioc/httpc.hpp b/programs/eosioc/httpc.hpp new file mode 100644 index 0000000000000000000000000000000000000000..531dcae72819052e221b5df42485027e50e34c3b --- /dev/null +++ b/programs/eosioc/httpc.hpp @@ -0,0 +1,49 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#pragma once + +namespace eosio { namespace client { namespace http { + fc::variant call( const std::string& server, uint16_t port, + const std::string& path, + const fc::variant& postdata = fc::variant() ); + + const string chain_func_base = "/v1/chain"; + const string get_info_func = chain_func_base + "/get_info"; + const string push_txn_func = chain_func_base + "/push_transaction"; + const string push_txns_func = chain_func_base + "/push_transactions"; + const string json_to_bin_func = chain_func_base + "/abi_json_to_bin"; + const string get_block_func = chain_func_base + "/get_block"; + const string get_account_func = chain_func_base + "/get_account"; + const string get_table_func = chain_func_base + "/get_table_rows"; + const string get_code_func = chain_func_base + "/get_code"; + const string get_currency_balance_func = chain_func_base + "/get_currency_balance"; + const string get_currency_stats_func = chain_func_base + "/get_currency_stats"; + const string get_required_keys = chain_func_base + "/get_required_keys"; + + const string account_history_func_base = "/v1/account_history"; + const string get_transaction_func = account_history_func_base + "/get_transaction"; + const string get_transactions_func = account_history_func_base + "/get_transactions"; + const string get_key_accounts_func = account_history_func_base + "/get_key_accounts"; + const string get_controlled_accounts_func = account_history_func_base + "/get_controlled_accounts"; + + const string net_func_base = "/v1/net"; + const string net_connect = net_func_base + "/connect"; + const string net_disconnect = net_func_base + "/disconnect"; + const string net_status = net_func_base + "/status"; + const string net_connections = net_func_base + "/connections"; + + + const string wallet_func_base = "/v1/wallet"; + const string wallet_create = wallet_func_base + "/create"; + const string wallet_open = wallet_func_base + "/open"; + const string wallet_list = wallet_func_base + "/list_wallets"; + const string wallet_list_keys = wallet_func_base + "/list_keys"; + const string wallet_public_keys = wallet_func_base + "/get_public_keys"; + const string wallet_lock = wallet_func_base + "/lock"; + const string wallet_lock_all = wallet_func_base + "/lock_all"; + const string wallet_unlock = wallet_func_base + "/unlock"; + const string wallet_import_key = wallet_func_base + "/import_key"; + const string wallet_sign_trx = wallet_func_base + "/sign_transaction"; + }}} \ No newline at end of file diff --git a/programs/eosioc/main.cpp b/programs/eosioc/main.cpp index 2f1e778520e66ad55c5047468c6c405d18940027..1328e2dc186954eebf3b6fd520ae1663843cf6b6 100644 --- a/programs/eosioc/main.cpp +++ b/programs/eosioc/main.cpp @@ -96,12 +96,14 @@ Options: #include "help_text.hpp" #include "localize.hpp" #include "config.hpp" +#include "httpc.hpp" using namespace std; using namespace eosio; using namespace eosio::chain; using namespace eosio::utilities; using namespace eosio::client::help; +using namespace eosio::client::http; using namespace eosio::client::localize; using namespace eosio::client::config; using namespace boost::filesystem; @@ -127,43 +129,6 @@ uint32_t port = 8888; string wallet_host = "localhost"; uint32_t wallet_port = 8888; -const string chain_func_base = "/v1/chain"; -const string get_info_func = chain_func_base + "/get_info"; -const string push_txn_func = chain_func_base + "/push_transaction"; -const string push_txns_func = chain_func_base + "/push_transactions"; -const string json_to_bin_func = chain_func_base + "/abi_json_to_bin"; -const string get_block_func = chain_func_base + "/get_block"; -const string get_account_func = chain_func_base + "/get_account"; -const string get_table_func = chain_func_base + "/get_table_rows"; -const string get_code_func = chain_func_base + "/get_code"; -const string get_currency_balance_func = chain_func_base + "/get_currency_balance"; -const string get_currency_stats_func = chain_func_base + "/get_currency_stats"; -const string get_required_keys = chain_func_base + "/get_required_keys"; - -const string account_history_func_base = "/v1/account_history"; -const string get_transaction_func = account_history_func_base + "/get_transaction"; -const string get_transactions_func = account_history_func_base + "/get_transactions"; -const string get_key_accounts_func = account_history_func_base + "/get_key_accounts"; -const string get_controlled_accounts_func = account_history_func_base + "/get_controlled_accounts"; - -const string net_func_base = "/v1/net"; -const string net_connect = net_func_base + "/connect"; -const string net_disconnect = net_func_base + "/disconnect"; -const string net_status = net_func_base + "/status"; -const string net_connections = net_func_base + "/connections"; - - -const string wallet_func_base = "/v1/wallet"; -const string wallet_create = wallet_func_base + "/create"; -const string wallet_open = wallet_func_base + "/open"; -const string wallet_list = wallet_func_base + "/list_wallets"; -const string wallet_list_keys = wallet_func_base + "/list_keys"; -const string wallet_public_keys = wallet_func_base + "/get_public_keys"; -const string wallet_lock = wallet_func_base + "/lock"; -const string wallet_lock_all = wallet_func_base + "/lock_all"; -const string wallet_unlock = wallet_func_base + "/unlock"; -const string wallet_import_key = wallet_func_base + "/import_key"; -const string wallet_sign_trx = wallet_func_base + "/sign_transaction"; inline std::vector sort_names( const std::vector& names ) { auto results = std::vector(names); @@ -213,19 +178,14 @@ vector get_account_permissions(const vector& pe return accountPermissions; } -fc::variant call( const std::string& server, uint16_t port, - const std::string& path, - const fc::variant& postdata = fc::variant() ); - - template fc::variant call( const std::string& server, uint16_t port, const std::string& path, - const T& v ) { return call( server, port, path, fc::variant(v) ); } + const T& v ) { return eosio::client::http::call( server, port, path, fc::variant(v) ); } template fc::variant call( const std::string& path, - const T& v ) { return call( host, port, path, fc::variant(v) ); } + const T& v ) { return eosio::client::http::call( host, port, path, fc::variant(v) ); } eosio::chain_apis::read_only::get_info_results get_info() { return call(host, port, get_info_func ).as(); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 93d78ba1a3aa60981594f87b1425ac1e10381ec0..972870fc57fb389c03008a565153ed033ed70c1e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,6 +16,8 @@ set( CMAKE_CXX_STANDARD 14 ) include_directories("${CMAKE_BINARY_DIR}/contracts") include_directories("${CMAKE_SOURCE_DIR}/contracts") +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/config.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/tests/config.hpp ESCAPE_QUOTES) + file(GLOB UNIT_TESTS "chain_tests/*.cpp" "api_tests/*.cpp" "tests/abi_tests.cpp" "tests/database_tests.cpp" "tests/misc_tests.cpp" "wasm_tests/*.cpp") add_executable( chain_test ${UNIT_TESTS} ${WASM_UNIT_TESTS} common/main.cpp ) diff --git a/tests/tests/abi_tests.cpp b/tests/tests/abi_tests.cpp index 647a11938ea29f78911cee2384c1f8a3af13603d..f3cfed2a9f95c415395918707804fe0272c9cad9 100644 --- a/tests/tests/abi_tests.cpp +++ b/tests/tests/abi_tests.cpp @@ -17,6 +17,8 @@ #include #include +#include "config.hpp" + using namespace eosio; using namespace chain; using namespace chain::contracts; @@ -354,25 +356,16 @@ BOOST_AUTO_TEST_CASE(uint_types) } FC_LOG_AND_RETHROW() } +using namespace eosio::tests::config; -BOOST_AUTO_TEST_CASE(generator) -{ try { - - if( std::getenv("EOSLIB") == nullptr ) { - wlog("*************************************"); - wlog("* EOSLIB env variable not defined *"); - wlog("* ABIGenerator tests will not run *"); - wlog("*************************************"); - return; - } +struct abi_gen_helper { - auto is_abi_generation_exception =[](const eosio::abi_generation_exception& e) -> bool { return true; }; + abi_gen_helper() {} - auto generate_abi = [this](const char* source, const char* abi, bool opt_sfs=false) -> bool { - - const char* eosiolib_path = std::getenv("EOSLIB"); - FC_ASSERT(eosiolib_path != NULL); + static bool is_abi_generation_exception(const eosio::abi_generation_exception& e) { return true; }; + bool generate_abi(const char* source, const char* abi, bool opt_sfs=false) { + std::string include_param = std::string("-I") + eosiolib_path; std::string stdcpp_include_param = std::string("-I") + eosiolib_path + "/libc++/upstream/include"; std::string stdc_include_param = std::string("-I") + eosiolib_path + "/musl/upstream/include"; @@ -394,7 +387,12 @@ BOOST_AUTO_TEST_CASE(generator) } return e; - }; + } + +}; + +BOOST_FIXTURE_TEST_CASE(abigen_unknown_type, abi_gen_helper) +{ try { const char* unknown_type = R"=====( #include @@ -405,7 +403,12 @@ BOOST_AUTO_TEST_CASE(generator) }; )====="; - BOOST_CHECK_EXCEPTION( generate_abi(unknown_type, ""), eosio::abi_generation_exception, is_abi_generation_exception ); + BOOST_CHECK_EXCEPTION( generate_abi(unknown_type, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception ); + +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_all_types, abi_gen_helper) +{ try { const char* all_types = R"=====( #include @@ -611,6 +614,11 @@ BOOST_AUTO_TEST_CASE(generator) )====="; BOOST_TEST( generate_abi(all_types, all_types_abi) == true); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_double_base, abi_gen_helper) +{ try { + const char* double_base = R"=====( #include @@ -627,7 +635,13 @@ BOOST_AUTO_TEST_CASE(generator) }; )====="; - BOOST_CHECK_EXCEPTION( generate_abi(double_base, ""), eosio::abi_generation_exception, is_abi_generation_exception ); + BOOST_CHECK_EXCEPTION( generate_abi(double_base, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception ); + +} FC_LOG_AND_RETHROW() } + + +BOOST_FIXTURE_TEST_CASE(abigen_double_action, abi_gen_helper) +{ try { const char* double_action = R"=====( #include @@ -684,6 +698,12 @@ BOOST_AUTO_TEST_CASE(generator) BOOST_TEST( generate_abi(double_action, double_action_abi) == true ); +} FC_LOG_AND_RETHROW() } + + +BOOST_FIXTURE_TEST_CASE(abigen_all_indexes, abi_gen_helper) +{ try { + const char* all_indexes = R"=====( #include #include @@ -831,6 +851,11 @@ BOOST_AUTO_TEST_CASE(generator) BOOST_TEST( generate_abi(all_indexes, all_indexes_abi) == true ); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_unable_to_determine_index, abi_gen_helper) +{ try { + const char* unable_to_determine_index = R"=====( #include @@ -842,10 +867,14 @@ BOOST_AUTO_TEST_CASE(generator) )====="; - BOOST_CHECK_EXCEPTION( generate_abi(unable_to_determine_index, ""), eosio::abi_generation_exception, is_abi_generation_exception ); + BOOST_CHECK_EXCEPTION( generate_abi(unable_to_determine_index, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception ); - //TODO: full action / full table +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_long_field_name, abi_gen_helper) +{ try { + //TODO: full action / full table // typedef fixed_string16 FieldName; const char* long_field_name = R"=====( #include @@ -857,7 +886,12 @@ BOOST_AUTO_TEST_CASE(generator) )====="; - BOOST_CHECK_EXCEPTION( generate_abi(long_field_name, ""), eosio::abi_generation_exception, is_abi_generation_exception ); + BOOST_CHECK_EXCEPTION( generate_abi(long_field_name, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception ); + +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_long_type_name, abi_gen_helper) +{ try { const char* long_type_name = R"=====( #include @@ -874,7 +908,12 @@ BOOST_AUTO_TEST_CASE(generator) )====="; - BOOST_CHECK_EXCEPTION( generate_abi(long_type_name, "{}"), eosio::abi_generation_exception, is_abi_generation_exception ); + BOOST_CHECK_EXCEPTION( generate_abi(long_type_name, "{}"), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception ); + +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_same_type_different_namespace, abi_gen_helper) +{ try { const char* same_type_different_namespace = R"=====( #include @@ -895,12 +934,17 @@ BOOST_AUTO_TEST_CASE(generator) )====="; - BOOST_CHECK_EXCEPTION( generate_abi(same_type_different_namespace, ""), eosio::abi_generation_exception, is_abi_generation_exception ); + BOOST_CHECK_EXCEPTION( generate_abi(same_type_different_namespace, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception ); + +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_bad_index_type, abi_gen_helper) +{ try { const char* bad_index_type = R"=====( #include - //@abi table i64 + //@abi table table1 i128i128 struct table1 { uint32_t key; uint64_t field1; @@ -909,12 +953,17 @@ BOOST_AUTO_TEST_CASE(generator) )====="; - BOOST_CHECK_EXCEPTION( generate_abi(bad_index_type, ""), eosio::abi_generation_exception, is_abi_generation_exception ); + BOOST_CHECK_EXCEPTION( generate_abi(bad_index_type, "{}"), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception ); + +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_full_table_decl, abi_gen_helper) +{ try { const char* full_table_decl = R"=====( #include - //@abi table i64 + //@abi table table1 i64 class table1 { public: uint64_t id; @@ -959,6 +1008,11 @@ BOOST_AUTO_TEST_CASE(generator) BOOST_TEST( generate_abi(full_table_decl, full_table_decl_abi) == true ); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_str_table_decl, abi_gen_helper) +{ try { + const char* str_table_decl = R"=====( #include #include @@ -1004,6 +1058,10 @@ BOOST_AUTO_TEST_CASE(generator) )====="; BOOST_TEST( generate_abi(str_table_decl, str_table_decl_abi) == true ); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_union_table, abi_gen_helper) +{ try { const char* union_table = R"=====( #include @@ -1016,7 +1074,12 @@ BOOST_AUTO_TEST_CASE(generator) )====="; - BOOST_CHECK_EXCEPTION( generate_abi(union_table, ""), eosio::abi_generation_exception, is_abi_generation_exception ); + BOOST_CHECK_EXCEPTION( generate_abi(union_table, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception ); + +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_same_action_different_type, abi_gen_helper) +{ try { const char* same_action_different_type = R"=====( #include @@ -1033,7 +1096,11 @@ BOOST_AUTO_TEST_CASE(generator) )====="; - BOOST_CHECK_EXCEPTION( generate_abi(same_action_different_type, ""), eosio::abi_generation_exception, is_abi_generation_exception ); + BOOST_CHECK_EXCEPTION( generate_abi(same_action_different_type, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception ); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_template_base, abi_gen_helper) +{ try { const char* template_base = R"=====( #include @@ -1045,7 +1112,7 @@ BOOST_AUTO_TEST_CASE(generator) typedef base base32; - //@abi table i64 + //@abi table table1 i64 class table1 : base32 { public: uint64_t id; @@ -1089,6 +1156,11 @@ BOOST_AUTO_TEST_CASE(generator) BOOST_TEST( generate_abi(template_base, template_base_abi) == true ); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_action_and_table, abi_gen_helper) +{ try { + const char* action_and_table = R"=====( #include @@ -1134,6 +1206,11 @@ BOOST_AUTO_TEST_CASE(generator) BOOST_TEST( generate_abi(action_and_table, action_and_table_abi) == true ); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_simple_typedef, abi_gen_helper) +{ try { + const char* simple_typedef = R"=====( #include @@ -1190,6 +1267,10 @@ BOOST_AUTO_TEST_CASE(generator) )====="; BOOST_TEST( generate_abi(simple_typedef, simple_typedef_abi) == true ); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_field_typedef, abi_gen_helper) +{ try { const char* field_typedef = R"=====( #include @@ -1264,9 +1345,248 @@ BOOST_AUTO_TEST_CASE(generator) BOOST_TEST( generate_abi(field_typedef, field_typedef_abi) == true ); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_vector_of_POD, abi_gen_helper) +{ try { + + const char* abigen_vector_of_POD = R"=====( + #include + #include + #include + + using namespace eosio; + using namespace std; + + //@abi table + struct table1 { + uint64_t field1; + vector uints64; + vector uints32; + vector uints16; + vector uints8; + }; + + )====="; + + const char* abigen_vector_of_POD_abi = R"=====( + { + "types": [], + "structs": [{ + "name": "table1", + "base": "", + "fields": [{ + "name": "field1", + "type": "uint64" + },{ + "name": "uints64", + "type": "uint64[]" + },{ + "name": "uints32", + "type": "uint32[]" + },{ + "name": "uints16", + "type": "uint16[]" + },{ + "name": "uints8", + "type": "uint8[]" + } + ] + } + ], + "actions": [], + "tables": [{ + "name": "table1", + "index_type": "i64", + "key_names": [ + "field1" + ], + "key_types": [ + "uint64" + ], + "type": "table1" + } + ] + } + )====="; + + BOOST_TEST( generate_abi(abigen_vector_of_POD, abigen_vector_of_POD_abi) == true ); } FC_LOG_AND_RETHROW() } +BOOST_FIXTURE_TEST_CASE(abigen_vector_of_structs, abi_gen_helper) +{ try { + + const char* abigen_vector_of_structs = R"=====( + #include + #include + #include + + using namespace eosio; + using namespace std; + + struct my_struct { + vector uints64; + vector uints32; + vector uints16; + vector uints8; + string str; + }; + + //@abi table + struct table1 { + uint64_t field1; + vector field2; + }; + + )====="; + + const char* abigen_vector_of_structs_abi = R"=====( + { + "types": [], + "structs": [{ + "name": "my_struct", + "base": "", + "fields": [{ + "name": "uints64", + "type": "uint64[]" + },{ + "name": "uints32", + "type": "uint32[]" + },{ + "name": "uints16", + "type": "uint16[]" + },{ + "name": "uints8", + "type": "uint8[]" + },{ + "name": "str", + "type": "string" + } + ] + },{ + "name": "table1", + "base": "", + "fields": [{ + "name": "field1", + "type": "uint64" + },{ + "name": "field2", + "type": "my_struct[]" + } + ] + } + ], + "actions": [], + "tables": [{ + "name": "table1", + "index_type": "i64", + "key_names": [ + "field1" + ], + "key_types": [ + "uint64" + ], + "type": "table1" + } + ] + } + )====="; + + BOOST_TEST( generate_abi(abigen_vector_of_structs, abigen_vector_of_structs_abi) == true ); + +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abigen_vector_multidimension, abi_gen_helper) +{ try { + + const char* abigen_vector_multidimension = R"=====( + #include + #include + #include + + using namespace eosio; + using namespace std; + + //@abi table + struct table1 { + uint64_t field1; + vector> field2; + }; + + )====="; + + BOOST_CHECK_EXCEPTION( generate_abi(abigen_vector_multidimension, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception ); + +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(abgigen_vector_alias, abi_gen_helper) +{ try { + + const char* abgigen_vector_alias = R"=====( + #include + #include + #include + #include + + using namespace std; + + struct row { + std::vector cells; + }; + + typedef vector array_of_rows; + + //@abi action + struct my_action { + uint64_t id; + array_of_rows rows; + }; + + )====="; + + const char* abgigen_vector_alias_abi = R"=====( + { + "types": [{ + "new_type_name": "array_of_rows", + "type": "row[]" + } + ], + "structs": [{ + "name": "row", + "base": "", + "fields": [{ + "name": "cells", + "type": "uint32[]" + } + ] + },{ + "name": "my_action", + "base": "", + "fields": [{ + "name": "id", + "type": "uint64" + },{ + "name": "rows", + "type": "array_of_rows" + } + ] + } + ], + "actions": [{ + "name": "myaction", + "type": "my_action" + } + ], + "tables": [] + } + )====="; + + BOOST_TEST( generate_abi(abgigen_vector_alias, abgigen_vector_alias_abi) == true ); + +} FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_CASE(general) { try { diff --git a/tests/tests/config.hpp.in b/tests/tests/config.hpp.in new file mode 100644 index 0000000000000000000000000000000000000000..77b0a4293eaebc00beaf80ee45012642ae3f4c42 --- /dev/null +++ b/tests/tests/config.hpp.in @@ -0,0 +1,8 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ + +namespace eosio { namespace tests { namespace config { + constexpr char eosiolib_path[] = "${CMAKE_CURRENT_SOURCE_DIR}/../contracts"; +}}} diff --git a/tools/eosiocpp.in b/tools/eosiocpp.in index 8a55ed0c034e734c66f69a7faddfd3044d3cc5a3..3c1b1a1a0cff7cd557ba5dc38133e4089d0e0ba9 100755 --- a/tools/eosiocpp.in +++ b/tools/eosiocpp.in @@ -1,9 +1,8 @@ #!/bin/bash EOSIO_INSTALL_DIR=@CMAKE_INSTALL_PREFIX@ -ABIGEN=${EOSIO_INSTALL_DIR}/bin/abi_gen -CODEGEN=${EOSIO_INSTALL_DIR}/bin/codegen - +ABIGEN=${EOSIO_INSTALL_DIR}/bin/eosio-abigen +BOOST_INCLUDE_DIR=@Boost_INCLUDE_DIR@ function copy_skeleton { set -e cp -r ${EOSIO_INSTALL_DIR}/share/skeleton/. $newname @@ -32,8 +31,24 @@ function build_contract { name=`basename $file` filePath=`dirname $file` - echo @WASM_CLANG@ -emit-llvm -O3 --std=c++14 --target=wasm32 -ffreestanding -nostdlib -fno-threadsafe-statics -fno-rtti -fno-exceptions -I ${EOSIO_INSTALL_DIR}/include -I $filePath -c $file -o $workdir/built/$name - @WASM_CLANG@ -emit-llvm -O3 --std=c++14 --target=wasm32 -ffreestanding -nostdlib -fno-threadsafe-statics -fno-rtti -fno-exceptions -I ${EOSIO_INSTALL_DIR}/include -I $filePath -c $file -o $workdir/built/$name + # echo @WASM_CLANG@ -emit-llvm -O3 --std=c++14 --target=wasm32 -nostdinc \ + # -nostdlib -nostdlibinc -ffreestanding -nostdlib -fno-threadsafe-statics -fno-rtti \ + # -fno-exceptions -I ${EOSIO_INSTALL_DIR}/include \ + # -I${EOSIO_INSTALL_DIR}/include/libc++/upstream/include \ + # -I${EOSIO_INSTALL_DIR}/include/musl/upstream/include \ + # -I${BOOST_INCLUDE_DIR} \ + # -I $filePath \ + # -c $file -o $workdir/built/$name + + @WASM_CLANG@ -emit-llvm -O3 --std=c++14 --target=wasm32 -nostdinc \ + -nostdlib -nostdlibinc -ffreestanding -nostdlib -fno-threadsafe-statics -fno-rtti \ + -fno-exceptions -I ${EOSIO_INSTALL_DIR}/include \ + -I${EOSIO_INSTALL_DIR}/include/libc++/upstream/include \ + -I${EOSIO_INSTALL_DIR}/include/musl/upstream/include \ + -I${BOOST_INCLUDE_DIR} \ + -I $filePath \ + -c $file -o $workdir/built/$name + done # echo @WASM_LLVM_LINK@ -o $workdir/linked.bc $workdir/built/* @@ -56,9 +71,13 @@ function generate_abi { fi context_folder=$(realpath $(dirname $1)) - + ${ABIGEN} -extra-arg=-c -extra-arg=--std=c++14 -extra-arg=--target=wasm32 \ - -extra-arg=-I${EOSIO_INSTALL_DIR}/include -extra-arg=-I$context_folder \ + -extra-arg=-nostdinc -extra-arg=-nostdinc++ -extra-arg=-DABIGEN \ + -extra-arg=-I${EOSIO_INSTALL_DIR}/include/libc++/upstream/include \ + -extra-arg=-I${EOSIO_INSTALL_DIR}/include/musl/upstream/include \ + -extra-arg=-I${BOOST_INCLUDE_DIR} \ + -extra-arg=-I${EOSIO_INSTALL_DIR}/include -extra-arg=-I$context_folder \ -extra-arg=-fparse-all-comments -destination-file=${outname} -verbose=0 \ -context=$context_folder $1 -- @@ -67,18 +86,6 @@ function generate_abi { fi echo "Generated ${outname} ..." - - if [[ "$genserialfunctions" == "yes" ]]; then - tmp=$(basename $(realpath $1)) - gen_name=${tmp%.*}.gen.hpp - ${CODEGEN} ${outname} > $context_folder/${gen_name} - - if [ "$?" -ne 0 ]; then - exit 1 - fi - - echo "Generated ${gen_name} ..." - fi } function print_help { @@ -95,12 +102,11 @@ function print_help { echo " -o | --outname [output.wast] [input.cpp ...]" echo " Generate the wast output file based on input cpp files" echo " OR" - echo " -g | --genabi contract.abi [ -gs ] types.hpp" + echo " -g | --genabi contract.abi types.hpp" echo " Generate the ABI specification file [EXPERIMENTAL]" } command="" -genserialfunctions="no" while [[ $# -gt 1 ]] do @@ -123,11 +129,6 @@ case $key in shift 2 break ;; - -gs) - genserialfunctions="yes" - shift 1 - break - ;; -g|--genabi) outname="$2" command="genabi"