├── .idea ├── polleos.iml ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── vcs.xml ├── misc.xml └── modules.xml ├── CMakeModules ├── FindWasm.cmake └── wasm.cmake ├── LICENSE ├── .gitignore ├── tests ├── main.cpp ├── polleos_tests.cpp └── CMakeLists.txt ├── CMakeLists.txt ├── eosio.token.hpp ├── polleos.hpp ├── polleos.abi └── polleos.cpp /.idea/polleos.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CMakeModules/FindWasm.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find WASM 2 | 3 | # TODO: Check if compiler is able to generate wasm32 4 | if ("${WASM_ROOT}" STREQUAL "") 5 | if (APPLE) 6 | set( WASM_ROOT "/usr/local/wasm" ) 7 | elseif (UNIX AND NOT APPLE) 8 | set( WASM_ROOT "$ENV{HOME}/opt/wasm" ) 9 | else() 10 | message(FATAL_ERROR "WASM not found and don't know where to look, please specify WASM_ROOT") 11 | endif() 12 | endif() 13 | find_program(WASM_CLANG clang PATHS ${WASM_ROOT}/bin NO_DEFAULT_PATH) 14 | find_program(WASM_LLC llc PATHS ${WASM_ROOT}/bin NO_DEFAULT_PATH) 15 | find_program(WASM_LLVM_LINK llvm-link PATHS ${WASM_ROOT}/bin NO_DEFAULT_PATH) 16 | 17 | include(FindPackageHandleStandardArgs) 18 | # handle the QUIETLY and REQUIRED arguments and set EOS_FOUND to TRUE 19 | # if all listed variables are TRUE 20 | 21 | find_package_handle_standard_args(WASM REQUIRED_VARS WASM_CLANG WASM_LLC WASM_LLVM_LINK) 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 sim31 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 3 | 4 | # User-specific stuff 5 | .idea/**/workspace.xml 6 | .idea/**/tasks.xml 7 | .idea/**/dictionaries 8 | .idea/**/shelf 9 | 10 | # Sensitive or high-churn files 11 | .idea/**/dataSources/ 12 | .idea/**/dataSources.ids 13 | .idea/**/dataSources.local.xml 14 | .idea/**/sqlDataSources.xml 15 | .idea/**/dynamic.xml 16 | .idea/**/uiDesigner.xml 17 | 18 | # Gradle 19 | .idea/**/gradle.xml 20 | .idea/**/libraries 21 | 22 | # CMake 23 | build 24 | build-debug 25 | 26 | # Mongo Explorer plugin 27 | .idea/**/mongoSettings.xml 28 | 29 | # File-based project format 30 | *.iws 31 | 32 | # IntelliJ 33 | out/ 34 | 35 | # mpeltonen/sbt-idea plugin 36 | .idea_modules/ 37 | 38 | # JIRA plugin 39 | atlassian-ide-plugin.xml 40 | 41 | # Cursive Clojure plugin 42 | .idea/replstate.xml 43 | 44 | # Crashlytics plugin (for Android Studio and IntelliJ) 45 | com_crashlytics_export_strings.xml 46 | crashlytics.properties 47 | crashlytics-build.properties 48 | fabric.properties 49 | 50 | # Editor-based Rest Client 51 | .idea/httpRequests 52 | 53 | # Vim 54 | 55 | # Swap 56 | [._]*.s[a-v][a-z] 57 | [._]*.sw[a-p] 58 | [._]s[a-v][a-z] 59 | [._]sw[a-p] 60 | 61 | # Session 62 | Session.vim 63 | 64 | # Temporary 65 | .netrwhist 66 | *~ 67 | # Auto-generated tag files 68 | tags 69 | 70 | # Tests 71 | tests/nodeos/data 72 | tests/node_modules 73 | tests/.idea 74 | -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * @copyright defined in eos/LICENSE.txt 4 | */ 5 | #define BOOST_TEST_MODULE polleos-tests 6 | #define BOOST_TEST_DYN_LINK 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | //extern uint32_t EOS_TESTING_GENESIS_TIMESTAMP; 15 | 16 | void translate_fc_exception(const fc::exception &e) { 17 | std::cerr << "\033[33m" << e.to_detail_string() << "\033[0m" << std::endl; 18 | BOOST_TEST_FAIL("Caught Unexpected Exception"); 19 | } 20 | 21 | struct eosio_test_fixture { 22 | eosio_test_fixture() { 23 | // Turn off blockchain logging if no --verbose parameter is not added 24 | // To have verbose enabled, call "tests/chain_test -- --verbose" 25 | bool is_verbose = false; 26 | std::string verbose_arg = "--verbose"; 27 | int argc = boost::unit_test::framework::master_test_suite().argc; 28 | char** argv = boost::unit_test::framework::master_test_suite().argv; 29 | for (int i = 0; i < argc; i++) { 30 | if (verbose_arg == argv[i]) { 31 | is_verbose = true; 32 | break; 33 | } 34 | } 35 | if(!is_verbose) 36 | fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::off); 37 | 38 | // Register fc::exception translator 39 | boost::unit_test::unit_test_monitor.register_exception_translator 40 | (&translate_fc_exception); 41 | 42 | std::srand(time(NULL)); 43 | std::cout << "Random number generator seeded to " << time(NULL) << std::endl; 44 | } 45 | }; 46 | 47 | BOOST_TEST_GLOBAL_FIXTURE( eosio_test_fixture ); 48 | 49 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9) 2 | project(polleos CXX) 3 | 4 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules") 5 | 6 | set(BOOST_INCLUDEDIR $ENV{HOME}/opt/boost_1_67_0/include CACHE PATH "Path to boost instalation directory") 7 | 8 | set(EOSIO_INSTALL_DIR /usr/local CACHE PATH "Path to eosio intstall dir") 9 | set(S2WASM_PATH ${EOSIO_INSTALL_DIR}/bin/eosio-s2wasm) 10 | set(WAST2WASM_PATH ${EOSIO_INSTALL_DIR}/bin/eosio-wast2wasm) 11 | set(EOSIOCPP_PATH ${EOSIO_INSTALL_DIR}/bin/eosiocpp) 12 | set(EOSIO_CONTRACTSDK_PATH ${EOSIO_INSTALL_DIR}/usr/share/eosio/contractsdk/lib) 13 | 14 | include("wasm") 15 | 16 | set(DEFAULT_SYSTEM_INCLUDE_FOLDERS ${EOSIO_INSTALL_DIR}/include/libc++/upstream/include 17 | ${EOSIO_INSTALL_DIR}/include/musl/upstream/include ${BOOST_INCLUDEDIR}) 18 | set(EOSIO_LIBS ${EOSIO_CONTRACTSDK_PATH}/eosiolib.bc ${EOSIO_CONTRACTSDK_PATH}/libc++.bc 19 | ${EOSIO_CONTRACTSDK_PATH}/libc.bc) 20 | 21 | set(INCLUDE_DIRS "${EOSIO_INSTALL_DIR}/include" "${CMAKE_SOURCE_DIR}/include") 22 | 23 | #include_directories(include) 24 | #include_directories(${EOSIO_INSTALL_DIR}/include) 25 | #include_directories(${EOSIO_INSTALL_DIR}/include/libc++/upstream/include) 26 | #include_directories(${EOSIO_INSTALL_DIR}/include/musl/upstream/include) 27 | #include_directories(${BOOST_INCLUDE_DIR}) 28 | #include_directories(${EOSIO_TOKEN_INCLUDE_DIR}) 29 | 30 | set(CPP_FILES 31 | ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_PROJECT_NAME}.cpp) 32 | 33 | set(HPP_FILES 34 | ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_PROJECT_NAME}.hpp) 35 | 36 | #set(CONTRACT_ASSEMBLY_FILE ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.s) 37 | #set(CONTRACT_WAST_FILE ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.wast) 38 | 39 | 40 | add_wast_executable(TARGET ${CMAKE_PROJECT_NAME} 41 | INCLUDE_FOLDERS "${INCLUDE_DIRS}" 42 | LIBRARIES ${EOSIO_LIBS} 43 | DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} 44 | SOURCE_FILES ${CPP_FILES}) 45 | 46 | 47 | set(CONTRACT_ABI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_PROJECT_NAME}.abi) 48 | 49 | configure_file("${CONTRACT_ABI_SRC}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) 50 | 51 | add_subdirectory(tests) 52 | -------------------------------------------------------------------------------- /eosio.token.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * @copyright defined in eos/LICENSE.txt 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace eosiosystem { 13 | class system_contract; 14 | } 15 | 16 | namespace eosio { 17 | 18 | using std::string; 19 | 20 | class token : public contract { 21 | public: 22 | token( account_name self ):contract(self){} 23 | 24 | void create( account_name issuer, 25 | asset maximum_supply); 26 | 27 | void issue( account_name to, asset quantity, string memo ); 28 | 29 | void transfer( account_name from, 30 | account_name to, 31 | asset quantity, 32 | string memo ); 33 | 34 | 35 | inline bool exists( symbol_name sym)const; 36 | 37 | inline asset get_supply( symbol_name sym )const; 38 | 39 | inline asset get_balance( account_name owner, symbol_name sym )const; 40 | 41 | private: 42 | 43 | friend eosiosystem::system_contract; 44 | 45 | private: 46 | struct account { 47 | asset balance; 48 | 49 | uint64_t primary_key()const { return balance.symbol.name(); } 50 | }; 51 | 52 | struct currency_stats { 53 | asset supply; 54 | asset max_supply; 55 | account_name issuer; 56 | 57 | uint64_t primary_key()const { return supply.symbol.name(); } 58 | }; 59 | 60 | typedef eosio::multi_index accounts; 61 | typedef eosio::multi_index stats; 62 | 63 | void sub_balance( account_name owner, asset value ); 64 | void add_balance( account_name owner, asset value, account_name ram_payer ); 65 | 66 | public: 67 | struct transfer_args { 68 | account_name from; 69 | account_name to; 70 | asset quantity; 71 | string memo; 72 | }; 73 | }; 74 | 75 | asset token::get_supply( symbol_name sym )const { 76 | 77 | stats statstable( _self, sym ); 78 | const auto& st = statstable.get( sym, "This token does not exist" ); 79 | return st.supply; 80 | } 81 | 82 | asset token::get_balance( account_name owner, symbol_name sym )const { 83 | 84 | accounts accountstable( _self, owner ); 85 | const auto& ac = accountstable.get( sym, "This account does not have any balance" ); 86 | return ac.balance; 87 | } 88 | 89 | bool token::exists(symbol_name sym)const { 90 | 91 | stats st(_self, sym); 92 | return st.find(sym) != st.end(); 93 | } 94 | 95 | } /// namespace eosio 96 | -------------------------------------------------------------------------------- /tests/polleos_tests.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | using namespace eosio; 18 | using namespace eosio::chain; 19 | using namespace eosio::testing; 20 | using namespace fc; 21 | using namespace std; 22 | 23 | using mvo = fc::mutable_variant_object; 24 | 25 | class polleos_tester : public tester { 26 | public: 27 | typedef uint64_t poll_id; 28 | typedef std::vector option_names; 29 | typedef extended_symbol token_info; 30 | typedef vector option_results; 31 | 32 | polleos_tester() { 33 | 34 | produce_blocks(2); 35 | 36 | create_accounts({N(alice), N(bob), N(carol), contract_name}); 37 | produce_blocks(2); 38 | 39 | set_code(contract_name, polleos_wast); 40 | set_abi(contract_name, polleos_abi); 41 | 42 | produce_blocks(); 43 | 44 | const auto& accnt = control->db().get(N(polleos)); 45 | abi_def abi; 46 | BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); 47 | abi_ser.set_abi(abi); 48 | } 49 | 50 | action_result push_action( const account_name& signer, const action_name &name, const variant_object &data ) { 51 | string action_type_name = abi_ser.get_action_type(name); 52 | 53 | action act; 54 | act.account = contract_name; 55 | act.name = name; 56 | act.data = abi_ser.variant_to_binary( action_type_name, data ); 57 | 58 | return base_tester::push_action( std::move(act), uint64_t(signer)); 59 | } 60 | 61 | action_result newpoll(string question, account_name owner, option_names options) { 62 | 63 | return push_action( owner, N(newpoll), mvo() 64 | ( "question", question) 65 | ( "creator", owner) 66 | ( "options", options ) 67 | ); 68 | } 69 | 70 | fc::variant get_poll( poll_id id ) { 71 | 72 | auto data = get_row_by_account( contract_name, contract_name, N(poll), id); 73 | return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "poll", data ); 74 | } 75 | 76 | 77 | const account_name contract_name = N(polleos); 78 | private: 79 | 80 | abi_serializer abi_ser; 81 | }; 82 | 83 | BOOST_AUTO_TEST_SUITE( polleos_tests ) 84 | 85 | BOOST_FIXTURE_TEST_CASE( create_poll, polleos_tester ) try { 86 | 87 | string question = "Q1"; 88 | option_names options {"opt1", "opt2", "opt3"}; 89 | option_results results { mvo("name", "opt1")("votes", 0.0), 90 | mvo("name", "opt2")("votes", 0.0), 91 | mvo("name", "opt3")("votes", 0.0) }; 92 | 93 | 94 | newpoll(question, N(alice), options); 95 | produce_blocks(1); 96 | 97 | variant created_poll = get_poll(0); 98 | 99 | variant required_poll = mvo() 100 | ("question", question) 101 | ("results", results) 102 | ("is_token_poll", false); 103 | 104 | cout << "Created poll: " << created_poll << endl; 105 | cout << "Expected poll: " << required_poll << endl; 106 | 107 | REQUIRE_MATCHING_OBJECT(required_poll, created_poll); 108 | } FC_LOG_AND_RETHROW() 109 | 110 | BOOST_AUTO_TEST_SUITE_END() 111 | 112 | -------------------------------------------------------------------------------- /polleos.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "eosio.token.hpp" 6 | 7 | class polleos : public eosio::contract { 8 | public: 9 | typedef uint64_t poll_id_t; 10 | typedef std::vector option_names_t; 11 | typedef eosio::extended_symbol token_info_t; 12 | typedef uint8_t option_id_t; 13 | 14 | polleos(account_name contract_name) : eosio::contract(contract_name), 15 | _polls(contract_name, contract_name) {} 16 | 17 | struct option { 18 | std::string name; 19 | 20 | option(std::string name) : name(name) {} 21 | 22 | option() {} 23 | 24 | EOSLIB_SERIALIZE(option, (name)) 25 | }; 26 | 27 | struct option_result : option { 28 | double votes = 0; 29 | 30 | option_result(const std::string& name, uint64_t votes) : option(name), 31 | votes(votes) {} 32 | 33 | option_result(const std::string& name) : option_result(name, 0) {} 34 | 35 | option_result() {} 36 | 37 | EOSLIB_SERIALIZE(option_result, (name)(votes)) 38 | }; 39 | 40 | typedef std::vector option_results; 41 | 42 | //@abi table 43 | struct poll { 44 | poll_id_t id; 45 | std::string question; 46 | option_results results; 47 | bool is_token_poll = false; 48 | token_info_t token; 49 | 50 | uint64_t primary_key() const { 51 | 52 | return id; 53 | } 54 | 55 | uint64_t get_reverse_key() const { 56 | 57 | return ~id; 58 | } 59 | 60 | void set(poll_id_t id, const std::string& question, 61 | const option_names_t& options, bool is_token_poll, 62 | token_info_t token); 63 | 64 | EOSLIB_SERIALIZE(poll, (id)(question)(results)(is_token_poll)(token)) 65 | }; 66 | 67 | //@abi table votes 68 | struct poll_vote { 69 | poll_id_t poll_id; 70 | option_id_t option_id; 71 | 72 | uint64_t primary_key() const { 73 | 74 | return poll_id; 75 | } 76 | 77 | EOSLIB_SERIALIZE(poll_vote, (poll_id)(option_id)) 78 | }; 79 | 80 | typedef eosio::multi_index 82 | > > poll_table; 83 | 84 | typedef eosio::multi_index vote_table; 85 | 86 | //@abi action 87 | void newpoll(const std::string& question, account_name creator, 88 | const std::vector& options); 89 | 90 | //@abi action 91 | void newtokenpoll(const std::string& question, account_name payer, 92 | const std::vector& options, 93 | token_info_t token); 94 | 95 | //@abi action 96 | void vote(poll_id_t id, account_name voter, option_id_t option_id); 97 | 98 | 99 | private: 100 | void store_poll(const std::string& question, account_name owner, 101 | const option_names_t& options, 102 | bool is_token_poll, token_info_t token); 103 | 104 | void store_vote(const poll& p, vote_table& votes, option_id_t option_id, 105 | double weight); 106 | 107 | void store_token_vote(const poll& p, vote_table& votes, option_id_t option_id); 108 | 109 | double to_weight(const eosio::asset& stake) { 110 | 111 | return stake.amount / std::pow(10, stake.symbol.precision()); 112 | } 113 | 114 | poll_table _polls; 115 | }; 116 | -------------------------------------------------------------------------------- /polleos.abi: -------------------------------------------------------------------------------- 1 | { 2 | "types": [{ 3 | "new_type_name": "poll_id_t", 4 | "type": "uint64" 5 | },{ 6 | "new_type_name": "option_results", 7 | "type": "option_result[]" 8 | },{ 9 | "new_type_name": "token_info_t", 10 | "type": "extended_symbol" 11 | },{ 12 | "new_type_name": "symbol_name", 13 | "type": "symbol" 14 | } 15 | ], 16 | "structs": [{ 17 | "name": "option", 18 | "base": "", 19 | "fields": [{ 20 | "name": "name", 21 | "type": "string" 22 | } 23 | ] 24 | },{ 25 | "name": "option_result", 26 | "base": "option", 27 | "fields": [{ 28 | "name": "votes", 29 | "type": "float64" 30 | } 31 | ] 32 | },{ 33 | "name": "symbol_type", 34 | "base": "", 35 | "fields": [{ 36 | "name": "value", 37 | "type": "symbol_name" 38 | } 39 | ] 40 | },{ 41 | "name": "extended_symbol", 42 | "base": "symbol_type", 43 | "fields": [{ 44 | "name": "contract", 45 | "type": "name" 46 | } 47 | ] 48 | },{ 49 | "name": "poll", 50 | "base": "", 51 | "fields": [{ 52 | "name": "id", 53 | "type": "poll_id_t" 54 | },{ 55 | "name": "question", 56 | "type": "string" 57 | },{ 58 | "name": "results", 59 | "type": "option_results" 60 | },{ 61 | "name": "is_token_poll", 62 | "type": "bool" 63 | },{ 64 | "name": "token", 65 | "type": "token_info_t" 66 | } 67 | ] 68 | },{ 69 | "name": "poll_vote", 70 | "base": "", 71 | "fields": [{ 72 | "name": "pollid", 73 | "type": "poll_id_t" 74 | },{ 75 | "name": "optionid", 76 | "type": "uint8" 77 | } 78 | ] 79 | },{ 80 | "name": "newpoll", 81 | "base": "", 82 | "fields": [{ 83 | "name": "question", 84 | "type": "string" 85 | },{ 86 | "name": "creator", 87 | "type": "name" 88 | },{ 89 | "name": "options", 90 | "type": "string[]" 91 | } 92 | ] 93 | },{ 94 | "name": "newtokenpoll", 95 | "base": "", 96 | "fields": [{ 97 | "name": "question", 98 | "type": "string" 99 | },{ 100 | "name": "creator", 101 | "type": "name" 102 | },{ 103 | "name": "options", 104 | "type": "string[]" 105 | },{ 106 | "name": "token", 107 | "type": "token_info_t" 108 | } 109 | ] 110 | },{ 111 | "name": "vote", 112 | "base": "", 113 | "fields": [{ 114 | "name": "id", 115 | "type": "poll_id_t" 116 | },{ 117 | "name": "voter", 118 | "type": "name" 119 | },{ 120 | "name": "option_id", 121 | "type": "uint8" 122 | } 123 | ] 124 | } 125 | ], 126 | "actions": [{ 127 | "name": "newpoll", 128 | "type": "newpoll", 129 | "ricardian_contract": "" 130 | },{ 131 | "name": "newtokenpoll", 132 | "type": "newtokenpoll", 133 | "ricardian_contract": "" 134 | },{ 135 | "name": "vote", 136 | "type": "vote", 137 | "ricardian_contract": "" 138 | } 139 | ], 140 | "tables": [{ 141 | "name": "poll", 142 | "index_type": "i64", 143 | "key_names": [ 144 | "id" 145 | ], 146 | "key_types": [ 147 | "poll_id_t" 148 | ], 149 | "type": "poll" 150 | },{ 151 | "name": "votes", 152 | "index_type": "i64", 153 | "key_names": [ 154 | "id" 155 | ], 156 | "key_types": [ 157 | "poll_id_t" 158 | ], 159 | "type": "poll_vote" 160 | } 161 | ], 162 | "ricardian_clauses": [] 163 | } -------------------------------------------------------------------------------- /polleos.cpp: -------------------------------------------------------------------------------- 1 | #include "polleos.hpp" 2 | #include 3 | 4 | void polleos::poll::set(polleos::poll_id_t id, const std::string& question, 5 | const option_names_t& options, bool is_token_poll, 6 | token_info_t token) { 7 | 8 | eosio_assert(!question.empty(), "Question can't be empty"); 9 | 10 | this->id = id; 11 | this->question = question; 12 | this->is_token_poll = is_token_poll; 13 | this->token = token; 14 | 15 | results.resize(options.size()); 16 | std::transform(options.begin(), options.end(), results.begin(), 17 | [&](std::string str) { 18 | eosio_assert(!str.empty(), "Option names can't be empty"); 19 | return option_result(str); 20 | }); 21 | } 22 | 23 | void polleos::store_poll(const std::string& question, account_name poll_owner, 24 | const option_names_t& options, 25 | bool is_token_poll, token_info_t token) { 26 | 27 | poll_id_t id; 28 | 29 | eosio_assert(options.size() < std::numeric_limits::max(), 30 | "Too many options"); 31 | 32 | _polls.emplace(poll_owner, [&](poll& p) { 33 | id = _polls.available_primary_key(); 34 | p.set(id, question, options, is_token_poll, token); 35 | }); 36 | 37 | eosio::print("Poll stored with id: ", id); 38 | } 39 | 40 | void polleos::store_vote(const polleos::poll& p, polleos::vote_table& votes, 41 | option_id_t option_id, double weight) { 42 | 43 | eosio_assert(weight > 0, "Vote weight cannot be less than 0. Contract logic issue"); 44 | 45 | // Voter (votes.get_scope()) pays 46 | votes.emplace(votes.get_scope(), [&](poll_vote& v) { 47 | v.poll_id = p.id; 48 | v.option_id = option_id; 49 | }); 50 | 51 | _polls.modify(p, votes.get_scope(), [&](poll& p) { 52 | p.results[option_id].votes += weight; 53 | }); 54 | } 55 | 56 | void polleos::store_token_vote(const polleos::poll& p, polleos::vote_table& votes, 57 | option_id_t option_id) { 58 | 59 | account_name voter = votes.get_scope(); 60 | 61 | eosio::token token(p.token.contract); 62 | // Should fail if voter is not a stakeholder 63 | eosio::asset balance = token.get_balance(voter, p.token.name()); 64 | // Some additional checks 65 | eosio_assert(balance.is_valid(), "Balance of voter account is invalid. Something" 66 | " wrong with token contract."); 67 | eosio_assert(balance.amount > 0, 68 | "Voter has to have more than 0 of tokens to participate in a poll!"); 69 | 70 | store_vote(p, votes, option_id, to_weight(balance)); 71 | } 72 | 73 | void polleos::newpoll(const std::string& question, account_name payer, 74 | const option_names_t& options) { 75 | 76 | store_poll(question, payer, options, false, token_info_t()); 77 | } 78 | 79 | void polleos::newtokenpoll(const std::string& question, account_name owner, 80 | const option_names_t& options, token_info_t token_inf) { 81 | 82 | eosio::token token(token_inf.contract); 83 | eosio_assert(token.exists(token_inf.name()), "This token does not exist"); 84 | store_poll(question, owner, options, true, token_inf); 85 | } 86 | 87 | void polleos::vote(polleos::poll_id_t id, account_name voter, option_id_t option_id) { 88 | 89 | eosio::require_auth(voter); 90 | 91 | const poll & p = _polls.get(id, "Poll with this id does not exist"); 92 | 93 | eosio_assert(option_id < p.results.size(), 94 | "Option with this id does not exist"); 95 | 96 | vote_table votes(get_self(), voter); 97 | eosio_assert(votes.find(p.id) == votes.end(), "This account has already " 98 | "voted in this poll"); 99 | 100 | if (p.is_token_poll) 101 | store_token_vote(p, votes, option_id); 102 | else 103 | store_vote(p, votes, option_id, 1); 104 | 105 | eosio::print("Vote stored!"); 106 | } 107 | 108 | EOSIO_ABI(polleos, (newpoll)(newtokenpoll)(vote)) 109 | 110 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #file(GLOB COMMON_SOURCES "common/*.cpp") 2 | 3 | #find_package( Gperftools QUIET ) 4 | #if( GPERFTOOLS_FOUND ) 5 | # message( STATUS "Found gperftools; compiling tests with TCMalloc") 6 | # list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc ) 7 | #endif() 8 | 9 | set(EOSIO_SRC_DIR "" CACHE PATH "Path to eosio source directory") 10 | set(EOSIO_BUILD_DIR "" CACHE PATH "Path to eosio build directory") 11 | set(BOOST_INCLUDEDIR $ENV{HOME}/opt/boost_1_66_0/include CACHE PATH "Path to boost instalation directory") 12 | 13 | # FIXME: not all might be needed 14 | set(EOSIO_LIB_BUILD_DIR "${EOSIO_BUILD_DIR}/libraries") 15 | set(EOSIO_CHAIN_LIB "${EOSIO_LIB_BUILD_DIR}/chain/libeosio_chain.a") 16 | set(EOSIO_CHAINBASE_LIB "${EOSIO_LIB_BUILD_DIR}/chainbase/libchainbase.a") 17 | set(EOSIO_TESTING_LIB "${EOSIO_LIB_BUILD_DIR}/testing/libeosio_testing.a") 18 | set(EOSIO_UTILITIES_LIB "${EOSIO_LIB_BUILD_DIR}/utilities/libeos_utilities.a") 19 | set(EOSIO_FC_LIB "${EOSIO_LIB_BUILD_DIR}/fc/libfc_debug.a") 20 | 21 | message("Lib: ${EOSIO_CHAIN_LIB} ${EOSIO_CHAINBASE_LIB} ${EOSIO_TESTING_LIB} 22 | ${EOSIO_UTILITIES_LIB} ${EOSIO_FC_LIB}") 23 | 24 | add_library(eosio_chain STATIC IMPORTED) 25 | set_target_properties(eosio_chain PROPERTIES IMPORTED_LOCATION "${EOSIO_CHAIN_LIB}") 26 | 27 | add_library(chainbase STATIC IMPORTED) 28 | set_target_properties(chainbase PROPERTIES IMPORTED_LOCATION "${EOSIO_CHAINBASE_LIB}") 29 | 30 | add_library(testing STATIC IMPORTED) 31 | set_target_properties(testing PROPERTIES IMPORTED_LOCATION "${EOSIO_TESTING_LIB}") 32 | 33 | add_library(utilities STATIC IMPORTED) 34 | set_target_properties(utilities PROPERTIES IMPORTED_LOCATION "${EOSIO_UTILITIES_LIB}") 35 | 36 | add_library(fc STATIC IMPORTED) 37 | set_target_properties(fc PROPERTIES IMPORTED_LOCATION "${EOSIO_FC_LIB}") 38 | 39 | add_library(binaryen STATIC IMPORTED) 40 | set_target_properties(binaryen PROPERTIES IMPORTED_LOCATION 41 | "${EOSIO_BUILD_DIR}/externals/binaryen/lib/libbinaryen.a") 42 | 43 | add_library(binaryen_support STATIC IMPORTED) 44 | set_target_properties(binaryen_support PROPERTIES IMPORTED_LOCATION 45 | "${EOSIO_BUILD_DIR}/externals/binaryen/lib/libsupport.a") 46 | 47 | add_library(binaryen_wasm STATIC IMPORTED) 48 | set_target_properties(binaryen_wasm PROPERTIES IMPORTED_LOCATION 49 | "${EOSIO_BUILD_DIR}/externals/binaryen/lib/libwasm.a") 50 | 51 | add_library(binaryen_cfg STATIC IMPORTED) 52 | set_target_properties(binaryen_cfg PROPERTIES IMPORTED_LOCATION 53 | "${EOSIO_BUILD_DIR}/externals/binaryen/lib/libcfg.a") 54 | 55 | add_library(binaryen_passes STATIC IMPORTED) 56 | set_target_properties(binaryen_passes PROPERTIES IMPORTED_LOCATION 57 | "${EOSIO_BUILD_DIR}/externals/binaryen/lib/libpasses.a") 58 | 59 | add_library(binaryen_asmjs STATIC IMPORTED) 60 | set_target_properties(binaryen_asmjs PROPERTIES IMPORTED_LOCATION 61 | "${EOSIO_BUILD_DIR}/externals/binaryen/lib/libasmjs.a") 62 | 63 | add_library(wasmjit_wasm STATIC IMPORTED) 64 | set_target_properties(wasmjit_wasm PROPERTIES IMPORTED_LOCATION 65 | "${EOSIO_BUILD_DIR}/libraries/wasm-jit/Source/WASM/libWASM.a") 66 | 67 | add_library(wasmjit_wast STATIC IMPORTED) 68 | set_target_properties(wasmjit_wast PROPERTIES IMPORTED_LOCATION 69 | "${EOSIO_BUILD_DIR}/libraries/wasm-jit/Source/WAST/libWAST.a") 70 | 71 | add_library(wasmjit_ir STATIC IMPORTED) 72 | set_target_properties(wasmjit_ir PROPERTIES IMPORTED_LOCATION 73 | "${EOSIO_BUILD_DIR}/libraries/wasm-jit/Source/IR/libIR.a") 74 | 75 | add_library(wasmjit_runtime STATIC IMPORTED) 76 | set_target_properties(wasmjit_runtime PROPERTIES IMPORTED_LOCATION 77 | "${EOSIO_BUILD_DIR}/libraries/wasm-jit/Source/Runtime/libRuntime.a") 78 | 79 | add_library(wasmjit_platform STATIC IMPORTED) 80 | set_target_properties(wasmjit_platform PROPERTIES IMPORTED_LOCATION 81 | "${EOSIO_BUILD_DIR}/libraries/wasm-jit/Source/Platform/libPlatform.a") 82 | 83 | add_library(wasmjit_logging STATIC IMPORTED) 84 | set_target_properties(wasmjit_logging PROPERTIES IMPORTED_LOCATION 85 | "${EOSIO_BUILD_DIR}/libraries/wasm-jit/Source/Logging/libLogging.a") 86 | 87 | add_library(builtins STATIC IMPORTED) 88 | set_target_properties(builtins PROPERTIES IMPORTED_LOCATION 89 | "${EOSIO_BUILD_DIR}/libraries/builtins/libbuiltins.a") 90 | 91 | add_library(softfloat STATIC IMPORTED) 92 | set_target_properties(softfloat PROPERTIES IMPORTED_LOCATION 93 | "${EOSIO_BUILD_DIR}/libraries/softfloat/libsoftfloat.a") 94 | 95 | 96 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${EOSIO_SRC_DIR}/libraries/fc/CMakeModules") 97 | find_package(LLVM 4.0 REQUIRED CONFIG) 98 | find_package(Secp256k1 REQUIRED) 99 | find_package(GMP REQUIRED) 100 | find_package(OpenSSL REQUIRED) 101 | 102 | find_package(Boost 1.67 REQUIRED COMPONENTS 103 | thread 104 | date_time 105 | filesystem 106 | system 107 | program_options 108 | signals 109 | serialization 110 | chrono 111 | unit_test_framework 112 | context 113 | locale 114 | iostreams) 115 | 116 | llvm_map_components_to_libnames(LLVM_LIBS support core passes mcjit native DebugInfoDWARF) 117 | link_directories(${LLVM_LIBRARY_DIR}) 118 | 119 | include_directories("${CMAKE_BINARY_DIR}") # For *.wast.hpp and *.abi.hpp 120 | include_directories("${CMAKE_SOURCE_DIR}/") 121 | include_directories("${EOSIO_SRC_DIR}/libraries/testing/include") 122 | include_directories("${EOSIO_SRC_DIR}/libraries/chain/include/") 123 | include_directories("${EOSIO_SRC_DIR}/libraries/fc/include/") 124 | include_directories("${EOSIO_SRC_DIR}/libraries/chainbase/include/") 125 | include_directories("${EOSIO_SRC_DIR}/libraries/utilities/include/") 126 | include_directories("${EOSIO_SRC_DIR}/libraries/wasm-jit/Include/") 127 | include_directories("${EOSIO_SRC_DIR}/libraries/softfloat/source/include") 128 | include_directories("${EOSIO_BUILD_DIR}/libraries/chain/include") 129 | include_directories("${EOSIO_BUILD_DIR}/contracts/") # For eosio.token.wast.hpp and abi 130 | include_directories("${BOOST_INCLUDEDIR}") 131 | 132 | #configure_file(${EOSIO_SRC_DIR}/include/config.hpp.in 133 | # ${CMAKE_CURRENT_BINARY_DIR}/include/config.hpp ESCAPE_QUOTES) 134 | 135 | file(GLOB UNIT_TESTS "*.cpp") 136 | 137 | #add_executable( polleos-tests ${UNIT_TESTS} ${WASM_UNIT_TESTS} ) 138 | add_executable( polleos-tests ${UNIT_TESTS}) 139 | #target_link_libraries( polleos-tests eosio_chain chainbase eosio_testing eos_utilities 140 | # abi_generator fc ${PLATFORM_SPECIFIC_LIBS} ) 141 | target_link_libraries( polleos-tests testing eosio_chain chainbase utilities fc 142 | ${OPENSSL_LIBRARIES} ${Secp256k1_LIBRARY} ${GMP_LIBRARIES} ${Boost_LIBRARIES} 143 | binaryen_wasm binaryen_support binaryen_cfg binaryen binaryen_passes 144 | binaryen_asmjs wasmjit_wasm wasmjit_wast wasmjit_ir wasmjit_runtime 145 | wasmjit_platform wasmjit_logging builtins softfloat ${LLVM_LIBS} -lpthread) 146 | 147 | #target_include_directories( unit_test PUBLIC ${CMAKE_BINARY_DIR}/contracts ${CMAKE_CURRENT_BINARY_DIR}/tests/contracts ) 148 | #target_include_directories( unit_test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/wasm_tests ) 149 | #target_include_directories( unit_test PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include ) 150 | #add_dependencies(unit_test asserter test_api test_api_mem test_api_db test_ram_limit test_api_multi_index exchange eosio.token proxy identity identity_test stltest infinite eosio.system eosio.token eosio.bios test.inline multi_index_test noop dice eosio.msig payloadless tic_tac_toe) 151 | 152 | #Manually run unit_test for all supported runtimes 153 | #To run unit_test with all log from blockchain displayed, put --verbose after --, i.e. unit_test -- --verbose 154 | #add_test(NAME unit_test_binaryen COMMAND unit_test 155 | # -t \!wasm_tests/weighted_cpu_limit_tests 156 | # --report_level=detailed --color_output -- --binaryen) 157 | #add_test(NAME unit_test_wavm COMMAND unit_test 158 | # -t \!wasm_tests/weighted_cpu_limit_tests 159 | # --report_level=detailed --color_output --catch_system_errors=no -- --wavm) 160 | 161 | if(ENABLE_COVERAGE_TESTING) 162 | 163 | set(Coverage_NAME ${PROJECT_NAME}_ut_coverage) 164 | 165 | if(NOT LCOV_PATH) 166 | message(FATAL_ERROR "lcov not found! Aborting...") 167 | endif() # NOT LCOV_PATH 168 | 169 | if(NOT LLVMCOV_PATH) 170 | message(FATAL_ERROR "llvm-cov not found! Aborting...") 171 | endif() # NOT LCOV_PATH 172 | 173 | if(NOT GENHTML_PATH) 174 | message(FATAL_ERROR "genhtml not found! Aborting...") 175 | endif() # NOT GENHTML_PATH 176 | 177 | # no spaces allowed within tests list 178 | set(ctest_tests 'unit_test_binaryen|unit_test_wavm') 179 | set(ctest_exclude_tests '') 180 | 181 | # Setup target 182 | add_custom_target(${Coverage_NAME} 183 | 184 | # Cleanup lcov 185 | COMMAND ${LCOV_PATH} --directory . --zerocounters 186 | 187 | # Run tests 188 | COMMAND ./tools/ctestwrapper.sh -R ${ctest_tests} -E ${ctest_exclude_tests} 189 | 190 | COMMAND ${LCOV_PATH} --directory . --capture --gcov-tool ./tools/llvm-gcov.sh --output-file ${Coverage_NAME}.info 191 | 192 | COMMAND ${LCOV_PATH} -remove ${Coverage_NAME}.info '*/boost/*' '/usr/lib/*' '/usr/include/*' '*/externals/*' '*/fc/*' '*/wasm-jit/*' --output-file ${Coverage_NAME}_filtered.info 193 | 194 | COMMAND ${GENHTML_PATH} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}_filtered.info 195 | 196 | COMMAND if [ "$CI" != "true" ]\; then ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.info ${Coverage_NAME}_filtered.info ${Coverage_NAME}.total ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned ${PROJECT_BINARY_DIR}/${Coverage_NAME}_filtered.info.cleaned\; fi 197 | 198 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 199 | COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report. Report published in ./${Coverage_NAME}" 200 | ) 201 | 202 | # Show info where to find the report 203 | add_custom_command(TARGET ${Coverage_NAME} POST_BUILD 204 | COMMAND ; 205 | COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." 206 | ) 207 | endif() 208 | -------------------------------------------------------------------------------- /CMakeModules/wasm.cmake: -------------------------------------------------------------------------------- 1 | find_package(Wasm) 2 | 3 | if(WASM_FOUND) 4 | message(STATUS "Using WASM clang => " ${WASM_CLANG}) 5 | message(STATUS "Using WASM llc => " ${WASM_LLC}) 6 | message(STATUS "Using WASM llvm-link => " ${WASM_LLVM_LINK}) 7 | else() 8 | message( FATAL_ERROR "No WASM compiler cound be found (make sure WASM_ROOT is set)" ) 9 | return() 10 | endif() 11 | macro(compile_wast) 12 | #read arguments include ones that we don't since arguments get forwared "as is" and we don't want to threat unknown argument names as values 13 | cmake_parse_arguments(ARG "NOWARNINGS" "TARGET;DESTINATION_FOLDER" "SOURCE_FILES;INCLUDE_FOLDERS;SYSTEM_INCLUDE_FOLDERS;LIBRARIES" ${ARGN}) 14 | set(target ${ARG_TARGET}) 15 | 16 | # NOTE: Setting SOURCE_FILE and looping over it to avoid cmake issue with compilation ${target}.bc's rule colliding with 17 | # linking ${target}.bc's rule 18 | if ("${ARG_SOURCE_FILES}" STREQUAL "") 19 | set(SOURCE_FILES ${target}.cpp) 20 | else() 21 | set(SOURCE_FILES ${ARG_SOURCE_FILES}) 22 | endif() 23 | set(outfiles "") 24 | foreach(srcfile ${SOURCE_FILES}) 25 | 26 | get_filename_component(outfile ${srcfile} NAME) 27 | get_filename_component(extension ${srcfile} EXT) 28 | get_filename_component(infile ${srcfile} ABSOLUTE) 29 | 30 | # -ffreestanding 31 | # Assert that compilation targets a freestanding environment. 32 | # This implies -fno-builtin. A freestanding environment is one in which the standard library may not exist, and program startup may not necessarily be at main. 33 | # The most obvious example is an OS kernel. 34 | 35 | # -nostdlib 36 | # Do not use the standard system startup files or libraries when linking. 37 | # No startup files and only the libraries you specify are passed to the linker, and options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored. 38 | # The compiler may generate calls to memcmp, memset, memcpy and memmove. 39 | # These entries are usually resolved by entries in libc. These entry points should be supplied through some other mechanism when this option is specified. 40 | 41 | # -fno-threadsafe-statics 42 | # Do not emit the extra code to use the routines specified in the C++ ABI for thread-safe initialization of local statics. 43 | # You can use this option to reduce code size slightly in code that doesn’t need to be thread-safe. 44 | 45 | # -fno-rtti 46 | # Disable generation of information about every class with virtual functions for use by the C++ run-time type identification features (dynamic_cast and typeid). 47 | 48 | # -fno-exceptions 49 | # Disable the generation of extra code needed to propagate exceptions 50 | if ("${extension}" STREQUAL ".c") 51 | set(STDFLAG -D_XOPEN_SOURCE=700) 52 | else() 53 | set(STDFLAG "--std=c++14") 54 | endif() 55 | 56 | set(WASM_COMMAND ${WASM_CLANG} -emit-llvm -O3 ${STDFLAG} --target=wasm32 -ffreestanding 57 | -nostdlib -nostdlibinc -fno-threadsafe-statics -fno-rtti -fno-exceptions 58 | -c ${infile} -o ${outfile}.bc 59 | ) 60 | if (${ARG_NOWARNINGS}) 61 | list(APPEND WASM_COMMAND -Wno-everything) 62 | else() 63 | list(APPEND WASM_COMMAND -Weverything -Wno-c++98-compat -Wno-old-style-cast -Wno-vla -Wno-vla-extension -Wno-c++98-compat-pedantic 64 | -Wno-missing-prototypes -Wno-missing-variable-declarations -Wno-packed -Wno-padded -Wno-c99-extensions -Wno-documentation-unknown-command) 65 | endif() 66 | 67 | foreach(folder ${ARG_INCLUDE_FOLDERS}) 68 | list(APPEND WASM_COMMAND -I ${folder}) 69 | endforeach() 70 | 71 | if ("${ARG_SYSTEM_INCLUDE_FOLDERS}" STREQUAL "") 72 | set (ARG_SYSTEM_INCLUDE_FOLDERS ${DEFAULT_SYSTEM_INCLUDE_FOLDERS}) 73 | endif() 74 | foreach(folder ${ARG_SYSTEM_INCLUDE_FOLDERS}) 75 | list(APPEND WASM_COMMAND -isystem ${folder}) 76 | endforeach() 77 | 78 | foreach(folder ${ARG_SYSTEM_INCLUDE_FOLDERS}) 79 | list(APPEND WASM_COMMAND -isystem ${folder}) 80 | endforeach() 81 | 82 | add_custom_command(OUTPUT ${outfile}.bc 83 | DEPENDS ${infile} 84 | COMMAND ${WASM_COMMAND} 85 | IMPLICIT_DEPENDS CXX ${infile} 86 | COMMENT "Building LLVM bitcode ${outfile}.bc" 87 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 88 | VERBATIM 89 | ) 90 | set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${outfile}.bc) 91 | list(APPEND outfiles ${outfile}.bc) 92 | 93 | endforeach(srcfile) 94 | 95 | set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.bc) 96 | 97 | endmacro(compile_wast) 98 | 99 | macro(add_wast_library) 100 | cmake_parse_arguments(ARG "NOWARNINGS" "TARGET;DESTINATION_FOLDER" "SOURCE_FILES;INCLUDE_FOLDERS;SYSTEM_INCLUDE_FOLDERS" ${ARGN}) 101 | set(target ${ARG_TARGET}) 102 | compile_wast(${ARGV}) 103 | 104 | get_filename_component("${ARG_TARGET}_BC_FILENAME" "${ARG_DESTINATION_FOLDER}/${ARG_TARGET}.bc" ABSOLUTE CACHE) 105 | add_custom_target(${target} ALL DEPENDS ${${ARG_TARGET}_BC_FILENAME}) 106 | 107 | add_custom_command(OUTPUT ${${ARG_TARGET}_BC_FILENAME} 108 | DEPENDS ${outfiles} 109 | COMMAND ${WASM_LLVM_LINK} -o ${${ARG_TARGET}_BC_FILENAME} ${outfiles} 110 | COMMENT "Linking LLVM bitcode library ${target}.bc" 111 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 112 | VERBATIM 113 | ) 114 | #TODO: Fix this path on pending cmake install changes 115 | install(FILES ${${ARG_TARGET}_BC_FILENAME} DESTINATION usr/share/eosio/contractsdk/lib) 116 | 117 | endmacro(add_wast_library) 118 | 119 | macro(add_wast_executable) 120 | cmake_parse_arguments(ARG "NOWARNINGS" "TARGET;DESTINATION_FOLDER;MAX_MEMORY" "SOURCE_FILES;INCLUDE_FOLDERS;SYSTEM_INCLUDE_FOLDERS;LIBRARIES" ${ARGN}) 121 | set(target ${ARG_TARGET}) 122 | set(DESTINATION_FOLDER ${ARG_DESTINATION_FOLDER}) 123 | 124 | compile_wast(${ARGV}) 125 | 126 | foreach(lib ${ARG_LIBRARIES}) 127 | list(APPEND LIBRARIES ${lib}) 128 | endforeach() 129 | 130 | message("${LIBRARIES}") 131 | 132 | add_custom_command(OUTPUT ${target}.bc 133 | DEPENDS ${outfiles} ${ARG_LIBRARIES} ${LIBRARIES} 134 | COMMAND ${WASM_LLVM_LINK} -only-needed -o ${target}.bc ${outfiles} ${LIBRARIES} 135 | COMMENT "Linking LLVM bitcode executable ${target}.bc" 136 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 137 | VERBATIM 138 | ) 139 | 140 | set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.bc) 141 | 142 | add_custom_command(OUTPUT ${target}.s 143 | DEPENDS ${target}.bc 144 | COMMAND ${WASM_LLC} -thread-model=single -asm-verbose=false -o ${target}.s ${target}.bc 145 | COMMENT "Generating textual assembly ${target}.s" 146 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 147 | VERBATIM 148 | ) 149 | set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.s) 150 | 151 | if(ARG_MAX_MEMORY) 152 | set(MAX_MEMORY_PARAM "-m" ${ARG_MAX_MEMORY}) 153 | endif() 154 | 155 | add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.wast 156 | DEPENDS ${target}.s 157 | COMMAND ${S2WASM_PATH} -o ${DESTINATION_FOLDER}/${target}.wast -s 10240 158 | ${MAX_MEMORY_PARAM} ${target}.s 159 | COMMENT "Generating WAST ${target}.wast" 160 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 161 | VERBATIM 162 | ) 163 | set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.wast) 164 | 165 | add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.wasm 166 | DEPENDS ${target}.wast 167 | COMMAND ${WAST2WASM_PATH} ${DESTINATION_FOLDER}/${target}.wast 168 | ${DESTINATION_FOLDER}/${target}.wasm -n 169 | COMMENT "Generating WASM ${target}.wasm" 170 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 171 | VERBATIM 172 | ) 173 | set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.wasm) 174 | 175 | STRING (REPLACE "." "_" TARGET_VARIABLE "${target}") 176 | 177 | add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.wast.hpp 178 | DEPENDS ${DESTINATION_FOLDER}/${target}.wast 179 | COMMAND echo "const char* const ${TARGET_VARIABLE}_wast = R\"=====(" > ${DESTINATION_FOLDER}/${target}.wast.hpp 180 | COMMAND cat ${DESTINATION_FOLDER}/${target}.wast >> ${DESTINATION_FOLDER}/${target}.wast.hpp 181 | COMMAND echo ")=====\";" >> ${DESTINATION_FOLDER}/${target}.wast.hpp 182 | COMMENT "Generating ${target}.wast.hpp" 183 | VERBATIM 184 | ) 185 | 186 | if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${target}.abi ) 187 | add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.abi.hpp 188 | DEPENDS ${DESTINATION_FOLDER}/${target}.abi 189 | COMMAND echo "const char* const ${TARGET_VARIABLE}_abi = R\"=====(" > ${DESTINATION_FOLDER}/${target}.abi.hpp 190 | COMMAND cat ${DESTINATION_FOLDER}/${target}.abi >> ${DESTINATION_FOLDER}/${target}.abi.hpp 191 | COMMAND echo ")=====\";" >> ${DESTINATION_FOLDER}/${target}.abi.hpp 192 | COMMENT "Generating ${target}.abi.hpp" 193 | VERBATIM 194 | ) 195 | set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.abi.hpp) 196 | set(extra_target_dependency ${DESTINATION_FOLDER}/${target}.abi.hpp) 197 | else() 198 | endif() 199 | 200 | add_custom_target(${target} ALL DEPENDS ${DESTINATION_FOLDER}/${target}.wast.hpp ${extra_target_dependency} ${DESTINATION_FOLDER}/${target}.wasm) 201 | 202 | set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${DESTINATION_FOLDER}/${target}.wast.hpp) 203 | 204 | set_property(TARGET ${target} PROPERTY INCLUDE_DIRECTORIES ${ARG_INCLUDE_FOLDERS}) 205 | 206 | set(extra_target_dependency) 207 | 208 | # For CLion code insight 209 | include_directories(..) 210 | if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${target}.hpp) 211 | set(HEADER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${target}.hpp) 212 | endif() 213 | file(GLOB HEADER_FILES ${ARG_INCLUDE_FOLDERS}/*.hpp ${SYSTEM_INCLUDE_FOLDERS}/*.hpp) 214 | add_executable(${target}.tmp EXCLUDE_FROM_ALL ${SOURCE_FILES} ${HEADER_FILE} ${HEADER_FILES}) 215 | 216 | add_test(NAME "validate_${target}_abi" 217 | COMMAND ${CMAKE_BINARY_DIR}/scripts/abi_is_json.py ${ABI_FILES}) 218 | 219 | endmacro(add_wast_executable) 220 | --------------------------------------------------------------------------------