提交 b799fed2 编写于 作者: B Bart Wyatt

Added test for basic wasm contract loading/unloading. Fixed bugs in the...

Added test for basic wasm contract loading/unloading.  Fixed bugs in the intrinsic code and made it impossible to complile with the same class of bugs in the future.  Did some basic style/renaming in the contracts directory and in the enclosed tutorial/doxygen files
上级 89ad9777
add_subdirectory(asserter)
add_subdirectory(currency) add_subdirectory(currency)
add_subdirectory(exchange) add_subdirectory(exchange)
add_subdirectory(infinite) add_subdirectory(infinite)
......
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
{
"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": []
}
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <asserter/asserter.hpp> /// 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<assertdef *>(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;
}
}
}
}
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eoslib/eos.hpp>
namespace asserter {
struct PACKED(assertdef) {
int8_t condition;
int8_t message_length;
char message[];
};
}
\ No newline at end of file
...@@ -46,7 +46,7 @@ extern "C" { ...@@ -46,7 +46,7 @@ extern "C" {
void apply( uint64_t code, uint64_t action ) { void apply( uint64_t code, uint64_t action ) {
if( code == N(currency) ) { if( code == N(currency) ) {
if( action == N(transfer) ) if( action == N(transfer) )
TOKEN_NAME::apply_currency_transfer( current_message< TOKEN_NAME::transfer >() ); TOKEN_NAME::apply_currency_transfer( current_action< TOKEN_NAME::transfer >() );
} }
} }
} }
...@@ -104,7 +104,7 @@ namespace native { ...@@ -104,7 +104,7 @@ namespace native {
<h3> Required Recipients </h3> <h3> Required Recipients </h3>
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. other contracts are notified anytime EOS tokens are transferred.
*/ */
......
...@@ -47,10 +47,10 @@ extern "C" { ...@@ -47,10 +47,10 @@ extern "C" {
* // } * // }
* *
* char buffer[128]; * 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 * 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 * print(msgsize); // Output: size of the above message's data field
* *
* require_notice(N(initc)); // initc account will be notified for this message * require_notice(N(initc)); // initc account will be notified for this message
...@@ -79,7 +79,7 @@ extern "C" { ...@@ -79,7 +79,7 @@ extern "C" {
* @param len - len of the current message to be copied * @param len - len of the current message to be copied
* @return the number of bytes copied to msg * @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 * Get the length of the current message's data field
...@@ -87,7 +87,7 @@ extern "C" { ...@@ -87,7 +87,7 @@ extern "C" {
* @brief Get the length of current message's data field * @brief Get the length of current message's data field
* @return the length of the 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 * Add the specified account to set of accounts to be notified
......
...@@ -3,43 +3,43 @@ ...@@ -3,43 +3,43 @@
* @copyright defined in eos/LICENSE.txt * @copyright defined in eos/LICENSE.txt
*/ */
#pragma once #pragma once
#include <eoslib/message.h> #include <eoslib/action.h>
#include <eoslib/print.hpp> #include <eoslib/print.hpp>
namespace eosio { namespace eosio {
/** /**
* @defgroup messagecppapi Message C++ API * @defgroup actioncppapi Action C++ API
* @ingroup messageapi * @ingroup actionapi
* @brief Type-safe C++ wrapers for Message C API * @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 * This method attempts to reinterpret the action 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. * 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: * Example:
* @code * @code
* struct dummy_message { * struct dummy_action {
* char a; //1 * char a; //1
* unsigned long long b; //8 * unsigned long long b; //8
* int c; //4 * int c; //4
* }; * };
* dummy_message msg = current_message<dummy_message>(); * dummy_action msg = current_action<dummy_action>();
* @endcode * @endcode
*/ */
template<typename T> template<typename T>
T current_message() { T current_action() {
T value; T value;
auto read = read_message( &value, sizeof(value) ); auto read = read_action( &value, sizeof(value) );
assert( read >= sizeof(value), "message shorter than expected" ); assert( read >= sizeof(value), "action shorter than expected" );
return value; return value;
} }
...@@ -52,7 +52,7 @@ namespace eosio { ...@@ -52,7 +52,7 @@ namespace eosio {
* This helper method enables you to add multiple accounts to accounts to be notified list with a single * 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. * 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 * @brief Verify specified accounts exist in the set of notified accounts
* *
...@@ -68,6 +68,6 @@ namespace eosio { ...@@ -68,6 +68,6 @@ namespace eosio {
} }
///@} messagecpp api ///@} actioncpp api
} // namespace eos } // namespace eos
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
void apply( uint64_t code, uint64_t action ) { void apply( uint64_t code, uint64_t action ) {
if( code == N(currency) ) { if( code == N(currency) ) {
if( action == N(transfer) ) if( action == N(transfer) )
currency::apply_currency_transfer( currentMessage< currency::Transfer >() ); currency::apply_currency_transfer( currentAction< currency::Transfer >() );
} else { } else {
assert( false, "rejecting unexpected event" ); assert( false, "rejecting unexpected event" );
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
*/ */
#pragma once #pragma once
#include <eoslib/types.hpp> #include <eoslib/types.hpp>
#include <eoslib/message.hpp> #include <eoslib/action.hpp>
#include <eoslib/print.hpp> #include <eoslib/print.hpp>
#include <eoslib/math.hpp> #include <eoslib/math.hpp>
#include <eoslib/transaction.hpp> #include <eoslib/transaction.hpp>
......
/** /**
@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 @brief Tool for sending transactions and querying state from @ref eosd
@section contents Table of Contents @section contents Table of Contents
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
- [Transfer EOS](#transfereos) - [Transfer EOS](#transfereos)
- [Getting Transaction](#gettingtransaction) - [Getting Transaction](#gettingtransaction)
- [Creating a Contract](#createcontract) - [Creating a Contract](#createcontract)
- [Pushing Message to Contract](#pushmessage) - [Pushing Actions to Contracts](#pushaction)
- [Querying Contract](#querycontract) - [Querying Contract](#querycontract)
- [Connecting to Particular Node](#particularnode) - [Connecting to Particular Node](#particularnode)
- [Using Separate Wallet App](#separatewallet) - [Using Separate Wallet App](#separatewallet)
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
@section intro Introduction to EOSC @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'. 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' 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 @@ ...@@ -41,7 +41,7 @@
After starting `eosd` you should be able to query the current blockchain state like so: 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, "head_block_num": 25048,
"last_irreversible_block_num": 25027, "last_irreversible_block_num": 25027,
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
Any transaction sent to the blockchain will need to be signed by the respective authority's private key. 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. 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 Creating wallet: default
Save password to use in the future to unlock this wallet. Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable. Without password imported keys will not be retrievable.
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
You can create multiple wallets by specifying unique name 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 Creating wallet: second-wallet
Save password to use in the future to unlock this wallet. Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable. Without password imported keys will not be retrievable.
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
And you will be see it in the list of your wallets And you will be see it in the list of your wallets
``` ```
$ ./eosc wallet list $ ./eosioc wallet list
Wallets: Wallets:
[ [
"default *", "default *",
...@@ -92,12 +92,12 @@ ...@@ -92,12 +92,12 @@
Import the key that you want to use to sign the transaction to your wallet. 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) 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 imported private key for: EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
``` ```
You will then be able to see the list of imported private keys and their respective public key 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", "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3" "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"
...@@ -109,12 +109,12 @@ ...@@ -109,12 +109,12 @@
To keep your private key safe, lock your wallet To keep your private key safe, lock your wallet
``` ```
$ ./eosc wallet lock -n second-wallet $ ./eosioc wallet lock -n second-wallet
Locked: 'second-wallet' Locked: 'second-wallet'
``` ```
Notice that the locked wallet doesn't have * symbol in the list Notice that the locked wallet doesn't have * symbol in the list
``` ```
$ ./eosc wallet list $ ./eosioc wallet list
Wallets: Wallets:
[ [
"default *", "default *",
...@@ -123,22 +123,22 @@ ...@@ -123,22 +123,22 @@
``` ```
To unlock it specify the password you get when creating the wallet 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' Unlocked: 'second-wallet'
``` ```
@section openwallet Opening Wallet @section openwallet Opening Wallet
All of the wallets data are store inside data_dir folder. 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: [] Wallets: []
$ ./eosc wallet open $ ./eosioc wallet open
Wallets: [ Wallets: [
"default" "default"
] ]
$ ./eosc wallet open -n second-wallet $ ./eosioc wallet open -n second-wallet
Wallets: [ Wallets: [
"default", "default",
"second-wallet" "second-wallet"
...@@ -148,23 +148,23 @@ ...@@ -148,23 +148,23 @@
@section createaccount Creating an Account @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, This will be your owner key,
``` ```
$ ./eosc create key $ ./eosioc create key
public: EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq public: EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq
private: 5JKbLfCXgcafDQVwHMm3shHt6iRWgrr9adcmt6vX3FNjAEtJGaT private: 5JKbLfCXgcafDQVwHMm3shHt6iRWgrr9adcmt6vX3FNjAEtJGaT
``` ```
And this will be your active key, And this will be your active key,
``` ```
$ ./eosc create key $ ./eosioc create key
public: EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA public: EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA
private: 5Hv22aPcjnENBv6X9o9nKGdkfrW44En6z4zJUt2PobAvbQXrT9z 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 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. to create `tester` using the owner and active keys created above. `inita` was specified in the genesis file.
...@@ -173,7 +173,7 @@ ...@@ -173,7 +173,7 @@
Then create an account called tester Then create an account called tester
``` ```
$ ./eosc create account inita tester EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA $ ./eosioc create account inita tester EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA
{ {
"transaction_id": "6acd2ece68c4b86c1fa209c3989235063384020781f2c67bbb80bc8d540ca120", "transaction_id": "6acd2ece68c4b86c1fa209c3989235063384020781f2c67bbb80bc8d540ca120",
"processed": { "processed": {
...@@ -185,7 +185,7 @@ ...@@ -185,7 +185,7 @@
"inita" "inita"
], ],
"signatures": [], "signatures": [],
"messages": [{ "actions": [{
"code": "eos", "code": "eos",
"type": "newaccount", "type": "newaccount",
"authorization": [{ "authorization": [{
...@@ -207,7 +207,7 @@ ...@@ -207,7 +207,7 @@
``` ```
You can see that `tester` is now the controlled_account under `inita` You can see that `tester` is now the controlled_account under `inita`
``` ```
$ ./eosc get servants inita $ ./eosioc get servants inita
{ {
"controlled_accounts": [ "controlled_accounts": [
"tester" "tester"
...@@ -220,7 +220,7 @@ ...@@ -220,7 +220,7 @@
After creating the account we can view the current account status like so: After creating the account we can view the current account status like so:
``` ```
$ ./eosc get account tester $ ./eosioc get account tester
{ {
"name": "tester", "name": "tester",
"eos_balance": 0, "eos_balance": 0,
...@@ -270,10 +270,10 @@ ...@@ -270,10 +270,10 @@
``` ```
Since we have the private key of the genesis accounts (i.e. inita, initb, initc, etc) in the wallet. 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", "transaction_id": "eb4b94b72718a369af09eb2e7885b3f494dd1d8a20278a6634611d5edd76b703",
"processed": { "processed": {
...@@ -287,7 +287,7 @@ ...@@ -287,7 +287,7 @@
"signatures": [ "signatures": [
"1f22e64240e1e479eee6ccbbd79a29f1a6eb6020384b4cca1a958e7c708d3e562009ae6e60afac96f9a3b89d729a50cd5a7b5a7a647540ba1678831bf970e83312" "1f22e64240e1e479eee6ccbbd79a29f1a6eb6020384b4cca1a958e7c708d3e562009ae6e60afac96f9a3b89d729a50cd5a7b5a7a647540ba1678831bf970e83312"
], ],
"messages": [{ "actions": [{
"code": "eos", "code": "eos",
"type": "transfer", "type": "transfer",
"authorization": [{ "authorization": [{
...@@ -333,7 +333,7 @@ ...@@ -333,7 +333,7 @@
Now we can verify that the funds were received. Now we can verify that the funds were received.
``` ```
$ ./eosc get account tester $ ./eosioc get account tester
{ {
"name": "tester", "name": "tester",
"eos_balance": "0.1000 EOS", "eos_balance": "0.1000 EOS",
...@@ -373,7 +373,7 @@ ...@@ -373,7 +373,7 @@
With account_history_api_plugin loaded in `eosd`, we can query for particular transaction 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", "transaction_id": "eb4b94b72718a369af09eb2e7885b3f494dd1d8a20278a6634611d5edd76b703",
"processed": { "processed": {
...@@ -387,7 +387,7 @@ ...@@ -387,7 +387,7 @@
"signatures": [ "signatures": [
"1f22e64240e1e479eee6ccbbd79a29f1a6eb6020384b4cca1a958e7c708d3e562009ae6e60afac96f9a3b89d729a50cd5a7b5a7a647540ba1678831bf970e83312" "1f22e64240e1e479eee6ccbbd79a29f1a6eb6020384b4cca1a958e7c708d3e562009ae6e60afac96f9a3b89d729a50cd5a7b5a7a647540ba1678831bf970e83312"
], ],
"messages": [{ "actions": [{
"code": "eos", "code": "eos",
"type": "transfer", "type": "transfer",
"authorization": [{ "authorization": [{
...@@ -430,7 +430,7 @@ ...@@ -430,7 +430,7 @@
``` ```
Also we can query list of transactions performed by certain account starting from recent one 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", "transaction_id": "eb4b94b72718a369af09eb2e7885b3f494dd1d8a20278a6634611d5edd76b703",
...@@ -446,26 +446,26 @@ ...@@ -446,26 +446,26 @@
@section createcontract Creating a Contract @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. 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). The next step is to publish the contract (.wast) and its abi (.abi).
We will need currency active key in our wallet for this We will need currency active key in our wallet for this
``` ```
$ ./eosc import 5Hv22aPcjnENBv6X9o9nKGdkfrW44En6z4zJUt2PobAvbQXrT9z $ ./eosioc import 5Hv22aPcjnENBv6X9o9nKGdkfrW44En6z4zJUt2PobAvbQXrT9z
imported private key for: EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA imported private key for: EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA
``` ```
Then proceed with setting the code 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... Reading WAST...
Assembling WASM... Assembling WASM...
Publishing contract... Publishing contract...
...@@ -480,7 +480,7 @@ ...@@ -480,7 +480,7 @@
"eos" "eos"
], ],
"signatures": [], "signatures": [],
"messages": [{ "actions": [{
"code": "eos", "code": "eos",
"type": "setcode", "type": "setcode",
"authorization": [{ "authorization": [{
...@@ -501,13 +501,13 @@ ...@@ -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. 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 code hash: 9b9db1a7940503a88535517049e64467a6e8f4e9e03af15e9968ec89dd794975
saving abi to currency.abi saving abi to currency.abi
$ cat currency.abi $ cat currency.abi
...@@ -552,10 +552,10 @@ ...@@ -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... 1589302ms thread-0 main.cpp:271 operator() ] Converting argument to binary...
1589304ms thread-0 main.cpp:290 operator() ] Transaction result: 1589304ms thread-0 main.cpp:290 operator() ] Transaction result:
{ {
...@@ -569,7 +569,7 @@ ...@@ -569,7 +569,7 @@
"tester" "tester"
], ],
"signatures": [], "signatures": [],
"messages": [{ "actions": [{
"code": "currency", "code": "currency",
"type": "transfer", "type": "transfer",
"authorization": [{ "authorization": [{
...@@ -606,7 +606,7 @@ ...@@ -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. 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... 3116153ms thread-0 main.cpp:271 operator() ] Converting argument to binary...
3116154ms thread-0 main.cpp:290 operator() ] Transaction result: 3116154ms thread-0 main.cpp:290 operator() ] Transaction result:
{ {
...@@ -620,7 +620,7 @@ ...@@ -620,7 +620,7 @@
"tester" "tester"
], ],
"signatures": [], "signatures": [],
"messages": [{ "actions": [{
"code": "currency", "code": "currency",
"type": "transfer", "type": "transfer",
"authorization": [{ "authorization": [{
...@@ -664,7 +664,7 @@ ...@@ -664,7 +664,7 @@
Now that `tester` has a balance of 0, if we attempt this transfer a second time it should fail: 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... 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 3543615ms thread-0 main.cpp:311 main ] Failed with error: 10 assert_exception: Assert Exception
status_code == 200: Error status_code == 200: Error
...@@ -683,12 +683,12 @@ ...@@ -683,12 +683,12 @@
This table is stored on the scope of each account instead of on `currency` scope. 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": [], "rows": [],
"more": false "more": false
} }
$./eosc get table inita currency account $./eosioc get table inita currency account
{ {
"rows": [{ "rows": [{
"account": "account", "account": "account",
...@@ -702,9 +702,9 @@ ...@@ -702,9 +702,9 @@
@section particularnode Connecting to Particular Node @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 @section separatewallet Using Separate Wallet App
...@@ -716,7 +716,7 @@ ...@@ -716,7 +716,7 @@
``` ```
Then for any operation that requires signing, use the --wallet-host and --wallet-port option 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 <COMMAND> <SUBCOMMAND> <PARAMS> ./eosioc --wallet-host 127.0.0.1 --wallet-port 8887 <COMMAND> <SUBCOMMAND> <PARAMS>
``` ```
...@@ -729,18 +729,18 @@ ...@@ -729,18 +729,18 @@
``` ```
And then for any operation that requires signing, use the `-s` option And then for any operation that requires signing, use the `-s` option
``` ```
./eosc <COMMAND> <SUBCOMMAND> -s <PARAMS> ./eosioc <COMMAND> <SUBCOMMAND> -s <PARAMS>
``` ```
@section additionaldoc Additional Documentation @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 ERROR: RequiredError: Subcommand required
Command Line Interface to Eos Daemon Command Line Interface to Eos Daemon
Usage: ./eosc [OPTIONS] SUBCOMMAND Usage: ./eosioc [OPTIONS] SUBCOMMAND
Options: Options:
-h,--help Print this help message and exit -h,--help Print this help message and exit
...@@ -761,18 +761,18 @@ ...@@ -761,18 +761,18 @@
``` ```
To get help with any particular subcommand, run it with no arguments as well: To get help with any particular subcommand, run it with no arguments as well:
``` ```
$ ./eosc create $ ./eosioc create
ERROR: RequiredError: Subcommand required ERROR: RequiredError: Subcommand required
Create various items, on and off the blockchain Create various items, on and off the blockchain
Usage: ./eosc create SUBCOMMAND Usage: ./eosioc create SUBCOMMAND
Subcommands: Subcommands:
key Create a new keypair and print the public and private keys key Create a new keypair and print the public and private keys
account Create a new account on the blockchain account Create a new account on the blockchain
$ ./eosc create account $ ./eosioc create account
ERROR: RequiredError: creator ERROR: RequiredError: creator
Create a new account on the blockchain Create a new account on the blockchain
Usage: ./eosc create account creator name OwnerKey ActiveKey Usage: ./eosioc create account creator name OwnerKey ActiveKey
Positionals: Positionals:
creator TEXT The name of the account creating the new account creator TEXT The name of the account creating the new account
......
...@@ -22,12 +22,12 @@ Welcome to the EOS.IO Documentation ...@@ -22,12 +22,12 @@ Welcome to the EOS.IO Documentation
## End User ## End User
- Wallet Creation and Management - Wallet Creation and Management
- [Create a wallet](https://eosio.github.io/eos/group__eosc.html#createwallet) - [Create a wallet](https://eosio.github.io/eos/group__eosioc.html#createwallet)
- [Import Key to Wallet](https://eosio.github.io/eos/group__eosc.html#importkey) - [Import Key to Wallet](https://eosio.github.io/eos/group__eosioc.html#importkey)
- [Locking and Unlocking Wallet](https://eosio.github.io/eos/group__eosc.html#lockwallets) - [Locking and Unlocking Wallet](https://eosio.github.io/eos/group__eosioc.html#lockwallets)
- [Create an Account](https://eosio.github.io/eos/group__eosc.html#createaccount) - [Create an Account](https://eosio.github.io/eos/group__eosioc.html#createaccount)
- [Transfer EOS](https://eosio.github.io/eos/group__eosc.html#transfereos) - [Transfer EOS](https://eosio.github.io/eos/group__eosioc.html#transfereos)
- [Getting Transaction](https://eosio.github.io/eos/group__eosc.html#gettingtransaction) - [Getting Transaction](https://eosio.github.io/eos/group__eosioc.html#gettingtransaction)
## Smart Contract Developers ## Smart Contract Developers
- [Introduction to Contract Development Tutorial](https://eosio.github.io/eos/md_contracts_eoslib_tutorial.html) - [Introduction to Contract Development Tutorial](https://eosio.github.io/eos/md_contracts_eoslib_tutorial.html)
......
...@@ -304,7 +304,7 @@ Content-Length: 1466 ...@@ -304,7 +304,7 @@ Content-Length: 1466
@subsubsection examplepushtrx Example push_transaction Usage @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`. 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. ...@@ -314,7 +314,7 @@ This method push multiple transactions at once.
@subsubsection examplepushtrxs Example push_transactions Usage @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. ...@@ -324,7 +324,7 @@ Get required keys to sign a transaction from list of your keys.
@subsubsection examplegetrequiredkeys Example get_required_keys Usage @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 @subsubsection examplegetrequiredkeysresult Example get_required_keys Result
......
...@@ -23,16 +23,16 @@ extern "C" { ...@@ -23,16 +23,16 @@ extern "C" {
*/ */
/** /**
* Aborts processing of this message and unwinds all pending changes if the test condition is true * Aborts processing of this action and unwinds all pending changes if the test condition is true
* @brief Aborts processing of this message and unwinds all pending changes * @brief Aborts processing of this action and unwinds all pending changes
* @param test - 0 to abort, 1 to ignore * @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 ); 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 * @brief Get time of the last accepted block
* @return time in seconds from 1970 of the last accepted block * @return time in seconds from 1970 of the last accepted block
*/ */
......
...@@ -8,7 +8,7 @@ For the rest of this tutorial we will use the term "contract" to refer to the co ...@@ -8,7 +8,7 @@ For the rest of this tutorial we will use the term "contract" to refer to the co
## Required Background Knowledge ## 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 and deploy the example contracts. If you have not yet successfully followed that tutorial, then do that
first and come back. first and come back.
...@@ -77,7 +77,7 @@ extern "C" { ...@@ -77,7 +77,7 @@ extern "C" {
} // 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: 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 ...@@ -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: Assuming your wallet is unlocked and has keys for `${account}`, you can now upload this contract to the blockchain with the following command:
```bash ```bash
$ eosc set contract ${account} hello.wast hello.abi $ eosioc set contract ${account} hello.wast hello.abi
Reading WAST... Reading WAST...
Assembling WASM... Assembling WASM...
Publishing contract... Publishing contract...
...@@ -113,7 +113,7 @@ Publishing contract... ...@@ -113,7 +113,7 @@ Publishing contract...
"signatures": [ "signatures": [
"2064610856c773423d239a388d22cd30b7ba98f6a9fbabfa621e42cec5dd03c3b87afdcbd68a3a82df020b78126366227674dfbdd33de7d488f2d010ada914b438" "2064610856c773423d239a388d22cd30b7ba98f6a9fbabfa621e42cec5dd03c3b87afdcbd68a3a82df020b78126366227674dfbdd33de7d488f2d010ada914b438"
], ],
"messages": [{ "actions": [{
"code": "eos", "code": "eos",
"type": "setcode", "type": "setcode",
"authorization": [{ "authorization": [{
...@@ -158,15 +158,15 @@ You will notice the lines "Init World!" are executed 3 times, this isn't a mista ...@@ -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 3. eosd pushes the generated block as if it received it from the network
- **prints "Init World!" a third time** - **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 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 message: anything we want. Let's try sending it an empty action:
```bash ```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 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 message type "hello" is dispatched to 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. account.
...@@ -182,7 +182,7 @@ The result is: ...@@ -182,7 +182,7 @@ The result is:
"${account}" "${account}"
], ],
"signatures": [], "signatures": [],
"messages": [{ "actions": [{
"code": "${account}", "code": "${account}",
"type": "hello", "type": "hello",
"authorization": [], "authorization": [],
...@@ -208,9 +208,9 @@ Hello World: ${account}->hello ...@@ -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. 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). 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: ...@@ -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"`. `transfer`. The type `transfer` is defined in the `structs` array in the object with `name` set to `"transfer"`.
```json ```json
...@@ -295,10 +295,10 @@ the `types` array to `Name`, which is a built in type used to encode a uint64_t ...@@ -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 ```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... 2570494ms thread-0 main.cpp:797 operator() ] Converting argument to binary...
{ {
"transaction_id": "b191eb8bff3002757839f204ffc310f1bfe5ba1872a64dda3fc42bfc2c8ed688", "transaction_id": "b191eb8bff3002757839f204ffc310f1bfe5ba1872a64dda3fc42bfc2c8ed688",
...@@ -310,7 +310,7 @@ eosc push message ${account} transfer '{"from":"currency","to":"inita","amount": ...@@ -310,7 +310,7 @@ eosc push message ${account} transfer '{"from":"currency","to":"inita","amount":
"initc" "initc"
], ],
"signatures": [], "signatures": [],
"messages": [{ "actions": [{
"code": "initc", "code": "initc",
"type": "transfer", "type": "transfer",
"authorization": [], "authorization": [],
...@@ -339,9 +339,9 @@ Hello World: ${account}->transfer ...@@ -339,9 +339,9 @@ Hello World: ${account}->transfer
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 ```json
"fields": { "fields": {
...@@ -351,7 +351,7 @@ According to the ABI the transfer message has the format: ...@@ -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 ```c
struct transfer { struct transfer {
...@@ -361,14 +361,14 @@ 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 action_size();
uint32_t readMessage( void* msg, uint32_t msglen ); 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 ```c
#include <hello.hpp> #include <hello.hpp>
...@@ -396,11 +396,11 @@ extern "C" { ...@@ -396,11 +396,11 @@ extern "C" {
void apply( uint64_t code, uint64_t action ) { void apply( uint64_t code, uint64_t action ) {
eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" ); eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" );
if( action == N(transfer) ) { if( action == N(transfer) ) {
transfer message; transfer action;
static_assert( sizeof(message) == 3*sizeof(uint64_t), "unexpected padding" ); static_assert( sizeof(action) == 3*sizeof(uint64_t), "unexpected padding" );
auto read = readMessage( &message, sizeof(message) ); auto read = read_action( &action, sizeof(action) );
assert( read == sizeof(message), "message too short" ); assert( read == sizeof(action), "action too short" );
eosio::print( "Transfer ", message.amount, " from ", eosio::Name(message.from), " to ", eosio::Name(message.to), "\n" ); 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: ...@@ -411,7 +411,7 @@ Then we can recompile and deploy it with:
```bash ```bash
eoscpp -o hello.wast hello.cpp 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 `eosd` will call init() again because of the redeploy
...@@ -425,7 +425,7 @@ Init World! ...@@ -425,7 +425,7 @@ Init World!
Then we can execute transfer: Then we can execute transfer:
```bash ```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", "transaction_id": "a777539b7d5f752fb40e6f2d019b65b5401be8bf91c8036440661506875ba1c0",
"processed": { "processed": {
...@@ -436,7 +436,7 @@ $ eosc push message ${account} transfer '{"from":"currency","to":"inita","amount ...@@ -436,7 +436,7 @@ $ eosc push message ${account} transfer '{"from":"currency","to":"inita","amount
"${account}" "${account}"
], ],
"signatures": [], "signatures": [],
"messages": [{ "actions": [{
"code": "${account}", "code": "${account}",
"type": "transfer", "type": "transfer",
"authorization": [], "authorization": [],
...@@ -468,15 +468,15 @@ Hello World: ${account}->transfer ...@@ -468,15 +468,15 @@ Hello World: ${account}->transfer
Transfer 50 from currency to inita 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 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. removes much of the boiler plate.
```c ```c
/// eoslib/message.hpp /// eoslib/action.hpp
namespace eosio { namespace eosio {
template<typename T> template<typename T>
T currentMessage(); T currentAction();
} }
``` ```
...@@ -508,8 +508,8 @@ extern "C" { ...@@ -508,8 +508,8 @@ extern "C" {
void apply( uint64_t code, uint64_t action ) { void apply( uint64_t code, uint64_t action ) {
eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" ); eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" );
if( action == N(transfer) ) { if( action == N(transfer) ) {
auto message = eosio::currentMessage<transfer>(); auto action = eosio::currentAction<transfer>();
eosio::print( "Transfer ", message.amount, " from ", message.from, " to ", message.to, "\n" ); eosio::print( "Transfer ", action.amount, " from ", action.from, " to ", action.to, "\n" );
} }
} }
...@@ -517,13 +517,13 @@ extern "C" { ...@@ -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. After compiling and uploading it you should get the same results as the C version.
## Requiring Sender Authority to Transfer ## 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. 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 ...@@ -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 ) { void apply( uint64_t code, uint64_t action ) {
eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" ); eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" );
if( action == N(transfer) ) { if( action == N(transfer) ) {
auto message = eosio::currentMessage<transfer>(); auto action = eosio::currentAction<transfer>();
eosio::requireAuth( message.from ); eosio::requireAuth( action.from );
eosio::print( "Transfer ", message.amount, " from ", message.from, " to ", message.to, "\n" ); 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 ...@@ -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: After building and deploying we can attempt to transfer again:
```bash ```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... 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 1881630ms thread-0 main.cpp:851 main ] Failed with error: 10 assert_exception: Assert Exception
status_code == 200: Error status_code == 200: Error
: 3030001 tx_missing_auth: missing required authority : 3030001 tx_missing_auth: missing required authority
Transaction is missing required authorization from initb Transaction is missing required authorization from initb
{"acct":"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 ...@@ -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`. 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 ```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. 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. 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 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. 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. ...@@ -583,10 +583,10 @@ the contract must abort and any changes made get automatically reverted.
void apply( uint64_t code, uint64_t action ) { void apply( uint64_t code, uint64_t action ) {
eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" ); eosio::print( "Hello World: ", eosio::Name(code), "->", eosio::Name(action), "\n" );
if( action == N(transfer) ) { if( action == N(transfer) ) {
auto message = eosio::currentMessage<transfer>(); auto action = eosio::currentAction<transfer>();
assert( message.amount > 0, "Must transfer an amount greater than 0" ); assert( action.amount > 0, "Must transfer an amount greater than 0" );
eosio::requireAuth( message.from ); eosio::requireAuth( action.from );
eosio::print( "Transfer ", message.amount, " from ", message.from, " to ", message.to, "\n" ); 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: ...@@ -595,8 +595,8 @@ We can now compile, deploy, and attempt to execute a transfer of 0:
```bash ```bash
$ eoscpp -o hello.wast hello.cpp $ eoscpp -o hello.wast hello.cpp
$ eosc set contract ${account} hello.wast hello.abi $ eosioc set contract ${account} hello.wast hello.abi
$ eosc push message ${account} transfer '{"from":"initb","to":"inita","amount":0}' --scope initc --permission initb@active $ 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 3071182ms thread-0 main.cpp:851 main ] Failed with error: 10 assert_exception: Assert Exception
status_code == 200: Error status_code == 200: Error
: 10 assert_exception: Assert Exception : 10 assert_exception: Assert Exception
......
...@@ -303,16 +303,16 @@ extern "C" { ...@@ -303,16 +303,16 @@ extern "C" {
if( code == N(exchange) ) { if( code == N(exchange) ) {
switch( action ) { switch( action ) {
case N(buy): case N(buy):
apply_exchange_buy( current_message<exchange::buy_order>() ); apply_exchange_buy( current_action<exchange::buy_order>() );
break; break;
case N(sell): case N(sell):
apply_exchange_sell( current_message<exchange::sell_order>() ); apply_exchange_sell( current_action<exchange::sell_order>() );
break; break;
case N(cancelbuy): case N(cancelbuy):
apply_exchange_cancel_buy( current_message<exchange::order_id>() ); apply_exchange_cancel_buy( current_action<exchange::order_id>() );
break; break;
case N(cancelsell): case N(cancelsell):
apply_exchange_cancel_sell( current_message<exchange::order_id>() ); apply_exchange_cancel_sell( current_action<exchange::order_id>() );
break; break;
default: default:
assert( false, "unknown action" ); assert( false, "unknown action" );
...@@ -320,11 +320,11 @@ extern "C" { ...@@ -320,11 +320,11 @@ extern "C" {
} }
else if( code == N(currency) ) { else if( code == N(currency) ) {
if( action == N(transfer) ) if( action == N(transfer) )
apply_currency_transfer( current_message<currency::transfer>() ); apply_currency_transfer( current_action<currency::transfer>() );
} }
else if( code == N(eos) ) { else if( code == N(eos) ) {
if( action == N(transfer) ) if( action == N(transfer) )
apply_eos_transfer( current_message<eosio::transfer>() ); apply_eos_transfer( current_action<eosio::transfer>() );
} }
else { else {
} }
......
...@@ -48,7 +48,7 @@ extern "C" { ...@@ -48,7 +48,7 @@ extern "C" {
void apply( uint64_t code, uint64_t action ) { void apply( uint64_t code, uint64_t action ) {
if( code == N(currency) ) { if( code == N(currency) ) {
if( action == N(transfer) ) if( action == N(transfer) )
infinite::apply_currency_transfer( current_message< infinite::transfer >() ); infinite::apply_currency_transfer( current_action< infinite::transfer >() );
} }
} }
} }
...@@ -55,15 +55,15 @@ extern "C" { ...@@ -55,15 +55,15 @@ extern "C" {
void apply( uint64_t code, uint64_t action ) { void apply( uint64_t code, uint64_t action ) {
if( code == N(currency) ) { if( code == N(currency) ) {
if( action == N(transfer) ) { if( action == N(transfer) ) {
apply_transfer(code, current_message<currency::transfer>()); apply_transfer(code, current_action<currency::transfer>());
} }
} else if ( code == N(eos) ) { } else if ( code == N(eos) ) {
if( action == N(transfer) ) { if( action == N(transfer) ) {
apply_transfer(code, current_message<eosio::transfer>()); apply_transfer(code, current_action<eosio::transfer>());
} }
} else if (code == N(proxy) ) { } else if (code == N(proxy) ) {
if ( action == N(setowner)) { if ( action == N(setowner)) {
apply_setowner(current_message<account_name>()); apply_setowner(current_action<account_name>());
} }
} }
} }
......
...@@ -14,9 +14,9 @@ extern "C" { ...@@ -14,9 +14,9 @@ extern "C" {
void apply( uint64_t code, uint64_t action ) { void apply( uint64_t code, uint64_t action ) {
if( code == N(simpledb) ) { if( code == N(simpledb) ) {
if( action == N(insertkv1) ) { if( action == N(insertkv1) ) {
// eosc push message simpledb insertkv1 '{"key":"a", "value":"aa"}' -S simpledb // eosioc push message simpledb insertkv1 '{"key":"a", "value":"aa"}' -S simpledb
// eosc get table simpledb simpledb keyvalue1 // eosioc get table simpledb simpledb keyvalue1
auto kv1 = eosio::current_message<key_value1>(); auto kv1 = eosio::current_action<key_value1>();
//eosio::print(kv1.key.len, "-", (const char*)kv1.key.str, "->" , kv1.value.len, "-", (const char*)kv1.value.str, "\n"); //eosio::print(kv1.key.len, "-", (const char*)kv1.key.str, "->" , kv1.value.len, "-", (const char*)kv1.value.str, "\n");
//Use kv1 in some way //Use kv1 in some way
...@@ -24,9 +24,9 @@ extern "C" { ...@@ -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); 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) ) { } else if( action == N(insertkv2) ) {
// eosc push message simpledb insertkv2 '{"key":"a", "value":{"name":"aaa", "age":10}}' -S simpledb // eosioc push message simpledb insertkv2 '{"key":"a", "value":{"name":"aaa", "age":10}}' -S simpledb
// eosc get table simpledb simpledb keyvalue2 // eosioc get table simpledb simpledb keyvalue2
auto kv2 = eosio::current_message<key_value2>(); auto kv2 = eosio::current_action<key_value2>();
//eosio::print(kv2.key.len, "-", (const char*)kv2.key.str, "->" , (const char*)kv2.value.name.str, "-", kv2.value.age, "\n"); //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 //Use kv2 in some way
...@@ -36,15 +36,15 @@ extern "C" { ...@@ -36,15 +36,15 @@ extern "C" {
} else if( action == N(insert1) ) { } else if( action == N(insert1) ) {
record1 tmp; record1 tmp;
read_message(&tmp, sizeof(tmp)); read_action(&tmp, sizeof(tmp));
store_i64( N(simpledb), N(record1), &tmp, sizeof(tmp) ); store_i64( N(simpledb), N(record1), &tmp, sizeof(tmp) );
} else if(action == N(insert2)) { } else if(action == N(insert2)) {
record2 tmp; record2 tmp;
read_message(&tmp, sizeof(tmp)); read_action(&tmp, sizeof(tmp));
store_i128i128( N(simpledb), N(record2), &tmp, sizeof(tmp) ); store_i128i128( N(simpledb), N(record2), &tmp, sizeof(tmp) );
} else if(action == N(insert3)) { } else if(action == N(insert3)) {
record3 tmp; record3 tmp;
read_message(&tmp, sizeof(tmp)); read_action(&tmp, sizeof(tmp));
store_i64i64i64( N(simpledb), N(record3), &tmp, sizeof(tmp) ); store_i64i64i64( N(simpledb), N(record3), &tmp, sizeof(tmp) );
} else { } else {
assert(0, "unknown message"); assert(0, "unknown message");
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include <eoslib/print.hpp> #include <eoslib/print.hpp>
// These functions can be auto-generated using the ABI definition. // 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), // struct has at least one variable length type (String, bytes, etc),
// otherwise the default function will do ok. // otherwise the default function will do ok.
// //
...@@ -25,10 +25,10 @@ namespace eosio { ...@@ -25,10 +25,10 @@ namespace eosio {
T bytes_to_value(const bytes& bytes_val) { return *reinterpret_cast<T*>(bytes_val.data); } T bytes_to_value(const bytes& bytes_val) { return *reinterpret_cast<T*>(bytes_val.data); }
template<> template<>
key_value1 current_message<key_value1>() { key_value1 current_action<key_value1>() {
uint32_t msgsize = message_size(); uint32_t msgsize = action_size();
char* buffer = (char *)eosio::malloc(msgsize); 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<char *> ds(buffer, msgsize); datastream<char *> ds(buffer, msgsize);
key_value1 value; key_value1 value;
raw::unpack(ds, value.key); raw::unpack(ds, value.key);
...@@ -62,10 +62,10 @@ namespace eosio { ...@@ -62,10 +62,10 @@ namespace eosio {
} }
template<> template<>
key_value2 current_message<key_value2>() { key_value2 current_action<key_value2>() {
uint32_t msgsize = message_size(); uint32_t msgsize = action_size();
char* buffer = (char *)eosio::malloc(msgsize); 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<char *> ds(buffer, msgsize); datastream<char *> ds(buffer, msgsize);
key_value2 value; key_value2 value;
raw::unpack(ds, value.key); raw::unpack(ds, value.key);
......
...@@ -59,7 +59,7 @@ struct account { ...@@ -59,7 +59,7 @@ struct account {
* any other contexts are notified * any other contexts are notified
*/ */
void apply_social_post() { void apply_social_post() {
const auto& post = current_message<post_action>(); const auto& post = current_action<post_action>();
require_auth( post.author ); require_auth( post.author );
assert( current_context() == post.author, "cannot call from any other context" ); assert( current_context() == post.author, "cannot call from any other context" );
...@@ -75,7 +75,7 @@ void apply_social_post() { ...@@ -75,7 +75,7 @@ void apply_social_post() {
* updates the vote total. When executed * updates the vote total. When executed
*/ */
void apply_social_vote() { void apply_social_vote() {
const auto& vote = current_message<vote_action>(); const auto& vote = current_action<vote_action>();
require_notice( vote.voter, vote.author ); require_notice( vote.voter, vote.author );
disable_context_code( vote.author() ); /// prevent the author's code from rejecting the potentially negative vote disable_context_code( vote.author() ); /// prevent the author's code from rejecting the potentially negative vote
......
...@@ -48,7 +48,7 @@ namespace TOKEN_NAME { ...@@ -48,7 +48,7 @@ namespace TOKEN_NAME {
uint32_t eospathlen; uint32_t eospathlen;
uint32_t ipfspathlen; uint32_t ipfspathlen;
char tmp[4098]; 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 ); auto linklen = read_link_from_buffer( tmp, bufferlen, link_to_set, eospathlen, ipfspathlen );
eosio::require_notice( link_to_set.owner ); eosio::require_notice( link_to_set.owner );
eosio::require_auth( link_to_set.owner ); eosio::require_auth( link_to_set.owner );
...@@ -109,20 +109,20 @@ extern "C" { ...@@ -109,20 +109,20 @@ extern "C" {
void apply( uint64_t code, uint64_t action ) { void apply( uint64_t code, uint64_t action ) {
if( code == N(storage) ) { if( code == N(storage) ) {
if( action == N(transfer) ) { 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) ) { } else if (action == N(setlink) ) {
TOKEN_NAME::apply_storage_setlink(); TOKEN_NAME::apply_storage_setlink();
} else if (action == N(removelink) ) { } else if (action == N(removelink) ) {
char tmp[1025]; char tmp[1025];
auto len = read_message( tmp, 1025 ); auto len = read_action( tmp, 1025 );
TOKEN_NAME::apply_storage_removelink( tmp, len ); TOKEN_NAME::apply_storage_removelink( tmp, len );
} else if (action == N(acceptstore) ) { } else if (action == N(acceptstore) ) {
char tmp[1025]; char tmp[1025];
auto len = read_message( tmp, 1025 ); auto len = read_action( tmp, 1025 );
TOKEN_NAME::apply_storage_createstore( tmp, len ); TOKEN_NAME::apply_storage_createstore( tmp, len );
} else if (action == N(rejectstore) ) { } else if (action == N(rejectstore) ) {
char tmp[1025]; char tmp[1025];
auto len = read_message( tmp, 1025 ); auto len = read_action( tmp, 1025 );
TOKEN_NAME::apply_storage_rejectstore( tmp, len ); TOKEN_NAME::apply_storage_rejectstore( tmp, len );
} else { } else {
assert(0, "unknown message"); assert(0, "unknown message");
......
...@@ -2,32 +2,32 @@ ...@@ -2,32 +2,32 @@
* @file * @file
* @copyright defined in eos/LICENSE.txt * @copyright defined in eos/LICENSE.txt
*/ */
#include <eoslib/message.hpp> #include <eoslib/action.hpp>
#include "test_api.hpp" #include "test_api.hpp"
unsigned int test_message::read_message_normal() { unsigned int test_action::read_action_normal() {
char buffer[100]; char buffer[100];
uint32_t total = 0; uint32_t total = 0;
WASM_ASSERT( current_code() == N(testapi), "current_code() == N(testapi)" ); WASM_ASSERT( current_code() == N(testapi), "current_code() == N(testapi)" );
WASM_ASSERT(message_size() == sizeof(dummy_message), "message_size() == sizeof(dummy_message)"); WASM_ASSERT(action_size() == sizeof(dummy_action), "action_size() == sizeof(dummy_action)");
total = read_message(buffer, 30); total = read_action(buffer, 30);
WASM_ASSERT(total == sizeof(dummy_message) , "read_message(30)" ); WASM_ASSERT(total == sizeof(dummy_action) , "read_action(30)" );
total = read_message(buffer, 100); total = read_action(buffer, 100);
WASM_ASSERT(total == sizeof(dummy_message) , "read_message(100)" ); WASM_ASSERT(total == sizeof(dummy_action) , "read_action(100)" );
total = read_message(buffer, 5); total = read_action(buffer, 5);
WASM_ASSERT(total == 5 , "read_message(5)" ); WASM_ASSERT(total == 5 , "read_action(5)" );
total = read_message(buffer, sizeof(dummy_message) ); total = read_action(buffer, sizeof(dummy_action) );
WASM_ASSERT(total == sizeof(dummy_message), "read_message(sizeof(dummy_message))" ); WASM_ASSERT(total == sizeof(dummy_action), "read_action(sizeof(dummy_action))" );
dummy_message *dummy13 = reinterpret_cast<dummy_message *>(buffer); dummy_action *dummy13 = reinterpret_cast<dummy_action *>(buffer);
WASM_ASSERT(dummy13->a == DUMMY_MESSAGE_DEFAULT_A, "dummy13->a == DUMMY_MESSAGE_DEFAULT_A"); 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->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"); WASM_ASSERT(dummy13->c == DUMMY_MESSAGE_DEFAULT_C, "dummy13->c == DUMMY_MESSAGE_DEFAULT_C");
...@@ -35,17 +35,17 @@ unsigned int test_message::read_message_normal() { ...@@ -35,17 +35,17 @@ unsigned int test_message::read_message_normal() {
return WASM_TEST_PASS; return WASM_TEST_PASS;
} }
unsigned int test_message::read_message_to_0() { unsigned int test_action::read_action_to_0() {
uint32_t total = read_message((void *)0, 0x7FFFFFFF); uint32_t total = read_action((void *)0, 0x7FFFFFFF);
return WASM_TEST_PASS; return WASM_TEST_PASS;
} }
unsigned int test_message::read_message_to_64k() { unsigned int test_action::read_action_to_64k() {
uint32_t total = read_message( (void *)((1<<16)-1), 0x7FFFFFFF); uint32_t total = read_action( (void *)((1<<16)-1), 0x7FFFFFFF);
return WASM_TEST_PASS; return WASM_TEST_PASS;
} }
unsigned int test_message::require_notice() { unsigned int test_action::require_notice() {
if( current_code() == N(testapi) ) { if( current_code() == N(testapi) ) {
eosio::require_notice( N(acc1) ); eosio::require_notice( N(acc1) );
eosio::require_notice( N(acc2) ); eosio::require_notice( N(acc2) );
...@@ -57,25 +57,25 @@ unsigned int test_message::require_notice() { ...@@ -57,25 +57,25 @@ unsigned int test_message::require_notice() {
return WASM_TEST_FAIL; return WASM_TEST_FAIL;
} }
unsigned int test_message::require_auth() { unsigned int test_action::require_auth() {
eosio::require_auth( N(acc3) ); eosio::require_auth( N(acc3) );
eosio::require_auth( N(acc4) ); eosio::require_auth( N(acc4) );
return WASM_TEST_PASS; return WASM_TEST_PASS;
} }
unsigned int test_message::assert_false() { unsigned int test_action::assert_false() {
assert(false, "test_message::assert_false"); assert(false, "test_action::assert_false");
return WASM_TEST_PASS; return WASM_TEST_PASS;
} }
unsigned int test_message::assert_true() { unsigned int test_action::assert_true() {
assert(true, "test_message::assert_true"); assert(true, "test_action::assert_true");
return WASM_TEST_PASS; return WASM_TEST_PASS;
} }
unsigned int test_message::now() { unsigned int test_action::now() {
uint32_t tmp = 0; uint32_t tmp = 0;
uint32_t total = read_message(&tmp, sizeof(uint32_t)); uint32_t total = read_action(&tmp, sizeof(uint32_t));
WASM_ASSERT( total == sizeof(uint32_t), "total == sizeof(uint32_t)"); WASM_ASSERT( total == sizeof(uint32_t), "total == sizeof(uint32_t)");
WASM_ASSERT( tmp == ::now(), "tmp == now()" ); WASM_ASSERT( tmp == ::now(), "tmp == now()" );
return WASM_TEST_PASS; return WASM_TEST_PASS;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "test_crypto.cpp" #include "test_crypto.cpp"
#include "test_db.cpp" #include "test_db.cpp"
#include "test_math.cpp" #include "test_math.cpp"
#include "test_message.cpp" #include "test_action.cpp"
#include "test_print.cpp" #include "test_print.cpp"
#include "test_string.cpp" #include "test_string.cpp"
#include "test_transaction.cpp" #include "test_transaction.cpp"
...@@ -31,15 +31,15 @@ extern "C" { ...@@ -31,15 +31,15 @@ extern "C" {
WASM_TEST_HANDLER(test_types, string_to_name); WASM_TEST_HANDLER(test_types, string_to_name);
WASM_TEST_HANDLER(test_types, name_class); WASM_TEST_HANDLER(test_types, name_class);
//test_message //test_action
WASM_TEST_HANDLER(test_message, read_message_normal); WASM_TEST_HANDLER(test_action, read_action_normal);
WASM_TEST_HANDLER(test_message, read_message_to_0); WASM_TEST_HANDLER(test_action, read_action_to_0);
WASM_TEST_HANDLER(test_message, read_message_to_64k); WASM_TEST_HANDLER(test_action, read_action_to_64k);
WASM_TEST_HANDLER(test_message, require_notice); WASM_TEST_HANDLER(test_action, require_notice);
WASM_TEST_HANDLER(test_message, require_auth); WASM_TEST_HANDLER(test_action, require_auth);
WASM_TEST_HANDLER(test_message, assert_false); WASM_TEST_HANDLER(test_action, assert_false);
WASM_TEST_HANDLER(test_message, assert_true); WASM_TEST_HANDLER(test_action, assert_true);
WASM_TEST_HANDLER(test_message, now); WASM_TEST_HANDLER(test_action, now);
//test_print //test_print
WASM_TEST_HANDLER(test_print, test_prints); WASM_TEST_HANDLER(test_print, test_prints);
......
...@@ -34,7 +34,7 @@ static constexpr u64 WASM_TEST_ACTION(const char* cls, const char* method) ...@@ -34,7 +34,7 @@ static constexpr u64 WASM_TEST_ACTION(const char* cls, const char* method)
} }
#pragma pack(push, 1) #pragma pack(push, 1)
struct dummy_message { struct dummy_action {
char a; //1 char a; //1
unsigned long long b; //8 unsigned long long b; //8
int c; //4 int c; //4
...@@ -45,7 +45,7 @@ struct u128_msg { ...@@ -45,7 +45,7 @@ struct u128_msg {
}; };
#pragma pack(pop) #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" ); static_assert( sizeof(u128_msg) == 16*3 , "unexpected packing" );
struct test_types { struct test_types {
...@@ -66,11 +66,11 @@ struct test_print { ...@@ -66,11 +66,11 @@ struct test_print {
#define DUMMY_MESSAGE_DEFAULT_B 0xab11cd1244556677 #define DUMMY_MESSAGE_DEFAULT_B 0xab11cd1244556677
#define DUMMY_MESSAGE_DEFAULT_C 0x7451ae12 #define DUMMY_MESSAGE_DEFAULT_C 0x7451ae12
struct test_message { struct test_action {
static unsigned int read_message_normal(); static unsigned int read_action_normal();
static unsigned int read_message_to_0(); static unsigned int read_action_to_0();
static unsigned int read_message_to_64k(); static unsigned int read_action_to_64k();
static unsigned int require_notice(); static unsigned int require_notice();
static unsigned int require_auth(); static unsigned int require_auth();
static unsigned int assert_false(); static unsigned int assert_false();
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @file * @file
* @copyright defined in eos/LICENSE.txt * @copyright defined in eos/LICENSE.txt
*/ */
#include <eoslib/message.h> #include <eoslib/action.h>
#include <eoslib/chain.h> #include <eoslib/chain.h>
#include "test_api.hpp" #include "test_api.hpp"
...@@ -16,7 +16,7 @@ struct producers { ...@@ -16,7 +16,7 @@ struct producers {
unsigned int test_chain::test_activeprods() { unsigned int test_chain::test_activeprods() {
producers msg_prods; producers msg_prods;
read_message(&msg_prods, sizeof(producers)); read_action(&msg_prods, sizeof(producers));
WASM_ASSERT(msg_prods.len == 21, "producers.len != 21"); WASM_ASSERT(msg_prods.len == 21, "producers.len != 21");
......
#include <eoslib/types.hpp> #include <eoslib/types.hpp>
#include <eoslib/message.hpp> #include <eoslib/action.hpp>
#include <eoslib/db.h> #include <eoslib/db.h>
#include <eoslib/db.hpp> #include <eoslib/db.hpp>
#include "test_api.hpp" #include "test_api.hpp"
......
#include <eoslib/types.hpp> #include <eoslib/types.hpp>
#include <eoslib/message.hpp> #include <eoslib/action.hpp>
#include <eoslib/math.hpp> #include <eoslib/math.hpp>
#include "test_api.hpp" #include "test_api.hpp"
unsigned int test_math::test_multeq_i128() { unsigned int test_math::test_multeq_i128() {
u128_msg msg; 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)" ); WASM_ASSERT( n == sizeof(u128_msg), "test_multeq_i128 n == sizeof(u128_msg)" );
multeq_i128(msg.values, msg.values+1); multeq_i128(msg.values, msg.values+1);
WASM_ASSERT( msg.values[0] == msg.values[2], "test_multeq_i128 msg.values[0] == msg.values[2]" ); 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() { ...@@ -15,7 +15,7 @@ unsigned int test_math::test_multeq_i128() {
unsigned int test_math::test_diveq_i128() { unsigned int test_math::test_diveq_i128() {
u128_msg msg; 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)" ); WASM_ASSERT( n == sizeof(u128_msg), "test_diveq_i128 n == sizeof(u128_msg)" );
diveq_i128(msg.values, msg.values+1); diveq_i128(msg.values, msg.values+1);
WASM_ASSERT( msg.values[0] == msg.values[2], "test_diveq_i128 msg.values[0] == msg.values[2]" ); WASM_ASSERT( msg.values[0] == msg.values[2], "test_diveq_i128 msg.values[0] == msg.values[2]" );
......
...@@ -3,19 +3,19 @@ ...@@ -3,19 +3,19 @@
* @copyright defined in eos/LICENSE.txt * @copyright defined in eos/LICENSE.txt
*/ */
#include <eoslib/transaction.hpp> #include <eoslib/transaction.hpp>
#include <eoslib/message.hpp> #include <eoslib/action.hpp>
#include "test_api.hpp" #include "test_api.hpp"
unsigned int test_transaction::send_message() { unsigned int test_transaction::send_message() {
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};
auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_message", "read_message_normal"), &payload, sizeof(dummy_message)); auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), &payload, sizeof(dummy_action));
message_send(msg); message_send(msg);
return WASM_TEST_PASS; return WASM_TEST_PASS;
} }
unsigned int test_transaction::send_message_empty() { 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); message_send(msg);
return WASM_TEST_PASS; return WASM_TEST_PASS;
} }
...@@ -24,9 +24,9 @@ unsigned int test_transaction::send_message_empty() { ...@@ -24,9 +24,9 @@ unsigned int test_transaction::send_message_empty() {
* cause failure due to too many pending inline messages * cause failure due to too many pending inline messages
*/ */
unsigned int test_transaction::send_message_max() { 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++) { 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; return WASM_TEST_FAIL;
...@@ -37,7 +37,7 @@ unsigned int test_transaction::send_message_max() { ...@@ -37,7 +37,7 @@ unsigned int test_transaction::send_message_max() {
*/ */
unsigned int test_transaction::send_message_large() { unsigned int test_transaction::send_message_large() {
char large_message[8 * 1024]; 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; return WASM_TEST_FAIL;
} }
...@@ -46,7 +46,7 @@ unsigned int test_transaction::send_message_large() { ...@@ -46,7 +46,7 @@ unsigned int test_transaction::send_message_large() {
*/ */
unsigned int test_transaction::send_message_recurse() { unsigned int test_transaction::send_message_recurse() {
char buffer[1024]; 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); auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_transaction", "send_message_recurse"), buffer, size);
message_send(msg); message_send(msg);
return WASM_TEST_PASS; return WASM_TEST_PASS;
...@@ -56,14 +56,14 @@ unsigned int test_transaction::send_message_recurse() { ...@@ -56,14 +56,14 @@ unsigned int test_transaction::send_message_recurse() {
* cause failure due to inline TX failure * cause failure due to inline TX failure
*/ */
unsigned int test_transaction::send_message_inline_fail() { 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); message_send(msg);
return WASM_TEST_PASS; return WASM_TEST_PASS;
} }
unsigned int test_transaction::send_transaction() { unsigned int test_transaction::send_transaction() {
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};
auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_message", "read_message_normal"), &payload, sizeof(dummy_message)); auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), &payload, sizeof(dummy_action));
auto trx = transaction_create(); auto trx = transaction_create();
...@@ -99,7 +99,7 @@ unsigned int test_transaction::send_transaction_large() { ...@@ -99,7 +99,7 @@ unsigned int test_transaction::send_transaction_large() {
transaction_require_scope(trx, N(testapi)); transaction_require_scope(trx, N(testapi));
for (int i = 0; i < 32; i ++) { for (int i = 0; i < 32; i ++) {
char large_message[4 * 1024]; 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); transaction_add_message(trx, msg);
} }
......
...@@ -112,7 +112,7 @@ namespace tic_tac_toe { ...@@ -112,7 +112,7 @@ namespace tic_tac_toe {
bool game_exists = Games::get(restart.challenger, game_to_restart, restart.host); bool game_exists = Games::get(restart.challenger, game_to_restart, restart.host);
assert(game_exists == true, "game doesn't exist!"); 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!"); assert(restart.by == game_to_restart.host || restart.by == game_to_restart.challenger, "this is not your game!");
// Reset game // Reset game
...@@ -150,9 +150,9 @@ namespace tic_tac_toe { ...@@ -150,9 +150,9 @@ namespace tic_tac_toe {
// Check if this game hasn't ended yet // Check if this game hasn't ended yet
assert(game_to_move.winner == N(none), "the game has ended!"); 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!"); 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!"); assert(move.by == game_to_move.turn, "it's not your turn yet!");
...@@ -194,13 +194,13 @@ extern "C" { ...@@ -194,13 +194,13 @@ extern "C" {
void apply( uint64_t code, uint64_t action ) { void apply( uint64_t code, uint64_t action ) {
if (code == N(tic.tac.toe)) { if (code == N(tic.tac.toe)) {
if (action == N(create)) { if (action == N(create)) {
tic_tac_toe::apply_create(current_message<tic_tac_toe::Create>()); tic_tac_toe::apply_create(current_action<tic_tac_toe::Create>());
} else if (action == N(restart)) { } else if (action == N(restart)) {
tic_tac_toe::apply_restart(current_message<tic_tac_toe::Restart>()); tic_tac_toe::apply_restart(current_action<tic_tac_toe::Restart>());
} else if (action == N(close)) { } else if (action == N(close)) {
tic_tac_toe::apply_close(current_message<tic_tac_toe::Close>()); tic_tac_toe::apply_close(current_action<tic_tac_toe::Close>());
} else if (action == N(move)) { } else if (action == N(move)) {
tic_tac_toe::apply_move(current_message<tic_tac_toe::Move>()); tic_tac_toe::apply_move(current_action<tic_tac_toe::Move>());
} }
} }
} }
......
...@@ -16,7 +16,7 @@ void apply_context::exec() ...@@ -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()); auto code = mutable_controller.get_wasm_cache().checkout_scoped(a.code_version, a.code.data(), a.code.size());
// get wasm_interface // get wasm_interface
auto &wasm = wasm_interface::get(); auto& wasm = wasm_interface::get();
wasm.apply(code, *this); wasm.apply(code, *this);
} }
} }
......
...@@ -187,6 +187,7 @@ void apply_eosio_setcode(apply_context& context) { ...@@ -187,6 +187,7 @@ void apply_eosio_setcode(apply_context& context) {
auto act = context.act.as<setcode>(); auto act = context.act.as<setcode>();
context.require_authorization(act.account); context.require_authorization(act.account);
context.require_write_scope( config::eosio_auth_scope );
FC_ASSERT( act.vmtype == 0 ); FC_ASSERT( act.vmtype == 0 );
FC_ASSERT( act.vmversion == 0 ); FC_ASSERT( act.vmversion == 0 );
......
...@@ -197,14 +197,16 @@ struct newaccount { ...@@ -197,14 +197,16 @@ struct newaccount {
}; };
struct setcode { struct setcode {
/*
setcode() = default; 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(account), vmtype(vmtype), vmversion(vmversion), code(code)//, abi(abi)
{} {}
*/
account_name account; account_name account;
uint8 vmtype; uint8 vmtype;
uint8 vmversion; uint8 vmversion;
bytes code; bytes code;
static scope_name get_scope() { static scope_name get_scope() {
......
...@@ -50,7 +50,7 @@ namespace eosio { namespace chain { ...@@ -50,7 +50,7 @@ namespace eosio { namespace chain {
* RAII wrapper to make sure that the cache entries are returned regardless of exceptions etc * RAII wrapper to make sure that the cache entries are returned regardless of exceptions etc
*/ */
struct scoped_entry { 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_id(code_id)
,code(code) ,code(code)
,cache(cache) ,cache(cache)
......
...@@ -29,7 +29,7 @@ struct wasm_context { ...@@ -29,7 +29,7 @@ struct wasm_context {
struct wasm_interface_impl { struct wasm_interface_impl {
optional<wasm_context> current_context; optional<wasm_context> current_context;
void call(const string& entry_point, const vector<Value>& args, wasm_cache::entry& code, apply_context &context); void call(const string& entry_point, const vector<Value>& args, wasm_cache::entry& code, apply_context& context);
}; };
class intrinsics_accessor { class intrinsics_accessor {
...@@ -113,6 +113,8 @@ template<> struct wasm_to_rvalue_type<I64> { static constexpr auto value = Resu ...@@ -113,6 +113,8 @@ template<> struct wasm_to_rvalue_type<I64> { static constexpr auto value = Resu
template<typename T> template<typename T>
constexpr auto wasm_to_rvalue_type_v = wasm_to_rvalue_type<T>::value; constexpr auto wasm_to_rvalue_type_v = wasm_to_rvalue_type<T>::value;
struct void_type{};
/** /**
* Forward delclaration of the invoker type which transcribes arguments to/from a native method * Forward delclaration of the invoker type which transcribes arguments to/from a native method
* and injects the appropriate checks * and injects the appropriate checks
...@@ -135,15 +137,16 @@ struct intrinsic_invoker_impl<Ret, std::tuple<>, std::tuple<Translated...>> { ...@@ -135,15 +137,16 @@ struct intrinsic_invoker_impl<Ret, std::tuple<>, std::tuple<Translated...>> {
return FunctionType::get(wasm_to_rvalue_type_v<Ret>, { wasm_to_value_type_v<Translated> ... }); return FunctionType::get(wasm_to_rvalue_type_v<Ret>, { wasm_to_value_type_v<Translated> ... });
} }
using wasm_method_type = Ret (*)(wasm_interface&, Translated...); using next_method_type = Ret (*)(wasm_interface&, Translated...);
using intrinsic_method_type = Ret (*)(Translated...);
template<wasm_method_type Method> template<next_method_type Method>
static Ret invoke(Translated... translated) { static Ret invoke(Translated... translated) {
wasm_interface& wasm = wasm_interface::get(); wasm_interface& wasm = wasm_interface::get();
return native_to_wasm_t<Ret>(Method(wasm, translated...)); return native_to_wasm_t<Ret>(Method(wasm, translated...));
} }
template<wasm_method_type Method> template<next_method_type Method>
static const auto fn() { static const auto fn() {
return invoke<Method>; return invoke<Method>;
} }
...@@ -154,20 +157,21 @@ struct intrinsic_invoker_impl<Ret, std::tuple<>, std::tuple<Translated...>> { ...@@ -154,20 +157,21 @@ struct intrinsic_invoker_impl<Ret, std::tuple<>, std::tuple<Translated...>> {
* @tparam Translated - the arguments to the wasm function * @tparam Translated - the arguments to the wasm function
*/ */
template<typename ...Translated> template<typename ...Translated>
struct intrinsic_invoker_impl<void, std::tuple<>, std::tuple<Translated...>> { struct intrinsic_invoker_impl<void_type, std::tuple<>, std::tuple<Translated...>> {
static const FunctionType* wasm_function_type() { static const FunctionType* wasm_function_type() {
return FunctionType::get(ResultType::none, { wasm_to_value_type_v<Translated> ... }); return FunctionType::get(ResultType::none, { wasm_to_value_type_v<Translated> ... });
} }
using wasm_method_type = void (*)(wasm_interface&, Translated...); using next_method_type = void_type (*)(wasm_interface&, Translated...);
using intrinsic_method_type = void (*)(Translated...);
template<wasm_method_type Method> template<next_method_type Method>
static void invoke(Translated... translated) { static void invoke(Translated... translated) {
wasm_interface& wasm = wasm_interface::get(); wasm_interface& wasm = wasm_interface::get();
Method(wasm, translated...); Method(wasm, translated...);
} }
template<wasm_method_type Method> template<next_method_type Method>
static const auto fn() { static const auto fn() {
return invoke<Method>; return invoke<Method>;
} }
...@@ -184,8 +188,11 @@ template<typename Ret, typename Input, typename... Inputs, typename... Translate ...@@ -184,8 +188,11 @@ template<typename Ret, typename Input, typename... Inputs, typename... Translate
struct intrinsic_invoker_impl<Ret, std::tuple<Input, Inputs...>, std::tuple<Translated...>> { struct intrinsic_invoker_impl<Ret, std::tuple<Input, Inputs...>, std::tuple<Translated...>> {
using translated_type = native_to_wasm_t<Input>; using translated_type = native_to_wasm_t<Input>;
using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., translated_type>>; using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., translated_type>>;
static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); }
using then_type = Ret (*)(wasm_interface&, Input, Inputs..., Translated...); 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<then_type Then> template<then_type Then>
static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, translated_type last) { static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, translated_type last) {
...@@ -211,8 +218,10 @@ struct intrinsic_invoker_impl<Ret, std::tuple<Input, Inputs...>, std::tuple<Tran ...@@ -211,8 +218,10 @@ struct intrinsic_invoker_impl<Ret, std::tuple<Input, Inputs...>, std::tuple<Tran
template<typename T, typename Ret, typename... Inputs, typename ...Translated> template<typename T, typename Ret, typename... Inputs, typename ...Translated>
struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, size_t, Inputs...>, std::tuple<Translated...>> { struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, size_t, Inputs...>, std::tuple<Translated...>> {
using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., I32, I32>>; using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., I32, I32>>;
static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); }
using then_type = Ret(*)(wasm_interface&, array_ptr<T>, size_t, Inputs..., Translated...); using then_type = Ret(*)(wasm_interface&, array_ptr<T>, 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<then_type Then> template<then_type Then>
static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, I32 ptr, I32 size) { static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, I32 ptr, I32 size) {
...@@ -240,8 +249,10 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, size_t, Inputs...>, ...@@ -240,8 +249,10 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, size_t, Inputs...>,
template<typename T, typename Ret, typename... Inputs, typename ...Translated> template<typename T, typename Ret, typename... Inputs, typename ...Translated>
struct intrinsic_invoker_impl<Ret, std::tuple<T*, Inputs...>, std::tuple<Translated...>> { struct intrinsic_invoker_impl<Ret, std::tuple<T*, Inputs...>, std::tuple<Translated...>> {
using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., I32>>; using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., I32>>;
static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); }
using then_type = Ret (*)(wasm_interface&, T*, Inputs..., Translated...); 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<then_type Then> template<then_type Then>
static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, I32 ptr) { static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, I32 ptr) {
...@@ -252,7 +263,7 @@ struct intrinsic_invoker_impl<Ret, std::tuple<T*, Inputs...>, std::tuple<Transla ...@@ -252,7 +263,7 @@ struct intrinsic_invoker_impl<Ret, std::tuple<T*, Inputs...>, std::tuple<Transla
template<then_type Then> template<then_type Then>
static const auto fn() { static const auto fn() {
return next_step::template fn<translate_one<Then>>; return next_step::template fn<translate_one<Then>>();
} }
}; };
...@@ -268,8 +279,10 @@ struct intrinsic_invoker_impl<Ret, std::tuple<T*, Inputs...>, std::tuple<Transla ...@@ -268,8 +279,10 @@ struct intrinsic_invoker_impl<Ret, std::tuple<T*, Inputs...>, std::tuple<Transla
template<typename T, typename Ret, typename... Inputs, typename ...Translated> template<typename T, typename Ret, typename... Inputs, typename ...Translated>
struct intrinsic_invoker_impl<Ret, std::tuple<T&, Inputs...>, std::tuple<Translated...>> { struct intrinsic_invoker_impl<Ret, std::tuple<T&, Inputs...>, std::tuple<Translated...>> {
using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., I32>>; using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., I32>>;
static const FunctionType* wasm_function_type() { return next_step::wasm_function_type(); }
using then_type = Ret (*)(wasm_interface&, T&, Inputs..., Translated...); 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<then_type Then> template<then_type Then>
static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, I32 ptr) { static Ret translate_one(wasm_interface& wasm, Inputs... rest, Translated... translated, I32 ptr) {
...@@ -282,7 +295,7 @@ struct intrinsic_invoker_impl<Ret, std::tuple<T&, Inputs...>, std::tuple<Transla ...@@ -282,7 +295,7 @@ struct intrinsic_invoker_impl<Ret, std::tuple<T&, Inputs...>, std::tuple<Transla
template<then_type Then> template<then_type Then>
static const auto fn() { static const auto fn() {
return next_step::template fn<translate_one<Then>>; return next_step::template fn<translate_one<Then>>();
} }
}; };
...@@ -295,6 +308,8 @@ struct intrinsic_function_invoker; ...@@ -295,6 +308,8 @@ struct intrinsic_function_invoker;
template<typename Cls, typename Ret, typename... Params> template<typename Cls, typename Ret, typename... Params>
struct intrinsic_function_invoker<Ret (Cls::*)(Params...)> { struct intrinsic_function_invoker<Ret (Cls::*)(Params...)> {
using impl = intrinsic_invoker_impl<Ret, std::tuple<Params...>, std::tuple<>>; using impl = intrinsic_invoker_impl<Ret, std::tuple<Params...>, std::tuple<>>;
using intrinsic_method_type = typename impl::intrinsic_method_type;
static const FunctionType* wasm_function_type() { return impl::wasm_function_type(); } static const FunctionType* wasm_function_type() { return impl::wasm_function_type(); }
template< Ret (Cls::*Method)(Params...) > template< Ret (Cls::*Method)(Params...) >
...@@ -303,21 +318,38 @@ struct intrinsic_function_invoker<Ret (Cls::*)(Params...)> { ...@@ -303,21 +318,38 @@ struct intrinsic_function_invoker<Ret (Cls::*)(Params...)> {
} }
template< Ret (Cls::*Method)(Params...) > template< Ret (Cls::*Method)(Params...) >
static const auto fn() { static const intrinsic_method_type fn() {
return impl::template fn<wrapper<Method>>();
}
};
template<typename Cls, typename... Params>
struct intrinsic_function_invoker<void (Cls::*)(Params...)> {
using impl = intrinsic_invoker_impl<void_type, std::tuple<Params...>, 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<wrapper<Method>>(); return impl::template fn<wrapper<Method>>();
} }
}; };
#define _REGISTER_INTRINSIC(R, DATA, METHOD)\ #define _REGISTER_INTRINSIC(R, CLS, METHOD)\
BOOST_PP_TUPLE_ELEM(2, 0, DATA).emplace( #METHOD, \ static Intrinsics::Function BOOST_PP_CAT(__intrinsic_fn_, __COUNTER__)(\
std::make_unique<Intrinsics::Function>(\ "env." BOOST_PP_STRINGIZE(METHOD),\
#METHOD,\ eosio::chain::intrinsic_function_invoker<decltype(&CLS::METHOD)>::wasm_function_type(),\
eosio::chain::intrinsic_function_invoker<decltype(&BOOST_PP_TUPLE_ELEM(2, 1, DATA)::METHOD)>::wasm_function_type(),\ (void *)eosio::chain::intrinsic_function_invoker<decltype(&CLS::METHOD)>::fn<&CLS::METHOD>()\
(void *)eosio::chain::intrinsic_function_invoker<decltype(&BOOST_PP_TUPLE_ELEM(2, 1, DATA)::METHOD)>::fn<&BOOST_PP_TUPLE_ELEM(2, 1, DATA)::METHOD>()\
)\
); );
#define REGISTER_INTRINSICS(DATA, MEMBERS)\ #define REGISTER_INTRINSICS(CLS, MEMBERS)\
BOOST_PP_SEQ_FOR_EACH(_REGISTER_INTRINSIC, DATA, MEMBERS) BOOST_PP_SEQ_FOR_EACH(_REGISTER_INTRINSIC, CLS, MEMBERS)
} }; } };
\ No newline at end of file
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include "Runtime/Runtime.h" #include "Runtime/Runtime.h"
#include "Runtime/Linker.h" #include "Runtime/Linker.h"
#include "Runtime/Intrinsics.h" #include "Runtime/Intrinsics.h"
#include "IR/Module.h"
#include "IR/Operators.h" #include "IR/Operators.h"
#include "IR/Validate.h" #include "IR/Validate.h"
#include "IR/Types.h" #include "IR/Types.h"
...@@ -31,8 +30,9 @@ using boost::asio::io_service; ...@@ -31,8 +30,9 @@ using boost::asio::io_service;
namespace eosio { namespace chain { namespace eosio { namespace chain {
FunctionInstance *resolve_intrinsic(const string& name); /**
* Integration with the WASM Linker to resolve our intrinsics
*/
struct root_resolver : Runtime::Resolver struct root_resolver : Runtime::Resolver
{ {
bool resolve(const string& mod_name, bool resolve(const string& mod_name,
...@@ -40,15 +40,12 @@ namespace eosio { namespace chain { ...@@ -40,15 +40,12 @@ namespace eosio { namespace chain {
ObjectType type, ObjectType type,
ObjectInstance*& out) override ObjectInstance*& out) override
{ {
if (mod_name == "env" && type.kind == ObjectKind::function ) { // Try to resolve an intrinsic first.
try { if(IntrinsicResolver::singleton.resolve(mod_name,export_name,type, out)) {
auto* intrinsic = resolve_intrinsic(export_name); return true;
if (intrinsic != nullptr) {
out = asObject(intrinsic);
return true;
}
} FC_RETHROW_EXCEPTIONS(error, "unresolvable symbol ${module}.${export}", ("module",mod_name)("export",export_name));
} }
FC_ASSERT( !"unresolvable", "${module}.${export}", ("module",mod_name)("export",export_name) );
return false; return false;
} }
}; };
...@@ -63,6 +60,8 @@ namespace eosio { namespace chain { ...@@ -63,6 +60,8 @@ namespace eosio { namespace chain {
:_ios() :_ios()
,_work(_ios) ,_work(_ios)
{ {
Runtime::init();
_utility_thread = std::thread([](io_service* ios){ _utility_thread = std::thread([](io_service* ios){
ios->run(); ios->run();
}, &_ios); }, &_ios);
...@@ -147,7 +146,7 @@ namespace eosio { namespace chain { ...@@ -147,7 +146,7 @@ namespace eosio { namespace chain {
return with_lock([&,this](){ return with_lock([&,this](){
auto iter = _cache.find(code_id); auto iter = _cache.find(code_id);
if (iter != _cache.end() && iter->second.available_instances > 0) { 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); return optional_entry_ref(*ptr);
} }
...@@ -186,7 +185,8 @@ namespace eosio { namespace chain { ...@@ -186,7 +185,8 @@ namespace eosio { namespace chain {
try { try {
Serialization::MemoryInputStream stream((const U8 *) wasm_binary, wasm_binary_size); 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; root_resolver resolver;
LinkResult link_result = linkModule(*module, resolver); LinkResult link_result = linkModule(*module, resolver);
...@@ -262,7 +262,7 @@ namespace eosio { namespace chain { ...@@ -262,7 +262,7 @@ namespace eosio { namespace chain {
* @param entry - the entry to return * @param entry - the entry to return
*/ */
void return_entry(const digest_type& code_id, wasm_cache::entry& entry) { 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 // sanitize by reseting the memory that may now be dirty
auto& info = (*fetch_info(code_id)).get(); auto& info = (*fetch_info(code_id)).get();
char* memstart = &memoryRef<char>( getDefaultMemory(entry.instance), 0 ); char* memstart = &memoryRef<char>( getDefaultMemory(entry.instance), 0 );
...@@ -338,7 +338,7 @@ namespace eosio { namespace chain { ...@@ -338,7 +338,7 @@ namespace eosio { namespace chain {
optional<wasm_context>& context; optional<wasm_context>& context;
}; };
void wasm_interface_impl::call(const string& entry_point, const vector<Value>& args, wasm_cache::entry& code, apply_context &context) void wasm_interface_impl::call(const string& entry_point, const vector<Value>& args, wasm_cache::entry& code, apply_context& context)
try { try {
FunctionInstance* call = asFunctionNullable(getInstanceExport(code.instance,entry_point) ); FunctionInstance* call = asFunctionNullable(getInstanceExport(code.instance,entry_point) );
if( !call ) { if( !call ) {
...@@ -361,9 +361,6 @@ namespace eosio { namespace chain { ...@@ -361,9 +361,6 @@ namespace eosio { namespace chain {
} }
wasm_interface& wasm_interface::get() { wasm_interface& wasm_interface::get() {
static bool init_once = [](){ Runtime::init(); return true; }();
boost::ignore_unused(init_once);
thread_local wasm_interface* single = nullptr; thread_local wasm_interface* single = nullptr;
if( !single ) { if( !single ) {
single = new wasm_interface(); single = new wasm_interface();
...@@ -528,24 +525,24 @@ DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) { ...@@ -528,24 +525,24 @@ DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) {
#endif #endif
#if defined(assert) #if defined(assert)
#undef assert #undef assert
#endif #endif
class intrinsics { class intrinsics {
public: public:
intrinsics(wasm_interface &wasm) intrinsics(wasm_interface& wasm)
:wasm(wasm) :wasm(wasm)
,context(intrinsics_accessor::get_context(wasm).context) ,context(intrinsics_accessor::get_context(wasm).context)
{} {}
int read_action(array_ptr<char> memory, size_t size) { int read_action(array_ptr<char> memory, size_t size) {
FC_ASSERT(size > 0); FC_ASSERT(size > 0);
int minlen = std::min<int>(context.act.data.size(), size); int minlen = std::min<size_t>(context.act.data.size(), size);
memcpy((void *)memory, context.act.data.data(), minlen); memcpy((void *)memory, context.act.data.data(), minlen);
return minlen; return minlen;
} }
void assert(bool condition, char const* str) { void assert(bool condition, char* str) {
std::string message( str ); std::string message( str );
if( !condition ) edump((message)); if( !condition ) edump((message));
FC_ASSERT( condition, "assertion failed: ${s}", ("s",message)); FC_ASSERT( condition, "assertion failed: ${s}", ("s",message));
...@@ -556,23 +553,6 @@ class intrinsics { ...@@ -556,23 +553,6 @@ class intrinsics {
apply_context& context; apply_context& context;
}; };
static map<string, unique_ptr<Intrinsics::Function>> intrinsic_registry; REGISTER_INTRINSICS(intrinsics, (read_action)(assert));
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;
}
} } /// eosio::chain } } /// eosio::chain
...@@ -45,11 +45,20 @@ namespace eosio { namespace testing { ...@@ -45,11 +45,20 @@ namespace eosio { namespace testing {
public_key_type get_public_key( name keyname, string role = "owner" ); public_key_type get_public_key( name keyname, string role = "owner" );
private_key_type get_private_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<chain_controller> control; unique_ptr<chain_controller> control;
bool chain_has_transaction( const transaction_id_type& txid ) const;
const transaction_receipt& get_transaction_receipt( const transaction_id_type& txid ) const;
private: private:
fc::temp_directory tempdir; fc::temp_directory tempdir;
chain_controller::controller_config cfg; chain_controller::controller_config cfg;
map<transaction_id_type, transaction_receipt> chain_transactions;
}; };
} } /// eosio::testing } } /// eosio::testing
...@@ -2,8 +2,14 @@ ...@@ -2,8 +2,14 @@
#include <eosio/chain/asset.hpp> #include <eosio/chain/asset.hpp>
#include <eosio/chain/contracts/types.hpp> #include <eosio/chain/contracts/types.hpp>
namespace eosio { namespace testing { #include <fc/utility.hpp>
#include "WAST/WAST.h"
#include "WASM/WASM.h"
#include "IR/Module.h"
#include "IR/Validate.h"
namespace eosio { namespace testing {
tester::tester() { tester::tester() {
cfg.block_log_dir = tempdir.path() / "blocklog"; cfg.block_log_dir = tempdir.path() / "blocklog";
...@@ -41,9 +47,21 @@ namespace eosio { namespace testing { ...@@ -41,9 +47,21 @@ namespace eosio { namespace testing {
void tester::close() { void tester::close() {
control.reset(); control.reset();
chain_transactions.clear();
} }
void tester::open() { void tester::open() {
control.reset( new chain_controller(cfg) ); 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 ) { signed_block tester::produce_block( fc::microseconds skip_time ) {
...@@ -134,4 +152,72 @@ namespace eosio { namespace testing { ...@@ -134,4 +152,72 @@ namespace eosio { namespace testing {
control->push_transaction( trx ); control->push_transaction( trx );
} FC_CAPTURE_AND_RETHROW( (account)(perm)(auth)(parent) ) } } 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<unsigned char> {
using namespace IR;
using namespace WAST;
using namespace WASM;
using namespace Serialization;
Module module;
vector<Error> 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<permission_level>{{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 } } /// eosio::test
...@@ -24,8 +24,13 @@ endif() ...@@ -24,8 +24,13 @@ endif()
file(GLOB UNIT_TESTS "chain_tests/*.cpp") 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} ) target_link_libraries( chain_test eosio_testing eosio_chain chainbase eos_utilities eos_egenesis_none chain_plugin fc ${PLATFORM_SPECIFIC_LIBS} )
if(WASM_TOOLCHAIN) if(WASM_TOOLCHAIN)
target_include_directories( chain_test PUBLIC ${CMAKE_BINARY_DIR}/contracts ${CMAKE_CURRENT_BINARY_DIR}/tests/contracts ) target_include_directories( chain_test PUBLIC ${CMAKE_BINARY_DIR}/contracts ${CMAKE_CURRENT_BINARY_DIR}/tests/contracts )
# add_dependencies(chain_test rate_limit_auth) # add_dependencies(chain_test rate_limit_auth)
......
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <asserter/asserter.wast.hpp>
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<permission_level>{{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<permission_level>{{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<permission_level>{{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()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册