提交 c03f7cf1 编写于 作者: B Bill Hamilton

Merge branch 'master' into eosio_build_centos

Merging master before push and PR
...@@ -39,7 +39,6 @@ pipeline { ...@@ -39,7 +39,6 @@ pipeline {
steps { steps {
sh ''' sh '''
. $HOME/.bash_profile . $HOME/.bash_profile
export EOSLIB=$(pwd)/contracts
cd build cd build
printf "Waiting for testing to be available..." printf "Waiting for testing to be available..."
while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done
...@@ -53,7 +52,6 @@ pipeline { ...@@ -53,7 +52,6 @@ pipeline {
steps { steps {
sh ''' sh '''
. $HOME/.bash_profile . $HOME/.bash_profile
export EOSLIB=$(pwd)/contracts
cd build cd build
printf "Waiting for testing to be available..." printf "Waiting for testing to be available..."
while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done
...@@ -67,7 +65,6 @@ pipeline { ...@@ -67,7 +65,6 @@ pipeline {
steps { steps {
sh ''' sh '''
. $HOME/.bash_profile . $HOME/.bash_profile
export EOSLIB=$(pwd)/contracts
cd build cd build
printf "Waiting for testing to be available..." printf "Waiting for testing to be available..."
while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done
...@@ -94,4 +91,4 @@ pipeline { ...@@ -94,4 +91,4 @@ pipeline {
} }
} }
} }
} }
\ No newline at end of file
...@@ -22,11 +22,13 @@ add_subdirectory(proxy) ...@@ -22,11 +22,13 @@ add_subdirectory(proxy)
add_subdirectory(test_api) add_subdirectory(test_api)
add_subdirectory(test_api_mem) add_subdirectory(test_api_mem)
add_subdirectory(test_api_db) add_subdirectory(test_api_db)
#add_subdirectory(simpledb) add_subdirectory(simpledb)
#add_subdirectory(storage) #add_subdirectory(storage)
#add_subdirectory(social) #add_subdirectory(social)
add_subdirectory(test.system) add_subdirectory(test.system)
add_subdirectory(noop) add_subdirectory(noop)
install( DIRECTORY eosiolib DESTINATION include/ ) install( DIRECTORY eosiolib DESTINATION include/ )
install( DIRECTORY musl DESTINATION include/ )
install( DIRECTORY libc++ DESTINATION include/ )
install( DIRECTORY skeleton DESTINATION share/ ) install( DIRECTORY skeleton DESTINATION share/ )
...@@ -3,73 +3,211 @@ ...@@ -3,73 +3,211 @@
"structs": [{ "structs": [{
"name": "record1", "name": "record1",
"base": "", "base": "",
"fields": [ "fields": [{
{"name":"key", "type":"uint64"}, "name": "key",
{"name":"u256", "type":"uint256"}, "type": "uint64"
{"name":"u128", "type":"uint128"}, },{
{"name":"u64", "type":"uint64"}, "name": "u256",
{"name":"u32", "type":"uint32"}, "type": "uint256"
{"name":"u16", "type":"uint16"}, },{
{"name":"u8", "type":"uint8"}, "name": "u128",
{"name":"i64", "type":"int64"}, "type": "uint128"
{"name":"i32", "type":"int32"}, },{
{"name":"i16", "type":"int16"}, "name": "u64",
{"name":"i8", "type":"int8"}, "type": "uint64"
{"name":"price", "type":"price"} },{
"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", "name": "record2",
"base": "", "base": "",
"fields": [ "fields": [{
{"name":"key1", "type":"uint128"}, "name": "key1",
{"name":"key2", "type":"uint128"} "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", "name": "record3",
"base": "", "base": "",
"fields": [ "fields": [{
{"name":"key1", "type":"uint64"}, "name": "key1",
{"name":"key2", "type":"uint64"}, "type": "uint64"
{"name":"key3", "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", "name": "key_value1",
"base": "", "base": "",
"fields": [ "fields": [{
{"name":"key", "type":"string"}, "name": "key",
{"name":"value", "type":"string"} "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", "name": "complex_type",
"base": "", "base": "",
"fields": [ "fields": [{
{"name":"name", "type":"string"}, "name": "name",
{"name":"age", "type":"uint64"} "type": "string"
},{
"name": "age",
"type": "uint64"
}
] ]
},{ },{
"name": "key_value2", "name": "key_value2",
"base": "", "base": "",
"fields": [ "fields": [{
{"name":"key", "type":"string"}, "name": "key",
{"name":"value", "type":"complex_type"} "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": [{ "actions": [{
"name": "insert1", "name": "insert1",
"type": "record1" "type": "insert_record1"
},{
"name": "remove1",
"type": "remove_record1"
},{ },{
"name": "insert2", "name": "insert2",
"type": "record2" "type": "insert_record2"
},{
"name": "remove2",
"type": "remove_record2"
},{ },{
"name": "insert3", "name": "insert3",
"type": "record3" "type": "insert_record3"
},{
"name": "remove3",
"type": "remove_record3"
},{ },{
"name": "insertkv1", "name": "insertkv1",
"type": "key_value1" "type": "insert_keyvalue1"
},{
"name": "removekv1",
"type": "remove_keyvalue1"
},{ },{
"name": "insertkv2", "name": "insertkv2",
"type": "key_value2" "type": "insert_keyvalue2"
},{
"name": "removekv2",
"type": "remove_keyvalue2"
} }
], ],
"tables": [{ "tables": [{
......
...@@ -2,60 +2,225 @@ ...@@ -2,60 +2,225 @@
* @file * @file
* @copyright defined in eos/LICENSE.txt * @copyright defined in eos/LICENSE.txt
*/ */
#include "simpledb.hpp" #include <string>
#include "simpledb.gen.hpp" #include <eosiolib/action.hpp>
#include <eosiolib/db.hpp>
#include <eosiolib/types.hpp> #include <eosiolib/types.hpp>
#include <eosiolib/raw.hpp> #include <eosiolib/serialize.hpp>
#include <eosiolib/db.hpp>
#include <eosiolib/system.h>
extern "C" { using namespace eosio;
namespace simpledb {
void apply( uint64_t code, uint64_t action ) { template<uint64_t Val>
if( code == N(simpledb) ) { struct dispatchable {
if( action == N(insertkv1) ) { constexpr static uint64_t action_name = Val;
// eosioc push message simpledb insertkv1 '{"key":"a", "value":"aa"}' -S simpledb };
// eosioc get table simpledb simpledb keyvalue1
auto kv1 = eosio::current_action<key_value1>(); //@abi table
eosio::print("Inserting key_value1\n"); struct record1 {
eosio::dump(kv1);
bytes b = eosio::raw::pack(kv1.value); uint64_t key;
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) ) { uint256 u256;
// eosioc push message simpledb insertkv2 '{"key":"a", "value":{"name":"aaa", "age":10}}' -S simpledb uint128_t u128;
// eosioc get table simpledb simpledb keyvalue2 uint64_t u64;
auto kv2 = eosio::current_action<key_value2>(); uint32_t u32;
eosio::print("Inserting key_value2\n"); uint16_t u16;
eosio::dump(kv2); uint8_t u8;
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); int64_t i64;
} else if( action == N(insert1) ) { int32_t i32;
// eosioc push message simpledb insert1 '{"key":75}' -S simpledb int16_t i16;
// eosioc get table simpledb simpledb record1 int8_t i8;
auto tmp = eosio::current_action<record1>();
eosio::print("Inserting record1\n"); EOSLIB_SERIALIZE( record1, (key)(u256)(u128)(u64)(u32)(u16)(u8)(i64)(i32)(i16)(i8) );
eosio::dump(tmp); };
auto bytes = eosio::raw::pack(tmp);
store_i64( N(simpledb), N(record1), bytes.data, bytes.len); //@abi action insert1
} else if(action == N(insert2)) { struct insert_record1 : dispatchable<N(insert1)> {
// eosioc push message simpledb insert2 '{"key1":"75", "key2":"77"}' -S simpledb record1 r1;
// eosioc get table simpledb simpledb record2 void process() {
auto tmp = eosio::current_action<record2>(); bytes b = eosio::pack(r1);
eosio::print("Inserting record2\n"); store_i64( N(simpledb), N(record1), N(simpledb), b.data(), b.size());
eosio::dump(tmp); }
auto bytes = eosio::raw::pack(tmp);
store_i128i128( N(simpledb), N(record2), bytes.data, bytes.len); EOSLIB_SERIALIZE( insert_record1, (r1) );
} else if(action == N(insert3)) { };
// eosioc push message simpledb insert3 '{"key1":75, "key2":77, "key3":79}' -S simpledb
// eosioc get table simpledb simpledb record3 //@abi action remove1
auto tmp = eosio::current_action<record3>(); struct remove_record1 : dispatchable<N(remove1)> {
eosio::print("Inserting record3\n"); uint64_t key;
eosio::dump(tmp); void process() {
auto bytes = eosio::raw::pack(tmp); remove_i64( N(simpledb), N(record1), (char *)this);
store_i64i64i64( N(simpledb), N(record3), bytes.data, bytes.len); }
} else {
eosio_assert(0, "unknown message"); 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<N(insert2)> {
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<N(remove2)> {
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<N(insert3)> {
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<N(remove3)> {
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<N(insertkv1)> {
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<N(removekv1)> {
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<N(insertkv2)> {
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<N(removekv2)> {
std::string key;
void process() {
remove_str( N(simpledb), N(keyvalue2), (char *)key.data(), key.size() );
}
EOSLIB_SERIALIZE( remove_keyvalue2, (key) );
};
template<typename ...Ts>
struct dispatcher_impl;
template<typename T>
struct dispatcher_impl<T> {
static bool dispatch(uint64_t action) {
if (action == T::action_name) {
unpack_action<T>().process();
return true;
} }
return false;
} }
} };
template<typename T, typename ...Rem>
struct dispatcher_impl<T, Rem...> {
static bool dispatch(uint64_t action) {
return dispatcher_impl<T>::dispatch(action) || dispatcher_impl<Rem...>::dispatch(action);
}
};
using dispatcher = dispatcher_impl<insert_record1, remove_record1, insert_record2, insert_record3, insert_keyvalue1, insert_keyvalue2>;
} }
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
#pragma once
#include <eosiolib/types.hpp>
#include <eosiolib/datastream.hpp>
#include <eosiolib/raw_fwd.hpp>
namespace eosio { namespace raw {
template<typename Stream> 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<typename Stream> 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<typename Stream> inline void pack( Stream& s, const record2& value ) {
raw::pack(s, value.key1);
raw::pack(s, value.key2);
}
template<typename Stream> inline void unpack( Stream& s, record2& value ) {
raw::unpack(s, value.key1);
raw::unpack(s, value.key2);
}
template<typename Stream> inline void pack( Stream& s, const record3& value ) {
raw::pack(s, value.key1);
raw::pack(s, value.key2);
raw::pack(s, value.key3);
}
template<typename Stream> inline void unpack( Stream& s, record3& value ) {
raw::unpack(s, value.key1);
raw::unpack(s, value.key2);
raw::unpack(s, value.key3);
}
template<typename Stream> inline void pack( Stream& s, const key_value1& value ) {
raw::pack(s, value.key);
raw::pack(s, value.value);
}
template<typename Stream> inline void unpack( Stream& s, key_value1& value ) {
raw::unpack(s, value.key);
raw::unpack(s, value.value);
}
template<typename Stream> inline void pack( Stream& s, const complex_type& value ) {
raw::pack(s, value.name);
raw::pack(s, value.age);
}
template<typename Stream> inline void unpack( Stream& s, complex_type& value ) {
raw::unpack(s, value.name);
raw::unpack(s, value.age);
}
template<typename Stream> inline void pack( Stream& s, const key_value2& value ) {
raw::pack(s, value.key);
raw::pack(s, value.value);
}
template<typename Stream> inline void unpack( Stream& s, key_value2& value ) {
raw::unpack(s, value.key);
raw::unpack(s, value.value);
}
} }
#include <eosiolib/raw.hpp>
namespace eosio {
void print_ident(int n){while(n-->0){print(" ");}};
template<typename Type>
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<record1>() {
return current_message_ex<record1>();
}
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<record2>() {
return current_message_ex<record2>();
}
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<record3>() {
return current_message_ex<record3>();
}
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<key_value1>() {
return current_message_ex<key_value1>();
}
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<complex_type>() {
return current_message_ex<complex_type>();
}
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<key_value2>() {
return current_message_ex<key_value2>();
}
} //eosio
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eos.hpp>
#include <eosiolib/string.hpp>
/* @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;
};
...@@ -27,18 +27,29 @@ void abi_generator::set_compiler_instance(CompilerInstance& compiler_instance) { ...@@ -27,18 +27,29 @@ void abi_generator::set_compiler_instance(CompilerInstance& compiler_instance) {
} }
void abi_generator::handle_tagdecl_definition(TagDecl* tag_decl) { void abi_generator::handle_tagdecl_definition(TagDecl* tag_decl) {
ASTContext& ctx = tag_decl->getASTContext(); ast_context = &tag_decl->getASTContext();
auto decl_location = tag_decl->getLocation().printToString(ctx.getSourceManager()); auto decl_location = tag_decl->getLocation().printToString(ast_context->getSourceManager());
try { try {
handle_decl(tag_decl); handle_decl(tag_decl);
} FC_CAPTURE_AND_RETHROW((decl_location)) } } FC_CAPTURE_AND_RETHROW((decl_location)) }
string abi_generator::remove_namespace(const string& full_name) { string abi_generator::remove_namespace(const string& full_name) {
string type_name = full_name; int i = full_name.size();
auto pos = type_name.find_last_of("::"); int on_spec = 0;
if(pos != string::npos) int colons = 0;
type_name = type_name.substr(pos+1); while( --i >= 0 ) {
return type_name; 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) { bool abi_generator::is_builtin_type(const string& type_name) {
...@@ -70,13 +81,14 @@ void abi_generator::handle_decl(const Decl* decl) { try { ...@@ -70,13 +81,14 @@ void abi_generator::handle_decl(const Decl* decl) { try {
ABI_ASSERT(decl != nullptr); ABI_ASSERT(decl != nullptr);
ABI_ASSERT(output != nullptr); ABI_ASSERT(output != nullptr);
ABI_ASSERT(ast_context != nullptr);
ASTContext& ctx = decl->getASTContext(); //ASTContext& ctx = decl->getASTContext();
const RawComment* raw_comment = ctx.getRawCommentForDeclNoCache(decl); const RawComment* raw_comment = ast_context->getRawCommentForDeclNoCache(decl);
if(!raw_comment) return; if(!raw_comment) return;
SourceManager& source_manager = ctx.getSourceManager(); SourceManager& source_manager = ast_context->getSourceManager();
auto file_name = source_manager.getFilename(raw_comment->getLocStart()); auto file_name = source_manager.getFilename(raw_comment->getLocStart());
if ( !abi_context.empty() && !file_name.startswith(abi_context) ) { if ( !abi_context.empty() && !file_name.startswith(abi_context) ) {
return; return;
...@@ -105,7 +117,7 @@ void abi_generator::handle_decl(const Decl* decl) { try { ...@@ -105,7 +117,7 @@ void abi_generator::handle_decl(const Decl* decl) { try {
auto qt = action_decl->getTypeForDecl()->getCanonicalTypeInternal(); 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), 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)); "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 { ...@@ -128,7 +140,7 @@ void abi_generator::handle_decl(const Decl* decl) { try {
ABI_ASSERT(table_decl != nullptr); ABI_ASSERT(table_decl != nullptr);
auto qt = table_decl->getTypeForDecl()->getCanonicalTypeInternal(); 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), 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)); "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 { ...@@ -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.name = boost::algorithm::to_lower_copy(boost::erase_all_copy(type_name, "_"));
table.type = type_name; table.type = type_name;
if(params.size() >= 1) if(params.size() >= 1) {
table.index_type = params[0]; table.name = params[0];
}
if(params.size() >= 2)
table.index_type = params[1];
else { try { else { try {
guess_index_type(table, *s); guess_index_type(table, *s);
} FC_CAPTURE_AND_RETHROW( (type_name) ) } } FC_CAPTURE_AND_RETHROW( (type_name) ) }
if(params.size() >= 2) {
table.name = params[1];
}
try { try {
guess_key_names(table, *s); guess_key_names(table, *s);
} FC_CAPTURE_AND_RETHROW( (type_name) ) } FC_CAPTURE_AND_RETHROW( (type_name) )
...@@ -181,9 +193,11 @@ bool abi_generator::is_string(const string& type) { ...@@ -181,9 +193,11 @@ bool abi_generator::is_string(const string& type) {
void abi_generator::get_all_fields(const struct_def& s, vector<field_def>& fields) { void abi_generator::get_all_fields(const struct_def& s, vector<field_def>& fields) {
abi_serializer abis(*output); abi_serializer abis(*output);
for(const auto& field : s.fields) { for(const auto& field : s.fields) {
fields.push_back(field); fields.push_back(field);
} }
if(s.base.size()) { if(s.base.size()) {
const auto* base = find_struct(s.base); const auto* base = find_struct(s.base);
ABI_ASSERT(base, "Unable to find base type ${type}",("type",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) { ...@@ -211,7 +225,7 @@ void abi_generator::guess_index_type(table_def& table, const struct_def s) {
vector<field_def> fields; vector<field_def> fields;
get_all_fields(s, fields); get_all_fields(s, fields);
if( is_str_index(fields) ) { if( is_str_index(fields) ) {
table.index_type = "str"; table.index_type = "str";
} else if ( is_i64i64i64_index(fields) ) { } else if ( is_i64i64i64_index(fields) ) {
...@@ -230,15 +244,28 @@ void abi_generator::guess_key_names(table_def& table, const struct_def s) { ...@@ -230,15 +244,28 @@ void abi_generator::guess_key_names(table_def& table, const struct_def s) {
vector<field_def> fields; vector<field_def> fields;
get_all_fields(s, fields); get_all_fields(s, fields);
if( table.index_type == "i64i64i64" && is_i64i64i64_index(fields) ) { if( table.index_type == "i64i64i64" || table.index_type == "i128i128"
table.key_names = vector<field_name>{fields[0].name, fields[1].name, fields[2].name}; || table.index_type == "i64") {
table.key_types = vector<type_name>{fields[0].type, fields[1].type, fields[2].type};
} else if( table.index_type == "i128i128" && is_i128i128_index(fields) ) { table.key_names.clear();
table.key_names = vector<field_name>{fields[0].name, fields[1].name}; table.key_types.clear();
table.key_types = vector<type_name>{fields[0].type, fields[1].type};
} else if( table.index_type == "i64" && is_i64_index(fields) ) { unsigned int key_size = 0;
table.key_names = vector<field_name>{fields[0].name}; bool valid_key = false;
table.key_types = vector<type_name>{fields[0].type}; 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) ) { } else if( table.index_type == "str" && is_str_index(fields) ) {
table.key_names = vector<field_name>{fields[0].name}; table.key_names = vector<field_name>{fields[0].name};
table.key_types = vector<type_name>{fields[0].type}; table.key_types = vector<type_name>{fields[0].type};
...@@ -298,95 +325,196 @@ bool abi_generator::is_one_filed_no_base(const string& type_name) { ...@@ -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) { string abi_generator::decl_to_string(clang::Decl* d) {
ASTContext& ctx = d->getASTContext(); //ASTContext& ctx = d->getASTContext();
const auto& sm = ctx.getSourceManager(); const auto& sm = ast_context->getSourceManager();
clang::SourceLocation b(d->getLocStart()), _e(d->getLocEnd()); clang::SourceLocation b(d->getLocStart()), _e(d->getLocEnd());
clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, sm, compiler_instance->getLangOpts())); clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, sm, compiler_instance->getLangOpts()));
return string(sm.getCharacterData(b), return string(sm.getCharacterData(b),
sm.getCharacterData(e)-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<TypedefType>(qt.getTypePtr());
}
vector<type_def> types_to_add; bool abi_generator::is_elaborated(const clang::QualType& qt) {
while(typeDef != nullptr) { return isa<ElaboratedType>(qt.getTypePtr());
const auto* typedef_decl = typeDef->getDecl(); }
auto qt = typedef_decl->getUnderlyingType().getUnqualifiedType();
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 ( is_elaborated(qt) )
if( full_name.find("<") != string::npos ) { qt = qt->getAs<clang::ElaboratedType>()->getNamedType();
break;
}
auto new_type_name = translate_type(typedef_decl->getName().str()); return isa<clang::TemplateSpecializationType>(qt.getTypePtr()) \
if(is_builtin_type(new_type_name)) { && boost::starts_with( get_type_name(qt, false), "vector");
break; }
}
bool abi_generator::is_vector(const string& type_name) {
return boost::ends_with(type_name, "[]");
}
//TODO: ABI_ASSERT TypeName length for typedef bool abi_generator::is_struct_specialization(const clang::QualType& qt) {
type_def abi_typedef; return is_struct(qt) && isa<clang::TemplateSpecializationType>(qt.getTypePtr());
abi_typedef.new_type_name = new_type_name; }
abi_typedef.type = remove_namespace( full_name );
const auto* td = find_type(abi_typedef.new_type_name); bool abi_generator::is_struct(const clang::QualType& sqt) {
if( td ) { clang::QualType qt(sqt);
ABI_ASSERT(abi_typedef.type == td->type); const auto* type = qt.getTypePtr();
typeDef = qt->getAs<clang::TypedefType>(); return !is_vector(qt) && (type->isStructureType() || type->isClassType());
continue; }
}
clang::QualType abi_generator::get_vector_element_type(const clang::QualType& qt) {
const auto* tst = clang::dyn_cast<const clang::TemplateSpecializationType>(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))); clang::QualType qt(get_named_type_if_elaborated(tqt));
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()))
);
types_to_add.push_back(abi_typedef); const auto* td_decl = qt->getAs<clang::TypedefType>()->getDecl();
typeDef = qt->getAs<clang::TypedefType>(); 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()); if( is_typedef(underlying_type) && !is_builtin_type(get_type_name(underlying_type)) )
output->types.insert(output->types.end(), types_to_add.begin(), types_to_add.end()); 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()); clang::QualType qt(sqt);
const auto* typedef_type = qual_type->getAs<clang::TypedefType>(); if(is_typedef(qt)) {
if( !is_builtin_type(type_name) && typedef_type != nullptr) { const auto* td_decl = qt->getAs<clang::TypedefType>()->getDecl();
add_typedef(typedef_type); qt = td_decl->getUnderlyingType().getUnqualifiedType();
} }
const auto* record_type = qt->getAs<clang::RecordType>();
ABI_ASSERT(record_type != nullptr);
auto cxxrecord_decl = clang::dyn_cast<CXXRecordDecl>(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<clang::TypedefType>()->getDecl();
qt = td_decl->getUnderlyingType().getUnqualifiedType();
}
const auto* record_type = qual_type->getAs<clang::RecordType>(); const auto* record_type = qt->getAs<clang::RecordType>();
ABI_ASSERT(record_type != nullptr); 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<clang::CXXRecordDecl>(record_type->getDecl()->getDefinition()); add_type(vector_element_type);
ABI_ASSERT(record_decl != nullptr);
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 string full_type_name = translate_type(get_type_name(qt, true));
if( is_builtin_type(name) ) { string type_name = translate_type(get_type_name(qt));
return name; 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<clang::ElaboratedType>()->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), ABI_ASSERT(name.size() <= sizeof(type_name),
"Type name > ${maxsize}, ${name}", "Type name > ${maxsize}, ${name}",
...@@ -400,58 +528,52 @@ string abi_generator::add_struct(const clang::QualType& qual_type) { ...@@ -400,58 +528,52 @@ string abi_generator::add_struct(const clang::QualType& qual_type) {
return name; return name;
} }
auto bases = record_decl->bases(); auto bases = get_struct_bases(qt);
auto total_bases = distance(bases.begin(), bases.end()); auto bitr = bases.begin();
if( total_bases > 1 ) { int total_bases = 0;
ABI_ASSERT(false, "Multiple inheritance not supported - ${type}", ("type",full_name));
}
string base_name; string base_name;
if( total_bases == 1 ) { while( bitr != bases.end() ) {
auto qt = bases.begin()->getType(); auto base_qt = bitr->getType();
base_name = add_struct(qt); const auto* record_type = base_qt->getAs<clang::RecordType>();
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; struct_def abi_struct;
for (const auto& field : record_decl->fields()) { for (const clang::FieldDecl* field : get_struct_fields(qt) ) {
field_def struct_field;
clang::QualType qt = field->getType(); 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()))); field_def struct_field{field_name, field_type_name};
ABI_ASSERT(is_builtin_type(get_vector_element_type(struct_field.type))
ABI_ASSERT(field_type.size() <= sizeof(decltype(struct_field.type)), || find_struct(get_vector_element_type(struct_field.type))
"Type name > ${maxsize}, ${type}::${name}", ("type",full_name)("name",field_type)("maxsize",sizeof(decltype(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)) , ABI_ASSERT(struct_field.type.size() <= sizeof(decltype(struct_field.type)),
"Field name > ${maxsize}, ${type}::${name}", ("type",full_name)("name",field->getNameAsString())("maxsize", sizeof(decltype(struct_field.name)))); "Type name > ${maxsize}, ${type}::${name}", ("type",struct_field.type)("name",struct_field.name)("maxsize",sizeof(decltype(struct_field.type))));
if( qt->getAs<clang::RecordType>() ) {
add_struct(qt);
//TODO: simplify if OPT_SINGLE_FIELD_STRUCT is enabled
}
struct_field.name = field->getNameAsString();
struct_field.type = 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.fields.push_back(struct_field);
} }
abi_struct.name = resolve_type(name); abi_struct.name = resolve_type(name);
abi_struct.base = remove_namespace(base_name); abi_struct.base = base_name;
output->structs.push_back(abi_struct);
if(verbose) {
cerr << "Adding type " << resolve_type(name) << " (" << full_name << ")\n";
}
output->structs.push_back(abi_struct);
full_types[name] = full_name; full_types[name] = full_name;
return full_name; return name;
} }
} }
\ No newline at end of file
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/Tooling.h" #include "clang/Tooling/Tooling.h"
#include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Core/QualTypeNames.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
...@@ -60,7 +61,7 @@ namespace eosio { ...@@ -60,7 +61,7 @@ namespace eosio {
map<string, uint64_t> type_size; map<string, uint64_t> type_size;
map<string, string> full_types; map<string, string> full_types;
string abi_context; string abi_context;
clang::ASTContext* ast_context;
public: public:
enum optimization { enum optimization {
...@@ -70,7 +71,8 @@ namespace eosio { ...@@ -70,7 +71,8 @@ namespace eosio {
abi_generator() abi_generator()
:optimizations(0) :optimizations(0)
, output(nullptr) , output(nullptr)
, compiler_instance(nullptr) , compiler_instance(nullptr)
, ast_context(nullptr)
{} {}
~abi_generator() {} ~abi_generator() {}
...@@ -161,11 +163,29 @@ namespace eosio { ...@@ -161,11 +163,29 @@ namespace eosio {
string decl_to_string(clang::Decl* d); 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 { struct abi_generator_astconsumer : public ASTConsumer {
......
...@@ -181,14 +181,19 @@ void apply_eosio_updateauth(apply_context& context) { ...@@ -181,14 +181,19 @@ void apply_eosio_updateauth(apply_context& context) {
if (act_auth.permission == config::owner_name || act_auth.permission == update.permission) { if (act_auth.permission == config::owner_name || act_auth.permission == update.permission) {
return true; return true;
} }
const permission_object *current = db.find<permission_object, by_owner>(boost::make_tuple(update.account, update.permission));
auto current = db.get<permission_object, by_owner>(boost::make_tuple(update.account, update.permission)); // Permission doesn't exist yet, check parent permission
while(current.name != config::owner_name) { if (current == nullptr) current = db.find<permission_object, by_owner>(boost::make_tuple(update.account, update.parent));
if (current.name == act_auth.permission) { // 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; return true;
} }
current = &db.get<permission_object>(current->parent);
current = db.get<permission_object>(current.parent);
} }
return false; return false;
......
...@@ -21,6 +21,9 @@ namespace eosio { namespace chain { ...@@ -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( 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( 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( 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_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" ) 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 { ...@@ -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( 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( 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 ) \ #define EOS_RECODE_EXC( cause_type, effect_type ) \
catch( const cause_type& e ) \ catch( const cause_type& e ) \
......
...@@ -2,6 +2,5 @@ add_subdirectory( eosiod ) ...@@ -2,6 +2,5 @@ add_subdirectory( eosiod )
add_subdirectory( eosioc ) add_subdirectory( eosioc )
add_subdirectory( eosiowd ) add_subdirectory( eosiowd )
add_subdirectory( eosio-launcher ) add_subdirectory( eosio-launcher )
add_subdirectory( eosio-codegen )
add_subdirectory( eosio-applesedemo ) add_subdirectory( eosio-applesedemo )
add_subdirectory( eosio-abigen ) add_subdirectory( eosio-abigen )
...@@ -42,16 +42,14 @@ static cl::opt<bool> abi_opt_sfs( ...@@ -42,16 +42,14 @@ static cl::opt<bool> abi_opt_sfs(
cl::desc("Optimize single field struct"), cl::desc("Optimize single field struct"),
cl::cat(abi_generator_category)); 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); CommonOptionsParser op(argc, argv, abi_generator_category);
ClangTool Tool(op.getCompilations(), op.getSourcePathList()); ClangTool Tool(op.getCompilations(), op.getSourcePathList());
abi_def abi; int result = Tool.run(create_factory(abi_verbose, abi_opt_sfs, abi_context, output).get());
int result = Tool.run(create_factory(abi_verbose, abi_opt_sfs, abi_context, abi).get());
if(!result) { if(!result) {
abi_serializer(abi).validate(); abi_serializer(output).validate();
fc::json::save_to_file<abi_def>(abi, abi_destination, true); fc::json::save_to_file<abi_def>(output, abi_destination, true);
} }
return result; return result;
} FC_CAPTURE_AND_LOG(()); return -1; } } FC_CAPTURE_AND_LOG((output)); return -1; }
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
)
/**
* @file
* @copyright defined in eos/LICENSE.txt
* @brief generates serialization/deserialization functions for contracts types
**/
#include <string>
#include <sstream>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <eosio/chain/types.hpp>
#include <eosio/chain/contracts/abi_serializer.hpp>
#include <fc/io/json.hpp>
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<typename Type>" << 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<typename Stream> 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<const " << type.base << "&>(value));" << endl;
output << tab << "}" << endl;
}
void generate_unpack(ostringstream& output, const struct_def& type) {
output << tab << "template<typename Stream> 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 <eosiolib/types.hpp>" << endl;
output << "#include <eosiolib/message.hpp>" << endl;
output << "#include <eosiolib/datastream.hpp>" << endl;
output << "#include <eosiolib/raw_fwd.hpp>" << 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 <eosiolib/raw.hpp>" << 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<abi_def>(argv[1]);
codegen generator(abi);
generator.generate();
return 0;
}
...@@ -183,7 +183,13 @@ e.g. ...@@ -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<int64_t, std::string> error_advice = { const std::map<int64_t, std::string> error_advice = {
{ 3120001, error_advice_3120001 }, { 3120001, error_advice_3120001 },
...@@ -192,6 +198,10 @@ const std::map<int64_t, std::string> error_advice = { ...@@ -192,6 +198,10 @@ const std::map<int64_t, std::string> error_advice = {
{ 3120004, error_advice_3120004 }, { 3120004, error_advice_3120004 },
{ 3120005, error_advice_3120005 }, { 3120005, error_advice_3120005 },
{ 3120006, error_advice_3120006 }, { 3120006, error_advice_3120006 },
{ 3130001, error_advice_3130001 },
{ 3130002, error_advice_3130002 },
{ 3130003, error_advice_3130003 },
{ 3130004, error_advice_3130004 },
{ 3030002, error_advice_3030002 } { 3030002, error_advice_3030002 }
}; };
......
...@@ -15,127 +15,135 @@ ...@@ -15,127 +15,135 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <fc/variant.hpp> #include <fc/variant.hpp>
#include <fc/io/json.hpp> #include <fc/io/json.hpp>
#include <fc/exception/exception.hpp> #include <eosio/chain/exceptions.hpp>
#include <eosio/http_plugin/http_plugin.hpp> #include <eosio/http_plugin/http_plugin.hpp>
#include <eosio/chain_plugin/chain_plugin.hpp> #include <eosio/chain_plugin/chain_plugin.hpp>
#include "httpc.hpp"
using boost::asio::ip::tcp; using boost::asio::ip::tcp;
namespace eosio { namespace client { namespace http {
fc::variant call( const std::string& server, uint16_t port, fc::variant call( const std::string& server, uint16_t port,
const std::string& path, const std::string& path,
const fc::variant& postdata ) const fc::variant& postdata ) {
{ try { try {
std::string postjson; std::string postjson;
if( !postdata.is_null() ) if( !postdata.is_null() )
postjson = fc::json::to_string( postdata ); postjson = fc::json::to_string( postdata );
boost::asio::io_service io_service; boost::asio::io_service io_service;
// Get a list of endpoints corresponding to the server name. // Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service); tcp::resolver resolver(io_service);
tcp::resolver::query query(server, std::to_string(port) ); tcp::resolver::query query(server, std::to_string(port) );
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end; tcp::resolver::iterator end;
while( endpoint_iterator != end ) { while( endpoint_iterator != end ) {
// Try each endpoint until we successfully establish a connection. // Try each endpoint until we successfully establish a connection.
tcp::socket socket(io_service); tcp::socket socket(io_service);
try { try {
boost::asio::connect(socket, endpoint_iterator); boost::asio::connect(socket, endpoint_iterator);
endpoint_iterator = end; endpoint_iterator = end;
} catch( std::exception& e ) { } catch( std::exception& e ) {
++endpoint_iterator; ++endpoint_iterator;
if( endpoint_iterator != end ) if( endpoint_iterator != end )
continue; continue;
else throw; else throw;
} }
// Form the request. We specify the "Connection: close" header so that the // Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This will // server will close the socket after transmitting the response. This will
// allow us to treat all data up until the EOF as the content. // allow us to treat all data up until the EOF as the content.
boost::asio::streambuf request; boost::asio::streambuf request;
std::ostream request_stream(&request); std::ostream request_stream(&request);
request_stream << "POST " << path << " HTTP/1.0\r\n"; request_stream << "POST " << path << " HTTP/1.0\r\n";
request_stream << "Host: " << server << "\r\n"; request_stream << "Host: " << server << "\r\n";
request_stream << "content-length: " << postjson.size() << "\r\n"; request_stream << "content-length: " << postjson.size() << "\r\n";
request_stream << "Accept: */*\r\n"; request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n"; request_stream << "Connection: close\r\n\r\n";
request_stream << postjson; request_stream << postjson;
// Send the request. // Send the request.
boost::asio::write(socket, request); boost::asio::write(socket, request);
// Read the response status line. The response streambuf will automatically // Read the response status line. The response streambuf will automatically
// grow to accommodate the entire line. The growth may be limited by passing // grow to accommodate the entire line. The growth may be limited by passing
// a maximum size to the streambuf constructor. // a maximum size to the streambuf constructor.
boost::asio::streambuf response; boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n"); boost::asio::read_until(socket, response, "\r\n");
// Check that response is OK. // Check that response is OK.
std::istream response_stream(&response); std::istream response_stream(&response);
std::string http_version; std::string http_version;
response_stream >> http_version; response_stream >> http_version;
unsigned int status_code; unsigned int status_code;
response_stream >> status_code; response_stream >> status_code;
std::string status_message; std::string status_message;
std::getline(response_stream, status_message); std::getline(response_stream, status_message);
FC_ASSERT( !(!response_stream || http_version.substr(0, 5) != "HTTP/"), "Invalid Response" ); FC_ASSERT( !(!response_stream || http_version.substr(0, 5) != "HTTP/"), "Invalid Response" );
// Read the response headers, which are terminated by a blank line. // Read the response headers, which are terminated by a blank line.
boost::asio::read_until(socket, response, "\r\n\r\n"); boost::asio::read_until(socket, response, "\r\n\r\n");
// Process the response headers. // Process the response headers.
std::string header; std::string header;
while (std::getline(response_stream, header) && header != "\r") while (std::getline(response_stream, header) && header != "\r")
{ {
// std::cout << header << "\n"; // std::cout << header << "\n";
} }
// std::cout << "\n"; // std::cout << "\n";
std::stringstream re; std::stringstream re;
// Write whatever content we already have to output. // Write whatever content we already have to output.
if (response.size() > 0) if (response.size() > 0)
// std::cout << &response; // std::cout << &response;
re << &response; re << &response;
// Read until EOF, writing data to output as we go. // Read until EOF, writing data to output as we go.
boost::system::error_code error; boost::system::error_code error;
while (boost::asio::read(socket, response, while (boost::asio::read(socket, response,
boost::asio::transfer_at_least(1), error)) boost::asio::transfer_at_least(1), error))
re << &response; re << &response;
if (error != boost::asio::error::eof) if (error != boost::asio::error::eof)
throw boost::system::system_error(error); throw boost::system::system_error(error);
// std::cout << re.str() <<"\n"; // std::cout << re.str() <<"\n";
const auto response_result = fc::json::from_string(re.str()); const auto response_result = fc::json::from_string(re.str());
if( status_code == 200 || status_code == 201 || status_code == 202 ) { if( status_code == 200 || status_code == 201 || status_code == 202 ) {
return response_result; return response_result;
} else { } else if( status_code == 404 ) {
auto &&error = response_result.as<eosio::error_results>().error; // Unknown endpoint
if (path.compare(0, chain_func_base.size(), chain_func_base) == 0) {
// eos recognized error code is from 3000000 to 3999999 throw chain::missing_chain_api_plugin_exception(FC_LOG_MESSAGE(error, "Chain API plugin is not enabled"));
// refer to libraries/chain/include/eosio/chain/exceptions.hpp } else if (path.compare(0, wallet_func_base.size(), wallet_func_base) == 0) {
if (error.code >= 3000000 && error.code <= 3999999) { throw chain::missing_wallet_api_plugin_exception(FC_LOG_MESSAGE(error, "Wallet is not available"));
// Construct fc exception from error } else if (path.compare(0, account_history_func_base.size(), account_history_func_base) == 0) {
const auto &stack_trace = error.stack_trace; throw chain::missing_account_history_api_plugin_exception(FC_LOG_MESSAGE(error, "Account History API plugin is not enabled"));
fc::exception new_exception(error.code, error.name, error.message); } else if (path.compare(0, net_func_base.size(), net_func_base) == 0) {
if (stack_trace.empty()) { throw chain::missing_net_api_plugin_exception(FC_LOG_MESSAGE(error, "Net API plugin is not enabled"));
new_exception.append_log(FC_LOG_MESSAGE(error, error.details)); }
} else { } else {
for (auto itr = stack_trace.begin(); itr != stack_trace.end(); itr++) { auto &&error = response_result.as<eosio::error_results>().error;
const auto &error_message = itr == stack_trace.begin() ? error.details : std::string(); // Construct fc exception from error
new_exception.append_log(fc::log_message(*itr, error_message)); const auto &stack_trace = error.stack_trace;
} fc::exception new_exception(error.code, error.name, error.message);
} if (stack_trace.empty()) {
throw new_exception; 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();
FC_ASSERT( status_code == 200, "Error code ${c}\n: ${msg}\n", ("c", status_code)("msg", re.str()) ); new_exception.append_log(fc::log_message(*itr, error_message));
} }
}
FC_ASSERT( !"unable to connect" ); throw new_exception;
} FC_RETHROW_EXCEPTIONS( error, "Request Path: ${server}:${port}${path}, Request Post Data: ${postdata}" , }
("server", server)("port", port)("path", path)("postdata", postdata) )
} 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
/**
* @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
...@@ -96,12 +96,14 @@ Options: ...@@ -96,12 +96,14 @@ Options:
#include "help_text.hpp" #include "help_text.hpp"
#include "localize.hpp" #include "localize.hpp"
#include "config.hpp" #include "config.hpp"
#include "httpc.hpp"
using namespace std; using namespace std;
using namespace eosio; using namespace eosio;
using namespace eosio::chain; using namespace eosio::chain;
using namespace eosio::utilities; using namespace eosio::utilities;
using namespace eosio::client::help; using namespace eosio::client::help;
using namespace eosio::client::http;
using namespace eosio::client::localize; using namespace eosio::client::localize;
using namespace eosio::client::config; using namespace eosio::client::config;
using namespace boost::filesystem; using namespace boost::filesystem;
...@@ -127,43 +129,6 @@ uint32_t port = 8888; ...@@ -127,43 +129,6 @@ uint32_t port = 8888;
string wallet_host = "localhost"; string wallet_host = "localhost";
uint32_t wallet_port = 8888; 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<name> sort_names( const std::vector<name>& names ) { inline std::vector<name> sort_names( const std::vector<name>& names ) {
auto results = std::vector<name>(names); auto results = std::vector<name>(names);
...@@ -213,19 +178,14 @@ vector<chain::permission_level> get_account_permissions(const vector<string>& pe ...@@ -213,19 +178,14 @@ vector<chain::permission_level> get_account_permissions(const vector<string>& pe
return accountPermissions; return accountPermissions;
} }
fc::variant call( const std::string& server, uint16_t port,
const std::string& path,
const fc::variant& postdata = fc::variant() );
template<typename T> template<typename T>
fc::variant call( const std::string& server, uint16_t port, fc::variant call( const std::string& server, uint16_t port,
const std::string& path, 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<typename T> template<typename T>
fc::variant call( const std::string& path, 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() { eosio::chain_apis::read_only::get_info_results get_info() {
return call(host, port, get_info_func ).as<eosio::chain_apis::read_only::get_info_results>(); return call(host, port, get_info_func ).as<eosio::chain_apis::read_only::get_info_results>();
......
...@@ -16,6 +16,8 @@ set( CMAKE_CXX_STANDARD 14 ) ...@@ -16,6 +16,8 @@ set( CMAKE_CXX_STANDARD 14 )
include_directories("${CMAKE_BINARY_DIR}/contracts") include_directories("${CMAKE_BINARY_DIR}/contracts")
include_directories("${CMAKE_SOURCE_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") 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 ) add_executable( chain_test ${UNIT_TESTS} ${WASM_UNIT_TESTS} common/main.cpp )
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <eosio/chain/contracts/abi_serializer.hpp> #include <eosio/chain/contracts/abi_serializer.hpp>
#include <eosio/abi_generator/abi_generator.hpp> #include <eosio/abi_generator/abi_generator.hpp>
#include "config.hpp"
using namespace eosio; using namespace eosio;
using namespace chain; using namespace chain;
using namespace chain::contracts; using namespace chain::contracts;
...@@ -354,25 +356,16 @@ BOOST_AUTO_TEST_CASE(uint_types) ...@@ -354,25 +356,16 @@ BOOST_AUTO_TEST_CASE(uint_types)
} FC_LOG_AND_RETHROW() } } FC_LOG_AND_RETHROW() }
using namespace eosio::tests::config;
BOOST_AUTO_TEST_CASE(generator) struct abi_gen_helper {
{ try {
if( std::getenv("EOSLIB") == nullptr ) {
wlog("*************************************");
wlog("* EOSLIB env variable not defined *");
wlog("* ABIGenerator tests will not run *");
wlog("*************************************");
return;
}
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 { static bool is_abi_generation_exception(const eosio::abi_generation_exception& e) { return true; };
const char* eosiolib_path = std::getenv("EOSLIB");
FC_ASSERT(eosiolib_path != NULL);
bool generate_abi(const char* source, const char* abi, bool opt_sfs=false) {
std::string include_param = std::string("-I") + eosiolib_path; std::string include_param = std::string("-I") + eosiolib_path;
std::string stdcpp_include_param = std::string("-I") + eosiolib_path + "/libc++/upstream/include"; 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"; std::string stdc_include_param = std::string("-I") + eosiolib_path + "/musl/upstream/include";
...@@ -394,7 +387,12 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -394,7 +387,12 @@ BOOST_AUTO_TEST_CASE(generator)
} }
return e; return e;
}; }
};
BOOST_FIXTURE_TEST_CASE(abigen_unknown_type, abi_gen_helper)
{ try {
const char* unknown_type = R"=====( const char* unknown_type = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
...@@ -405,7 +403,12 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -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"=====( const char* all_types = R"=====(
#include <eosiolib/types.hpp> #include <eosiolib/types.hpp>
...@@ -611,6 +614,11 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -611,6 +614,11 @@ BOOST_AUTO_TEST_CASE(generator)
)====="; )=====";
BOOST_TEST( generate_abi(all_types, all_types_abi) == true); 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"=====( const char* double_base = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
...@@ -627,7 +635,13 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -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"=====( const char* double_action = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
...@@ -684,6 +698,12 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -684,6 +698,12 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(double_action, double_action_abi) == true ); 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"=====( const char* all_indexes = R"=====(
#include <eosiolib/types.hpp> #include <eosiolib/types.hpp>
#include <string> #include <string>
...@@ -831,6 +851,11 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -831,6 +851,11 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(all_indexes, all_indexes_abi) == true ); 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"=====( const char* unable_to_determine_index = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
...@@ -842,10 +867,14 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -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; // typedef fixed_string16 FieldName;
const char* long_field_name = R"=====( const char* long_field_name = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
...@@ -857,7 +886,12 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -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"=====( const char* long_type_name = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
...@@ -874,7 +908,12 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -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"=====( const char* same_type_different_namespace = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
...@@ -895,12 +934,17 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -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"=====( const char* bad_index_type = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
//@abi table i64 //@abi table table1 i128i128
struct table1 { struct table1 {
uint32_t key; uint32_t key;
uint64_t field1; uint64_t field1;
...@@ -909,12 +953,17 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -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"=====( const char* full_table_decl = R"=====(
#include <eosiolib/types.hpp> #include <eosiolib/types.hpp>
//@abi table i64 //@abi table table1 i64
class table1 { class table1 {
public: public:
uint64_t id; uint64_t id;
...@@ -959,6 +1008,11 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -959,6 +1008,11 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(full_table_decl, full_table_decl_abi) == true ); 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"=====( const char* str_table_decl = R"=====(
#include <eosiolib/types.hpp> #include <eosiolib/types.hpp>
#include <string> #include <string>
...@@ -1004,6 +1058,10 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -1004,6 +1058,10 @@ BOOST_AUTO_TEST_CASE(generator)
)====="; )=====";
BOOST_TEST( generate_abi(str_table_decl, str_table_decl_abi) == true ); 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"=====( const char* union_table = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
...@@ -1016,7 +1074,12 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -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"=====( const char* same_action_different_type = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
...@@ -1033,7 +1096,11 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -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"=====( const char* template_base = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
...@@ -1045,7 +1112,7 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -1045,7 +1112,7 @@ BOOST_AUTO_TEST_CASE(generator)
typedef base<uint32_t> base32; typedef base<uint32_t> base32;
//@abi table i64 //@abi table table1 i64
class table1 : base32 { class table1 : base32 {
public: public:
uint64_t id; uint64_t id;
...@@ -1089,6 +1156,11 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -1089,6 +1156,11 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(template_base, template_base_abi) == true ); 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"=====( const char* action_and_table = R"=====(
#include <eosiolib/types.h> #include <eosiolib/types.h>
...@@ -1134,6 +1206,11 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -1134,6 +1206,11 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(action_and_table, action_and_table_abi) == true ); 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"=====( const char* simple_typedef = R"=====(
#include <eosiolib/types.hpp> #include <eosiolib/types.hpp>
...@@ -1190,6 +1267,10 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -1190,6 +1267,10 @@ BOOST_AUTO_TEST_CASE(generator)
)====="; )=====";
BOOST_TEST( generate_abi(simple_typedef, simple_typedef_abi) == true ); 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"=====( const char* field_typedef = R"=====(
#include <eosiolib/types.hpp> #include <eosiolib/types.hpp>
...@@ -1264,9 +1345,248 @@ BOOST_AUTO_TEST_CASE(generator) ...@@ -1264,9 +1345,248 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(field_typedef, field_typedef_abi) == true ); 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 <vector>
#include <string>
#include <eosiolib/types.hpp>
using namespace eosio;
using namespace std;
//@abi table
struct table1 {
uint64_t field1;
vector<uint64_t> uints64;
vector<uint32_t> uints32;
vector<uint16_t> uints16;
vector<uint8_t> 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() } } FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_vector_of_structs, abi_gen_helper)
{ try {
const char* abigen_vector_of_structs = R"=====(
#include <vector>
#include <string>
#include <eosiolib/types.hpp>
using namespace eosio;
using namespace std;
struct my_struct {
vector<uint64_t> uints64;
vector<uint32_t> uints32;
vector<uint16_t> uints16;
vector<uint8_t> uints8;
string str;
};
//@abi table
struct table1 {
uint64_t field1;
vector<my_struct> 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 <vector>
#include <string>
#include <eosiolib/types.hpp>
using namespace eosio;
using namespace std;
//@abi table
struct table1 {
uint64_t field1;
vector<vector<uint64_t>> 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 <string>
#include <vector>
#include <eosiolib/types.hpp>
#include <eosiolib/print.hpp>
using namespace std;
struct row {
std::vector<uint32_t> cells;
};
typedef vector<row> 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) BOOST_AUTO_TEST_CASE(general)
{ try { { try {
......
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
namespace eosio { namespace tests { namespace config {
constexpr char eosiolib_path[] = "${CMAKE_CURRENT_SOURCE_DIR}/../contracts";
}}}
#!/bin/bash #!/bin/bash
EOSIO_INSTALL_DIR=@CMAKE_INSTALL_PREFIX@ EOSIO_INSTALL_DIR=@CMAKE_INSTALL_PREFIX@
ABIGEN=${EOSIO_INSTALL_DIR}/bin/abi_gen ABIGEN=${EOSIO_INSTALL_DIR}/bin/eosio-abigen
CODEGEN=${EOSIO_INSTALL_DIR}/bin/codegen BOOST_INCLUDE_DIR=@Boost_INCLUDE_DIR@
function copy_skeleton { function copy_skeleton {
set -e set -e
cp -r ${EOSIO_INSTALL_DIR}/share/skeleton/. $newname cp -r ${EOSIO_INSTALL_DIR}/share/skeleton/. $newname
...@@ -32,8 +31,24 @@ function build_contract { ...@@ -32,8 +31,24 @@ function build_contract {
name=`basename $file` name=`basename $file`
filePath=`dirname $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 # echo @WASM_CLANG@ -emit-llvm -O3 --std=c++14 --target=wasm32 -nostdinc \
@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 # -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 done
# echo @WASM_LLVM_LINK@ -o $workdir/linked.bc $workdir/built/* # echo @WASM_LLVM_LINK@ -o $workdir/linked.bc $workdir/built/*
...@@ -56,9 +71,13 @@ function generate_abi { ...@@ -56,9 +71,13 @@ function generate_abi {
fi fi
context_folder=$(realpath $(dirname $1)) context_folder=$(realpath $(dirname $1))
${ABIGEN} -extra-arg=-c -extra-arg=--std=c++14 -extra-arg=--target=wasm32 \ ${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 \ -extra-arg=-fparse-all-comments -destination-file=${outname} -verbose=0 \
-context=$context_folder $1 -- -context=$context_folder $1 --
...@@ -67,18 +86,6 @@ function generate_abi { ...@@ -67,18 +86,6 @@ function generate_abi {
fi fi
echo "Generated ${outname} ..." 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 { function print_help {
...@@ -95,12 +102,11 @@ function print_help { ...@@ -95,12 +102,11 @@ function print_help {
echo " -o | --outname [output.wast] [input.cpp ...]" echo " -o | --outname [output.wast] [input.cpp ...]"
echo " Generate the wast output file based on input cpp files" echo " Generate the wast output file based on input cpp files"
echo " OR" echo " OR"
echo " -g | --genabi contract.abi [ -gs ] types.hpp" echo " -g | --genabi contract.abi types.hpp"
echo " Generate the ABI specification file [EXPERIMENTAL]" echo " Generate the ABI specification file [EXPERIMENTAL]"
} }
command="" command=""
genserialfunctions="no"
while [[ $# -gt 1 ]] while [[ $# -gt 1 ]]
do do
...@@ -123,11 +129,6 @@ case $key in ...@@ -123,11 +129,6 @@ case $key in
shift 2 shift 2
break break
;; ;;
-gs)
genserialfunctions="yes"
shift 1
break
;;
-g|--genabi) -g|--genabi)
outname="$2" outname="$2"
command="genabi" command="genabi"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册