diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index 512e0b4c463719be0760b6fb49b09ecd8cf3658d..bfd6c83727e2ffce1ee1ff2f1cd1e181d450699b 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(asserter) add_subdirectory(currency) add_subdirectory(exchange) add_subdirectory(infinite) diff --git a/contracts/asserter/CMakeLists.txt b/contracts/asserter/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..af67a67658b173a1f8243d0b02b0911c6dc3c444 --- /dev/null +++ b/contracts/asserter/CMakeLists.txt @@ -0,0 +1,3 @@ +file(GLOB ABI_FILES "*.abi") +add_wast_target(asserter "${CMAKE_SOURCE_DIR}/contracts" ${CMAKE_CURRENT_BINARY_DIR}) +configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) \ No newline at end of file diff --git a/contracts/asserter/asserter.abi b/contracts/asserter/asserter.abi new file mode 100644 index 0000000000000000000000000000000000000000..58d77e25e4640042b1ef83d6cc27eabddeb45a44 --- /dev/null +++ b/contracts/asserter/asserter.abi @@ -0,0 +1,27 @@ +{ + "types": [], + "structs": [ + { + "name": "assertdef", + "base": "", + "fields": { + "condition": "int8", + "message": "string" + } + }, { + "name": "nothing", + "base": "", + "fields": {} + } + ], + "actions": [ + { + "action": "procassert", + "type": "assert_def" + }, { + "action": "provereset", + "type": "nothing" + } + ], + "tables": [] +} diff --git a/contracts/asserter/asserter.cpp b/contracts/asserter/asserter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a20e6a20b3d8efb6e5b927c4220dbea996904205 --- /dev/null +++ b/contracts/asserter/asserter.cpp @@ -0,0 +1,39 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ + +#include /// defines assert_def struct (abi) + +using namespace asserter; + +static int global_variable = 45; + +extern "C" { + /// The apply method implements the dispatch of events to this contract + void apply( uint64_t code, uint64_t action ) { + if( code == N(asserter) ) { + if( action == N(procassert) ) { + assertdef check; + read_action(&check, sizeof(assertdef)); + + unsigned char buffer[256]; + size_t actsize = read_action(buffer, 256); + assertdef *def = reinterpret_cast(buffer); + + // make sure to null term the string + if (actsize < 255) { + buffer[actsize] = 0; + } else { + buffer[255] = 0; + } + + // maybe assert? + assert(def->condition, def->message); + } else if( action == N(provereset) ) { + assert(global_variable == 45, "Global Variable Initialized poorly"); + global_variable = 100; + } + } + } +} diff --git a/contracts/asserter/asserter.hpp b/contracts/asserter/asserter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..151fb3659b3d1f74599d23eb181c70dccf18a6c6 --- /dev/null +++ b/contracts/asserter/asserter.hpp @@ -0,0 +1,14 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ + +#include + +namespace asserter { + struct PACKED(assertdef) { + int8_t condition; + int8_t message_length; + char message[]; + }; +} \ No newline at end of file diff --git a/contracts/currency/currency.cpp b/contracts/currency/currency.cpp index 959cce83075c11ee9bf5828b0d380f98e1bbac19..00754789322f0632607c92f5bb13985c445daed0 100644 --- a/contracts/currency/currency.cpp +++ b/contracts/currency/currency.cpp @@ -46,7 +46,7 @@ extern "C" { void apply( uint64_t code, uint64_t action ) { if( code == N(currency) ) { if( action == N(transfer) ) - TOKEN_NAME::apply_currency_transfer( current_message< TOKEN_NAME::transfer >() ); + TOKEN_NAME::apply_currency_transfer( current_action< TOKEN_NAME::transfer >() ); } } } diff --git a/contracts/eos/eos.cpp b/contracts/eos/eos.cpp index c936a452d1b350f7443ffd68466e5f97922c1fab..770d7cffb875d5983763298b455c2879959c818a 100644 --- a/contracts/eos/eos.cpp +++ b/contracts/eos/eos.cpp @@ -104,7 +104,7 @@ namespace native {

Required Recipients

- This message requires that the accounts `from` and `to` are listed in the required recipients. This ensures + This action requires that the accounts `from` and `to` are listed in the required recipients. This ensures other contracts are notified anytime EOS tokens are transferred. */ diff --git a/contracts/eoslib/message.h b/contracts/eoslib/action.h similarity index 93% rename from contracts/eoslib/message.h rename to contracts/eoslib/action.h index e999632b708446f0f0b59dd7b19111fcff44cd90..88e5446b90bebbf23279f8cab41975e14c47d154 100644 --- a/contracts/eoslib/message.h +++ b/contracts/eoslib/action.h @@ -47,10 +47,10 @@ extern "C" { * // } * * char buffer[128]; - * uint32_t total = read_message(buffer, 5); // buffer contains the content of the message up to 5 bytes + * uint32_t total = read_action(buffer, 5); // buffer contains the content of the message up to 5 bytes * print(total); // Output: 5 * - * uint32_t msgsize = message_size(); + * uint32_t msgsize = action_size(); * print(msgsize); // Output: size of the above message's data field * * require_notice(N(initc)); // initc account will be notified for this message @@ -79,7 +79,7 @@ extern "C" { * @param len - len of the current message to be copied * @return the number of bytes copied to msg */ - uint32_t read_message( void* msg, uint32_t len ); + uint32_t read_action( void* msg, uint32_t len ); /** * Get the length of the current message's data field @@ -87,7 +87,7 @@ extern "C" { * @brief Get the length of current message's data field * @return the length of the current message's data field */ - uint32_t message_size(); + uint32_t action_size(); /** * Add the specified account to set of accounts to be notified diff --git a/contracts/eoslib/message.hpp b/contracts/eoslib/action.hpp similarity index 58% rename from contracts/eoslib/message.hpp rename to contracts/eoslib/action.hpp index ae076cf1ae222936e3c9f95275cf0acf6c3668d4..ba87f1c0f1ab7c2a1a448266a74730e7b8e8b9c5 100644 --- a/contracts/eoslib/message.hpp +++ b/contracts/eoslib/action.hpp @@ -3,43 +3,43 @@ * @copyright defined in eos/LICENSE.txt */ #pragma once -#include +#include #include namespace eosio { /** - * @defgroup messagecppapi Message C++ API - * @ingroup messageapi - * @brief Type-safe C++ wrapers for Message C API + * @defgroup actioncppapi Action C++ API + * @ingroup actionapi + * @brief Type-safe C++ wrapers for Action C API * - * @note There are some methods from the @ref messagecapi that can be used directly from C++ + * @note There are some methods from the @ref actioncapi that can be used directly from C++ * * @{ */ /** * - * This method attempts to reinterpret the message body as type T. This will only work - * if the message has no dynamic fields and the struct packing on type T is properly defined. + * This method attempts to reinterpret the action body as type T. This will only work + * if the action has no dynamic fields and the struct packing on type T is properly defined. * - * @brief Interpret the message body as type T + * @brief Interpret the action body as type T * * Example: * @code - * struct dummy_message { + * struct dummy_action { * char a; //1 * unsigned long long b; //8 * int c; //4 * }; - * dummy_message msg = current_message(); + * dummy_action msg = current_action(); * @endcode */ template - T current_message() { + T current_action() { T value; - auto read = read_message( &value, sizeof(value) ); - assert( read >= sizeof(value), "message shorter than expected" ); + auto read = read_action( &value, sizeof(value) ); + assert( read >= sizeof(value), "action shorter than expected" ); return value; } @@ -52,7 +52,7 @@ namespace eosio { * This helper method enables you to add multiple accounts to accounts to be notified list with a single * call rather than having to call the similar C API multiple times. * - * @note message.code is also considered as part of the set of notified accounts + * @note action.code is also considered as part of the set of notified accounts * * @brief Verify specified accounts exist in the set of notified accounts * @@ -68,6 +68,6 @@ namespace eosio { } - ///@} messagecpp api + ///@} actioncpp api } // namespace eos diff --git a/contracts/eoslib/contracts.dox b/contracts/eoslib/contracts.dox index d6e8d9bae4aeba30e523f20e1f11700b2163085e..fbb649ecdef63822cc442854b37df1dfb279866e 100644 --- a/contracts/eoslib/contracts.dox +++ b/contracts/eoslib/contracts.dox @@ -49,7 +49,7 @@ void apply( uint64_t code, uint64_t action ) { if( code == N(currency) ) { if( action == N(transfer) ) - currency::apply_currency_transfer( currentMessage< currency::Transfer >() ); + currency::apply_currency_transfer( currentAction< currency::Transfer >() ); } else { assert( false, "rejecting unexpected event" ); } diff --git a/contracts/eoslib/eos.hpp b/contracts/eoslib/eos.hpp index e3c85f62327b19af672dceeafbb3d61064e0a01f..5038fe060c3976b479bfe12bb391f0b5ccacfbeb 100644 --- a/contracts/eoslib/eos.hpp +++ b/contracts/eoslib/eos.hpp @@ -4,7 +4,7 @@ */ #pragma once #include -#include +#include #include #include #include diff --git a/contracts/eoslib/eosc.dox b/contracts/eoslib/eosc.dox index d7f233cf2be5d7b7e393d036728b3cbbe472a673..c3203f86c89b3665f3faf5d400bff037a4196fe8 100644 --- a/contracts/eoslib/eosc.dox +++ b/contracts/eoslib/eosc.dox @@ -1,6 +1,6 @@ /** - @defgroup eosc EOS Command Line Client (eosc) + @defgroup eosioc EOS Command Line Client (eosioc) @brief Tool for sending transactions and querying state from @ref eosd @section contents Table of Contents @@ -14,7 +14,7 @@ - [Transfer EOS](#transfereos) - [Getting Transaction](#gettingtransaction) - [Creating a Contract](#createcontract) - - [Pushing Message to Contract](#pushmessage) + - [Pushing Actions to Contracts](#pushaction) - [Querying Contract](#querycontract) - [Connecting to Particular Node](#particularnode) - [Using Separate Wallet App](#separatewallet) @@ -23,7 +23,7 @@ @section intro Introduction to EOSC - `eosc` is a command line tool that interfaces with the REST api exposed by @ref eosd. In order to use `eosc` you will need to + `eosioc` is a command line tool that interfaces with the REST api exposed by @ref eosd. In order to use `eosioc` you will need to have a local copy of `eosd` running and configured to load the 'eosio::chain_api_plugin'. In order to sign transaction and push it to the blockchain, you will need to have the 'eosio::wallet_api_plugin' @@ -41,7 +41,7 @@ After starting `eosd` you should be able to query the current blockchain state like so: ``` - $ ./eosc get info + $ ./eosioc get info { "head_block_num": 25048, "last_irreversible_block_num": 25027, @@ -58,7 +58,7 @@ Any transaction sent to the blockchain will need to be signed by the respective authority's private key. Before you will be able to sign the transaction, you will need a wallet to store and manage the private key. ``` - $ ./eosc wallet create + $ ./eosioc wallet create Creating wallet: default Save password to use in the future to unlock this wallet. Without password imported keys will not be retrievable. @@ -68,7 +68,7 @@ You can create multiple wallets by specifying unique name ``` - $ ./eosc wallet create -n second-wallet + $ ./eosioc wallet create -n second-wallet Creating wallet: second-wallet Save password to use in the future to unlock this wallet. Without password imported keys will not be retrievable. @@ -77,7 +77,7 @@ And you will be see it in the list of your wallets ``` - $ ./eosc wallet list + $ ./eosioc wallet list Wallets: [ "default *", @@ -92,12 +92,12 @@ Import the key that you want to use to sign the transaction to your wallet. The following will import key for genesis accounts (i.e. inita, initb, initc, ..., initu) ``` - $ ./eosc wallet import 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 + $ ./eosioc wallet import 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 imported private key for: EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV ``` You will then be able to see the list of imported private keys and their respective public key ``` - $ ./eosc wallet keys + $ ./eosioc wallet keys [[ "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3" @@ -109,12 +109,12 @@ To keep your private key safe, lock your wallet ``` - $ ./eosc wallet lock -n second-wallet + $ ./eosioc wallet lock -n second-wallet Locked: 'second-wallet' ``` Notice that the locked wallet doesn't have * symbol in the list ``` - $ ./eosc wallet list + $ ./eosioc wallet list Wallets: [ "default *", @@ -123,22 +123,22 @@ ``` To unlock it specify the password you get when creating the wallet ``` - $ ./eosc wallet unlock -n second-wallet --password PW5Ji6JUrLjhKAVn68nmacLxwhvtqUAV18J7iycZppsPKeoGGgBEw + $ ./eosioc wallet unlock -n second-wallet --password PW5Ji6JUrLjhKAVn68nmacLxwhvtqUAV18J7iycZppsPKeoGGgBEw Unlocked: 'second-wallet' ``` @section openwallet Opening Wallet All of the wallets data are store inside data_dir folder. - When you restart your wallet app (in this case `eosd`), you will need to open the wallet so `eosc` can have access to it. + When you restart your wallet app (in this case `eosd`), you will need to open the wallet so `eosioc` can have access to it. ``` - $ ./eosc wallet list + $ ./eosioc wallet list Wallets: [] - $ ./eosc wallet open + $ ./eosioc wallet open Wallets: [ "default" ] - $ ./eosc wallet open -n second-wallet + $ ./eosioc wallet open -n second-wallet Wallets: [ "default", "second-wallet" @@ -148,23 +148,23 @@ @section createaccount Creating an Account - In order to create an account you will need two new keys: owner and active. You can ask `eosc` to create some keys for you: + In order to create an account you will need two new keys: owner and active. You can ask `eosioc` to create some keys for you: This will be your owner key, ``` - $ ./eosc create key + $ ./eosioc create key public: EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq private: 5JKbLfCXgcafDQVwHMm3shHt6iRWgrr9adcmt6vX3FNjAEtJGaT ``` And this will be your active key, ``` - $ ./eosc create key + $ ./eosioc create key public: EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA private: 5Hv22aPcjnENBv6X9o9nKGdkfrW44En6z4zJUt2PobAvbQXrT9z ``` - @note eosc does not save the generated private key. + @note eosioc does not save the generated private key. Next we will create the account `tester`, but because all accounts need to be created by an existing account we will ask the `inita` account to create `tester` using the owner and active keys created above. `inita` was specified in the genesis file. @@ -173,7 +173,7 @@ Then create an account called tester ``` - $ ./eosc create account inita tester EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA + $ ./eosioc create account inita tester EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA { "transaction_id": "6acd2ece68c4b86c1fa209c3989235063384020781f2c67bbb80bc8d540ca120", "processed": { @@ -185,7 +185,7 @@ "inita" ], "signatures": [], - "messages": [{ + "actions": [{ "code": "eos", "type": "newaccount", "authorization": [{ @@ -207,7 +207,7 @@ ``` You can see that `tester` is now the controlled_account under `inita` ``` - $ ./eosc get servants inita + $ ./eosioc get servants inita { "controlled_accounts": [ "tester" @@ -220,7 +220,7 @@ After creating the account we can view the current account status like so: ``` - $ ./eosc get account tester + $ ./eosioc get account tester { "name": "tester", "eos_balance": 0, @@ -270,10 +270,10 @@ ``` Since we have the private key of the genesis accounts (i.e. inita, initb, initc, etc) in the wallet. - We can fund our `tester` account via `eosc` through any of the genesis account with the following command: + We can fund our `tester` account via `eosioc` through any of the genesis account with the following command: ``` - $ ./eosc transfer inita tester 1000 + $ ./eosioc transfer inita tester 1000 { "transaction_id": "eb4b94b72718a369af09eb2e7885b3f494dd1d8a20278a6634611d5edd76b703", "processed": { @@ -287,7 +287,7 @@ "signatures": [ "1f22e64240e1e479eee6ccbbd79a29f1a6eb6020384b4cca1a958e7c708d3e562009ae6e60afac96f9a3b89d729a50cd5a7b5a7a647540ba1678831bf970e83312" ], - "messages": [{ + "actions": [{ "code": "eos", "type": "transfer", "authorization": [{ @@ -333,7 +333,7 @@ Now we can verify that the funds were received. ``` - $ ./eosc get account tester + $ ./eosioc get account tester { "name": "tester", "eos_balance": "0.1000 EOS", @@ -373,7 +373,7 @@ With account_history_api_plugin loaded in `eosd`, we can query for particular transaction ``` - $ ./eosc get transaction eb4b94b72718a369af09eb2e7885b3f494dd1d8a20278a6634611d5edd76b703 + $ ./eosioc get transaction eb4b94b72718a369af09eb2e7885b3f494dd1d8a20278a6634611d5edd76b703 { "transaction_id": "eb4b94b72718a369af09eb2e7885b3f494dd1d8a20278a6634611d5edd76b703", "processed": { @@ -387,7 +387,7 @@ "signatures": [ "1f22e64240e1e479eee6ccbbd79a29f1a6eb6020384b4cca1a958e7c708d3e562009ae6e60afac96f9a3b89d729a50cd5a7b5a7a647540ba1678831bf970e83312" ], - "messages": [{ + "actions": [{ "code": "eos", "type": "transfer", "authorization": [{ @@ -430,7 +430,7 @@ ``` Also we can query list of transactions performed by certain account starting from recent one ``` - $ ./eosc get transactions inita + $ ./eosioc get transactions inita [ { "transaction_id": "eb4b94b72718a369af09eb2e7885b3f494dd1d8a20278a6634611d5edd76b703", @@ -446,26 +446,26 @@ @section createcontract Creating a Contract - In this section we will use `eosc` to create and publish a currency contract. You can find the example currency contract in the `eos/contracts/currency` directory. + In this section we will use `eosioc` to create and publish a currency contract. You can find the example currency contract in the `eos/contracts/currency` directory. The first step is to create an account for currency. We will have the `inita` account create the `currency` account. Ensure you have inita private key imported. ``` - $ ./eosc create account inita currency EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA + $ ./eosioc create account inita currency EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA ``` The next step is to publish the contract (.wast) and its abi (.abi). We will need currency active key in our wallet for this ``` - $ ./eosc import 5Hv22aPcjnENBv6X9o9nKGdkfrW44En6z4zJUt2PobAvbQXrT9z + $ ./eosioc import 5Hv22aPcjnENBv6X9o9nKGdkfrW44En6z4zJUt2PobAvbQXrT9z imported private key for: EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA ``` Then proceed with setting the code ``` - $ ./eosc set contract currency ../../../contracts/currency/currency.wast ../../../contracts/currency/currency.abi + $ ./eosioc set contract currency ../../../contracts/currency/currency.wast ../../../contracts/currency/currency.abi Reading WAST... Assembling WASM... Publishing contract... @@ -480,7 +480,7 @@ "eos" ], "signatures": [], - "messages": [{ + "actions": [{ "code": "eos", "type": "setcode", "authorization": [{ @@ -501,13 +501,13 @@ } ``` - @section pushmessage Pushing Message to Contract + @section pushaction Pushing Actions to Contracts After the contract is published it initially allocates all of the currency to the `currency` account. So lets transfer some of it to our tester. - We can query the blockchain for the .abi of the contract, on which we can check the list of available actions and their respective message structure + We can query the blockchain for the .abi of the contract, on which we can check the list of available actions and their respective action structure ``` - $ ./eosc get code --a currency.abi currency + $ ./eosioc get code --a currency.abi currency code hash: 9b9db1a7940503a88535517049e64467a6e8f4e9e03af15e9968ec89dd794975 saving abi to currency.abi $ cat currency.abi @@ -552,10 +552,10 @@ } ``` - From the above abi, we can see that `currency` contract accepts an action called `transfer` that accepts message with fields `from`, `to`, and `amount`. + From the above abi, we can see that `currency` contract accepts an action called `transfer` that accepts action with fields `from`, `to`, and `amount`. ``` - $ ./eosc push message currency transfer '{"from":"currency","to":"tester","amount":50}' -S currency -S tester -p currency@active + $ ./eosioc push action currency transfer '{"from":"currency","to":"tester","amount":50}' -S currency -S tester -p currency@active 1589302ms thread-0 main.cpp:271 operator() ] Converting argument to binary... 1589304ms thread-0 main.cpp:290 operator() ] Transaction result: { @@ -569,7 +569,7 @@ "tester" ], "signatures": [], - "messages": [{ + "actions": [{ "code": "currency", "type": "transfer", "authorization": [{ @@ -606,7 +606,7 @@ Now we can transfer it from `tester` to `inita` and require the permission of `tester`. This should drain the balance of `tester` to 0. ``` - $ ./eosc push message currency transfer '{"from":"tester","to":"inita","amount":50}' -S inita -S tester -p tester@active + $ ./eosioc push action currency transfer '{"from":"tester","to":"inita","amount":50}' -S inita -S tester -p tester@active 3116153ms thread-0 main.cpp:271 operator() ] Converting argument to binary... 3116154ms thread-0 main.cpp:290 operator() ] Transaction result: { @@ -620,7 +620,7 @@ "tester" ], "signatures": [], - "messages": [{ + "actions": [{ "code": "currency", "type": "transfer", "authorization": [{ @@ -664,7 +664,7 @@ Now that `tester` has a balance of 0, if we attempt this transfer a second time it should fail: ``` - $ ./eosc push message currency transfer '{"from":"tester","to":"inita","amount":50}' -S inita -S tester -p tester@active + $ ./eosioc push action currency transfer '{"from":"tester","to":"inita","amount":50}' -S inita -S tester -p tester@active 3543610ms thread-0 main.cpp:271 operator() ] Converting argument to binary... 3543615ms thread-0 main.cpp:311 main ] Failed with error: 10 assert_exception: Assert Exception status_code == 200: Error @@ -683,12 +683,12 @@ This table is stored on the scope of each account instead of on `currency` scope. ``` - $./eosc get table tester currency account + $./eosioc get table tester currency account { "rows": [], "more": false } - $./eosc get table inita currency account + $./eosioc get table inita currency account { "rows": [{ "account": "account", @@ -702,9 +702,9 @@ @section particularnode Connecting to Particular Node - By default, `eosc` will connect to `eosd` running on localhost port 8888. You can connect to another `eosd` node by specifying its host and port. + By default, `eosioc` will connect to `eosd` running on localhost port 8888. You can connect to another `eosd` node by specifying its host and port. ``` - ./eosc -H localhost -p 8889 + ./eosioc -H localhost -p 8889 ``` @section separatewallet Using Separate Wallet App @@ -716,7 +716,7 @@ ``` Then for any operation that requires signing, use the --wallet-host and --wallet-port option ``` - ./eosc --wallet-host 127.0.0.1 --wallet-port 8887 + ./eosioc --wallet-host 127.0.0.1 --wallet-port 8887 ``` @@ -729,18 +729,18 @@ ``` And then for any operation that requires signing, use the `-s` option ``` - ./eosc -s + ./eosioc -s ``` @section additionaldoc Additional Documentation - eosc contains documentation for all of its commands. For a list of all commands known to eosc, simply run it with no arguments: + eosioc contains documentation for all of its commands. For a list of all commands known to eosioc, simply run it with no arguments: ``` - $ ./eosc + $ ./eosioc ERROR: RequiredError: Subcommand required Command Line Interface to Eos Daemon - Usage: ./eosc [OPTIONS] SUBCOMMAND + Usage: ./eosioc [OPTIONS] SUBCOMMAND Options: -h,--help Print this help message and exit @@ -761,18 +761,18 @@ ``` To get help with any particular subcommand, run it with no arguments as well: ``` - $ ./eosc create + $ ./eosioc create ERROR: RequiredError: Subcommand required Create various items, on and off the blockchain - Usage: ./eosc create SUBCOMMAND + Usage: ./eosioc create SUBCOMMAND Subcommands: key Create a new keypair and print the public and private keys account Create a new account on the blockchain - $ ./eosc create account + $ ./eosioc create account ERROR: RequiredError: creator Create a new account on the blockchain - Usage: ./eosc create account creator name OwnerKey ActiveKey + Usage: ./eosioc create account creator name OwnerKey ActiveKey Positionals: creator TEXT The name of the account creating the new account diff --git a/contracts/eoslib/mainpage.md b/contracts/eoslib/mainpage.md index 36dfebc49fa1e784a83f7c213bf710fdec65e74f..0d975575bafd0b89c218a4b335238ba6e8a952f3 100644 --- a/contracts/eoslib/mainpage.md +++ b/contracts/eoslib/mainpage.md @@ -22,12 +22,12 @@ Welcome to the EOS.IO Documentation ## End User - Wallet Creation and Management - - [Create a wallet](https://eosio.github.io/eos/group__eosc.html#createwallet) - - [Import Key to Wallet](https://eosio.github.io/eos/group__eosc.html#importkey) - - [Locking and Unlocking Wallet](https://eosio.github.io/eos/group__eosc.html#lockwallets) - - [Create an Account](https://eosio.github.io/eos/group__eosc.html#createaccount) - - [Transfer EOS](https://eosio.github.io/eos/group__eosc.html#transfereos) - - [Getting Transaction](https://eosio.github.io/eos/group__eosc.html#gettingtransaction) + - [Create a wallet](https://eosio.github.io/eos/group__eosioc.html#createwallet) + - [Import Key to Wallet](https://eosio.github.io/eos/group__eosioc.html#importkey) + - [Locking and Unlocking Wallet](https://eosio.github.io/eos/group__eosioc.html#lockwallets) + - [Create an Account](https://eosio.github.io/eos/group__eosioc.html#createaccount) + - [Transfer EOS](https://eosio.github.io/eos/group__eosioc.html#transfereos) + - [Getting Transaction](https://eosio.github.io/eos/group__eosioc.html#gettingtransaction) ## Smart Contract Developers - [Introduction to Contract Development Tutorial](https://eosio.github.io/eos/md_contracts_eoslib_tutorial.html) diff --git a/contracts/eoslib/rpc.dox b/contracts/eoslib/rpc.dox index 2f382b3fae7187ecd49ec359e78f66ec76c2a434..26c3ded8ed4f865b218082fa80bedc1acabb2d7b 100644 --- a/contracts/eoslib/rpc.dox +++ b/contracts/eoslib/rpc.dox @@ -304,7 +304,7 @@ Content-Length: 1466 @subsubsection examplepushtrx Example push_transaction Usage This example assumes a transfer operation. The `refBlockNum` and `refBlockPrefix` are provided as a result of `/v1/chain/get_block`. ``` -curl http://localhost:8888/v1/chain/push_transaction -X POST -d '{"refBlockNum":"100","refBlockPrefix":"137469861","expiration":"2017-09-25T06:28:49","scope":["initb","initc"],"messages":[{"code":"currency","type":"transfer","recipients":["initb","initc"],"authorization":[{"account":"initb","permission":"active"}],"data":"000000000041934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}' +curl http://localhost:8888/v1/chain/push_transaction -X POST -d '{"refBlockNum":"100","refBlockPrefix":"137469861","expiration":"2017-09-25T06:28:49","scope":["initb","initc"],"actions":[{"code":"currency","type":"transfer","recipients":["initb","initc"],"authorization":[{"account":"initb","permission":"active"}],"data":"000000000041934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}' ``` @@ -314,7 +314,7 @@ This method push multiple transactions at once. @subsubsection examplepushtrxs Example push_transactions Usage ``` -curl http://localhost:8888/v1/chain/push_transaction -X POST -d '[{"refBlockNum":"101","refBlockPrefix":"4159312339","expiration":"2017-09-25T06:28:49","scope":["initb","initc"],"messages":[{"code":"currency","type":"transfer","recipients":["initb","initc"],"authorization":[{"account":"initb","permission":"active"}],"data":"000000000041934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}, {"refBlockNum":"101","refBlockPrefix":"4159312339","expiration":"2017-09-25T06:28:49","scope":["inita","initc"],"messages":[{"code":"currency","type":"transfer","recipients":["inita","initc"],"authorization":[{"account":"inita","permission":"active"}],"data":"000000008040934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}]' +curl http://localhost:8888/v1/chain/push_transaction -X POST -d '[{"refBlockNum":"101","refBlockPrefix":"4159312339","expiration":"2017-09-25T06:28:49","scope":["initb","initc"],"actions":[{"code":"currency","type":"transfer","recipients":["initb","initc"],"authorization":[{"account":"initb","permission":"active"}],"data":"000000000041934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}, {"refBlockNum":"101","refBlockPrefix":"4159312339","expiration":"2017-09-25T06:28:49","scope":["inita","initc"],"actions":[{"code":"currency","type":"transfer","recipients":["inita","initc"],"authorization":[{"account":"inita","permission":"active"}],"data":"000000008040934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}]' ``` @@ -324,7 +324,7 @@ Get required keys to sign a transaction from list of your keys. @subsubsection examplegetrequiredkeys Example get_required_keys Usage ``` -curl http://localhost:8888/v1/chain/get_required_keys -X POST -d '{"transaction": {"refBlockNum":"100","refBlockPrefix":"137469861","expiration":"2017-09-25T06:28:49","scope":["initb","initc"],"messages":[{"code":"currency","type":"transfer","recipients":["initb","initc"],"authorization":[{"account":"initb","permission":"active"}],"data":"000000000041934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}, "available_keys":["EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq","EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA","EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"]}' +curl http://localhost:8888/v1/chain/get_required_keys -X POST -d '{"transaction": {"refBlockNum":"100","refBlockPrefix":"137469861","expiration":"2017-09-25T06:28:49","scope":["initb","initc"],"actions":[{"code":"currency","type":"transfer","recipients":["initb","initc"],"authorization":[{"account":"initb","permission":"active"}],"data":"000000000041934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}, "available_keys":["EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq","EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA","EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"]}' ``` @subsubsection examplegetrequiredkeysresult Example get_required_keys Result diff --git a/contracts/eoslib/system.h b/contracts/eoslib/system.h index 3eca6193284a34d0584fd53db4eaecb7dd91dca6..ae8a0f32242960f16658c88bab546f22b21dc0d1 100644 --- a/contracts/eoslib/system.h +++ b/contracts/eoslib/system.h @@ -23,16 +23,16 @@ extern "C" { */ /** - * Aborts processing of this message and unwinds all pending changes if the test condition is true - * @brief Aborts processing of this message and unwinds all pending changes + * Aborts processing of this action and unwinds all pending changes if the test condition is true + * @brief Aborts processing of this action and unwinds all pending changes * @param test - 0 to abort, 1 to ignore - * @param cstr - a null terminated message to explain the reason for failure + * @param cstr - a null terminated action to explain the reason for failure */ void assert( uint32_t test, const char* cstr ); /** - * Returns the time in seconds from 1970 of the last accepted block (not the block including this message) + * Returns the time in seconds from 1970 of the last accepted block (not the block including this action) * @brief Get time of the last accepted block * @return time in seconds from 1970 of the last accepted block */ diff --git a/contracts/eoslib/tutorial.md b/contracts/eoslib/tutorial.md index 95131c665afe0fe237d73298c2bdc9837333c9fa..6ea04137869f35da8c1f72532b6b2c84da94d48e 100644 --- a/contracts/eoslib/tutorial.md +++ b/contracts/eoslib/tutorial.md @@ -8,7 +8,7 @@ For the rest of this tutorial we will use the term "contract" to refer to the co ## Required Background Knowledge -This tutorial assumes that you have basic understanding of how to use 'eosd' and 'eosc' to setup a node +This tutorial assumes that you have basic understanding of how to use 'eosd' and 'eosioc' to setup a node and deploy the example contracts. If you have not yet successfully followed that tutorial, then do that first and come back. @@ -77,7 +77,7 @@ extern "C" { } // extern "C" ``` -This contract implements the two entry points, `init` and `apply`. All it does is log the messages delivered and makes no other checks. Anyone can deliver any message at any time provided the block producers allow it. Absent any required signatures, the contract will be billed for the bandwidth consumed. +This contract implements the two entry points, `init` and `apply`. All it does is log the actions delivered and makes no other checks. Anyone can deliver any action at any time provided the block producers allow it. Absent any required signatures, the contract will be billed for the bandwidth consumed. You can compile this contract into a text version of WASM (.wast) like so: @@ -96,7 +96,7 @@ Now that you have compiled your application it is time to deploy it. This will r Assuming your wallet is unlocked and has keys for `${account}`, you can now upload this contract to the blockchain with the following command: ```bash -$ eosc set contract ${account} hello.wast hello.abi +$ eosioc set contract ${account} hello.wast hello.abi Reading WAST... Assembling WASM... Publishing contract... @@ -113,7 +113,7 @@ Publishing contract... "signatures": [ "2064610856c773423d239a388d22cd30b7ba98f6a9fbabfa621e42cec5dd03c3b87afdcbd68a3a82df020b78126366227674dfbdd33de7d488f2d010ada914b438" ], - "messages": [{ + "actions": [{ "code": "eos", "type": "setcode", "authorization": [{ @@ -158,15 +158,15 @@ You will notice the lines "Init World!" are executed 3 times, this isn't a mista 3. eosd pushes the generated block as if it received it from the network - **prints "Init World!" a third time** -At this point your contract is ready to start receiving messages. Since the default message handler accepts all messages we can send it -anything we want. Let's try sending it an empty message: +At this point your contract is ready to start receiving actions. Since the default action handler accepts all actions we can send it +anything we want. Let's try sending it an empty action: ```bash -$ eosc push message ${account} hello '"abcd"' --scope ${account} +$ eosioc push action ${account} hello '"abcd"' --scope ${account} ``` -This command will send the message "hello" with binary data represented by the hex string "abcd". Note, in a bit we will show how to define the ABI so that -you can replace the hex string with a pretty, easy-to-read, JSON object. For now we merely want to demonstrate how the message type "hello" is dispatched to +This command will send the action "hello" with binary data represented by the hex string "abcd". Note, in a bit we will show how to define the ABI so that +you can replace the hex string with a pretty, easy-to-read, JSON object. For now we merely want to demonstrate how the action type "hello" is dispatched to account. @@ -182,7 +182,7 @@ The result is: "${account}" ], "signatures": [], - "messages": [{ + "actions": [{ "code": "${account}", "type": "hello", "authorization": [], @@ -208,9 +208,9 @@ Hello World: ${account}->hello Once again your contract was executed and undone twice before being applied the 3rd time as part of a generated block. -### Message Name Restrictions +### Action Name Restrictions -Message types (eg. "hello") are actually base32 encoded 64 bit integers. This means they are limited to the charcters a-z, 1-5, and '.' for the first +Action types (eg. "hello") are actually base32 encoded 64 bit integers. This means they are limited to the charcters a-z, 1-5, and '.' for the first 12 charcters and if there is a 13th character then it is restricted to the first 16 characters ('.' and a-p). @@ -265,7 +265,7 @@ Here is an example of what the skeleton contract ABI looks like: } ``` -You will notice that this ABI defines an action `transfer` of type `transfer`. This tells EOS.IO that when `${account}->transfer` message is seen that the payload is of type +You will notice that this ABI defines an action `transfer` of type `transfer`. This tells EOS.IO that when `${account}->transfer` action is seen that the payload is of type `transfer`. The type `transfer` is defined in the `structs` array in the object with `name` set to `"transfer"`. ```json @@ -295,10 +295,10 @@ the `types` array to `Name`, which is a built in type used to encode a uint64_t ... ``` -Now that we have reviewed the ABI defined by the skeleton, we can construct a message call for `transfer`: +Now that we have reviewed the ABI defined by the skeleton, we can construct a action call for `transfer`: ```bash -eosc push message ${account} transfer '{"from":"currency","to":"inita","amount":50}' --scope initc +eosioc push action ${account} transfer '{"from":"currency","to":"inita","amount":50}' --scope initc 2570494ms thread-0 main.cpp:797 operator() ] Converting argument to binary... { "transaction_id": "b191eb8bff3002757839f204ffc310f1bfe5ba1872a64dda3fc42bfc2c8ed688", @@ -310,7 +310,7 @@ eosc push message ${account} transfer '{"from":"currency","to":"inita","amount": "initc" ], "signatures": [], - "messages": [{ + "actions": [{ "code": "initc", "type": "transfer", "authorization": [], @@ -339,9 +339,9 @@ Hello World: ${account}->transfer Hello World: ${account}->transfer ``` -## Processing Arguments of Transfer Message +## Processing Arguments of Transfer Action -According to the ABI the transfer message has the format: +According to the ABI the transfer action has the format: ```json "fields": { @@ -351,7 +351,7 @@ According to the ABI the transfer message has the format: } ``` -We also know that AccountName -> Name -> UInt64 which means that the binary representation of the message is the same as: +We also know that AccountName -> Name -> UInt64 which means that the binary representation of the action is the same as: ```c struct transfer { @@ -361,14 +361,14 @@ struct transfer { }; ``` -The EOS.IO C API provides access to the message payload via the Message API: +The EOS.IO C API provides access to the action payload via the Action API: ``` -uint32_t messageSize(); -uint32_t readMessage( void* msg, uint32_t msglen ); +uint32_t action_size(); +uint32_t read_action( void* act, uint32_t actlen ); ``` -Let's modify `hello.cpp` to print out the content of the message: +Let's modify `hello.cpp` to print out the content of the action: ```c #include @@ -396,11 +396,11 @@ extern "C" { void apply( uint64_t code, uint64_t action ) { eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" ); if( action == N(transfer) ) { - transfer message; - static_assert( sizeof(message) == 3*sizeof(uint64_t), "unexpected padding" ); - auto read = readMessage( &message, sizeof(message) ); - assert( read == sizeof(message), "message too short" ); - eosio::print( "Transfer ", message.amount, " from ", eosio::Name(message.from), " to ", eosio::Name(message.to), "\n" ); + transfer action; + static_assert( sizeof(action) == 3*sizeof(uint64_t), "unexpected padding" ); + auto read = read_action( &action, sizeof(action) ); + assert( read == sizeof(action), "action too short" ); + eosio::print( "Transfer ", action.amount, " from ", eosio::Name(action.from), " to ", eosio::Name(action.to), "\n" ); } } @@ -411,7 +411,7 @@ Then we can recompile and deploy it with: ```bash eoscpp -o hello.wast hello.cpp -eosc set contract ${account} hello.wast hello.abi +eosioc set contract ${account} hello.wast hello.abi ``` `eosd` will call init() again because of the redeploy @@ -425,7 +425,7 @@ Init World! Then we can execute transfer: ```bash -$ eosc push message ${account} transfer '{"from":"currency","to":"inita","amount":50}' --scope ${account} +$ eosioc push action ${account} transfer '{"from":"currency","to":"inita","amount":50}' --scope ${account} { "transaction_id": "a777539b7d5f752fb40e6f2d019b65b5401be8bf91c8036440661506875ba1c0", "processed": { @@ -436,7 +436,7 @@ $ eosc push message ${account} transfer '{"from":"currency","to":"inita","amount "${account}" ], "signatures": [], - "messages": [{ + "actions": [{ "code": "${account}", "type": "transfer", "authorization": [], @@ -468,15 +468,15 @@ Hello World: ${account}->transfer Transfer 50 from currency to inita ``` -### Using C++ API to Read Messages +### Using C++ API to Read Actions So far we used the C API because it is the lowest level API that is directly exposed by EOS.IO to the WASM virtual machine. Fortunately, eoslib provides a higher level API that removes much of the boiler plate. ```c -/// eoslib/message.hpp +/// eoslib/action.hpp namespace eosio { template - T currentMessage(); + T currentAction(); } ``` @@ -508,8 +508,8 @@ extern "C" { void apply( uint64_t code, uint64_t action ) { eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" ); if( action == N(transfer) ) { - auto message = eosio::currentMessage(); - eosio::print( "Transfer ", message.amount, " from ", message.from, " to ", message.to, "\n" ); + auto action = eosio::currentAction(); + eosio::print( "Transfer ", action.amount, " from ", action.from, " to ", action.to, "\n" ); } } @@ -517,13 +517,13 @@ extern "C" { ``` -You will notice that we updated the `transfer` struct to use the `eosio::Name` type directly, and then condenced the checks around `readMessage` to a single call to `currentMessage`. +You will notice that we updated the `transfer` struct to use the `eosio::Name` type directly, and then condenced the checks around `read_action` to a single call to `currentAction`. After compiling and uploading it you should get the same results as the C version. ## Requiring Sender Authority to Transfer -One of the most common requirements of any contract is to define who is allowed to perform the action. In the case of a curency transfer, we want require that the account defined by the `from` parameter signs off on the message. +One of the most common requirements of any contract is to define who is allowed to perform the action. In the case of a curency transfer, we want require that the account defined by the `from` parameter signs off on the action. The EOS.IO software will take care of enforcing and validating the signatures, all you need to do is require the necessary authority. @@ -532,9 +532,9 @@ The EOS.IO software will take care of enforcing and validating the signatures, a void apply( uint64_t code, uint64_t action ) { eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" ); if( action == N(transfer) ) { - auto message = eosio::currentMessage(); - eosio::requireAuth( message.from ); - eosio::print( "Transfer ", message.amount, " from ", message.from, " to ", message.to, "\n" ); + auto action = eosio::currentAction(); + eosio::requireAuth( action.from ); + eosio::print( "Transfer ", action.amount, " from ", action.from, " to ", action.to, "\n" ); } } ... @@ -543,14 +543,14 @@ The EOS.IO software will take care of enforcing and validating the signatures, a After building and deploying we can attempt to transfer again: ```bash - eosc push message ${account} transfer '{"from":"initb","to":"inita","amount":50}' --scope ${account} + eosioc push action ${account} transfer '{"from":"initb","to":"inita","amount":50}' --scope ${account} 1881603ms thread-0 main.cpp:797 operator() ] Converting argument to binary... 1881630ms thread-0 main.cpp:851 main ] Failed with error: 10 assert_exception: Assert Exception status_code == 200: Error : 3030001 tx_missing_auth: missing required authority Transaction is missing required authorization from initb {"acct":"initb"} - thread-0 message_handling_contexts.cpp:19 require_authorization + thread-0 action_handling_contexts.cpp:19 require_authorization ... ``` @@ -563,17 +563,17 @@ Hello World: initc->transfer This shows that it attempted to apply your transaction, printed the initial "Hello World" and then aborted when `eosio::requireAuth` failed to find authorization of account `initb`. -We can fix that by telling `eosc` to add the required permission: +We can fix that by telling `eosioc` to add the required permission: ```bash - eosc push message ${account} transfer '{"from":"initb","to":"inita","amount":50}' --scope ${account} --permission initb@active + eosioc push action ${account} transfer '{"from":"initb","to":"inita","amount":50}' --scope ${account} --permission initb@active ``` The `--permission` command defines the account and permission level, in this case we use the `active` authority which is the default. This time the transfer should have worked like we saw before. -## Aborting a Message on Error +## Aborting a Action on Error A large part of contract development is verifying preconditions, such that the amount transferred is greater than 0. If a user attempts to execute an invalid action, then the contract must abort and any changes made get automatically reverted. @@ -583,10 +583,10 @@ the contract must abort and any changes made get automatically reverted. void apply( uint64_t code, uint64_t action ) { eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" ); if( action == N(transfer) ) { - auto message = eosio::currentMessage(); - assert( message.amount > 0, "Must transfer an amount greater than 0" ); - eosio::requireAuth( message.from ); - eosio::print( "Transfer ", message.amount, " from ", message.from, " to ", message.to, "\n" ); + auto action = eosio::currentAction(); + assert( action.amount > 0, "Must transfer an amount greater than 0" ); + eosio::requireAuth( action.from ); + eosio::print( "Transfer ", action.amount, " from ", action.from, " to ", action.to, "\n" ); } } ... @@ -595,8 +595,8 @@ We can now compile, deploy, and attempt to execute a transfer of 0: ```bash $ eoscpp -o hello.wast hello.cpp - $ eosc set contract ${account} hello.wast hello.abi - $ eosc push message ${account} transfer '{"from":"initb","to":"inita","amount":0}' --scope initc --permission initb@active + $ eosioc set contract ${account} hello.wast hello.abi + $ eosioc push action ${account} transfer '{"from":"initb","to":"inita","amount":0}' --scope initc --permission initb@active 3071182ms thread-0 main.cpp:851 main ] Failed with error: 10 assert_exception: Assert Exception status_code == 200: Error : 10 assert_exception: Assert Exception diff --git a/contracts/exchange/exchange.cpp b/contracts/exchange/exchange.cpp index dfbeecdba5568193476b2ff3eb8490b7022cfddf..f65952478edeef8e345b604564813cea0a2d1197 100644 --- a/contracts/exchange/exchange.cpp +++ b/contracts/exchange/exchange.cpp @@ -303,16 +303,16 @@ extern "C" { if( code == N(exchange) ) { switch( action ) { case N(buy): - apply_exchange_buy( current_message() ); + apply_exchange_buy( current_action() ); break; case N(sell): - apply_exchange_sell( current_message() ); + apply_exchange_sell( current_action() ); break; case N(cancelbuy): - apply_exchange_cancel_buy( current_message() ); + apply_exchange_cancel_buy( current_action() ); break; case N(cancelsell): - apply_exchange_cancel_sell( current_message() ); + apply_exchange_cancel_sell( current_action() ); break; default: assert( false, "unknown action" ); @@ -320,11 +320,11 @@ extern "C" { } else if( code == N(currency) ) { if( action == N(transfer) ) - apply_currency_transfer( current_message() ); + apply_currency_transfer( current_action() ); } else if( code == N(eos) ) { if( action == N(transfer) ) - apply_eos_transfer( current_message() ); + apply_eos_transfer( current_action() ); } else { } diff --git a/contracts/infinite/infinite.cpp b/contracts/infinite/infinite.cpp index 02176133f5891f89a7644cbd166f9634ebf46530..a00698e6ed737d5a75577fd14ee9c4422c9fdd1e 100644 --- a/contracts/infinite/infinite.cpp +++ b/contracts/infinite/infinite.cpp @@ -48,7 +48,7 @@ extern "C" { void apply( uint64_t code, uint64_t action ) { if( code == N(currency) ) { if( action == N(transfer) ) - infinite::apply_currency_transfer( current_message< infinite::transfer >() ); + infinite::apply_currency_transfer( current_action< infinite::transfer >() ); } } } diff --git a/contracts/proxy/proxy.cpp b/contracts/proxy/proxy.cpp index ed32a49aab4bdea2fd4d9e8c5e701fed1cbfc017..510c509266b797825f2e40f830ff2a27d0617b89 100644 --- a/contracts/proxy/proxy.cpp +++ b/contracts/proxy/proxy.cpp @@ -55,15 +55,15 @@ extern "C" { void apply( uint64_t code, uint64_t action ) { if( code == N(currency) ) { if( action == N(transfer) ) { - apply_transfer(code, current_message()); + apply_transfer(code, current_action()); } } else if ( code == N(eos) ) { if( action == N(transfer) ) { - apply_transfer(code, current_message()); + apply_transfer(code, current_action()); } } else if (code == N(proxy) ) { if ( action == N(setowner)) { - apply_setowner(current_message()); + apply_setowner(current_action()); } } } diff --git a/contracts/simpledb/simpledb.cpp b/contracts/simpledb/simpledb.cpp index 7d2299e18c9765c5d1fca4adc45d7dca38d43356..ec2eec78f489236a7e7b55f4c85f0ff2b9bd07bd 100644 --- a/contracts/simpledb/simpledb.cpp +++ b/contracts/simpledb/simpledb.cpp @@ -14,9 +14,9 @@ extern "C" { void apply( uint64_t code, uint64_t action ) { if( code == N(simpledb) ) { if( action == N(insertkv1) ) { - // eosc push message simpledb insertkv1 '{"key":"a", "value":"aa"}' -S simpledb - // eosc get table simpledb simpledb keyvalue1 - auto kv1 = eosio::current_message(); + // eosioc push message simpledb insertkv1 '{"key":"a", "value":"aa"}' -S simpledb + // eosioc get table simpledb simpledb keyvalue1 + auto kv1 = eosio::current_action(); //eosio::print(kv1.key.len, "-", (const char*)kv1.key.str, "->" , kv1.value.len, "-", (const char*)kv1.value.str, "\n"); //Use kv1 in some way @@ -24,9 +24,9 @@ extern "C" { uint32_t err = store_str( N(simpledb), N(keyvalue1), (char *)kv1.key.get_data(), kv1.key.get_size(), (char*)kv1_bytes.data, kv1_bytes.len); } else if( action == N(insertkv2) ) { - // eosc push message simpledb insertkv2 '{"key":"a", "value":{"name":"aaa", "age":10}}' -S simpledb - // eosc get table simpledb simpledb keyvalue2 - auto kv2 = eosio::current_message(); + // eosioc push message simpledb insertkv2 '{"key":"a", "value":{"name":"aaa", "age":10}}' -S simpledb + // eosioc get table simpledb simpledb keyvalue2 + auto kv2 = eosio::current_action(); //eosio::print(kv2.key.len, "-", (const char*)kv2.key.str, "->" , (const char*)kv2.value.name.str, "-", kv2.value.age, "\n"); //Use kv2 in some way @@ -36,15 +36,15 @@ extern "C" { } else if( action == N(insert1) ) { record1 tmp; - read_message(&tmp, sizeof(tmp)); + read_action(&tmp, sizeof(tmp)); store_i64( N(simpledb), N(record1), &tmp, sizeof(tmp) ); } else if(action == N(insert2)) { record2 tmp; - read_message(&tmp, sizeof(tmp)); + read_action(&tmp, sizeof(tmp)); store_i128i128( N(simpledb), N(record2), &tmp, sizeof(tmp) ); } else if(action == N(insert3)) { record3 tmp; - read_message(&tmp, sizeof(tmp)); + read_action(&tmp, sizeof(tmp)); store_i64i64i64( N(simpledb), N(record3), &tmp, sizeof(tmp) ); } else { assert(0, "unknown message"); diff --git a/contracts/simpledb/simpledb.gen.hpp b/contracts/simpledb/simpledb.gen.hpp index a726a55fae7be2997c6fe88c10a9f3d1a99f62bc..051efdec5720e9c816d585384fa6a3c530069814 100644 --- a/contracts/simpledb/simpledb.gen.hpp +++ b/contracts/simpledb/simpledb.gen.hpp @@ -4,7 +4,7 @@ #include // These functions can be auto-generated using the ABI definition. -// The specialization for current_message must only be defined if the +// The specialization for current_action must only be defined if the // struct has at least one variable length type (String, bytes, etc), // otherwise the default function will do ok. // @@ -25,10 +25,10 @@ namespace eosio { T bytes_to_value(const bytes& bytes_val) { return *reinterpret_cast(bytes_val.data); } template<> - key_value1 current_message() { - uint32_t msgsize = message_size(); + key_value1 current_action() { + uint32_t msgsize = action_size(); char* buffer = (char *)eosio::malloc(msgsize); - assert(read_message(buffer, msgsize) == msgsize, "error reading key_value1"); + assert(read_action(buffer, msgsize) == msgsize, "error reading key_value1"); datastream ds(buffer, msgsize); key_value1 value; raw::unpack(ds, value.key); @@ -62,10 +62,10 @@ namespace eosio { } template<> - key_value2 current_message() { - uint32_t msgsize = message_size(); + key_value2 current_action() { + uint32_t msgsize = action_size(); char* buffer = (char *)eosio::malloc(msgsize); - assert(read_message(buffer, msgsize) == msgsize, "error reading key_value2"); + assert(read_action(buffer, msgsize) == msgsize, "error reading key_value2"); datastream ds(buffer, msgsize); key_value2 value; raw::unpack(ds, value.key); diff --git a/contracts/social/social.cpp b/contracts/social/social.cpp index a34c6a6b6938c9d4cccbecd1bd3c578daadc8d9c..c962bd99b2192810ff879543d93ee0e7d00b84d3 100644 --- a/contracts/social/social.cpp +++ b/contracts/social/social.cpp @@ -59,7 +59,7 @@ struct account { * any other contexts are notified */ void apply_social_post() { - const auto& post = current_message(); + const auto& post = current_action(); require_auth( post.author ); assert( current_context() == post.author, "cannot call from any other context" ); @@ -75,7 +75,7 @@ void apply_social_post() { * updates the vote total. When executed */ void apply_social_vote() { - const auto& vote = current_message(); + const auto& vote = current_action(); require_notice( vote.voter, vote.author ); disable_context_code( vote.author() ); /// prevent the author's code from rejecting the potentially negative vote diff --git a/contracts/storage/storage.cpp b/contracts/storage/storage.cpp index 4bffa7a3d4fe1255a172a98ec816b3d87d83a1a6..f07f1b4c8107f45075ab93a1b0684023a2d69c32 100644 --- a/contracts/storage/storage.cpp +++ b/contracts/storage/storage.cpp @@ -48,7 +48,7 @@ namespace TOKEN_NAME { uint32_t eospathlen; uint32_t ipfspathlen; char tmp[4098]; - auto bufferlen = read_message(tmp, 4098); + auto bufferlen = read_action(tmp, 4098); auto linklen = read_link_from_buffer( tmp, bufferlen, link_to_set, eospathlen, ipfspathlen ); eosio::require_notice( link_to_set.owner ); eosio::require_auth( link_to_set.owner ); @@ -109,20 +109,20 @@ extern "C" { void apply( uint64_t code, uint64_t action ) { if( code == N(storage) ) { if( action == N(transfer) ) { - TOKEN_NAME::apply_storage_transfer( eosio::current_message< TOKEN_NAME::transfer >() ); + TOKEN_NAME::apply_storage_transfer( eosio::current_action< TOKEN_NAME::transfer >() ); } else if (action == N(setlink) ) { TOKEN_NAME::apply_storage_setlink(); } else if (action == N(removelink) ) { char tmp[1025]; - auto len = read_message( tmp, 1025 ); + auto len = read_action( tmp, 1025 ); TOKEN_NAME::apply_storage_removelink( tmp, len ); } else if (action == N(acceptstore) ) { char tmp[1025]; - auto len = read_message( tmp, 1025 ); + auto len = read_action( tmp, 1025 ); TOKEN_NAME::apply_storage_createstore( tmp, len ); } else if (action == N(rejectstore) ) { char tmp[1025]; - auto len = read_message( tmp, 1025 ); + auto len = read_action( tmp, 1025 ); TOKEN_NAME::apply_storage_rejectstore( tmp, len ); } else { assert(0, "unknown message"); diff --git a/contracts/test_api/test_action.cpp b/contracts/test_api/test_action.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d199c63d4b0b5e31cfbe3e0eb1957ee29511f36e --- /dev/null +++ b/contracts/test_api/test_action.cpp @@ -0,0 +1,83 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include + +#include "test_api.hpp" + +unsigned int test_action::read_action_normal() { + + char buffer[100]; + uint32_t total = 0; + + WASM_ASSERT( current_code() == N(testapi), "current_code() == N(testapi)" ); + + WASM_ASSERT(action_size() == sizeof(dummy_action), "action_size() == sizeof(dummy_action)"); + + total = read_action(buffer, 30); + WASM_ASSERT(total == sizeof(dummy_action) , "read_action(30)" ); + + total = read_action(buffer, 100); + WASM_ASSERT(total == sizeof(dummy_action) , "read_action(100)" ); + + total = read_action(buffer, 5); + WASM_ASSERT(total == 5 , "read_action(5)" ); + + total = read_action(buffer, sizeof(dummy_action) ); + WASM_ASSERT(total == sizeof(dummy_action), "read_action(sizeof(dummy_action))" ); + + dummy_action *dummy13 = reinterpret_cast(buffer); + WASM_ASSERT(dummy13->a == DUMMY_MESSAGE_DEFAULT_A, "dummy13->a == DUMMY_MESSAGE_DEFAULT_A"); + WASM_ASSERT(dummy13->b == DUMMY_MESSAGE_DEFAULT_B, "dummy13->b == DUMMY_MESSAGE_DEFAULT_B"); + WASM_ASSERT(dummy13->c == DUMMY_MESSAGE_DEFAULT_C, "dummy13->c == DUMMY_MESSAGE_DEFAULT_C"); + + return WASM_TEST_PASS; +} + +unsigned int test_action::read_action_to_0() { + uint32_t total = read_action((void *)0, 0x7FFFFFFF); + return WASM_TEST_PASS; +} + +unsigned int test_action::read_action_to_64k() { + uint32_t total = read_action( (void *)((1<<16)-1), 0x7FFFFFFF); + return WASM_TEST_PASS; +} + +unsigned int test_action::require_notice() { + if( current_code() == N(testapi) ) { + eosio::require_notice( N(acc1) ); + eosio::require_notice( N(acc2) ); + eosio::require_notice( N(acc1), N(acc2) ); + return WASM_TEST_FAIL; + } else if ( current_code() == N(acc1) || current_code() == N(acc2) ) { + return WASM_TEST_PASS; + } + return WASM_TEST_FAIL; +} + +unsigned int test_action::require_auth() { + eosio::require_auth( N(acc3) ); + eosio::require_auth( N(acc4) ); + return WASM_TEST_PASS; +} + +unsigned int test_action::assert_false() { + assert(false, "test_action::assert_false"); + return WASM_TEST_PASS; +} + +unsigned int test_action::assert_true() { + assert(true, "test_action::assert_true"); + return WASM_TEST_PASS; +} + +unsigned int test_action::now() { + uint32_t tmp = 0; + uint32_t total = read_action(&tmp, sizeof(uint32_t)); + WASM_ASSERT( total == sizeof(uint32_t), "total == sizeof(uint32_t)"); + WASM_ASSERT( tmp == ::now(), "tmp == now()" ); + return WASM_TEST_PASS; +} + diff --git a/contracts/test_api/test_api.cpp b/contracts/test_api/test_api.cpp index f8db1354186bb8d3bcf95ec6083a2e9c6353cd52..b2f3c4dcafd168ab785681b225f72907c66d7a50 100644 --- a/contracts/test_api/test_api.cpp +++ b/contracts/test_api/test_api.cpp @@ -9,7 +9,7 @@ #include "test_crypto.cpp" #include "test_db.cpp" #include "test_math.cpp" -#include "test_message.cpp" +#include "test_action.cpp" #include "test_print.cpp" #include "test_string.cpp" #include "test_transaction.cpp" @@ -31,15 +31,15 @@ extern "C" { WASM_TEST_HANDLER(test_types, string_to_name); WASM_TEST_HANDLER(test_types, name_class); - //test_message - WASM_TEST_HANDLER(test_message, read_message_normal); - WASM_TEST_HANDLER(test_message, read_message_to_0); - WASM_TEST_HANDLER(test_message, read_message_to_64k); - WASM_TEST_HANDLER(test_message, require_notice); - WASM_TEST_HANDLER(test_message, require_auth); - WASM_TEST_HANDLER(test_message, assert_false); - WASM_TEST_HANDLER(test_message, assert_true); - WASM_TEST_HANDLER(test_message, now); + //test_action + WASM_TEST_HANDLER(test_action, read_action_normal); + WASM_TEST_HANDLER(test_action, read_action_to_0); + WASM_TEST_HANDLER(test_action, read_action_to_64k); + WASM_TEST_HANDLER(test_action, require_notice); + WASM_TEST_HANDLER(test_action, require_auth); + WASM_TEST_HANDLER(test_action, assert_false); + WASM_TEST_HANDLER(test_action, assert_true); + WASM_TEST_HANDLER(test_action, now); //test_print WASM_TEST_HANDLER(test_print, test_prints); diff --git a/contracts/test_api/test_api.hpp b/contracts/test_api/test_api.hpp index 1bad52b2513afcf7def57a2aa091a6624d0daebb..2a850d5b46f2f7e89e881b3bc75cfe72f5795c3b 100644 --- a/contracts/test_api/test_api.hpp +++ b/contracts/test_api/test_api.hpp @@ -34,7 +34,7 @@ static constexpr u64 WASM_TEST_ACTION(const char* cls, const char* method) } #pragma pack(push, 1) -struct dummy_message { +struct dummy_action { char a; //1 unsigned long long b; //8 int c; //4 @@ -45,7 +45,7 @@ struct u128_msg { }; #pragma pack(pop) -static_assert( sizeof(dummy_message) == 13 , "unexpected packing" ); +static_assert( sizeof(dummy_action) == 13 , "unexpected packing" ); static_assert( sizeof(u128_msg) == 16*3 , "unexpected packing" ); struct test_types { @@ -66,11 +66,11 @@ struct test_print { #define DUMMY_MESSAGE_DEFAULT_B 0xab11cd1244556677 #define DUMMY_MESSAGE_DEFAULT_C 0x7451ae12 -struct test_message { +struct test_action { - static unsigned int read_message_normal(); - static unsigned int read_message_to_0(); - static unsigned int read_message_to_64k(); + static unsigned int read_action_normal(); + static unsigned int read_action_to_0(); + static unsigned int read_action_to_64k(); static unsigned int require_notice(); static unsigned int require_auth(); static unsigned int assert_false(); diff --git a/contracts/test_api/test_chain.cpp b/contracts/test_api/test_chain.cpp index 1ea75561f97cd756ea24445aa3e3ca554a06fe67..34fbecfea864b3598a4ed5c8f42980a25583534b 100644 --- a/contracts/test_api/test_chain.cpp +++ b/contracts/test_api/test_chain.cpp @@ -2,7 +2,7 @@ * @file * @copyright defined in eos/LICENSE.txt */ -#include +#include #include #include "test_api.hpp" @@ -16,7 +16,7 @@ struct producers { unsigned int test_chain::test_activeprods() { producers msg_prods; - read_message(&msg_prods, sizeof(producers)); + read_action(&msg_prods, sizeof(producers)); WASM_ASSERT(msg_prods.len == 21, "producers.len != 21"); diff --git a/contracts/test_api/test_db.cpp b/contracts/test_api/test_db.cpp index 22ad8ea146bd924e1e057834177dc3bd9ba7b1e9..e69b79b35beb3e5ac3a6208ae27f6443948722a3 100644 --- a/contracts/test_api/test_db.cpp +++ b/contracts/test_api/test_db.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include "test_api.hpp" diff --git a/contracts/test_api/test_math.cpp b/contracts/test_api/test_math.cpp index e98be4a36d03d53eac719883da17937e59fbe538..5dbe95748c268fbdd94f52ed62cc496724e08c7c 100644 --- a/contracts/test_api/test_math.cpp +++ b/contracts/test_api/test_math.cpp @@ -1,12 +1,12 @@ #include -#include +#include #include #include "test_api.hpp" unsigned int test_math::test_multeq_i128() { u128_msg msg; - auto n = read_message(&msg, sizeof(u128_msg)); + auto n = read_action(&msg, sizeof(u128_msg)); WASM_ASSERT( n == sizeof(u128_msg), "test_multeq_i128 n == sizeof(u128_msg)" ); multeq_i128(msg.values, msg.values+1); WASM_ASSERT( msg.values[0] == msg.values[2], "test_multeq_i128 msg.values[0] == msg.values[2]" ); @@ -15,7 +15,7 @@ unsigned int test_math::test_multeq_i128() { unsigned int test_math::test_diveq_i128() { u128_msg msg; - auto n = read_message(&msg, sizeof(u128_msg)); + auto n = read_action(&msg, sizeof(u128_msg)); WASM_ASSERT( n == sizeof(u128_msg), "test_diveq_i128 n == sizeof(u128_msg)" ); diveq_i128(msg.values, msg.values+1); WASM_ASSERT( msg.values[0] == msg.values[2], "test_diveq_i128 msg.values[0] == msg.values[2]" ); diff --git a/contracts/test_api/test_message.cpp b/contracts/test_api/test_message.cpp deleted file mode 100644 index 7510d0b76be94decfc02dd8c25e01c898b357a60..0000000000000000000000000000000000000000 --- a/contracts/test_api/test_message.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include - -#include "test_api.hpp" - -unsigned int test_message::read_message_normal() { - - char buffer[100]; - uint32_t total = 0; - - WASM_ASSERT( current_code() == N(testapi), "current_code() == N(testapi)" ); - - WASM_ASSERT(message_size() == sizeof(dummy_message), "message_size() == sizeof(dummy_message)"); - - total = read_message(buffer, 30); - WASM_ASSERT(total == sizeof(dummy_message) , "read_message(30)" ); - - total = read_message(buffer, 100); - WASM_ASSERT(total == sizeof(dummy_message) , "read_message(100)" ); - - total = read_message(buffer, 5); - WASM_ASSERT(total == 5 , "read_message(5)" ); - - total = read_message(buffer, sizeof(dummy_message) ); - WASM_ASSERT(total == sizeof(dummy_message), "read_message(sizeof(dummy_message))" ); - - dummy_message *dummy13 = reinterpret_cast(buffer); - WASM_ASSERT(dummy13->a == DUMMY_MESSAGE_DEFAULT_A, "dummy13->a == DUMMY_MESSAGE_DEFAULT_A"); - WASM_ASSERT(dummy13->b == DUMMY_MESSAGE_DEFAULT_B, "dummy13->b == DUMMY_MESSAGE_DEFAULT_B"); - WASM_ASSERT(dummy13->c == DUMMY_MESSAGE_DEFAULT_C, "dummy13->c == DUMMY_MESSAGE_DEFAULT_C"); - - return WASM_TEST_PASS; -} - -unsigned int test_message::read_message_to_0() { - uint32_t total = read_message((void *)0, 0x7FFFFFFF); - return WASM_TEST_PASS; -} - -unsigned int test_message::read_message_to_64k() { - uint32_t total = read_message( (void *)((1<<16)-1), 0x7FFFFFFF); - return WASM_TEST_PASS; -} - -unsigned int test_message::require_notice() { - if( current_code() == N(testapi) ) { - eosio::require_notice( N(acc1) ); - eosio::require_notice( N(acc2) ); - eosio::require_notice( N(acc1), N(acc2) ); - return WASM_TEST_FAIL; - } else if ( current_code() == N(acc1) || current_code() == N(acc2) ) { - return WASM_TEST_PASS; - } - return WASM_TEST_FAIL; -} - -unsigned int test_message::require_auth() { - eosio::require_auth( N(acc3) ); - eosio::require_auth( N(acc4) ); - return WASM_TEST_PASS; -} - -unsigned int test_message::assert_false() { - assert(false, "test_message::assert_false"); - return WASM_TEST_PASS; -} - -unsigned int test_message::assert_true() { - assert(true, "test_message::assert_true"); - return WASM_TEST_PASS; -} - -unsigned int test_message::now() { - uint32_t tmp = 0; - uint32_t total = read_message(&tmp, sizeof(uint32_t)); - WASM_ASSERT( total == sizeof(uint32_t), "total == sizeof(uint32_t)"); - WASM_ASSERT( tmp == ::now(), "tmp == now()" ); - return WASM_TEST_PASS; -} - diff --git a/contracts/test_api/test_transaction.cpp b/contracts/test_api/test_transaction.cpp index 43b8411f219e0aa3d76d6f3f84f586ab51c6acee..55c9cbee67405b36b614166acc520f25092e15e8 100644 --- a/contracts/test_api/test_transaction.cpp +++ b/contracts/test_api/test_transaction.cpp @@ -3,19 +3,19 @@ * @copyright defined in eos/LICENSE.txt */ #include -#include +#include #include "test_api.hpp" unsigned int test_transaction::send_message() { - dummy_message payload = {DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; - auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_message", "read_message_normal"), &payload, sizeof(dummy_message)); + dummy_action payload = {DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; + auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), &payload, sizeof(dummy_action)); message_send(msg); return WASM_TEST_PASS; } unsigned int test_transaction::send_message_empty() { - auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_message", "assert_true"), nullptr, 0); + auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "assert_true"), nullptr, 0); message_send(msg); return WASM_TEST_PASS; } @@ -24,9 +24,9 @@ unsigned int test_transaction::send_message_empty() { * cause failure due to too many pending inline messages */ unsigned int test_transaction::send_message_max() { - dummy_message payload = {DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; + dummy_action payload = {DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; for (int i = 0; i < 10; i++) { - message_create(N(testapi), WASM_TEST_ACTION("test_message", "read_message_normal"), &payload, sizeof(dummy_message)); + message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), &payload, sizeof(dummy_action)); } return WASM_TEST_FAIL; @@ -37,7 +37,7 @@ unsigned int test_transaction::send_message_max() { */ unsigned int test_transaction::send_message_large() { char large_message[8 * 1024]; - message_create(N(testapi), WASM_TEST_ACTION("test_message", "read_message_normal"), large_message, sizeof(large_message)); + message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), large_message, sizeof(large_message)); return WASM_TEST_FAIL; } @@ -46,7 +46,7 @@ unsigned int test_transaction::send_message_large() { */ unsigned int test_transaction::send_message_recurse() { char buffer[1024]; - uint32_t size = read_message(buffer, 1024); + uint32_t size = read_action(buffer, 1024); auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_transaction", "send_message_recurse"), buffer, size); message_send(msg); return WASM_TEST_PASS; @@ -56,14 +56,14 @@ unsigned int test_transaction::send_message_recurse() { * cause failure due to inline TX failure */ unsigned int test_transaction::send_message_inline_fail() { - auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_message", "assert_false"), nullptr, 0); + auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "assert_false"), nullptr, 0); message_send(msg); return WASM_TEST_PASS; } unsigned int test_transaction::send_transaction() { - dummy_message payload = {DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; - auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_message", "read_message_normal"), &payload, sizeof(dummy_message)); + dummy_action payload = {DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; + auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), &payload, sizeof(dummy_action)); auto trx = transaction_create(); @@ -99,7 +99,7 @@ unsigned int test_transaction::send_transaction_large() { transaction_require_scope(trx, N(testapi)); for (int i = 0; i < 32; i ++) { char large_message[4 * 1024]; - auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_message", "read_message_normal"), large_message, sizeof(large_message)); + auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), large_message, sizeof(large_message)); transaction_add_message(trx, msg); } diff --git a/contracts/tic_tac_toe/tic_tac_toe.cpp b/contracts/tic_tac_toe/tic_tac_toe.cpp index 3b922e7fee621e761d0be39878a9b7dd846d3bb4..91621a48a17d8283b3cfcaa5e01d4478ae39f320 100644 --- a/contracts/tic_tac_toe/tic_tac_toe.cpp +++ b/contracts/tic_tac_toe/tic_tac_toe.cpp @@ -112,7 +112,7 @@ namespace tic_tac_toe { bool game_exists = Games::get(restart.challenger, game_to_restart, restart.host); assert(game_exists == true, "game doesn't exist!"); - // Check if this game belongs to the message sender + // Check if this game belongs to the action sender assert(restart.by == game_to_restart.host || restart.by == game_to_restart.challenger, "this is not your game!"); // Reset game @@ -150,9 +150,9 @@ namespace tic_tac_toe { // Check if this game hasn't ended yet assert(game_to_move.winner == N(none), "the game has ended!"); - // Check if this game belongs to the message sender + // Check if this game belongs to the action sender assert(move.by == game_to_move.host || move.by == game_to_move.challenger, "this is not your game!"); - // Check if this is the message sender's turn + // Check if this is the action sender's turn assert(move.by == game_to_move.turn, "it's not your turn yet!"); @@ -194,13 +194,13 @@ extern "C" { void apply( uint64_t code, uint64_t action ) { if (code == N(tic.tac.toe)) { if (action == N(create)) { - tic_tac_toe::apply_create(current_message()); + tic_tac_toe::apply_create(current_action()); } else if (action == N(restart)) { - tic_tac_toe::apply_restart(current_message()); + tic_tac_toe::apply_restart(current_action()); } else if (action == N(close)) { - tic_tac_toe::apply_close(current_message()); + tic_tac_toe::apply_close(current_action()); } else if (action == N(move)) { - tic_tac_toe::apply_move(current_message()); + tic_tac_toe::apply_move(current_action()); } } } diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 3febd9d1493573439a51e487db8ffa6a3ff68cef..d7fd0d265e3b38c1b4c67116b953f9cbf2e4a604 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -16,7 +16,7 @@ void apply_context::exec() auto code = mutable_controller.get_wasm_cache().checkout_scoped(a.code_version, a.code.data(), a.code.size()); // get wasm_interface - auto &wasm = wasm_interface::get(); + auto& wasm = wasm_interface::get(); wasm.apply(code, *this); } } diff --git a/libraries/chain/contracts/eosio_contract.cpp b/libraries/chain/contracts/eosio_contract.cpp index 43fabf0768b90e844097dba96a1f9c72232ae344..3aeef8129e3dc3d66abb31a45d6a8629f93a4938 100644 --- a/libraries/chain/contracts/eosio_contract.cpp +++ b/libraries/chain/contracts/eosio_contract.cpp @@ -187,6 +187,7 @@ void apply_eosio_setcode(apply_context& context) { auto act = context.act.as(); context.require_authorization(act.account); + context.require_write_scope( config::eosio_auth_scope ); FC_ASSERT( act.vmtype == 0 ); FC_ASSERT( act.vmversion == 0 ); diff --git a/libraries/chain/include/eosio/chain/contracts/types.hpp b/libraries/chain/include/eosio/chain/contracts/types.hpp index 549594c08962c693851f09a99c4a52ae5fee0aaa..e267a322c6733835e839a38907ec3d4bf3e9a556 100644 --- a/libraries/chain/include/eosio/chain/contracts/types.hpp +++ b/libraries/chain/include/eosio/chain/contracts/types.hpp @@ -197,14 +197,16 @@ struct newaccount { }; struct setcode { + /* setcode() = default; - setcode(const account_name& account, const uint8& vmtype, const uint8& vmversion, const bytes& code/*, const abi& abi*/) + setcode(const account_name& account, const uint8& vmtype, const uint8& vmversion, const bytes& code) :account(account), vmtype(vmtype), vmversion(vmversion), code(code)//, abi(abi) {} + */ account_name account; - uint8 vmtype; - uint8 vmversion; + uint8 vmtype; + uint8 vmversion; bytes code; static scope_name get_scope() { diff --git a/libraries/chain/include/eosio/chain/wasm_interface.hpp b/libraries/chain/include/eosio/chain/wasm_interface.hpp index 66794b6ab39d5aa4ecebe92c29405ff83b4c5e81..cac9ed51f1a3423e7a126993035858db9ded9dd2 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface.hpp @@ -50,7 +50,7 @@ namespace eosio { namespace chain { * RAII wrapper to make sure that the cache entries are returned regardless of exceptions etc */ struct scoped_entry { - explicit scoped_entry(const digest_type& code_id, entry &code, wasm_cache &cache) + explicit scoped_entry(const digest_type& code_id, entry& code, wasm_cache& cache) :code_id(code_id) ,code(code) ,cache(cache) diff --git a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp index b60f9dbbe813d2be3b2c5ab5a99aed4e8446dc28..b87b5cd5b53cfda4dbfb23c466520ba0b5b51004 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp @@ -29,7 +29,7 @@ struct wasm_context { struct wasm_interface_impl { optional current_context; - void call(const string& entry_point, const vector& args, wasm_cache::entry& code, apply_context &context); + void call(const string& entry_point, const vector& args, wasm_cache::entry& code, apply_context& context); }; class intrinsics_accessor { @@ -113,6 +113,8 @@ template<> struct wasm_to_rvalue_type { static constexpr auto value = Resu template constexpr auto wasm_to_rvalue_type_v = wasm_to_rvalue_type::value; +struct void_type{}; + /** * Forward delclaration of the invoker type which transcribes arguments to/from a native method * and injects the appropriate checks @@ -135,15 +137,16 @@ struct intrinsic_invoker_impl, std::tuple> { return FunctionType::get(wasm_to_rvalue_type_v, { wasm_to_value_type_v ... }); } - using wasm_method_type = Ret (*)(wasm_interface&, Translated...); + using next_method_type = Ret (*)(wasm_interface&, Translated...); + using intrinsic_method_type = Ret (*)(Translated...); - template + template static Ret invoke(Translated... translated) { wasm_interface& wasm = wasm_interface::get(); return native_to_wasm_t(Method(wasm, translated...)); } - template + template static const auto fn() { return invoke; } @@ -154,20 +157,21 @@ struct intrinsic_invoker_impl, std::tuple> { * @tparam Translated - the arguments to the wasm function */ template -struct intrinsic_invoker_impl, std::tuple> { +struct intrinsic_invoker_impl, std::tuple> { static const FunctionType* wasm_function_type() { return FunctionType::get(ResultType::none, { wasm_to_value_type_v ... }); } - using wasm_method_type = void (*)(wasm_interface&, Translated...); + using next_method_type = void_type (*)(wasm_interface&, Translated...); + using intrinsic_method_type = void (*)(Translated...); - template + template static void invoke(Translated... translated) { wasm_interface& wasm = wasm_interface::get(); Method(wasm, translated...); } - template + template static const auto fn() { return invoke; } @@ -184,8 +188,11 @@ template, std::tuple> { using translated_type = native_to_wasm_t; using next_step = intrinsic_invoker_impl, std::tuple>; - static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); } using then_type = Ret (*)(wasm_interface&, Input, Inputs..., Translated...); + using intrinsic_method_type = typename next_step::intrinsic_method_type; + + static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); } + template static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, translated_type last) { @@ -211,8 +218,10 @@ struct intrinsic_invoker_impl, std::tuple struct intrinsic_invoker_impl, size_t, Inputs...>, std::tuple> { using next_step = intrinsic_invoker_impl, std::tuple>; - static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); } using then_type = Ret(*)(wasm_interface&, array_ptr, size_t, Inputs..., Translated...); + using intrinsic_method_type = typename next_step::intrinsic_method_type; + + static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); } template static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, I32 ptr, I32 size) { @@ -240,8 +249,10 @@ struct intrinsic_invoker_impl, size_t, Inputs...>, template struct intrinsic_invoker_impl, std::tuple> { using next_step = intrinsic_invoker_impl, std::tuple>; - static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); } using then_type = Ret (*)(wasm_interface&, T*, Inputs..., Translated...); + using intrinsic_method_type = typename next_step::intrinsic_method_type; + + static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); } template static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, I32 ptr) { @@ -252,7 +263,7 @@ struct intrinsic_invoker_impl, std::tuple static const auto fn() { - return next_step::template fn>; + return next_step::template fn>(); } }; @@ -268,8 +279,10 @@ struct intrinsic_invoker_impl, std::tuple struct intrinsic_invoker_impl, std::tuple> { using next_step = intrinsic_invoker_impl, std::tuple>; - static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); } using then_type = Ret (*)(wasm_interface&, T&, Inputs..., Translated...); + using intrinsic_method_type = typename next_step::intrinsic_method_type; + + static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); } template static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, I32 ptr) { @@ -282,7 +295,7 @@ struct intrinsic_invoker_impl, std::tuple static const auto fn() { - return next_step::template fn>; + return next_step::template fn>(); } }; @@ -295,6 +308,8 @@ struct intrinsic_function_invoker; template struct intrinsic_function_invoker { using impl = intrinsic_invoker_impl, std::tuple<>>; + using intrinsic_method_type = typename impl::intrinsic_method_type; + static const FunctionType* wasm_function_type() { return impl::wasm_function_type(); } template< Ret (Cls::*Method)(Params...) > @@ -303,21 +318,38 @@ struct intrinsic_function_invoker { } template< Ret (Cls::*Method)(Params...) > - static const auto fn() { + static const intrinsic_method_type fn() { + return impl::template fn>(); + } +}; + +template +struct intrinsic_function_invoker { + using impl = intrinsic_invoker_impl, std::tuple<>>; + using intrinsic_method_type = typename impl::intrinsic_method_type; + + static const FunctionType* wasm_function_type() { return impl::wasm_function_type(); } + + template< void (Cls::*Method)(Params...) > + static void_type wrapper(wasm_interface& wasm, Params... params) { + (Cls(wasm).*Method)(params...); + return void_type(); + } + + template< void (Cls::*Method)(Params...) > + static const intrinsic_method_type fn() { return impl::template fn>(); } }; -#define _REGISTER_INTRINSIC(R, DATA, METHOD)\ - BOOST_PP_TUPLE_ELEM(2, 0, DATA).emplace( #METHOD, \ - std::make_unique(\ - #METHOD,\ - eosio::chain::intrinsic_function_invoker::wasm_function_type(),\ - (void *)eosio::chain::intrinsic_function_invoker::fn<&BOOST_PP_TUPLE_ELEM(2, 1, DATA)::METHOD>()\ - )\ +#define _REGISTER_INTRINSIC(R, CLS, METHOD)\ + static Intrinsics::Function BOOST_PP_CAT(__intrinsic_fn_, __COUNTER__)(\ + "env." BOOST_PP_STRINGIZE(METHOD),\ + eosio::chain::intrinsic_function_invoker::wasm_function_type(),\ + (void *)eosio::chain::intrinsic_function_invoker::fn<&CLS::METHOD>()\ ); -#define REGISTER_INTRINSICS(DATA, MEMBERS)\ - BOOST_PP_SEQ_FOR_EACH(_REGISTER_INTRINSIC, DATA, MEMBERS) +#define REGISTER_INTRINSICS(CLS, MEMBERS)\ + BOOST_PP_SEQ_FOR_EACH(_REGISTER_INTRINSIC, CLS, MEMBERS) } }; \ No newline at end of file diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index c515671d17240978419ae81727b578518438036b..3ed03ded498c5fdf0a8152eab8b36cf89a1ca57c 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -12,7 +12,6 @@ #include "Runtime/Runtime.h" #include "Runtime/Linker.h" #include "Runtime/Intrinsics.h" -#include "IR/Module.h" #include "IR/Operators.h" #include "IR/Validate.h" #include "IR/Types.h" @@ -31,8 +30,9 @@ using boost::asio::io_service; namespace eosio { namespace chain { - FunctionInstance *resolve_intrinsic(const string& name); - + /** + * Integration with the WASM Linker to resolve our intrinsics + */ struct root_resolver : Runtime::Resolver { bool resolve(const string& mod_name, @@ -40,15 +40,12 @@ namespace eosio { namespace chain { ObjectType type, ObjectInstance*& out) override { - if (mod_name == "env" && type.kind == ObjectKind::function ) { - try { - auto* intrinsic = resolve_intrinsic(export_name); - if (intrinsic != nullptr) { - out = asObject(intrinsic); - return true; - } - } FC_RETHROW_EXCEPTIONS(error, "unresolvable symbol ${module}.${export}", ("module",mod_name)("export",export_name)); + // Try to resolve an intrinsic first. + if(IntrinsicResolver::singleton.resolve(mod_name,export_name,type, out)) { + return true; } + + FC_ASSERT( !"unresolvable", "${module}.${export}", ("module",mod_name)("export",export_name) ); return false; } }; @@ -63,6 +60,8 @@ namespace eosio { namespace chain { :_ios() ,_work(_ios) { + Runtime::init(); + _utility_thread = std::thread([](io_service* ios){ ios->run(); }, &_ios); @@ -147,7 +146,7 @@ namespace eosio { namespace chain { return with_lock([&,this](){ auto iter = _cache.find(code_id); if (iter != _cache.end() && iter->second.available_instances > 0) { - auto &ptr = iter->second.instances.at(iter->second.available_instances--); + auto &ptr = iter->second.instances.at(--(iter->second.available_instances)); return optional_entry_ref(*ptr); } @@ -186,7 +185,8 @@ namespace eosio { namespace chain { try { Serialization::MemoryInputStream stream((const U8 *) wasm_binary, wasm_binary_size); - WASM::serializeWithInjection(stream, *module); + #warning TODO: restore checktime injection? + WASM::serialize(stream, *module); root_resolver resolver; LinkResult link_result = linkModule(*module, resolver); @@ -262,7 +262,7 @@ namespace eosio { namespace chain { * @param entry - the entry to return */ void return_entry(const digest_type& code_id, wasm_cache::entry& entry) { - _ios.post([&,this](){ + _ios.post([&,code_id,this](){ // sanitize by reseting the memory that may now be dirty auto& info = (*fetch_info(code_id)).get(); char* memstart = &memoryRef( getDefaultMemory(entry.instance), 0 ); @@ -338,7 +338,7 @@ namespace eosio { namespace chain { optional& context; }; - void wasm_interface_impl::call(const string& entry_point, const vector& args, wasm_cache::entry& code, apply_context &context) + void wasm_interface_impl::call(const string& entry_point, const vector& args, wasm_cache::entry& code, apply_context& context) try { FunctionInstance* call = asFunctionNullable(getInstanceExport(code.instance,entry_point) ); if( !call ) { @@ -361,9 +361,6 @@ namespace eosio { namespace chain { } wasm_interface& wasm_interface::get() { - static bool init_once = [](){ Runtime::init(); return true; }(); - boost::ignore_unused(init_once); - thread_local wasm_interface* single = nullptr; if( !single ) { single = new wasm_interface(); @@ -528,24 +525,24 @@ DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) { #endif #if defined(assert) -#undef assert + #undef assert #endif class intrinsics { public: - intrinsics(wasm_interface &wasm) + intrinsics(wasm_interface& wasm) :wasm(wasm) ,context(intrinsics_accessor::get_context(wasm).context) {} int read_action(array_ptr memory, size_t size) { FC_ASSERT(size > 0); - int minlen = std::min(context.act.data.size(), size); + int minlen = std::min(context.act.data.size(), size); memcpy((void *)memory, context.act.data.data(), minlen); return minlen; } - void assert(bool condition, char const* str) { + void assert(bool condition, char* str) { std::string message( str ); if( !condition ) edump((message)); FC_ASSERT( condition, "assertion failed: ${s}", ("s",message)); @@ -556,23 +553,6 @@ class intrinsics { apply_context& context; }; -static map> intrinsic_registry; -static void lazy_register_intrinsics() -{ - if (intrinsic_registry.size() !=0 ) { - return; - } - REGISTER_INTRINSICS((intrinsic_registry, intrinsics), (read_action)(assert)); -}; - -FunctionInstance *resolve_intrinsic(const string& name) { - lazy_register_intrinsics(); - auto iter = intrinsic_registry.find(name); - if (iter != intrinsic_registry.end()) { - return (iter->second)->function; - } - - return nullptr; -} +REGISTER_INTRINSICS(intrinsics, (read_action)(assert)); } } /// eosio::chain diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 7279a6e122c222cf026d44a70b3bd4ba95d62941..72d1a9350dc56200123298ce69f10d9b23e4aaa8 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -45,11 +45,20 @@ namespace eosio { namespace testing { public_key_type get_public_key( name keyname, string role = "owner" ); private_key_type get_private_key( name keyname, string role = "owner" ); + void set_code( account_name name, const char* wast ); + + unique_ptr control; + bool chain_has_transaction( const transaction_id_type& txid ) const; + const transaction_receipt& get_transaction_receipt( const transaction_id_type& txid ) const; + + private: - fc::temp_directory tempdir; - chain_controller::controller_config cfg; + fc::temp_directory tempdir; + chain_controller::controller_config cfg; + + map chain_transactions; }; } } /// eosio::testing diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index 20647b2e9e62f2ec1636a07e5be602cf63e2b973..bfea334f2b652a75aa9f79514c384015f5191d02 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -2,8 +2,14 @@ #include #include -namespace eosio { namespace testing { +#include + +#include "WAST/WAST.h" +#include "WASM/WASM.h" +#include "IR/Module.h" +#include "IR/Validate.h" +namespace eosio { namespace testing { tester::tester() { cfg.block_log_dir = tempdir.path() / "blocklog"; @@ -41,9 +47,21 @@ namespace eosio { namespace testing { void tester::close() { control.reset(); + chain_transactions.clear(); } void tester::open() { control.reset( new chain_controller(cfg) ); + chain_transactions.clear(); + // this will not index generated transactions + control->applied_block.connect([this]( const signed_block& block ){ + for( const auto& cycle : block.cycles_summary ) { + for ( const auto& shard : cycle ) { + for( const auto& receipt: shard ) { + chain_transactions.emplace(receipt.id, receipt); + } + } + } + }); } signed_block tester::produce_block( fc::microseconds skip_time ) { @@ -134,4 +152,72 @@ namespace eosio { namespace testing { control->push_transaction( trx ); } FC_CAPTURE_AND_RETHROW( (account)(perm)(auth)(parent) ) } + void tester::set_code( account_name account, const char* wast ) try { + const auto assemble = [](const char* wast) -> vector { + using namespace IR; + using namespace WAST; + using namespace WASM; + using namespace Serialization; + + Module module; + vector parse_errors; + parseModule(wast, fc::const_strlen(wast), module, parse_errors); + if (!parse_errors.empty()) { + fc::exception parse_exception( + FC_LOG_MESSAGE(warn, "Failed to parse WAST"), + fc::std_exception_code, + "wast_parse_error", + "Failed to parse WAST" + ); + + for (const auto& err: parse_errors) { + parse_exception.append_log( FC_LOG_MESSAGE(error, ":${desc}: ${message}", ("desc", err.locus.describe())("message", err.message.c_str()) ) ); + parse_exception.append_log( FC_LOG_MESSAGE(error, string(err.locus.column(8), ' ') + "^" )); + } + + throw parse_exception; + } + + try { + // Serialize the WebAssembly module. + ArrayOutputStream stream; + serialize(stream,module); + return stream.getBytes(); + } catch(const FatalSerializationException& ex) { + fc::exception serialize_exception ( + FC_LOG_MESSAGE(warn, "Failed to serialize wasm: ${message}", ("message", ex.message)), + fc::std_exception_code, + "wasm_serialization_error", + "Failed to serialize WASM" + ); + throw serialize_exception; + } + }; + + auto wasm = assemble(wast); + + signed_transaction trx; + trx.write_scope = {config::eosio_auth_scope}; + trx.actions.emplace_back( vector{{account,config::active_name}}, + contracts::setcode{ + .account = account, + .vmtype = 0, + .vmversion = 0, + .code = bytes(wasm.begin(), wasm.end()) + }); + + set_tapos( trx ); + trx.sign( get_private_key( account, "active" ), chain_id_type() ); + control->push_transaction( trx ); + } FC_CAPTURE_AND_RETHROW( (account)(wast) ) + + bool tester::chain_has_transaction( const transaction_id_type& txid ) const { + return chain_transactions.count(txid) != 0; + } + + const transaction_receipt& tester::get_transaction_receipt( const transaction_id_type& txid ) const { + return chain_transactions.at(txid); + } + + } } /// eosio::test diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ceedd24806c824aff7931a73de1bbf797e1d9c8f..9bd34426c97e84bb2b26ead95a13d2a94343e8a7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -24,8 +24,13 @@ endif() file(GLOB UNIT_TESTS "chain_tests/*.cpp") -add_executable( chain_test ${UNIT_TESTS} common/main.cpp ) +if(WASM_TOOLCHAIN) + file(GLOB WASM_UNIT_TESTS "wasm_tests/*.cpp") +endif() + +add_executable( chain_test ${UNIT_TESTS} ${WASM_UNIT_TESTS} common/main.cpp ) target_link_libraries( chain_test eosio_testing eosio_chain chainbase eos_utilities eos_egenesis_none chain_plugin fc ${PLATFORM_SPECIFIC_LIBS} ) + if(WASM_TOOLCHAIN) target_include_directories( chain_test PUBLIC ${CMAKE_BINARY_DIR}/contracts ${CMAKE_CURRENT_BINARY_DIR}/tests/contracts ) # add_dependencies(chain_test rate_limit_auth) diff --git a/tests/wasm_tests/wasm_tests.cpp b/tests/wasm_tests/wasm_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2ada101a3bf0fd9ca0c952dee403b87568fb4e0 --- /dev/null +++ b/tests/wasm_tests/wasm_tests.cpp @@ -0,0 +1,120 @@ +#include +#include +#include + +using namespace eosio; +using namespace eosio::chain; +using namespace eosio::chain::contracts; +using namespace eosio::testing; + +struct assertdef { + int8_t condition; + string message; + + static scope_name get_scope() { + return N(asserter); + } + + static action_name get_name() { + return N(procassert); + } +}; + +FC_REFLECT(assertdef, (condition)(message)); + +struct provereset { + static scope_name get_scope() { + return N(asserter); + } + + static action_name get_name() { + return N(provereset); + } +}; + +FC_REFLECT_EMPTY(provereset); + +BOOST_AUTO_TEST_SUITE(wasm_tests) + +/** + * Prove that action reading and assertions are working + */ +BOOST_FIXTURE_TEST_CASE( basic_test, tester ) try { + produce_blocks(2); + + create_accounts( {N(asserter)} ); + transfer( N(inita), N(asserter), "10.0000 EOS", "memo" ); + produce_block(); + + set_code(N(asserter), asserter_wast); + produce_blocks(1); + + transaction_id_type no_assert_id; + { + signed_transaction trx; + trx.actions.emplace_back( vector{{N(asserter),config::active_name}}, + assertdef {1, "Should Not Assert!"} ); + + set_tapos( trx ); + trx.sign( get_private_key( N(asserter), "active" ), chain_id_type() ); + control->push_transaction( trx ); + no_assert_id = trx.id(); + } + + produce_blocks(1); + + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(no_assert_id)); + const auto& receipt = get_transaction_receipt(no_assert_id); + BOOST_CHECK_EQUAL(transaction_receipt::executed, receipt.status); + + transaction_id_type yes_assert_id; + { + signed_transaction trx; + trx.actions.emplace_back( vector{{N(asserter),config::active_name}}, + assertdef {0, "Should Assert!"} ); + + set_tapos( trx ); + trx.sign( get_private_key( N(asserter), "active" ), chain_id_type() ); + BOOST_CHECK_THROW(control->push_transaction( trx ), fc::assert_exception); + yes_assert_id = trx.id(); + } + + produce_blocks(1); + + BOOST_REQUIRE_EQUAL(false, chain_has_transaction(yes_assert_id)); + +} FC_LOG_AND_RETHROW() /// basic_test + +/** + * Prove the modifications to global variables are wiped between runs + */ +BOOST_FIXTURE_TEST_CASE( prove_mem_reset, tester ) try { + produce_blocks(2); + + create_accounts( {N(asserter)} ); + transfer( N(inita), N(asserter), "10.0000 EOS", "memo" ); + produce_block(); + + set_code(N(asserter), asserter_wast); + produce_blocks(1); + + // repeat the action multiple times, each time the action handler checks for the expected + // default value then modifies the value which should not survive until the next invoction + for (int i = 0; i < 5; i++) { + signed_transaction trx; + trx.actions.emplace_back( vector{{N(asserter),config::active_name}}, + provereset {} ); + + set_tapos( trx ); + trx.sign( get_private_key( N(asserter), "active" ), chain_id_type() ); + control->push_transaction( trx ); + produce_blocks(1); + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); + const auto& receipt = get_transaction_receipt(trx.id()); + BOOST_CHECK_EQUAL(transaction_receipt::executed, receipt.status); + } + +} FC_LOG_AND_RETHROW() /// prove_mem_reset + + +BOOST_AUTO_TEST_SUITE_END()