Skip to content

Commit

Permalink
Merge pull request EOSIO#136 from EOSIO/feature/contract_datastream
Browse files Browse the repository at this point in the history
Feature/contract datastream
  • Loading branch information
larryk85 authored Oct 9, 2018
2 parents 8d3b644 + c6793f7 commit dcbb426
Show file tree
Hide file tree
Showing 16 changed files with 106 additions and 610 deletions.
2 changes: 1 addition & 1 deletion eosio_llvm
Submodule eosio_llvm updated 1 files
+1 −1 tools/clang
2 changes: 1 addition & 1 deletion examples/abigen_test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ project(abigen_test_example VERSION 1.0.0)
find_package(eosio.cdt)

### generate both the wasm and abi
add_eosio_cdt_executable( test test.cpp )
add_contract( abitest abitest abitest.cpp )
22 changes: 11 additions & 11 deletions examples/abigen_test/test.cpp → examples/abigen_test/abitest.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <eosiolib/eosio.hpp>
#include <eosiolib/optional.hpp>
#include <optional>

using namespace eosio;

Expand All @@ -11,7 +11,7 @@ namespace test {
void printddd() { print("testa"); }
int fielda;
float fieldb;
account_name name;
capi_name name;
};

struct testb {
Expand All @@ -24,24 +24,23 @@ namespace test {
};
}

class test_contract : public eosio::contract {
CONTRACT abitest : public eosio::contract {
public:
using contract::contract;

// mark this method as an action and specify the name explicity
[[ eosio::action("testacta") ]]
void testact_a( account_name user, const std::string& s, std::vector<int>& c, std::vector<std::string> sv ) {
void testact_a( name user, const std::string& s, std::vector<int>& c, std::vector<std::string> sv ) {
print( "Hello, ", name{user} );
}

// mark this method as an action
[[ eosio::action ]]
void testactb( test::test_c input, type_def td, optional<int> cc, bool d ) {
ACTION testactb( test::test_c input, type_def td, std::optional<int> cc, bool d ) {
print(input.num);
}

// mark this struct as a table and allow multi_index typedefs to define the tables
struct [[eosio::table]] testtable {
TABLE testtable {
uint64_t owner;
uint64_t third;
uint64_t primary_key() const { return owner; }
Expand All @@ -56,9 +55,10 @@ class test_contract : public eosio::contract {
};
};

typedef eosio::multi_index< N(testtab), test_contract::testtable > testtable_t;
typedef eosio::multi_index< N(testtaba), test_contract::testtable > testtable_a_t;
typedef eosio::multi_index< N(testtab2), test_contract::test_table2 > testtable2_t;
typedef eosio::multi_index< "testtab"_n, abitest::testtable > testtable_t;
typedef eosio::multi_index< "testtaba"_n, abitest::testtable > testtable_a_t;
typedef eosio::multi_index< "testtab2"_n, abitest::test_table2 > testtable2_t;

// NOTE THIS IS A TEST CONTRACT AND WILL NOT WORK CORRECTLY, the action `testa` will not be in the dispatcher of this macro
EOSIO_ABI( test_contract, (testact_a)(testactb) )
extern "C"
void apply(uint64_t, uint64_t, uint64_t){}
2 changes: 1 addition & 1 deletion examples/hello/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ find_package(eosio.cdt)
#add_executable( hello.wasm hello.cpp )

### Generate the wasm and abi
add_eosio_cdt_executable( hello hello.cpp )
add_contract( hello hello hello.cpp )
9 changes: 5 additions & 4 deletions examples/hello/hello.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include <eosiolib/eosio.hpp>

using namespace eosio;
class hello : public eosio::contract {

CONTRACT hello : public eosio::contract {
public:
using contract::contract;

[[eosio::action]]
void hi( account_name user ) {
ACTION hi( name user ) {
print( "Hello, ", name{user} );
}
};

EOSIO_ABI( hello, (hi) )
EOSIO_DISPATCH( hello, (hi) )
3 changes: 3 additions & 0 deletions examples/template/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ cmake_minimum_required(VERSION 3.5)
project(template_example VERSION 1.0.0)

find_package(eosio.cdt)

# add contract
add_contract( <contract name>, <target name>, <source files....> )
1 change: 0 additions & 1 deletion libraries/eosiolib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,3 @@ install(TARGETS eosio EXPORT EosioLib
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../eosiolib DESTINATION ${CMAKE_BINARY_DIR}/include FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp")
add_custom_command( TARGET eosio POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:eosio> ${CMAKE_BINARY_DIR}/lib )
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../eosiolib DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/core_symbol.hpp DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/eosiolib)
14 changes: 7 additions & 7 deletions libraries/eosiolib/action.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,14 @@ namespace eosio {
*
* @brief Name of the account the action is intended for
*/
name code_account;
name account;

/**
* Name of the action
*
* @brief Name of the action
*/
name action_name;
name name;

/**
* List of permissions that authorize this action
Expand Down Expand Up @@ -232,8 +232,8 @@ namespace eosio {
* @param value - The action struct that will be serialized via pack into data
*/
template<typename T>
action( const permission_level& auth, name a, name n, T&& value )
:code_account(a), action_name(n), authorization(1,auth), data(pack(std::forward<T>(value))) {}
action( const permission_level& auth, struct name a, struct name n, T&& value )
:account(a), name(n), authorization(1,auth), data(pack(std::forward<T>(value))) {}

/**
* Construct a new action object with the given action struct
Expand All @@ -246,10 +246,10 @@ namespace eosio {
* @param value - The action struct that will be serialized via pack into data
*/
template<typename T>
action( std::vector<permission_level> auths, name a, name n, T&& value )
:code_account(a), action_name(n), authorization(std::move(auths)), data(pack(std::forward<T>(value))) {}
action( std::vector<permission_level> auths, struct name a, struct name n, T&& value )
:account(a), name(n), authorization(std::move(auths)), data(pack(std::forward<T>(value))) {}

EOSLIB_SERIALIZE( action, (code_account)(action_name)(authorization)(data) )
EOSLIB_SERIALIZE( action, (account)(name)(authorization)(data) )

/**
* Send the action as inline action
Expand Down
43 changes: 41 additions & 2 deletions libraries/eosiolib/contract.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <eosiolib/name.hpp>
#include <eosiolib/datastream.hpp>

namespace eosio {

Expand All @@ -23,9 +24,20 @@ class contract {
* Construct a new contract given the contract name
*
* @brief Construct a new contract object.
* @param n - The name of this contract
* @param receiver - The name of this contract
* @param code - The code name of the action this contract is processing.
*/
contract( name n ):_self(n){}
contract( name receiver, name code ):_self(receiver), _code(code) {}

/**
* Construct a new contract given the contract name
*
* @brief Construct a new contract object.
* @param receiver - The name of this contract
* @param code - The code name of the action this contract is processing.
* @param ds - The datastream used
*/
contract( name receiver, name code, datastream<const char*> ds ):_self(receiver),_code(code),_ds(ds) {}

/**
*
Expand All @@ -35,6 +47,20 @@ class contract {
* @return name - The name of this contract
*/
inline name get_self()const { return _self; }

/**
* The code name of the action this contract is processing.
* @brief The code name of the action this contract is processing.
* @return name - The code name of the action this contract is processing.
*/
inline name get_code()const { return _code; }

/**
* Get the datastream for this contract
* @brief Get the datastream for this contract
* @return datastream<const char*> - The datastream for this contract
*/
inline datastream<const char*> get_datastream()const { return _ds; }

protected:
/**
Expand All @@ -43,6 +69,19 @@ class contract {
* @brief The name of this contract.
*/
name _self;

/**
* The code name of the action this contract is processing.
*
* @brief The code name of the action this contract is processing.
*/
name _code;

/**
* The datastream for this contract
*@ The datastream for this contract
*/
datastream<const char*> _ds = datastream<const char*>(nullptr, 0);
};

/// @} contracttype
Expand Down
2 changes: 1 addition & 1 deletion libraries/eosiolib/datastream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, eosio::symbol& sym
*
* @brief Serialize ignored_wrapper<T>'s T value
* @param ds - The stream to write
* @param ignore - The value to serialize
* @param val - The value to serialize
* @tparam Stream - Type of datastream buffer
* @return datastream<Stream>& - Reference to the datastream
*/
Expand Down
47 changes: 22 additions & 25 deletions libraries/eosiolib/dispatcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ namespace eosio {
* @param func - The action handler
* @return true
*/
template<typename T, typename Q, typename... Args>
bool execute_action( T* obj, void (Q::*func)(Args...) ) {
template<typename T, typename... Args>
bool execute_action( name self, name code, void (T::*func)(Args...) ) {
size_t size = action_data_size();

//using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions
Expand All @@ -73,31 +73,34 @@ namespace eosio {
buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size);
read_action_data( buffer, size );
}

auto args = unpack<std::tuple<std::decay_t<Args>...>>( (char*)buffer, size );

if ( max_stack_buffer_size < size ) {
free(buffer);
}
std::tuple<std::decay_t<Args>...> args;
datastream<const char*> ds((char*)buffer, size);
ds >> args;

T inst(self, code, ds);

auto f2 = [&]( auto... a ){
(obj->*func)( a... );
((&inst)->*func)( a... );
};

boost::mp11::tuple_apply( f2, args );
if ( max_stack_buffer_size < size ) {
free(buffer);
}
return true;
}
/// @} dispatcher

// Helper macro for EOSIO_API
#define EOSIO_API_CALL( r, OP, elem ) \
// Helper macro for EOSIO_DISPATCH_INTERNAL
#define EOSIO_DISPATCH_INTERNAL( r, OP, elem ) \
case eosio::name( BOOST_PP_STRINGIZE(elem) ).value: \
eosio::execute_action( &thiscontract, &OP::elem ); \
eosio::execute_action( eosio::name(receiver), eosio::name(code), &OP::elem ); \
break;

// Helper macro for EOSIO_ABI
#define EOSIO_API( TYPE, MEMBERS ) \
BOOST_PP_SEQ_FOR_EACH( EOSIO_API_CALL, TYPE, MEMBERS )
// Helper macro for EOSIO_DISPATCH
#define EOSIO_DISPATCH_HELPER( TYPE, MEMBERS ) \
BOOST_PP_SEQ_FOR_EACH( EOSIO_DISPATCH_INTERNAL, TYPE, MEMBERS )

/**
* @addtogroup dispatcher
Expand All @@ -114,21 +117,15 @@ namespace eosio {
*
* Example:
* @code
* EOSIO_ABI( eosio::bios, (setpriv)(setalimits)(setglimits)(setprods)(reqauth) )
* EOSIO_DISPATCH( eosio::bios, (setpriv)(setalimits)(setglimits)(setprods)(reqauth) )
* @endcode
*/
#define EOSIO_ABI( TYPE, MEMBERS ) \
#define EOSIO_DISPATCH( TYPE, MEMBERS ) \
extern "C" { \
void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \
eosio::name self(receiver); \
if( action == eosio::name("onerror").value) { \
/* onerror is only valid if it is for the "eosio" code account and authorized by "eosio"'s "active permission */ \
eosio_assert(code == eosio::name("eosio").value, "onerror action's are only valid from the \"eosio\" system account"); \
} \
if( code == self.value || action == eosio::name("onerror").value ) { \
TYPE thiscontract( self ); \
if( code == receiver ) { \
switch( action ) { \
EOSIO_API( TYPE, MEMBERS ) \
EOSIO_DISPATCH_HELPER( TYPE, MEMBERS ) \
} \
/* does not allow destructor of thiscontract to run: eosio_exit(0); */ \
} \
Expand Down
7 changes: 7 additions & 0 deletions libraries/eosiolib/eosio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,10 @@
#include <eosiolib/multi_index.hpp>
#include <eosiolib/dispatcher.hpp>
#include <eosiolib/contract.hpp>

/**
* Helper macros to reduce the verbosity for common contracts
*/
#define CONTRACT class [[eosio::contract]]
#define ACTION [[eosio::action]] void
#define TABLE struct [[eosio::table]]
Loading

0 comments on commit dcbb426

Please sign in to comment.