diff --git a/.travis.yml b/.travis.yml index 56bb9f78026d5c740772fa41d604271c8c49a1e5..23952ef80062a4490e7984f44bd09000fbecccb6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ matrix: - libgmp-dev - libclang-4.0-dev - python3 + - sharutils - os: osx osx_image: xcode9.1 before_install: @@ -49,7 +50,7 @@ before_install: cd boost_1_64_0 ./bootstrap.sh --prefix=$TRAVIS_BUILD_DIR/ext echo 'using clang : 4.0 : clang++-4.0 ;' >> project-config.jam - ./b2 -d0 -j4 --with-thread --with-date_time --with-system --with-filesystem --with-program_options --with-signals --with-serialization --with-chrono --with-test --with-context --with-locale --with-coroutine toolset=clang link=static install + ./b2 -d0 -j4 --with-iostreams --with-thread --with-date_time --with-system --with-filesystem --with-program_options --with-signals --with-serialization --with-chrono --with-test --with-context --with-locale --with-coroutine toolset=clang link=static install cd $TRAVIS_BUILD_DIR/ext wget https://cmake.org/files/v3.9/cmake-3.9.0-Linux-x86_64.tar.gz tar xzf cmake-3.9.0-Linux-x86_64.tar.gz @@ -77,7 +78,7 @@ script: - mkdir build && cd build - ${CMAKE_DIR}cmake -G Ninja -DWASM_LLVM_CONFIG=$TRAVIS_BUILD_DIR/ext/wasm-compiler/bin/llvm-config -DSecp256k1_ROOT_DIR=$TRAVIS_BUILD_DIR/ext -DBINARYEN_ROOT=$TRAVIS_BUILD_DIR/ext/wasm-compiler -DCMAKE_PREFIX_PATH=$TRAVIS_BUILD_DIR/ext -DCMAKE_BUILD_TYPE=Release -DBUILD_MONGO_DB_PLUGIN=true $EOS_CMAKE_OPTIONS .. - ninja -j4 - - '[ "$TRAVIS_OS_NAME" == "osx" ] || ctest --output-on-failure' + - '[ "$TRAVIS_OS_NAME" == "osx" ] || (export EOSLIB=$TRAVIS_BUILD_DIR/contracts; ctest --output-on-failure)' - cpack deploy: diff --git a/CMakeLists.txt b/CMakeLists.txt index 38ae54c94e4548cdffeadfb55ded0a2a841b4c89..49af03343e11ddf3c0b81f8a73a5a3e44a8c3a72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,9 +171,7 @@ if(WASM_TOOLCHAIN) message(STATUS "Using WASM llvm-link => " ${WASM_LLVM_LINK}) add_subdirectory(contracts) else() - message(STATUS "--------------------------------------------------------------------") - message(STATUS "No WASM compiler could be found ... (skipping building of contracts)") - message(STATUS "--------------------------------------------------------------------") + message( FATAL_ERROR "No WASM compiler cound be found" ) endif() include(installer) diff --git a/CMakeModules/wasm.cmake b/CMakeModules/wasm.cmake index 0881c8a2b4c6f811168811ad734bcd3de2af7511..390dcbd9b52d176985ce4389ad7fad8c5f7a603e 100644 --- a/CMakeModules/wasm.cmake +++ b/CMakeModules/wasm.cmake @@ -138,10 +138,11 @@ macro(add_wast_target target INCLUDE_FOLDERS DESTINATION_FOLDER) VERBATIM ) set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.wast) - + STRING (REPLACE "." "_" TARGET_VARIABLE "${target}") + add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.wast.hpp DEPENDS ${DESTINATION_FOLDER}/${target}.wast - COMMAND echo "const char* ${target}_wast = R\"=====(" > ${DESTINATION_FOLDER}/${target}.wast.hpp + COMMAND echo "const char* const ${TARGET_VARIABLE}_wast = R\"=====(" > ${DESTINATION_FOLDER}/${target}.wast.hpp COMMAND cat ${DESTINATION_FOLDER}/${target}.wast >> ${DESTINATION_FOLDER}/${target}.wast.hpp COMMAND echo ")=====\";" >> ${DESTINATION_FOLDER}/${target}.wast.hpp COMMENT "Generating ${target}.wast.hpp" @@ -151,7 +152,7 @@ macro(add_wast_target target INCLUDE_FOLDERS DESTINATION_FOLDER) if (EXISTS ${DESTINATION_FOLDER}/${target}.abi ) add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.abi.hpp DEPENDS ${DESTINATION_FOLDER}/${target}.abi - COMMAND echo "const char* ${target}_abi = R\"=====(" > ${DESTINATION_FOLDER}/${target}.abi.hpp + COMMAND echo "const char* const ${TARGET_VARIABLE}_abi = R\"=====(" > ${DESTINATION_FOLDER}/${target}.abi.hpp COMMAND cat ${DESTINATION_FOLDER}/${target}.abi >> ${DESTINATION_FOLDER}/${target}.abi.hpp COMMAND echo ")=====\";" >> ${DESTINATION_FOLDER}/${target}.abi.hpp COMMENT "Generating ${target}.abi.hpp" diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 89ea2b22f26a8ae86ba2a61554082eea66253123..39cd12bee4ef3b29de2bef2b6edd507dc86bc2a1 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -31,7 +31,7 @@ RUN wget https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar. && ./bootstrap.sh --prefix=/usr/local \ && echo 'using clang : 4.0 : clang++-4.0 ;' >> project-config.jam \ && ./b2 -d0 -j4 --with-thread --with-date_time --with-system --with-filesystem --with-program_options \ - --with-signals --with-serialization --with-chrono --with-test --with-context --with-locale --with-coroutine toolset=clang link=static install \ + --with-signals --with-serialization --with-chrono --with-test --with-context --with-locale --with-coroutine --with-iostreams toolset=clang link=static install \ && cd .. && rm -rf boost_1_64_0 RUN wget https://github.com/mongodb/mongo-c-driver/releases/download/1.8.0/mongo-c-driver-1.8.0.tar.gz -O - | tar -xz \ diff --git a/README.md b/README.md index f25433730894b09d79901363132daf45430cf8a2..045045183fc0a1adf4a064d11db3d6744f969cf5 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ The public testnet described in the [wiki](https://github.com/EOSIO/eos/wiki/Tes 2. [Setting up a build/development environment](#setup) 1. [Automated build script](#autobuild) 1. [Clean install Ubuntu 16.10 for a local testnet](#autoubuntulocal) - 2. [Clean install Ubuntu 16.10 for the public testnet](#autobuntupublic) + 2. [Clean install Ubuntu 16.10 for the public testnet](#autoubuntupublic) 3. [MacOS Sierra 10.12.6 for a local testnet](#automaclocal) 4. [MacOS Sierra 10.12.6 for the public testnet](#automacpublic) 3. [Building EOS and running a node](#runanode) @@ -61,25 +61,29 @@ The following instructions detail the process of getting the software, building For Ubuntu 16.10 and MacOS Sierra, there is an automated build script that can install all dependencies and builds EOS. -It is called build.sh with the following inputs. +It is called eosio-build.sh with the following inputs. - architecture [ubuntu|darwin] - optional mode [full|build] The second optional input can be `full` or `build` where `full` implies that it installs dependencies and builds eos. If you omit this input then the build script installs dependencies and then builds eos. ```bash -./build.sh +./eosio-build.sh ``` -Choose whether you will be building for a local testnet or for the public testnet and jump to the appropriate section below. Clone the EOS repository recursively as described and run build.sh located in the root `eos` folder. +Choose whether you will be building for a local testnet or for the public testnet and jump to the appropriate section below. Clone the EOS repository recursively as described and run eosio-build.sh located in the root `eos` folder. + +:warning: **As of February 2018, `master` is under heavy development and is not suitable for experimentation.** :warning: + +We strongly recommend following the instructions for building the public testnet version for [Ubuntu](#autoubuntupublic) or [Mac OS X](#automacpublic). `master` is in pieces on the garage floor while we rebuild this hotrod. This notice will be removed when `master` is usable again. Your patience is appreciated. -#### Clean install Ubuntu 16.10 for a local testnet +#### :no_entry: Clean install Ubuntu 16.10 for a local testnet :no_entry: ```bash git clone https://github.com/eosio/eos --recursive cd eos -./build.sh ubuntu +./eosio-build.sh ubuntu ``` Now you can proceed to the next step - [Creating and launching a single-node testnet](#singlenode) @@ -92,13 +96,13 @@ git clone https://github.com/eosio/eos --recursive cd eos git checkout dawn-2.x -./build.sh ubuntu +./eosio-build.sh ubuntu ``` Now you can proceed to the next step - [Running a node on the public testnet](#publictestnet) -#### MacOS Sierra for a local testnet +#### :no_entry: MacOS Sierra for a local testnet :no_entry: Before running the script make sure you have updated XCode and brew: @@ -107,13 +111,13 @@ xcode-select --install ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" ``` -Then clone the EOS repository recursively and run build.sh in the root `eos` folder. +Then clone the EOS repository recursively and run eosio-build.sh in the root `eos` folder. ```bash git clone https://github.com/eosio/eos --recursive cd eos -./build.sh darwin +./eosio-build.sh darwin ``` Now you can proceed to the next step - [Creating and launching a single-node testnet](#singlenode) @@ -128,14 +132,14 @@ xcode-select --install ruby -e "$(curl -fsSl https://raw.githubusercontent.com/Homebrew/install/master/install)" ``` -Then clone the EOS repository recursively, checkout the branch that is compatible with the public testnet, and run build.sh in the root `eos` folder. +Then clone the EOS repository recursively, checkout the branch that is compatible with the public testnet, and run eosio-build.sh in the root `eos` folder. ```bash git clone https://github.com/eosio/eos --recursive cd eos git checkout dawn-2.x -./build.sh darwin +./eosio-build.sh darwin ``` Now you can proceed to the next step - [Running a node on the public testnet](#publictestnet) @@ -184,8 +188,8 @@ EOS comes with a number of programs you can find in `~/eos/build/programs`. They * eosiod - server-side blockchain node component * eosioc - command line interface to interact with the blockchain -* eosio-walletd - EOS wallet -* launcher - application for nodes network composing and deployment; [more on launcher](https://github.com/EOSIO/eos/blob/master/testnet.md) +* eosiowd - EOS wallet +* eosio-launcher - application for nodes network composing and deployment; [more on eosio-launcher](https://github.com/EOSIO/eos/blob/master/testnet.md) ### Creating and launching a single-node testnet @@ -425,14 +429,14 @@ As expected, the receiving account **inita** now has a balance of **20** tokens, ## Running multi-node local testnet -To run a local testnet you can use a `launcher` application provided in the `~/eos/build/programs/launcher` folder. +To run a local testnet you can use the `eosio-launcher` application provided in the `~/eos/build/programs/eosio-launcher` folder. For testing purposes you will run two local production nodes talking to each other. ```bash cd ~/eos/build cp ../genesis.json ./ -./programs/launcher/launcher -p2 --skip-signature +./programs/eosio-launcher/eosio-launcher -p2 --skip-signature ``` This command will generate two data folders for each instance of the node: `tn_data_00` and `tn_data_01`. @@ -453,7 +457,7 @@ To confirm the nodes are running, run the following `eosioc` commands: For each command, you should get a JSON response with blockchain information. -You can read more on launcher and its settings [here](https://github.com/EOSIO/eos/blob/master/testnet.md) +You can read more on eosio-launcher and its settings [here](https://github.com/EOSIO/eos/blob/master/testnet.md) ## Running a local node connected to the public testnet diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index df12816231db07903544f7549c2f5e7399c5ba12..654a2c040eba15b252f2af806aa53233fce54d27 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory(test_api_mem) #add_subdirectory(simpledb) #add_subdirectory(storage) #add_subdirectory(social) +add_subdirectory(noop) install( DIRECTORY eosiolib DESTINATION include/ ) install( DIRECTORY skeleton DESTINATION share/ ) diff --git a/contracts/eosio.system/eosio.system.abi b/contracts/eosio.system/eosio.system.abi index c8d8e4b16e908bcede68ba02f90bd7d86d7ed391..b67e3c8c6149b00d3b558ffb28b17e1881998617 100644 --- a/contracts/eosio.system/eosio.system.abi +++ b/contracts/eosio.system/eosio.system.abi @@ -10,8 +10,16 @@ "fields": [ {"name":"from", "type":"account_name"}, {"name":"to", "type":"account_name"}, - {"name":"quantity", "type":"uint64"} + {"name":"quantity", "type":"asset"}, + {"name":"memo", "type":"string"} ] + },{ + "name": "issue", + "base": "", + "fields": [ + {"name":"to", "type":"account_name"}, + {"name":"quantity", "type":"asset"} + ] },{ "name": "account", "base": "", @@ -19,11 +27,23 @@ {"name":"key", "type":"name"}, {"name":"balance", "type":"uint64"} ] + },{ + "name": "nonce", + "base": "", + "fields": [ + {"name":"value", "type":"string"} + ] } ], "actions": [{ "name": "transfer", "type": "transfer" + },{ + "name": "issue", + "type": "issue" + },{ + "name": "nonce", + "type": "nonce" } ], "tables": [{ diff --git a/contracts/eosio.system/eosio.system.hpp b/contracts/eosio.system/eosio.system.hpp index e87b4db2acc7032a696fb1e1d7cbc4f7fd7a334d..6b2c9dff14ce585a4a3f71dc7e04dd41eb69c79e 100644 --- a/contracts/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/eosio.system.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,34 @@ namespace eosiosystem { static const account_name system_account = N(eosio.system); typedef eosio::generic_currency< eosio::token > currency; + struct total_bandwidth { + account_name owner; + typename currency::token_type total_net_weight; + typename currency::token_type total_cpu_weight; + }; + + typedef eosio::table64 total_bandwidth; + + struct delegated_bandwidth { + account_name from; + account_name to; + typename currency::token_type net_weight; + typename currency::token_type cpu_weight; + + uint32_t start_pending_net_withdraw = 0; + typename currency::token_type pending_net_withdraw; + uint64_t deferred_net_withdraw_handler = 0; + + uint32_t start_pending_cpu_withdraw = 0; + typename currency::token_type pending_cpu_withdraw; + uint64_t deferred_cpu_withdraw_handler = 0; + }; + + ACTION( SystemAccount, finshundel ) { + account_name from; + account_name to; + }; + ACTION( SystemAccount, regproducer ) { account_name producer_to_register; @@ -31,6 +60,35 @@ namespace eosiosystem { EOSLIB_SERIALIZE( regproxy, (proxy_to_register) ); }; + ACTION( SystemAccount, delnetbw ) { + account_name from; + account_name receiver; + typename currency::token_type stake_quantity; + + EOSLIB_SERIALIZE( delnetbw, (delegator)(receiver)(stake_quantity) ) + }; + + ACTION( SystemAccount, undelnetbw ) { + account_name from; + account_name receiver; + typename currency::token_type stake_quantity; + + EOSLIB_SERIALIZE( delnetbw, (delegator)(receiver)(stake_quantity) ) + }; + + ACTION( SystemAccount, nonce ) { + eosio::string value; + + EOSLIB_SERIALIZE( nonce, (value) ); + }; + + static void on( const delnetbw& del ) { + require_auth( del.from ); + // require_account( receiver ); + + currency::inline_transfer( del.from, SystemAccount, del.stake_quantity, "stake bandwidth" ); + } + static void on( const regproducer& reg ) { require_auth( reg.producer_to_register ); } @@ -39,16 +97,15 @@ namespace eosiosystem { require_auth( reg.proxy_to_register ); } + static void on( const nonce& ) { + } static void apply( account_name code, action_name act ) { - if( !eosio::dispatch( code, act) ) - { - assert( false, "received unexpected action" ); + if( !eosio::dispatch( code, act) ) { + if ( !eosio::dispatch( code, act ) ) { + eosio::print("Unexpected action: ", act, "\n"); + assert( false, "received unexpected action"); + } } } /// apply }; diff --git a/contracts/eosiolib/db.h b/contracts/eosiolib/db.h index f8a9900b4ac870172f0119326b5998bf61370df7..a74f7e2b80c7456186506c21027fbaccb67a6019 100644 --- a/contracts/eosiolib/db.h +++ b/contracts/eosiolib/db.h @@ -124,7 +124,7 @@ extern "C" { * @throw if called with an invalid precondition execution will be aborted * */ -int32_t store_i64( account_name scope, table_name table, const void* data, uint32_t datalen ); +int32_t store_i64( account_name scope, table_name table, account_name bta, const void* data, uint32_t datalen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -143,7 +143,7 @@ int32_t store_i64( account_name scope, table_name table, const void* data, uint3 * @throw if called with an invalid precondition execution will be aborted * */ -int32_t update_i64( account_name scope, table_name table, const void* data, uint32_t datalen ); +int32_t update_i64( account_name scope, table_name table, account_name bta, const void* data, uint32_t datalen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -154,7 +154,7 @@ int32_t update_i64( account_name scope, table_name table, const void* data, uint * * @return the number of bytes read or -1 if key was not found */ -int32_t load_i64( account_name scope, account_name code, table_name table, void* data, uint32_t datalen ); +int32_t load_i64( account_name code, account_name scope, table_name table, void* data, uint32_t datalen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -165,7 +165,7 @@ int32_t load_i64( account_name scope, account_name code, table_name table, void* * * @return the number of bytes read or -1 if no record found */ -int32_t front_i64( account_name scope, account_name code, table_name table, void* data, uint32_t datalen ); +int32_t front_i64( account_name code, account_name scope, table_name table, void* data, uint32_t datalen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -176,7 +176,7 @@ int32_t front_i64( account_name scope, account_name code, table_name table, void * * @return the number of bytes read or -1 if no record found */ -int32_t back_i64( account_name scope, account_name code, table_name table, void* data, uint32_t datalen ); +int32_t back_i64( account_name code, account_name scope, table_name table, void* data, uint32_t datalen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -187,7 +187,7 @@ int32_t back_i64( account_name scope, account_name code, table_name table, void* * * @return the number of bytes read or -1 if key was not found */ -int32_t next_i64( account_name scope, account_name code, table_name table, void* data, uint32_t datalen ); +int32_t next_i64( account_name code, account_name scope, table_name table, void* data, uint32_t datalen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -198,7 +198,7 @@ int32_t next_i64( account_name scope, account_name code, table_name table, void* * * @return the number of bytes read or -1 if key was not found */ -int32_t previous_i64( account_name scope, account_name code, table_name table, void* data, uint32_t datalen ); +int32_t previous_i64( account_name code, account_name scope, table_name table, void* data, uint32_t datalen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -209,7 +209,7 @@ int32_t previous_i64( account_name scope, account_name code, table_name table, v * * @return the number of bytes read or -1 if key was not found */ -int32_t lower_bound_i64( account_name scope, account_name code, table_name table, void* data, uint32_t datalen ); +int32_t lower_bound_i64( account_name code, account_name scope, table_name table, void* data, uint32_t datalen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -220,7 +220,7 @@ int32_t lower_bound_i64( account_name scope, account_name code, table_name table * * @return the number of bytes read or -1 if key was not found */ -int32_t upper_bound_i64( account_name scope, account_name code, table_name table, void* data, uint32_t datalen ); +int32_t upper_bound_i64( account_name code, account_name scope, table_name table, void* data, uint32_t datalen ); /** * @param scope - the account socpe that will be read, must exist in the transaction scopes list @@ -263,7 +263,7 @@ int32_t remove_i64( account_name scope, table_name table, void* data ); * @throw if called with an invalid precondition execution will be aborted * */ - int32_t store_str( account_name scope, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); +int32_t store_str( account_name scope, table_name table, account_name bta, char* key, uint32_t keylen, char* value, uint32_t valuelen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -285,7 +285,7 @@ int32_t remove_i64( account_name scope, table_name table, void* data ); * @throw if called with an invalid precondition execution will be aborted * */ - int32_t update_str( account_name scope, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); +int32_t update_str( account_name scope, table_name table, account_name bta, char* key, uint32_t keylen, char* value, uint32_t valuelen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -298,7 +298,7 @@ int32_t remove_i64( account_name scope, table_name table, void* data ); * * @return the number of bytes read or -1 if key was not found */ - int32_t load_str( account_name scope, account_name code, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); + int32_t load_str( account_name code, account_name scope, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -310,7 +310,7 @@ int32_t remove_i64( account_name scope, table_name table, void* data ); * @param valuelen - maximum length of the record value to read * @return the number of bytes read or -1 if key was not found */ - int32_t front_str( account_name scope, account_name code, table_name table, char* value, uint32_t valuelen ); + int32_t front_str( account_name code, account_name scope, table_name table, char* value, uint32_t valuelen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -322,7 +322,7 @@ int32_t remove_i64( account_name scope, table_name table, void* data ); * @param valuelen - maximum length of the record value to read * @return the number of bytes read or -1 if key was not found */ - int32_t back_str( account_name scope, account_name code, table_name table, char* value, uint32_t valuelen ); + int32_t back_str( account_name code, account_name scope, table_name table, char* value, uint32_t valuelen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -334,7 +334,7 @@ int32_t remove_i64( account_name scope, table_name table, void* data ); * @param valuelen - maximum length of the record value to read * @return the number of bytes read or -1 if key was not found */ - int32_t next_str( account_name scope, account_name code, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); + int32_t next_str( account_name code, account_name scope, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -346,7 +346,7 @@ int32_t remove_i64( account_name scope, table_name table, void* data ); * @param valuelen - maximum length of the record value to read * @return the number of bytes read or -1 if key was not found */ - int32_t previous_str( account_name scope, account_name code, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); + int32_t previous_str( account_name code, account_name scope, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -358,7 +358,7 @@ int32_t remove_i64( account_name scope, table_name table, void* data ); * @param valuelen - maximum length of the record value to read * @return the number of bytes read or -1 if key was not found */ - int32_t lower_bound_str( account_name scope, account_name code, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); + int32_t lower_bound_str( account_name code, account_name scope, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -370,7 +370,7 @@ int32_t remove_i64( account_name scope, table_name table, void* data ); * @param valuelen - maximum length of the record value to read * @return the number of bytes read or -1 if key was not found */ - int32_t upper_bound_str( account_name scope, account_name code, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); + int32_t upper_bound_str( account_name code, account_name scope, table_name table, char* key, uint32_t keylen, char* value, uint32_t valuelen ); /** * @param key - location of the record key @@ -488,7 +488,7 @@ int32_t remove_i64( account_name scope, table_name table, void* data ); * @throw if called with an invalid precondition execution will be aborted * */ -int32_t load_primary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t load_primary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -499,7 +499,7 @@ int32_t load_primary_i128i128( account_name scope, account_name code, table_name * * @return the number of bytes read or -1 if no record found */ -int32_t front_primary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t front_primary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -510,7 +510,7 @@ int32_t front_primary_i128i128( account_name scope, account_name code, table_nam * * @return the number of bytes read or -1 if no record found */ -int32_t back_primary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t back_primary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -521,7 +521,7 @@ int32_t back_primary_i128i128( account_name scope, account_name code, table_name * * @return the number of bytes read or -1 if no record found */ -int32_t next_primary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t next_primary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -532,7 +532,7 @@ int32_t next_primary_i128i128( account_name scope, account_name code, table_name * * @return the number of bytes read or -1 if no record found */ -int32_t previous_primary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t previous_primary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -543,7 +543,7 @@ int32_t previous_primary_i128i128( account_name scope, account_name code, table_ * * @return the number of bytes read or -1 if no record found */ -int32_t upper_bound_primary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t upper_bound_primary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -554,7 +554,7 @@ int32_t upper_bound_primary_i128i128( account_name scope, account_name code, tab * * @return the number of bytes read or -1 if no record found */ -int32_t lower_bound_primary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t lower_bound_primary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -575,7 +575,7 @@ int32_t lower_bound_primary_i128i128( account_name scope, account_name code, tab * @throw if called with an invalid precondition execution will be aborted * */ -int32_t load_secondary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t load_secondary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -586,7 +586,7 @@ int32_t load_secondary_i128i128( account_name scope, account_name code, table_na * * @return the number of bytes read or -1 if no record found */ -int32_t front_secondary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t front_secondary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -597,7 +597,7 @@ int32_t front_secondary_i128i128( account_name scope, account_name code, table_n * * @return the number of bytes read or -1 if no record found */ -int32_t back_secondary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t back_secondary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -608,7 +608,7 @@ int32_t back_secondary_i128i128( account_name scope, account_name code, table_na * * @return the number of bytes read or -1 if no record found */ -int32_t next_secondary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t next_secondary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -619,7 +619,7 @@ int32_t next_secondary_i128i128( account_name scope, account_name code, table_na * * @return the number of bytes read or -1 if no record found */ -int32_t previous_secondary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t previous_secondary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -630,7 +630,7 @@ int32_t previous_secondary_i128i128( account_name scope, account_name code, tabl * * @return the number of bytes read or -1 if no record found */ -int32_t upper_bound_secondary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t upper_bound_secondary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -641,7 +641,7 @@ int32_t upper_bound_secondary_i128i128( account_name scope, account_name code, t * * @return the number of bytes read or -1 if no record found */ -int32_t lower_bound_secondary_i128i128( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t lower_bound_secondary_i128i128( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** @@ -659,7 +659,7 @@ int32_t remove_i128i128( account_name scope, table_name table, const void* data * @param len - the length of the data * @return 1 if a new record was created, 0 if an existing record was updated */ -int32_t store_i128i128( account_name scope, table_name table, const void* data, uint32_t len ); +int32_t store_i128i128( account_name scope, table_name table, account_name bta, const void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -668,7 +668,7 @@ int32_t store_i128i128( account_name scope, table_name table, const void* data, * @param len - the length of the data * @return 1 if the record was updated, 0 if no record with key was found */ -int32_t update_i128i128( account_name scope, table_name table, const void* data, uint32_t len ); +int32_t update_i128i128( account_name scope, table_name table, account_name bta, const void* data, uint32_t len ); ///@} dbi128i128 @@ -762,7 +762,7 @@ int32_t update_i128i128( account_name scope, table_name table, const void* data, * @throw if called with an invalid precondition execution will be aborted * */ -int32_t load_primary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t load_primary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -773,7 +773,7 @@ int32_t load_primary_i64i64i64( account_name scope, account_name code, table_nam * * @return the number of bytes read or -1 if no record found */ -int32_t front_primary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t front_primary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -784,7 +784,7 @@ int32_t front_primary_i64i64i64( account_name scope, account_name code, table_na * * @return the number of bytes read or -1 if no record found */ -int32_t back_primary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t back_primary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -795,7 +795,7 @@ int32_t back_primary_i64i64i64( account_name scope, account_name code, table_nam * * @return the number of bytes read or -1 if no record found */ -int32_t next_primary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t next_primary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -806,7 +806,7 @@ int32_t next_primary_i64i64i64( account_name scope, account_name code, table_nam * * @return the number of bytes read or -1 if no record found */ -int32_t previous_primary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t previous_primary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -817,7 +817,7 @@ int32_t previous_primary_i64i64i64( account_name scope, account_name code, table * * @return the number of bytes read or -1 if no record found */ -int32_t upper_bound_primary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t upper_bound_primary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -828,7 +828,7 @@ int32_t upper_bound_primary_i64i64i64( account_name scope, account_name code, ta * * @return the number of bytes read or -1 if no record found */ -int32_t lower_bound_primary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t lower_bound_primary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -848,7 +848,7 @@ int32_t lower_bound_primary_i64i64i64( account_name scope, account_name code, ta * @throw if called with an invalid precondition execution will be aborted * */ -int32_t load_secondary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t load_secondary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -859,7 +859,7 @@ int32_t load_secondary_i64i64i64( account_name scope, account_name code, table_n * * @return the number of bytes read or -1 if no record found */ -int32_t front_secondary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t front_secondary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -870,7 +870,7 @@ int32_t front_secondary_i64i64i64( account_name scope, account_name code, table_ * * @return the number of bytes read or -1 if no record found */ -int32_t back_secondary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t back_secondary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -881,7 +881,7 @@ int32_t back_secondary_i64i64i64( account_name scope, account_name code, table_n * * @return the number of bytes read or -1 if no record found */ -int32_t next_secondary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t next_secondary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -892,7 +892,7 @@ int32_t next_secondary_i64i64i64( account_name scope, account_name code, table_n * * @return the number of bytes read or -1 if no record found */ -int32_t previous_secondary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t previous_secondary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -903,7 +903,7 @@ int32_t previous_secondary_i64i64i64( account_name scope, account_name code, tab * * @return the number of bytes read or -1 if no record found */ -int32_t upper_bound_secondary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t upper_bound_secondary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -914,7 +914,7 @@ int32_t upper_bound_secondary_i64i64i64( account_name scope, account_name code, * * @return the number of bytes read or -1 if no record found */ -int32_t lower_bound_secondary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t lower_bound_secondary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -934,7 +934,7 @@ int32_t lower_bound_secondary_i64i64i64( account_name scope, account_name code, * @throw if called with an invalid precondition execution will be aborted * */ -int32_t load_tertiary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t load_tertiary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -945,7 +945,7 @@ int32_t load_tertiary_i64i64i64( account_name scope, account_name code, table_na * * @return the number of bytes read or -1 if no record found */ -int32_t front_tertiary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t front_tertiary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -956,7 +956,7 @@ int32_t front_tertiary_i64i64i64( account_name scope, account_name code, table_n * * @return the number of bytes read or -1 if no record found */ -int32_t back_tertiary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t back_tertiary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -967,7 +967,7 @@ int32_t back_tertiary_i64i64i64( account_name scope, account_name code, table_na * * @return the number of bytes read or -1 if no record found */ -int32_t next_tertiary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t next_tertiary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -978,7 +978,7 @@ int32_t next_tertiary_i64i64i64( account_name scope, account_name code, table_na * * @return the number of bytes read or -1 if no record found */ -int32_t previous_tertiary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t previous_tertiary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -989,7 +989,7 @@ int32_t previous_tertiary_i64i64i64( account_name scope, account_name code, tabl * * @return the number of bytes read or -1 if no record found */ -int32_t upper_bound_tertiary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t upper_bound_tertiary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -1000,7 +1000,7 @@ int32_t upper_bound_tertiary_i64i64i64( account_name scope, account_name code, t * * @return the number of bytes read or -1 if no record found */ -int32_t lower_bound_tertiary_i64i64i64( account_name scope, account_name code, table_name table, void* data, uint32_t len ); +int32_t lower_bound_tertiary_i64i64i64( account_name code, account_name scope, table_name table, void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -1017,7 +1017,7 @@ int32_t remove_i64i64i64( account_name scope, table_name table, const void* data * @param len - length of the data * @return 1 if a new record was created, 0 if an existing record was updated */ -int32_t store_i64i64i64( account_name scope, table_name table, const void* data, uint32_t len ); +int32_t store_i64i64i64( account_name scope, table_name table, account_name bta, const void* data, uint32_t len ); /** * @param scope - the account scope that will be read, must exist in the transaction scopes list @@ -1026,7 +1026,7 @@ int32_t store_i64i64i64( account_name scope, table_name table, const void* data, * @param len - length of the data * @return 1 if the record was updated, 0 if no record with key was found */ -int32_t update_i64i64i64( account_name scope, table_name table, const void* data, uint32_t len ); +int32_t update_i64i64i64( account_name scope, table_name table, account_name bta, const void* data, uint32_t len ); ///@} dbi64i64i64 } diff --git a/contracts/eosiolib/db.hpp b/contracts/eosiolib/db.hpp index 75aa264b3838dc46544d6ecf343116f7530f37da..8fe7f3996903dc97f0a8a42a6511c22d89dcf154 100644 --- a/contracts/eosiolib/db.hpp +++ b/contracts/eosiolib/db.hpp @@ -27,72 +27,72 @@ struct table_impl{}; template<> struct table_impl { - static int32_t front_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return front_primary_i128i128( scope, code, table_n, data, len ); + static int32_t front_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return front_primary_i128i128( code, scope, table_n, data, len ); } - static int32_t back_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return back_primary_i128i128( scope, code, table_n, data, len ); + static int32_t back_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return back_primary_i128i128( code, scope, table_n, data, len ); } - static int32_t load_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return load_primary_i128i128( scope, code, table_n, data, len ); + static int32_t load_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return load_primary_i128i128( code, scope, table_n, data, len ); } - static int32_t next_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return next_primary_i128i128( scope, code, table_n, data, len ); + static int32_t next_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return next_primary_i128i128( code, scope, table_n, data, len ); } - static int32_t previous_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return previous_primary_i128i128( scope, code, table_n, data, len ); + static int32_t previous_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return previous_primary_i128i128( code, scope, table_n, data, len ); } - static int32_t upper_bound_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return upper_bound_primary_i128i128( scope, code, table_n, data, len ); + static int32_t upper_bound_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return upper_bound_primary_i128i128( code, scope, table_n, data, len ); } - static int32_t lower_bound_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return lower_bound_primary_i128i128( scope, code, table_n, data, len ); + static int32_t lower_bound_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return lower_bound_primary_i128i128( code, scope, table_n, data, len ); } - static int32_t front_secondary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return front_secondary_i128i128( scope, code, table_n, data, len ); + static int32_t front_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return front_secondary_i128i128( code, scope, table_n, data, len ); } - static int32_t back_secondary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return back_secondary_i128i128( scope, code, table_n, data, len ); + static int32_t back_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return back_secondary_i128i128( code, scope, table_n, data, len ); } - static int32_t load_secondary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return load_secondary_i128i128( scope, code, table_n, data, len ); + static int32_t load_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return load_secondary_i128i128( code, scope, table_n, data, len ); } - static int32_t next_secondary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return next_secondary_i128i128( scope, code, table_n, data, len ); + static int32_t next_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return next_secondary_i128i128( code, scope, table_n, data, len ); } - static int32_t previous_secondary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return previous_secondary_i128i128( scope, code, table_n, data, len ); + static int32_t previous_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return previous_secondary_i128i128( code, scope, table_n, data, len ); } - static int32_t upper_bound_secondary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return upper_bound_secondary_i128i128( scope, code, table_n, data, len ); + static int32_t upper_bound_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return upper_bound_secondary_i128i128( code, scope, table_n, data, len ); } - static int32_t lower_bound_secondary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return lower_bound_secondary_i128i128( scope, code, table_n, data, len ); + static int32_t lower_bound_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return lower_bound_secondary_i128i128( code, scope, table_n, data, len ); } static int32_t remove( uint64_t scope, uint64_t table_n, const void* data ) { return remove_i128i128( scope, table_n, data ); } - static int32_t store( account_name scope, table_name table_n, const void* data, uint32_t len ) { - return store_i128i128( scope, table_n, data, len ); + static int32_t store( account_name scope, table_name table_n, account_name bta, const void* data, uint32_t len ) { + return store_i128i128( scope, table_n, bta, data, len ); } - static int32_t update( account_name scope, table_name table_n, const void* data, uint32_t len ) { - return update_i128i128( scope, table_n, data, len ); + static int32_t update( account_name scope, table_name table_n, account_name bta, const void* data, uint32_t len ) { + return update_i128i128( scope, table_n, bta, data, len ); } }; @@ -175,7 +175,7 @@ struct table_impl { * @ingroup databaseCpp * @{ */ -template +template struct table { private: typedef table_impl impl; @@ -196,7 +196,7 @@ struct table { * @return true if successful read. */ static bool front( Record& r, uint64_t s = scope ) { - return impl::front_primary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::front_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -206,7 +206,7 @@ struct table { * @return true if successful read. */ static bool back( Record& r, uint64_t s = scope ) { - return impl::back_primary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::back_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -216,7 +216,7 @@ struct table { * @return true if successful read. */ static bool next( Record& r, uint64_t s = scope ) { - return impl::next_primary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::next_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -226,7 +226,7 @@ struct table { * @return true if successful read. */ static bool previous( Record& r, uint64_t s = scope ) { - return impl::previous_primary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::previous_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -238,7 +238,7 @@ struct table { */ static bool get( const PrimaryType& p, Record& r, uint64_t s = scope ) { *reinterpret_cast(&r) = p; - return impl::load_primary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::load_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -249,7 +249,7 @@ struct table { * @return true if successful read. */ static bool lower_bound( const PrimaryType& p, Record& r ) { - return impl::lower_bound_primary( scope, code, table_n, &p &r, sizeof(Record) ) == sizeof(Record); + return impl::lower_bound_primary( code, scope, table_n, &p &r, sizeof(Record) ) == sizeof(Record); } /** @@ -260,7 +260,7 @@ struct table { * @return true if successful read. */ static bool upper_bound( const PrimaryType& p, Record& r ) { - return impl::upper_bound_primary( scope, code, table_n, &p &r, sizeof(Record) ) == sizeof(Record); + return impl::upper_bound_primary( code, scope, table_n, &p &r, sizeof(Record) ) == sizeof(Record); } /** @@ -286,7 +286,7 @@ struct table { * @return true if successful read. */ static bool front( Record& r, uint64_t s = scope ) { - return impl::front_secondary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::front_secondary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -296,7 +296,7 @@ struct table { * @return true if successful read. */ static bool back( Record& r, uint64_t s = scope ) { - return impl::back_secondary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::back_secondary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -306,7 +306,7 @@ struct table { * @return true if successful read. */ static bool next( Record& r, uint64_t s = scope ) { - return impl::next_secondary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::next_secondary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -316,7 +316,7 @@ struct table { * @return true if successful read. */ static bool previous( Record& r, uint64_t s = scope ) { - return impl::previous_secondary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::previous_secondary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -327,7 +327,7 @@ struct table { * @return true if successful read. */ static bool get( const SecondaryType& p, Record& r, uint64_t s = scope ) { - return impl::load_secondary( s, code, table_n, &p &r, sizeof(Record) ) == sizeof(Record); + return impl::load_secondary( code, s, table_n, &p &r, sizeof(Record) ) == sizeof(Record); } /** @@ -339,7 +339,7 @@ struct table { */ static bool lower_bound( const SecondaryType& p, Record& r, uint64_t s = scope ) { - return impl::lower_bound_secondary( s, code, table_n, &p &r, sizeof(Record) ) == sizeof(Record); + return impl::lower_bound_secondary( code, s, table_n, &p &r, sizeof(Record) ) == sizeof(Record); } /** @@ -350,7 +350,7 @@ struct table { * @return true if successful read. */ static bool upper_bound( const SecondaryType& p, Record& r, uint64_t s = scope ) { - return impl::upper_bound_secondary( s, code, table_n, &p &r, sizeof(Record) ) == sizeof(Record); + return impl::upper_bound_secondary( code, s, table_n, &p &r, sizeof(Record) ) == sizeof(Record); } /** @@ -376,7 +376,7 @@ struct table { static bool get( const PrimaryType& p, Record& r, uint64_t s = scope ) { *reinterpret_cast(&r) = p; - return impl::load_primary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::load_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -387,8 +387,8 @@ struct table { * * @return true if successful store. */ - static bool store( const Record& r, uint64_t s = scope ) { - assert( impl::store( s, table_n, &r, sizeof(r) ), "error storing record" ); + static bool store( const Record& r, uint64_t s = scope, uint64_t b = bta ) { + assert( impl::store( s, table_n, b, &r, sizeof(r) ), "error storing record" ); return true; } @@ -400,8 +400,8 @@ struct table { * * @return true if successful update. */ - static bool update( const Record& r, uint64_t s = scope ) { - assert( impl::update( s, table_n, &r, sizeof(r) ), "error updating record" ); + static bool update( const Record& r, uint64_t s = scope, uint64_t b = bta ) { + assert( impl::update( s, table_n, b, &r, sizeof(r) ), "error updating record" ); return true; } @@ -422,44 +422,44 @@ struct table { template<> struct table_impl { - static int32_t front_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return front_i64( scope, code, table_n, data, len ); + static int32_t front_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return front_i64( code, scope, table_n, data, len ); } - static int32_t back_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return back_i64( scope, code, table_n, data, len ); + static int32_t back_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return back_i64( code, scope, table_n, data, len ); } - static int32_t load_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return load_i64( scope, code, table_n, data, len ); + static int32_t load_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return load_i64( code, scope, table_n, data, len ); } - static int32_t next_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return next_i64( scope, code, table_n, data, len ); + static int32_t next_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return next_i64( code, scope, table_n, data, len ); } - static int32_t previous_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return previous_i64( scope, code, table_n, data, len ); + static int32_t previous_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return previous_i64( code, scope, table_n, data, len ); } - static int32_t lower_bound_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return lower_bound_i64( scope, code, table_n, data, len ); + static int32_t lower_bound_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return lower_bound_i64( code, scope, table_n, data, len ); } - static int32_t upper_bound_primary( uint64_t scope, uint64_t code, uint64_t table_n, void* data, uint32_t len ) { - return upper_bound_i64(scope, code, table_n, data, len); + static int32_t upper_bound_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) { + return upper_bound_i64( code, scope, table_n, data, len ); } static int32_t remove( uint64_t scope, uint64_t table_n, const void* data ) { return remove_i64( scope, table_n, (uint64_t*)data); } - static int32_t store( account_name scope, table_name table_n, const void* data, uint32_t len ) { - return store_i64( scope, table_n, data, len ); + static int32_t store( account_name scope, table_name table_n, account_name bta, const void* data, uint32_t len ) { + return store_i64( scope, table_n, bta, data, len ); } - static int32_t update( account_name scope, table_name table_n, const void* data, uint32_t len ) { - return update_i64( scope, table_n, data, len ); + static int32_t update( account_name scope, table_name table_n, account_name bta, const void* data, uint32_t len ) { + return update_i64( scope, table_n, bta, data, len ); } }; @@ -531,8 +531,8 @@ struct table_impl { * @ingroup databaseCpp * @{ */ -template -struct table { +template +struct table { private: typedef table_impl impl; static_assert( sizeof(PrimaryType) <= sizeof(Record), "invalid template parameters" ); @@ -549,7 +549,7 @@ struct table { * @return true if successfully retrieved the front of the table. */ static bool front( Record& r ) { - return impl::front_primary( scope, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::front_primary( code, scope, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -558,7 +558,7 @@ struct table { * @return true if successfully retrieved the back of the table. */ static bool back( Record& r ) { - return impl::back_primary( scope, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::back_primary( code, scope, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -567,7 +567,7 @@ struct table { * @return true if successfully retrieved the next record. */ static bool next( Record& r ) { - return impl::next_primary( scope, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::next_primary( code, scope, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -576,7 +576,7 @@ struct table { * @return true if successfully retrieved the previous record. */ static bool previous( Record& r ) { - return impl::previous_primary( scope, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::previous_primary( code, scope, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -587,7 +587,7 @@ struct table { */ static bool get( const PrimaryType& p, Record& r, uint64_t s = scope ) { *reinterpret_cast(&r) = p; - return impl::load_primary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::load_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -597,7 +597,7 @@ struct table { */ static bool lower_bound( const PrimaryType& p, Record& r ) { *reinterpret_cast(&r) = p; - return impl::lower_bound_primary( scope, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::lower_bound_primary( code, scope, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -607,7 +607,7 @@ struct table { */ static bool upper_bound( const PrimaryType& p, Record& r ) { *reinterpret_cast(&r) = p; - return impl::upper_bound_primary( scope, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::upper_bound_primary( code, scope, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -646,7 +646,7 @@ struct table { */ static bool get( const PrimaryType& p, Record& r, uint64_t s = scope ) { *reinterpret_cast(&r) = p; - return impl::load_primary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::load_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -657,7 +657,7 @@ struct table { * @return true if get succeeds. */ static bool get( Record& r, uint64_t s = scope ) { - return impl::load_primary( s, code, table_n, &r, sizeof(Record) ) == sizeof(Record); + return impl::load_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); } /** @@ -667,8 +667,8 @@ struct table { * @param s - scope; defaults to scope of the class. * @return true if store succeeds. */ - static bool store( const Record& r, uint64_t s = scope ) { - return impl::store( s, table_n, &r, sizeof(r) ) != 0; + static bool store( const Record& r, uint64_t s = scope, uint64_t b = bta ) { + return impl::store( s, table_n, b, &r, sizeof(r) ) != 0; } /** @@ -678,8 +678,8 @@ struct table { * @param s - scope; defaults to scope of the class. * @return true if update succeeds. */ - static bool update( const Record& r, uint64_t s = scope ) { - return impl::update( s, table_n, &r, sizeof(r) ) != 0; + static bool update( const Record& r, uint64_t s = scope, uint64_t b = bta ) { + return impl::update( s, table_n, b, &r, sizeof(r) ) != 0; } /** @@ -697,44 +697,44 @@ struct table { template<> struct table_impl_obj { - static int32_t store( account_name scope, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { - return store_str( scope, table_n, key, keylen, data, datalen ); + static int32_t store( account_name scope, table_name table_n, account_name bta, char* key, uint32_t keylen, char* data, uint32_t datalen ) { + return store_str( scope, table_n, bta, key, keylen, data, datalen ); } - static int32_t update( account_name scope, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { - return update_str( scope, table_n, key, keylen, data, datalen ); + static int32_t update( account_name scope, table_name table_n, account_name bta, char* key, uint32_t keylen, char* data, uint32_t datalen ) { + return update_str( scope, table_n, bta, key, keylen, data, datalen ); } - static int32_t front( account_name scope, account_name code, table_name table_n, char* data, uint32_t len ) { - return front_str( scope, code, table_n, data, len ); + static int32_t front( account_name code, account_name scope, table_name table_n, char* data, uint32_t len ) { + return front_str( code, scope, table_n, data, len ); } - static int32_t back( account_name scope, account_name code, table_name table_n, char* data, uint32_t len ) { - return back_str( scope, code, table_n, data, len ); + static int32_t back( account_name code, account_name scope, table_name table_n, char* data, uint32_t len ) { + return back_str( code, scope, table_n, data, len ); } - static int32_t load( account_name scope, account_name code, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { - return load_str( scope, code, table_n, key, keylen, data, datalen ); + static int32_t load( account_name code, account_name scope, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { + return load_str( code, scope, table_n, key, keylen, data, datalen ); } - static int32_t next( account_name scope, account_name code, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { - return next_str( scope, code, table_n, key, keylen, data, datalen ); + static int32_t next( account_name code, account_name scope, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { + return next_str( code, scope, table_n, key, keylen, data, datalen ); } - static int32_t previous( account_name scope, account_name code, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { - return previous_str( scope, code, table_n, key, keylen, data, datalen ); + static int32_t previous( account_name code, account_name scope, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { + return previous_str( code, scope, table_n, key, keylen, data, datalen ); } - static int32_t lower_bound( account_name scope, account_name code, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { - return lower_bound_str( scope, code, table_n, key, keylen, data, datalen ); + static int32_t lower_bound( account_name code, account_name scope, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { + return lower_bound_str( code, scope, table_n, key, keylen, data, datalen ); } - static int32_t upper_bound( account_name scope, account_name code, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { - return upper_bound_str( scope, code, table_n, key, keylen, data, datalen ); + static int32_t upper_bound( account_name code, account_name scope, table_name table_n, char* key, uint32_t keylen, char* data, uint32_t datalen ) { + return upper_bound_str( code, scope, table_n, key, keylen, data, datalen ); } static int32_t remove( account_name scope, table_name table_n, char* key, uint32_t keylen ) { - return remove_str( scope, table_n, key, keylen ); + return remove_str( scope, table_n, key, keylen ); } }; @@ -751,7 +751,7 @@ struct table_impl_obj { * @{ */ -template +template struct var_table { private: typedef table_impl_obj impl; @@ -769,7 +769,7 @@ struct var_table { * @return 1 if a new record was created, 0 if an existing record was updated */ int32_t store( primary key, uint32_t keylen, char* record, uint32_t len ) { - return impl::store( scope, table_n, key, keylen, record, len ); + return impl::store( scope, table_n, bta, key, keylen, record, len ); } /** @@ -782,7 +782,7 @@ struct var_table { * @return 1 if the record was updated, 0 if no record with key was found */ int32_t update( primary key, uint32_t keylen, char* record, uint32_t len ) { - return impl::update( scope, table_n, key, keylen, record, len ); + return impl::update( scope, table_n, bta, key, keylen, record, len ); } /** @@ -795,7 +795,7 @@ struct var_table { * @return the number of bytes read or -1 if key was not found */ int32_t front( char* record, uint32_t len ) { - return impl::front( scope, code, table_n, record, len ); + return impl::front( code, scope, table_n, record, len ); } /** @@ -808,7 +808,7 @@ struct var_table { * @return the number of bytes read or -1 if key was not found */ int32_t back( char* record, uint32_t len ) { - return impl::back( scope, code, table_n, record, len ); + return impl::back( code, scope, table_n, record, len ); } /** @@ -821,7 +821,7 @@ struct var_table { * @return the number of bytes read or -1 if key was not found */ int32_t load( primary key, uint32_t keylen, char* record, uint32_t len ) { - return impl::load( scope, code, table_n, key, keylen, record, len ); + return impl::load( code, scope, table_n, key, keylen, record, len ); } /** @@ -834,7 +834,7 @@ struct var_table { * @return the number of bytes read or -1 if key was not found */ int32_t next( primary key, uint32_t keylen, char* record, uint32_t len ) { - return impl::next( scope, code, table_n, key, keylen, record, len ); + return impl::next( code, scope, table_n, key, keylen, record, len ); } /** @@ -847,7 +847,7 @@ struct var_table { * @return the number of bytes read or -1 if key was not found */ int32_t previous( primary key, uint32_t keylen, char* record, uint32_t len ) { - return impl::previous( scope, code, table_n, key, keylen, record, len ); + return impl::previous( code, scope, table_n, key, keylen, record, len ); } /** @@ -860,7 +860,7 @@ struct var_table { * @return the number of bytes read or -1 if key was not found */ int32_t lower_bound( primary key, uint32_t keylen, char* record, uint32_t len ) { - return impl::lower_bound( scope, code, table_n, key, keylen, record, len ); + return impl::lower_bound( code, scope, table_n, key, keylen, record, len ); } /** @@ -873,7 +873,7 @@ struct var_table { * @return the number of bytes read or -1 if key was not found */ int32_t upper_bound( primary key, uint32_t keylen, char* record, uint32_t len ) { - return impl::upper_bound( scope, code, table_n, key, keylen, record, len ); + return impl::upper_bound( code, scope, table_n, key, keylen, record, len ); } /** @@ -895,7 +895,7 @@ struct var_table { } // namespace eosio -#define TABLE2(NAME, SCOPE, CODE, TABLE, TYPE, PRIMARY_NAME, PRIMARY_TYPE, SECONDARY_NAME, SECONDARY_TYPE) \ - using NAME = eosio::table; \ +#define TABLE2(NAME, CODE, SCOPE, TABLE, TYPE, PRIMARY_NAME, PRIMARY_TYPE, SECONDARY_NAME, SECONDARY_TYPE) \ + using NAME = eosio::table; \ typedef NAME::primary_index PRIMARY_NAME; \ typedef NAME::secondary_index SECONDARY_NAME; diff --git a/contracts/eosiolib/generic_currency.hpp b/contracts/eosiolib/generic_currency.hpp index bb9c646feffc13874839a538bd42cb1012f536c8..fe0f4e35f0084b7d9eb504415b37875428c62f33 100644 --- a/contracts/eosiolib/generic_currency.hpp +++ b/contracts/eosiolib/generic_currency.hpp @@ -74,8 +74,8 @@ namespace eosio { * Each user stores their balance in the singleton table under the * scope of their account name. */ - typedef table64 accounts; - typedef table64 stats; + typedef table64 accounts; + typedef table64 stats; static token_type get_balance( account_name owner ) { return accounts::get_or_create( token_type::symbol, owner ).balance; @@ -115,7 +115,7 @@ namespace eosio { static void apply( account_name c, action_name act) { - eosio::dispatch(c,act); + eosio::dispatch(c,act); } }; diff --git a/contracts/eosiolib/rpc.dox b/contracts/eosiolib/rpc.dox index 80e0b8bb40de4b0b99bcfa40cab3cfd4f2c3d09d..d792e36b01e9999ea4d3c153140b620791abed8d 100644 --- a/contracts/eosiolib/rpc.dox +++ b/contracts/eosiolib/rpc.dox @@ -104,7 +104,7 @@ Get information related to an account. @subsubsection examplegetaccount Example get_account Usage ``` -$ curl http://127.0.0.1:8888/v1/chain/get_account -X POST -d '{"name":"inita"}' +$ curl http://127.0.0.1:8888/v1/chain/get_account -X POST -d '{"account_name":"inita"}' ``` @subsubsection examplegetaccountresult Example get_account Result diff --git a/contracts/eosiolib/singleton.hpp b/contracts/eosiolib/singleton.hpp index 01e9528d4ac512d58fa200c100bbb0da6b36e4b1..cd935faa0cfb44f03611eb7f87eb419ee63d4964 100644 --- a/contracts/eosiolib/singleton.hpp +++ b/contracts/eosiolib/singleton.hpp @@ -11,7 +11,7 @@ namespace eosio { * @tparam SingletonName - the name of this singlton variable * @tparam T - the type of the singleton */ - template + template class singleton { public: @@ -19,20 +19,26 @@ namespace eosio { static bool exists( scope_name scope = Code ) { uint64_t key = SingletonName; - auto read = load_i64( scope, Code, key, (char*)&key, sizeof(key) ); + auto read = load_i64( Code, scope, key, (char*)&key, sizeof(key) ); return read > 0; } static T get( scope_name scope = Code ) { char temp[1024+8]; *reinterpret_cast(temp) = SingletonName; - auto read = load_i64( scope, Code, SingletonName, temp, sizeof(temp) ); + auto read = load_i64( Code, scope, SingletonName, temp, sizeof(temp) ); assert( read > 0, "singleton does not exist" ); - datastream ds(temp + sizeof(SingletonName), read); + return unpack( temp + sizeof(SingletonName), read ); + } - T result; - unpack( ds, result ); - return result; + static T get_or_default( scope_name scope = Code, const T& def = T() ) { + char temp[1024+8]; + *reinterpret_cast(temp) = SingletonName; + auto read = load_i64( Code, scope, SingletonName, temp, sizeof(temp) ); + if ( read < 0 ) { + return def; + } + return unpack( temp + sizeof(SingletonName), read ); } static T get_or_create( scope_name scope = Code, const T& def = T() ) { @@ -40,19 +46,15 @@ namespace eosio { *reinterpret_cast(temp) = SingletonName; - auto read = load_i64( scope, Code, SingletonName, temp, sizeof(temp) ); + auto read = load_i64( Code, scope, SingletonName, temp, sizeof(temp) ); if( read < 0 ) { set( def, scope ); return def; } - - datastream ds(temp + sizeof(SingletonName), read); - T result; - ds >> result; - return result; + return unpack( temp + sizeof(SingletonName), read ); } - static void set( const T& value = T(), scope_name scope = Code ) { + static void set( const T& value = T(), scope_name scope = Code, account_name b = BillToAccount ) { auto size = pack_size( value ); char buf[size+ sizeof(SingletonName)]; @@ -62,7 +64,12 @@ namespace eosio { ds << SingletonName; ds << value; - store_i64( scope, SingletonName, buf, sizeof(buf) ); + store_i64( scope, SingletonName, b, buf, sizeof(buf) ); + } + + static void remove( scope_name scope = Code ) { + uint64_t key = SingletonName; + remove_i64( scope, SingletonName, &key ); } }; diff --git a/contracts/eosiolib/string.hpp b/contracts/eosiolib/string.hpp index b5f7258562d4e2adca1bf5edbefced6d73cf3d25..cb04a5c26f2ffda76aae57573ccf1bd37d6ae3da 100644 --- a/contracts/eosiolib/string.hpp +++ b/contracts/eosiolib/string.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace eosio { /** diff --git a/contracts/eosiolib/table.hpp b/contracts/eosiolib/table.hpp index cc391dd68ee4d0154a03bd585c672412f079adde..8082f893635102f6865c792c0e6f8849b91afea9 100644 --- a/contracts/eosiolib/table.hpp +++ b/contracts/eosiolib/table.hpp @@ -8,19 +8,19 @@ namespace eosio { * @tparam TableName - the name of the table with rows of type T * @tparam T - a struct where the first 8 bytes are used as primary/unique key */ - template + template class table64 { public: static bool exists( uint64_t key, scope_name scope = DefaultScope) { - auto read = load_i64( scope, DefaultScope, TableName, (char*)&key, sizeof(key) ); + auto read = load_i64( DefaultScope, scope, TableName, (char*)&key, sizeof(key) ); return read > 0; } static T get( uint64_t key, scope_name scope = DefaultScope ) { char temp[1024]; *reinterpret_cast(temp) = key; - auto read = load_i64( scope, DefaultScope , TableName, temp, sizeof(temp) ); + auto read = load_i64( DefaultScope, scope , TableName, temp, sizeof(temp) ); assert( read > 0, "key does not exist" ); datastream ds(temp, read); @@ -33,7 +33,7 @@ namespace eosio { char temp[1024]; *reinterpret_cast(temp) = key; - auto read = load_i64( scope, DefaultScope, TableName, temp, sizeof(temp) ); + auto read = load_i64( DefaultScope, scope, TableName, temp, sizeof(temp) ); if( read < 0 ) { set( def, scope ); return def; @@ -60,7 +60,7 @@ namespace eosio { return result; } - static void set( const T& value = T(), scope_name scope = DefaultScope ) { + static void set( const T& value = T(), scope_name scope = DefaultScope, uint64_t bta = BillToAccount ) { auto size = pack_size( value ); char buf[size]; assert( size <= 1024, "singleton too big to store" ); @@ -68,7 +68,7 @@ namespace eosio { datastream ds( buf, size ); ds << value; - store_i64( scope, TableName, buf, ds.tellp() ); + store_i64( scope, TableName, bta, buf, ds.tellp() ); } static void remove( uint64_t key, scope_name scope = DefaultScope ) { @@ -77,7 +77,7 @@ namespace eosio { }; - template + template class table_i64i64i64 { public: table_i64i64i64( uint64_t scope = Code ) @@ -93,7 +93,7 @@ namespace eosio { temp[1] = secondary; temp[2] = tertiary; - auto read = lower_bound_primary_i64i64i64( Code, _scope, TableName, + auto read = lower_bound_primary_i64i64i64( Code, _scope, TableName, (char*)temp, sizeof(temp) ); if( read <= 0 ) { return false; @@ -104,27 +104,37 @@ namespace eosio { return true; } - bool next_primary( T& result, const T& current ) { + bool primary_upper_bound( T& result, + uint64_t primary = 0, + uint64_t secondary = 0, + uint64_t tertiary = 0 ) { + uint64_t temp[1024/8]; - memcpy( temp, (const char*)¤t, 3*sizeof(uint64_t) ); - - auto read = next_primary_i64i64i64( Code, _scope, TableName, + temp[0] = primary; + temp[1] = secondary; + temp[2] = tertiary; + + auto read = upper_bound_primary_i64i64i64( Code, _scope, TableName, (char*)temp, sizeof(temp) ); if( read <= 0 ) { return false; } - datastream ds( (char*)temp, sizeof(temp) ); - ds >> result; + result = unpack( (char*)temp, sizeof(temp) ); return true; } - void store( const T& value, account_name bill_to ) { + bool next_primary( T& result, const T& current ) { + const uint64_t* keys = reinterpret_cast(¤t); + return primary_upper_bound(result, keys[0], keys[1], keys[2]); + } + + void store( const T& value, account_name bill_to = BillToAccount ) { char temp[1024]; datastream ds(temp, sizeof(temp) ); ds << value; - store_i64i64i64( _scope, TableName, temp, ds.tellp() ); + store_i64i64i64( _scope, TableName, bill_to, temp, ds.tellp() ); } void remove(uint64_t primary_key, uint64_t seconday_key, uint64_t tertiary_key) { diff --git a/contracts/identity/identity.abi b/contracts/identity/identity.abi index cb008b47aeb600119323a15eba17e14a8b417cd0..b07f79a4458b25efba2b0d70cba63fff22fab72f 100644 --- a/contracts/identity/identity.abi +++ b/contracts/identity/identity.abi @@ -62,18 +62,12 @@ {"name":"identity", "type":"uint64"}, {"name":"creator", "type":"account_name"} ] - },{ - "name": "trustrow", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"trusted", "type":"uint8"} - ] },{ "name": "accountrow", "base": "", "fields": [ - {"name":"account", "type":"account_name"} + {"name":"singleton_name", "type":"uint64"}, + {"name":"identity", "type":"uint64"} ] } ], @@ -110,7 +104,7 @@ "key_types": [ "uint64" ] },{ "name": "trust", - "type": "trustrow", + "type": "account_name", "index_type": "i64", "key_names" : [ "account" ], "key_types": [ "account_name" ] diff --git a/contracts/identity/identity.hpp b/contracts/identity/identity.hpp index e42e9d3ee4d7dcce3c6b42c68c1ac6c44fb339b7..42c8dbe567b226ac38b5b6d555937d3573dcd937 100644 --- a/contracts/identity/identity.hpp +++ b/contracts/identity/identity.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -10,6 +11,7 @@ namespace identity { using eosio::action_meta; using eosio::table_i64i64i64; using eosio::table64; + using eosio::singleton; using eosio::string; using eosio::vector; @@ -193,10 +195,10 @@ namespace identity { } }; - typedef table_i64i64i64 certs_table; - typedef table64 idents_table; - typedef table64 accounts_table; - typedef table64 trust_table; + typedef table_i64i64i64 certs_table; + typedef table64 idents_table; + typedef singleton accounts_table; + typedef table64 trust_table; static identity_name get_claimed_identity( account_name acnt ) { return accounts_table::get_or_default(acnt, 0); @@ -209,13 +211,19 @@ namespace identity { certs_table certs( ident ); certrow row; bool ok = certs.primary_lower_bound(row, N(owner), 1, 0); + account_name owner = 0; while (ok && row.property == N(owner) && row.trusted) { if (sizeof(account_name) == row.data.size()) { account_name account = *reinterpret_cast(row.data.data()); if (ident == get_claimed_identity(account)) { if (is_trusted(row.certifier) ) { // the certifier is still trusted - return account; + if (!owner || owner == account) { + owner = account; + } else { + //contradiction found: different owners certified for the same identity + return 0; + } } else if (DeployToAccount == current_receiver()){ //the certifier is no longer trusted, need to unset the flag row.trusted = 0; @@ -227,8 +235,13 @@ namespace identity { } else { // bad row - skip it } + //ok = certs.primary_upper_bound(row, row.property, row.trusted, row.certifier); ok = certs.next_primary(row, row); } + if (owner) { + //owner found, no contradictions among certifications flaged as trusted + return owner; + } // trusted certification not found // let's see if some of untrusted certifications became trusted ok = certs.primary_lower_bound(row, N(owner), 0, 0); @@ -236,18 +249,25 @@ namespace identity { if (sizeof(account_name) == row.data.size()) { account_name account = *reinterpret_cast(row.data.data()); if (ident == get_claimed_identity(account) && is_trusted(row.certifier)) { - // the certifier became trusted, need to set the flag - row.trusted = 1; - certs.store( row, 0 ); //assuming 0 means bill to the same account - return *reinterpret_cast(row.data.data()); + if (DeployToAccount == current_receiver()) { + // the certifier became trusted and we have permissions to update the flag + row.trusted = 1; + certs.store( row, 0 ); //assuming 0 means bill to the same account + } + if (!owner || owner == account) { + owner = account; + } else { + //contradiction found: different owners certified for the same identity + return 0; + } } } else { // bad row - skip it } + //ok = certs.primary_upper_bound(row, row.property, row.trusted, row.certifier); ok = certs.next_primary(row, row); } - - return 0; + return owner; } static identity_name get_identity_for_account( account_name acnt ) { @@ -258,10 +278,7 @@ namespace identity { } static bool is_trusted_by( account_name trusted, account_name by ) { - trustrow def; - def.trusted = 0; - trustrow row = trust_table::get_or_default( trusted, by, def ); - return def.trusted; + return trust_table::exists(trusted, by); } static bool is_trusted( account_name acnt ) { @@ -283,13 +300,9 @@ namespace identity { require_recipient( t.trusting ); if( t.trust != 0 ) { - trustrow row{ .account = t.trusting, - .trusted = t.trust }; - trust_table::set( row, t.trustor ); + trust_table::set( t.trusting, t.trustor ); } else { - trustrow row{ .account = t.trusting, - .trusted = t.trust }; - trust_table::remove( row.account, t.trustor ); + trust_table::remove( t.trusting, t.trustor ); } } @@ -318,7 +331,7 @@ namespace identity { row.trusted = is_trusted( cert.certifier ); row.certifier = cert.certifier; row.confidence = value.confidence; - assert(value.type.get_size() <= 32, "certrow::type shouldn't be longer than 32 bytes"); + assert(value.type.get_size() <= 32, "certrow::type should be not longer than 32 bytes"); row.type = value.type; row.data = value.data; @@ -330,17 +343,21 @@ namespace identity { if (value.property == N(owner)) { assert(sizeof(account_name) == value.data.size(), "data size doesn't match account_name size"); account_name acnt = *reinterpret_cast(value.data.data()); - accounts_table::set( acnt, cert.identity ); + if (cert.certifier == acnt) { //only self-certitication affects accounts_table + accounts_table::set( cert.identity, acnt ); + } } } else { - //remove both tursted and untrusted because we cannot now if it was trusted back at creation time + //remove both tursted and untrusted because we cannot know if it was trusted back at creation time certs.remove(value.property, 0, cert.certifier); certs.remove(value.property, 1, cert.certifier); //special handling for owner if (value.property == N(owner)) { assert(sizeof(account_name) == value.data.size(), "data size doesn't match account_name size"); account_name acnt = *reinterpret_cast(value.data.data()); - accounts_table::remove( acnt, cert.identity ); + if (cert.certifier == acnt) { //only self-certitication affects accounts_table + accounts_table::remove( acnt ); + } } } } diff --git a/contracts/identity/test/identity_test.cpp b/contracts/identity/test/identity_test.cpp index 38c57a429ccc5c3ccca0a70917c54687fef8ea20..63a25715215d84aa777ff212fa3732d8fcb6f3d8 100644 --- a/contracts/identity/test/identity_test.cpp +++ b/contracts/identity/test/identity_test.cpp @@ -49,7 +49,7 @@ namespace identity_test { } }; - typedef singleton result_table; + typedef singleton result_table; static void on( const get_owner_for_identity& c ) { account_name owner = identity_contract::get_owner_for_identity(c.identity); diff --git a/contracts/noop/CMakeLists.txt b/contracts/noop/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..687e32fd39e3656dd3ad9dce31275251c65f5e14 --- /dev/null +++ b/contracts/noop/CMakeLists.txt @@ -0,0 +1,3 @@ +file(GLOB ABI_FILES "*.abi") +configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) +add_wast_target(noop "${CMAKE_SOURCE_DIR}/contracts" ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/contracts/noop/noop.abi b/contracts/noop/noop.abi new file mode 100644 index 0000000000000000000000000000000000000000..f40898c17dd2bfba3a09b63e396f0e27f0a831a8 --- /dev/null +++ b/contracts/noop/noop.abi @@ -0,0 +1,23 @@ +{ + "types": [{ + "new_type_name": "account_name", + "type": "name" + } + ], + "structs": [{ + "name": "anyaction", + "base": "", + "fields": [ + {"name":"from", "type":"account_name"}, + {"name":"type", "type":"string"}, + {"name":"data", "type":"string"} + ] + } + ], + "actions": [{ + "name":"anyaction", + "type":"anyaction" + } +], + "tables": [] +} diff --git a/contracts/noop/noop.cpp b/contracts/noop/noop.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95c629cdb61cedc0e43f5055f5a47bda349cc4fe --- /dev/null +++ b/contracts/noop/noop.cpp @@ -0,0 +1,15 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ + +#include + +namespace noop { + extern "C" { + /// The apply method implements the dispatch of events to this contract + void apply( uint64_t code, uint64_t action ) { + eosio::dispatch(code, action); + } + } +} diff --git a/contracts/noop/noop.hpp b/contracts/noop/noop.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a1dbbce7665a73a96688def76a6baf90a4cede85 --- /dev/null +++ b/contracts/noop/noop.hpp @@ -0,0 +1,40 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#pragma once + +#include +#include +#include + +using namespace eosio; + +namespace noop { + /** + noop contract + All it does is require sender authorization. + Actions: anyaction + */ + + + class noop { + public: + + ACTION(N(noop), anyaction) { + anyaction() { } + anyaction(account_name f, const string& t, const string& d): from(f), type(t), data(d) { } + + account_name from; + string type; + string data; + + EOSLIB_SERIALIZE(anyaction, (from)(type)(data)) + }; + + static void on(const anyaction& act) + { + require_auth(act.from); + } + }; +} /// noop diff --git a/contracts/proxy/proxy.cpp b/contracts/proxy/proxy.cpp index 942ad4bd22a48cfd0f65cb2f5c1b9a5dea10da48..dac7e3828623cdbbfb680a2a88279c4a689dd231 100644 --- a/contracts/proxy/proxy.cpp +++ b/contracts/proxy/proxy.cpp @@ -3,12 +3,26 @@ * @copyright defined in eos/LICENSE.txt */ #include -#include +#include #include namespace proxy { using namespace eosio; + namespace configs { + bool get(config &out, const account_name &self) { + auto read = load_i64(self, self, N(config), (char*)&out, sizeof(config)); + if (read < 0) { + return false; + } + return true; + } + + void store(const config &in, const account_name &self) { + store_i64(self, N(config), self, (const char *)&in, sizeof(config)); + } + }; + template void apply_transfer(account_name code, const T& transfer) { config code_config; @@ -44,9 +58,10 @@ namespace proxy { template void apply_onerror( const deferred_transaction& failed_dtrx ) { + eosio::print("starting onerror\n"); const auto self = current_receiver(); config code_config; - assert(configs::get(code_config, self), "Attempting to use unconfigured proxy"); + assert(configs::get(code_config, self), "Attempting use of unconfigured proxy"); auto id = code_config.next_id++; configs::store(code_config, self); @@ -63,12 +78,14 @@ extern "C" { /// The apply method implements the dispatch of events to this contract void apply( uint64_t code, uint64_t action ) { - if ( code == N(eosio) ) { - if( action == N(transfer) ) { - apply_transfer(code, unpack_action()); - } else if ( action == N(onerror)) { + if ( code == N(eosio)) { + if (action == N(onerror)) { apply_onerror(deferred_transaction::from_current_action()); } + } else if ( code == N(eosio.system) ) { + if( action == N(transfer) ) { + apply_transfer(code, unpack_action::currency::transfer_memo>()); + } } else if (code == current_receiver() ) { if ( action == N(setowner)) { apply_setowner(current_action()); diff --git a/contracts/proxy/proxy.hpp b/contracts/proxy/proxy.hpp index 452f077aeeccdb7a3d637ea466d74b4cbe125409..95a7e498ff6245835555c8bada0c31dadc4d6f08 100644 --- a/contracts/proxy/proxy.hpp +++ b/contracts/proxy/proxy.hpp @@ -3,7 +3,6 @@ * @copyright defined in eos/LICENSE.txt */ #include -#include namespace proxy { @@ -22,6 +21,4 @@ namespace proxy { uint32_t next_id = 0; }; - using configs = eosio::table; - } /// namespace proxy diff --git a/build.sh b/eosio-build.sh similarity index 100% rename from build.sh rename to eosio-build.sh diff --git a/genesis.json b/genesis.json index 49bed6bc7ecbe1ab27397909ee588ed8a8dc9f7b..815207b46151dbbf20abe422875b048ac616c0a4 100644 --- a/genesis.json +++ b/genesis.json @@ -15,127 +15,127 @@ "name": "inita", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initb", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initc", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initd", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "inite", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initf", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initg", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "inith", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initi", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initj", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initk", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initl", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initm", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initn", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "inito", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initp", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initq", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initr", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "inits", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initt", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" },{ "name": "initu", "owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "liquid_balance": "1000000.0000 EOS" + "liquid_balance": "1000000.0000 EOS", "staking_balance": "100.0000 EOS" }], "initial_producers": [{ diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 3bf4428e4facff1e3edf2c3b8134b1409b0b07ce..7e37f405b7dbec36487d36ae827c6eecbd9faea9 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -9,6 +9,7 @@ add_library( eosio_chain block.cpp wast_to_wasm.cpp wasm_interface.cpp + wasm_eosio_constraints.cpp apply_context.cpp rate_limiting.cpp @@ -22,8 +23,6 @@ add_library( eosio_chain chain_controller.cpp contracts/eosio_contract.cpp - contracts/producer_objects.cpp - contracts/staked_balance_objects.cpp contracts/chain_initializer.cpp contracts/genesis_state.cpp contracts/abi_serializer.cpp @@ -36,6 +35,7 @@ target_link_libraries( eosio_chain eos_utilities fc chainbase Logging IR WAST WA target_include_directories( eosio_chain PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include" + "${CMAKE_BINARY_DIR}/contracts" ) if(MSVC) diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index d82a549d5b4e0d975e2c775e1aed3d3e809ca9c6..a3c0503deb76cf04ad17447d44701852e86a40ea 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -17,6 +17,7 @@ void apply_context::exec_one() (*native)(*this); } else { const auto &a = mutable_controller.get_database().get(receiver); + privileged = a.privileged; if (a.code.size() > 0) { // get code from cache @@ -101,7 +102,7 @@ void apply_context::exec() } for( uint32_t i = 0; i < _inline_actions.size(); ++i ) { - apply_context ncontext( mutable_controller, mutable_db, _inline_actions[i], trx_meta); + apply_context ncontext( mutable_controller, mutable_db, _inline_actions[i], trx_meta, _checktime_limit); ncontext.exec(); append_results(move(ncontext.results)); } @@ -204,22 +205,22 @@ void apply_context::cancel_deferred( uint32_t sender_id ) { results.canceled_deferred.emplace_back(receiver, sender_id); } -const contracts::table_id_object* apply_context::find_table( name scope, name code, name table ) { +const contracts::table_id_object* apply_context::find_table( name code, name scope, name table ) { require_read_lock(code, scope); - return db.find(boost::make_tuple(scope, code, table)); + return db.find(boost::make_tuple(code, scope, table)); } -const contracts::table_id_object& apply_context::find_or_create_table( name scope, name code, name table ) { +const contracts::table_id_object& apply_context::find_or_create_table( name code, name scope, name table ) { require_read_lock(code, scope); - const auto* existing_tid = db.find(boost::make_tuple(scope, code, table)); + const auto* existing_tid = db.find(boost::make_tuple(code, scope, table)); if (existing_tid != nullptr) { return *existing_tid; } require_write_lock(scope); return mutable_db.create([&](contracts::table_id_object &t_id){ - t_id.scope = scope; t_id.code = code; + t_id.scope = scope; t_id.table = table; }); } @@ -233,21 +234,29 @@ vector apply_context::get_active_producers() const { return accounts; } +void apply_context::checktime_start() { + _checktime_start = fc::time_point::now(); +} + +void apply_context::checktime() const { + if ((fc::time_point::now() - _checktime_start).count() > _checktime_limit) { + throw checktime_exceeded(); + } +} + const bytes& apply_context::get_packed_transaction() { if( !trx_meta.packed_trx.size() ) { if (_cached_trx.empty()) { - auto size = fc::raw::pack_size(trx_meta.trx); + auto size = fc::raw::pack_size(trx_meta.trx()); _cached_trx.resize(size); fc::datastream ds(_cached_trx.data(), size); - fc::raw::pack(ds, trx_meta.trx); + fc::raw::pack(ds, trx_meta.trx()); } return _cached_trx; } return trx_meta.packed_trx; - } - } } /// eosio::chain diff --git a/libraries/chain/chain_controller.cpp b/libraries/chain/chain_controller.cpp index 936c85bb5c2b323d1d83ab09d0e35ce33005daf2..89d803e5ede9266df0217dc55322f1bcce67c0c4 100644 --- a/libraries/chain/chain_controller.cpp +++ b/libraries/chain/chain_controller.cpp @@ -4,7 +4,6 @@ */ #include -#include #include #include @@ -16,7 +15,6 @@ #include #include #include -#include #include #include @@ -41,15 +39,32 @@ namespace eosio { namespace chain { -bool is_start_of_round( block_num_type block_num ) { - return (block_num % config::blocks_per_round) == 0; +#ifdef NDEBUG +const uint32_t chain_controller::default_received_block_transaction_execution_time_ms = 12; +const uint32_t chain_controller::default_transaction_execution_time_ms = 3; +const uint32_t chain_controller::default_create_block_transaction_execution_time_ms = 3; +#else +const uint32_t chain_controller::default_received_block_transaction_execution_time_ms = 72; +const uint32_t chain_controller::default_transaction_execution_time_ms = 18; +const uint32_t chain_controller::default_create_block_transaction_execution_time_ms = 18; +#endif + +bool chain_controller::is_start_of_round( block_num_type block_num )const { + return 0 == (block_num % blocks_per_round()); +} + +uint32_t chain_controller::blocks_per_round()const { + return get_global_properties().active_producers.producers.size()*config::producer_repititions; } chain_controller::chain_controller( const chain_controller::controller_config& cfg ) :_db( cfg.shared_memory_dir, (cfg.read_only ? database::read_only : database::read_write), cfg.shared_memory_size), - _block_log(cfg.block_log_dir) + _block_log(cfg.block_log_dir), + _create_block_txn_execution_time(default_create_block_transaction_execution_time_ms * 1000), + _rcvd_block_txn_execution_time(default_received_block_transaction_execution_time_ms * 1000), + _txn_execution_time(default_transaction_execution_time_ms * 1000) { _initialize_indexes(); @@ -251,7 +266,7 @@ transaction_trace chain_controller::push_transaction(const packed_transaction& t transaction_trace chain_controller::_push_transaction(const packed_transaction& trx) { transaction_metadata mtrx( trx, get_chain_id(), head_block_time()); - check_transaction_authorization(mtrx.trx, trx.signatures); + check_transaction_authorization(mtrx.trx(), trx.signatures); auto result = _push_transaction(std::move(mtrx)); @@ -278,7 +293,7 @@ static void record_locks_for_data_access(const vector& action_trac transaction_trace chain_controller::_push_transaction( transaction_metadata&& data ) { - const transaction& trx = data.trx; + const transaction& trx = data.trx(); // If this is the first transaction pushed after applying a block, start a new undo session. // This allows us to quickly rewind to the clean state of the head block, in case a new block arrives. if( !_pending_block ) { @@ -425,11 +440,12 @@ void chain_controller::_finalize_block( const block_trace& trace ) { try { update_global_properties( b ); update_global_dynamic_data( b ); update_signing_producer(signing_producer, b); - update_last_irreversible_block(); create_block_summary(b); clear_expired_transactions(); + update_last_irreversible_block(); + applied_block( trace ); //emit if (_currently_replaying_blocks) applied_irreversible_block(b); @@ -443,7 +459,7 @@ signed_block chain_controller::generate_block( uint32_t skip /* = 0 */ ) { try { - return with_skip_flags( skip, [&](){ + return with_skip_flags( skip | created_block, [&](){ return _db.with_write_lock( [&](){ return _generate_block( when, producer, block_signing_private_key ); }); @@ -454,54 +470,61 @@ signed_block chain_controller::_generate_block( block_timestamp_type when, account_name producer, const private_key_type& block_signing_key ) { try { - uint32_t skip = _skip_flags; - uint32_t slot_num = get_slot_at_time( when ); - FC_ASSERT( slot_num > 0 ); - account_name scheduled_producer = get_scheduled_producer( slot_num ); - FC_ASSERT( scheduled_producer == producer ); + + try { + uint32_t skip = _skip_flags; + uint32_t slot_num = get_slot_at_time( when ); + FC_ASSERT( slot_num > 0 ); + account_name scheduled_producer = get_scheduled_producer( slot_num ); + FC_ASSERT( scheduled_producer == producer ); - const auto& producer_obj = get_producer(scheduled_producer); + const auto& producer_obj = get_producer(scheduled_producer); - if( !_pending_block ) { - _start_pending_block(); - } + if( !_pending_block ) { + _start_pending_block(); + } - _finalize_pending_cycle(); + _finalize_pending_cycle(); - if( !(skip & skip_producer_signature) ) - FC_ASSERT( producer_obj.signing_key == block_signing_key.get_public_key() ); + if( !(skip & skip_producer_signature) ) + FC_ASSERT( producer_obj.signing_key == block_signing_key.get_public_key(), + "producer key ${pk}, block key ${bk}", ("pk", producer_obj.signing_key)("bk", block_signing_key.get_public_key()) ); - _pending_block->timestamp = when; - _pending_block->producer = producer_obj.owner; - _pending_block->previous = head_block_id(); - _pending_block->block_mroot = get_dynamic_global_properties().block_merkle_root.get_root(); - _pending_block->transaction_mroot = transaction_metadata::calculate_transaction_merkle_root( _pending_transaction_metas ); - _pending_block->action_mroot = _pending_block_trace->calculate_action_merkle_root(); + _pending_block->timestamp = when; + _pending_block->producer = producer_obj.owner; + _pending_block->previous = head_block_id(); + _pending_block->block_mroot = get_dynamic_global_properties().block_merkle_root.get_root(); + _pending_block->transaction_mroot = transaction_metadata::calculate_transaction_merkle_root( _pending_transaction_metas ); + _pending_block->action_mroot = _pending_block_trace->calculate_action_merkle_root(); + if( is_start_of_round( _pending_block->block_num() ) ) { + auto latest_producer_schedule = _calculate_producer_schedule(); + if( latest_producer_schedule != _head_producer_schedule() ) + _pending_block->new_producers = latest_producer_schedule; + } - if( is_start_of_round( _pending_block->block_num() ) ) { - auto latest_producer_schedule = _calculate_producer_schedule(); - if( latest_producer_schedule != _head_producer_schedule() ) - _pending_block->new_producers = latest_producer_schedule; - } + if( !(skip & skip_producer_signature) ) + _pending_block->sign( block_signing_key ); - if( !(skip & skip_producer_signature) ) - _pending_block->sign( block_signing_key ); + _finalize_block( *_pending_block_trace ); - _finalize_block( *_pending_block_trace ); + _pending_block_session->push(); - _pending_block_session->push(); + auto result = move( *_pending_block ); - auto result = move( *_pending_block ); + clear_pending(); - _pending_block_trace.reset(); - _pending_block.reset(); - _pending_block_session.reset(); + if (!(skip&skip_fork_db)) { + _fork_db.push_block(result); + } + return result; + } catch ( ... ) { + clear_pending(); - if (!(skip&skip_fork_db)) { - _fork_db.push_block(result); + elog( "error while producing block" ); + _start_pending_block(); + throw; } - return result; } FC_CAPTURE_AND_RETHROW( (producer) ) } @@ -524,6 +547,7 @@ void chain_controller::clear_pending() _pending_block_trace.reset(); _pending_block.reset(); _pending_block_session.reset(); + _pending_transaction_metas.clear(); } FC_CAPTURE_AND_RETHROW() } //////////////////// private methods //////////////////// @@ -581,10 +605,11 @@ void chain_controller::__apply_block(const signed_block& next_block) /// cache the input tranasction ids so that they can be looked up when executing the /// summary vector input_metas; - map trx_index; + input_metas.reserve(next_block.input_transactions.size()); + map trx_index; for( const auto& t : next_block.input_transactions ) { input_metas.emplace_back(t, chain_id_type(), next_block.timestamp); - trx_index[input_metas.back().id] = &input_metas.back(); + trx_index[input_metas.back().id] = input_metas.size() - 1; } block_trace next_block_trace(next_block); @@ -637,7 +662,7 @@ void chain_controller::__apply_block(const signed_block& next_block) auto make_metadata = [&]() -> transaction_metadata* { auto itr = trx_index.find(receipt.id); if( itr != trx_index.end() ) { - return itr->second; + return &input_metas.at(itr->second); } else { const auto& gtrx = _db.get(receipt.id); auto trx = fc::raw::unpack(gtrx.packed_trx.data(), gtrx.packed_trx.size()); @@ -862,7 +887,8 @@ const producer_object& chain_controller::validate_block_header(uint32_t skip, co elog("Did not produce block within block_interval ${bi}ms, took ${t}ms)", ("bi", config::block_interval_ms)("t", (time_point(next_block.timestamp) - head_block_time()).count() / 1000)); } - if (next_block.block_num() % config::blocks_per_round != 0) { + + if( !is_start_of_round( next_block.block_num() ) ) { EOS_ASSERT(!next_block.new_producers, block_validate_exception, "Producer changes may only occur at the end of a round."); } @@ -896,18 +922,8 @@ void chain_controller::create_block_summary(const signed_block& next_block) { * block_signing_key is null. */ producer_schedule_type chain_controller::_calculate_producer_schedule()const { - const auto& producers_by_vote = _db.get_index(); - auto itr = producers_by_vote.begin(); - producer_schedule_type schedule; - uint32_t count = 0; - while( itr != producers_by_vote.end() && count < schedule.producers.size() ) { - schedule.producers[count].producer_name = itr->owner_name; - schedule.producers[count].block_signing_key = get_producer(itr->owner_name).signing_key; - ++itr; - if( schedule.producers[count].block_signing_key != public_key_type() ) { - ++count; - } - } + producer_schedule_type schedule = get_global_properties().new_active_producers; + const auto& hps = _head_producer_schedule(); schedule.version = hps.version; if( hps != schedule ) @@ -918,7 +934,7 @@ producer_schedule_type chain_controller::_calculate_producer_schedule()const { /** * Returns the most recent and/or pending producer schedule */ -const producer_schedule_type& chain_controller::_head_producer_schedule()const { +const shared_producer_schedule_type& chain_controller::_head_producer_schedule()const { const auto& gpo = get_global_properties(); if( gpo.pending_active_producers.size() ) return gpo.pending_active_producers.back().second; @@ -944,9 +960,14 @@ void chain_controller::update_global_properties(const signed_block& b) { try { if( props.pending_active_producers.size() && props.pending_active_producers.back().first == b.block_num() ) props.pending_active_producers.back().second = schedule; else - props.pending_active_producers.push_back( make_pair(b.block_num(),schedule) ); - }); + { + props.pending_active_producers.emplace_back( props.pending_active_producers.get_allocator() );// props.pending_active_producers.size()+1, props.pending_active_producers.get_allocator() ); + auto& back = props.pending_active_producers.back(); + back.first = b.block_num(); + back.second = schedule; + } + }); auto active_producers_authority = authority(config::producers_authority_threshold, {}, {}); @@ -1020,10 +1041,18 @@ void chain_controller::_initialize_indexes() { _db.add_index(); _db.add_index(); _db.add_index(); + + + _db.add_index(); _db.add_index(); + _db.add_index(); + _db.add_index(); + + _db.add_index(); _db.add_index(); + _db.add_index(); _db.add_index(); _db.add_index(); @@ -1050,6 +1079,8 @@ void chain_controller::_initialize_chain(contracts::chain_initializer& starter) const auto& gp = _db.create([&starter](global_property_object& p) { p.configuration = starter.get_chain_start_configuration(); p.active_producers = starter.get_chain_start_producers(); + p.new_active_producers = starter.get_chain_start_producers(); + wdump((starter.get_chain_start_producers())); }); _db.create([&](dynamic_global_property_object& p) { @@ -1224,7 +1255,7 @@ void chain_controller::update_global_dynamic_data(const signed_block& b) { dgp.recent_slots_filled += 1; dgp.recent_slots_filled <<= missed_blocks; } else - if(config::percent_100 * get_global_properties().active_producers.producers.size() / config::blocks_per_round > config::required_producer_participation) + if(config::percent_100 * get_global_properties().active_producers.producers.size() / blocks_per_round() > config::required_producer_participation) dgp.recent_slots_filled = uint64_t(-1); else dgp.recent_slots_filled = 0; @@ -1254,7 +1285,8 @@ void chain_controller::update_last_irreversible_block() vector producer_objs; producer_objs.reserve(gpo.active_producers.producers.size()); - std::transform(gpo.active_producers.producers.begin(), gpo.active_producers.producers.end(), std::back_inserter(producer_objs), + std::transform(gpo.active_producers.producers.begin(), + gpo.active_producers.producers.end(), std::back_inserter(producer_objs), [this](const producer_key& pk) { return &get_producer(pk.producer_name); }); static_assert(config::irreversible_threshold_percent > 0, "irreversible threshold must be nonzero"); @@ -1266,6 +1298,12 @@ void chain_controller::update_last_irreversible_block() }); uint32_t new_last_irreversible_block_num = producer_objs[offset]->last_confirmed_block_num; + // TODO: right now the code cannot handle the head block being irreversible for reasons that are purely + // implementation details. We can and should remove this special case once the rest of the logic is fixed. + if (producer_objs.size() == 1) { + new_last_irreversible_block_num -= 1; + } + if (new_last_irreversible_block_num > dpo.last_irreversible_block_num) { _db.modify(dpo, [&](dynamic_global_property_object& _dpo) { @@ -1285,7 +1323,7 @@ void chain_controller::update_last_irreversible_block() block_to_write <= new_last_irreversible_block_num; ++block_to_write) { auto block = fetch_block_by_number(block_to_write); - assert(block); + FC_ASSERT( block, "unable to find last irreversible block to write" ); _block_log.append(*block); applied_irreversible_block(*block); } @@ -1310,7 +1348,6 @@ void chain_controller::update_last_irreversible_block() } } - // Trim fork_database and undo histories _fork_db.set_max_size(head_block_num() - new_last_irreversible_block_num + 1); _db.commit(new_last_irreversible_block_num); @@ -1342,10 +1379,12 @@ account_name chain_controller::get_scheduled_producer(uint32_t slot_num)const const dynamic_global_property_object& dpo = get_dynamic_global_properties(); uint64_t current_aslot = dpo.current_absolute_slot + slot_num; const auto& gpo = _db.get(); - //auto number_of_active_producers = gpo.active_producers.size(); - auto index = current_aslot % (config::blocks_per_round); //TODO configure number of repetitions by producer + auto number_of_active_producers = gpo.active_producers.producers.size(); + auto index = current_aslot % (number_of_active_producers); index /= config::producer_repititions; + FC_ASSERT( gpo.active_producers.producers.size() > 0, "no producers defined" ); + return gpo.active_producers.producers[index].producer_name; } @@ -1397,8 +1436,8 @@ static void log_handled_exceptions(const transaction& trx) { transaction_trace chain_controller::__apply_transaction( transaction_metadata& meta ) { transaction_trace result(meta.id); - for (const auto &act : meta.trx.actions) { - apply_context context(*this, _db, act, meta); + for (const auto &act : meta.trx().actions) { + apply_context context(*this, _db, act, meta, txn_execution_time()); context.exec(); fc::move_append(result.action_traces, std::move(context.results.applied_actions)); fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions)); @@ -1418,7 +1457,7 @@ transaction_trace chain_controller::__apply_transaction( transaction_metadata& m } update_usage(meta, act_usage); - record_transaction(meta.trx); + record_transaction(meta.trx()); return result; } @@ -1434,7 +1473,7 @@ transaction_trace chain_controller::_apply_transaction( transaction_metadata& me throw; } // log exceptions we can handle with the error handle, throws otherwise - log_handled_exceptions(meta.trx); + log_handled_exceptions(meta.trx()); return _apply_error( meta ); } @@ -1451,7 +1490,7 @@ transaction_trace chain_controller::_apply_error( transaction_metadata& meta ) { try { auto temp_session = _db.start_undo_session(true); - apply_context context(*this, _db, etrx.actions.front(), meta); + apply_context context(*this, _db, etrx.actions.front(), meta, txn_execution_time()); context.exec(); fc::move_append(result.action_traces, std::move(context.results.applied_actions)); fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions)); @@ -1464,7 +1503,7 @@ transaction_trace chain_controller::_apply_error( transaction_metadata& meta ) { } update_usage(meta, act_usage); - record_transaction(meta.trx); + record_transaction(meta.trx()); temp_session.squash(); return result; @@ -1535,7 +1574,7 @@ void chain_controller::update_usage( transaction_metadata& meta, uint32_t act_us { set> authorizing_accounts; - for( const auto& act : meta.trx.actions ) + for( const auto& act : meta.trx().actions ) for( const auto& auth : act.authorization ) authorizing_accounts.emplace( auth.actor, auth.permission ); @@ -1549,38 +1588,36 @@ void chain_controller::update_usage( transaction_metadata& meta, uint32_t act_us auto head_time = head_block_time(); for( const auto& authaccnt : authorizing_accounts ) { + const auto& buo = _db.get( authaccnt.first ); _db.modify( buo, [&]( auto& bu ){ bu.bytes.add_usage( trx_size, head_time ); bu.acts.add_usage( act_usage, head_time ); }); - const auto& sbo = _db.get(authaccnt.first); - // TODO enable this after fixing divide by 0 with virtual_net_bandwidth and total_staked_tokens - /// note: buo.bytes.value is in ubytes and virtual_net_bandwidth is in bytes, so - // we convert to fixed int uin128_t with 60 bits of precision, divide by rate limiting precision - // then divide by virtual max_block_size which gives us % of virtual max block size in fixed width uint128_t used_ubytes = buo.bytes.value; uint128_t used_uacts = buo.acts.value; uint128_t virtual_max_ubytes = dgpo.virtual_net_bandwidth * config::rate_limiting_precision; uint128_t virtual_max_uacts = dgpo.virtual_act_bandwidth * config::rate_limiting_precision; - uint64_t user_stake = sbo.staked_balance; if( !(_skip_flags & genesis_setup) ) { - FC_ASSERT( (used_ubytes * dgpo.total_staked_tokens) <= (user_stake * virtual_max_ubytes), "authorizing account '${n}' has insufficient net bandwidth for this transaction", + #warning TODO: restore bandwidth checks + /* setting of bandwidth currently not implemented + FC_ASSERT( (used_ubytes * dgpo.total_net_weight) <= (buo.net_weight * virtual_max_ubytes), "authorizing account '${n}' has insufficient net bandwidth for this transaction", ("n",name(authaccnt.first)) ("used_bytes",double(used_ubytes)/1000000.) - ("user_stake",user_stake) + ("user_net_weight",buo.net_weight) ("virtual_max_bytes", double(virtual_max_ubytes)/1000000. ) - ("total_staked_tokens", dgpo.total_staked_tokens) + ("total_net_weight", dgpo.total_net_weight) ); - FC_ASSERT( (used_uacts * dgpo.total_staked_tokens) <= (user_stake * virtual_max_uacts), "authorizing account '${n}' has insufficient compute bandwidth for this transaction", + FC_ASSERT( (used_uacts * dgpo.total_cpu_weight) <= (buo.cpu_weight* virtual_max_uacts), "authorizing account '${n}' has insufficient compute bandwidth for this transaction", ("n",name(authaccnt.first)) ("used_acts",double(used_uacts)/1000000.) - ("user_stake",user_stake) + ("user_cpu_weight",buo.cpu_weight) ("virtual_max_uacts", double(virtual_max_uacts)/1000000. ) - ("total_staked_tokens", dgpo.total_staked_tokens) - ); + ("total_cpu_tokens", dgpo.total_cpu_weight) + ); + */ } // for any transaction not sent by code, update the affirmative last time a given permission was used @@ -1617,4 +1654,20 @@ const apply_handler* chain_controller::find_apply_handler( account_name receiver return nullptr; } +void chain_controller::set_txn_execution_times(uint32_t create_block_txn_execution_time, uint32_t rcvd_block_txn_execution_time, uint32_t txn_execution_time) +{ + _create_block_txn_execution_time = create_block_txn_execution_time; + _rcvd_block_txn_execution_time = rcvd_block_txn_execution_time; + _txn_execution_time = txn_execution_time; +} + +uint32_t chain_controller::txn_execution_time() const +{ + return _skip_flags & received_block + ? _rcvd_block_txn_execution_time + : (_skip_flags && created_block + ? _create_block_txn_execution_time + : _txn_execution_time); +} + } } /// eosio::chain diff --git a/libraries/chain/contracts/abi_serializer.cpp b/libraries/chain/contracts/abi_serializer.cpp index 8e4834020b57c5a210e6f7d5222a5925cb14c24e..6d848af82a015fe0eb11b5d126d1589677f3d2a1 100644 --- a/libraries/chain/contracts/abi_serializer.cpp +++ b/libraries/chain/contracts/abi_serializer.cpp @@ -98,7 +98,6 @@ namespace eosio { namespace chain { namespace contracts { built_in_types.emplace("action_def", pack_unpack()); built_in_types.emplace("table_def", pack_unpack()); built_in_types.emplace("abi_def", pack_unpack()); - built_in_types.emplace("nonce", pack_unpack()); } void abi_serializer::set_abi(const abi_def& abi) { diff --git a/libraries/chain/contracts/chain_initializer.cpp b/libraries/chain/contracts/chain_initializer.cpp index e791bb78af7e6a5951786441820828a0617b6c91..a7cbe3ea1053fe37a4cea355ecc7dbff8cf9d9fb 100644 --- a/libraries/chain/contracts/chain_initializer.cpp +++ b/libraries/chain/contracts/chain_initializer.cpp @@ -3,12 +3,17 @@ * @copyright defined in eos/LICENSE.txt */ #include -#include #include #include #include #include +#include + +#include +#include + +#include #include #include @@ -23,36 +28,25 @@ chain_config chain_initializer::get_chain_start_configuration() { return genesis.initial_configuration; } -producer_schedule_type chain_initializer::get_chain_start_producers() { +producer_schedule_type chain_initializer::get_chain_start_producers() { producer_schedule_type result; - std::transform(genesis.initial_producers.begin(), genesis.initial_producers.end(), result.producers.begin(), - [](const auto& p) { return producer_key{p.owner_name,p.block_signing_key}; }); + result.producers.push_back( {config::system_account_name, genesis.initial_key} ); + idump((result)); return result; } void chain_initializer::register_types(chain_controller& chain, chainbase::database& db) { - // Install the native contract's indexes; we can't do anything until our objects are recognized - db.add_index(); - db.add_index(); #define SET_APP_HANDLER( contract, scope, action, nspace ) \ chain._set_apply_handler( #contract, #scope, #action, &BOOST_PP_CAT(contracts::apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) ) - SET_APP_HANDLER( eosio, eosio, setproducer, eosio ); SET_APP_HANDLER( eosio, eosio, newaccount, eosio ); - SET_APP_HANDLER( eosio, eosio, transfer, eosio ); - SET_APP_HANDLER( eosio, eosio, lock, eosio ); - SET_APP_HANDLER( eosio, eosio, claim, eosio ); - SET_APP_HANDLER( eosio, eosio, unlock, eosio ); - SET_APP_HANDLER( eosio, eosio, okproducer, eosio ); - SET_APP_HANDLER( eosio, eosio, setproxy, eosio ); SET_APP_HANDLER( eosio, eosio, setcode, eosio ); SET_APP_HANDLER( eosio, eosio, setabi, eosio ); SET_APP_HANDLER( eosio, eosio, updateauth, eosio ); SET_APP_HANDLER( eosio, eosio, deleteauth, eosio ); SET_APP_HANDLER( eosio, eosio, linkauth, eosio ); SET_APP_HANDLER( eosio, eosio, unlinkauth, eosio ); - SET_APP_HANDLER( eosio, eosio, nonce, eosio ); SET_APP_HANDLER( eosio, eosio, onerror, eosio ); SET_APP_HANDLER( eosio, eosio, postrecovery, eosio ); SET_APP_HANDLER( eosio, eosio, passrecovery, eosio ); @@ -66,13 +60,6 @@ abi_def chain_initializer::eos_contract_abi() eos_abi.types.push_back( type_def{"account_name","name"} ); eos_abi.types.push_back( type_def{"share_type","int64"} ); eos_abi.types.push_back( type_def{"onerror","bytes"} ); - eos_abi.actions.push_back( action_def{name("transfer"), "transfer"} ); - eos_abi.actions.push_back( action_def{name("lock"), "lock"} ); - eos_abi.actions.push_back( action_def{name("unlock"), "unlock"} ); - eos_abi.actions.push_back( action_def{name("claim"), "claim"} ); - eos_abi.actions.push_back( action_def{name("okproducer"), "okproducer"} ); - eos_abi.actions.push_back( action_def{name("setproducer"), "setproducer"} ); - eos_abi.actions.push_back( action_def{name("setproxy"), "setproxy"} ); eos_abi.actions.push_back( action_def{name("setcode"), "setcode"} ); eos_abi.actions.push_back( action_def{name("setabi"), "setabi"} ); eos_abi.actions.push_back( action_def{name("linkauth"), "linkauth"} ); @@ -84,62 +71,9 @@ abi_def chain_initializer::eos_contract_abi() eos_abi.actions.push_back( action_def{name("passrecovery"), "passrecovery"} ); eos_abi.actions.push_back( action_def{name("vetorecovery"), "vetorecovery"} ); eos_abi.actions.push_back( action_def{name("onerror"), "onerror"} ); - eos_abi.actions.push_back( action_def{name("nonce"), "nonce"} ); // ACTION PAYLOADS - eos_abi.structs.emplace_back( struct_def { - "transfer", "", { - {"from", "account_name"}, - {"to", "account_name"}, - {"amount", "uint64"}, - {"memo", "string"}, - } - }); - - eos_abi.structs.emplace_back( struct_def { - "lock", "", { - {"from", "account_name"}, - {"to", "account_name"}, - {"amount", "share_type"}, - } - }); - - eos_abi.structs.emplace_back( struct_def { - "unlock", "", { - {"account", "account_name"}, - {"amount", "share_type"}, - } - }); - - eos_abi.structs.emplace_back( struct_def { - "claim", "", { - {"account", "account_name"}, - {"amount", "share_type"}, - } - }); - - eos_abi.structs.emplace_back( struct_def { - "okproducer", "", { - {"voter", "account_name"}, - {"producer", "account_name"}, - {"approve", "int8"}, - } - }); - - eos_abi.structs.emplace_back( struct_def { - "setproducer", "", { - {"name", "account_name"}, - {"key", "public_key"}, - {"configuration", "chain_config"}, - } - }); - eos_abi.structs.emplace_back( struct_def { - "setproxy", "", { - {"stakeholder", "account_name"}, - {"proxy", "account_name"}, - } - }); eos_abi.structs.emplace_back( struct_def { "setcode", "", { @@ -197,7 +131,6 @@ abi_def chain_initializer::eos_contract_abi() {"owner", "authority"}, {"active", "authority"}, {"recovery", "authority"}, - {"deposit", "asset"}, } }); @@ -221,12 +154,6 @@ abi_def chain_initializer::eos_contract_abi() } }); - eos_abi.structs.emplace_back( struct_def { - "nonce", "", { - {"value", "name"} - } - }); - // DATABASE RECORDS eos_abi.structs.emplace_back( struct_def { "account", "", { @@ -275,57 +202,76 @@ std::vector chain_initializer::prepare_database( chain_controller& chain std::vector messages_to_process; /// Create the native contract accounts manually; sadly, we can't run their contracts to make them create themselves - auto create_native_account = [this, &db](account_name name, auto liquid_balance) { + auto create_native_account = [this, &db](account_name name) { db.create([this, &name](account_object& a) { a.name = name; a.creation_date = genesis.initial_timestamp; + a.privileged = true; if( name == config::system_account_name ) { a.set_abi(eos_contract_abi()); } }); - const auto& owner = db.create([&name](permission_object& p) { + const auto& owner = db.create([&](permission_object& p) { p.owner = name; p.name = "owner"; p.auth.threshold = 1; + p.auth.keys.push_back( key_weight{ .key = genesis.initial_key, .weight = 1 } ); }); - db.create([&name, &owner](permission_object& p) { + db.create([&](permission_object& p) { p.owner = name; p.parent = owner.id; p.name = "active"; p.auth.threshold = 1; + p.auth.keys.push_back( key_weight{ .key = genesis.initial_key, .weight = 1 } ); + }); + db.create([&](auto& sb) { + sb.owner = name; + sb.net_weight = -1; + sb.cpu_weight = -1; + sb.db_reserved_capacity = -1; + }); + + db.create( [&]( auto& pro ) { + pro.owner = config::system_account_name; + pro.signing_key = genesis.initial_key; }); - intialize_eosio_tokens(db, name, liquid_balance); - db.create([&](auto& sb) { sb.owner_name = name; }); - db.create([&](auto& sb) { sb.owner = name; }); }; - create_native_account(config::system_account_name, config::initial_token_supply); + create_native_account(config::system_account_name); // Queue up messages which will run contracts to create the initial accounts + auto init_eosio_sytem = genesis_state_type::initial_account_type(name(config::eosio_system_account_name).to_string(), 0, 0, genesis.eosio_system_key, genesis.eosio_system_key); + genesis.initial_accounts.emplace_back(move(init_eosio_sytem)); + for (const auto& acct : genesis.initial_accounts) { action message( {{config::system_account_name, config::active_name}}, newaccount{ config::system_account_name, acct.name, authority(acct.owner_key), authority(acct.active_key), - authority(acct.owner_key), - acct.staking_balance}); + authority(acct.owner_key) + }); messages_to_process.emplace_back(move(message)); - - if (acct.liquid_balance > asset(0)) { - message = action( {{config::system_account_name, config::active_name}}, - transfer{ .from = config::system_account_name, .to = acct.name, - .amount = acct.liquid_balance.amount, .memo = "Genesis Allocation"}); - messages_to_process.emplace_back(move(message)); - } } - // Create initial producers - auto create_producer = boost::adaptors::transformed([config = genesis.initial_configuration](const auto& p) { - return action( {{p.owner_name, config::active_name}}, - setproducer(p.owner_name, p.block_signing_key, config)); - }); - boost::copy(genesis.initial_producers | create_producer, std::back_inserter(messages_to_process)); + // Create initial contracts eosio.system + auto wasm = wast_to_wasm(eosio_system_wast); + action eosio_system_setcode({{config::eosio_system_account_name, config::active_name}}, + contracts::setcode{ + .account = config::eosio_system_account_name, + .vmtype = 0, + .vmversion = 0, + .code = bytes(wasm.begin(), wasm.end()) + }); + auto abi = fc::json::from_string(eosio_system_abi).template as(); + action eosio_system_setabi({{config::eosio_system_account_name, config::active_name}}, + contracts::setabi{ + .account = config::eosio_system_account_name, + .abi = abi + }); + messages_to_process.emplace_back(move(eosio_system_setcode)); + messages_to_process.emplace_back(move(eosio_system_setabi)); + // Create special accounts auto create_special_account = [this, &db](account_name name, const auto& owner, const auto& active) { @@ -349,9 +295,7 @@ std::vector chain_initializer::prepare_database( chain_controller& chain auto empty_authority = authority(0, {}, {}); auto active_producers_authority = authority(config::producers_authority_threshold, {}, {}); - for(auto& p : genesis.initial_producers) { - active_producers_authority.accounts.push_back({{p.owner_name, config::active_name}, 1}); - } + active_producers_authority.accounts.push_back({{config::system_account_name, config::active_name}, 1}); create_special_account(config::nobody_account_name, empty_authority, empty_authority); create_special_account(config::producers_account_name, empty_authority, active_producers_authority); diff --git a/libraries/chain/contracts/eosio_contract.cpp b/libraries/chain/contracts/eosio_contract.cpp index 40d6a5b306b891a11f4e0c285485685d94738bd9..41cec9e23315518a45db77358d185094a6fb4df0 100644 --- a/libraries/chain/contracts/eosio_contract.cpp +++ b/libraries/chain/contracts/eosio_contract.cpp @@ -15,8 +15,6 @@ #include #include #include -#include -#include #include #include @@ -42,31 +40,16 @@ void intialize_eosio_tokens(chainbase::database& db, const account_name& system_ } static void modify_eosio_balance( apply_context& context, const account_name& account, share_type amt) { - const auto& t_id = context.find_or_create_table(account, config::system_account_name, N(currency)); + const auto& t_id = context.find_or_create_table(config::system_account_name, account, N(currency)); uint64_t key = N(account); share_type balance = 0; context.front_record(t_id, &key, (char *)&balance, sizeof(balance)); balance += amt; - context.store_record(t_id, &key, (const char *)&balance, sizeof(balance)); + context.store_record(t_id, config::system_account_name, &key, (const char *)&balance, sizeof(balance)); } -share_type get_eosio_balance( const chainbase::database& db, const account_name &account ) { - const auto* t_id = db.find(boost::make_tuple(account, config::system_account_name, N(currency))); - if (!t_id) { - return share_type(0); - } - - const auto& idx = db.get_index(); - auto itr = idx.lower_bound(boost::make_tuple(t_id->id)); - if ( itr == idx.end() || itr->t_id != t_id->id ) { - return share_type(0); - } - - FC_ASSERT(itr->value.size() == sizeof(share_type), "Invalid data in EOSIO balance table"); - return *reinterpret_cast(itr->value.data()); -} void validate_authority_precondition( const apply_context& context, const authority& auth ) { for(const auto& a : auth.accounts) { @@ -76,9 +59,7 @@ void validate_authority_precondition( const apply_context& context, const author } /** - * This method is called assuming precondition_system_newaccount succeeds and proceeds to - * deduct the balance of the account creator by deposit, this deposit is supposed to be - * credited to the staked balance the new account in the @staked contract. + * This method is called assuming precondition_system_newaccount succeeds a */ void apply_eosio_newaccount(apply_context& context) { auto create = context.act.as(); @@ -118,104 +99,10 @@ void apply_eosio_newaccount(apply_context& context) { const auto& owner_permission = create_permission("owner", 0, std::move(create.owner)); create_permission("active", owner_permission.id, std::move(create.active)); - share_type creator_balance = get_eosio_balance(context.db, create.creator); - - EOS_ASSERT(creator_balance >= create.deposit.amount, action_validate_exception, - "Creator '${c}' has insufficient funds to make account creation deposit of ${a}", - ("c", create.creator)("a", create.deposit)); - - modify_eosio_balance(context, create.creator, -create.deposit.amount); - - const auto& sbo = context.mutable_db.create([&]( staked_balance_object& sbo) { - sbo.owner_name = create.name; - sbo.staked_balance = 0; - }); - sbo.stake_tokens( create.deposit.amount, context.mutable_db ); - db.create([&]( auto& bu ) { bu.owner = create.name; }); } FC_CAPTURE_AND_RETHROW( (create) ) } -/** - * - * @ingroup native_eos - * @defgroup eos_eosio_transfer eosio::eos_transfer - */ -///@{ - - -void apply_eosio_transfer(apply_context& context) { - auto transfer = context.act.as(); - - try { - EOS_ASSERT(transfer.amount > 0, action_validate_exception, "Must transfer a positive amount"); - context.require_write_lock(transfer.to); - context.require_write_lock(transfer.from); - - context.require_authorization(transfer.from); - - context.require_recipient(transfer.to); - context.require_recipient(transfer.from); - } FC_CAPTURE_AND_RETHROW((transfer)) - - - try { - auto& db = context.mutable_db; - share_type from_balance = get_eosio_balance(db, transfer.from); - - EOS_ASSERT(from_balance >= transfer.amount, action_validate_exception, "Insufficient Funds", - ("from_balance", from_balance)("transfer.amount",transfer.amount)); - - modify_eosio_balance(context, transfer.from, - share_type(transfer.amount) ); - modify_eosio_balance(context, transfer.to, share_type(transfer.amount) ); - - } FC_CAPTURE_AND_RETHROW( (transfer) ) -} -///@} - -/** - * Deduct the balance from the from account. - */ -void apply_eosio_lock(apply_context& context) { - auto lock = context.act.as(); - - EOS_ASSERT(lock.amount > 0, action_validate_exception, "Locked amount must be positive"); - - context.require_write_lock(lock.to); - context.require_write_lock(lock.from); - context.require_write_lock(config::system_account_name); - - context.require_authorization(lock.from); - - context.require_recipient(lock.to); - context.require_recipient(lock.from); - - share_type locker_balance = get_eosio_balance(context.db, lock.from); - - EOS_ASSERT( locker_balance >= lock.amount, action_validate_exception, - "Account ${a} lacks sufficient funds to lock ${amt} EOS", ("a", lock.from)("amt", lock.amount)("available",locker_balance) ); - - modify_eosio_balance(context, lock.from, -share_type(lock.amount)); - - const auto& balance = context.db.get(lock.to); - balance.stake_tokens(lock.amount, context.mutable_db); -} - -void apply_eosio_unlock(apply_context& context) { - auto unlock = context.act.as(); - - context.require_authorization(unlock.account); - - EOS_ASSERT(unlock.amount >= 0, action_validate_exception, "Unlock amount cannot be negative"); - - const auto& balance = context.db.get(unlock.account); - - EOS_ASSERT(balance.staked_balance >= unlock.amount, action_validate_exception, - "Insufficient locked funds to unlock ${a}", ("a", unlock.amount)); - - balance.begin_unstaking_tokens(unlock.amount, context.mutable_db); -} - void apply_eosio_setcode(apply_context& context) { auto& db = context.mutable_db; @@ -229,6 +116,10 @@ void apply_eosio_setcode(apply_context& context) { auto code_id = fc::sha256::hash( act.code.data(), act.code.size() ); + // TODO: remove this compilation step in favor of validation without compilation + auto& code = context.mutable_controller.get_wasm_cache().checkout(code_id, act.code.data(), act.code.size()); + context.mutable_controller.get_wasm_cache().checkin(code_id, code); + const auto& account = db.get(act.account); // wlog( "set code: ${size}", ("size",act.code.size())); db.modify( account, [&]( auto& a ) { @@ -262,148 +153,6 @@ void apply_eosio_setabi(apply_context& context) { }); } -void apply_eosio_claim(apply_context& context) { - auto claim = context.act.as(); - - EOS_ASSERT(claim.amount > 0, action_validate_exception, "Claim amount must be positive"); - - context.require_authorization(claim.account); - - auto balance = context.db.find(claim.account); - - EOS_ASSERT(balance != nullptr, action_validate_exception, - "Could not find staked balance for ${name}", ("name", claim.account)); - - auto balance_release_time = balance->last_unstaking_time + fc::seconds(config::staked_balance_cooldown_sec); - auto now = context.controller.head_block_time(); - - EOS_ASSERT(now >= balance_release_time, action_validate_exception, - "Cannot claim balance until ${releaseDate}", ("releaseDate", balance_release_time)); - EOS_ASSERT(balance->unstaking_balance >= claim.amount, action_validate_exception, - "Cannot claim ${claimAmount} as only ${available} is available for claim", - ("claimAmount", claim.amount)("available", balance->unstaking_balance)); - - const auto& staked_balance = context.db.get(claim.account); - staked_balance.finish_unstaking_tokens(claim.amount, context.mutable_db); - - modify_eosio_balance(context, claim.account, share_type(claim.amount)); -} - - -void apply_eosio_setproducer(apply_context& context) { - auto update = context.act.as(); - context.require_authorization(update.name); - EOS_ASSERT(update.name.good(), action_validate_exception, "Producer owner name cannot be empty"); - - auto& db = context.mutable_db; - auto producer = db.find(update.name); - - if (producer) { - EOS_ASSERT(producer->signing_key != update.key || producer->configuration != update.configuration, - action_validate_exception, "Producer's new settings may not be identical to old settings"); - - db.modify(*producer, [&](producer_object& p) { - p.signing_key = update.key; - p.configuration = update.configuration; - }); - } else { - db.create([&](producer_object& p) { - p.owner = update.name; - p.signing_key = update.key; - p.configuration = update.configuration; - }); - db.create([&](producer_votes_object& pvo) { - pvo.owner_name = update.name; - }); - } -} - - -void apply_eosio_okproducer(apply_context& context) { - auto approve = context.act.as(); - EOS_ASSERT(approve.approve == 0 || approve.approve == 1, action_validate_exception, - "Unknown approval value: ${val}; must be either 0 or 1", ("val", approve.approve)); - context.require_recipient(approve.voter); - context.require_recipient(approve.producer); - - context.require_write_lock(config::system_account_name); - context.require_write_lock(approve.voter); - context.require_authorization(approve.voter); - - - auto& db = context.mutable_db; - const auto& producer = db.get(approve.producer); - const auto& voter = db.get(approve.voter); - - - EOS_ASSERT(voter.producer_votes.contains(), action_validate_exception, - "Cannot approve producer; approving account '${name}' proxies its votes to '${proxy}'", - ("name", voter.owner_name)("proxy", voter.producer_votes.get())); - - - const auto& slate = voter.producer_votes.get(); - - EOS_ASSERT(slate.size < config::max_producer_votes, action_validate_exception, - "Cannot approve producer; approved producer count is already at maximum"); - if (approve.approve) - EOS_ASSERT(!slate.contains(producer.owner_name), action_validate_exception, - "Cannot add approval to producer '${name}'; producer is already approved", - ("name", producer.owner_name)); - else - EOS_ASSERT(slate.contains(producer.owner_name), action_validate_exception, - "Cannot remove approval from producer '${name}'; producer is not approved", - ("name", producer.owner_name)); - - - auto total_voting_stake = voter.staked_balance; - - // Add/remove votes from producer - db.modify(producer, [approve = approve.approve, total_voting_stake](producer_votes_object& pvo) { - if (approve) - pvo.update_votes(total_voting_stake); - else - pvo.update_votes(-total_voting_stake); - }); - // Add/remove producer from voter's approved producer list - db.modify(voter, [&approve, producer = producer.owner_name](staked_balance_object& sbo) { - auto& slate = sbo.producer_votes.get(); - if (approve.approve) - slate.add(producer); - else - slate.remove(producer); - }); -} - -void apply_eosio_setproxy(apply_context& context) { - auto svp = context.act.as(); - FC_ASSERT( !"Not Implemented Yet" ); - - /* - context.require_authorization( spv.stakeholder ); - - context.require_recipient(svp.stakeholder); - context.require_recipient(svp.proxy); - - auto& db = context.mutable_db; - const auto& proxy = db.get(context.act.recipient(svp.proxy)); - const auto& balance = db.get(context.act.recipient(svp.stakeholder)); - - - auto proxy = db.find(context.act.recipient(svp.proxy)); - - - if (svp.proxy != svp.stakeholder) { - // We are enabling proxying to svp.proxy - proxy.add_proxy_source(context.act.recipient(svp.stakeholder), balance.staked_balance, db); - db.modify(balance, [target = proxy.proxy_target](staked_balance_object& sbo) { sbo.producer_votes = target; }); - } else { - // We are disabling proxying to balance.producer_votes.get() - proxy.remove_proxy_source(context.act.recipient(svp.stakeholder), balance.staked_balance, db); - db.modify(balance, [](staked_balance_object& sbo) { sbo.producer_votes = producer_slate{}; }); - } - */ -} - void apply_eosio_updateauth(apply_context& context) { context.require_write_lock( config::eosio_auth_scope ); @@ -548,9 +297,6 @@ void apply_eosio_unlinkauth(apply_context& context) { db.remove(*link); } -void apply_eosio_nonce(apply_context&) { - /// do nothing -} void apply_eosio_onerror(apply_context& context) { assert(context.trx_meta.sender); @@ -567,7 +313,7 @@ static const abi_serializer& get_abi_serializer() { } static optional get_pending_recovery(apply_context& context, account_name account ) { - const auto* t_id = context.find_table(account, config::system_account_name, N(recovery)); + const auto* t_id = context.find_table(config::system_account_name, account, N(recovery)); if (t_id) { uint64_t key = account; int32_t record_size = context.front_record(*t_id, &key, nullptr, 0); @@ -588,13 +334,13 @@ static optional get_pending_recovery(apply_context& context, account_na static uint32_t get_next_sender_id(apply_context& context) { context.require_write_lock( config::eosio_auth_scope ); - const auto& t_id = context.find_or_create_table(config::eosio_auth_scope, config::system_account_name, N(deferred.seq)); + const auto& t_id = context.find_or_create_table(config::system_account_name, config::eosio_auth_scope, N(deferred.seq)); uint64_t key = N(config::eosio_auth_scope); uint32_t next_serial = 0; context.front_record(t_id, &key, (char *)&next_serial, sizeof(uint32_t)); uint32_t result = next_serial++; - context.store_record(t_id, &key, (char *)&next_serial, sizeof(uint32_t)); + context.store_record(t_id, config::system_account_name, &key, (char *)&next_serial, sizeof(uint32_t)); return result; } @@ -681,15 +427,15 @@ void apply_eosio_postrecovery(apply_context& context) { context.execute_deferred(std::move(dtrx)); - const auto& t_id = context.find_or_create_table(account, config::system_account_name, N(recovery)); + const auto& t_id = context.find_or_create_table(config::system_account_name, account, N(recovery)); auto data = get_abi_serializer().variant_to_binary("pending_recovery", record_data); - context.store_record(t_id,&account.value, data.data() + sizeof(uint64_t), data.size() - sizeof(uint64_t)); + context.store_record(t_id, 0, &account.value, data.data() + sizeof(uint64_t), data.size() - sizeof(uint64_t)); context.console_append_formatted("Recovery Started for account ${account} : ${memo}\n", mutable_variant_object()("account", account)("memo", recover_act.memo)); } static void remove_pending_recovery(apply_context& context, const account_name& account) { - const auto& t_id = context.find_or_create_table(account, config::system_account_name, N(recovery)); + const auto& t_id = context.find_or_create_table(config::system_account_name, account, N(recovery)); context.remove_record(t_id, &account.value); } diff --git a/libraries/chain/contracts/producer_objects.cpp b/libraries/chain/contracts/producer_objects.cpp deleted file mode 100644 index 2f8cbf9d7f27cdb5071a1c535524cead2b89ca27..0000000000000000000000000000000000000000 --- a/libraries/chain/contracts/producer_objects.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include -#include - -#include - -#include -#include -#include - -namespace eosio { namespace chain { namespace contracts { - - - -} } } // namespace eosio::chain::contracts diff --git a/libraries/chain/contracts/staked_balance_objects.cpp b/libraries/chain/contracts/staked_balance_objects.cpp deleted file mode 100644 index 4e33adc436fa5b8dbd59546554965184e2631250..0000000000000000000000000000000000000000 --- a/libraries/chain/contracts/staked_balance_objects.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include -#include - -#include - -#include - -namespace eosio { namespace chain { namespace contracts { - -void staked_balance_object::stake_tokens(share_type new_stake, chainbase::database& db) const { - // Update the staked balance - db.modify(*this, [&new_stake](staked_balance_object& sbo) { - sbo.staked_balance += new_stake; - }); - - db.modify( db.get(), [&]( auto& dgpo ){ - dgpo.total_staked_tokens += new_stake; - }); - - propagate_votes(new_stake, db); -} - -void staked_balance_object::begin_unstaking_tokens(share_type amount, chainbase::database& db) const { - // Remember there might be stake left over from a previous, uncompleted unstaking in unstaking_balance - auto delta_stake = unstaking_balance - amount; - - // Update actual stake balance and invariants around it - stake_tokens(delta_stake, db); - // Update stats for unstaking process - db.modify(*this, [&amount, &db](staked_balance_object& sbo) { - sbo.unstaking_balance = amount; - sbo.last_unstaking_time = db.get(dynamic_global_property_object::id_type()).time; - }); - -} - -void staked_balance_object::finish_unstaking_tokens(share_type amount, chainbase::database& db) const { - db.modify(*this, [&amount](staked_balance_object& sbo) { - sbo.unstaking_balance -= amount; - }); - db.modify( db.get(), [&]( auto& dgpo ){ - dgpo.total_staked_tokens -= amount; - }); -} - -void staked_balance_object::propagate_votes(share_type staked_delta, chainbase::database& db) const { - if (producer_votes.contains()) - // This account votes for producers directly; update their stakes - boost::for_each(producer_votes.get().range(), [&db, &staked_delta](const account_name& name) { - db.modify(db.get(name), [&db, &staked_delta](producer_votes_object& pvo) { - pvo.update_votes(staked_delta); - }); - }); - else { - } -} - -} } } // namespace eosio::chain::contracts diff --git a/libraries/chain/get_config.cpp b/libraries/chain/get_config.cpp index caceaebd38ee9f7acadcdc5221602f3515d9b00e..54fcd85350a9649ab81defc77ddb7d3b2d7daf7c 100644 --- a/libraries/chain/get_config.cpp +++ b/libraries/chain/get_config.cpp @@ -13,8 +13,8 @@ fc::variant_object get_config() { fc::mutable_variant_object result; - result["block_interval_ms"] = config::block_interval_ms; - result["producer_count"] = config::producer_count; +// result["block_interval_ms"] = config::block_interval_ms; +// result["producer_count"] = config::producer_count; /// TODO: add extra config parms return result; } diff --git a/libraries/chain/include/eosio/chain/account_object.hpp b/libraries/chain/include/eosio/chain/account_object.hpp index f8220958fcb046edee826c3b8ed24436b695a87c..d0ea6b9d21850f532ccf78829ab792fed8ef51ac 100644 --- a/libraries/chain/include/eosio/chain/account_object.hpp +++ b/libraries/chain/include/eosio/chain/account_object.hpp @@ -19,6 +19,9 @@ namespace eosio { namespace chain { account_name name; uint8_t vm_type = 0; uint8_t vm_version = 0; + bool privileged = false; + bool frozen = false; + time_point_sec last_code_update; digest_type code_version; block_timestamp_type creation_date; diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index 445ece579d99862a3c8f18d153167de8e0f486af..bb4fe9ffb2de5b7e2135462ee30172530ddab41d 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -14,16 +14,201 @@ namespace chainbase { class database; } namespace eosio { namespace chain { +using contracts::key_value_object; + class chain_controller; class apply_context { + private: + template + class iterator_cache { + public: + typedef contracts::table_id_object table_id_object; + + iterator_cache(){ + _iterator_to_object.reserve(32); + } + + void cache_table( const table_id_object& tobj ) { + _table_cache[tobj.id] = &tobj; + } + + const table_id_object& get_table( table_id_object::id_type i ) { + auto itr = _table_cache.find(i); + FC_ASSERT( itr != _table_cache.end(), "an invariant was broken, table should be in cache" ); + return *_table_cache[i]; + } + + const T& get( int iterator ) { + FC_ASSERT( iterator >= 0, "invalid iterator" ); + FC_ASSERT( iterator < _iterator_to_object.size(), "iterator out of range" ); + auto result = _iterator_to_object[iterator]; + FC_ASSERT( result, "reference of deleted object" ); + return *result; + } + + void remove( int iterator, const T& obj ) { + _iterator_to_object[iterator] = nullptr; + _object_to_iterator.erase( &obj ); + } + + int add( const T& obj ) { + auto itr = _object_to_iterator.find( &obj ); + if( itr != _object_to_iterator.end() ) + return itr->second; + + _iterator_to_object.push_back( &obj ); + _object_to_iterator[&obj] = _iterator_to_object.size() - 1; + + return _iterator_to_object.size() - 1; + } + + private: + map _table_cache; + vector _iterator_to_object; + map _object_to_iterator; + }; public: - apply_context(chain_controller& con, chainbase::database& db, const action& a, const transaction_metadata& trx_meta) + template + class generic_index + { + public: + typedef typename ObjectType::secondary_key_type secondary_key_type; + generic_index( apply_context& c ):context(c){} + + int store( uint64_t scope, uint64_t table, const account_name& payer, + uint64_t id, const secondary_key_type& value ) + { + FC_ASSERT( payer != account_name(), "must specify a valid account to pay for new record" ); - :controller(con), db(db), act(a), mutable_controller(con), - mutable_db(db), used_authorizations(act.authorization.size(), false), - trx_meta(trx_meta) {} + context.require_write_lock( scope ); + + const auto& tab = context.find_or_create_table( scope, context.receiver, table ); + + const auto& obj = context.mutable_db.create( [&]( auto& o ){ + o.t_id = tab.id; + o.primary_key = id; + o.secondary_key = value; + o.payer = payer; + }); + + context.mutable_db.modify( tab, [&]( auto& t ) { + ++t.count; + }); + + context.update_db_usage( payer, sizeof(secondary_key_type)+200 ); + + itr_cache.cache_table( tab ); + return itr_cache.add( obj ); + } + + void remove( int iterator ) { + const auto& obj = itr_cache.get( iterator ); + context.update_db_usage( obj.payer, -( sizeof(secondary_key_type)+200 ) ); + + const auto& table_obj = itr_cache.get_table( obj.t_id ); + context.require_write_lock( table_obj.scope ); + + context.mutable_db.modify( table_obj, [&]( auto& t ) { + --t.count; + }); + context.mutable_db.remove( obj ); + + itr_cache.remove( iterator, obj ); + } + + void update( int iterator, account_name payer, const secondary_key_type& secondary ) { + const auto& obj = itr_cache.get( iterator ); + + if( payer == account_name() ) payer = obj.payer; + + if( obj.payer != payer ) { + context.update_db_usage( obj.payer, -(sizeof(secondary_key_type)+200) ); + context.update_db_usage( payer, +(sizeof(secondary_key_type)+200) ); + } + + context.mutable_db.modify( obj, [&]( auto& o ) { + o.secondary_key = secondary; + o.payer = payer; + }); + } + + int find_secondary( uint64_t code, uint64_t scope, uint64_t table, const secondary_key_type& secondary ) { + auto tab = context.find_table( scope, context.receiver, table ); + if( !tab ) return -1; + + const auto* obj = context.db.find( boost::make_tuple( tab->id, secondary ) ); + if( !obj ) return -1; + + itr_cache.cache_table( *tab ); + return itr_cache.add( *obj ); + } + + int lowerbound_secondary( uint64_t code, uint64_t scope, uint64_t table, const secondary_key_type& secondary ) { + auto tab = context.find_table( scope, context.receiver, table ); + if( !tab ) return -1; + + const auto& idx = context.db.get_index< chainbase::get_index_type::type, contracts::by_secondary >(); + auto itr = idx.lower_bound( boost::make_tuple( tab->id, secondary ) ); + if( itr == idx.end() ) return -1; + if( itr->t_id != tab->id ) return -1; + + itr_cache.cache_table( *tab ); + return itr_cache.add( *itr ); + } + + int upperbound_secondary( uint64_t code, uint64_t scope, uint64_t table, const secondary_key_type& secondary ) { + auto tab = context.find_table( scope, context.receiver, table ); + if( !tab ) return -1; + + const auto& idx = context.db.get_index< chainbase::get_index_type::type, contracts::by_secondary >(); + auto itr = idx.upper_bound( boost::make_tuple( tab->id, secondary ) ); + if( itr == idx.end() ) return -1; + if( itr->t_id != tab->id ) return -1; + + itr_cache.cache_table( *tab ); + return itr_cache.add( *itr ); + } + + int find_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary ) { + auto tab = context.find_table( scope, context.receiver, table ); + if( !tab ) return -1; + + const auto* obj = context.db.find( boost::make_tuple( tab->id, primary ) ); + if( !obj ) return -1; + + itr_cache.cache_table( *tab ); + return itr_cache.add( *obj ); + } + + void get( int iterator, uint64_t& primary, secondary_key_type& secondary ) { + const auto& obj = itr_cache.get( iterator ); + primary = obj.primary_key; + secondary = obj.secondary_key; + } + + private: + apply_context& context; + iterator_cache itr_cache; + }; + + + + + apply_context(chain_controller& con, chainbase::database& db, const action& a, const transaction_metadata& trx_meta, uint32_t checktime_limit) + + :controller(con), + db(db), + act(a), + mutable_controller(con), + mutable_db(db), + used_authorizations(act.authorization.size(), false), + trx_meta(trx_meta), + idx64(*this), + idx128(*this), + _checktime_limit(checktime_limit) + {} void exec(); @@ -32,14 +217,14 @@ class apply_context { void cancel_deferred( uint32_t sender_id ); using table_id_object = contracts::table_id_object; - const table_id_object* find_table( name scope, name code, name table ); - const table_id_object& find_or_create_table( name scope, name code, name table ); + const table_id_object* find_table( name code, name scope, name table ); + const table_id_object& find_or_create_table( name code, name scope, name table ); template - int32_t store_record( const table_id_object& t_id, const typename ObjectType::key_type* keys, const char* value, size_t valuelen ); + int32_t store_record( const table_id_object& t_id, const account_name& bta, const typename ObjectType::key_type* keys, const char* value, size_t valuelen ); template - int32_t update_record( const table_id_object& t_id, const typename ObjectType::key_type* keys, const char* value, size_t valuelen ); + int32_t update_record( const table_id_object& t_id, const account_name& bta, const typename ObjectType::key_type* keys, const char* value, size_t valuelen ); template int32_t remove_record( const table_id_object& t_id, const typename ObjectType::key_type* keys ); @@ -103,6 +288,7 @@ class apply_context { const chainbase::database& db; ///< database where state is stored const action& act; ///< message being applied account_name receiver; ///< the code that is currently running + bool privileged = false; chain_controller& mutable_controller; chainbase::database& mutable_db; @@ -181,8 +367,156 @@ class apply_context { console_append(fc::format_string(fmt, vo)); } + void checktime_start(); + + void checktime() const; + + void update_db_usage( const account_name& payer, int64_t delta ) { + require_write_lock( payer ); + if( (delta > 0) && payer != account_name(receiver) ) { + require_authorization( payer ); + } + } + + + int db_store_i64( uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) { + require_write_lock( scope ); + const auto& tab = find_or_create_table( scope, receiver, table ); + auto tableid = tab.id; + + FC_ASSERT( payer != account_name(), "must specify a valid account to pay for new record" ); + + const auto& obj = mutable_db.create( [&]( auto& o ) { + o.t_id = tableid; + o.primary_key = id; + o.value.resize( buffer_size ); + o.payer = payer; + memcpy( o.value.data(), buffer, buffer_size ); + }); + + mutable_db.modify( tab, [&]( auto& t ) { + ++t.count; + }); + + update_db_usage( payer, buffer_size + 200 ); + + keyval_cache.cache_table( tab ); + return keyval_cache.add( obj ); + } + + void db_update_i64( int iterator, account_name payer, const char* buffer, size_t buffer_size ) { + const key_value_object& obj = keyval_cache.get( iterator ); + + require_write_lock( keyval_cache.get_table( obj.t_id ).scope ); + + int64_t old_size = obj.value.size(); + + if( payer == account_name() ) payer = obj.payer; + + if( account_name(obj.payer) == payer ) { + update_db_usage( obj.payer, buffer_size + 200 - old_size ); + } else { + update_db_usage( obj.payer, -(old_size+200) ); + update_db_usage( payer, (buffer_size+200) ); + } + + mutable_db.modify( obj, [&]( auto& o ) { + o.value.resize( buffer_size ); + memcpy( o.value.data(), buffer, buffer_size ); + o.payer = payer; + }); + } + + void db_remove_i64( int iterator ) { + const key_value_object& obj = keyval_cache.get( iterator ); + update_db_usage( obj.payer, -(obj.value.size()+200) ); + + const auto& table_obj = keyval_cache.get_table( obj.t_id ); + require_write_lock( table_obj.scope ); + + mutable_db.modify( table_obj, [&]( auto& t ) { + --t.count; + }); + mutable_db.remove( obj ); + + keyval_cache.remove( iterator, obj ); + } + + int db_get_i64( int iterator, uint64_t& id, char* buffer, size_t buffer_size ) { + const key_value_object& obj = keyval_cache.get( iterator ); + if( buffer_size >= obj.value.size() ) { + memcpy( buffer, obj.value.data(), obj.value.size() ); + } + id = obj.primary_key; + return obj.value.size(); + } + + int db_next_i64( int iterator ) { + const auto& obj = keyval_cache.get( iterator ); + const auto& idx = db.get_index(); + + auto itr = idx.iterator_to( obj ); + ++itr; + + if( itr == idx.end() ) return -1; + if( itr->t_id != obj.t_id ) return -1; + + return keyval_cache.add( *itr ); + } + + int db_find_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { + require_read_lock( code, scope ); + + const auto* tab = find_table( scope, code, table ); + if( !tab ) return -1; + + + const key_value_object* obj = db.find( boost::make_tuple( tab->id, id ) ); + if( !obj ) return -1; + + keyval_cache.cache_table( *tab ); + return keyval_cache.add( *obj ); + } + + int db_lowerbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { + require_read_lock( code, scope ); + + const auto* tab = find_table( scope, code, table ); + if( !tab ) return -1; + + + const auto& idx = db.get_index(); + auto itr = idx.lower_bound( boost::make_tuple( tab->id, id ) ); + if( itr == idx.end() ) return -1; + if( itr->t_id != tab->id ) return -1; + + keyval_cache.cache_table( *tab ); + return keyval_cache.add( *itr ); + } + + int db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { + require_read_lock( code, scope ); + + const auto* tab = find_table( scope, code, table ); + if( !tab ) return -1; + + + const auto& idx = db.get_index(); + auto itr = idx.upper_bound( boost::make_tuple( tab->id, id ) ); + if( itr == idx.end() ) return -1; + if( itr->t_id != tab->id ) return -1; + + keyval_cache.cache_table( *tab ); + return keyval_cache.add( *itr ); + } + + + generic_index idx64; + generic_index idx128; private: + iterator_cache keyval_cache; + void append_results(apply_results &&other) { fc::move_append(results.applied_actions, move(other.applied_actions)); fc::move_append(results.generated_transactions, move(other.generated_transactions)); @@ -198,6 +532,8 @@ class apply_context { vector _read_locks; vector _write_scopes; bytes _cached_trx; + fc::time_point _checktime_start; + const uint32_t _checktime_limit; }; using apply_handler = std::function; @@ -320,57 +656,25 @@ using apply_handler = std::function; template< typename ObjectType > using key_helper = key_helper_impl; - /// find_tuple helper - template - struct exact_tuple_impl { - static auto get(const contracts::table_id_object& tid, const KeyType* keys, Args... args ) { - return exact_tuple_impl::get(tid, keys, raw_key_value(keys, KeyIndex), args...); - } - }; - - template - struct exact_tuple_impl { - static auto get(const contracts::table_id_object& tid, const KeyType*, Args... args) { - return boost::make_tuple(tid.id, args...); - } - }; - - template - using exact_tuple = exact_tuple_impl; - - template< typename KeyType, int NullKeyCount, typename Scope, typename ... Args > - struct lower_bound_tuple_impl { + template< typename KeyType, int KeyIndex, size_t Offset, typename ... Args > + struct partial_tuple_impl { static auto get(const contracts::table_id_object& tid, const KeyType* keys, Args... args) { - return lower_bound_tuple_impl::get(tid, keys, KeyType(0), args...); + return partial_tuple_impl::get(tid, keys, raw_key_value(keys, Offset + KeyIndex), args...); } }; - template< typename KeyType, typename Scope, typename ... Args > - struct lower_bound_tuple_impl { + template< typename KeyType, size_t Offset, typename ... Args > + struct partial_tuple_impl { static auto get(const contracts::table_id_object& tid, const KeyType* keys, Args... args) { - return boost::make_tuple( tid.id, raw_key_value(keys, scope_to_key_index_v), args...); + return boost::make_tuple( tid.id, raw_key_value(keys, Offset), args...); } }; template< typename IndexType, typename Scope > - using lower_bound_tuple = lower_bound_tuple_impl - 1, Scope>; + using partial_tuple = partial_tuple_impl - 1, impl::scope_to_key_index_v>; - template< typename KeyType, int NullKeyCount, typename Scope, typename ... Args > - struct upper_bound_tuple_impl { - static auto get(const contracts::table_id_object& tid, const KeyType* keys, Args... args) { - return upper_bound_tuple_impl::get(tid, keys, KeyType(-1), args...); - } - }; - - template< typename KeyType, typename Scope, typename ... Args > - struct upper_bound_tuple_impl { - static auto get(const contracts::table_id_object& tid, const KeyType* keys, Args... args) { - return boost::make_tuple( tid.id, raw_key_value(keys, scope_to_key_index_v), args...); - } - }; - - template< typename IndexType, typename Scope > - using upper_bound_tuple = upper_bound_tuple_impl - 1, Scope>; + template + using exact_tuple = partial_tuple_impl; template struct record_scope_compare { @@ -395,7 +699,7 @@ using apply_handler = std::function; template - int32_t apply_context::store_record( const table_id_object& t_id, const typename ObjectType::key_type* keys, const char* value, size_t valuelen ) { + int32_t apply_context::store_record( const table_id_object& t_id, const account_name& bta, const typename ObjectType::key_type* keys, const char* value, size_t valuelen ) { require_write_lock( t_id.scope ); auto tuple = impl::exact_tuple::get(t_id, keys); @@ -418,7 +722,7 @@ using apply_handler = std::function; } template - int32_t apply_context::update_record( const table_id_object& t_id, const typename ObjectType::key_type* keys, const char* value, size_t valuelen ) { + int32_t apply_context::update_record( const table_id_object& t_id, const account_name& bta, const typename ObjectType::key_type* keys, const char* value, size_t valuelen ) { require_write_lock( t_id.scope ); auto tuple = impl::exact_tuple::get(t_id, keys); @@ -456,7 +760,7 @@ using apply_handler = std::function; require_read_lock( t_id.code, t_id.scope ); const auto& idx = db.get_index(); - auto tuple = impl::lower_bound_tuple::get(t_id, keys); + auto tuple = impl::partial_tuple::get(t_id, keys); auto itr = idx.lower_bound(tuple); if( itr == idx.end() || @@ -527,49 +831,6 @@ using apply_handler = std::function; } } - template - int32_t apply_context::next_record( const table_id_object& t_id, typename IndexType::value_type::key_type* keys, char* value, size_t valuelen ) { - require_read_lock( t_id.code, t_id.scope ); - - const auto& pidx = db.get_index(); - - auto tuple = impl::exact_tuple::get(t_id, keys); - auto pitr = pidx.find(tuple); - - if(pitr == pidx.end()) - return 0; - - const auto& fidx = db.get_index(); - auto itr = fidx.indicies().template project(pitr); - - const auto& idx = db.get_index(); - - if( itr == idx.end() || - itr->t_id != t_id.id || - !impl::key_helper::compare(*itr, keys) ) { - return 0; - } - - ++itr; - - if( itr == idx.end() || - itr->t_id != t_id.id ) { - return 0; - } - - impl::key_helper::get(keys, *itr); - - if (valuelen) { - auto copylen = std::min(itr->value.size(), valuelen); - if (copylen) { - itr->value.copy(value, copylen); - } - return copylen; - } else { - return itr->value.size(); - } - } - template int32_t apply_context::previous_record( const table_id_object& t_id, typename IndexType::value_type::key_type* keys, char* value, size_t valuelen ) { require_read_lock( t_id.code, t_id.scope ); @@ -614,7 +875,7 @@ using apply_handler = std::function; require_read_lock( t_id.code, t_id.scope ); const auto& idx = db.get_index(); - auto tuple = impl::lower_bound_tuple::get(t_id, keys); + auto tuple = impl::partial_tuple::get(t_id, keys); auto itr = idx.lower_bound(tuple); if( itr == idx.end() || @@ -638,7 +899,7 @@ using apply_handler = std::function; require_read_lock( t_id.code, t_id.scope ); const auto& idx = db.get_index(); - auto tuple = impl::upper_bound_tuple::get(t_id, keys); + auto tuple = impl::partial_tuple::get(t_id, keys); auto itr = idx.upper_bound(tuple); if( itr == idx.end() || diff --git a/libraries/chain/include/eosio/chain/asset.hpp b/libraries/chain/include/eosio/chain/asset.hpp index 6bdae8f1ebc5197f7af76b02d7de679d69718ec6..98d77ab4d3cd673c3309c2c07b09669850ca4753 100644 --- a/libraries/chain/include/eosio/chain/asset.hpp +++ b/libraries/chain/include/eosio/chain/asset.hpp @@ -39,34 +39,34 @@ struct asset uint8_t decimals()const; string symbol_name()const; int64_t precision()const; - const symbol& symbol() const { return sym; } + const symbol& get_symbol() const { return sym; } static asset from_string(const string& from); string to_string()const; asset& operator += (const asset& o) { - FC_ASSERT(symbol() == o.symbol()); + FC_ASSERT(get_symbol() == o.get_symbol()); amount += o.amount; return *this; } asset& operator -= (const asset& o) { - FC_ASSERT(symbol() == o.symbol()); + FC_ASSERT(get_symbol() == o.get_symbol()); amount -= o.amount; return *this; } - asset operator -()const { return asset(-amount, symbol()); } + asset operator -()const { return asset(-amount, get_symbol()); } friend bool operator == (const asset& a, const asset& b) { - return std::tie(a.symbol(), a.amount) == std::tie(b.symbol(), b.amount); + return std::tie(a.get_symbol(), a.amount) == std::tie(b.get_symbol(), b.amount); } friend bool operator < (const asset& a, const asset& b) { - FC_ASSERT(a.symbol() == b.symbol()); - return std::tie(a.amount,a.symbol()) < std::tie(b.amount,b.symbol()); + FC_ASSERT(a.get_symbol() == b.get_symbol()); + return std::tie(a.amount,a.get_symbol()) < std::tie(b.amount,b.get_symbol()); } friend bool operator <= (const asset& a, const asset& b) { return (a == b) || (a < b); } friend bool operator != (const asset& a, const asset& b) { return !(a == b); } @@ -74,13 +74,13 @@ struct asset friend bool operator >= (const asset& a, const asset& b) { return !(a < b); } friend asset operator - (const asset& a, const asset& b) { - FC_ASSERT(a.symbol() == b.symbol()); - return asset(a.amount - b.amount, a.symbol()); + FC_ASSERT(a.get_symbol() == b.get_symbol()); + return asset(a.amount - b.amount, a.get_symbol()); } friend asset operator + (const asset& a, const asset& b) { - FC_ASSERT(a.symbol() == b.symbol()); - return asset(a.amount + b.amount, a.symbol()); + FC_ASSERT(a.get_symbol() == b.get_symbol()); + return asset(a.amount + b.amount, a.get_symbol()); } friend std::ostream& operator << (std::ostream& out, const asset& a) { return out << a.to_string(); } diff --git a/libraries/chain/include/eosio/chain/chain_controller.hpp b/libraries/chain/include/eosio/chain/chain_controller.hpp index 94fff1abb1f965cc3cd2fd996434225e72b59380..79c6bc37bde3ccd7bc30cc3853e953b0ac20b482 100644 --- a/libraries/chain/include/eosio/chain/chain_controller.hpp +++ b/libraries/chain/include/eosio/chain/chain_controller.hpp @@ -50,7 +50,7 @@ namespace eosio { namespace chain { skip_output_check = 1 << 13, ///< used to skip checks for outputs in block exactly matching those created from apply pushed_transaction = 1 << 14, ///< used to indicate that the origination of the call was from a push_transaction, to determine time allotment created_block = 1 << 15, ///< used to indicate that the origination of the call was for creating a block, to determine time allotment - received_block = 1 << 16, ///< used to indicate that the origination of the call was for a received block, to determine time allotment + received_block = 1 << 16, ///< used to indicate that the origination of the call was for a received block, to determine time allotment genesis_setup = 1 << 17, ///< used to indicate that the origination of the call was for a genesis transaction skip_missed_block_penalty = 1 << 18, ///< used to indicate that missed blocks shouldn't count against producers (used in long unit tests) }; @@ -121,6 +121,8 @@ namespace eosio { namespace chain { * @return True if the controller is now applying a block; false otherwise */ bool is_applying_block()const { return _currently_applying_block; } + bool is_start_of_round( block_num_type n )const; + uint32_t blocks_per_round()const; chain_id_type get_chain_id()const { return chain_id_type(); } /// TODO: make this hash of constitution @@ -292,10 +294,17 @@ namespace eosio { namespace chain { )const; + void set_txn_execution_times(uint32_t create_block_txn_execution_time, uint32_t rcvd_block_txn_execution_time, uint32_t txn_execution_time); + + static const uint32_t default_received_block_transaction_execution_time_ms; + static const uint32_t default_transaction_execution_time_ms; + static const uint32_t default_create_block_transaction_execution_time_ms; private: const apply_handler* find_apply_handler( account_name contract, scope_name scope, action_name act )const; + uint32_t txn_execution_time() const; + friend class contracts::chain_initializer; friend class apply_context; @@ -321,7 +330,7 @@ namespace eosio { namespace chain { void _initialize_chain(contracts::chain_initializer& starter); producer_schedule_type _calculate_producer_schedule()const; - const producer_schedule_type& _head_producer_schedule()const; + const shared_producer_schedule_type& _head_producer_schedule()const; void replay(); @@ -432,6 +441,10 @@ namespace eosio { namespace chain { map< account_name, map > _apply_handlers; wasm_cache _wasm_cache; + + uint32_t _create_block_txn_execution_time; + uint32_t _rcvd_block_txn_execution_time; + uint32_t _txn_execution_time; }; } } diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index ee9a30fc55017c4749049e4bdff458ac596935e1..ba174cc7e609de3d0956333b7f619ad7b2e6241a 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -13,12 +13,12 @@ typedef __uint128_t uint128_t; const static auto default_block_log_dir = "block_log"; const static auto default_shared_memory_dir = "shared_mem"; const static auto default_shared_memory_size = 1024*1024*1024ll; -const static int producer_count = 21; const static uint64_t system_account_name = N(eosio); const static uint64_t nobody_account_name = N(nobody); const static uint64_t anybody_account_name = N(anybody); const static uint64_t producers_account_name = N(producers); +const static uint64_t eosio_system_account_name = N(eosio.system); const static uint64_t eosio_auth_scope = N(eosio.auth); const static uint64_t eosio_all_scope = N(eosio.all); @@ -71,13 +71,13 @@ const static uint16_t max_recursion_depth = 6; /** * The number of sequential blocks produced by a single producer */ -const static int producer_repititions = 6; +const static int producer_repititions = 12; /** * The number of blocks produced per round is based upon all producers having a chance * to produce all of their consecutive blocks. */ -const static int blocks_per_round = producer_count * producer_repititions; +//const static int blocks_per_round = producer_count * producer_repititions; const static int irreversible_threshold_percent= 70 * percent_1; const static int max_producer_votes = 30; diff --git a/libraries/chain/include/eosio/chain/contracts/contract_table_objects.hpp b/libraries/chain/include/eosio/chain/contracts/contract_table_objects.hpp index 514fcf885458c8335164a1d38c207d1f82c7aece..46f3c3c67755347a30ac519318cc9cdb50d73393 100644 --- a/libraries/chain/include/eosio/chain/contracts/contract_table_objects.hpp +++ b/libraries/chain/include/eosio/chain/contracts/contract_table_objects.hpp @@ -18,12 +18,13 @@ namespace eosio { namespace chain { namespace contracts { OBJECT_CTOR(table_id_object) id_type id; - scope_name scope; account_name code; + scope_name scope; table_name table; + uint32_t count = 0; /// the number of elements in the table }; - struct by_scope_code_table; + struct by_code_scope_table; using table_id_multi_index = chainbase::shared_multi_index_container< table_id_object, @@ -31,10 +32,10 @@ namespace eosio { namespace chain { namespace contracts { ordered_unique, member >, - ordered_unique, + ordered_unique, composite_key< table_id_object, - member, member, + member, member > > @@ -47,6 +48,7 @@ namespace eosio { namespace chain { namespace contracts { struct by_scope_secondary; struct by_scope_tertiary; + struct key_value_object : public chainbase::object { OBJECT_CTOR(key_value_object, (value)) @@ -57,6 +59,7 @@ namespace eosio { namespace chain { namespace contracts { table_id t_id; uint64_t primary_key; shared_string value; + account_name payer = 0; }; using key_value_index = chainbase::shared_multi_index_container< @@ -73,6 +76,90 @@ namespace eosio { namespace chain { namespace contracts { > >; + struct by_primary; + struct by_secondary; + + template + struct secondary_index + { + struct index_object : public chainbase::object { + OBJECT_CTOR(index_object) + typedef SecondaryKey secondary_key_type; + + typename chainbase::object::id_type id; + table_id t_id; + uint64_t primary_key; + SecondaryKey secondary_key; + account_name payer; + }; + + + typedef chainbase::shared_multi_index_container< + index_object, + indexed_by< + ordered_unique, member>, + ordered_unique, + composite_key< index_object, + member, + member + >, + composite_key_compare< std::less, std::less > + >, + ordered_unique, + composite_key< index_object, + member, + member + > + > + > + > index_index; + }; + + typedef secondary_index::index_object index64_object; + typedef secondary_index::index_index index64_index; + + typedef secondary_index::index_object index128_object; + typedef secondary_index::index_index index128_index; + + /* + struct index64_object : public chainbase::object { + OBJECT_CTOR(index64_object) + + typedef uint64_t key_type; + static const int number_of_keys = 1; + + id_type id; + table_id t_id; + uint64_t primary_key; + uint64_t secondary_key; + account_name payer; + }; + + using index64_index = chainbase::shared_multi_index_container< + index64_object, + indexed_by< + ordered_unique, member>, + ordered_unique, + composite_key< index64_object, + member, + member + >, + composite_key_compare< std::less, std::less > + >, + ordered_unique, + composite_key< index64_object, + member, + member + > + > + > + >; + */ + + + + + struct shared_string_less { bool operator()( const char* a, const char* b )const { return less(a, b); @@ -103,6 +190,7 @@ namespace eosio { namespace chain { namespace contracts { table_id t_id; shared_string primary_key; shared_string value; + account_name payer; }; using keystr_value_index = chainbase::shared_multi_index_container< @@ -130,6 +218,7 @@ namespace eosio { namespace chain { namespace contracts { uint128_t primary_key; uint128_t secondary_key; shared_string value; + account_name payer; }; using key128x128_value_index = chainbase::shared_multi_index_container< @@ -155,6 +244,45 @@ namespace eosio { namespace chain { namespace contracts { > >; + + struct key64x64_value_object : public chainbase::object { + OBJECT_CTOR(key64x64_value_object, (value)) + + typedef uint64_t key_type; + static const int number_of_keys = 2; + + id_type id; + table_id t_id; + uint64_t primary_key; + uint64_t secondary_key; + shared_string value; + account_name payer; + }; + + using key64x64_value_index = chainbase::shared_multi_index_container< + key64x64_value_object, + indexed_by< + ordered_unique, member>, + ordered_unique, + composite_key< key64x64_value_object, + member, + member, + member + >, + composite_key_compare< std::less,std::less,std::less > + >, + ordered_unique, + composite_key< key64x64_value_object, + member, + member, + member + >, + composite_key_compare< std::less,std::less,std::less > + > + > + >; + + struct key64x64x64_value_object : public chainbase::object { OBJECT_CTOR(key64x64x64_value_object, (value)) @@ -167,6 +295,7 @@ namespace eosio { namespace chain { namespace contracts { uint64_t secondary_key; uint64_t tertiary_key; shared_string value; + account_name payer; }; using key64x64x64_value_index = chainbase::shared_multi_index_container< @@ -208,10 +337,15 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::table_id_object, eosio::chain: CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key_value_object, eosio::chain::contracts::key_value_index) CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::keystr_value_object, eosio::chain::contracts::keystr_value_index) CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key128x128_value_object, eosio::chain::contracts::key128x128_value_index) +CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key64x64_value_object, eosio::chain::contracts::key64x64_value_index) CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key64x64x64_value_object, eosio::chain::contracts::key64x64x64_value_index) -FC_REFLECT(eosio::chain::contracts::table_id_object, (id)(scope)(code)(table) ) -FC_REFLECT(eosio::chain::contracts::key_value_object, (id)(t_id)(primary_key)(value) ) -FC_REFLECT(eosio::chain::contracts::keystr_value_object, (id)(t_id)(primary_key)(value) ) -FC_REFLECT(eosio::chain::contracts::key128x128_value_object, (id)(t_id)(primary_key)(secondary_key)(value) ) -FC_REFLECT(eosio::chain::contracts::key64x64x64_value_object, (id)(t_id)(primary_key)(secondary_key)(tertiary_key)(value) ) +CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::index64_object, eosio::chain::contracts::index64_index) +CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::index128_object, eosio::chain::contracts::index128_index) + +FC_REFLECT(eosio::chain::contracts::table_id_object, (id)(code)(scope)(table) ) +FC_REFLECT(eosio::chain::contracts::key_value_object, (id)(t_id)(primary_key)(value)(payer) ) +FC_REFLECT(eosio::chain::contracts::keystr_value_object, (id)(t_id)(primary_key)(value)(payer) ) +FC_REFLECT(eosio::chain::contracts::key128x128_value_object, (id)(t_id)(primary_key)(secondary_key)(value)(payer) ) +FC_REFLECT(eosio::chain::contracts::key64x64_value_object, (id)(t_id)(primary_key)(secondary_key)(value)(payer) ) +FC_REFLECT(eosio::chain::contracts::key64x64x64_value_object, (id)(t_id)(primary_key)(secondary_key)(tertiary_key)(value)(payer) ) diff --git a/libraries/chain/include/eosio/chain/contracts/eos_contract.hpp b/libraries/chain/include/eosio/chain/contracts/eos_contract.hpp index a7edd61b4e01fc71290414af744d74bd123f9950..563f8252f5655501ae15a92d5af6c8a0a8c98f40 100644 --- a/libraries/chain/include/eosio/chain/contracts/eos_contract.hpp +++ b/libraries/chain/include/eosio/chain/contracts/eos_contract.hpp @@ -25,23 +25,10 @@ namespace eosio { namespace chain { namespace contracts { void apply_eosio_passrecovery(apply_context&); void apply_eosio_vetorecovery(apply_context&); - void apply_eosio_transfer(apply_context& context); - void apply_eosio_lock(apply_context& context); - void apply_eosio_claim(apply_context&); - void apply_eosio_unlock(apply_context&); - - void apply_eosio_okproducer(apply_context&); - void apply_eosio_setproducer(apply_context&); - void apply_eosio_setproxy(apply_context&); - void apply_eosio_setcode(apply_context&); void apply_eosio_setabi(apply_context&); - void apply_eosio_nonce(apply_context&); void apply_eosio_onerror(apply_context&); ///@} end action handlers - - share_type get_eosio_balance( const chainbase::database& db, const account_name& account ); - } } } /// namespace eosio::contracts diff --git a/libraries/chain/include/eosio/chain/contracts/genesis_state.hpp b/libraries/chain/include/eosio/chain/contracts/genesis_state.hpp index 1e5df55ae3f036e469687be3aa3e9708aad84e4b..919830a717ea8709747735918c81171b7b09ea03 100644 --- a/libraries/chain/include/eosio/chain/contracts/genesis_state.hpp +++ b/libraries/chain/include/eosio/chain/contracts/genesis_state.hpp @@ -61,6 +61,9 @@ struct genesis_state_type { }; time_point initial_timestamp; + public_key_type initial_key; + public_key_type eosio_system_key; + vector initial_accounts; vector initial_producers; @@ -85,5 +88,5 @@ FC_REFLECT(eosio::chain::contracts::genesis_state_type::initial_account_type, FC_REFLECT(eosio::chain::contracts::genesis_state_type::initial_producer_type, (owner_name)(block_signing_key)) FC_REFLECT(eosio::chain::contracts::genesis_state_type, - (initial_timestamp)(initial_configuration)(initial_accounts) + (initial_timestamp)(initial_key)(initial_configuration)(initial_accounts) (initial_producers)(initial_chain_id)) diff --git a/libraries/chain/include/eosio/chain/contracts/objects.hpp b/libraries/chain/include/eosio/chain/contracts/objects.hpp deleted file mode 100644 index e78fbc88a0ae397e9f1c6c81fb3a826b8a6f1ab4..0000000000000000000000000000000000000000 --- a/libraries/chain/include/eosio/chain/contracts/objects.hpp +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -/// @file This file #include's all database objects/indices used by the C++ native contract implementation - -#include -#include diff --git a/libraries/chain/include/eosio/chain/contracts/producer_objects.hpp b/libraries/chain/include/eosio/chain/contracts/producer_objects.hpp deleted file mode 100644 index 741014a20ee8edbdb6782e3477981293b8424b70..0000000000000000000000000000000000000000 --- a/libraries/chain/include/eosio/chain/contracts/producer_objects.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include -#include -#include - -#include - -#include - -#include - -namespace eosio { namespace chain { namespace contracts { - -FC_DECLARE_EXCEPTION(producer_race_overflow_exception, 10000000, "Producer Virtual Race time has overflowed"); - -/** - * @brief The producer_votes_object class tracks all votes for and by the block producers - * - * This class tracks the voting for block producers, as well as the virtual time 'race' to select the runner-up block - * producer. - * - * This class also tracks the votes cast by block producers on various chain configuration options and key documents. - */ -class producer_votes_object : public chainbase::object { - OBJECT_CTOR(producer_votes_object) - - id_type id; - account_name owner_name; - share_type votes = 0; - - /** - * @brief Update the tally of votes for the producer - * @param delta_votes The change in votes since the last update - */ - void update_votes(share_type delta_votes) { - votes += delta_votes; - } -}; - -using boost::multi_index::const_mem_fun; -/// Index producers by their owner's name -struct by_owner_name; -/// Index producers by projected race finishing time, from soonest to latest -struct by_projected_race_finish_time; -/// Index producers by votes, from greatest to least -struct by_votes; - -using producer_votes_multi_index = chainbase::shared_multi_index_container< - producer_votes_object, - indexed_by< - ordered_unique< tag, - member - >, - ordered_unique< tag, - member - >, - ordered_unique< tag, - composite_key, - member - >, - composite_key_compare< std::greater,std::less > - > - > ->; - -/// Index proxies by the proxy target account name -struct by_target_name; - -} } } // namespace eosio::chain::contracts - -CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::producer_votes_object, eosio::chain::contracts::producer_votes_multi_index) diff --git a/libraries/chain/include/eosio/chain/contracts/staked_balance_objects.hpp b/libraries/chain/include/eosio/chain/contracts/staked_balance_objects.hpp deleted file mode 100644 index 208119683cfa7526cc51f4ce4555192baafa78b1..0000000000000000000000000000000000000000 --- a/libraries/chain/include/eosio/chain/contracts/staked_balance_objects.hpp +++ /dev/null @@ -1,115 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include -#include -#include - -#include - -#include - -namespace eosio { namespace chain { namespace contracts { - -/** - * @brief The producer_slate struct stores a list of producers voted on by an account - */ -struct producer_slate { - std::array votes; - size_t size = 0; - - void add(account_name producer) { - votes[size++] = producer; - std::inplace_merge(votes.begin(), votes.begin() + size - 1, votes.begin() + size); - } - void remove(account_name producer) { - auto itr = std::remove(votes.begin(), votes.begin() + size, producer); - size = std::distance(votes.begin(), itr); - } - bool contains(account_name producer) const { - return std::binary_search(votes.begin(), votes.begin() + size, producer); - } - - auto range() { return boost::make_iterator_range_n(votes.begin(), size); } - auto range() const { return boost::make_iterator_range_n(votes.begin(), size); } -}; - -/** - * @brief The staked_balance_object class tracks the staked balance (voting balance) for accounts - */ -class staked_balance_object : public chainbase::object { - OBJECT_CTOR(staked_balance_object) - - id_type id; - account_name owner_name; - - share_type staked_balance = 0; - share_type unstaking_balance = 0; - time_point last_unstaking_time = time_point::maximum(); - - uint128_t staked_balance_percent = 0; - - /// The account's vote on producers. This may either be a list of approved producers, or an account to proxy vote to - fc::static_variant producer_votes = producer_slate{}; - - /** - * @brief Add the provided stake to this balance, maintaining invariants - * @param new_stake The new stake to add to the balance - * @param db Read-write reference to the database - * - * This method will update this object with the new stake, while maintaining invariants around the stake balance, - * such as by updating vote tallies - */ - void stake_tokens(share_type new_stake, chainbase::database& db) const; - /** - * @brief Begin unstaking the specified amount of stake, maintaining invariants - * @param amount The amount of stake to begin unstaking - * @param db Read-write reference to the database - * - * This method will update this object's balances while maintaining invariants around the stake balances, such as by - * updating vote tallies - */ - void begin_unstaking_tokens(share_type amount, chainbase::database& db) const; - /** - * @brief Finish unstaking the specified amount of stake - * @param amount The amount of stake to finish unstaking - * @param db Read-write reference to the database - * - * This method will update this object's balances. There aren't really any invariants to maintain on this call, as - * the tokens are already unstaked and removed from vote tallies, but it is provided for completeness' sake. - */ - void finish_unstaking_tokens(share_type amount, chainbase::database& db) const; - - /** - * @brief Propagate the specified change in stake to the producer votes or the proxy - * @param staked_delta The change in stake - * @param db Read-write reference to the database - * - * This method will apply the provided delta in voting stake to the next stage in the producer voting pipeline, - * whether that be the producers in the slate, or the account the votes are proxied to. - * - * This method will *not* update this object in any way. It will not adjust @ref staked_balance, etc - */ - void propagate_votes(share_type staked_delta, chainbase::database& db) const; -}; - -struct by_owner_name; - -using staked_balance_multi_index = chainbase::shared_multi_index_container< - staked_balance_object, - indexed_by< - ordered_unique, - member - >, - ordered_unique, - member - > - > ->; - -} } } // namespace eosio::chain::contracts - -CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::staked_balance_object, eosio::chain::contracts::staked_balance_multi_index) diff --git a/libraries/chain/include/eosio/chain/contracts/types.hpp b/libraries/chain/include/eosio/chain/contracts/types.hpp index 4aeeb514f9a2fbe263dc36195af1632d585dd621..ba224a04c1a6020f1c30e0874741cc9549948f52 100644 --- a/libraries/chain/include/eosio/chain/contracts/types.hpp +++ b/libraries/chain/include/eosio/chain/contracts/types.hpp @@ -103,83 +103,12 @@ struct abi_def { vector tables; }; -struct transfer { - account_name from; - account_name to; - uint64 amount; - string memo; - - static account_name get_account() { - return config::system_account_name; - } - - static name get_name() { - return N(transfer); - } -}; - -struct lock { - lock() = default; - lock(const account_name& from, const account_name& to, const share_type& amount) - :from(from), to(to), amount(amount) - {} - - account_name from; - account_name to; - share_type amount; - - static account_name get_account() { - return config::system_account_name; - } - - static action_name get_name() { - return N(lock); - } -}; - -struct unlock { - unlock() = default; - unlock(const account_name& account, const share_type& amount) - :account(account), amount(amount) - {} - - account_name account; - share_type amount; - - static account_name get_account() { - return config::system_account_name; - } - - static action_name get_name() { - return N(unlock); - } -}; - -struct claim { - claim() = default; - claim(const account_name& account, const share_type& amount) - :account(account), amount(amount) - {} - - account_name account; - share_type amount; - - static account_name get_account() { - return config::system_account_name; - } - - static action_name get_name() { - return N(claim); - } -}; - struct newaccount { account_name creator; account_name name; authority owner; authority active; authority recovery; - asset deposit; static account_name get_account() { return config::system_account_name; @@ -218,61 +147,6 @@ struct setabi { } }; -struct setproducer { - setproducer() = default; - setproducer(const account_name& name, const public_key_type& key, const chain_config& configuration) - :name(name), key(key), configuration(configuration) - {} - - account_name name; - public_key_type key; - chain_config configuration; - - static account_name get_account() { - return config::system_account_name; - } - - static action_name get_name() { - return N(setproducer); - } -}; - -struct okproducer { - okproducer() = default; - okproducer(const account_name& voter, const account_name& producer, const int8_t& approve) - :voter(voter), producer(producer), approve(approve) - {} - - account_name voter; - account_name producer; - int8_t approve; - - static account_name get_account() { - return config::system_account_name; - } - - static action_name get_name() { - return N(okproducer); - } -}; - -struct setproxy { - setproxy() = default; - setproxy(const account_name& stakeholder, const account_name& proxy) - :stakeholder(stakeholder), proxy(proxy) - {} - - account_name stakeholder; - account_name proxy; - - static account_name get_account() { - return config::system_account_name; - } - - static action_name get_name() { - return N(setproxy); - } -}; struct updateauth { account_name account; @@ -397,18 +271,6 @@ struct vetorecovery { } }; -using nonce_type = name; -struct nonce { - nonce_type value; - - static account_name get_account() { - return config::system_account_name; - } - - static action_name get_name() { - return N(nonce); - } -}; } } } /// namespace eosio::chain::contracts @@ -418,16 +280,10 @@ FC_REFLECT( eosio::chain::contracts::struct_def , (name)(b FC_REFLECT( eosio::chain::contracts::action_def , (name)(type) ) FC_REFLECT( eosio::chain::contracts::table_def , (name)(index_type)(key_names)(key_types)(type) ) FC_REFLECT( eosio::chain::contracts::abi_def , (types)(structs)(actions)(tables) ) -FC_REFLECT( eosio::chain::contracts::transfer , (from)(to)(amount)(memo) ) -FC_REFLECT( eosio::chain::contracts::lock , (from)(to)(amount) ) -FC_REFLECT( eosio::chain::contracts::unlock , (account)(amount) ) -FC_REFLECT( eosio::chain::contracts::claim , (account)(amount) ) -FC_REFLECT( eosio::chain::contracts::newaccount , (creator)(name)(owner)(active)(recovery)(deposit) ) + +FC_REFLECT( eosio::chain::contracts::newaccount , (creator)(name)(owner)(active)(recovery) ) FC_REFLECT( eosio::chain::contracts::setcode , (account)(vmtype)(vmversion)(code) ) //abi FC_REFLECT( eosio::chain::contracts::setabi , (account)(abi) ) -FC_REFLECT( eosio::chain::contracts::setproducer , (name)(key)(configuration) ) -FC_REFLECT( eosio::chain::contracts::okproducer , (voter)(producer)(approve) ) -FC_REFLECT( eosio::chain::contracts::setproxy , (stakeholder)(proxy) ) FC_REFLECT( eosio::chain::contracts::updateauth , (account)(permission)(parent)(data) ) FC_REFLECT( eosio::chain::contracts::deleteauth , (account)(permission) ) FC_REFLECT( eosio::chain::contracts::linkauth , (account)(code)(type)(requirement) ) @@ -435,5 +291,4 @@ FC_REFLECT( eosio::chain::contracts::unlinkauth , (account FC_REFLECT( eosio::chain::contracts::postrecovery , (account)(data)(memo) ) FC_REFLECT( eosio::chain::contracts::passrecovery , (account) ) FC_REFLECT( eosio::chain::contracts::vetorecovery , (account) ) -FC_REFLECT( eosio::chain::contracts::nonce , (value) ) diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index c86570b45033f55883fac1e43d57540dd2a36e18..3b74deb3a325dc6c6d6d11222a87683115acc3aa 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -20,6 +20,7 @@ namespace eosio { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( unlinkable_block_exception, eosio::chain::chain_exception, 3090000, "unlinkable block" ) FC_DECLARE_DERIVED_EXCEPTION( black_swan_exception, eosio::chain::chain_exception, 3100000, "black swan" ) FC_DECLARE_DERIVED_EXCEPTION( unknown_block_exception, eosio::chain::chain_exception, 3110000, "unknown block" ) + FC_DECLARE_DERIVED_EXCEPTION( chain_type_exception, eosio::chain::chain_exception, 3120000, "chain type exception" ) FC_DECLARE_DERIVED_EXCEPTION( block_tx_output_exception, eosio::chain::block_validate_exception, 3020001, "transaction outputs in block do not match transaction outputs from applying block" ) FC_DECLARE_DERIVED_EXCEPTION( block_concurrency_exception, eosio::chain::block_validate_exception, 3020002, "block does not guarantee concurrent exection without conflicts" ) @@ -52,6 +53,13 @@ namespace eosio { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( pop_empty_chain, eosio::chain::undo_database_exception, 3070001, "there are no blocks to pop" ) + FC_DECLARE_DERIVED_EXCEPTION( name_type_exception, eosio::chain::chain_type_exception, 3120001, "Invalid name" ) + FC_DECLARE_DERIVED_EXCEPTION( public_key_type_exception, eosio::chain::chain_type_exception, 3120002, "Invalid public key" ) + FC_DECLARE_DERIVED_EXCEPTION( authority_type_exception, eosio::chain::chain_type_exception, 3120003, "Invalid authority" ) + FC_DECLARE_DERIVED_EXCEPTION( action_type_exception, eosio::chain::chain_type_exception, 3120004, "Invalid action" ) + FC_DECLARE_DERIVED_EXCEPTION( transaction_type_exception, eosio::chain::chain_type_exception, 3120005, "Invalid transaction" ) + FC_DECLARE_DERIVED_EXCEPTION( abi_type_exception, eosio::chain::chain_type_exception, 3120006, "Invalid ABI" ) + #define EOS_RECODE_EXC( cause_type, effect_type ) \ catch( const cause_type& e ) \ diff --git a/libraries/chain/include/eosio/chain/global_property_object.hpp b/libraries/chain/include/eosio/chain/global_property_object.hpp index a2787f01644d83d03692991aee78f2bbb1d532d5..0aa340bab26e9a083f5a7f0d90f32159e440e172 100644 --- a/libraries/chain/include/eosio/chain/global_property_object.hpp +++ b/libraries/chain/include/eosio/chain/global_property_object.hpp @@ -18,6 +18,14 @@ namespace eosio { namespace chain { + struct blocknum_producer_schedule { + blocknum_producer_schedule( allocator a ) + :second(a){} + + block_num_type first; + shared_producer_schedule_type second; + }; + /** * @class global_property_object * @brief Maintains global state information (committee_member list, current fees) @@ -28,18 +36,19 @@ namespace eosio { namespace chain { */ class global_property_object : public chainbase::object { - OBJECT_CTOR(global_property_object, (pending_active_producers) ) + OBJECT_CTOR(global_property_object, (active_producers)(new_active_producers)(pending_active_producers) ) id_type id; chain_config configuration; - producer_schedule_type active_producers; + shared_producer_schedule_type active_producers; + shared_producer_schedule_type new_active_producers; /** every block that has change in producer schedule gets inserted into this list, this includes * all blocks that see a change in producer signing keys or vote order. * * TODO: consider moving this to a more effeicent datatype */ - shared_vector< pair > pending_active_producers; + shared_vector< blocknum_producer_schedule > pending_active_producers; }; @@ -63,7 +72,10 @@ namespace eosio { namespace chain { time_point time; account_name current_producer; - share_type total_staked_tokens; + uint64_t total_net_weight = 1; + uint64_t total_cpu_weight = 1; + uint64_t total_db_capacity = 1024*1024*1024ull*1024ull; + uint64_t total_db_reserved = 0; /** * The current absolute slot number. Equal to the total diff --git a/libraries/chain/include/eosio/chain/producer_schedule.hpp b/libraries/chain/include/eosio/chain/producer_schedule.hpp index 3446a024b77bf21de7a957b770a9210048ee096f..52eaae5d39a9c89fcc72b5720e29094e57d5c6e5 100644 --- a/libraries/chain/include/eosio/chain/producer_schedule.hpp +++ b/libraries/chain/include/eosio/chain/producer_schedule.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace eosio { namespace chain { @@ -23,13 +24,39 @@ namespace eosio { namespace chain { */ struct producer_schedule_type { uint32_t version = 0; ///< sequentially incrementing version number - fc::array producers; + vector producers; + }; + + struct shared_producer_schedule_type { + shared_producer_schedule_type( chainbase::allocator alloc ) + :producers(alloc){} + + shared_producer_schedule_type& operator=( const producer_schedule_type& a ) { + version = a.version; + producers.clear(); + producers.reserve( a.producers.size() ); + for( const auto& p : a.producers ) + producers.push_back(p); + return *this; + } + + operator producer_schedule_type()const { + producer_schedule_type result; + result.producers.reserve(producers.size()); + for( const auto& p : producers ) + result.producers.push_back(p); + return result; + } + + uint32_t version = 0; ///< sequentially incrementing version number + shared_vector producers; }; inline bool operator == ( const producer_schedule_type& a, const producer_schedule_type& b ) { if( a.version != b.version ) return false; + if ( a.producers.size() != b.producers.size() ) return false; for( uint32_t i = 0; i < a.producers.size(); ++i ) if( a.producers[i] != b.producers[i] ) return false; return true; diff --git a/libraries/chain/include/eosio/chain/rate_limiting.hpp b/libraries/chain/include/eosio/chain/rate_limiting.hpp index 08098708e620bd4974b32d5b9b46de65457b29cf..e16adc668fb5aa289491310b651b5c0d884f7be1 100644 --- a/libraries/chain/include/eosio/chain/rate_limiting.hpp +++ b/libraries/chain/include/eosio/chain/rate_limiting.hpp @@ -55,6 +55,10 @@ namespace eosio { namespace chain { id_type id; account_name owner; + uint64_t net_weight = 0; + uint64_t cpu_weight = 0; + uint64_t db_reserved_capacity = 0; /// bytes + average_accumulator bytes; average_accumulator acts; ///< tracks a logical number of actions processed diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index 4d1d42f380e3e6755b37497f436cdd78b99851a1..344da4795e5d35f852ab4188c98db3756ba73485 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -8,54 +8,62 @@ namespace eosio { namespace chain { -struct transaction_metadata { +class transaction_metadata { // transaction_metadata( const transaction& t ) // :trx(t) // ,id(trx.id()) {} - - transaction_metadata( const transaction& t, const time_point& published, const account_name& sender, uint32_t sender_id, const char* raw_data, size_t raw_size ) - :trx(t) - ,id(trx.id()) - ,published(published) - ,sender(sender),sender_id(sender_id),raw_data(raw_data),raw_size(raw_size) - {} - - transaction_metadata( const packed_transaction& t, chain_id_type chainid, const time_point& published ); - - transaction_metadata( transaction_metadata && ) = default; - transaction_metadata& operator= (transaction_metadata &&) = default; - - // things for packed_transaction - optional raw_trx; - optional decompressed_trx; - - // things for signed/packed transactions - optional> signing_keys; - - const transaction& trx; - transaction_id_type id; - - uint32_t region_id = 0; - uint32_t cycle_index = 0; - uint32_t shard_index = 0; - uint32_t bandwidth_usage = 0; - time_point published; - - // things for processing deferred transactions - optional sender; - uint32_t sender_id = 0; - - // packed form to pass to contracts if needed - const char* raw_data = nullptr; - size_t raw_size = 0; - - vector packed_trx; - - // scopes available to this transaction if we are applying a block - optional*> allowed_read_locks; - optional*> allowed_write_locks; - - static digest_type calculate_transaction_merkle_root( const vector& metas ); + public: + transaction_metadata( const transaction& t, const time_point& published, const account_name& sender, uint32_t sender_id, const char* raw_data, size_t raw_size ) + :id(t.id()) + ,published(published) + ,sender(sender),sender_id(sender_id),raw_data(raw_data),raw_size(raw_size),_trx(&t) + {} + + transaction_metadata( const packed_transaction& t, chain_id_type chainid, const time_point& published ); + + transaction_metadata( transaction_metadata && ) = default; + transaction_metadata& operator= (transaction_metadata &&) = default; + + // things for packed_transaction + optional raw_trx; + optional decompressed_trx; + + // things for signed/packed transactions + optional> signing_keys; + + transaction_id_type id; + + uint32_t region_id = 0; + uint32_t cycle_index = 0; + uint32_t shard_index = 0; + uint32_t bandwidth_usage = 0; + time_point published; + + // things for processing deferred transactions + optional sender; + uint32_t sender_id = 0; + + // packed form to pass to contracts if needed + const char* raw_data = nullptr; + size_t raw_size = 0; + + vector packed_trx; + + // scopes available to this transaction if we are applying a block + optional*> allowed_read_locks; + optional*> allowed_write_locks; + + const transaction& trx() const{ + if (decompressed_trx) { + return *decompressed_trx; + } else { + return *_trx; + } + } + + static digest_type calculate_transaction_merkle_root( const vector& metas ); + private: + const transaction* _trx; }; } } // eosio::chain diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index abe2a3f4a138c270f97bfded3d0948699855b4c7..e1f40cb318079f895bd5fe35f55645a9ca42b4e5 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -120,6 +120,9 @@ namespace eosio { namespace chain { action_code_object_type, key_value_object_type, key128x128_value_object_type, + key64x64_value_object_type, + index64_object_type, + index128_object_type, action_permission_object_type, global_property_object_type, dynamic_global_property_object_type, @@ -172,6 +175,9 @@ FC_REFLECT_ENUM(eosio::chain::object_type, (action_code_object_type) (key_value_object_type) (key128x128_value_object_type) + (key64x64_value_object_type) + (index64_object_type) + (index128_object_type) (action_permission_object_type) (global_property_object_type) (dynamic_global_property_object_type) diff --git a/libraries/chain/include/eosio/chain/wasm_eosio_constraints.hpp b/libraries/chain/include/eosio/chain/wasm_eosio_constraints.hpp new file mode 100644 index 0000000000000000000000000000000000000000..323f3cd14c9bfb066db304dda414710a08cfd424 --- /dev/null +++ b/libraries/chain/include/eosio/chain/wasm_eosio_constraints.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace IR { + struct Module; +}; + +namespace eosio { namespace chain { + +//Throws if something in the module violates +void validate_eosio_wasm_constraints(const IR::Module& m); + +}} diff --git a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp index fc33455354c1136850bc6c2675f44add89ed5176..d83162dc372932046f5569fc23157000df8d41f0 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp @@ -28,8 +28,8 @@ struct wasm_cache::entry { struct wasm_context { wasm_context(wasm_cache::entry &code, apply_context& ctx) : code(code), context(ctx) { - //initialize to minimum bytes and limit this to 32 bit space - sbrk_bytes = (1 << IR::numBytesPerPageLog2) > UINT32_MAX ? UINT32_MAX : 1 << IR::numBytesPerPageLog2; + MemoryInstance* default_mem = Runtime::getDefaultMemory(code.instance); + sbrk_bytes = default_mem ? Runtime::getMemoryNumPages(default_mem) << IR::numBytesPerPageLog2 : 0; } wasm_cache::entry& code; apply_context& context; diff --git a/libraries/chain/name.cpp b/libraries/chain/name.cpp index 5428c92d027357303af60f7b9a74281649e93ef0..262e2dc221a635eb00ed49dd21cbdc91b2df6b94 100644 --- a/libraries/chain/name.cpp +++ b/libraries/chain/name.cpp @@ -2,15 +2,16 @@ #include #include #include +#include namespace eosio { namespace chain { void name::set( const char* str ) { try { const auto len = strnlen(str,14); - FC_ASSERT( len <= 13 ); + EOS_ASSERT( len <= 13, name_type_exception, "Name is longer than 13 characters (${name}) ", ("name",string(str)) ); value = string_to_name(str); - FC_ASSERT( to_string() == string(str), "name not properly normalized", ("name",string(str))("normalized",to_string()) ); + EOS_ASSERT( to_string() == string(str), name_type_exception, "Name not properly normalized (name: ${name}, normalized: ${normalized}) ", ("name",string(str))("normalized",to_string()) ); }FC_CAPTURE_AND_RETHROW( (str) ) } name::operator string()const { diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index 9e913ff16c0b80f270f1fd97d2edafbd43452173..f17a8c33bb65cc2b245cf557e77502eb50ec880c 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -7,7 +7,6 @@ namespace eosio { namespace chain { transaction_metadata::transaction_metadata( const packed_transaction& t, chain_id_type chainid, const time_point& published ) :raw_trx(t.get_raw_transaction()) ,decompressed_trx(fc::raw::unpack(*raw_trx)) - ,trx(*decompressed_trx) ,id(decompressed_trx->id()) ,bandwidth_usage( (uint32_t)fc::raw::pack_size(t) ) ,published(published) @@ -19,8 +18,9 @@ digest_type transaction_metadata::calculate_transaction_merkle_root( const vecto vector ids; ids.reserve(metas.size()); - for( const auto& t : metas ) - ids.emplace_back( t.id ); + for( const auto& t : metas ) { + ids.emplace_back(t.id); + } return merkle( std::move(ids) ); } diff --git a/libraries/chain/wasm_eosio_constraints.cpp b/libraries/chain/wasm_eosio_constraints.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5154485589c8a0d82fd2d8cd394c055296f5dcb2 --- /dev/null +++ b/libraries/chain/wasm_eosio_constraints.cpp @@ -0,0 +1,112 @@ +#include +#include +#include +#include "IR/Module.h" +#include "IR/Operators.h" + +namespace eosio { namespace chain { + +using namespace IR; + +struct nop_opcode_visitor { + typedef void Result; + + #define VISIT_OPCODE(opcode,name,nameString,Imm,...) \ + virtual void name(Imm) {} + ENUM_OPERATORS(VISIT_OPCODE) + #undef VISIT_OPCODE + + void unknown(Opcode) { + FC_THROW_EXCEPTION(wasm_execution_error, "Smart contract encountered unknown opcode"); + } +}; + +struct eosio_constraints_visitor : public nop_opcode_visitor { + ///Make this some sort of visitor enum to reduce chance of copy pasta errors (but + // the override declaration makes it somewhat safe) + + //While it's possible to access beyond 1MiB by giving an offset that's 1MiB-1 and + // an 8 byte data type, that's fine. There will be enough of a guard on the end + // of 1MiB where it's not a problem + void fail_large_offset(U32 offset) { + if(offset >= 1024*1024) + FC_THROW_EXCEPTION(wasm_execution_error, "Smart contract used an invalid large memory store/load offset"); + } + void i32_load (LoadOrStoreImm<2> imm) override { fail_large_offset(imm.offset); } + void i64_load (LoadOrStoreImm<3> imm) override { fail_large_offset(imm.offset); } + void i32_load8_s (LoadOrStoreImm<0> imm) override { fail_large_offset(imm.offset); } + void i32_load8_u (LoadOrStoreImm<0> imm) override { fail_large_offset(imm.offset); } + void i32_load16_s (LoadOrStoreImm<1> imm) override { fail_large_offset(imm.offset); } + void i32_load16_u (LoadOrStoreImm<1> imm) override { fail_large_offset(imm.offset); } + void i64_load8_s (LoadOrStoreImm<0> imm) override { fail_large_offset(imm.offset); } + void i64_load8_u (LoadOrStoreImm<0> imm) override { fail_large_offset(imm.offset); } + void i64_load16_s (LoadOrStoreImm<1> imm) override { fail_large_offset(imm.offset); } + void i64_load16_u (LoadOrStoreImm<1> imm) override { fail_large_offset(imm.offset); } + void i64_load32_s (LoadOrStoreImm<2> imm) override { fail_large_offset(imm.offset); } + void i64_load32_u (LoadOrStoreImm<2> imm) override { fail_large_offset(imm.offset); } + void i32_store (LoadOrStoreImm<2> imm) override { fail_large_offset(imm.offset); } + void i64_store (LoadOrStoreImm<3> imm) override { fail_large_offset(imm.offset); } + void i32_store8 (LoadOrStoreImm<0> imm) override { fail_large_offset(imm.offset); } + void i32_store16 (LoadOrStoreImm<1> imm) override { fail_large_offset(imm.offset); } + void i64_store8 (LoadOrStoreImm<0> imm) override { fail_large_offset(imm.offset); } + void i64_store16 (LoadOrStoreImm<1> imm) override { fail_large_offset(imm.offset); } + void i64_store32 (LoadOrStoreImm<2> imm) override { fail_large_offset(imm.offset); } + + void f32_load (LoadOrStoreImm<2> imm) override { fail_large_offset(imm.offset); } + void f64_load (LoadOrStoreImm<3> imm) override { fail_large_offset(imm.offset); } + void f32_store (LoadOrStoreImm<2> imm) override { fail_large_offset(imm.offset); } + void f64_store (LoadOrStoreImm<3> imm) override { fail_large_offset(imm.offset); } + + #define VISIT_OPCODE(opcode,name,nameString,Imm,...) \ + void name(Imm) override { FC_THROW_EXCEPTION(wasm_execution_error, "Smart contracts may not use WASM memory operators"); } + ENUM_MEMORY_OPERATORS(VISIT_OPCODE); + #undef VISIT_OPCODE + +}; + +void validate_eosio_wasm_constraints(const Module& m) { + if(m.memories.defs.size() && m.memories.defs[0].type.size.min > 16) + FC_THROW_EXCEPTION(wasm_execution_error, "Smart contract initial memory size must be less than or equal to 1MiB"); + + for(const DataSegment& ds : m.dataSegments) { + if(ds.baseOffset.type != InitializerExpression::Type::i32_const) + FC_THROW_EXCEPTION(wasm_execution_error, "Smart contract has unexpected memory base offset type"); + if(static_cast(ds.baseOffset.i32) + ds.data.size() > 64*1024) + FC_THROW_EXCEPTION(wasm_execution_error, "Smart contract data segments must lie in first 64KiB"); + } + + if(m.tables.defs.size() && m.tables.defs[0].type.size.min > 1024) + FC_THROW_EXCEPTION(wasm_execution_error, "Smart contract table limited to 1024 elements"); + + unsigned mutable_globals_total_size = 0; + for(const GlobalDef& global_def : m.globals.defs) { + if(!global_def.type.isMutable) + continue; + switch(global_def.type.valueType) { + case ValueType::any: + case ValueType::num: + FC_THROW_EXCEPTION(wasm_execution_error, "Smart contract has unexpected global definition value type"); + case ValueType::i64: + case ValueType::f64: + mutable_globals_total_size += 4; + case ValueType::i32: + case ValueType::f32: + mutable_globals_total_size += 4; + } + } + if(mutable_globals_total_size > 1024) + FC_THROW_EXCEPTION(wasm_execution_error, "Smart contract has more than 1KiB of mutable globals"); + + //Some of the OperatorDecoderStream users inside of WAVM track the control stack and quit parsing from + // OperatorDecoderStream when the control stack is empty (since that would indicate unreachable code). + // Not doing that here, yet, since it's not clear it's required for the purpose of the validation + eosio_constraints_visitor visitor; + for(const FunctionDef& fd : m.functions.defs) { + OperatorDecoderStream decoder(fd.code); + while(decoder) { + decoder.decodeOp(visitor); + } + } +} + +}} \ No newline at end of file diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 5c30ff7ad648c8e2cd54a120e763cdc735f63a24..c311924440a7f81447ab80e81a6d137f031a5cfc 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -7,8 +7,11 @@ #include #include #include +#include #include #include +#include +#include #include #include @@ -221,7 +224,8 @@ namespace eosio { namespace chain { try { Serialization::MemoryInputStream stream((const U8 *) wasm_binary, wasm_binary_size); #warning TODO: restore checktime injection? - WASM::serialize(stream, *module); + WASM::serializeWithInjection(stream, *module); + validate_eosio_wasm_constraints(*module); root_resolver resolver; LinkResult link_result = linkModule(*module, resolver); @@ -370,6 +374,7 @@ namespace eosio { namespace chain { FC_ASSERT( getFunctionType(call)->parameters.size() == args.size() ); auto context_guard = scoped_context(current_context, code, context); + context.checktime_start(); runInstanceStartFunc(code.instance); Runtime::invokeFunction(call,args); } catch( const Runtime::Exception& e ) { @@ -419,6 +424,7 @@ class context_aware_api { uint32_t& sbrk_bytes; }; +/* class chain_api : public context_aware_api { public: using context_aware_api::context_aware_api; @@ -430,19 +436,176 @@ class chain_api : public context_aware_api { return active_prods.size() * sizeof(chain::account_name); } }; +*/ + +class privileged_api : public context_aware_api { + public: + privileged_api( wasm_interface& wasm ) + :context_aware_api(wasm) + { + FC_ASSERT( context.privileged, "${code} does not have permission to call this API", ("code",context.receiver) ); + } + + /** + * This should schedule the feature to be activated once the + * block that includes this call is irreversible. It should + * fail if the feature is already pending. + * + * Feature name should be base32 encoded name. + */ + void activate_feature( int64_t feature_name ) { + FC_ASSERT( !"Unsupported Harfork Detected" ); + } + + /** + * This should return true if a feature is active and irreversible, false if not. + * + * Irreversiblity by fork-database is not consensus safe, therefore, this defines + * irreversiblity only by block headers not by BFT short-cut. + */ + int is_feature_active( int64_t feature_name ) { + return false; + } + + void set_resource_limits( account_name account, + int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight, + int64_t cpu_usec_per_period ) { + auto& buo = context.db.get( account ); + FC_ASSERT( buo.db_usage <= ram_bytes, "attempt to free to much space" ); + + auto& gdp = context.controller.get_dynamic_global_properties(); + context.mutable_db.modify( gdp, [&]( auto& p ) { + p.total_net_weight -= buo.net_weight; + p.total_net_weight += net_weight; + p.total_cpu_weight -= buo.cpu_weight; + p.total_cpu_weight += cpu_weight; + p.total_db_reserved -= buo.db_reserved_capacity; + p.total_db_reserved += ram_bytes; + }); + + context.mutable_db.modify( buo, [&]( auto& o ){ + o.net_weight = net_weight; + o.cpu_weight = cpu_weight; + o.db_reserved_capacity = ram_bytes; + }); + } + + + void get_resource_limits( account_name account, + uint64_t& ram_bytes, uint64_t& net_weight, uint64_t cpu_weight ) { + } + + void set_active_producers( array_ptr packed_producer_schedule, size_t datalen) { + datastream ds( packed_producer_schedule, datalen ); + producer_schedule_type psch; + fc::raw::unpack(ds, psch); + + context.mutable_db.modify( context.controller.get_global_properties(), + [&]( auto& gprops ) { + gprops.new_active_producers = psch; + }); + } + + bool is_privileged( account_name n )const { + return context.db.get( n ).privileged; + } + bool is_frozen( account_name n )const { + return context.db.get( n ).frozen; + } + void set_privileged( account_name n, bool is_priv ) { + const auto& a = context.db.get( n ); + context.mutable_db.modify( a, [&]( auto& ma ){ + ma.privileged = is_priv; + }); + } + + void freeze_account( account_name n , bool should_freeze ) { + const auto& a = context.db.get( n ); + context.mutable_db.modify( a, [&]( auto& ma ){ + ma.frozen = should_freeze; + }); + } + + /// TODO: add inline/deferred with support for arbitrary permissions rather than code/current auth +}; + +class checktime_api : public context_aware_api { +public: + using context_aware_api::context_aware_api; + + void checktime() { + context.checktime(); + } +}; + +class producer_api : public context_aware_api { + public: + using context_aware_api::context_aware_api; + + int get_active_producers(array_ptr producers, size_t datalen) { + auto active_producers = context.get_active_producers(); + size_t len = active_producers.size() * sizeof(chain::account_name); + size_t cpy_len = std::min(datalen, len); + memcpy(producers, active_producers.data(), cpy_len); + return len; + } +}; class crypto_api : public context_aware_api { public: using context_aware_api::context_aware_api; + /** + * This method can be optimized out during replay as it has + * no possible side effects other than "passing". + */ + void assert_recover_key( fc::sha256& digest, + array_ptr sig, size_t siglen, + array_ptr pub, size_t publen ) { + fc::crypto::signature s; + fc::crypto::public_key p; + datastream ds( sig, siglen ); + datastream pubds( pub, publen ); + + fc::raw::unpack(ds, s); + fc::raw::unpack(ds, p); + + auto check = fc::crypto::public_key( s, digest, false ); + FC_ASSERT( check == p, "Error expected key different than recovered key" ); + } + + int recover_key( fc::sha256& digest, + array_ptr sig, size_t siglen, + array_ptr pub, size_t publen ) { + fc::crypto::signature s; + datastream ds( sig, siglen ); + datastream pubds( pub, publen ); + + fc::raw::unpack(ds, s); + fc::raw::pack( pubds, fc::crypto::public_key( s, digest, false ) ); + return pubds.tellp(); + } + void assert_sha256(array_ptr data, size_t datalen, const fc::sha256& hash_val) { auto result = fc::sha256::hash( data, datalen ); FC_ASSERT( result == hash_val, "hash miss match" ); } + void sha1(array_ptr data, size_t datalen, fc::sha1& hash_val) { + hash_val = fc::sha1::hash( data, datalen ); + } + void sha256(array_ptr data, size_t datalen, fc::sha256& hash_val) { hash_val = fc::sha256::hash( data, datalen ); } + + void sha512(array_ptr data, size_t datalen, fc::sha512& hash_val) { + hash_val = fc::sha512::hash( data, datalen ); + } + + void ripemd160(array_ptr data, size_t datalen, fc::ripemd160& hash_val) { + hash_val = fc::ripemd160::hash( data, datalen ); + } }; class string_api : public context_aware_api { @@ -537,39 +700,90 @@ class console_api : public context_aware_api { } }; +class database_api : public context_aware_api { + public: + using context_aware_api::context_aware_api; + + int db_store_i64( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, array_ptr buffer, size_t buffer_size ) { + return context.db_store_i64( scope, table, payer, id, buffer, buffer_size ); + } + void db_update_i64( int itr, uint64_t payer, array_ptr buffer, size_t buffer_size ) { + context.db_update_i64( itr, payer, buffer, buffer_size ); + } + void db_remove_i64( int itr ) { + context.db_remove_i64( itr ); + } + int db_get_i64( int itr, uint64_t& id, array_ptr buffer, size_t buffer_size ) { + return context.db_get_i64( itr, id, buffer, buffer_size ); + } + int db_next_i64( int itr ) { return context.db_next_i64(itr); } + int db_find_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { + return context.db_find_i64( code, scope, table, id ); + } + int db_lowerbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { + return context.db_lowerbound_i64( code, scope, table, id ); + } + int db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { + return context.db_lowerbound_i64( code, scope, table, id ); + } + + int db_idx64_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const uint64_t& secondary ) { + return context.idx64.store( scope, table, payer, id, secondary ); + } + void db_idx64_update( int iterator, uint64_t payer, const uint64_t& secondary ) { + return context.idx64.update( iterator, payer, secondary ); + } + void db_idx64_remove( int iterator ) { + return context.idx64.remove( iterator ); + } + + + int db_idx128_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const uint128_t& secondary ) { + return context.idx128.store( scope, table, payer, id, secondary ); + } + void db_idx128_update( int iterator, uint64_t payer, const uint128_t& secondary ) { + return context.idx128.update( iterator, payer, secondary ); + } + void db_idx128_remove( int iterator ) { + return context.idx128.remove( iterator ); + } +}; + + + template class db_api : public context_aware_api { using KeyType = typename ObjectType::key_type; static constexpr int KeyCount = ObjectType::number_of_keys; using KeyArrayType = KeyType[KeyCount]; - using ContextMethodType = int(apply_context::*)(const table_id_object&, const KeyType*, const char*, size_t); + using ContextMethodType = int(apply_context::*)(const table_id_object&, const account_name&, const KeyType*, const char*, size_t); private: - int call(ContextMethodType method, const scope_name& scope, const name& table, array_ptr data, size_t data_len) { - const auto& t_id = context.find_or_create_table(scope, context.receiver, table); + int call(ContextMethodType method, const scope_name& scope, const name& table, account_name bta, array_ptr data, size_t data_len) { + const auto& t_id = context.find_or_create_table(context.receiver, scope, table); FC_ASSERT(data_len >= KeyCount * sizeof(KeyType), "Data is not long enough to contain keys"); const KeyType* keys = reinterpret_cast((const char *)data); const char* record_data = ((const char*)data) + sizeof(KeyArrayType); size_t record_len = data_len - sizeof(KeyArrayType); - return (context.*(method))(t_id, keys, record_data, record_len); + return (context.*(method))(t_id, bta, keys, record_data, record_len) + sizeof(KeyArrayType); } public: using context_aware_api::context_aware_api; - int store(const scope_name& scope, const name& table, array_ptr data, size_t data_len) { - auto res = call(&apply_context::store_record, scope, table, data, data_len); + int store(const scope_name& scope, const name& table, const account_name& bta, array_ptr data, size_t data_len) { + auto res = call(&apply_context::store_record, scope, table, bta, data, data_len); + //ilog("STORE [${scope},${code},${table}] => ${res} :: ${HEX}", ("scope",scope)("code",context.receiver)("table",table)("res",res)("HEX", fc::to_hex(data, data_len))); return res; - } - int update(const scope_name& scope, const name& table, array_ptr data, size_t data_len) { - return call(&apply_context::update_record, scope, table, data, data_len); + int update(const scope_name& scope, const name& table, const account_name& bta, array_ptr data, size_t data_len) { + return call(&apply_context::update_record, scope, table, bta, data, data_len); } int remove(const scope_name& scope, const name& table, const KeyArrayType &keys) { - const auto& t_id = context.find_or_create_table(scope, context.receiver, table); + const auto& t_id = context.find_or_create_table(context.receiver, scope, table); return context.remove_record(t_id, keys); } }; @@ -623,8 +837,8 @@ class db_index_api : public context_aware_api { using ContextMethodType = int(apply_context::*)(const table_id_object&, KeyType*, char*, size_t); - int call(ContextMethodType method, const scope_name& scope, const account_name& code, const name& table, array_ptr data, size_t data_len) { - auto maybe_t_id = context.find_table(scope, context.receiver, table); + int call(ContextMethodType method, const account_name& code, const scope_name& scope, const name& table, array_ptr data, size_t data_len) { + auto maybe_t_id = context.find_table(code, scope, table); if (maybe_t_id == nullptr) { return 0; } @@ -646,6 +860,7 @@ class db_index_api : public context_aware_api { public: using context_aware_api::context_aware_api; +<<<<<<< HEAD int load(const scope_name& scope, const account_name& code, const name& table, array_ptr data, size_t data_len) { auto res = call(&apply_context::load_record, scope, code, table, data, data_len); return res; @@ -739,7 +954,6 @@ class db_index_api : public context_aware_ int upper_bound_str(const scope_name& scope, const account_name& code, const name& table, array_ptr key, size_t key_len, array_ptr data, size_t data_len) { return call(&apply_context::upper_bound_record, scope, code, table, key, key_len, data, data_len); } - }; class memory_api : public context_aware_api { @@ -813,14 +1027,14 @@ class transaction_api : public context_aware_api { } int expiration() { - return context.trx_meta.trx.expiration.sec_since_epoch(); + return context.trx_meta.trx().expiration.sec_since_epoch(); } int tapos_block_num() { - return context.trx_meta.trx.ref_block_num; + return context.trx_meta.trx().ref_block_num; } int tapos_block_prefix() { - return context.trx_meta.trx.ref_block_prefix; + return context.trx_meta.trx().ref_block_prefix; } void send_inline( array_ptr data, size_t data_len ) { @@ -1061,11 +1275,11 @@ REGISTER_INTRINSICS(math_api, (double_to_i64, int64_t(int64_t) ) (i64_to_double, int64_t(int64_t) ) ); - +/* REGISTER_INTRINSICS(chain_api, (get_active_producers, int(int, int) ) ); - +*/ REGISTER_INTRINSICS(compiler_builtins, (__break_point, void() ) (__ashlti3, void(int, int64_t, int64_t, int) ) @@ -1077,6 +1291,54 @@ REGISTER_INTRINSICS(compiler_builtins, (__modti3, void(int, int64_t, int64_t, int64_t, int64_t) ) (__umodti3, void(int, int64_t, int64_t, int64_t, int64_t) ) (__multi3, void(int, int64_t, int64_t, int64_t, int64_t) ) + +REGISTER_INTRINSICS(privileged_api, + (activate_feature, void(int64_t)) + (is_feature_active, int(int64_t)) + (set_resource_limits, void(int64_t,int64_t,int64_t,int64_t,int64_t)) + (set_active_producers, void(int,int)) + (is_privileged, int(int64_t)) + (set_privileged, void(int64_t, int)) + (freeze_account, void(int64_t, int)) + (is_frozen, int(int64_t)) +); + +REGISTER_INTRINSICS(checktime_api, + (checktime, void()) +); + +REGISTER_INTRINSICS(producer_api, + (get_active_producers, int(int, int)) +); + +REGISTER_INTRINSICS( database_api, + (db_store_i64, int(int64_t,int64_t,int64_t,int64_t,int,int)) + (db_update_i64, void(int,int64_t,int,int)) + (db_remove_i64, void(int)) + (db_get_i64, int(int, int, int, int)) + (db_next_i64, int(int)) + (db_find_i64, int(int64_t,int64_t,int64_t,int64_t)) + (db_lowerbound_i64, int(int64_t,int64_t,int64_t,int64_t)) + + (db_idx64_store, int(int64_t,int64_t,int64_t,int64_t,int)) + (db_idx64_remove, void(int)) + (db_idx64_update, void(int,int64_t,int)) + + + (db_idx128_store, int(int64_t,int64_t,int64_t,int64_t,int)) + (db_idx128_remove, void(int)) + (db_idx128_update, void(int,int64_t,int)) +) + +REGISTER_INTRINSICS(crypto_api, + (assert_recover_key, void(int, int, int, int, int)) + (recover_key, int(int, int, int, int, int)) + (assert_sha256, void(int, int, int)) + (sha1, void(int, int, int)) + (sha256, void(int, int, int)) + (sha512, void(int, int, int)) + (ripemd160, void(int, int, int)) +>>>>>>> master ); REGISTER_INTRINSICS(string_api, @@ -1144,15 +1406,14 @@ REGISTER_INTRINSICS(memory_api, #define DB_METHOD_SEQ(SUFFIX) \ - (store, int32_t(int64_t, int64_t, int, int), "store_"#SUFFIX )\ - (update, int32_t(int64_t, int64_t, int, int), "update_"#SUFFIX )\ + (store, int32_t(int64_t, int64_t, int64_t, int, int), "store_"#SUFFIX ) \ + (update, int32_t(int64_t, int64_t, int64_t, int, int), "update_"#SUFFIX ) \ (remove, int32_t(int64_t, int64_t, int), "remove_"#SUFFIX ) #define DB_INDEX_METHOD_SEQ(SUFFIX)\ (load, int32_t(int64_t, int64_t, int64_t, int, int), "load_"#SUFFIX )\ (front, int32_t(int64_t, int64_t, int64_t, int, int), "front_"#SUFFIX )\ (back, int32_t(int64_t, int64_t, int64_t, int, int), "back_"#SUFFIX )\ - (next, int32_t(int64_t, int64_t, int64_t, int, int), "next_"#SUFFIX )\ (previous, int32_t(int64_t, int64_t, int64_t, int, int), "previous_"#SUFFIX )\ (lower_bound, int32_t(int64_t, int64_t, int64_t, int, int), "lower_bound_"#SUFFIX )\ (upper_bound, int32_t(int64_t, int64_t, int64_t, int, int), "upper_bound_"#SUFFIX )\ @@ -1160,17 +1421,21 @@ REGISTER_INTRINSICS(memory_api, using db_api_key_value_object = db_api; using db_api_keystr_value_object = db_api; using db_api_key128x128_value_object = db_api; +using db_api_key64x64_value_object = db_api; using db_api_key64x64x64_value_object = db_api; using db_index_api_key_value_index_by_scope_primary = db_index_api; using db_index_api_keystr_value_index_by_scope_primary = db_index_api; using db_index_api_key128x128_value_index_by_scope_primary = db_index_api; using db_index_api_key128x128_value_index_by_scope_secondary = db_index_api; +using db_index_api_key64x64_value_index_by_scope_primary = db_index_api; +using db_index_api_key64x64_value_index_by_scope_secondary = db_index_api; using db_index_api_key64x64x64_value_index_by_scope_primary = db_index_api; using db_index_api_key64x64x64_value_index_by_scope_secondary = db_index_api; using db_index_api_key64x64x64_value_index_by_scope_tertiary = db_index_api; REGISTER_INTRINSICS(db_api_key_value_object, DB_METHOD_SEQ(i64)); REGISTER_INTRINSICS(db_api_key128x128_value_object, DB_METHOD_SEQ(i128i128)); +REGISTER_INTRINSICS(db_api_key64x64_value_object, DB_METHOD_SEQ(i64i64)); REGISTER_INTRINSICS(db_api_key64x64x64_value_object, DB_METHOD_SEQ(i64i64i64)); REGISTER_INTRINSICS(db_api_keystr_value_object, (store_str, int32_t(int64_t, int64_t, int, int, int, int) ) @@ -1188,6 +1453,8 @@ REGISTER_INTRINSICS(db_index_api_keystr_value_index_by_scope_primary, (upper_bound_str, int32_t(int64_t, int64_t, int64_t, int, int, int, int) )); REGISTER_INTRINSICS(db_index_api_key128x128_value_index_by_scope_primary, DB_INDEX_METHOD_SEQ(primary_i128i128)); REGISTER_INTRINSICS(db_index_api_key128x128_value_index_by_scope_secondary, DB_INDEX_METHOD_SEQ(secondary_i128i128)); +REGISTER_INTRINSICS(db_index_api_key64x64_value_index_by_scope_primary, DB_INDEX_METHOD_SEQ(primary_i64i64)); +REGISTER_INTRINSICS(db_index_api_key64x64_value_index_by_scope_secondary, DB_INDEX_METHOD_SEQ(secondary_i64i64)); REGISTER_INTRINSICS(db_index_api_key64x64x64_value_index_by_scope_primary, DB_INDEX_METHOD_SEQ(primary_i64i64i64)); REGISTER_INTRINSICS(db_index_api_key64x64x64_value_index_by_scope_secondary, DB_INDEX_METHOD_SEQ(secondary_i64i64i64)); REGISTER_INTRINSICS(db_index_api_key64x64x64_value_index_by_scope_tertiary, DB_INDEX_METHOD_SEQ(tertiary_i64i64i64)); diff --git a/libraries/fc/include/fc/exception/exception.hpp b/libraries/fc/include/fc/exception/exception.hpp index 47b30712cbe4fc7ff7cf2829db75e4992a161b14..cab8dc70e1a0e00ad2e6ae2ec49cc2fbfe9de07d 100644 --- a/libraries/fc/include/fc/exception/exception.hpp +++ b/libraries/fc/include/fc/exception/exception.hpp @@ -102,6 +102,11 @@ namespace fc */ std::string to_string( log_level ll = log_level::info )const; + /** + * Generates a user-friendly error report. + */ + std::string top_message( )const; + /** * Throw this exception as its most derived type. * diff --git a/libraries/fc/src/exception.cpp b/libraries/fc/src/exception.cpp index 56e2162d43ecaf38bc355255732b7bf5dde37cf5..17cb19da65c784179465fce491f1684731591592 100644 --- a/libraries/fc/src/exception.cpp +++ b/libraries/fc/src/exception.cpp @@ -185,6 +185,21 @@ namespace fc return ss.str(); } + /** + * Generates a user-friendly error report. + */ + string exception::top_message( )const + { + for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ++itr ) + { + auto s = fc::format_string( itr->get_format(), itr->get_data() ); + if (!s.empty()) { + return s; + } + } + return string(); + } + void NO_RETURN exception_factory::rethrow( const exception& e )const { auto itr = _registered_exceptions.find( e.code() ); diff --git a/libraries/testing/CMakeLists.txt b/libraries/testing/CMakeLists.txt index 667f129614f2929b83c3b29086e0b8b842cc1871..2c248c47ddb5483d861cdb96af9be7af9446fd69 100644 --- a/libraries/testing/CMakeLists.txt +++ b/libraries/testing/CMakeLists.txt @@ -1,4 +1,4 @@ -file(GLOB HEADERS "include/eosio/tester/*.hpp") +file(GLOB HEADERS "include/eosio/testing/*.hpp") ## SORT .cpp by most likely to change / break compile add_library( eosio_testing diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 450cdc4c66c58ced512f8ab5291c683f578a98f5..e28af55419785511501b6f72e4533f8bf53c1eb5 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace eosio { namespace testing { @@ -14,16 +15,20 @@ namespace eosio { namespace testing { */ class tester { public: - tester(); + typedef string action_result; + + tester(bool process_genesis = true); void close(); void open(); + void create_init_accounts(); signed_block produce_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms) ); void produce_blocks( uint32_t n = 1 ); transaction_trace push_transaction( packed_transaction& trx ); transaction_trace push_transaction( signed_transaction& trx ); + action_result push_action(action&& cert_act, uint64_t authorizer); void set_tapos( signed_transaction& trx ) const; void create_accounts( vector names, asset init_bal, bool multisig = false ) { @@ -37,8 +42,9 @@ namespace eosio { namespace testing { void create_account( account_name name, asset initial_balance = asset(), account_name creator = N(inita), bool multisig = false ); void create_account( account_name name, string balance = "0.0000 EOS", account_name creator = N(inita), bool multisig = false ); - transaction_trace transfer( account_name from, account_name to, asset amount, string memo = "" ); - transaction_trace transfer( account_name from, account_name to, string amount, string memo = "" ); + transaction_trace push_nonce( account_name from, const string& role, const string& v = "blah" ); + transaction_trace transfer( account_name from, account_name to, asset amount, string memo = "", account_name currency = config::eosio_system_account_name ); + transaction_trace transfer( account_name from, account_name to, string amount, string memo = "", account_name currency = config::eosio_system_account_name ); template const auto& get( Args&&... args ) { @@ -63,6 +69,18 @@ namespace eosio { namespace testing { const symbol& asset_symbol, const account_name& account ) const; + static vector to_uint8_vector(const string& s); + + static vector to_uint8_vector(uint64_t x); + + static uint64_t to_uint64(fc::variant x); + + static string to_string(fc::variant x); + + static action_result success() { return string(); } + + static action_result error(const string& msg) { return msg; } + private: fc::temp_directory tempdir; chain_controller::controller_config cfg; @@ -86,4 +104,5 @@ namespace eosio { namespace testing { string expected; }; + } } /// eosio::testing diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index 9a95a978ca42594ec81815d71c51453e7e4fc62b..d4cabf8689f58219bcf0237ed8a514a0ff5fb10a 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -1,8 +1,12 @@ +#include #include #include #include #include #include +#include + +#include #include #include @@ -14,32 +18,59 @@ namespace eosio { namespace testing { - tester::tester() { + tester::tester(bool process_genesis) { cfg.block_log_dir = tempdir.path() / "blocklog"; cfg.shared_memory_dir = tempdir.path() / "shared"; cfg.shared_memory_size = 1024*1024*8; cfg.genesis.initial_timestamp = fc::time_point::from_iso_string("2020-01-01T00:00:00.000"); - cfg.genesis.initial_accounts.resize( config::producer_count ); - cfg.genesis.initial_producers.resize( config::producer_count ); - - - // uint64_t init_name = N(inita); - string init_name = "inita"; - for( uint32_t i = 0; i < config::producer_count; ++i ) { - auto pubkey = get_public_key(init_name); - cfg.genesis.initial_accounts[i].name = string(account_name(init_name)); - cfg.genesis.initial_accounts[i].owner_key = get_public_key(init_name,"owner"); - cfg.genesis.initial_accounts[i].active_key = get_public_key(init_name,"active"); - cfg.genesis.initial_accounts[i].liquid_balance = asset::from_string( "1000000.0000 EOS" ); - cfg.genesis.initial_accounts[i].staking_balance = asset::from_string( "1000000.0000 EOS" ); - cfg.genesis.initial_producers[i].owner_name = string(account_name(init_name)); - cfg.genesis.initial_producers[i].block_signing_key = get_public_key( init_name, "producer" ); - - init_name[4]++; - } + cfg.genesis.initial_key = get_public_key( config::system_account_name, "active" ); + cfg.genesis.eosio_system_key = get_public_key( config::eosio_system_account_name, "active"); open(); + if (process_genesis) + create_init_accounts(); + } + + void tester::create_init_accounts() { + + contracts::abi_def eosio_system_abi_def = fc::json::from_string(eosio_system_abi).as(); + chain::contracts::abi_serializer eosio_system_serializer(eosio_system_abi_def); + + signed_transaction trx; + set_tapos(trx); + + action act; + act.account = config::eosio_system_account_name; + act.name = N(issue); + act.authorization = vector{{config::eosio_system_account_name,config::active_name}}; + act.data = eosio_system_serializer.variant_to_binary("issue", fc::json::from_string("{\"to\":\"eosio.system\",\"quantity\":\"1000000000.0000 EOS\"}")); + trx.actions.push_back(act); + set_tapos(trx); + trx.sign( get_private_key( config::eosio_system_account_name, "active" ), chain_id_type() ); + push_transaction(trx); + + create_account(N(inita), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initb), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initc), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initd), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(inite), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initf), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initg), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(inith), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initi), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initj), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initk), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initl), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initm), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initn), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(inito), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initp), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initq), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initr), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(inits), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initt), "1000000.0000 EOS", config::eosio_system_account_name); + create_account(N(initu), "1000000.0000 EOS", config::eosio_system_account_name); } public_key_type tester::get_public_key( name keyname, string role ) const { @@ -75,7 +106,7 @@ namespace eosio { namespace testing { auto next_time = head_time + skip_time; uint32_t slot = control->get_slot_at_time( next_time ); auto sch_pro = control->get_scheduled_producer(slot); - auto priv_key = get_private_key( sch_pro, "producer" ); + auto priv_key = get_private_key( sch_pro, "active" ); return control->generate_block( next_time, sch_pro, priv_key, skip_missed_block_penalty ); } @@ -110,12 +141,12 @@ namespace eosio { namespace testing { .owner = owner_auth, .active = authority( get_public_key( a, "active" ) ), .recovery = authority( get_public_key( a, "recovery" ) ), - .deposit = initial_balance }); set_tapos(trx); trx.sign( get_private_key( creator, "active" ), chain_id_type() ); push_transaction( trx ); + transfer(creator, a, initial_balance); } transaction_trace tester::push_transaction( packed_transaction& trx ) { @@ -127,26 +158,101 @@ namespace eosio { namespace testing { return push_transaction( ptrx ); } + tester::action_result tester::push_action(action&& cert_act, uint64_t authorizer) { + signed_transaction trx; + if (authorizer) { + cert_act.authorization = vector{{authorizer, config::active_name}}; + } + trx.actions.emplace_back(std::move(cert_act)); + set_tapos(trx); + if (authorizer) { + trx.sign(get_private_key(authorizer, "active"), chain_id_type()); + } + try { + push_transaction(trx); + } catch (const fc::exception& ex) { + return error(ex.top_message()); + } + produce_block(); + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); + return success(); + } + void tester::create_account( account_name a, string initial_balance, account_name creator, bool multisig ) { create_account( a, asset::from_string(initial_balance), creator, multisig ); } - - transaction_trace tester::transfer( account_name from, account_name to, string amount, string memo ) { + auto resolver = []( tester& t, const account_name& name ) -> optional { + try { + const auto& accnt = t.control->get_database().get(name); + contracts::abi_def abi; + if (contracts::abi_serializer::to_abi(accnt.abi, abi)) { + return contracts::abi_serializer(abi); + } + return optional(); + } FC_RETHROW_EXCEPTIONS(error, "Failed to find or parse ABI for ${name}", ("name", name)) + }; + + transaction_trace tester::push_nonce(account_name from, const string& role, const string& v) { + variant pretty_trx = fc::mutable_variant_object() + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", name(config::eosio_system_account_name)) + ("name", "nonce") + ("authorization", fc::variants({ + fc::mutable_variant_object() + ("actor", from) + ("permission", name(config::owner_name)) + })) + ("data", fc::mutable_variant_object() + ("value", v) + ) + }) + ); + + signed_transaction trx; + auto resolve = [this](const account_name& name) -> optional { + return resolver(*this, name); + }; + contracts::abi_serializer::from_variant(pretty_trx, trx, resolve); + set_tapos( trx ); + + trx.sign( get_private_key( from, role ), chain_id_type() ); + return push_transaction( trx ); + } + + transaction_trace tester::transfer( account_name from, account_name to, string amount, string memo, account_name currency ) { return transfer( from, to, asset::from_string(amount), memo ); } - transaction_trace tester::transfer( account_name from, account_name to, asset amount, string memo ) { + + transaction_trace tester::transfer( account_name from, account_name to, asset amount, string memo, account_name currency ) { + variant pretty_trx = fc::mutable_variant_object() + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", currency) + ("name", "transfer") + ("authorization", fc::variants({ + fc::mutable_variant_object() + ("actor", from) + ("permission", name(config::active_name)) + })) + ("data", fc::mutable_variant_object() + ("from", from) + ("to", to) + ("quantity", amount) + ("memo", memo) + ) + }) + ); + signed_transaction trx; - trx.actions.emplace_back( vector{{from,config::active_name}}, - contracts::transfer{ - .from = from, - .to = to, - .amount = amount.amount, - .memo = memo - } ); + auto resolve = [this](const account_name& name) -> optional { + return resolver(*this, name); + }; + contracts::abi_serializer::from_variant(pretty_trx, trx, resolve); + set_tapos( trx ); - set_tapos(trx); - trx.sign( get_private_key( from, "active" ), chain_id_type() ); + trx.sign( get_private_key( from, name(config::active_name).to_string() ), chain_id_type() ); return push_transaction( trx ); } @@ -250,10 +356,8 @@ namespace eosio { namespace testing { } share_type tester::get_balance( const account_name& account ) const { - const auto& db = control->get_database(); - return contracts::get_eosio_balance(db, account); + return get_currency_balance( config::eosio_system_account_name, EOS_SYMBOL, account ).amount; } - /** * Reads balance as stored by generic_currency contract */ @@ -261,7 +365,7 @@ namespace eosio { namespace testing { const symbol& asset_symbol, const account_name& account ) const { const auto& db = control->get_database(); - const auto* tbl = db.find(boost::make_tuple(account, code, N(account))); + const auto* tbl = db.find(boost::make_tuple(code, account, N(account))); share_type result = 0; // the balance is implied to be 0 if either the table or row does not exist @@ -275,5 +379,31 @@ namespace eosio { namespace testing { return asset(result, asset_symbol); } + vector tester::to_uint8_vector(const string& s) { + vector v(s.size()); + copy(s.begin(), s.end(), v.begin()); + return v; + }; + + vector tester::to_uint8_vector(uint64_t x) { + vector v(sizeof(x)); + *reinterpret_cast(v.data()) = x; + return v; + }; + + uint64_t tester::to_uint64(fc::variant x) { + vector blob; + fc::from_variant(x, blob); + FC_ASSERT(8 == blob.size()); + return *reinterpret_cast(blob.data()); + } + + string tester::to_string(fc::variant x) { + vector v; + fc::from_variant(x, v); + string s(v.size(), 0); + copy(v.begin(), v.end(), s.begin()); + return s; + } } } /// eosio::test diff --git a/libraries/utilities/include/eosio/utilities/exception_macros.hpp b/libraries/utilities/include/eosio/utilities/exception_macros.hpp index 5bd3f59a4f236c4d3ef7b65f097051fa26f46c75..1382bfe4505560e065e7b3aca3a18e96fcca4adc 100644 --- a/libraries/utilities/include/eosio/utilities/exception_macros.hpp +++ b/libraries/utilities/include/eosio/utilities/exception_macros.hpp @@ -8,6 +8,15 @@ FC_THROW_EXCEPTION( exc_type, FORMAT, __VA_ARGS__ ); \ FC_MULTILINE_MACRO_END +#define EOS_CAPTURE_AND_RETHROW(exc_type, FORMAT, ... ) \ + catch (fc::exception& e) { \ + exc_type new_exception(FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ )); \ + for (const auto& log: e.get_log()) { \ + new_exception.append_log(log); \ + } \ + throw new_exception; \ + } + #define EOS_DECLARE_OP_BASE_EXCEPTIONS( op_name ) \ FC_DECLARE_DERIVED_EXCEPTION( \ diff --git a/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp b/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp index d4195127d263ae7bc954d43639892cee721e78b3..8e2b5199bbfc82d43e4945ad049806b1c33b753f 100644 --- a/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp +++ b/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp @@ -186,8 +186,10 @@ public: {} - void addCall(const Module& module, Serialization::OutputStream& inByteStream) + void addCall(Module& module, Serialization::OutputStream& inByteStream) { + // make sure the import is added + addImport(module); OpcodeAndImm* encodedOperator = (OpcodeAndImm*)inByteStream.advance(sizeof(OpcodeAndImm)); encodedOperator->opcode = Opcode::call; // checktime will be the last defined import @@ -217,11 +219,17 @@ public: void addImport(Module& module) { - const U32 functionTypeIndex = typeSlot; - module.functions.imports.push_back({{functionTypeIndex},std::move(u8"env"),std::move(u8"checktime")}); + if (module.functions.imports.size() == 0 || module.functions.imports.back().exportName.compare(u8"checktime") != 0) { + if (typeSlot < 0) { + addTypeSlot(module); + } + + const U32 functionTypeIndex = typeSlot; + module.functions.imports.push_back({{functionTypeIndex}, std::move(u8"env"), std::move(u8"checktime")}); + } } - void conditionallyAddCall(Opcode opcode, const ControlStructureImm& imm, const Module& module, Serialization::OutputStream& inByteStream) + void conditionallyAddCall(Opcode opcode, const ControlStructureImm& imm, Module& module, Serialization::OutputStream& inByteStream) { switch(opcode) { @@ -234,8 +242,14 @@ public: } template - void conditionallyAddCall(Opcode , const Imm& , const Module& , Serialization::OutputStream& ) + void conditionallyAddCall(Opcode , const Imm& , Module& , Serialization::OutputStream& ) + { + } + + void adjustIfFunctionIndex(Uptr& index, ObjectKind kind) { + if (kind == ObjectKind::function) + ++index; } void adjustExportIndex(Module& module) @@ -243,8 +257,7 @@ public: // all function exports need to have their index increased to account for inserted definition for (auto& exportDef : module.exports) { - if (exportDef.kind == ObjectKind::function) - ++exportDef.index; + adjustIfFunctionIndex(exportDef.index, exportDef.kind); } } @@ -265,12 +278,13 @@ private: struct NoOpInjection { - void addCall(const Module& , Serialization::OutputStream& ) {} + void addCall(Module& , Serialization::OutputStream& ) {} void setTypeSlot(const Module& , ResultType , const std::vector& ) {} void addTypeSlot(Module& ) {} void addImport(Module& ) {} template - void conditionallyAddCall(Opcode , const Imm& , const Module& , Serialization::OutputStream& ) {} + void conditionallyAddCall(Opcode , const Imm& , Module& , Serialization::OutputStream& ) {} + void adjustIfFunctionIndex(Uptr& , ObjectKind ) {} void adjustExportIndex(Module& ) {} template void adjustCallIndex(const Module& , Imm& ) {} @@ -614,13 +628,6 @@ namespace WASM Opcode opcode; serialize(bodyStream,opcode); - ////disallow memory operations - #define VISIT_OPCODE(_,name,...) \ - if(opcode == Opcode::name) \ - throw FatalSerializationException("memory instructions not allowed"); - ENUM_MEMORY_OPERATORS(VISIT_OPCODE) - #undef VISIT_OPCODE - switch(opcode) { #define VISIT_OPCODE(_,name,nameString,Imm,...) \ @@ -859,6 +866,7 @@ namespace WASM { serializeVarUInt32(sectionStream,module.startFunctionIndex); }); + injection.adjustIfFunctionIndex(module.startFunctionIndex, ObjectKind::function); } template diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 03e4c6ce69539f911f9cb80fe2565e0b854337a8..3864e3c7f7687ab8073e90ee9effc04297976aea 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -13,7 +13,6 @@ #include -#include #include #include @@ -30,7 +29,6 @@ using namespace eosio::chain; using namespace eosio::chain::config; using fc::flat_map; -#warning TODO: rate limiting //using txn_msg_rate_limits = chain_controller::txn_msg_rate_limits; @@ -54,17 +52,6 @@ public: //txn_msg_rate_limits rate_limits; }; -#ifdef NDEBUG -const uint32_t chain_plugin::default_received_block_transaction_execution_time = 12; -const uint32_t chain_plugin::default_transaction_execution_time = 3; -const uint32_t chain_plugin::default_create_block_transaction_execution_time = 3; -#else -const uint32_t chain_plugin::default_received_block_transaction_execution_time = 72; -const uint32_t chain_plugin::default_transaction_execution_time = 18; -const uint32_t chain_plugin::default_create_block_transaction_execution_time = 18; -#endif - - chain_plugin::chain_plugin() :my(new chain_plugin_impl()) { } @@ -79,11 +66,11 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip ("block-log-dir", bpo::value()->default_value("blocks"), "the location of the block log (absolute path or relative to application data dir)") ("checkpoint,c", bpo::value>()->composing(), "Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints.") - ("rcvd-block-trans-execution-time", bpo::value()->default_value(default_received_block_transaction_execution_time), + ("rcvd-block-trans-execution-time", bpo::value()->default_value(chain_controller::default_received_block_transaction_execution_time_ms), "Limits the maximum time (in milliseconds) that is allowed a transaction's code to execute from a received block.") - ("trans-execution-time", bpo::value()->default_value(default_transaction_execution_time), + ("trans-execution-time", bpo::value()->default_value(chain_controller::default_transaction_execution_time_ms), "Limits the maximum time (in milliseconds) that is allowed a pushed transaction's code to execute.") - ("create-block-trans-execution-time", bpo::value()->default_value(default_create_block_transaction_execution_time), + ("create-block-trans-execution-time", bpo::value()->default_value(chain_controller::default_create_block_transaction_execution_time_ms), "Limits the maximum time (in milliseconds) that is allowed a transaction's code to execute while creating a block.") #warning TODO: rate limiting /*("per-authorized-account-transaction-msg-rate-limit-time-frame-sec", bpo::value()->default_value(default_per_auth_account_time_frame_seconds), @@ -333,7 +320,7 @@ read_only::get_table_rows_result read_only::get_table_rows( const read_only::get vector read_only::get_currency_balance( const read_only::get_currency_balance_params& p )const { vector results; - walk_table(p.account, p.code, N(account), [&](const contracts::key_value_object& obj){ + walk_table(p.code, p.account, N(account), [&](const contracts::key_value_object& obj){ share_type balance; fc::datastream ds(obj.value.data(), obj.value.size()); fc::raw::unpack(ds, balance); @@ -450,13 +437,6 @@ read_only::get_account_results read_only::get_account( const get_account_params& result.account_name = params.account_name; const auto& d = db.get_database(); - share_type balance = contracts::get_eosio_balance(d, params.account_name ); - const auto& staked_balance = d.get( params.account_name ); - - result.eos_balance = asset(balance, EOS_SYMBOL); - result.staked_balance = asset(staked_balance.staked_balance); - result.unstaking_balance = asset(staked_balance.unstaking_balance); - result.last_unstaking_time = staked_balance.last_unstaking_time; const auto& permissions = d.get_index(); auto perm = permissions.lower_bound( boost::make_tuple( params.account_name ) ); diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index a0cfe65fae58d62e47536695c565bbb29b9fcfbe..eda7ac1d97a898c5011d0c221c3a77cf2f751dc7 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -77,13 +77,9 @@ public: struct get_account_results { name account_name; - asset eos_balance = asset(0,EOS_SYMBOL); - asset staked_balance; - asset unstaking_balance; - fc::time_point_sec last_unstaking_time; vector permissions; - optional producer; }; + struct get_account_params { name account_name; }; @@ -164,8 +160,8 @@ public: struct get_table_rows_params { bool json = false; - name scope; name code; + name scope; name table; // string table_type; string table_key; @@ -200,13 +196,13 @@ public: fc::variant get_currency_stats( const get_currency_stats_params& params )const; - void copy_row(const chain::contracts::key_value_object& obj, vector& data)const { + static void copy_row(const chain::contracts::key_value_object& obj, vector& data) { data.resize( sizeof(uint64_t) + obj.value.size() ); memcpy( data.data(), &obj.primary_key, sizeof(uint64_t) ); memcpy( data.data()+sizeof(uint64_t), obj.value.data(), obj.value.size() ); } - void copy_row(const chain::contracts::keystr_value_object& obj, vector& data)const { + static void copy_row(const chain::contracts::keystr_value_object& obj, vector& data) { data.resize( obj.primary_key.size() + obj.value.size() + 8 ); fc::datastream ds(data.data(), data.size()); fc::raw::pack(ds, obj.primary_key); @@ -214,14 +210,14 @@ public: data.resize(ds.tellp()); } - void copy_row(const chain::contracts::key128x128_value_object& obj, vector& data)const { + static void copy_row(const chain::contracts::key128x128_value_object& obj, vector& data) { data.resize( 2*sizeof(uint128_t) + obj.value.size() ); memcpy( data.data(), &obj.primary_key, sizeof(uint128_t) ); memcpy( data.data()+sizeof(uint128_t), &obj.secondary_key, sizeof(uint128_t) ); memcpy( data.data()+2*sizeof(uint128_t), obj.value.data(), obj.value.size() ); } - void copy_row(const chain::contracts::key64x64x64_value_object& obj, vector& data)const { + static void copy_row(const chain::contracts::key64x64x64_value_object& obj, vector& data) { data.resize( 3*sizeof(uint64_t) + obj.value.size() ); memcpy( data.data(), &obj.primary_key, sizeof(uint64_t) ); memcpy( data.data()+sizeof(uint64_t), &obj.secondary_key, sizeof(uint64_t) ); @@ -230,10 +226,10 @@ public: } template - void walk_table(const name& scope, const name& code, const name& table, Function f) const + void walk_table(const name& code, const name& scope, const name& table, Function f) const { const auto& d = db.get_database(); - const auto* t_id = d.find(boost::make_tuple(scope, code, table)); + const auto* t_id = d.find(boost::make_tuple(code, scope, table)); if (t_id != nullptr) { const auto &idx = d.get_index(); decltype(t_id->id) next_tid(t_id->id._id + 1); @@ -255,7 +251,7 @@ public: abi_serializer abis; abis.set_abi(abi); - const auto* t_id = d.find(boost::make_tuple(p.scope, p.code, p.table)); + const auto* t_id = d.find(boost::make_tuple(p.code, p.scope, p.table)); if (t_id != nullptr) { const auto &idx = d.get_index(); decltype(t_id->id) next_tid(t_id->id._id + 1); @@ -356,10 +352,6 @@ public: void get_chain_id (chain::chain_id_type &cid) const; - static const uint32_t default_received_block_transaction_execution_time; - static const uint32_t default_transaction_execution_time; - static const uint32_t default_create_block_transaction_execution_time; - private: unique_ptr my; }; @@ -376,14 +368,14 @@ FC_REFLECT(eosio::chain_apis::read_only::get_block_params, (block_num_or_id)) FC_REFLECT_DERIVED( eosio::chain_apis::read_only::get_block_results, (eosio::chain::signed_block), (id)(block_num)(ref_block_prefix) ); FC_REFLECT( eosio::chain_apis::read_write::push_transaction_results, (transaction_id)(processed) ) -FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_params, (json)(scope)(code)(table)(table_key)(lower_bound)(upper_bound)(limit) ) +FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_params, (json)(code)(scope)(table)(table_key)(lower_bound)(upper_bound)(limit) ) FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_result, (rows)(more) ); FC_REFLECT( eosio::chain_apis::read_only::get_currency_balance_params, (code)(account)(symbol)); FC_REFLECT( eosio::chain_apis::read_only::get_currency_stats_params, (code)(symbol)); FC_REFLECT( eosio::chain_apis::read_only::get_currency_stats_result, (supply)); -FC_REFLECT( eosio::chain_apis::read_only::get_account_results, (account_name)(eos_balance)(staked_balance)(unstaking_balance)(last_unstaking_time)(permissions)(producer) ) +FC_REFLECT( eosio::chain_apis::read_only::get_account_results, (account_name)(permissions) ) FC_REFLECT( eosio::chain_apis::read_only::get_code_results, (account_name)(code_hash)(wast)(abi) ) FC_REFLECT( eosio::chain_apis::read_only::get_account_params, (account_name) ) FC_REFLECT( eosio::chain_apis::read_only::get_code_params, (account_name) ) diff --git a/plugins/make_new_plugin.sh b/plugins/eosio-make_new_plugin.sh similarity index 100% rename from plugins/make_new_plugin.sh rename to plugins/eosio-make_new_plugin.sh diff --git a/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp b/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp index 293b10ca5fa27551c8708a874dfb75dfe33000be..f9bf9f2305e2e65f0653a083e7d65cc997ae4cc5 100644 --- a/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp +++ b/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp @@ -222,7 +222,6 @@ struct faucet_testnet_plugin_impl { auto& plugin = _app.get_plugin(); plugin.get_chain_id(chainid); chain_controller& cc = plugin.chain(); - const asset deposit(1); signed_transaction trx; auto memo = fc::variant(fc::time_point::now()).as_string() + " " + fc::variant(fc::time_point::now().time_since_epoch()).as_string(); @@ -233,7 +232,7 @@ struct faucet_testnet_plugin_impl { auto recovery_auth = chain::authority{1, {}, {{{_create_account_name, "active"}, 1}}}; trx.actions.emplace_back(vector{{_create_account_name,"active"}}, - contracts::newaccount{_create_account_name, new_account_name, owner_auth, active_auth, recovery_auth, deposit}); + contracts::newaccount{_create_account_name, new_account_name, owner_auth, active_auth, recovery_auth}); trx.expiration = cc.head_block_time() + fc::seconds(30); trx.set_reference_block(cc.head_block_id()); diff --git a/plugins/mongo_db_plugin/mongo_db_plugin.cpp b/plugins/mongo_db_plugin/mongo_db_plugin.cpp index 35af7dc6632d3971810b82624d2fb226288992c3..7c3ea51a85b04f3602f9a63aa19aa98061a4146f 100644 --- a/plugins/mongo_db_plugin/mongo_db_plugin.cpp +++ b/plugins/mongo_db_plugin/mongo_db_plugin.cpp @@ -292,7 +292,8 @@ void mongo_db_plugin_impl::_process_irreversible_block(const signed_block& block auto blk_doc = block_doc << "transactions" << stream::open_array; int32_t trx_num = -1; - for (const auto& trx : block.input_transactions) { + for (const auto& packed_trx : block.input_transactions) { + const signed_transaction& trx = packed_trx.get_signed_transaction(); ++trx_num; auto txn_oid = bsoncxx::oid{}; @@ -402,6 +403,7 @@ void mongo_db_plugin_impl::update_account(const chain::action& msg) { if (msg.name == transfer) { auto now = std::chrono::duration_cast( std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()}); + /* todo need to follow eosio.system transfer auto transfer = msg.as(); auto from_name = transfer.from.to_string(); auto to_name = transfer.to.to_string(); @@ -410,8 +412,8 @@ void mongo_db_plugin_impl::update_account(const chain::action& msg) { asset from_balance = asset::from_string(from_account.view()["eos_balance"].get_utf8().value.to_string()); asset to_balance = asset::from_string(to_account.view()["eos_balance"].get_utf8().value.to_string()); - from_balance -= chain::share_type(transfer.amount); - to_balance += chain::share_type(transfer.amount); + from_balance -= asset(chain::share_type(transfer.amount)); + to_balance += asset(chain::share_type(transfer.amount)); document update_from{}; update_from << "$set" << open_document << "eos_balance" << from_balance.to_string() @@ -424,34 +426,17 @@ void mongo_db_plugin_impl::update_account(const chain::action& msg) { accounts.update_one(document{} << "_id" << from_account.view()["_id"].get_oid() << finalize, update_from.view()); accounts.update_one(document{} << "_id" << to_account.view()["_id"].get_oid() << finalize, update_to.view()); - +*/ } else if (msg.name == newaccount) { auto now = std::chrono::duration_cast( std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()}); auto newaccount = msg.as(); - // find creator to update its balance - auto from_name = newaccount.creator.to_string(); - document find_from{}; - find_from << "name" << from_name; - auto from_account = accounts.find_one(find_from.view()); - if (!from_account) { - elog("Unable to find account ${n}", ("n", from_name)); - return; - } - // decrease creator by deposit amount - auto from_view = from_account->view(); - asset from_balance = asset::from_string(from_view["eos_balance"].get_utf8().value.to_string()); - from_balance -= newaccount.deposit; - document update_from{}; - update_from << "$set" << open_document << "eos_balance" << from_balance.to_string() << close_document; - accounts.update_one(find_from.view(), update_from.view()); - - // create new account with staked deposit amount + // create new account bsoncxx::builder::stream::document doc{}; doc << "name" << newaccount.name.to_string() << "eos_balance" << asset().to_string() - << "staked_balance" << newaccount.deposit.to_string() + << "staked_balance" << asset().to_string() << "unstaking_balance" << asset().to_string() << "createdAt" << b_date{now} << "updatedAt" << b_date{now}; @@ -459,72 +444,6 @@ void mongo_db_plugin_impl::update_account(const chain::action& msg) { elog("Failed to insert account ${n}", ("n", newaccount.name)); } - } else if (msg.name == lock) { - auto now = std::chrono::duration_cast( - std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()}); - auto lock = msg.as(); - auto from_account = find_account(accounts, lock.from); - auto to_account = find_account(accounts, lock.to); - - asset from_balance = asset::from_string(from_account.view()["eos_balance"].get_utf8().value.to_string()); - asset to_balance = asset::from_string(to_account.view()["stacked_balance"].get_utf8().value.to_string()); - from_balance -= lock.amount; - to_balance += lock.amount; - - document update_from{}; - update_from << "$set" << open_document << "eos_balance" << from_balance.to_string() - << "updatedAt" << b_date{now} - << close_document; - document update_to{}; - update_to << "$set" << open_document << "stacked_balance" << to_balance.to_string() - << "updatedAt" << b_date{now} - << close_document; - - accounts.update_one(document{} << "_id" << from_account.view()["_id"].get_oid() << finalize, update_from.view()); - accounts.update_one(document{} << "_id" << to_account.view()["_id"].get_oid() << finalize, update_to.view()); - - } else if (msg.name == unlock) { - auto now = std::chrono::duration_cast( - std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()}); - auto unlock = msg.as(); - auto from_account = find_account(accounts, unlock.account); - - asset unstack_balance = asset::from_string(from_account.view()["unstacking_balance"].get_utf8().value.to_string()); - asset stack_balance = asset::from_string(from_account.view()["stacked_balance"].get_utf8().value.to_string()); - auto deltaStake = unstack_balance - unlock.amount; - stack_balance += deltaStake; - unstack_balance = unlock.amount; - // TODO: proxies and last_unstaking_time - - document update_from{}; - update_from << "$set" << open_document - << "staked_balance" << stack_balance.to_string() - << "unstacking_balance" << unstack_balance.to_string() - << "updatedAt" << b_date{now} - << close_document; - - accounts.update_one(document{} << "_id" << from_account.view()["_id"].get_oid() << finalize, update_from.view()); - - } else if (msg.name == claim) { - auto now = std::chrono::duration_cast( - std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()}); - auto claim = msg.as(); - auto from_account = find_account(accounts, claim.account); - - asset balance = asset::from_string(from_account.view()["eos_balance"].get_utf8().value.to_string()); - asset unstack_balance = asset::from_string(from_account.view()["unstacking_balance"].get_utf8().value.to_string()); - unstack_balance -= claim.amount; - balance += claim.amount; - - document update_from{}; - update_from << "$set" << open_document - << "eos_balance" << balance.to_string() - << "unstacking_balance" << unstack_balance.to_string() - << "updatedAt" << b_date{now} - << close_document; - - accounts.update_one(document{} << "_id" << from_account.view()["_id"].get_oid() << finalize, update_from.view()); - } else if (msg.name == setabi) { auto now = std::chrono::duration_cast( std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()}); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 091290dd154069a13b5e503af89e875ef8e20a93..aa07ef833da2b281c9025ad79d3465cc6d922228 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -50,7 +50,7 @@ namespace eosio { class connection; class sync_manager; - + class big_msg_manager; using connection_ptr = std::shared_ptr; using connection_wptr = std::weak_ptr; @@ -156,6 +156,7 @@ namespace eosio { std::set< connection_ptr > connections; bool done = false; unique_ptr< sync_manager > sync_master; + unique_ptr< big_msg_manager > bm_master; unique_ptr connector_check; unique_ptr transaction_check; @@ -174,7 +175,6 @@ namespace eosio { string user_agent_name; chain_plugin* chain_plug; - size_t just_send_it_max = 0; bool send_whole_blocks = false; int started_sessions = 0; @@ -194,14 +194,9 @@ namespace eosio { template void send_all( const net_message &msg, VerifierFunc verify ); - // template - // void send_all(net_message_ptr msg, VerifierFunc verify); - void send_all_txn(const signed_transaction& txn); static void transaction_ready( const packed_transaction& txn); void broadcast_block_impl( const signed_block &sb); - size_t cache_txn( const transaction_id_type, const signed_transaction &txn); - bool is_valid( const handshake_message &msg); void handle_message( connection_ptr c, const handshake_message &msg); @@ -265,6 +260,7 @@ namespace eosio { * If there are no configured private keys, returns an empty signature. */ chain::signature_type sign_compact(const chain::public_key_type& signer, const fc::sha256& digest) const; + static const fc::string logger_name; static fc::logger logger; }; @@ -277,8 +273,6 @@ namespace eosio { } static net_plugin_impl *my_impl; - const fc::string net_plugin_impl::logger_name("net_plugin_impl"); - fc::logger net_plugin_impl::logger(net_plugin_impl::logger_name); /** * default value initializers @@ -370,9 +364,8 @@ namespace eosio { ~connection(); void initialize(); - block_state_index block_state; + block_state_index blk_state; transaction_state_index trx_state; - sync_state_ptr sync_receiving; // we are requesting info from this peer sync_state_ptr sync_requested; // this peer is requesting info from us socket_ptr socket; @@ -400,6 +393,8 @@ namespace eosio { unique_ptr response_expected; optional pending_fetch; go_away_reason no_retry; + block_id_type fork_head; + uint32_t fork_head_num; connection_status get_status()const { connection_status stat; @@ -463,9 +458,8 @@ namespace eosio { void txn_send_pending(const vector &ids); void txn_send(const vector &txn_lis); - uint32_t send_branch(chain_controller &cc, block_id_type bid, uint32_t lib_num, block_id_type lib_id); - void blk_send_branch( const vector &ids); + void blk_send_branch(); void blk_send(const vector &txn_lis); void stop_send(); @@ -477,6 +471,7 @@ namespace eosio { void send_next_message(); void send_next_txn(); + void cancel_wait(); void sync_wait(); void fetch_wait(); void sync_timeout(boost::system::error_code ec); @@ -495,14 +490,10 @@ namespace eosio { * encountered unpacking or processing the message. */ bool process_next_message(net_plugin_impl& impl, uint32_t message_length); - static const fc::string logger_name; static fc::logger logger; }; - const fc::string connection::logger_name("connection"); - fc::logger connection::logger(connection::logger_name); - struct msgHandler : public fc::visitor { net_plugin_impl &impl; connection_ptr c; @@ -516,41 +507,75 @@ namespace eosio { }; class sync_manager { - public: - uint32_t sync_known_lib_num; - uint32_t sync_last_requested_num; - uint32_t sync_req_span; - connection_ptr source; - bool active; + private: + enum stages { + lib_catchup, + head_catchup, + in_sync + }; + + uint32_t sync_known_lib_num; + uint32_t sync_last_requested_num; + uint32_t sync_req_span; + uint32_t last_repeated; + connection_ptr source; + stages state; deque _blocks; chain_plugin * chain_plug; public: sync_manager(uint32_t span); + bool is_active(connection_ptr conn); void reset_lib_num(); bool sync_required(); - void request_next_chunk(connection_ptr conn); - void take_chunk(connection_ptr c); + void request_next_chunk(connection_ptr conn = connection_ptr() ); void start_sync(connection_ptr c, uint32_t target); - - void set_blocks_to_fetch(vector); - void assign_fectch(connection_ptr c); + void send_handshakes(); void reassign_fetch(connection_ptr c, go_away_reason reason); + void verify_catchup(connection_ptr c, uint32_t num, block_id_type id); + void recv_block(connection_ptr c, const signed_block &blk, bool accepted); + void recv_handshake(connection_ptr c, const handshake_message& msg); + void recv_notice(connection_ptr c, const notice_message& msg); + + static const fc::string logger_name; + static fc::logger logger; + }; + + class big_msg_manager { + public: + uint32_t just_send_it_max; + vector req_blks; + vector req_txn; + + bool requested_blk (block_id_type bid); + bool requested_txn (transaction_id_type tid); + void bcast_summary (const block_summary_message& msg); + void bcast_block (const signed_block& msg,connection_ptr skip = connection_ptr() ); + void bcast_transaction (const signed_transaction& msg, connection_ptr skip = connection_ptr() ); + void bcast_transaction (const packed_transaction& msg, connection_ptr skip = connection_ptr() ); + void recv_block (connection_ptr conn, const signed_block& msg); + void recv_transaction (connection_ptr conn, const signed_transaction& msg); + void recv_notice (connection_ptr conn, const notice_message& msg); static const fc::string logger_name; static fc::logger logger; }; + const fc::string net_plugin_impl::logger_name("net_plugin_impl"); + fc::logger net_plugin_impl::logger(net_plugin_impl::logger_name); + const fc::string connection::logger_name("connection"); + fc::logger connection::logger(connection::logger_name); const fc::string sync_manager::logger_name("sync_manager"); fc::logger sync_manager::logger(sync_manager::logger_name); + const fc::string big_msg_manager::logger_name("big_msg_manager"); + fc::logger big_msg_manager::logger(big_msg_manager::logger_name); //--------------------------------------------------------------------------- connection::connection( string endpoint ) - : block_state(), + : blk_state(), trx_state(), - sync_receiving(), sync_requested(), socket( std::make_shared( std::ref( app().get_io_service() ))), node_id(), @@ -564,16 +589,17 @@ namespace eosio { peer_addr(endpoint), response_expected(), pending_fetch(), - no_retry(go_away_reason::no_reason) + no_retry(no_reason), + fork_head(), + fork_head_num() { wlog( "created connection to ${n}", ("n", endpoint) ); initialize(); } connection::connection( socket_ptr s ) - : block_state(), + : blk_state(), trx_state(), - sync_receiving(), sync_requested(), socket( s ), node_id(), @@ -587,7 +613,9 @@ namespace eosio { peer_addr(), response_expected(), pending_fetch(), - no_retry(go_away_reason::no_reason) + no_retry(no_reason), + fork_head(), + fork_head_num(0) { wlog( "accepted network connection" ); initialize(); @@ -616,7 +644,7 @@ namespace eosio { void connection::reset() { sync_requested.reset(); - block_state.clear(); + blk_state.clear(); trx_state.clear(); } @@ -647,15 +675,12 @@ namespace eosio { flush_queues(); connecting = false; syncing = false; - sync_receiving.reset(); reset(); sent_handshake_count = 0; last_handshake_recv = handshake_message(); last_handshake_sent = handshake_message(); my_impl->sync_master->reset_lib_num(); - if(response_expected) { - response_expected->cancel(); - } + cancel_wait(); pending_message_buffer.reset(); } @@ -686,54 +711,7 @@ namespace eosio { } } - uint32_t connection::send_branch(chain_controller &cc, block_id_type bid, uint32_t lib_num, block_id_type lib_id) { - static uint32_t dbg_depth = 0; - uint32_t count = 0; - try { - optional b = cc.fetch_block_by_id(bid); - if( b ) { - block_id_type prev = b->previous; - if( prev == lib_id) { - enqueue( *b ); - count = 1; - } - else { - uint32_t pnum = block_header::num_from_id( prev ); - if( pnum < lib_num ) { - uint32_t irr = cc.last_irreversible_block_num(); - elog( "Whoa! branch regression passed last irreversible block! depth = ${d}", ("d",dbg_depth )); - optional pb = cc.fetch_block_by_id (prev); - block_id_type pprev; - if (!pb ) { - fc_dlog(logger, "no block for prev"); - } else { - pprev = pb->previous; - } - fc_dlog(logger, "irr = ${irr} lib_nim = ${ln} pnum = ${pn}", ("irr",irr)("ln",lib_num)("pn",pnum)); - fc_dlog(logger, "prev = ${p}", ("p",prev)); - fc_dlog(logger, "lib = ${p}", ("p",lib_id)); - fc_dlog(logger, "bid = ${p}", ("p",bid)); - fc_dlog(logger, "ppre = ${p}", ("p",pprev)); - } - else { - ++dbg_depth; - count = send_branch (cc, prev, lib_num, lib_id ); - --dbg_depth; - if (count > 0) { - enqueue( *b ); - ++count; - } - } - } - } - } catch (...) { - elog( "Send Branch failed, caught unidentified exception"); - } - return count; - } - - - void connection::blk_send_branch(const vector &ids) { + void connection::blk_send_branch() { chain_controller &cc = my_impl->chain_plug->chain(); uint32_t head_num = cc.head_block_num (); notice_message note; @@ -754,43 +732,83 @@ namespace eosio { head_id = cc.get_block_id_for_num(head_num); } catch (const assert_exception &ex) { - fc_dlog(logger, "caught assert ${x}",("x",ex.what())); + elog( "unable to retrieve block info: ${n} for ${p}",("n",ex.to_string())("p",peer_name())); enqueue(note); return; } - uint32_t count = send_branch(cc, head_id, lib_num, lib_id); - fc_dlog(logger, "Sent ${n} blocks on my fork",("n",count)); + catch (const fc::exception &ex) { + } + catch (...) { + } + + vector > bstack; + block_id_type null_id; + for (auto bid = head_id; bid != null_id && bid != lib_id; ) { + try { + optional b = cc.fetch_block_by_id(bid); + if ( b ) { + bid = b->previous; + bstack.push_back(b); + } + else { + break; + } + } catch (...) { + break; + } + } + size_t count = 0; + if (bstack.back()->previous == lib_id) { + count = bstack.size(); + while (bstack.size()) { + enqueue (*bstack.back()); + bstack.pop_back(); + } + } + + fc_ilog(logger, "Sent ${n} blocks on my fork",("n",count)); syncing = false; } void connection::blk_send(const vector &ids) { chain_controller &cc = my_impl->chain_plug->chain(); - - for(auto blkid : ids) { + int count = 0; + for(auto &blkid : ids) { + ++count; try { optional b = cc.fetch_block_by_id(blkid); if(b) { enqueue(*b); } + else { + ilog("fetch block by id returned null, id ${id} on block ${c} of ${s} for ${p}", + ("id",blkid)("c",count)("s",ids.size())("p",peer_name())); + break; + } } catch (const assert_exception &ex) { - elog( "caught assert on fetch_block_by_id, ${ex}",("ex",ex.what())); - // keep going, client can ask another peer + elog( "caught assert on fetch_block_by_id, ${ex}, id ${id} on block ${c} of ${s} for ${p}", + ("ex",ex.to_string())("id",blkid)("c",count)("s",ids.size())("p",peer_name())); + break; } catch (...) { - elog( "failed to retrieve block for id"); + elog( "caught othser exception fetching block id ${id} on block ${c} of ${s} for ${p}", + ("id",blkid)("c",count)("s",ids.size())("p",peer_name())); + break; } } } void connection::stop_send() { + syncing = false; txn_queue.clear(); } void connection::send_handshake( ) { handshake_initializer::populate(last_handshake_sent); last_handshake_sent.generation = ++sent_handshake_count; - fc_dlog(logger, "Sending handshake to ${ep}", ("ep", peer_addr)); + fc_dlog(logger, "Sending handshake generation ${g} to ${ep}", + ("g",last_handshake_sent.generation)("ep", peer_addr)); enqueue(last_handshake_sent); } @@ -882,8 +900,9 @@ namespace eosio { } void connection::cancel_sync(go_away_reason reason) { - fc_dlog(logger,"cancel sync reason = ${m}, out queue size ${o} ", ("m",reason_str(reason)) ("o", out_queue.size())); - sync_receiving.reset(); + fc_dlog(logger,"cancel sync reason = ${m}, out queue size ${o} peer ${p}", + ("m",reason_str(reason)) ("o", out_queue.size())("p", peer_name())); + cancel_wait(); flush_queues(); switch (reason) { case validation : @@ -997,6 +1016,11 @@ namespace eosio { elog("actually sent ${limit} pending transactions to ${p}",("limit",limit)("p",peer_name())); } + void connection::cancel_wait() { + if (response_expected) + response_expected->cancel(); + } + void connection::sync_wait( ) { response_expected->expires_from_now( my_impl->resp_expected_period); connection_wptr c(shared_from_this()); @@ -1027,9 +1051,7 @@ namespace eosio { void connection::sync_timeout( boost::system::error_code ec ) { if( !ec ) { - if( sync_receiving && sync_receiving->last < sync_receiving->end_block) { - my_impl->sync_master->reassign_fetch (shared_from_this(),benign_other); - } + my_impl->sync_master->reassign_fetch (shared_from_this(),benign_other); } else if( ec == boost::asio::error::operation_aborted) { } @@ -1066,9 +1088,7 @@ namespace eosio { bool connection::process_next_message(net_plugin_impl& impl, uint32_t message_length) { try { - if (response_expected) { - response_expected->cancel(); - } + cancel_wait(); // If it is a signed_block, then save the raw message for the cache // This must be done before we unpack the message. // This code is copied from fc::io::unpack(..., unsigned_int) @@ -1101,16 +1121,27 @@ namespace eosio { //----------------------------------------------------------- - sync_manager::sync_manager( uint32_t span ) + sync_manager::sync_manager( uint32_t req_span ) :sync_known_lib_num( 0 ) ,sync_last_requested_num( 0 ) - ,sync_req_span( span ) + ,sync_req_span( req_span ) + ,last_repeated( 0 ) ,source() - ,active(false) + ,state(in_sync) { chain_plug = app( ).find_plugin( ); } + bool sync_manager::is_active(connection_ptr c) { + if (state == head_catchup && c) { + bool fhset = c->fork_head != block_id_type(); + fc_dlog(logger, "fork_head_num = ${fn} fork_head set = ${s}", + ("fn", c->fork_head_num)("s", fhset)); + return c->fork_head != block_id_type() && c->fork_head_num < chain_plug->chain().head_block_num(); + } + return state != in_sync; + } + void sync_manager::reset_lib_num() { sync_known_lib_num = chain_plug->chain().last_irreversible_block_num(); sync_last_requested_num = chain_plug->chain().head_block_num(); @@ -1118,9 +1149,6 @@ namespace eosio { if( c->last_handshake_recv.last_irreversible_block_num > sync_known_lib_num) { sync_known_lib_num =c->last_handshake_recv.last_irreversible_block_num; } - if( c->sync_receiving && c->sync_receiving->end_block > sync_last_requested_num) { - sync_last_requested_num = c->sync_receiving->end_block; - } } } @@ -1131,11 +1159,11 @@ namespace eosio { chain_plug->chain( ).head_block_num( ) < sync_last_requested_num ); } - void sync_manager::request_next_chunk( connection_ptr conn = connection_ptr() ) { + void sync_manager::request_next_chunk( connection_ptr conn ) { uint32_t head_block = chain_plug->chain().head_block_num(); if (head_block < sync_last_requested_num) { - fc_dlog (logger, "ignoring request, head is ${h} last req = ${r}",("h",head_block)("r",sync_last_requested_num)); + ilog ("ignoring request, head is ${h} last req = ${r}",("h",head_block)("r",sync_last_requested_num)); return; } @@ -1154,11 +1182,12 @@ namespace eosio { auto cptr = my_impl->connections.find(source); if (cptr == my_impl->connections.end()) { elog ("unable to find previous source connection in connections list"); + source.reset(); cptr = my_impl->connections.begin(); } else { ++cptr; } - while (true) { + while (my_impl->connections.size() > 1) { if (cptr == my_impl->connections.end()) { cptr = my_impl->connections.begin(); if (!source) { @@ -1193,47 +1222,22 @@ namespace eosio { if( end > sync_known_lib_num ) end = sync_known_lib_num; if( end > 0 && end >= start ) { - fc_dlog(logger,"conn ${n} recv blks ${s} to ${e}",("n",source->peer_name() )("s",start)("e",end)); - source->sync_receiving.reset(new sync_state( start, end, sync_last_requested_num ) ); + fc_dlog(logger, "conn ${n} requesting range ${s} to ${e}", + ("n",source->peer_name())("s",start)("e",end)); + sync_request_message srm = {start,end}; + source->enqueue( net_message(srm)); + sync_last_requested_num = end; } } - else { - fc_dlog(logger, "conn ${n} resetting sync recv",("n",source->peer_name() )); - source->sync_receiving.reset( ); - } - - if(source->sync_receiving && source->sync_receiving->start_block == head_block + 1) { - fc_dlog(logger, "conn ${n} requesting range ${rs} to ${re} should be ${s} to ${e}", - ("n",source->peer_name())("rs",source->sync_receiving->start_block)("re",source->sync_receiving->end_block)("s",start)("e",end)); - source->enqueue( (sync_request_message){source->sync_receiving->start_block, - source->sync_receiving->end_block}); - sync_last_requested_num = source->sync_receiving->end_block; - } } - void sync_manager::take_chunk( connection_ptr c) { - if( !c->sync_receiving) { - fc_dlog(logger, "take_chunk called, but sync_receiving is empty"); - return; - } - sync_state_ptr ss; - c->sync_receiving.swap(ss); - fc_dlog(logger, "conn ${n} covered blks ${s} to ${e}",("n",c->peer_name() )("s",ss->start_block)("e",ss->end_block)); - - if( chain_plug->chain().head_block_num() == sync_known_lib_num ) { - handshake_message hello; - handshake_initializer::populate(hello); - fc_dlog(logger, "All caught up with last known last irreversible block resending handshake"); - active = false; - for( auto &ci : my_impl->connections) { - if( ci->current()) { - hello.generation = ++ci->sent_handshake_count; - ci->last_handshake_sent = hello; - ci->enqueue( hello ); - } + void sync_manager::send_handshakes () + { + for( auto &ci : my_impl->connections) { + if( ci->current()) { + ci->send_handshake(); } } - request_next_chunk(); } void sync_manager::start_sync( connection_ptr c, uint32_t target) { @@ -1246,18 +1250,14 @@ namespace eosio { uint32_t hnum = chain_plug->chain().head_block_num(); fc_dlog( logger, "We are already caught up, my irr = ${b}, head = ${h}, target = ${t}", ("b",bnum)("h",hnum)("t",target)); - active = false; return; } - active = true; + state = lib_catchup; - ilog( "Catching up with chain, our last req is ${cc}, theirs is ${t} peer ${p}", ( "cc",sync_last_requested_num)("t",target)("p",c->peer_name())); + fc_ilog(logger, "Catching up with chain, our last req is ${cc}, theirs is ${t} peer ${p}", + ( "cc",sync_last_requested_num)("t",target)("p",c->peer_name())); - if( c->sync_receiving && c->sync_receiving->end_block > 0) { - ilog("connection already has end block ${eb}",("eb",c->sync_receiving->end_block)); - return; - } request_next_chunk(c); } @@ -1267,191 +1267,619 @@ namespace eosio { request_next_chunk(); } - //------------------------------------------------------------------------ + void sync_manager::recv_handshake (connection_ptr c, const handshake_message &msg) { + chain_controller& cc = chain_plug->chain(); + uint32_t lib_num = cc.last_irreversible_block_num( ); + uint32_t peer_lib = msg.last_irreversible_block_num; + reset_lib_num(); + c->syncing = false; + state = in_sync; - void net_plugin_impl::connect( connection_ptr c ) { - if( c->no_retry != go_away_reason::no_reason) { - fc_dlog( logger, "Skipping connect due to go_away reason ${r}",("r", reason_str( c->no_retry ))); + //-------------------------------- + // sync need checkz; (lib == last irreversible block) + // + // 0. my head block id == peer head id means we are all caugnt up block wise + // 1. my head block num < peer lib - start sync locally + // 2. my lib > peer head num - send an last_irr_catch_up notice if not the first generation + // + // 3 my head block num <= peer head block num - update sync state and send a catchup request + // 4 my head block num > peer block num ssend a notice catchup if this is not the first generation + // + //----------------------------- + + uint32_t head = cc.head_block_num( ); + block_id_type head_id = cc.head_block_id(); + if (head_id == msg.head_id) { + fc_dlog(logger, "sync check state 0"); + // notify peer of our pending transactions + notice_message note; + note.known_blocks.mode = none; + note.known_trx.mode = catch_up; + note.known_trx.pending = my_impl->local_txns.size(); + c->enqueue( note ); + return; + } + if (head < peer_lib) { + fc_dlog(logger, "sync check state 1"); + start_sync( c, peer_lib); + return; + } + if (lib_num > msg.head_num ) { + fc_dlog(logger, "sync check state 2"); + // for generation 1, we wlso sent a handshake so they will treat this as state 1 + if ( msg.generation > 1 ) { + notice_message note; + note.known_trx.pending = lib_num; + note.known_trx.mode = last_irr_catch_up; + note.known_blocks.mode = last_irr_catch_up; + note.known_blocks.pending = head; + c->enqueue( note ); + } + c->syncing = true; return; } - auto colon = c->peer_addr.find(':'); - - if (colon == std::string::npos || colon == 0) { - elog ("Invalid peer address. must be \"host:port\": ${p}", ("p",c->peer_addr)); + if (head <= msg.head_num ) { + fc_dlog(logger, "sync check state 3"); + // if (state == in_sync ) { + verify_catchup (c, msg.head_num, msg.head_id); + // } + return; + } + else { + fc_dlog(logger, "sync check state 4"); + if ( msg.generation > 1 ) { + notice_message note; + note.known_trx.mode = none; + note.known_blocks.mode = catch_up; + note.known_blocks.pending = head; + note.known_blocks.ids.push_back(head_id); + c->enqueue( note ); + } + c->syncing = true; return; } + elog ("sync check failed to resolve status"); + } - auto host = c->peer_addr.substr( 0, colon ); - auto port = c->peer_addr.substr( colon + 1); - idump((host)(port)); - tcp::resolver::query query( tcp::v4(), host.c_str(), port.c_str() ); - // Note: need to add support for IPv6 too + void sync_manager::verify_catchup(connection_ptr c, uint32_t num, block_id_type id) { + request_message req; + req.req_blocks.mode = catch_up; + for (auto cc : my_impl->connections) { + if (cc->fork_head == id || + cc->fork_head_num > num) + req.req_blocks.mode = none; + break; + } + if( req.req_blocks.mode == catch_up ) { + c->fork_head = id; + c->fork_head_num = num; + state = head_catchup; + } + else { + c->fork_head = block_id_type(); + c->fork_head_num = 0; + } + req.req_trx.mode = none; + c->enqueue( req ); + } - resolver->async_resolve( query, - [c, this]( const boost::system::error_code& err, - tcp::resolver::iterator endpoint_itr ){ - if( !err ) { - connect( c, endpoint_itr ); - } else { - elog( "Unable to resolve ${peer_addr}: ${error}", - ( "peer_addr", c->peer_name() )("error", err.message() ) ); - } - }); + void sync_manager::recv_notice (connection_ptr c, const notice_message &msg) { + fc_ilog (logger, "sync_manager got ${m} block notice",("m",modes_str(msg.known_blocks.mode))); + if (msg.known_blocks.mode == catch_up) { + if (msg.known_blocks.ids.size() == 0) { + elog ("got a catch up with ids size = 0"); + } + else { + verify_catchup(c, msg.known_blocks.pending, msg.known_blocks.ids.back()); + } + } + else { + c->last_handshake_recv.last_irreversible_block_num = msg.known_trx.pending; + reset_lib_num (); + start_sync(c, msg.known_blocks.pending); + } } - void net_plugin_impl::connect( connection_ptr c, tcp::resolver::iterator endpoint_itr ) { - if( c->no_retry != go_away_reason::no_reason) { - string rsn = reason_str(c->no_retry); + void sync_manager::recv_block (connection_ptr c, const signed_block &blk, bool accepted) { + if (!accepted) { + uint32_t head_num = chain_plug->chain().head_block_num(); + if (head_num != last_repeated) { + ilog ("block not accepted, try requesting one more time"); + last_repeated = head_num; + send_handshakes(); + } + else { + ilog ("a second attenpt to retrive block ${n} failed", + ("n", head_num + 1)); + last_repeated = 0; + c->close(); + } return; } - auto current_endpoint = *endpoint_itr; - ++endpoint_itr; - c->connecting = true; - c->socket->async_connect( current_endpoint, - [c, endpoint_itr, this] - ( const boost::system::error_code& err ) { - if( !err ) { - start_session( c ); - c->send_handshake (); - } else { - if( endpoint_itr != tcp::resolver::iterator() ) { - c->close(); - connect( c, endpoint_itr ); - } - else { - elog( "connection failed to ${peer}: ${error}", - ( "peer", c->peer_name())("error",err.message())); - c->connecting = false; - my_impl->close(c); - } - } - } ); + last_repeated = 0; + + if (state == head_catchup) { + fc_dlog (logger, "sync_manager in head_catchup state"); + state = in_sync; + for (auto cp : my_impl->connections) { + if (cp->fork_head == block_id_type()) { + continue; + } + if (cp->fork_head == blk.id() || + cp->fork_head_num < blk.block_num()) { + c->fork_head = block_id_type(); + c->fork_head_num = 0; + } + else { + state = head_catchup; + } + } + } + else if (state == lib_catchup) { + uint32_t num = blk.block_num(); + if( num == sync_known_lib_num ) { + fc_dlog( logger, "All caught up with last known last irreversible block resending handshake"); + c->cancel_wait(); + state = in_sync; + send_handshakes(); + } + else if (num == sync_last_requested_num) { + request_next_chunk(); + } + else { + c->sync_wait(); + } + } } - void net_plugin_impl::start_session( connection_ptr con ) { - boost::asio::ip::tcp::no_delay nodelay( true ); - con->socket->set_option( nodelay ); - start_read_message( con ); - ++started_sessions; + //------------------------------------------------------------------------ - // for now, we can just use the application main loop. - // con->readloop_complete = bf::async( [=](){ read_loop( con ); } ); - // con->writeloop_complete = bf::async( [=](){ write_loop con ); } ); + void big_msg_manager::bcast_summary (const block_summary_message& bsm) { + //iterate through the transaction ids and send to any connection which does not know + // about the transaction + my_impl->send_all( bsm,[](connection_ptr c) -> bool { return true; }); } - - void net_plugin_impl::start_listen_loop( ) { - auto socket = std::make_shared( std::ref( app().get_io_service() ) ); - acceptor->async_accept( *socket, [socket,this]( boost::system::error_code ec ) { - if( !ec ) { - uint32_t visitors = 0; - for (auto &conn : connections) { - if(conn->current() && conn->peer_addr.empty()) { - visitors++; - } - } - if (num_clients != visitors) { - ilog ("checking max client, visitors = ${v} num clients ${n}",("v",visitors)("n",num_clients)); - num_clients = visitors; + void big_msg_manager::bcast_block (const signed_block& sb, connection_ptr skip) { + net_message msg(sb); + uint32_t packsiz = fc::raw::pack_size(msg); + uint32_t msgsiz = packsiz + sizeof(packsiz); + notice_message pending_notify; + block_id_type bid = sb.id(); + pending_notify.known_blocks.mode = normal; + pending_notify.known_blocks.ids.push_back( bid ); + pending_notify.known_trx.mode = none; + if (msgsiz > just_send_it_max) { + my_impl->send_all(pending_notify, [skip, bid](connection_ptr c) -> bool { + if (c == skip || !c->current()) + return false; + const auto& bs = c->blk_state.find(bid); + bool unknown = bs == c->blk_state.end(); + if (unknown) { + c->blk_state.insert(block_state({bid,false,true,fc::time_point() })); } - if( max_client_count == 0 || num_clients < max_client_count ) { - ++num_clients; - connection_ptr c = std::make_shared( socket ); - connections.insert( c ); - start_session( c ); - } else { - elog( "Error max_client_count ${m} exceeded", - ( "m", max_client_count) ); - socket->close( ); + else { + elog("${p} already has knowledge of block ${b}", ("p",c->peer_name())("b",bid)); } - start_listen_loop(); - } else { - elog( "Error accepting connection: ${m}",( "m", ec.message() ) ); + return unknown; + }); + } + else { + block_id_type prev = sb.previous; + for (auto cp : my_impl->connections) { + if (cp == skip || !cp->current()) { + continue; + } + const auto& bs = cp->blk_state.find (prev); + if (bs != cp->blk_state.end() && !bs->is_known) { + cp->blk_state.insert(block_state({bid,false,true,fc::time_point() })); + cp->enqueue( pending_notify ); + } + else { + cp->enqueue( sb ); } - }); - } - - void net_plugin_impl::start_read_message( connection_ptr conn ) { - - try { - if(!conn->socket) { - return; } - conn->socket->async_read_some( - conn->pending_message_buffer.get_buffer_sequence_for_boost_async_read(), - [this,conn]( boost::system::error_code ec, std::size_t bytes_transferred ) { - try { - if( !ec ) { - if (bytes_transferred > conn->pending_message_buffer.bytes_to_write()) { - elog("async_read_some callback: bytes_transfered = ${bt}, buffer.bytes_to_write = ${btw}",("bt",bytes_transferred)("btw",conn->pending_message_buffer.bytes_to_write())); - } - FC_ASSERT(bytes_transferred <= conn->pending_message_buffer.bytes_to_write()); - conn->pending_message_buffer.advance_write_ptr(bytes_transferred); - while (conn->pending_message_buffer.bytes_to_read() > 0) { - uint32_t bytes_in_buffer = conn->pending_message_buffer.bytes_to_read(); - - if (bytes_in_buffer < message_header_size) { - break; - } else { - uint32_t message_length; - auto index = conn->pending_message_buffer.read_index(); - conn->pending_message_buffer.peek(&message_length, sizeof(message_length), index); - if(message_length > def_send_buffer_size*2) { - elog("incoming message length unexpected (${i})", ("i", message_length)); - close(conn); - return; - } - if (bytes_in_buffer >= message_length + message_header_size) { - conn->pending_message_buffer.advance_read_ptr(message_header_size); - if (!conn->process_next_message(*this, message_length)) { - return; - } - } else { - conn->pending_message_buffer.add_space(message_length + message_header_size - bytes_in_buffer); - break; - } - } - } - start_read_message(conn); - } else { - auto pname = conn->peer_name(); - if (ec.value() != boost::asio::error::eof) { - elog( "Error reading message from ${p}: ${m}",("p",pname)( "m", ec.message() ) ); - } else { - ilog( "Peer ${p} closed connection",("p",pname) ); - } - close( conn ); - } - } - catch(const std::exception &ex) { - string pname = conn ? conn->peer_name() : "no connection name"; - elog("Exception in handling read data from ${p} ${s}",("p",pname)("s",ex.what())); - close( conn ); - } - catch(const fc::exception &ex) { - string pname = conn ? conn->peer_name() : "no connection name"; - elog("Exception in handling read data ${s}", ("p",pname)("s",ex.to_string())); - close( conn ); - } - catch (...) { - string pname = conn ? conn->peer_name() : "no connection name"; - elog( "Undefined exception hanlding the read data from connection ${p}",( "p",pname)); - close( conn ); - } - } - ); - } catch (...) { - string pname = conn ? conn->peer_name() : "no connection name"; - elog( "Undefined exception handling reading ${p}",("p",pname) ); - close( conn ); } } - size_t net_plugin_impl::count_open_sockets() const - { - size_t count = 0; - for( auto &c : connections) { + void big_msg_manager::bcast_transaction (const signed_transaction& txn, connection_ptr skip) { + transaction_id_type txnid = txn.id(); + if( my_impl->local_txns.get().find( txnid ) != my_impl->local_txns.end( ) ) { //found + fc_dlog(logger, "found txnid in local_txns" ); + return; + } + net_message msg(txn); + uint32_t packsiz = fc::raw::pack_size(msg); + uint32_t bufsiz = packsiz + sizeof(packsiz); + vector buff(bufsiz); + fc::datastream ds( buff.data(), bufsiz); + ds.write( reinterpret_cast(&packsiz), sizeof(packsiz) ); + fc::raw::pack( ds, msg ); + + uint16_t bn = static_cast(txn.ref_block_num); + node_transaction_state nts = {txnid,time_point::now(), + txn.expiration, + txn.expiration, + buff, + bn, true}; + my_impl->local_txns.insert(nts); + fc_dlog(logger, "bufsiz = ${bs} max = ${max}",("bs", bufsiz)("max", just_send_it_max)); + + if( bufsiz <= just_send_it_max) { + my_impl->send_all( txn, [skip, txnid](connection_ptr c) -> bool { + if( c == skip || c->syncing ) { + return false; + } + const auto& bs = c->trx_state.find(txnid); + bool unknown = bs == c->trx_state.end(); + if( unknown) { + c->trx_state.insert(transaction_state({txnid,true,true,(uint32_t)-1, + fc::time_point(),fc::time_point() })); + fc_dlog(logger, "sending whole txn to ${n}", ("n",c->peer_name() ) ); + } + return unknown; + }); + } + else { + notice_message pending_notify; + pending_notify.known_trx.mode = normal; + pending_notify.known_trx.ids.push_back( txnid ); + pending_notify.known_blocks.mode = none; + my_impl->send_all(pending_notify, [skip, txnid](connection_ptr c) -> bool { + if (c == skip || c->syncing) { + return false; + } + const auto& bs = c->trx_state.find(txnid); + bool unknown = bs == c->trx_state.end(); + if( unknown) { + fc_dlog(logger, "sending notice to ${n}", ("n",c->peer_name() ) ); + + c->trx_state.insert(transaction_state({txnid,false,true,(uint32_t)-1, + fc::time_point(),fc::time_point() })); + } + return unknown; + }); + } + + } + + void big_msg_manager::bcast_transaction (const packed_transaction& txn, connection_ptr skip) { + // TODO: avoid this reserialization by updating protocol to use packed_transactions directly + auto strx = signed_transaction(txn.get_transaction(), txn.signatures); + bcast_transaction( strx, skip ); + } + + bool big_msg_manager::requested_blk( block_id_type blk_id) { + for (auto ref = req_blks.begin(); ref != req_blks.end(); ++ref) { + if (*ref == blk_id) { + req_blks.erase(ref); + return true; + } + } + return false; + } + + bool big_msg_manager::requested_txn( transaction_id_type txn_id) { + for (auto ref = req_txn.begin(); ref != req_txn.end(); ++ref) { + if (*ref == txn_id) { + req_txn.erase(ref); + return true; + } + } + return false; + } + + void big_msg_manager::recv_block (connection_ptr c, const signed_block& msg) { + block_id_type blk_id = msg.id(); + uint16_t num = msg.block_num(); + if( requested_blk(blk_id) ) { + notice_message note; + note.known_blocks.mode = normal; + note.known_blocks.ids.push_back( blk_id ); + note.known_trx.mode = none; + my_impl->send_all(note, [blk_id](connection_ptr conn) -> bool { + const auto& bs = conn->blk_state.find(blk_id); + bool unknown = bs == conn->blk_state.end(); + if (unknown) { + conn->blk_state.insert(block_state({blk_id,false,true,fc::time_point() })); + } + else { + + } + return unknown; + }); + } + else if(!my_impl->sync_master->is_active(c)) { + net_message nmsg(msg); + if(fc::raw::pack_size(nmsg) < just_send_it_max ) { + fc_dlog(logger, "forwarding the signed block"); + my_impl->send_all( msg, [c, blk_id, num](connection_ptr conn) -> bool { + bool sendit = false; + if( c != conn && !conn->syncing ) { + auto b = conn->blk_state.get().find(blk_id); + if(b == conn->blk_state.end()) { + conn->blk_state.insert( (block_state){blk_id,true,true,fc::time_point()}); + sendit = true; + } else if (!b->is_known) { + conn->blk_state.modify(b,make_known()); + sendit = true; + } + } + fc_dlog(logger, "${action} block ${num} to ${c}",("action", sendit ? "sending " : "skipping ")("num",num)("c", conn->peer_name() )); + return sendit; + }); + } + } + else { + fc_dlog(logger, "not forwarding from active syncing connection ${p}",("p",c->peer_name())); + } + } + + void big_msg_manager::recv_transaction (connection_ptr c, const signed_transaction& msg) { + transaction_id_type txn_id = msg.id(); + if( requested_txn(txn_id) ) { + notice_message notify; + notify.known_trx.mode = normal; + notify.known_trx.ids.push_back( txn_id ); + notify.known_blocks.mode = none; + my_impl->send_all(notify, [txn_id](connection_ptr conn) -> bool { + const auto& bs = conn->trx_state.find(txn_id); + bool unknown = bs == conn->trx_state.end(); + if (unknown) { + conn->trx_state.insert(transaction_state({txn_id,false,true,(uint32_t)-1, fc::time_point(), fc::time_point() })); + } + else { + + } + return unknown; + }); + } + else { + bcast_transaction(msg, c); + } + } + + void big_msg_manager::recv_notice (connection_ptr c, const notice_message& msg) { + request_message req; + bool send_req = false; + chain_controller &cc = my_impl->chain_plug->chain(); + if (msg.known_trx.mode == normal) { + req.req_trx.mode = normal; + req.req_trx.pending = 0; + for( const auto& t : msg.known_trx.ids ) { + const auto &tx = my_impl->local_txns.get( ).find( t ); + + if( tx == my_impl->local_txns.end( ) ) { + c->trx_state.insert( ( transaction_state ){ t,true,true,( uint32_t ) - 1, + fc::time_point( ),fc::time_point( ) } ); + + req.req_trx.ids.push_back( t ); + req_txn.push_back( t ); + } + } + send_req = !req.req_trx.ids.empty(); + } + else if (msg.known_trx.mode != none) { + elog ("passed a notice_message with something other than a normal on none known_trx"); + return; + } + if (msg.known_blocks.mode == normal) { + req.req_blocks.mode = normal; + for( const auto& blkid : msg.known_blocks.ids) { + optional b; + try { + b = cc.fetch_block_by_id(blkid); + } catch (const assert_exception &ex) { + ilog( "caught assert on fetch_block_by_id, ${ex}",("ex",ex.what())); + // keep going, client can ask another peer + } catch (...) { + elog( "failed to retrieve block for id"); + } + if(b) { + bool known=true; + bool noticed=true; + c->blk_state.insert((block_state){blkid,known,noticed,fc::time_point::now()}); + send_req = true; + req.req_blocks.ids.push_back( blkid ); + req_blks.push_back( blkid ); + } + } + } + else if (msg.known_blocks.mode != none) { + elog ("passed a notice_message with something other than a normal on none known_blocks"); + return; + } + fc_dlog( logger, "send req = ${sr}", ("sr",send_req)); + if( send_req) { + c->enqueue(req); + } + + } + + //------------------------------------------------------------------------ + + void net_plugin_impl::connect( connection_ptr c ) { + if( c->no_retry != go_away_reason::no_reason) { + fc_dlog( logger, "Skipping connect due to go_away reason ${r}",("r", reason_str( c->no_retry ))); + return; + } + + auto colon = c->peer_addr.find(':'); + + if (colon == std::string::npos || colon == 0) { + elog ("Invalid peer address. must be \"host:port\": ${p}", ("p",c->peer_addr)); + return; + } + + auto host = c->peer_addr.substr( 0, colon ); + auto port = c->peer_addr.substr( colon + 1); + idump((host)(port)); + tcp::resolver::query query( tcp::v4(), host.c_str(), port.c_str() ); + // Note: need to add support for IPv6 too + + resolver->async_resolve( query, + [c, this]( const boost::system::error_code& err, + tcp::resolver::iterator endpoint_itr ){ + if( !err ) { + connect( c, endpoint_itr ); + } else { + elog( "Unable to resolve ${peer_addr}: ${error}", + ( "peer_addr", c->peer_name() )("error", err.message() ) ); + } + }); + } + + void net_plugin_impl::connect( connection_ptr c, tcp::resolver::iterator endpoint_itr ) { + if( c->no_retry != go_away_reason::no_reason) { + string rsn = reason_str(c->no_retry); + return; + } + auto current_endpoint = *endpoint_itr; + ++endpoint_itr; + c->connecting = true; + c->socket->async_connect( current_endpoint, [c, endpoint_itr, this] ( const boost::system::error_code& err ) { + if( !err ) { + start_session( c ); + c->send_handshake (); + } else { + if( endpoint_itr != tcp::resolver::iterator() ) { + c->close(); + connect( c, endpoint_itr ); + } + else { + elog( "connection failed to ${peer}: ${error}", + ( "peer", c->peer_name())("error",err.message())); + c->connecting = false; + my_impl->close(c); + } + } + } ); + } + + void net_plugin_impl::start_session( connection_ptr con ) { + boost::asio::ip::tcp::no_delay nodelay( true ); + con->socket->set_option( nodelay ); + start_read_message( con ); + ++started_sessions; + + // for now, we can just use the application main loop. + // con->readloop_complete = bf::async( [=](){ read_loop( con ); } ); + // con->writeloop_complete = bf::async( [=](){ write_loop con ); } ); + } + + + void net_plugin_impl::start_listen_loop( ) { + auto socket = std::make_shared( std::ref( app().get_io_service() ) ); + acceptor->async_accept( *socket, [socket,this]( boost::system::error_code ec ) { + if( !ec ) { + uint32_t visitors = 0; + for (auto &conn : connections) { + if(conn->current() && conn->peer_addr.empty()) { + visitors++; + } + } + if (num_clients != visitors) { + ilog ("checking max client, visitors = ${v} num clients ${n}",("v",visitors)("n",num_clients)); + num_clients = visitors; + } + if( max_client_count == 0 || num_clients < max_client_count ) { + ++num_clients; + connection_ptr c = std::make_shared( socket ); + connections.insert( c ); + start_session( c ); + } else { + elog( "Error max_client_count ${m} exceeded", + ( "m", max_client_count) ); + socket->close( ); + } + start_listen_loop(); + } else { + elog( "Error accepting connection: ${m}",( "m", ec.message() ) ); + } + }); + } + + void net_plugin_impl::start_read_message( connection_ptr conn ) { + + try { + if(!conn->socket) { + return; + } + conn->socket->async_read_some + (conn->pending_message_buffer.get_buffer_sequence_for_boost_async_read(), + [this,conn]( boost::system::error_code ec, std::size_t bytes_transferred ) { + try { + if( !ec ) { + if (bytes_transferred > conn->pending_message_buffer.bytes_to_write()) { + elog("async_read_some callback: bytes_transfered = ${bt}, buffer.bytes_to_write = ${btw}", + ("bt",bytes_transferred)("btw",conn->pending_message_buffer.bytes_to_write())); + } + FC_ASSERT(bytes_transferred <= conn->pending_message_buffer.bytes_to_write()); + conn->pending_message_buffer.advance_write_ptr(bytes_transferred); + while (conn->pending_message_buffer.bytes_to_read() > 0) { + uint32_t bytes_in_buffer = conn->pending_message_buffer.bytes_to_read(); + + if (bytes_in_buffer < message_header_size) { + break; + } else { + uint32_t message_length; + auto index = conn->pending_message_buffer.read_index(); + conn->pending_message_buffer.peek(&message_length, sizeof(message_length), index); + if(message_length > def_send_buffer_size*2) { + elog("incoming message length unexpected (${i})", ("i", message_length)); + close(conn); + return; + } + if (bytes_in_buffer >= message_length + message_header_size) { + conn->pending_message_buffer.advance_read_ptr(message_header_size); + if (!conn->process_next_message(*this, message_length)) { + return; + } + } else { + conn->pending_message_buffer.add_space(message_length + message_header_size - bytes_in_buffer); + break; + } + } + } + start_read_message(conn); + } else { + auto pname = conn->peer_name(); + if (ec.value() != boost::asio::error::eof) { + elog( "Error reading message from ${p}: ${m}",("p",pname)( "m", ec.message() ) ); + } else { + ilog( "Peer ${p} closed connection",("p",pname) ); + } + close( conn ); + } + } + catch(const std::exception &ex) { + string pname = conn ? conn->peer_name() : "no connection name"; + elog("Exception in handling read data from ${p} ${s}",("p",pname)("s",ex.what())); + close( conn ); + } + catch(const fc::exception &ex) { + string pname = conn ? conn->peer_name() : "no connection name"; + elog("Exception in handling read data ${s}", ("p",pname)("s",ex.to_string())); + close( conn ); + } + catch (...) { + string pname = conn ? conn->peer_name() : "no connection name"; + elog( "Undefined exception hanlding the read data from connection ${p}",( "p",pname)); + close( conn ); + } + } ); + } catch (...) { + string pname = conn ? conn->peer_name() : "no connection name"; + elog( "Undefined exception handling reading ${p}",("p",pname) ); + close( conn ); + } + } + + size_t net_plugin_impl::count_open_sockets() const + { + size_t count = 0; + for( auto &c : connections) { if(c->socket->is_open()) ++count; } @@ -1494,7 +1922,7 @@ namespace eosio { } void net_plugin_impl::handle_message( connection_ptr c, const handshake_message &msg) { - ilog("got a handshake_message from ${p} ${h}", ("p",c->peer_addr)("h",msg.p2p_address)); + fc_dlog( logger, "got a handshake_message from ${p} ${h}", ("p",c->peer_addr)("h",msg.p2p_address)); if (!is_valid(msg)) { elog( "Invalid handshake message received from ${p} ${h}", ("p",c->peer_addr)("h",msg.p2p_address)); c->enqueue( go_away_message( fatal_other )); @@ -1526,8 +1954,8 @@ namespace eosio { if (msg.time + c->last_handshake_sent.time <= check->last_handshake_sent.time + check->last_handshake_recv.time) continue; - fc_dlog(logger, "sending go_away duplicate to ${ep}", ("ep",msg.p2p_address) ); - go_away_message gam(go_away_reason::duplicate); + fc_dlog( logger, "sending go_away duplicate to ${ep}", ("ep",msg.p2p_address) ); + go_away_message gam(duplicate); gam.node_id = node_id; c->enqueue(gam); c->no_retry = duplicate; @@ -1574,6 +2002,10 @@ namespace eosio { block_id_type peer_lib_id = cc.get_block_id_for_num( peer_lib); on_fork =( msg.last_irreversible_block_id != peer_lib_id); } + catch( const unknown_block_exception &ex) { + wlog( "peer last irreversible block ${pl} is unknown", ("pl", peer_lib)); + on_fork = true; + } catch( ...) { wlog( "caught an exception getting block id for ${pl}",("pl",peer_lib)); on_fork = true; @@ -1591,83 +2023,15 @@ namespace eosio { } c->last_handshake_recv = msg; - sync_master->reset_lib_num(); - c->syncing = false; - - //-------------------------------- - // sync need checkz; - // - // 0. my head block id == peer head id means we are all caugnt up block wise - // 1. my head block num < peer lib - start sync locally - // 2. my lib > peer head num - send an last_irr_catch_up notice if not the first generation - // - // 3 my head block num <= peer head block num - update sync state and send a catchup request - // 4 my head block num > peer block num ssend a notice catchup if this is not the first generation - // - //----------------------------- - - uint32_t head = cc.head_block_num( ); - block_id_type head_id = cc.head_block_id(); - if (head_id == msg.head_id) { - fc_dlog(logger, "sync check state 0"); - notice_message note; - note.known_blocks.mode = none; - note.known_trx.mode = catch_up; - note.known_trx.pending = local_txns.size(); - c->enqueue( note ); - return; - } - if (head < peer_lib) { - fc_dlog(logger, "sync check state 1"); - sync_master->start_sync( c, peer_lib); - return; - } - if (lib_num > msg.head_num ) { - fc_dlog(logger, "sync check state 2"); - if ( msg.generation > 1 ) { - notice_message note; - note.known_trx.pending = head; - note.known_trx.mode = last_irr_catch_up; - note.known_blocks.mode = last_irr_catch_up; - note.known_blocks.pending = lib_num; - c->enqueue( note ); - } - c->syncing = true; - return; - } - - if (head <= msg.head_num ) { - fc_dlog(logger, "sync check state 3 (skipped = ${s}",("s", sync_master->active)); - if (!sync_master->active ) { - request_message req; - req.req_trx.mode = none; - req.req_blocks.mode = catch_up; - req.req_blocks.pending = lib_num; - c->enqueue( req ); - } - return; - } - else { - fc_dlog(logger, "sync check state 4"); - if ( msg.generation > 1 ) { - notice_message note; - note.known_trx.mode = none; - note.known_blocks.mode = catch_up; - note.known_blocks.pending = head - lib_num; - c->enqueue( note ); - } - c->syncing = true; - return; - } - elog ("sync check failed to resolve status"); - return; + sync_master->recv_handshake(c,msg); } void net_plugin_impl::handle_message( connection_ptr c, const go_away_message &msg ) { string rsn = reason_str( msg.reason ); - ilog( "received a go away message, reason = ${r}",("r",rsn)); + ilog( "received a go away message from ${p}, reason = ${r}", + ("p", c->peer_name())("r",rsn)); c->no_retry = msg.reason; - if(msg.reason == go_away_reason::duplicate ) { + if(msg.reason == duplicate ) { c->node_id = msg.node_id; } c->flush_queues(); @@ -1711,17 +2075,14 @@ namespace eosio { // notices of previously unknown blocks or txns, // fc_dlog(logger, "got a notice_message from ${p}", ("p",c->peer_name())); - notice_message fwd; request_message req; bool send_req = false; - chain_controller &cc = chain_plug->chain(); switch (msg.known_trx.mode) { case none: break; case last_irr_catch_up: { c->last_handshake_recv.head_num = msg.known_trx.pending; req.req_trx.mode = none; - fwd.known_trx.mode = none; break; } case catch_up : { @@ -1739,24 +2100,7 @@ namespace eosio { break; } case normal: { - fwd.known_trx.mode = normal; - fwd.known_trx.pending = 0; - req.req_trx.mode = normal; - req.req_trx.pending = 0; - for( const auto& t : msg.known_trx.ids ) { - const auto &tx = my_impl->local_txns.get( ).find( t ); - - if( tx == my_impl->local_txns.end( ) ) { - c->trx_state.insert( ( transaction_state ){ t,true,true,( uint32_t ) - 1, - fc::time_point( ),fc::time_point( ) } ); - - if( !sync_master->active ) { - fwd.known_trx.ids.push_back( t ); - } - req.req_trx.ids.push_back( t ); - } - } - send_req = !req.req_trx.ids.empty(); + bm_master->recv_notice (c, msg); } } @@ -1769,87 +2113,19 @@ namespace eosio { } break; } - case last_irr_catch_up : { - c->last_handshake_recv.last_irreversible_block_num = msg.known_trx.pending; - sync_master->reset_lib_num (); - if (!c->sync_receiving ) { - - sync_master->start_sync(c, msg.known_blocks.pending); - } - break; - } - case catch_up : { - req.req_blocks.mode = catch_up; - req.req_blocks.pending = msg.known_blocks.pending; - send_req = true; + case last_irr_catch_up: + case catch_up: { + sync_master->recv_notice(c,msg); break; } case normal : { - req.req_blocks.mode = normal; - for( const auto& blkid : msg.known_blocks.ids) { - optional b; - try { - b = cc.fetch_block_by_id(blkid); - } catch (const assert_exception &ex) { - elog( "caught assert on fetch_block_by_id, ${ex}",("ex",ex.what())); - // keep going, client can ask another peer - } catch (...) { - elog( "failed to retrieve block for id"); - } - if(!b) { - c->block_state.insert((block_state){blkid,false,true,fc::time_point::now()}); - fwd.known_blocks.ids.push_back(blkid); - send_req = true; - req.req_blocks.ids.push_back(blkid); - } - } + bm_master->recv_notice (c, msg); break; } default: { fc_dlog(logger, "received a bogus known_blocks.mode ${m} from ${p}",("m",static_cast(msg.known_blocks.mode))("p",c->peer_name())); } } - - if (fwd.known_trx.mode == normal || - fwd.known_blocks.mode == normal) { - for (auto &conn : my_impl->connections) { - if (conn->syncing || conn == c) { - continue; - } - notice_message to_peer; - to_peer.known_trx.mode = fwd.known_trx.mode; - if (fwd.known_trx.mode == normal) { - for (const auto &t : fwd.known_trx.ids) { - const auto &tx = conn->trx_state.get( ).find( t ); - if( tx == conn->trx_state.end( ) ) { - conn->trx_state.insert((transaction_state){t,false,true,(uint32_t)-1, - fc::time_point(),fc::time_point()}); - to_peer.known_trx.ids.push_back( t ); - } - } - if (to_peer.known_trx.ids.empty()) { - to_peer.known_trx.mode = none; - } - } - to_peer.known_blocks.mode = fwd.known_blocks.mode; - if (fwd.known_blocks.mode == normal) { - for (const auto &bid : fwd.known_blocks.ids) { - const auto &blk = conn->block_state.get( ).find( bid ); - if( blk == conn->block_state.end( ) ) { - conn->block_state.insert((block_state){bid,false,true,fc::time_point()} ); - to_peer.known_blocks.ids.push_back( bid ); - } - } - if (to_peer.known_blocks.ids.empty()) { - to_peer.known_blocks.mode = none; - } - } - if (to_peer.known_trx.mode == normal || - to_peer.known_blocks.mode == normal) { - conn->enqueue (to_peer); - } - } - } fc_dlog(logger, "send req = ${sr}", ("sr",send_req)); if( send_req) { c->enqueue(req); @@ -1859,8 +2135,8 @@ namespace eosio { void net_plugin_impl::handle_message( connection_ptr c, const request_message &msg) { switch (msg.req_blocks.mode) { case catch_up : - fc_dlog(logger, "got a catch_up request_message from ${p}", ("p",c->peer_name())); - c->blk_send_branch( msg.req_trx.ids ); + fc_dlog( logger, "got a catch_up request_message from ${p}", ("p",c->peer_name())); + c->blk_send_branch( ); break; case normal : fc_dlog(logger, "got a normal request_message from ${p}", ("p",c->peer_name())); @@ -1912,7 +2188,7 @@ namespace eosio { return; } } - if( sync_master->active ) { + if( sync_master->is_active(c) ) { fc_dlog(logger, "got a txn during sync - dropping"); return; } @@ -1920,9 +2196,6 @@ namespace eosio { if(entry != local_txns.end( ) ) { local_txns.modify( entry, update_entry( msg ) ); } - else { - cache_txn(txnid, msg); - } auto tx = c->trx_state.find(txnid); if( tx == c->trx_state.end()) { @@ -1955,112 +2228,46 @@ namespace eosio { } void net_plugin_impl::handle_message( connection_ptr c, const signed_block &msg) { - fc_dlog(logger, "got signed_block #${n} from ${p}", ("n",msg.block_num())("p",c->peer_name())); chain_controller &cc = chain_plug->chain(); block_id_type blk_id = msg.id(); - bool has_chunk = false; - uint32_t num = msg.block_num(); - bool syncing = sync_master->active; + uint32_t blk_num = msg.block_num(); + try { if( cc.is_known_block(blk_id)) { return; } } catch( ...) { + // should this even be caught? + elog("Caught an unknown exception trying to recall blockID"); } - if( cc.head_block_num() >= msg.block_num()) { - elog( "received forking block #${n} from ${p}",( "n",num)("p",c->peer_name())); - } - fc::microseconds age( fc::time_point::now() - msg.timestamp); - fc_dlog(logger, "got signed_block #${n} from ${p} block age in secs = ${age}",("n",msg.block_num())("p",c->peer_name())("age",age.to_seconds())); - if( syncing ) { - has_chunk =( c->sync_receiving && c->sync_receiving->end_block > 0); + fc::microseconds age( fc::time_point::now() - msg.timestamp); + fc_dlog(logger, "got signed_block #${n} from ${p} block age in secs = ${age}", + ("n",blk_num)("p",c->peer_name())("age",age.to_seconds())); - if( !has_chunk) { - if(c->sync_receiving) - elog("got a block while syncing but sync_receiving end block == 0 #${n} from ${p}", ( "n",num)("p",c->peer_name())); - else - elog("got a block while syncing but no sync_receiving set #${n} from ${p}", ( "n",num)("p",c->peer_name())); - } - else { - if( c->sync_receiving->last + 1 != num) { - wlog( "expected block ${next} but got ${num} from ${p}",("next",c->sync_receiving->last+1)("num",num)("p",c->peer_name())); - sync_master->reassign_fetch(c,benign_other); - return; - } - c->sync_receiving->last = num; - } - } go_away_reason reason = fatal_other; - fc_dlog(logger, "last irreversible block = ${lib}", ("lib", cc.last_irreversible_block_num())); - if( !syncing || num == cc.head_block_num()+1 ) { - try { - chain_plug->accept_block(msg, syncing); - reason = no_reason; - } catch( const unlinkable_block_exception &ex) { - elog( "unlinkable_block_exception accept block #${n} syncing from ${p}",("n",num)("p",c->peer_name())); - reason = unlinkable; - } catch( const block_validate_exception &ex) { - elog( "block_validate_exception accept block #${n} syncing from ${p}",("n",num)("p",c->peer_name())); - reason = validation; - } catch( const assert_exception &ex) { - elog( "unable to accept block on assert exception ${n} from ${p}",("n",ex.to_string())("p",c->peer_name())); - } catch( const fc::exception &ex) { - elog( "accept_block threw a non-assert exception ${x} from ${p}",( "x",ex.to_string())("p",c->peer_name())); - reason = no_reason; - } catch( ...) { - elog( "handle sync block caught something else from ${p}",("num",num)("p",c->peer_name())); - } - } - - if( has_chunk) { - if( reason != no_reason ) { - wlog("block ${num}, ${bid} not accepted from ${p}",("num",num)("p",c->peer_name())("bid",blk_id)); - sync_master->reassign_fetch(c,reason); - } - - if( num == c->sync_receiving->end_block) { - sync_master->take_chunk( c); - } else { - c->sync_wait( ); - } + try { + chain_plug->accept_block(msg, sync_master->is_active(c)); + reason = no_reason; + } catch( const unlinkable_block_exception &ex) { + elog( "unlinkable_block_exception accept block #${n} syncing from ${p}",("n",blk_num)("p",c->peer_name())); + reason = unlinkable; + } catch( const block_validate_exception &ex) { + elog( "block_validate_exception accept block #${n} syncing from ${p}",("n",blk_num)("p",c->peer_name())); + reason = validation; + } catch( const assert_exception &ex) { + elog( "unable to accept block on assert exception ${n} from ${p}",("n",ex.to_string())("p",c->peer_name())); + } catch( const fc::exception &ex) { + elog( "accept_block threw a non-assert exception ${x} from ${p}",( "x",ex.to_string())("p",c->peer_name())); + reason = no_reason; + } catch( ...) { + elog( "handle sync block caught something else from ${p}",("num",blk_num)("p",c->peer_name())); } - else { - if( reason == unlinkable ) { - ilog("See if we can re-request the missing block"); - - handshake_message hello; - handshake_initializer::populate(hello); - for( auto &ci : my_impl->connections) { - if( ci->current()) { - hello.generation = ++ci->sent_handshake_count; - ci->last_handshake_sent = hello; - fc_dlog(logger, "send to ${p}", ("p",ci->peer_name())); - ci->enqueue( hello ); - } - } - } - else { - if(age < fc::seconds(3) && fc::raw::pack_size(msg) < just_send_it_max && !c->syncing ) { - fc_dlog(logger, "forwarding the signed block"); - send_all( msg, [c, blk_id, num](connection_ptr conn) -> bool { - bool sendit = false; - if( c != conn && !conn->syncing ) { - auto b = conn->block_state.get().find(blk_id); - if(b == conn->block_state.end()) { - conn->block_state.insert( (block_state){blk_id,true,true,fc::time_point()}); - sendit = true; - } else if (!b->is_known) { - conn->block_state.modify(b,make_known()); - sendit = true; - } - } - fc_dlog(logger, "${action} block ${num} to ${c}",("action", sendit ? "sending " : "skipping ")("num",num)("c", conn->peer_name() )); - return sendit; - }); - } - } + + if( reason == no_reason ) { + bm_master->recv_block (c, msg); } + sync_master->recv_block (c, msg, reason == no_reason); } void net_plugin_impl::start_conn_timer( ) { @@ -2156,106 +2363,17 @@ namespace eosio { --num_clients; } c->close(); - if( c->sync_receiving) - sync_master->take_chunk( c); - } - - - size_t net_plugin_impl::cache_txn(const transaction_id_type txnid, - const signed_transaction& txn ) { - net_message msg(txn); - uint32_t packsiz = fc::raw::pack_size(msg); - uint32_t bufsiz = packsiz + sizeof(packsiz); - vector buff(bufsiz); - fc::datastream ds( buff.data(), bufsiz); - ds.write( reinterpret_cast(&packsiz), sizeof(packsiz) ); - - fc::raw::pack( ds, msg ); - - uint16_t bn = static_cast(txn.ref_block_num); - node_transaction_state nts = {txnid,time_point::now(), - txn.expiration, - txn.expiration, - buff, - bn, true}; - local_txns.insert(nts); - return bufsiz; - } - - void net_plugin_impl::send_all_txn( const signed_transaction& txn) { - transaction_id_type txnid = txn.id(); - if( local_txns.get().find( txnid ) != local_txns.end( ) ) { //found - fc_dlog(logger, "found txnid in local_txns" ); - return; - } - - size_t bufsiz = cache_txn(txnid, txn); - fc_dlog(logger, "bufsiz = ${bs} max = ${max}",("bs", (uint32_t)bufsiz)("max", just_send_it_max)); - - if( bufsiz <= just_send_it_max) { - send_all( txn, [txn, txnid](connection_ptr c) -> bool { - const auto& bs = c->trx_state.find(txnid); - bool unknown = bs == c->trx_state.end(); - if( unknown) { - c->trx_state.insert(transaction_state({txnid,true,true,(uint32_t)-1, - fc::time_point(),fc::time_point() })); - fc_dlog(logger, "sending whole txn to ${n}", ("n",c->peer_name() ) ); - } - return unknown; - }); - } - else { - notice_message pending_notify; - pending_notify.known_trx.mode = normal; - pending_notify.known_trx.ids.push_back( txnid ); - pending_notify.known_blocks.mode = none; - send_all(pending_notify, [txnid](connection_ptr c) -> bool { - const auto& bs = c->trx_state.find(txnid); - bool unknown = bs == c->trx_state.end(); - if( unknown) { - - fc_dlog(logger, "sending notice to ${n}", ("n",c->peer_name() ) ); - c->trx_state.insert(transaction_state({txnid,false,true,(uint32_t)-1, - fc::time_point(),fc::time_point() })); - } - return unknown; - }); - } - } + } /** * This one is necessary to hook into the boost notifier api **/ void net_plugin_impl::transaction_ready( const packed_transaction& txn) { - // TODO: avoid this reserialization by updating protocol to use packed_transactions directly - auto strx = signed_transaction(txn.get_transaction(), txn.signatures); - my_impl->send_all_txn( strx ); + my_impl->bm_master->bcast_transaction( txn ); } void net_plugin_impl::broadcast_block_impl( const chain::signed_block &sb) { - net_message msg(sb); - uint32_t packsiz = fc::raw::pack_size(msg); - uint32_t msgsiz = packsiz + sizeof(packsiz); - - if (msgsiz <= just_send_it_max) { - send_all( sb,[](connection_ptr c) -> bool { return true; }); - } - else { - notice_message pending_notify; - block_id_type bid = sb.id(); - pending_notify.known_blocks.mode = normal; - pending_notify.known_blocks.ids.push_back( bid ); - pending_notify.known_trx.mode = none; - send_all(pending_notify, [bid](connection_ptr c) -> bool { - const auto& bs = c->block_state.find(bid); - bool unknown = bs == c->block_state.end(); - if( unknown) { - fc_dlog(logger, "sending block notice to ${n}", ("n",c->peer_name() ) ); - c->block_state.insert(block_state({bid,false,true,fc::time_point() })); - } - return unknown; - }); - } + bm_master->bcast_block(sb); } bool net_plugin_impl::authenticate_peer(const handshake_message& msg) const { @@ -2428,6 +2546,7 @@ namespace eosio { fc::get_logger_map()[connection::logger_name] = connection::logger; fc::get_logger_map()[net_plugin_impl::logger_name] = net_plugin_impl::logger; fc::get_logger_map()[sync_manager::logger_name] = sync_manager::logger; + fc::get_logger_map()[big_msg_manager::logger_name] = big_msg_manager::logger; // Setting a parent would in theory get us the default appenders for free but // a) the parent's log level overrides our own in that case; and @@ -2436,6 +2555,7 @@ namespace eosio { connection::logger.add_appender(appender); net_plugin_impl::logger.add_appender(appender); sync_manager::logger.add_appender(appender); + big_msg_manager::logger.add_appender(appender); } if( options.count( "log-level-net-plugin" ) ) { @@ -2446,6 +2566,7 @@ namespace eosio { connection::logger.set_log_level(logl); net_plugin_impl::logger.set_log_level(logl); sync_manager::logger.set_log_level(logl); + big_msg_manager::logger.set_log_level(logl); } my->network_version = static_cast(app().version()); @@ -2453,11 +2574,12 @@ namespace eosio { my->send_whole_blocks = def_send_whole_blocks; my->sync_master.reset( new sync_manager(options.at("sync-fetch-span").as() ) ); + my->bm_master.reset( new big_msg_manager ); my->connector_period = std::chrono::seconds(options.at("connection-cleanup-period").as()); my->txn_exp_period = def_txn_expire_wait; my->resp_expected_period = def_resp_expected_wait; - my->just_send_it_max = def_max_just_send; + my->bm_master->just_send_it_max = def_max_just_send; my->max_client_count = options.at("max-clients").as(); my->num_clients = 0; @@ -2585,7 +2707,9 @@ namespace eosio { my->acceptor.reset(nullptr); } ilog( "exit shutdown" ); - } FC_CAPTURE_AND_RETHROW() } + } + FC_CAPTURE_AND_RETHROW() + } void net_plugin::broadcast_block( const chain::signed_block &sb) { fc_dlog(my->logger, "broadcasting block #${num}",("num",sb.block_num()) ); diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 25fc9abb1fbcc463f88c4b00e9234c08b551393f..4f2333ff34839badc36094ad2580643ffa5f7c50 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -224,7 +224,7 @@ block_production_condition::block_production_condition_enum producer_plugin_impl ilog("Not producing block because production is disabled until we receive a recent block (see: --enable-stale-production)"); break; case block_production_condition::not_my_turn: - ilog("Not producing block because it isn't my turn"); + ilog("Not producing block because it isn't my turn, its ${scheduled_producer}", (capture) ); break; case block_production_condition::not_time_yet: ilog("Not producing block because slot has not yet arrived"); diff --git a/plugins/txn_test_gen_plugin/CMakeLists.txt b/plugins/txn_test_gen_plugin/CMakeLists.txt index 44091b38850c7035716cf28cdaef844c4669820b..74ccd7c6046b7eea82642ce669e6795836a8219d 100644 --- a/plugins/txn_test_gen_plugin/CMakeLists.txt +++ b/plugins/txn_test_gen_plugin/CMakeLists.txt @@ -1,3 +1,4 @@ +if(WASM_TOOLCHAIN) file(GLOB HEADERS "include/eosio/txn_test_gen_plugin/*.hpp") add_library( txn_test_gen_plugin txn_test_gen_plugin.cpp @@ -5,6 +6,7 @@ add_library( txn_test_gen_plugin target_link_libraries( txn_test_gen_plugin appbase fc http_plugin chain_plugin ) target_include_directories( txn_test_gen_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) +target_include_directories( txn_test_gen_plugin PUBLIC ${CMAKE_BINARY_DIR}/contracts ) install( TARGETS txn_test_gen_plugin @@ -14,3 +16,5 @@ install( TARGETS ARCHIVE DESTINATION lib ) install( FILES ${HEADERS} DESTINATION "include/eosio/txn_test_gen_plugin" ) + +endif() \ No newline at end of file diff --git a/plugins/txn_test_gen_plugin/README.md b/plugins/txn_test_gen_plugin/README.md index 048a6971e01cfea8eee228da1b5beb3d8d9fc07b..96c92c0f493972b870e11af9947f37bef646cc7a 100644 --- a/plugins/txn_test_gen_plugin/README.md +++ b/plugins/txn_test_gen_plugin/README.md @@ -1,10 +1,10 @@ # txn\_test\_gen\_plugin -This plugin provides a way to generate a given amount of test transactions per second. It runs internally to eosd to reduce overhead. +This plugin provides a way to generate a given amount of transactions per second against the currency contract. It runs internally to eosd to reduce overhead. ## Setup -Create the two accounts used for transactions. Must give account & private key used for creation. +Create the two accounts used for transactions and set the currency contract code. Must give account & private key used for creation. ``` curl --data-binary '["inita", "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"]' http://localhost:7777/v1/txn_test_gen/create_test_accounts @@ -15,10 +15,11 @@ curl --data-binary '["inita", "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvF Start generation: ``` -curl --data-binary '["one", 400]' http://localhost:7777/v1/txn_test_gen/start_generation +curl --data-binary '["one", 20, 16]' http://localhost:7777/v1/txn_test_gen/start_generation ``` -First parameter is some "salt" added to the transaction memos to ensure if this test is being run on other nodes concurrently no identical transactions are created. The second parameter is the requested transactions per second. This knob is currently quite crude so you don't always get what you ask for. Also, 400 is the limit. +First parameter is some "salt" added to the transaction memos to ensure if this test is being run on other nodes concurrently no identical transactions are created. The second parameter is the frequency in milliseconds to wake up and send transactions. The third parameter is how many transactions to send on each wake up (must be an even number). There are some constraints on these numbers to prevent anything too wild. + Stop generation ``` diff --git a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp index 60224f41c8260e6fb99173a5fd33b5669447c3dd..5e4e484299c0dc9112ae340c724ac47ddcfc0efb 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -4,16 +4,28 @@ */ #include #include +#include #include #include #include #include #include +#include #include #include +#include +#include +#include +#include +#include +#include + +#include +#include + namespace eosio { namespace detail { struct txn_test_gen_empty {}; }} @@ -44,6 +56,11 @@ using namespace eosio::chain; } \ }} +#define INVOKE_V_R_R_R(api_handle, call_name, in_param0, in_param1, in_param2) \ + const auto& vs = fc::json::json::from_string(body).as(); \ + api_handle->call_name(vs.at(0).as(), vs.at(1).as(), vs.at(2).as()); \ + eosio::detail::txn_test_gen_empty result; + #define INVOKE_V_R_R(api_handle, call_name, in_param0, in_param1) \ const auto& vs = fc::json::json::from_string(body).as(); \ api_handle->call_name(vs.at(0).as(), vs.at(1).as()); \ @@ -57,8 +74,11 @@ struct txn_test_gen_plugin_impl { void create_test_accounts(const std::string& init_name, const std::string& init_priv_key) { name newaccountA("txn.test.a"); name newaccountB("txn.test.b"); + name newaccountC("currency"); name creator(init_name); + contracts::abi_def currency_abi_def = fc::json::from_string(currency_abi).as(); + chain_controller& cc = app().get_plugin().chain(); chain::chain_id_type chainid; app().get_plugin().get_chain_id(chainid); @@ -66,23 +86,25 @@ struct txn_test_gen_plugin_impl { fc::crypto::private_key txn_test_receiver_A_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); fc::crypto::private_key txn_test_receiver_B_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); + fc::crypto::private_key txn_test_receiver_C_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'c'))); fc::crypto::public_key txn_text_receiver_A_pub_key = txn_test_receiver_A_priv_key.get_public_key(); fc::crypto::public_key txn_text_receiver_B_pub_key = txn_test_receiver_B_priv_key.get_public_key(); + fc::crypto::public_key txn_text_receiver_C_pub_key = txn_test_receiver_C_priv_key.get_public_key(); fc::crypto::private_key creator_priv_key = fc::crypto::private_key(init_priv_key); - //stake some currency; and then create some test accounts + + //create some test accounts auto memo = fc::variant(fc::time_point::now()).as_string() + " " + fc::variant(fc::time_point::now().time_since_epoch()).as_string(); signed_transaction trx; trx.expiration = cc.head_block_time() + fc::seconds(30); trx.set_reference_block(cc.head_block_id()); - trx.actions.emplace_back(vector{{creator,"active"}}, contracts::lock{creator, creator, 300}); //create "A" account { auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}}; auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}}; auto recovery_auth = eosio::chain::authority{1, {}, {{{creator, "active"}, 1}}}; - trx.actions.emplace_back(vector{{creator,"active"}}, contracts::newaccount{creator, newaccountA, owner_auth, active_auth, recovery_auth, stake}); + trx.actions.emplace_back(vector{{creator,"active"}}, contracts::newaccount{creator, newaccountA, owner_auth, active_auth, recovery_auth}); } //create "B" account { @@ -90,33 +112,106 @@ struct txn_test_gen_plugin_impl { auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_B_pub_key, 1}}, {}}; auto recovery_auth = eosio::chain::authority{1, {}, {{{creator, "active"}, 1}}}; - trx.actions.emplace_back(vector{{creator,"active"}}, contracts::newaccount{creator, newaccountB, owner_auth, active_auth, recovery_auth, stake}); + trx.actions.emplace_back(vector{{creator,"active"}}, contracts::newaccount{creator, newaccountB, owner_auth, active_auth, recovery_auth}); + } + //create "currency" account + { + auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_C_pub_key, 1}}, {}}; + auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_C_pub_key, 1}}, {}}; + auto recovery_auth = eosio::chain::authority{1, {}, {{{creator, "active"}, 1}}}; + + trx.actions.emplace_back(vector{{creator,"active"}}, contracts::newaccount{creator, newaccountC, owner_auth, active_auth, recovery_auth}); } + trx.sign(creator_priv_key, chainid); cc.push_transaction(packed_transaction(trx)); - //now, transfer some balance to new accounts + //create currency contract { - uint64_t balance = 10000; signed_transaction trx; - trx.actions.emplace_back(vector{{creator,"active"}}, contracts::transfer{creator, newaccountA, balance, memo}); - trx.actions.emplace_back(vector{{creator,"active"}}, contracts::transfer{creator, newaccountB, balance, memo}); - trx.expiration = cc.head_block_time() + fc::seconds(30); + vector wasm = wast_to_wasm(std::string(currency_wast)); + + contracts::setcode handler; + handler.account = newaccountC; + handler.code.assign(wasm.begin(), wasm.end()); + + trx.actions.emplace_back( vector{{newaccountC,"active"}}, handler); + + { + contracts::setabi handler; + handler.account = newaccountC; + handler.abi = currency_abi_def; + trx.actions.emplace_back( vector{{newaccountC,"active"}}, handler); + } + trx.set_reference_block(cc.head_block_id()); - trx.sign(creator_priv_key, chainid); + trx.sign(txn_test_receiver_C_priv_key, chainid); + cc.push_transaction(packed_transaction(trx)); + } + + //issue & fund the two accounts with currency contract currency + { + signed_transaction trx; + abi_serializer currency_serializer(currency_abi_def); + + { + action act; + act.account = N(currency); + act.name = N(issue); + act.authorization = vector{{newaccountC,config::active_name}}; + act.data = currency_serializer.variant_to_binary("issue", fc::json::from_string("{\"to\":\"currency\",\"quantity\":\"600.0000 CUR\"}")); + trx.actions.push_back(act); + } + { + action act; + act.account = N(currency); + act.name = N(transfer); + act.authorization = vector{{newaccountC,config::active_name}}; + act.data = currency_serializer.variant_to_binary("transfer", fc::json::from_string("{\"from\":\"currency\",\"to\":\"txn.test.a\",\"quantity\":\"200.0000 CUR\",\"memo\":\"\"}")); + trx.actions.push_back(act); + } + { + action act; + act.account = N(currency); + act.name = N(transfer); + act.authorization = vector{{newaccountC,config::active_name}}; + act.data = currency_serializer.variant_to_binary("transfer", fc::json::from_string("{\"from\":\"currency\",\"to\":\"txn.test.b\",\"quantity\":\"200.0000 CUR\",\"memo\":\"\"}")); + trx.actions.push_back(act); + } + + trx.set_reference_block(cc.head_block_id()); + trx.sign(txn_test_receiver_C_priv_key, chainid); cc.push_transaction(packed_transaction(trx)); } } - void start_generation(const std::string& salt, const uint64_t& persecond) { + void start_generation(const std::string& salt, const uint64_t& period, const uint64_t& batch_size) { if(running) throw fc::exception(fc::invalid_operation_exception_code); + if(period < 1 || period > 2500) + throw fc::exception(fc::invalid_operation_exception_code); + if(batch_size < 1 || batch_size > 250) + throw fc::exception(fc::invalid_operation_exception_code); + if(batch_size & 1) + throw fc::exception(fc::invalid_operation_exception_code); + running = true; - memo_salt = salt; - timer_timeout = 1000/boost::algorithm::clamp(persecond/2, 1, 200); + //create the actions here + act_a_to_b.account = N(currency); + act_a_to_b.name = N(transfer); + act_a_to_b.authorization = vector{{name("txn.test.a"),config::active_name}}; + act_a_to_b.data = currency_serializer.variant_to_binary("transfer", fc::json::from_string(fc::format_string("{\"from\":\"txn.test.a\",\"to\":\"txn.test.b\",\"quantity\":\"1.0000 CUR\",\"memo\":\"${l}\"}", fc::mutable_variant_object()("l", salt)))); + + act_b_to_a.account = N(currency); + act_b_to_a.name = N(transfer); + act_b_to_a.authorization = vector{{name("txn.test.b"),config::active_name}}; + act_b_to_a.data = currency_serializer.variant_to_binary("transfer", fc::json::from_string(fc::format_string("{\"from\":\"txn.test.b\",\"to\":\"txn.test.a\",\"quantity\":\"1.0000 CUR\",\"memo\":\"${l}\"}", fc::mutable_variant_object()("l", salt)))); + + timer_timeout = period; + batch = batch_size/2; - ilog("Started transaction test plugin; performing ${p} transactions/second", ("p", 1000/timer_timeout*2)); + ilog("Started transaction test plugin; performing ${p} transactions every ${m}ms", ("p", batch_size)("m", period)); arm_timer(boost::asio::high_resolution_timer::clock_type::now()); } @@ -145,31 +240,32 @@ struct txn_test_gen_plugin_impl { name sender("txn.test.a"); name recipient("txn.test.b"); + fc::crypto::private_key a_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); + fc::crypto::private_key b_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); + + static uint64_t nonce; - std::string memo = memo_salt + fc::variant(fc::time_point::now()).as_string() + " " + fc::variant(fc::time_point::now().time_since_epoch()).as_string(); - //make transaction a->b + for(unsigned int i = 0; i < batch; ++i) { { signed_transaction trx; - trx.actions.emplace_back(vector{{sender,"active"}}, contracts::transfer{sender, recipient, 1, memo}); - trx.expiration = cc.head_block_time() + fc::seconds(30); + trx.actions.push_back(act_a_to_b); + trx.actions.emplace_back(action({}, config::eosio_system_account_name, "nonce", fc::raw::pack(nonce))); trx.set_reference_block(cc.head_block_id()); - - fc::crypto::private_key creator_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); - trx.sign(creator_priv_key, chainid); + trx.expiration = cc.head_block_time() + fc::seconds(30); + trx.sign(a_priv_key, chainid); cc.push_transaction(packed_transaction(trx)); } - //make transaction b->a { signed_transaction trx; - trx.actions.emplace_back(vector{{recipient,"active"}}, contracts::transfer{recipient, sender, 1, memo}); - trx.expiration = cc.head_block_time() + fc::seconds(30); + trx.actions.push_back(act_b_to_a); + trx.actions.emplace_back(action({}, config::eosio_system_account_name, "nonce", fc::raw::pack(nonce))); trx.set_reference_block(cc.head_block_id()); - - fc::crypto::private_key b_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); + trx.expiration = cc.head_block_time() + fc::seconds(30); trx.sign(b_priv_key, chainid); cc.push_transaction(packed_transaction(trx)); } + } } void stop_generation() { @@ -184,8 +280,12 @@ struct txn_test_gen_plugin_impl { bool running{false}; unsigned timer_timeout; + unsigned batch; + + action act_a_to_b; + action act_b_to_a; - std::string memo_salt; + abi_serializer currency_serializer = fc::json::from_string(currency_abi).as(); }; txn_test_gen_plugin::txn_test_gen_plugin() {} @@ -201,7 +301,7 @@ void txn_test_gen_plugin::plugin_startup() { app().get_plugin().add_api({ CALL(txn_test_gen, my, create_test_accounts, INVOKE_V_R_R(my, create_test_accounts, std::string, std::string), 200), CALL(txn_test_gen, my, stop_generation, INVOKE_V_V(my, stop_generation), 200), - CALL(txn_test_gen, my, start_generation, INVOKE_V_R_R(my, start_generation, std::string, uint64_t), 200) + CALL(txn_test_gen, my, start_generation, INVOKE_V_R_R_R(my, start_generation, std::string, uint64_t, uint64_t), 200) }); my.reset(new txn_test_gen_plugin_impl); } diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index 9a731873bd0d44571317f0e116c0a5bdce8e01bb..886826aa12a6109e98d9a9f40531cc33bd1284cd 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -1,7 +1,7 @@ add_subdirectory( eosiod ) add_subdirectory( eosioc ) -add_subdirectory( eosio-walletd ) -add_subdirectory( launcher ) -add_subdirectory( codegen ) -add_subdirectory( applesedemo ) -add_subdirectory( abi_gen ) +add_subdirectory( eosiowd ) +add_subdirectory( eosio-launcher ) +add_subdirectory( eosio-codegen ) +add_subdirectory( eosio-applesedemo ) +add_subdirectory( eosio-abigen ) diff --git a/programs/applesedemo/CMakeLists.txt b/programs/applesedemo/CMakeLists.txt deleted file mode 100644 index 90efc2334c88834e4347292d92a3ed074b42ae58..0000000000000000000000000000000000000000 --- a/programs/applesedemo/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -if(APPLE) -add_executable( applesedemo main.cpp r1_signature_compactor.cpp ) - - -target_link_libraries( applesedemo - PRIVATE fc ${PLATFORM_SPECIFIC_LIBS} - ) - -set_target_properties(applesedemo PROPERTIES LINK_FLAGS "-framework security -framework corefoundation") - -#Demostration of signing automatically during build; you will need to change parameters for your signing credentials -#[[ -add_custom_command(TARGET applesedemo POST_BUILD - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/sign.sh C5139C2C4D7FA071EFBFD86CE44B652631C9376A 5A4683969Z.one.block.applesedemo /Users/spoon/Library/MobileDevice/Provisioning\ Profiles/95813ad5-e880-432f-85c6-ade3b3298392.provisionprofile - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - VERBATIM - ) -]] - -install( TARGETS - applesedemo - - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib -) - -endif(APPLE) \ No newline at end of file diff --git a/programs/abi_gen/CMakeLists.txt b/programs/eosio-abigen/CMakeLists.txt similarity index 81% rename from programs/abi_gen/CMakeLists.txt rename to programs/eosio-abigen/CMakeLists.txt index 0af74bb4605aa7a33d09236275fb9efcaa3b08c9..61ac022a2e67a76746681899b31f7af46d511f8e 100644 --- a/programs/abi_gen/CMakeLists.txt +++ b/programs/eosio-abigen/CMakeLists.txt @@ -3,7 +3,7 @@ find_package(LLVM 4.0 REQUIRED CONFIG) link_directories(${LLVM_LIBRARY_DIR}) -add_executable(abi_gen ${SOURCES}) +add_executable(eosio-abigen ${SOURCES}) set( CMAKE_CXX_STANDARD 14 ) @@ -17,11 +17,11 @@ if( GPERFTOOLS_FOUND ) list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc ) endif() -target_link_libraries(abi_gen abi_generator) +target_link_libraries(eosio-abigen abi_generator) install( TARGETS - abi_gen + eosio-abigen RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib diff --git a/programs/abi_gen/main.cpp b/programs/eosio-abigen/main.cpp similarity index 100% rename from programs/abi_gen/main.cpp rename to programs/eosio-abigen/main.cpp diff --git a/programs/eosio-applesedemo/CMakeLists.txt b/programs/eosio-applesedemo/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..145c5a1081c22ab5b454ea2ab2db689a6b734591 --- /dev/null +++ b/programs/eosio-applesedemo/CMakeLists.txt @@ -0,0 +1,28 @@ +if(APPLE) +add_executable( eosio-applesedemo main.cpp r1_signature_compactor.cpp ) + + +target_link_libraries( eosio-applesedemo + PRIVATE fc ${PLATFORM_SPECIFIC_LIBS} + ) + +set_target_properties(eosio-applesedemo PROPERTIES LINK_FLAGS "-framework security -framework corefoundation") + +#Demostration of signing automatically during build; you will need to change parameters for your signing credentials +#[[ +add_custom_command(TARGET eosio-applesedemo POST_BUILD + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/sign.sh C5139C2C4D7FA071EFBFD86CE44B652631C9376A 5A4683969Z.one.block.eosio-applesedemo /Users/spoon/Library/MobileDevice/Provisioning\ Profiles/95813ad5-e880-432f-85c6-ade3b3298392.provisionprofile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + VERBATIM + ) +]] + +install( TARGETS + eosio-applesedemo + + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) + +endif(APPLE) diff --git a/programs/applesedemo/README.md b/programs/eosio-applesedemo/README.md similarity index 100% rename from programs/applesedemo/README.md rename to programs/eosio-applesedemo/README.md diff --git a/programs/applesedemo/main.cpp b/programs/eosio-applesedemo/main.cpp similarity index 100% rename from programs/applesedemo/main.cpp rename to programs/eosio-applesedemo/main.cpp diff --git a/programs/applesedemo/r1_signature_compactor.cpp b/programs/eosio-applesedemo/r1_signature_compactor.cpp similarity index 100% rename from programs/applesedemo/r1_signature_compactor.cpp rename to programs/eosio-applesedemo/r1_signature_compactor.cpp diff --git a/programs/applesedemo/r1_signature_compactor.hpp b/programs/eosio-applesedemo/r1_signature_compactor.hpp similarity index 100% rename from programs/applesedemo/r1_signature_compactor.hpp rename to programs/eosio-applesedemo/r1_signature_compactor.hpp diff --git a/programs/applesedemo/sign.sh b/programs/eosio-applesedemo/sign.sh similarity index 100% rename from programs/applesedemo/sign.sh rename to programs/eosio-applesedemo/sign.sh diff --git a/programs/codegen/CMakeLists.txt b/programs/eosio-codegen/CMakeLists.txt similarity index 82% rename from programs/codegen/CMakeLists.txt rename to programs/eosio-codegen/CMakeLists.txt index 4eedc5ba764b5721745adbddd9d393b664302edd..12d8b124a8d90b57d59271a75f02b05cb7f234c6 100644 --- a/programs/codegen/CMakeLists.txt +++ b/programs/eosio-codegen/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable( codegen main.cpp ) +add_executable( eosio-codegen main.cpp ) if( UNIX AND NOT APPLE ) set(rt_library rt ) endif() @@ -9,11 +9,11 @@ if( GPERFTOOLS_FOUND ) list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc ) endif() -target_link_libraries( codegen +target_link_libraries( eosio-codegen PRIVATE fc eosio_chain ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS - codegen + eosio-codegen RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/programs/codegen/main.cpp b/programs/eosio-codegen/main.cpp similarity index 100% rename from programs/codegen/main.cpp rename to programs/eosio-codegen/main.cpp diff --git a/programs/launcher/CMakeLists.txt b/programs/eosio-launcher/CMakeLists.txt similarity index 84% rename from programs/launcher/CMakeLists.txt rename to programs/eosio-launcher/CMakeLists.txt index 9613920d12436158f344171a8bf3b30cfed4da94..84cff6df0379b938e8aba20498840e63ebf1980b 100644 --- a/programs/launcher/CMakeLists.txt +++ b/programs/eosio-launcher/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable( launcher main.cpp ) +add_executable( eosio-launcher main.cpp ) if( UNIX AND NOT APPLE ) set(rt_library rt ) endif() @@ -26,13 +26,13 @@ endif() configure_file(config.hpp.in config.hpp ESCAPE_QUOTES) -target_include_directories(launcher PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(eosio-launcher PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(launcher +target_link_libraries(eosio-launcher PRIVATE fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS - launcher + eosio-launcher RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/programs/launcher/config.hpp.in b/programs/eosio-launcher/config.hpp.in similarity index 100% rename from programs/launcher/config.hpp.in rename to programs/eosio-launcher/config.hpp.in diff --git a/programs/launcher/main.cpp b/programs/eosio-launcher/main.cpp similarity index 99% rename from programs/launcher/main.cpp rename to programs/eosio-launcher/main.cpp index eb94bc83158916be4aa30bce72f3bb638d68314c..06bd33ff8f5e9d4dd561c25fc44fd95526d5be60 100644 --- a/programs/launcher/main.cpp +++ b/programs/eosio-launcher/main.cpp @@ -1273,7 +1273,7 @@ launcher_def::bounce (const string& node_numbers) { string cmd = "cd " + host.eos_root_dir + "; " + "export EOSIO_HOME=" + host.eos_root_dir + string("; ") + "export EOSIO_TN_NODE=" + node_num + "; " - + "./scripts/tn_bounce.sh"; + + "./scripts/eosio-tn_bounce.sh"; cout << "Bouncing " << node.name << endl; if (!do_ssh(cmd, host.host_name)) { cerr << "Unable to bounce " << node.name << endl; @@ -1293,7 +1293,7 @@ launcher_def::down (const string& node_numbers) { + "export EOSIO_HOME=" + host.eos_root_dir + "; " + "export EOSIO_TN_NODE=" + node_num + "; " + "export EOSIO_TN_RESTART_DATA_DIR=" + node.data_dir + "; " - + "./scripts/tn_down.sh"; + + "./scripts/eosio-tn_down.sh"; cout << "Taking down " << node.name << endl; if (!do_ssh(cmd, host.host_name)) { cerr << "Unable to down " << node.name << endl; @@ -1311,7 +1311,7 @@ launcher_def::roll (const string& host_names) { auto host = find_host_by_name_or_address(host_name); string cmd = "cd " + host->eos_root_dir + "; " + "export EOSIO_HOME=" + host->eos_root_dir + "; " - + "./scripts/tn_roll.sh"; + + "./scripts/eosio-tn_roll.sh"; if (!do_ssh(cmd, host_name)) { cerr << "Unable to roll " << host << endl; exit (-1); @@ -1393,9 +1393,9 @@ int main (int argc, char *argv[]) { ("timestamp,i",bpo::value(>s),"set the timestamp for the first block. Use \"now\" to indicate the current time") ("launch,l",bpo::value(), "select a subset of nodes to launch. Currently may be \"all\", \"none\", or \"local\". If not set, the default is to launch all unless an output file is named, in which case it starts none.") ("kill,k", bpo::value(&kill_arg),"The launcher retrieves the previously started process ids and issues a kill to each.") - ("down", bpo::value(&down_nodes),"comma-separated list of node numbers that will be taken down using the tn_down.sh script") - ("bounce", bpo::value(&bounce_nodes),"comma-separated list of node numbers that will be restarted using the tn_bounce.sh script") - ("roll", bpo::value(&roll_nodes),"comma-separated list of host names where the nodes should be rolled to a new version using the tn_roll.sh script") + ("down", bpo::value(&down_nodes),"comma-separated list of node numbers that will be taken down using the eosio-tn_down.sh script") + ("bounce", bpo::value(&bounce_nodes),"comma-separated list of node numbers that will be restarted using the eosio-tn_bounce.sh script") + ("roll", bpo::value(&roll_nodes),"comma-separated list of host names where the nodes should be rolled to a new version using the eosio-tn_roll.sh script") ("version,v", "print version information") ("help,h","print this list"); diff --git a/programs/eosioc/help_text.cpp b/programs/eosioc/help_text.cpp index 39c4652efc9b43c357b178fee85647dc77b1f8f7..2f799d58d81f7f228b29c7fd9ce9e4c0d13d7974 100644 --- a/programs/eosioc/help_text.cpp +++ b/programs/eosioc/help_text.cpp @@ -96,9 +96,134 @@ auto smatch_to_variant(const std::smatch& smatch) { return result; }; +const char* error_advice_3120001 = R"=====(Name should be less than 13 characters and only contains the following symbol .12345abcdefghijklmnopqrstuvwxyz)====="; + +const char* error_advice_3120002 = R"=====(Public key should be encoded in base58 and starts with EOS prefix)====="; + +const char* error_advice_3120003 = R"=====(Ensure that your authority JSON follows the following format! +{ + "threshold":"uint32_t", + "keys":[{ "key":"public_key", "weight":"uint16_t" }], + "accounts":[{ + "permission":{ "actor":"account_name", "permission":"permission_name" }, + "weight":"uint16_t" + }] +} +e.g. +{ + "threshold":"1", + "keys":[{ "key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":"1" }], + "accounts":[{ + "permission":{ "actor":"initb", "permission":"social" }, + "weight":"1 + }] +})====="; + +const char* error_advice_3120004 = R"=====(Ensure that your action JSON follows the contract's abi!)====="; + +const char* error_advice_3120005 = R"=====(Ensure that your transaction JSON follows the following format!\n" +{ + "ref_block_num":"uint16_t", + "ref_block_prefix":"uint32_t", + "expiration":"YYYY-MM-DDThh:mm", + "region": "uint16_t", + "read_scope":[ "account_name" ], + "write_scope":[ "account_name" ], + "actions":[{ + "account":"account_name", + "name":"action_name", + "authorization":[{ "actor":"account_name","permission":"permission_name" }], + "data":"bytes" + }] +}" +e.g. +{ + "ref_block_num":"1000", + "ref_block_prefix":"3463702842", + "expiration":"2018-01-23T01:51:05", + "region": "0", + "read_scope":[ "initb", "initc" ], + "write_scope":[ "initb", "initc" ], + "actions":[{ + "account":"eosio", + "name":"transfer", + "authorization":[{ "actor":"initb","permission":"active" }], + "data":"000000008093dd74000000000094dd74e80300000000000000" + }] +})====="; + +const char* error_advice_3120006 = R"=====(Ensure that your abi JSON follows the following format! +{ + "types" : [{ "new_type_name":"type_name", "type":"type_name" }], + "structs" : [{ "name":"type_name", "base":"type_name", "fields": [{ "name":"field_name", "type": "type_name" }] }], + "actions" : [{ "name":"action_name","type":"type_name"}], + "tables" : [{ + "name":"table_name", + "index_type":"type_name", + "key_names":[ "field_name" ], + "key_types":[ "type_name" ], + "type":"type_name" " + }] +} +e.g. +{ + "types" : [{ "new_type_name":"account_name", "type":"name" }], + "structs" : [ + { "name":"foo", "base":"", "fields": [{ "name":"by", "type": "account_name" }] },\n " + { "name":"foobar", "base":"", "fields": [{ "name":"by", "type": "account_name" }] } + ], + "actions" : [{ "name":"foo","type":"foo"}], + "tables" : [{ + "name":"foobar_table", + "index_type":"i64", + "key_names":[ "by" ], + "key_types":[ "account_name" ], + "type":"foobar" " + }] +})====="; + +const std::map error_advice = { + { 3120001, error_advice_3120001 }, + { 3120002, error_advice_3120002 }, + { 3120003, error_advice_3120003 }, + { 3120004, error_advice_3120004 }, + { 3120005, error_advice_3120005 }, + { 3120006, error_advice_3120006 } +}; + + namespace eosio { namespace client { namespace help { +bool print_recognized_error_code(const fc::exception& e) { + // eos recognized error code is from 3000000 to 3999999 + // refer to libraries/chain/include/eosio/chain/exceptions.hpp + if (e.code() >= 3000000 && e.code() <= 3999999) { + std::string advice, explanation; + + // Get advice, if any + const auto advice_itr = error_advice.find(e.code()); + if (advice_itr != error_advice.end()) advice = advice_itr->second; + + // Get explanation from log, if any + for (auto &log : e.get_log()) { + // Check if there's a log to display + if (!log.get_format().empty()) { + // Localize the message as needed + explanation += "\n " + localized_with_variant(log.get_format().data(), log.get_data()); + } + } + if (!explanation.empty()) explanation = std::string("Error Details:") + explanation; + + std::cerr << "\033[31m" << "Error " << e.code() << ": " << e.what() << "\033[0m"; + if (!advice.empty()) std::cerr << "\n" << "\033[32m" << advice << "\033[0m"; + if (!explanation.empty()) std::cerr << "\n" << "\033[33m" << explanation << "\033[0m" << std::endl; + return true; + } + return false; +} bool print_help_text(const fc::exception& e) { + // Check if the exception has recognized error code + if (print_recognized_error_code(e)) return true; bool result = false; // Large input strings to std::regex can cause SIGSEGV, this is a known bug in libstdc++. // See https://stackoverflow.com/questions/36304204/%D0%A1-regex-segfault-on-long-sequences diff --git a/programs/eosioc/main.cpp b/programs/eosioc/main.cpp index 93c0439ea8b35c1783e0ef1f5e68b4a26633eb39..40c9d6e6bb181e4b57e58c04a642fe63e823cdda 100644 --- a/programs/eosioc/main.cpp +++ b/programs/eosioc/main.cpp @@ -34,7 +34,6 @@ Subcommands: set Set or update blockchain state transfer Transfer EOS from account to account wallet Interact with local wallet - benchmark Configure and execute benchmarks push Push arbitrary transactions to the blockchain ``` @@ -227,7 +226,8 @@ uint64_t generate_nonce_value() { } chain::action generate_nonce() { - return chain::action( {}, contracts::nonce{.value = generate_nonce_value()} ); + auto v = generate_nonce_value(); + return chain::action( {}, config::eosio_system_account_name, "nonce", fc::raw::pack(v)); } vector get_account_permissions(const vector& permissions) { @@ -300,18 +300,16 @@ void send_transaction( signed_transaction& trx, bool skip_sign, packed_transacti std::cout << fc::json::to_pretty_string(push_transaction(trx, skip_sign, compression)) << std::endl; } -void create_account(name creator, name newaccount, public_key_type owner, public_key_type active, bool sign, uint64_t staked_deposit) { +void create_account(name creator, name newaccount, public_key_type owner, public_key_type active, bool skip_sign) { auto owner_auth = eosio::chain::authority{1, {{owner, 1}}, {}}; auto active_auth = eosio::chain::authority{1, {{active, 1}}, {}}; auto recovery_auth = eosio::chain::authority{1, {}, {{{creator, "active"}, 1}}}; - asset deposit(staked_deposit); - vector actions; actions.emplace_back( vector{{creator,"active"}}, - contracts::newaccount{creator, newaccount, owner_auth, active_auth, recovery_auth, deposit}); + contracts::newaccount{creator, newaccount, owner_auth, active_auth, recovery_auth}); - send_actions(std::move(actions), !sign); + send_actions(std::move(actions), skip_sign); } chain::action create_updateauth(const name& account, const name& permission, const name& parent, const authority& auth, const name& permissionAuth) { @@ -362,16 +360,20 @@ struct set_account_permission_subcommand { } else { authority auth; if (boost::istarts_with(authorityJsonOrFile, "EOS")) { - auth = authority(public_key_type(authorityJsonOrFile)); + try { + auth = authority(public_key_type(authorityJsonOrFile)); + } EOS_CAPTURE_AND_RETHROW(public_key_type_exception, "") } else { fc::variant parsedAuthority; - if (boost::istarts_with(authorityJsonOrFile, "{")) { - parsedAuthority = fc::json::from_string(authorityJsonOrFile); - } else { - parsedAuthority = fc::json::from_file(authorityJsonOrFile); - } - - auth = parsedAuthority.as(); + try { + if (boost::istarts_with(authorityJsonOrFile, "{")) { + parsedAuthority = fc::json::from_string(authorityJsonOrFile); + } else { + parsedAuthority = fc::json::from_file(authorityJsonOrFile); + } + auth = parsedAuthority.as(); + } EOS_CAPTURE_AND_RETHROW(authority_type_exception, "Fail to parse Authority JSON") + } name parent; @@ -479,40 +481,23 @@ int main( int argc, char** argv ) { // create account string creator; string account_name; - string ownerKey; - string activeKey; + string owner_key_str; + string active_key_str; bool skip_sign = false; - uint64_t staked_deposit=10000; auto createAccount = create->add_subcommand("account", localized("Create a new account on the blockchain"), false); createAccount->add_option("creator", creator, localized("The name of the account creating the new account"))->required(); createAccount->add_option("name", account_name, localized("The name of the new account"))->required(); - createAccount->add_option("OwnerKey", ownerKey, localized("The owner public key for the account"))->required(); - createAccount->add_option("ActiveKey", activeKey, localized("The active public key for the account"))->required(); + createAccount->add_option("OwnerKey", owner_key_str, localized("The owner public key for the account"))->required(); + createAccount->add_option("ActiveKey", active_key_str, localized("The active public key for the account"))->required(); createAccount->add_flag("-s,--skip-signature", skip_sign, localized("Specify that unlocked wallet keys should not be used to sign transaction")); - createAccount->add_option("--staked-deposit", staked_deposit, localized("the staked deposit transfered to the new account")); add_standard_transaction_options(createAccount); createAccount->set_callback([&] { - create_account(creator, account_name, public_key_type(ownerKey), public_key_type(activeKey), !skip_sign, staked_deposit); - }); - - // create producer - vector permissions; - auto createProducer = create->add_subcommand("producer", localized("Create a new producer on the blockchain"), false); - createProducer->add_option("name", account_name, localized("The name of the new producer"))->required(); - createProducer->add_option("OwnerKey", ownerKey, localized("The public key for the producer"))->required(); - createProducer->add_option("-p,--permission", permissions, - localized("An account and permission level to authorize, as in 'account@permission' (default user@active)")); - createProducer->add_flag("-s,--skip-signature", skip_sign, localized("Specify that unlocked wallet keys should not be used to sign transaction")); - add_standard_transaction_options(createProducer); - createProducer->set_callback([&account_name, &ownerKey, &permissions, &skip_sign] { - if (permissions.empty()) { - permissions.push_back(account_name + "@active"); - } - auto account_permissions = get_account_permissions(permissions); - - vector actions; - actions.emplace_back( account_permissions, contracts::setproducer{account_name, public_key_type(ownerKey), chain_config{}} ); - send_actions(std::move(actions), skip_sign); + public_key_type owner_key, active_key; + try { + owner_key = public_key_type(owner_key_str); + active_key = public_key_type(active_key_str); + } EOS_CAPTURE_AND_RETHROW(public_key_type_exception, "Invalid Public Key") + create_account(creator, account_name, owner_key, active_key, skip_sign); }); // Get subcommand @@ -743,7 +728,9 @@ int main( int argc, char** argv ) { if (abi->count()) { contracts::setabi handler; handler.account = account; - handler.abi = fc::json::from_file(abiPath).as(); + try { + handler.abi = fc::json::from_file(abiPath).as(); + } EOS_CAPTURE_AND_RETHROW(abi_type_exception, "Fail to parse ABI JSON") actions.emplace_back( vector{{account,"active"}}, handler); } @@ -751,59 +738,6 @@ int main( int argc, char** argv ) { send_actions(std::move(actions), skip_sign, packed_transaction::zlib); }); - // set producer approve/unapprove subcommand - string producer; - auto producerSubcommand = setSubcommand->add_subcommand("producer", localized("Approve/unapprove producer")); - producerSubcommand->require_subcommand(); - auto approveCommand = producerSubcommand->add_subcommand("approve", localized("Approve producer")); - producerSubcommand->add_subcommand("unapprove", localized("Unapprove producer")); - producerSubcommand->add_option("user-name", account_name, localized("The name of the account approving"))->required(); - producerSubcommand->add_option("producer-name", producer, localized("The name of the producer to approve"))->required(); - producerSubcommand->add_option("-p,--permission", permissions, - localized("An account and permission level to authorize, as in 'account@permission' (default user@active)")); - producerSubcommand->add_flag("-s,--skip-signature", skip_sign, localized("Specify that unlocked wallet keys should not be used to sign transaction")); - add_standard_transaction_options(producerSubcommand); - producerSubcommand->set_callback([&] { - // don't need to check unapproveCommand because one of approve or unapprove is required - bool approve = producerSubcommand->got_subcommand(approveCommand); - if (permissions.empty()) { - permissions.push_back(account_name + "@active"); - } - auto account_permissions = get_account_permissions(permissions); - - vector actions; - actions.emplace_back( account_permissions, contracts::okproducer{account_name, producer, approve}); - - push_actions(std::move(actions), skip_sign); - std::cout << localized("Set producer approval from ${name} for ${producer} to ${approve}", - ("name", account_name)("producer", producer)("value", approve ? "approve" : "unapprove")) << std::endl; - }); - - // set proxy subcommand - string proxy; - auto proxySubcommand = setSubcommand->add_subcommand("proxy", localized("Set proxy account for voting")); - proxySubcommand->add_option("user-name", account_name, localized("The name of the account to proxy from"))->required(); - proxySubcommand->add_option("proxy-name", proxy, localized("The name of the account to proxy (unproxy if not provided)")); - proxySubcommand->add_option("-p,--permission", permissions, - localized("An account and permission level to authorize, as in 'account@permission' (default user@active)")); - proxySubcommand->add_flag("-s,--skip-signature", skip_sign, localized("Specify that unlocked wallet keys should not be used to sign transaction")); - add_standard_transaction_options(proxySubcommand); - proxySubcommand->set_callback([&] { - if (permissions.empty()) { - permissions.push_back(account_name + "@active"); - } - auto account_permissions = get_account_permissions(permissions); - if (proxy.empty()) { - proxy = account_name; - } - - vector actions; - actions.emplace_back( account_permissions, contracts::setproxy{account_name, proxy}); - - push_actions(std::move(actions), skip_sign); - std::cout << localized("Set proxy for ${name} to ${proxy}", ("name", account_name)("proxy", proxy)) << std::endl; - }); - // set account auto setAccount = setSubcommand->add_subcommand("account", localized("set or update blockchain account state"))->require_subcommand(); @@ -829,21 +763,26 @@ int main( int argc, char** argv ) { transfer->add_flag("-s,--skip-sign", skip_sign, localized("Specify that unlocked wallet keys should not be used to sign transaction")); add_standard_transaction_options(transfer); transfer->set_callback([&] { + auto transfer = fc::mutable_variant_object + ("from", sender) + ("to", recipient) + ("quantity", asset(amount)) + ("memo", memo); + auto args = fc::mutable_variant_object + ("code", name(config::eosio_system_account_name)) + ("action", "transfer") + ("args", transfer); + + auto result = call(json_to_bin_func, args); + std::vector actions; + actions.emplace_back(vector{{sender,"active"}}, + config::eosio_system_account_name, "transfer", result.get_object()["binargs"].as()); if (tx_force_unique) { - if (memo.size() == 0) { - // use the memo to add a nonce - memo = fc::to_string(generate_nonce_value()); - } else { - // add a nonce actions - actions.emplace_back( generate_nonce() ); - } + actions.emplace_back( generate_nonce() ); } - actions.emplace_back( vector{{sender,"active"}}, - contracts::transfer{ .from = sender, .to = recipient, .amount = amount, .memo = memo}); - send_actions(std::move(actions), skip_sign); }); @@ -972,150 +911,6 @@ int main( int argc, char** argv ) { std::cout << fc::json::to_pretty_string(v) << std::endl; }); - // Benchmark subcommand - auto benchmark = app.add_subcommand( "benchmark", localized("Configure and execute benchmarks"), false ); - benchmark->require_subcommand(); - auto benchmark_setup = benchmark->add_subcommand( "setup", localized("Configures initial condition for benchmark") ); - uint64_t number_of_accounts = 2; - benchmark_setup->add_option("accounts", number_of_accounts, localized("the number of accounts in transfer among"))->required(); - string c_account; - benchmark_setup->add_option("creator", c_account, localized("The creator account for benchmark accounts"))->required(); - string owner_key; - string active_key; - benchmark_setup->add_option("owner", owner_key, localized("The owner key to use for account creation"))->required(); - benchmark_setup->add_option("active", active_key, localized("The active key to use for account creation"))->required(); - add_standard_transaction_options(benchmark_setup); - - benchmark_setup->set_callback([&]{ - auto controlling_account_arg = fc::mutable_variant_object( "controlling_account", c_account); - auto response_servants = call(get_controlled_accounts_func, controlling_account_arg); - fc::variant_object response_var; - fc::from_variant(response_servants, response_var); - std::vector controlled_accounts_vec; - fc::from_variant(response_var["controlled_accounts"], controlled_accounts_vec); - long num_existing_accounts = std::count_if(controlled_accounts_vec.begin(), - controlled_accounts_vec.end(), - [](auto const &s) { return s.find("benchmark") != std::string::npos;}); - boost::format fmter("%1% accounts already exist"); - fmter % num_existing_accounts; - EOSC_ASSERT( number_of_accounts > num_existing_accounts, fmter.str().c_str()); - - number_of_accounts -= num_existing_accounts; - std::cerr << localized("Creating ${number_of_accounts} accounts with initial balances", ("number_of_accounts",number_of_accounts)) << std::endl; - - if (num_existing_accounts == 0) { - EOSC_ASSERT( number_of_accounts >= 2, "must create at least 2 accounts" ); - } - - auto info = get_info(); - - vector batch; - batch.reserve( number_of_accounts ); - for( uint32_t i = num_existing_accounts; i < num_existing_accounts + number_of_accounts; ++i ) { - name newaccount( name("benchmark").value + i ); - public_key_type owner(owner_key), active(active_key); - name creator(c_account); - - auto owner_auth = eosio::chain::authority{1, {{owner, 1}}, {}}; - auto active_auth = eosio::chain::authority{1, {{active, 1}}, {}}; - auto recovery_auth = eosio::chain::authority{1, {}, {{{creator, "active"}, 1}}}; - - asset deposit(1); - - signed_transaction trx; - trx.actions.emplace_back( vector{{creator,"active"}}, - contracts::newaccount{creator, newaccount, owner_auth, active_auth, recovery_auth, deposit}); - - trx.expiration = info.head_block_time + tx_expiration; - trx.set_reference_block(info.head_block_id); - batch.emplace_back(trx); - info = get_info(); - } - auto result = call( push_txns_func, batch ); - std::cout << fc::json::to_pretty_string(result) << std::endl; - }); - - auto benchmark_transfer = benchmark->add_subcommand( "transfer", localized("executes random transfers among accounts") ); - uint64_t number_of_transfers = 0; - bool loop = false; - benchmark_transfer->add_option("accounts", number_of_accounts, localized("the number of accounts in transfer among"))->required(); - benchmark_transfer->add_option("count", number_of_transfers, localized("the number of transfers to execute"))->required(); - benchmark_transfer->add_option("loop", loop, localized("whether or not to loop for ever")); - add_standard_transaction_options(benchmark_transfer); - benchmark_transfer->set_callback([&]{ - EOSC_ASSERT( number_of_accounts >= 2, "must create at least 2 accounts" ); - - std::cerr << localized("Funding ${number_of_accounts} accounts from init", ("number_of_accounts",number_of_accounts)) << std::endl; - auto info = get_info(); - vector batch; - batch.reserve(100); - for( uint32_t i = 0; i < number_of_accounts; ++i ) { - name sender( "initb" ); - name recipient( name("benchmark").value + i); - uint32_t amount = 100000; - - signed_transaction trx; - trx.actions.emplace_back( vector{{sender,"active"}}, - contracts::transfer{ .from = sender, .to = recipient, .amount = amount, .memo = memo}); - trx.expiration = info.head_block_time + tx_expiration; - trx.set_reference_block(info.head_block_id); - - batch.emplace_back(trx); - if( batch.size() == 100 ) { - auto result = call( push_txns_func, batch ); - // std::cout << fc::json::to_pretty_string(result) << std::endl; - batch.resize(0); - } - } - if( batch.size() ) { - auto result = call( push_txns_func, batch ); - //std::cout << fc::json::to_pretty_string(result) << std::endl; - batch.resize(0); - } - - - std::cerr << localized("Generating random ${number_of_transfers} transfers among ${number_of_accounts}",("number_of_transfers",number_of_transfers)("number_of_accounts",number_of_accounts)) << std::endl; - while( true ) { - auto info = get_info(); - uint64_t amount = 1; - - for( uint32_t i = 0; i < number_of_transfers; ++i ) { - signed_transaction trx; - - name sender( name("benchmark").value + rand() % number_of_accounts ); - name recipient( name("benchmark").value + rand() % number_of_accounts ); - - while( recipient == sender ) - recipient = name( name("benchmark").value + rand() % number_of_accounts ); - - - auto memo = fc::variant(fc::time_point::now()).as_string() + " " + fc::variant(fc::time_point::now().time_since_epoch()).as_string(); - trx.actions.emplace_back( vector{{sender,"active"}}, - contracts::transfer{ .from = sender, .to = recipient, .amount = amount, .memo = memo}); - trx.expiration = info.head_block_time + tx_expiration; - trx.set_reference_block( info.head_block_id); - - batch.emplace_back(trx); - if( batch.size() == 40 ) { - auto result = call( push_txns_func, batch ); - //std::cout << fc::json::to_pretty_string(result) << std::endl; - batch.resize(0); - info = get_info(); - } - } - - if (batch.size() > 0) { - auto result = call( push_txns_func, batch ); - std::cout << fc::json::to_pretty_string(result) << std::endl; - batch.resize(0); - info = get_info(); - } - if( !loop ) break; - } - }); - - - // Push subcommand auto push = app.add_subcommand("push", localized("Push arbitrary transactions to the blockchain"), false); push->require_subcommand(); @@ -1124,6 +919,7 @@ int main( int argc, char** argv ) { string contract; string action; string data; + vector permissions; auto actionsSubcommand = push->add_subcommand("action", localized("Push a transaction with a single action")); actionsSubcommand->fallthrough(false); actionsSubcommand->add_option("contract", contract, @@ -1137,10 +933,15 @@ int main( int argc, char** argv ) { add_standard_transaction_options(actionsSubcommand); actionsSubcommand->set_callback([&] { ilog("Converting argument to binary..."); + fc::variant action_args_var; + try { + action_args_var = fc::json::from_string(data); + } EOS_CAPTURE_AND_RETHROW(action_type_exception, "Fail to parse action JSON") + auto arg= fc::mutable_variant_object ("code", contract) ("action", action) - ("args", fc::json::from_string(data)); + ("args", action_args_var); auto result = call(json_to_bin_func, arg); auto accountPermissions = get_account_permissions(permissions); @@ -1160,7 +961,11 @@ int main( int argc, char** argv ) { auto trxSubcommand = push->add_subcommand("transaction", localized("Push an arbitrary JSON transaction")); trxSubcommand->add_option("transaction", trxJson, localized("The JSON of the transaction to push"))->required(); trxSubcommand->set_callback([&] { - auto trx_result = call(push_txn_func, fc::json::from_string(trxJson)); + fc::variant trx_var; + try { + trx_var = fc::json::from_string(trxJson); + } EOS_CAPTURE_AND_RETHROW(transaction_type_exception, "Fail to parse transaction JSON") + auto trx_result = call(push_txn_func, trx_var); std::cout << fc::json::to_pretty_string(trx_result) << std::endl; }); @@ -1169,7 +974,11 @@ int main( int argc, char** argv ) { auto trxsSubcommand = push->add_subcommand("transactions", localized("Push an array of arbitrary JSON transactions")); trxsSubcommand->add_option("transactions", trxsJson, localized("The JSON array of the transactions to push"))->required(); trxsSubcommand->set_callback([&] { - auto trxs_result = call(push_txn_func, fc::json::from_string(trxsJson)); + fc::variant trx_var; + try { + trx_var = fc::json::from_string(trxJson); + } EOS_CAPTURE_AND_RETHROW(transaction_type_exception, "Fail to parse transaction JSON") + auto trxs_result = call(push_txn_func, trx_var); std::cout << fc::json::to_pretty_string(trxs_result) << std::endl; }); diff --git a/programs/eosiod/CMakeLists.txt b/programs/eosiod/CMakeLists.txt index efe06ecbfc1cfec5e09ab72a006ac728c99911b4..4e56daa5d05143aeffcb66cd105cd710fd8017bf 100644 --- a/programs/eosiod/CMakeLists.txt +++ b/programs/eosiod/CMakeLists.txt @@ -46,7 +46,7 @@ target_link_libraries( eosiod PRIVATE -Wl,${whole_archive_flag} account_history_api_plugin -Wl,${no_whole_archive_flag} account_history_plugin PRIVATE -Wl,${whole_archive_flag} chain_api_plugin -Wl,${no_whole_archive_flag} producer_plugin chain_plugin PRIVATE -Wl,${whole_archive_flag} wallet_api_plugin -Wl,${no_whole_archive_flag} - PRIVATE net_plugin net_api_plugin -Wl,${whole_archive_flag} txn_test_gen_plugin -Wl,${no_whole_archive_flag} + PRIVATE net_plugin net_api_plugin -Wl,${whole_archive_flag} txn_test_gen_plugin -Wl,${no_whole_archive_flag} PRIVATE http_plugin -Wl,${whole_archive_flag} faucet_testnet_plugin -Wl,${no_whole_archive_flag} PRIVATE eosio_chain fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) diff --git a/programs/eosio-walletd/CMakeLists.txt b/programs/eosiowd/CMakeLists.txt similarity index 72% rename from programs/eosio-walletd/CMakeLists.txt rename to programs/eosiowd/CMakeLists.txt index b665eaa2bb697d586c6a15f65d719ba0419167b1..cb8c51c25382231c60609e9bd00b5a8079f60d10 100644 --- a/programs/eosio-walletd/CMakeLists.txt +++ b/programs/eosiowd/CMakeLists.txt @@ -1,22 +1,22 @@ -add_executable( eosio-walletd main.cpp ) +add_executable( eosiowd main.cpp ) if( UNIX AND NOT APPLE ) set(rt_library rt ) endif() find_package( Gperftools QUIET ) if( GPERFTOOLS_FOUND ) - message( STATUS "Found gperftools; compiling eosio-walletd with TCMalloc") + message( STATUS "Found gperftools; compiling eosiowd with TCMalloc") list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc ) endif() -target_link_libraries( eosio-walletd +target_link_libraries( eosiowd PRIVATE appbase PRIVATE wallet_api_plugin wallet_plugin PRIVATE http_plugin PRIVATE eosio_chain fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS - eosio-walletd + eosiowd RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/programs/eosio-walletd/main.cpp b/programs/eosiowd/main.cpp similarity index 100% rename from programs/eosio-walletd/main.cpp rename to programs/eosiowd/main.cpp diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 00e6034f56c9f59165034ca37ec7ac925130d8ed..e903d69ea07f4a61a5814ca368fd0a3064464399 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -1,5 +1,5 @@ -configure_file(tn_bounce.sh tn_bounce.sh COPYONLY) -configure_file(tn_down.sh tn_down.sh COPYONLY) -configure_file(tn_roll.sh tn_roll.sh COPYONLY) -configure_file(tn_up.sh tn_up.sh COPYONLY) +configure_file(eosio-tn_bounce.sh eosio-tn_bounce.sh COPYONLY) +configure_file(eosio-tn_down.sh eosio-tn_down.sh COPYONLY) +configure_file(eosio-tn_roll.sh eosio-tn_roll.sh COPYONLY) +configure_file(eosio-tn_up.sh eosio-tn_up.sh COPYONLY) diff --git a/scripts/tn_bounce.sh b/scripts/eosio-tn_bounce.sh similarity index 78% rename from scripts/tn_bounce.sh rename to scripts/eosio-tn_bounce.sh index 07ab19f6a5b3955ee43199a772992fe50cfc9199..7dc3647f832dc4ba6dff415d9863f4519d9dcec4 100755 --- a/scripts/tn_bounce.sh +++ b/scripts/eosio-tn_bounce.sh @@ -1,14 +1,14 @@ #!/bin/bash # -# tn_bounce is used to restart a node that is acting badly or is down. -# usage: tn_bounce.sh [arglist] +# eosio-tn_bounce is used to restart a node that is acting badly or is down. +# usage: eosio-tn_bounce.sh [arglist] # arglist will be passed to the node's command line. First with no modifiers # then with --replay and then a third time with --resync # # the data directory and log file are set by this script. Do not pass them on # the command line. # -# in most cases, simply running ./tn_bounce.sh is sufficient. +# in most cases, simply running ./eosio-tn_bounce.sh is sufficient. # cd $EOSIO_HOME @@ -40,8 +40,8 @@ fi echo DD = $DD export EOSIO_TN_RESTART_DATA_DIR=$DD -bash $EOSIO_HOME/scripts/tn_down.sh -bash $EOSIO_HOME/scripts/tn_up.sh $* +bash $EOSIO_HOME/scripts/eosio-tn_down.sh +bash $EOSIO_HOME/scripts/eosio-tn_up.sh $* unset EOSIO_TN_RESTART_DATA_DIR cd - diff --git a/scripts/tn_down.sh b/scripts/eosio-tn_down.sh similarity index 90% rename from scripts/tn_down.sh rename to scripts/eosio-tn_down.sh index befdc1dbbdd87aeead45e0abddc178c71b5eda15..0b98ab3ff3cf08c4f4bcb709f725bad7a3800006 100755 --- a/scripts/tn_down.sh +++ b/scripts/eosio-tn_down.sh @@ -1,7 +1,7 @@ #!/bin/bash # -# tn_down.sh is used by the tn_bounce.sh and tn_roll.sh scripts. It is intended to terminate -# specific EOS daemon processes. +# eosio-tn_down.sh is used by the eosio-tn_bounce.sh and eosio-tn_roll.sh scripts. +# It is intended to terminate specific EOS.IO daemon processes. # diff --git a/scripts/tn_roll.sh b/scripts/eosio-tn_roll.sh similarity index 79% rename from scripts/tn_roll.sh rename to scripts/eosio-tn_roll.sh index 77fbc66e003bae2da6cf8d7613216adfb1f06e2a..edc0f5f24fa748bd088a0831acc33236ef64d2e2 100755 --- a/scripts/tn_roll.sh +++ b/scripts/eosio-tn_roll.sh @@ -1,16 +1,16 @@ #!/bin/bash # -# tn_roll is used to have all of the instances of the EOS daemon on a host brought down -# so that the underlying executable image file (the "text file") caan be replaced. Then +# eosio-tn_roll is used to have all of the instances of the EOS daemon on a host brought down +# so that the underlying executable image file (the "text file") can be replaced. Then # all instances are restarted. -# usage: tn_roll.sh [arglist] +# usage: eosio-tn_roll.sh [arglist] # arglist will be passed to the node's command line. First with no modifiers # then with --replay and then a third time with --resync # -# the data directory and log file are set by this script. Do not pass them on +# The data directory and log file are set by this script. Do not pass them on # the command line. # -# in most cases, simply running ./tn_roll.sh is sufficient. +# In most cases, simply running ./eosio-tn_roll.sh is sufficient. # if [ -z "$EOSIO_HOME" ]; then @@ -75,16 +75,16 @@ fi echo DD = $DD export EOSIO_TN_RESTART_DATA_DIR=$DD -bash $EOSIO_HOME/scripts/tn_down.sh +bash $EOSIO_HOME/scripts/eosio-tn_down.sh cp $SDIR/$RD/$prog $RD/$prog if [ $DD = "all" ]; then for EOSIO_TN_RESTART_DATA_DIR in `ls -d tn_data_??`; do - bash $EOSIO_HOME/scripts/tn_up.sh $* + bash $EOSIO_HOME/scripts/eosio-tn_up.sh $* done else - bash $EOSIO_HOME/scripts/tn_up.sh $* + bash $EOSIO_HOME/scripts/eosio-tn_up.sh $* fi unset EOSIO_TN_RESTART_DATA_DIR diff --git a/scripts/tn_up.sh b/scripts/eosio-tn_up.sh old mode 100644 new mode 100755 similarity index 88% rename from scripts/tn_up.sh rename to scripts/eosio-tn_up.sh index a32cd99acef32efe8ea90e445703c48e749151c3..8a81ed1211f57f4bbe3941c661f1eba7f7090212 --- a/scripts/tn_up.sh +++ b/scripts/eosio-tn_up.sh @@ -1,8 +1,8 @@ #!/bin/bash # -# tn_up is a helper script used to start a node that was previously stopped -# it is not intended to be run stand-alone, it is a companion to the tn_bounce.sh and -# tn_roll.sh scripts. +# eosio-tn_up is a helper script used to start a node that was previously stopped. +# It is not intended to be run stand-alone; it is a companion to the +# eosio-tn_bounce.sh and eosio-tn_roll.sh scripts. connected="0" diff --git a/scripts/install_dependencies.sh b/scripts/install_dependencies.sh index aa3e598331977593ba349373ec202b110998f2aa..da36442ea1d267499320338c0bc582c9a29666e4 100644 --- a/scripts/install_dependencies.sh +++ b/scripts/install_dependencies.sh @@ -8,7 +8,7 @@ if [ $ARCH == "ubuntu" ]; then libbz2-dev libssl-dev libgmp3-dev \ autotools-dev build-essential \ libbz2-dev libicu-dev python-dev \ - autoconf libtool git curl + autoconf libtool git curl automake OPENSSL_ROOT_DIR=/usr/local/opt/openssl OPENSSL_LIBRARIES=/usr/local/opt/openssl/lib diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a8cb2832c062a04545ed58af7af2de95fe6445a7..dfcab43361d1d3c687951c484798ca72b3502edb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,7 +27,7 @@ target_link_libraries( chain_test eosio_testing eosio_chain chainbase eos_utilit 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_CURRENT_SOURCE_DIR}/wasm_tests ) - add_dependencies(chain_test asserter test_api currency proxy) + add_dependencies(chain_test asserter test_api currency proxy identity) endif() @@ -49,6 +49,7 @@ endif() #endif() # configure_file(${CMAKE_CURRENT_SOURCE_DIR}/p2p_tests/sync/test.sh ${CMAKE_CURRENT_BINARY_DIR}/p2p_tests/sync/test.sh COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/p2p_tests/dawn_515/test.sh ${CMAKE_CURRENT_BINARY_DIR}/p2p_tests/dawn_515/test.sh COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/trans_sync_across_mixed_cluster_test.sh ${CMAKE_CURRENT_BINARY_DIR}/trans_sync_across_mixed_cluster_test.sh COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/distributed-transactions-test.py ${CMAKE_CURRENT_BINARY_DIR}/distributed-transactions-test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/distributed-transactions-remote-test.py ${CMAKE_CURRENT_BINARY_DIR}/distributed-transactions-remote-test.py COPYONLY) @@ -58,20 +59,22 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testUtils.py ${CMAKE_CURRENT_BINARY_D configure_file(${CMAKE_CURRENT_SOURCE_DIR}/eosiod_run_test.py ${CMAKE_CURRENT_BINARY_DIR}/eosiod_run_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/eosiod_run_remote_test.py ${CMAKE_CURRENT_BINARY_DIR}/eosiod_run_remote_test.py COPYONLY) -add_test(NAME eosiod_run_test COMMAND tests/eosiod_run_test.py --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -add_test(NAME p2p_sync_test COMMAND tests/p2p_tests/sync/test.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -add_test(NAME p2p_sync_test_p2_d10 COMMAND tests/p2p_tests/sync/test.sh -p 2 -d 10 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -add_test(NAME message_storm COMMAND tests/p2p_tests/sync/test.sh -m -p 21 -n 21 -d 5 -l WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -add_test(NAME eosiod_run_remote_test COMMAND tests/eosiod_run_remote_test.py --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -if(BUILD_MONGO_DB_PLUGIN) - add_test(NAME eosiod_run_test-mongodb COMMAND tests/eosiod_run_test.py --mongodb --exit-early --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -endif() -add_test(chain_test chain_test) -add_test(NAME trans_sync_across_mixed_cluster_test COMMAND tests/trans_sync_across_mixed_cluster_test.sh -p 1 -n 2 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -add_test(NAME distributed-transactions-test COMMAND tests/distributed-transactions-test.py -p 1 -n 4 --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -add_test(NAME distributed-transactions-remote-test COMMAND tests/distributed-transactions-remote-test.py --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -add_test(NAME restart-scenarios-test_resync COMMAND tests/restart-scenarios-test.py -c resync -p3 --dumpErrorDetails WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -add_test(NAME restart-scenarios-test_replay COMMAND tests/restart-scenarios-test.py -c replay -p3 --dumpErrorDetails WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_test(chain_test chain_test --report_level=detailed) +# TODO: Tests removed until working again on master. +# TODO: add_test(NAME eosiod_run_test COMMAND tests/eosiod_run_test.py --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +# TODO: add_test(NAME p2p_sync_test COMMAND tests/p2p_tests/sync/test.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +# TODO: add_test(NAME p2p_sync_test_p2_d10 COMMAND tests/p2p_tests/sync/test.sh -p 2 -d 10 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +# TODO: add_test(NAME message_storm COMMAND tests/p2p_tests/sync/test.sh -m -p 21 -n 21 -d 5 -l WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +# TODO: add_test(NAME p2p_dawn515_test COMMAND tests/p2p_tests/dawn_515/test.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +# TODO: add_test(NAME eosiod_run_remote_test COMMAND tests/eosiod_run_remote_test.py --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +# TODO: if(BUILD_MONGO_DB_PLUGIN) +# TODO: add_test(NAME eosiod_run_test-mongodb COMMAND tests/eosiod_run_test.py --mongodb --exit-early --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +# TODO: endif() +# TODO: add_test(NAME trans_sync_across_mixed_cluster_test COMMAND tests/trans_sync_across_mixed_cluster_test.sh -p 1 -n 2 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +# TODO: add_test(NAME distributed-transactions-test COMMAND tests/distributed-transactions-test.py -p 1 -n 4 --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +# TODO: add_test(NAME distributed-transactions-remote-test COMMAND tests/distributed-transactions-remote-test.py --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +# TODO: add_test(NAME restart-scenarios-test_resync COMMAND tests/restart-scenarios-test.py -c resync -p3 --dumpErrorDetails WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +# TODO: add_test(NAME restart-scenarios-test_replay COMMAND tests/restart-scenarios-test.py -c replay -p3 --dumpErrorDetails WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) if(ENABLE_COVERAGE_TESTING) diff --git a/tests/chain_tests/block_tests.cpp b/tests/chain_tests/block_tests.cpp index a76ba9dd3efef80f73fd5cde635df20aac7d6547..0b24705bf91c48212fab04ad4c655e90df9421eb 100644 --- a/tests/chain_tests/block_tests.cpp +++ b/tests/chain_tests/block_tests.cpp @@ -35,6 +35,20 @@ BOOST_AUTO_TEST_CASE( schedule_test ) { try { ilog("exiting"); } FC_LOG_AND_RETHROW() }/// schedule_test +BOOST_AUTO_TEST_CASE( push_block ) { try { + tester test1, test2(false); + + for (uint32 i = 0; i < 1000; ++i) { + test2.control->push_block(test1.produce_block()); + } + + test1.create_account(N(alice), asset::from_string("100.0000 EOS")); + test2.control->push_block(test1.produce_block()); + + test1.transfer(N(inita), N(alice), asset(1000), "memo"); + test2.control->push_block(test1.produce_block()); +} FC_LOG_AND_RETHROW() }/// schedule_test + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/chain_tests/recovery_tests.cpp b/tests/chain_tests/recovery_tests.cpp index 4148bb5b7cf400ff9ced7d0cdeb476ccdf12b9ed..2337cc760c0943d53330674bedb030b4311d2b5f 100644 --- a/tests/chain_tests/recovery_tests.cpp +++ b/tests/chain_tests/recovery_tests.cpp @@ -1,8 +1,6 @@ #include #include -#include - using namespace eosio; using namespace eosio::chain; @@ -37,26 +35,13 @@ auto make_vetorecovery(const tester &t, account_name account, permission_name ve return trx; } -auto push_nonce(tester &t, const string& role) { - // ensure the old owner key is valid - signed_transaction trx; - trx.actions.emplace_back( vector{{N(alice),config::owner_name}}, - nonce{ - .value = t.control->head_block_num() - } ); - t.set_tapos(trx); - trx.sign(t.get_private_key(N(alice), role), chain_id_type()); - t.push_transaction(trx); - return trx.id(); -}; - BOOST_AUTO_TEST_SUITE(recovery_tests) BOOST_FIXTURE_TEST_CASE( test_recovery_owner, tester ) try { produce_blocks(1000); - create_account(N(alice), asset::from_string("1000.000 EOS")); + create_account(N(alice), asset::from_string("1000.0000 EOS")); produce_block(); fc::time_point expected_recovery(fc::seconds(control->head_block_time().sec_since_epoch()) +fc::days(30)); @@ -75,13 +60,13 @@ BOOST_FIXTURE_TEST_CASE( test_recovery_owner, tester ) try { auto skip_time = expected_recovery - control->head_block_time() - fc::milliseconds(config::block_interval_ms); produce_block(skip_time); control->push_deferred_transactions(true); - auto last_old_nonce_id = push_nonce(*this, "owner"); + auto last_old_nonce_id = push_nonce(N(alice), "owner").id; produce_block(); control->push_deferred_transactions(true); BOOST_REQUIRE_EQUAL(chain_has_transaction(last_old_nonce_id), true); - BOOST_REQUIRE_THROW(push_nonce(*this, "owner"), tx_missing_sigs); - auto first_new_nonce_id = push_nonce(*this, "owner.recov"); + BOOST_REQUIRE_THROW(push_nonce(N(alice), "owner"), tx_missing_sigs); + auto first_new_nonce_id = push_nonce(N(alice), "owner.recov").id; produce_block(); BOOST_REQUIRE_EQUAL(chain_has_transaction(first_new_nonce_id), true); @@ -89,7 +74,7 @@ BOOST_FIXTURE_TEST_CASE( test_recovery_owner, tester ) try { BOOST_FIXTURE_TEST_CASE( test_recovery_owner_veto, tester ) try { produce_blocks(1000); - create_account(N(alice), asset::from_string("1000.000 EOS")); + create_account(N(alice), asset::from_string("1000.0000 EOS")); produce_block(); fc::time_point expected_recovery(fc::seconds(control->head_block_time().sec_since_epoch()) +fc::days(30)); @@ -107,7 +92,7 @@ BOOST_FIXTURE_TEST_CASE( test_recovery_owner_veto, tester ) try { auto skip_time = expected_recovery - control->head_block_time() - fc::milliseconds(config::block_interval_ms); produce_block(skip_time); control->push_deferred_transactions(true); - auto last_old_nonce_id = push_nonce(*this, "owner"); + auto last_old_nonce_id = push_nonce(N(alice), "owner").id; // post the veto at the last possible time { @@ -122,8 +107,8 @@ BOOST_FIXTURE_TEST_CASE( test_recovery_owner_veto, tester ) try { // make sure the old owner is still in control - BOOST_REQUIRE_THROW(push_nonce(*this, "owner.recov"), tx_missing_sigs); - auto first_new_nonce_id = push_nonce(*this, "owner"); + BOOST_REQUIRE_THROW(push_nonce(N(alice), "owner.recov"), tx_missing_sigs); + auto first_new_nonce_id = push_nonce(N(alice), "owner").id; produce_block(); BOOST_REQUIRE_EQUAL(chain_has_transaction(first_new_nonce_id), true); @@ -131,7 +116,7 @@ BOOST_FIXTURE_TEST_CASE( test_recovery_owner_veto, tester ) try { BOOST_FIXTURE_TEST_CASE( test_recovery_bad_creator, tester ) try { produce_blocks(1000); - create_account(N(alice), asset::from_string("1000.000 EOS"), N(inita), true); + create_account(N(alice), asset::from_string("1000.0000 EOS"), N(inita), true); produce_block(); fc::time_point expected_recovery(fc::seconds(control->head_block_time().sec_since_epoch()) +fc::days(30)); @@ -175,7 +160,7 @@ BOOST_FIXTURE_TEST_CASE( test_recovery_bad_creator, tester ) try { control->push_deferred_transactions(true); // make sure the recovery goes through - auto first_new_nonce_id = push_nonce(*this, "owner"); + auto first_new_nonce_id = push_nonce(N(alice), "owner").id; produce_block(); BOOST_REQUIRE_EQUAL(chain_has_transaction(first_new_nonce_id), true); diff --git a/tests/chain_tests/transfer_tests.cpp b/tests/chain_tests/transfer_tests.cpp index acf6ee2f08b19916c57459276c2d0f906c3e78c5..8164d79b485b4848325e8f5e5f65fdef510d46fd 100644 --- a/tests/chain_tests/transfer_tests.cpp +++ b/tests/chain_tests/transfer_tests.cpp @@ -1,8 +1,6 @@ #include #include - -#include - +#include using namespace eosio; using namespace eosio::chain; @@ -22,26 +20,26 @@ BOOST_AUTO_TEST_CASE( transfer_test ) { try { { const asset dans_balance( test.get_balance( N(dan) ) ); - FC_ASSERT( dans_balance == asset::from_string("10.0000 EOS") ); + FC_ASSERT( dans_balance == asset::from_string("110.0000 EOS") ); } test.produce_block(); { const asset dans_balance( test.get_balance( N(dan) ) ); - FC_ASSERT( dans_balance == asset::from_string("10.0000 EOS") ); + FC_ASSERT( dans_balance == asset::from_string("110.0000 EOS") ); } /// insufficient funds - BOOST_REQUIRE_THROW(test.transfer(N(dan),N(bart), "11.0000 EOS", "memo"), action_validate_exception); + BOOST_REQUIRE_THROW(test.transfer(N(dan),N(bart), "111.0000 EOS", "memo"), assert_exception); /// this should succeed because dan has sufficient balance - test.transfer(N(dan),N(bart), "10.0000 EOS", "memo"); + test.transfer(N(dan),N(bart), "110.0000 EOS", "memo"); - /// verify that bart now has 10.000 + /// verify that bart now has 110.000 + 100.000 const asset barts_balance( test.get_balance( N(bart) ) ); - FC_ASSERT( barts_balance == asset::from_string("10.0000 EOS") ); + FC_ASSERT( barts_balance == asset::from_string("210.0000 EOS") ); { /// verify that dan now has 0.000 @@ -51,47 +49,82 @@ BOOST_AUTO_TEST_CASE( transfer_test ) { try { /// should throw because -1 becomes uint64 max which is greater than balance - BOOST_REQUIRE_THROW(test.transfer(N(bart),N(dan), asset(-1), "memo"), action_validate_exception); - - - - { + BOOST_REQUIRE_THROW(test.transfer(N(bart),N(dan), asset(-1), "memo"), assert_exception); + + auto resolver = [&]( const account_name& name ) -> optional { + try { + const auto& accnt = test.control->get_database().get( name ); + abi_def abi; + if (abi_serializer::to_abi(accnt.abi, abi)) { + return abi_serializer(abi); + } + return optional(); + } FC_RETHROW_EXCEPTIONS(error, "Failed to find or parse ABI for ${name}", ("name", name)) + }; + + { auto from = N(bart); auto to = N(dan); asset amount(1); - signed_transaction trx; - trx.actions.emplace_back( vector{{from,config::active_name}}, - contracts::transfer{ - .from = from, - .to = to, - .amount = amount.amount, - .memo = "memo" - } ); + variant pretty_trx = mutable_variant_object() + ("actions", variants({ + mutable_variant_object() + ("account", name(config::eosio_system_account_name)) + ("name", "transfer") + ("authorization", variants({ + mutable_variant_object() + ("actor", "bart") + ("permission", name(config::active_name).to_string()) + })) + ("data", mutable_variant_object() + ("from", "bart") + ("to", "dan") + ("quantity", amount) + ("memo", "memo") + ) + }) + ); + signed_transaction trx; + abi_serializer::from_variant(pretty_trx, trx, resolver); test.set_tapos( trx ); + BOOST_REQUIRE_THROW( test.push_transaction( trx ), tx_missing_sigs ); trx.sign( test.get_private_key( from, "active" ), chain_id_type() ); test.push_transaction( trx ); - } + } - { + { auto from = N(bart); auto to = N(dan); asset amount(1); - signed_transaction trx; - trx.actions.emplace_back( vector{{to,config::active_name}}, - contracts::transfer{ - .from = from, - .to = to, - .amount = amount.amount, - .memo = "memo" - } ); + variant pretty_trx = mutable_variant_object() + ("actions", variants({ + mutable_variant_object() + ("account", name(config::eosio_system_account_name)) + ("name", "transfer") + ("authorization", variants({ + mutable_variant_object() + ("actor", "dan") + ("permission", name(config::active_name).to_string()) + })) + ("data", mutable_variant_object() + ("from", "bart") + ("to", "dan") + ("quantity", amount) + ("memo", "memo") + ) + }) + ); + signed_transaction trx; + abi_serializer::from_variant(pretty_trx, trx, resolver); test.set_tapos( trx ); - trx.sign( test.get_private_key( to, "active" ), chain_id_type() ); + + trx.sign( test.get_private_key( to, "active" ), chain_id_type() ); /// action not provided from authority BOOST_REQUIRE_THROW( test.push_transaction( trx ), tx_missing_auth); - } + } } FC_LOG_AND_RETHROW() } /// transfer_test @@ -122,29 +155,51 @@ BOOST_AUTO_TEST_CASE( transfer_delegation ) { try { test.produce_block( fc::hours(2) ); ///< skip 2 hours - - /// execute a transfer from dan to bart signed by trust - { - auto from = N(dan); - auto to = N(bart); + auto resolver = [&]( const account_name& name ) -> optional { + try { + const auto& accnt = test.control->get_database().get( name ); + abi_def abi; + if (abi_serializer::to_abi(accnt.abi, abi)) { + return abi_serializer(abi); + } + return optional(); + } FC_RETHROW_EXCEPTIONS(error, "Failed to find or parse ABI for ${name}", ("name", name)) + }; + + /// execute a transfer from dan to bart signed by trust + { + auto from = N(bart); + auto to = N(dan); asset amount(1); + variant pretty_trx = mutable_variant_object() + ("actions", variants({ + mutable_variant_object() + ("account", name(config::eosio_system_account_name)) + ("name", "transfer") + ("authorization", variants({ + mutable_variant_object() + ("actor", "dan") + ("permission", name(config::active_name).to_string()) + })) + ("data", mutable_variant_object() + ("from", "dan") + ("to", "trust") + ("quantity", amount) + ("memo", "memo") + ) + }) + ); signed_transaction trx; - trx.actions.emplace_back( vector{{from,config::active_name}}, - contracts::transfer{ - .from = from, - .to = to, - .amount = amount.amount, - .memo = "memo" - } ); - + abi_serializer::from_variant(pretty_trx, trx, resolver); test.set_tapos( trx ); + trx.sign( test.get_private_key( N(trust), "active" ), chain_id_type() ); wdump((fc::raw::pack_size(trx))); /// action not provided from authority test.push_transaction( trx ); - } + } } FC_LOG_AND_RETHROW() } diff --git a/tests/p2p_tests/dawn_515/test.sh b/tests/p2p_tests/dawn_515/test.sh new file mode 100755 index 0000000000000000000000000000000000000000..13158f1f9e924f376edc8126c9eff0ab71983106 --- /dev/null +++ b/tests/p2p_tests/dawn_515/test.sh @@ -0,0 +1,284 @@ +#!/bin/bash + +############################################################### +# Extracts staging directory and launchs cluster. +############################################################### + +pnodes=1 +total_nodes=3 +topo=star +delay=1 + +read -d '' config00 << EOF +shared-file-size = 8192 +p2p-server-address = localhost:9876 +plugin = eosio::producer_plugin +plugin = eosio::chain_api_plugin +plugin = eosio::account_history_plugin +plugin = eosio::account_history_api_plugin +required-participation = true +shared-file-dir = blockchain +http-server-address = 127.0.0.1:8888 +block-log-dir = blocks +p2p-listen-endpoint = 0.0.0.0:9876 +allowed-connection = any +private-key = ['EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV','5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3'] +send-whole-blocks = true +readonly = 0 +genesis-json = ./genesis.json +producer-name = inita +producer-name = initb +producer-name = initc +producer-name = initd +producer-name = inite +producer-name = initf +producer-name = initg +producer-name = inith +producer-name = initi +producer-name = initj +producer-name = initk +producer-name = initl +producer-name = initm +producer-name = initn +producer-name = inito +producer-name = initp +producer-name = initq +producer-name = initr +producer-name = inits +producer-name = initt +producer-name = initu +EOF + +read -d '' config01 << EOF +genesis-json = ./genesis.json +block-log-dir = blocks +readonly = 0 +send-whole-blocks = true +shared-file-dir = blockchain +shared-file-size = 8192 +http-server-address = 127.0.0.1:8889 +p2p-listen-endpoint = 0.0.0.0:9877 +p2p-server-address = localhost:9877 +allowed-connection = any +p2p-peer-address = localhost:9876 +plugin = eosio::chain_api_plugin +plugin = eosio::account_history_plugin +plugin = eosio::account_history_api_plugin +EOF + +read -d '' config02 << EOF +genesis-json = ./genesis.json +block-log-dir = blocks +readonly = 0 +send-whole-blocks = true +shared-file-dir = blockchain +shared-file-size = 8192 +http-server-address = 127.0.0.1:8890 +p2p-listen-endpoint = 0.0.0.0:9878 +p2p-server-address = localhost:9877 +allowed-connection = any +p2p-peer-address = localhost:9876 +plugin = eosio::chain_api_plugin +plugin = eosio::account_history_plugin +plugin = eosio::account_history_api_plugin +EOF + +read -d '' logging00 << EOF +{ + "includes": [], + "appenders": [{ + "name": "stderr", + "type": "console", + "args": { + "stream": "std_error", + "level_colors": [{ + "level": "debug", + "color": "green" + },{ + "level": "warn", + "color": "brown" + },{ + "level": "error", + "color": "red" + } + ] + }, + "enabled": true + },{ + "name": "stdout", + "type": "console", + "args": { + "stream": "std_out", + "level_colors": [{ + "level": "debug", + "color": "green" + },{ + "level": "warn", + "color": "brown" + },{ + "level": "error", + "color": "red" + } + ] + }, + "enabled": true + } + ], + "loggers": [{ + "name": "default", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + } + ] +} +EOF + +read -d '' logging01 << EOF +{ + "includes": [], + "appenders": [{ + "name": "stderr", + "type": "console", + "args": { + "stream": "std_error", + "level_colors": [{ + "level": "debug", + "color": "green" + },{ + "level": "warn", + "color": "brown" + },{ + "level": "error", + "color": "red" + } + ] + }, + "enabled": true + },{ + "name": "stdout", + "type": "console", + "args": { + "stream": "std_out", + "level_colors": [{ + "level": "debug", + "color": "green" + },{ + "level": "warn", + "color": "brown" + },{ + "level": "error", + "color": "red" + } + ] + }, + "enabled": true + } + ], + "loggers": [{ + "name": "default", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + } + ] +} +EOF + +read -d '' logging02 << EOF +{ + "includes": [], + "appenders": [{ + "name": "stderr", + "type": "console", + "args": { + "stream": "std_error", + "level_colors": [{ + "level": "debug", + "color": "green" + },{ + "level": "warn", + "color": "brown" + },{ + "level": "error", + "color": "red" + } + ] + }, + "enabled": true + },{ + "name": "stdout", + "type": "console", + "args": { + "stream": "std_out", + "level_colors": [{ + "level": "debug", + "color": "green" + },{ + "level": "warn", + "color": "brown" + },{ + "level": "error", + "color": "red" + } + ] + }, + "enabled": true + } + ], + "loggers": [{ + "name": "default", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + } + ] +} +EOF + +rm -rf staging +rm -rf tn_data_* + +cName=config.ini +lName=logging.json + +path=staging/tn_data_00 +mkdir -p $path +echo "$config00" > $path/$cName +echo "$logging00" > $path/$lName + +path=staging/tn_data_01 +mkdir -p $path +echo "$config01" > $path/$cName +echo "$logging01" > $path/$lName + +path=staging/tn_data_02 +mkdir -p $path +echo "$config02" > $path/$cName +echo "$logging02" > $path/$lName + + +programs/launcher/launcher -p $pnodes -n $total_nodes --nogen -d $delay + +sleep 1 +res=$(grep "reason = duplicate" tn_data_0*/stderr.txt | wc -l) + +if [ $res -ne 0 ]; then + echo FAILURE: got a \"duplicate\" message +else + echo "SUCCESS" +fi + +programs/launcher/launcher -k 15 +rm -rf staging +rm -rf tn_data_* +exit $res diff --git a/tests/p2p_tests/sync/test.sh b/tests/p2p_tests/sync/test.sh index 31b367ca17ceca0db5d4134f07adac1907cdadb6..9edb990423cb9f8d47f5d77fb4a7ea496c4fd28a 100755 --- a/tests/p2p_tests/sync/test.sh +++ b/tests/p2p_tests/sync/test.sh @@ -53,7 +53,7 @@ else fi total_nodes="${total_nodes:-`echo $pnodes`}" -launcherPath="programs/launcher/launcher" +launcherPath="programs/eosio-launcher/eosio-launcher" clientPath="programs/eosioc/eosioc" rm -rf tn_data_* diff --git a/tests/testUtils.py b/tests/testUtils.py index 7e60d08455dd52c452b6f7a9bfa58a64b6bc4bd4..9091a6a5234980279edd5b7a6e52fd4bf6876f2f 100755 --- a/tests/testUtils.py +++ b/tests/testUtils.py @@ -23,11 +23,11 @@ class Utils: EosServerName="eosiod" EosClientPath="programs/eosioc/eosioc" - EosWalletPath="programs/eosio-walletd/eosio-walletd" + EosWalletPath="programs/eosiowd/eosiowd" EosServerName="eosiod" EosServerPath="programs/eosiod/%s" % (EosServerName) - EosLauncherPath="programs/launcher/launcher" + EosLauncherPath="programs/eosio-launcher/eosio-launcher" MongoPath="mongo" @staticmethod diff --git a/tests/tests/abi_tests.cpp b/tests/tests/abi_tests.cpp index 772dd8fbcd12c8c5e6a5492d14d91c4d5d28168d..1d17efad3bafd3cd46deea0b4749d14094ce66e6 100644 --- a/tests/tests/abi_tests.cpp +++ b/tests/tests/abi_tests.cpp @@ -304,12 +304,6 @@ const char* my_abi = R"=====( },{ "name": "abidef_arr", "type": "abi_def[]" - },{ - "name": "nonce", - "type": "nonce" - },{ - "name": "nonce_arr", - "type": "nonce[]" }] } ], @@ -420,6 +414,8 @@ BOOST_AUTO_TEST_CASE(generator) const char* all_types = R"=====( #include #include + #include + #include typedef int field; typedef int struct_def; @@ -448,7 +444,7 @@ BOOST_AUTO_TEST_CASE(generator) fixed_string32 field6; fixed_string16 field7; type_name field8; - bytes field9; + eosio::bytes field9; uint8_t field10; uint16_t field11; uint32_t field12; @@ -479,9 +475,8 @@ BOOST_AUTO_TEST_CASE(generator) action_def field37; table_def field38; abi_def field39; - nonce field40; - public_key field41; - asset field42; + public_key field40; + eosio::asset field41; }; )====="; @@ -610,12 +605,9 @@ BOOST_AUTO_TEST_CASE(generator) "type": "abi_def" },{ "name": "field40", - "type": "nonce" - },{ - "name": "field41", "type": "public_key" },{ - "name": "field42", + "name": "field41", "type": "asset" }] }], @@ -1296,8 +1288,8 @@ BOOST_AUTO_TEST_CASE(general) { "publickey" : "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "publickey_arr" : ["EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"], - "asset" : "100.00 EOS", - "asset_arr" : ["100.00 EOS","100.00 EOS"], + "asset" : "100.0000 EOS", + "asset_arr" : ["100.0000 EOS","100.0000 EOS"], "string" : "ola ke ase", "string_arr" : ["ola ke ase","ola ke desi"], @@ -1364,8 +1356,6 @@ BOOST_AUTO_TEST_CASE(general) "ref_block_prefix":"2", "expiration":"2021-12-20T15:30", "region": "1", - "read_scope":["acc1"], - "write_scope":["acc1"], "actions":[{"scope":"scopename1", "name":"actionname1", "authorization":[{"actor":"acc1","permission":"permname1"}], "data":"445566"}] }, "transaction_arr": [{ @@ -1373,16 +1363,12 @@ BOOST_AUTO_TEST_CASE(general) "ref_block_prefix":"2", "expiration":"2021-12-20T15:30", "region": "1", - "read_scope":["acc1"], - "write_scope":["acc1"], "actions":[{"scope":"acc1", "name":"actionname1", "authorization":[{"actor":"acc1","permission":"permname1"}], "data":"445566"}] },{ "ref_block_num":"2", "ref_block_prefix":"3", "expiration":"2021-12-20T15:40", "region": "1", - "read_scope":["acc2"], - "write_scope":["acc2"], "actions":[{"scope":"acc2", "name":"actionname2", "authorization":[{"actor":"acc2","permission":"permname2"}], "data":""}] }], "strx": { @@ -1390,8 +1376,6 @@ BOOST_AUTO_TEST_CASE(general) "ref_block_prefix":"2", "expiration":"2021-12-20T15:30", "region": "1", - "read_scope":["acc1"], - "write_scope":["acc1"], "signatures" : ["EOSJzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwT77X1U"], "actions":[{"scope":"scopename1", "name":"actionname1", "authorization":[{"actor":"acc1","permission":"permname1"}], "data":"445566"}] }, @@ -1400,8 +1384,6 @@ BOOST_AUTO_TEST_CASE(general) "ref_block_prefix":"2", "expiration":"2021-12-20T15:30", "region": "1", - "read_scope":["acc1"], - "write_scope":["acc1"], "signatures" : ["EOSJzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwT77X1U"], "actions":[{"scope":"acc1", "name":"actionname1", "authorization":[{"actor":"acc1","permission":"permname1"}], "data":"445566"}] },{ @@ -1409,8 +1391,6 @@ BOOST_AUTO_TEST_CASE(general) "ref_block_prefix":"3", "expiration":"2021-12-20T15:40", "region": "1", - "read_scope":["acc2"], - "write_scope":["acc2"], "signatures" : ["EOSJzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwT77X1U"], "actions":[{"scope":"acc2", "name":"actionname2", "authorization":[{"actor":"acc2","permission":"permname2"}], "data":""}] }], @@ -1505,14 +1485,6 @@ BOOST_AUTO_TEST_CASE(general) "structs" : [{"name":"struct1", "base":"base1", "fields": [{"name":"name1", "type": "type1"}, {"name":"name2", "type": "type2"}] }], "actions" : [{"name":"action1","type":"type1"}], "tables" : [{"name":"table1","index_type":"indextype1","key_names":["keyname1"],"key_types":["typename1"],"type":"type1"}] - }], - "nonce": { - "value": "nonce1" - }, - "nonce_arr": [{ - "value": "nonce1" - },{ - "value": "nonce2" }] } )====="; @@ -1573,244 +1545,6 @@ BOOST_AUTO_TEST_CASE(abi_cycle) } FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(transfer) -{ try { - - abi_serializer abis(chain_initializer::eos_contract_abi()); - - const char* test_data = R"=====( - { - "from" : "from.acct", - "to" : "to.acct", - "amount" : 18446744073709551515, - "memo" : "really important transfer" - } - )====="; - - auto var = fc::json::from_string(test_data); - - auto transfer = var.as(); - BOOST_TEST("from.acct" == transfer.from); - BOOST_TEST("to.acct" == transfer.to); - BOOST_TEST(18446744073709551515u == transfer.amount); - BOOST_TEST("really important transfer" == transfer.memo); - - auto var2 = verify_round_trip_conversion( abis, "transfer", var ); - auto transfer2 = var2.as(); - BOOST_TEST(transfer.from == transfer2.from); - BOOST_TEST(transfer.to == transfer2.to); - BOOST_TEST(transfer.amount == transfer2.amount); - BOOST_TEST(transfer.memo == transfer2.memo); - -} FC_LOG_AND_RETHROW() } - -BOOST_AUTO_TEST_CASE(lock) -{ try { - - abi_serializer abis(chain_initializer::eos_contract_abi()); - - BOOST_CHECK(true); - const char* test_data = R"=====( - { - "from" : "from.acct", - "to" : "to.acct", - "amount" : -9223372036854775807, - } - )====="; - - auto var = fc::json::from_string(test_data); - - auto lock = var.as(); - BOOST_TEST("from.acct" == lock.from); - BOOST_TEST("to.acct" == lock.to); - BOOST_TEST(-9223372036854775807 == lock.amount); - - auto var2 = verify_round_trip_conversion( abis, "lock", var ); - auto lock2 = var2.as(); - BOOST_TEST(lock.from == lock2.from); - BOOST_TEST(lock.to == lock2.to); - BOOST_TEST(lock.amount == lock2.amount); - -} FC_LOG_AND_RETHROW() } - -BOOST_AUTO_TEST_CASE(unlock) -{ try { - - abi_serializer abis(chain_initializer::eos_contract_abi()); - - BOOST_CHECK(true); - const char* test_data = R"=====( - { - "account" : "an.acct", - "amount" : -9223372036854775807, - } - )====="; - - auto var = fc::json::from_string(test_data); - - auto unlock = var.as(); - BOOST_TEST("an.acct" == unlock.account); - BOOST_TEST(-9223372036854775807 == unlock.amount); - - auto var2 = verify_round_trip_conversion( abis, "unlock", var ); - auto unlock2 = var2.as(); - BOOST_TEST(unlock.account == unlock2.account); - BOOST_TEST(unlock.amount == unlock2.amount); - -} FC_LOG_AND_RETHROW() } - -BOOST_AUTO_TEST_CASE(claim) -{ try { - - abi_serializer abis(chain_initializer::eos_contract_abi()); - - BOOST_CHECK(true); - const char* test_data = R"=====( - { - "account" : "an.acct", - "amount" : -9223372036854775807, - } - )====="; - - auto var = fc::json::from_string(test_data); - - auto claim = var.as(); - BOOST_TEST("an.acct" == claim.account); - BOOST_TEST(-9223372036854775807 == claim.amount); - - auto var2 = verify_round_trip_conversion( abis, "claim", var ); - auto claim2 = var2.as(); - BOOST_TEST(claim.account == claim2.account); - BOOST_TEST(claim.amount == claim2.amount); - -} FC_LOG_AND_RETHROW() } - -BOOST_AUTO_TEST_CASE(okproducer) -{ try { - - abi_serializer abis(chain_initializer::eos_contract_abi()); - - BOOST_CHECK(true); - const char* test_data = R"=====( - { - "voter" : "an.acct", - "producer" : "an.acct2", - "approve" : -128, - } - )====="; - - auto var = fc::json::from_string(test_data); - - auto okproducer = var.as(); - BOOST_TEST("an.acct" == okproducer.voter); - BOOST_TEST("an.acct2" == okproducer.producer); - BOOST_TEST(-128 == okproducer.approve); - - auto var2 = verify_round_trip_conversion( abis, "okproducer", var ); - auto okproducer2 = var2.as(); - BOOST_TEST(okproducer.voter == okproducer2.voter); - BOOST_TEST(okproducer.producer == okproducer2.producer); - BOOST_TEST(okproducer.approve == okproducer2.approve); - -} FC_LOG_AND_RETHROW() } - -BOOST_AUTO_TEST_CASE(setproducer) -{ try { - - abi_serializer abis(chain_initializer::eos_contract_abi()); - const char* test_data = R"=====( - { - "name" : "acct.name", - "key" : "EOS5PnYq6BZn7H9GvL68cCLjWUZThRemTJoJmybCn1iEpVUXLb5Az", - "configuration" : { - "producer_pay": "-9223372036854775717", - "target_block_size": "2147483145", - "max_block_size": "2147483135", - "target_block_acts_per_scope": "2147473155", - "max_block_acts_per_scope": "2147483165", - "target_block_acts": "4194967295", - "max_block_acts": "4294957295", - "real_threads": "9223372036854772717", - "max_storage_size": "9223372036854775805", - "max_transaction_lifetime": "2147483125", - "max_authority_depth": "63777", - "max_transaction_exec_time": "2146483015", - "max_inline_depth": "64267", - "max_inline_action_size": "4294867295", - "max_generated_transaction_size": "4292967295" - } - } - )====="; - - auto var = fc::json::from_string(test_data); - - auto setproducer = var.as(); - BOOST_TEST("acct.name" == setproducer.name); - BOOST_TEST("EOS5PnYq6BZn7H9GvL68cCLjWUZThRemTJoJmybCn1iEpVUXLb5Az" == (string)setproducer.key); - BOOST_TEST(-9223372036854775717 == setproducer.configuration.producer_pay); - BOOST_TEST(2147483145u == setproducer.configuration.target_block_size); - BOOST_TEST(2147483135u == setproducer.configuration.max_block_size); - BOOST_TEST(2147473155u == setproducer.configuration.target_block_acts_per_scope); - BOOST_TEST(2147483165u == setproducer.configuration.max_block_acts_per_scope); - BOOST_TEST(4194967295u == setproducer.configuration.target_block_acts); - BOOST_TEST(4294957295u == setproducer.configuration.max_block_acts); - BOOST_TEST(9223372036854772717u == setproducer.configuration.real_threads); - BOOST_TEST(9223372036854775805u == setproducer.configuration.max_storage_size); - BOOST_TEST(2147483125u == setproducer.configuration.max_transaction_lifetime); - BOOST_TEST(63777u == setproducer.configuration.max_authority_depth); - BOOST_TEST(2146483015u == setproducer.configuration.max_transaction_exec_time); - BOOST_TEST(64267u == setproducer.configuration.max_inline_depth); - BOOST_TEST(4294867295u == setproducer.configuration.max_inline_action_size); - BOOST_TEST(4292967295u == setproducer.configuration.max_generated_transaction_size); - - auto var2 = verify_round_trip_conversion( abis, "setproducer", var ); - auto setproducer2 = var2.as(); - BOOST_TEST(setproducer.name == setproducer2.name); - BOOST_TEST((string)setproducer.key == (string)setproducer2.key); - BOOST_TEST(setproducer.configuration.producer_pay == setproducer2.configuration.producer_pay); - BOOST_TEST(setproducer.configuration.target_block_size == setproducer2.configuration.target_block_size); - BOOST_TEST(setproducer.configuration.max_block_size == setproducer2.configuration.max_block_size); - BOOST_TEST(setproducer.configuration.target_block_acts_per_scope == setproducer2.configuration.target_block_acts_per_scope); - BOOST_TEST(setproducer.configuration.max_block_acts_per_scope == setproducer2.configuration.max_block_acts_per_scope); - BOOST_TEST(setproducer.configuration.target_block_acts == setproducer2.configuration.target_block_acts); - BOOST_TEST(setproducer.configuration.max_block_acts == setproducer2.configuration.max_block_acts); - BOOST_TEST(setproducer.configuration.real_threads == setproducer2.configuration.real_threads); - BOOST_TEST(setproducer.configuration.max_storage_size == setproducer2.configuration.max_storage_size); - BOOST_TEST(setproducer.configuration.max_transaction_lifetime == setproducer2.configuration.max_transaction_lifetime); - BOOST_TEST(setproducer.configuration.max_authority_depth == setproducer2.configuration.max_authority_depth); - BOOST_TEST(setproducer.configuration.max_transaction_exec_time == setproducer2.configuration.max_transaction_exec_time); - BOOST_TEST(setproducer.configuration.max_inline_depth == setproducer2.configuration.max_inline_depth); - BOOST_TEST(setproducer.configuration.max_inline_action_size == setproducer2.configuration.max_inline_action_size); - BOOST_TEST(setproducer.configuration.max_generated_transaction_size == setproducer2.configuration.max_generated_transaction_size); - -} FC_LOG_AND_RETHROW() } - -BOOST_AUTO_TEST_CASE(setproxy) -{ try { - - abi_serializer abis(chain_initializer::eos_contract_abi()); - - BOOST_CHECK(true); - const char* test_data = R"=====( - { - "stakeholder" : "stake.hldr", - "proxy" : "stkhdr.prxy" - } - )====="; - - auto var = fc::json::from_string(test_data); - - auto setproxy = var.as(); - BOOST_TEST("stake.hldr" == setproxy.stakeholder); - BOOST_TEST("stkhdr.prxy" == setproxy.proxy); - - auto var2 = verify_round_trip_conversion( abis, "setproxy", var ); - auto setproxy2 = var2.as(); - BOOST_TEST(setproxy.stakeholder == setproxy2.stakeholder); - BOOST_TEST(setproxy.proxy == setproxy2.proxy); - -} FC_LOG_AND_RETHROW() } - BOOST_AUTO_TEST_CASE(linkauth) { try { @@ -1995,8 +1729,7 @@ BOOST_AUTO_TEST_CASE(newaccount) {"key" : "EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf", "weight" : 57605} ], "accounts" : [ {"permission" : {"actor" : "prm.acct1", "permission" : "prm.prm1"}, "weight" : 53005 }, {"permission" : {"actor" : "prm.acct2", "permission" : "prm.prm2"}, "weight" : 53405 }] - }, - "deposit" : "-90000000.0000 EOS" + } } )====="; @@ -2054,9 +1787,6 @@ BOOST_AUTO_TEST_CASE(newaccount) BOOST_TEST("prm.prm2" == newaccount.recovery.accounts[1].permission.permission); BOOST_TEST(53405u == newaccount.recovery.accounts[1].weight); - BOOST_TEST(-900000000000 == newaccount.deposit.amount); - BOOST_TEST(symbol(EOS_SYMBOL) == newaccount.deposit.symbol()); - auto var2 = verify_round_trip_conversion( abis, "newaccount", var ); auto newaccount2 = var2.as(); BOOST_TEST(newaccount.creator == newaccount2.creator); @@ -2110,9 +1840,6 @@ BOOST_AUTO_TEST_CASE(newaccount) BOOST_TEST(newaccount.recovery.accounts[1].permission.permission == newaccount2.recovery.accounts[1].permission.permission); BOOST_TEST(newaccount.recovery.accounts[1].weight == newaccount2.recovery.accounts[1].weight); - BOOST_TEST(newaccount.deposit.amount == newaccount2.deposit.amount); - BOOST_TEST(newaccount.deposit.symbol() == newaccount2.deposit.symbol()); - } FC_LOG_AND_RETHROW() } @@ -2404,29 +2131,6 @@ BOOST_AUTO_TEST_CASE(vetorecovery) } FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(nonce) -{ try { - - abi_serializer abis(chain_initializer::eos_contract_abi()); - - const char* test_data = R"=====( - { - "value" : "nonce.value" - } - )====="; - - auto var = fc::json::from_string(test_data); - - auto nonce = var.as(); - BOOST_TEST("nonce.value" == nonce.value); - - auto var2 = verify_round_trip_conversion( abis, "nonce", var ); - auto nonce2 = var2.as(); - BOOST_TEST(nonce.value == nonce2.value); - -} FC_LOG_AND_RETHROW() } - - BOOST_AUTO_TEST_CASE(abi_type_repeat) { try { diff --git a/tests/tests/database_tests.cpp b/tests/tests/database_tests.cpp index 9ff03aca3cbbbcade49f2d06d1c6709532444fc5..d03ba98aa713046f9ba4500aaaab4292ab57ca78 100644 --- a/tests/tests/database_tests.cpp +++ b/tests/tests/database_tests.cpp @@ -58,12 +58,17 @@ BOOST_AUTO_TEST_SUITE(database_tests) } // Utility function to check expected irreversible block - auto calc_exp_last_irr_block_num = [&](uint32_t head_block_num) { + auto calc_exp_last_irr_block_num = [&](uint32_t head_block_num) -> uint32_t { const global_property_object &gpo = test.control->get_global_properties(); const auto producers_size = gpo.active_producers.producers.size(); - const auto min_producers = EOS_PERCENT(producers_size, config::irreversible_threshold_percent); - return head_block_num - (((min_producers - 1) * config::producer_repititions) + 1 + - (head_block_num % config::producer_repititions)); + const auto max_reversible_rounds = EOS_PERCENT(producers_size, config::percent_100 - config::irreversible_threshold_percent); + if( max_reversible_rounds == 0) { + return head_block_num - 1; + } else { + const auto current_round = head_block_num / config::producer_repititions; + const auto irreversible_round = current_round - max_reversible_rounds; + return (irreversible_round + 1) * config::producer_repititions - 1; + } }; // Check the last irreversible block number is set correctly diff --git a/tests/trans_sync_across_mixed_cluster_test.sh b/tests/trans_sync_across_mixed_cluster_test.sh index a4ef452050f432976f01604fa8024fc601fcf49c..d9158a8ef0a8685cb7e47e1d76cd0a492f63378a 100755 --- a/tests/trans_sync_across_mixed_cluster_test.sh +++ b/tests/trans_sync_across_mixed_cluster_test.sh @@ -66,7 +66,7 @@ verifyErrorCode() killAll() { - programs/launcher/launcher -k 15 + programs/eosio-launcher/eosio-launcher -k 15 } cleanup() @@ -113,7 +113,7 @@ cleanup # stand up eosiod cluster launcherOpts="-p $pnodes -n $total_nodes -s $topo -d $delay" echo Launcher options: --eosiod \"--plugin eosio::wallet_api_plugin\" $launcherOpts -programs/launcher/launcher --eosiod "--plugin eosio::wallet_api_plugin" $launcherOpts +programs/eosio-launcher/eosio-launcher --eosiod "--plugin eosio::wallet_api_plugin" $launcherOpts sleep 7 startPort=8888 diff --git a/tests/wasm_tests/currency_tests.cpp b/tests/wasm_tests/currency_tests.cpp index ea91beb0b258142245c24507279698204f7986a7..0f5ef27b5613e95c7af80ffc7c47c8b2199e8c6d 100644 --- a/tests/wasm_tests/currency_tests.cpp +++ b/tests/wasm_tests/currency_tests.cpp @@ -51,7 +51,7 @@ BOOST_FIXTURE_TEST_CASE( test_generic_currency, tester ) try { std::cerr << act.console << "\n"; produce_block(); - auto actual = get_currency_balance(N(currency), expected.symbol(), N(usera)); + auto actual = get_currency_balance(N(currency), expected.get_symbol(), N(usera)); BOOST_REQUIRE_EQUAL(expected, actual); } @@ -93,7 +93,7 @@ BOOST_FIXTURE_TEST_CASE( test_currency, tester ) try { produce_block(); BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); - BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.symbol(), N(currency)), asset::from_string( "1000000.0000 CUR" )); + BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.get_symbol(), N(currency)), asset::from_string( "1000000.0000 CUR" )); } // make a transfer from the contract to a user @@ -117,7 +117,7 @@ BOOST_FIXTURE_TEST_CASE( test_currency, tester ) try { produce_block(); BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); - BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.symbol(), N(alice)), asset::from_string( "100.0000 CUR" )); + BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.get_symbol(), N(alice)), asset::from_string( "100.0000 CUR" )); } // Overspend! @@ -141,8 +141,8 @@ BOOST_FIXTURE_TEST_CASE( test_currency, tester ) try { produce_block(); BOOST_REQUIRE_EQUAL(false, chain_has_transaction(trx.id())); - BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.symbol(), N(alice)), asset::from_string( "100.0000 CUR" )); - BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.symbol(), N(bob)), asset::from_string( "0.0000 CUR" )); + BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.get_symbol(), N(alice)), asset::from_string( "100.0000 CUR" )); + BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.get_symbol(), N(bob)), asset::from_string( "0.0000 CUR" )); } // Full spend @@ -166,8 +166,8 @@ BOOST_FIXTURE_TEST_CASE( test_currency, tester ) try { produce_block(); BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); - BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.symbol(), N(alice)), asset::from_string( "0.0000 CUR" )); - BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.symbol(), N(bob)), asset::from_string( "100.0000 CUR" )); + BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.get_symbol(), N(alice)), asset::from_string( "0.0000 CUR" )); + BOOST_REQUIRE_EQUAL(get_currency_balance(N(currency), token_supply.get_symbol(), N(bob)), asset::from_string( "100.0000 CUR" )); } } FC_LOG_AND_RETHROW() /// test_currency diff --git a/tests/wasm_tests/identity_tests.cpp b/tests/wasm_tests/identity_tests.cpp index cb0ec97ea302755e64cf7d6162734627942d2d32..f5dee69bccb0037abf500d87ecb56d11ca0e038a 100644 --- a/tests/wasm_tests/identity_tests.cpp +++ b/tests/wasm_tests/identity_tests.cpp @@ -21,14 +21,13 @@ using namespace eosio::chain_apis; using namespace eosio::testing; using namespace fc; -#if 0 class identity_tester : public tester { public: identity_tester() { produce_blocks(2); - create_accounts( {N(identity), N(identitytest), N(alice), N(bob)}, asset::from_string("100000.0000 EOS") ); + create_accounts( {N(identity), N(identitytest), N(alice), N(bob), N(carol)}, asset::from_string("100000.0000 EOS") ); produce_blocks(1000); set_code(N(identity), identity_wast); @@ -46,11 +45,14 @@ public: abi_def abi_test; BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(acnt_test.abi, abi_test), true); abi_ser_test.set_abi(abi_test); + + const global_property_object &gpo = control->get_global_properties(); + producer_name = (string)gpo.active_producers.producers.front().producer_name; } uint64_t get_result_uint64() { const auto& db = control->get_database(); - const auto* t_id = db.find(boost::make_tuple(0, N(identitytest), N(result))); + const auto* t_id = db.find(boost::make_tuple(N(identitytest), 0, N(result))); FC_ASSERT(t_id != 0, "Table id not found"); const auto& idx = db.get_index(); @@ -65,52 +67,42 @@ public: uint64_t get_owner_for_identity(uint64_t identity) { - signed_transaction trx; action get_owner_act; get_owner_act.account = N(identitytest); get_owner_act.name = N(getowner); get_owner_act.data = abi_ser_test.variant_to_binary("getowner", mutable_variant_object() ("identity", identity) ); - trx.actions.emplace_back(std::move(get_owner_act)); - set_tapos(trx); - control->push_transaction(trx); - produce_block(); - BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); + BOOST_REQUIRE_EQUAL(success(), push_action(std::move(get_owner_act), 0)); + return get_result_uint64(); + } + uint64_t get_identity_for_account(const string& account) + { + action get_identity_act; + get_identity_act.account = N(identitytest); + get_identity_act.name = N(getidentity); + get_identity_act.data = abi_ser_test.variant_to_binary("getidentity", mutable_variant_object() + ("account", account) + ); + BOOST_REQUIRE_EQUAL(success(), push_action(std::move(get_identity_act), 0)); return get_result_uint64(); } - string create_identity(const string& account_name, uint64_t identity, bool auth = true) { - signed_transaction trx; + action_result create_identity(const string& account_name, uint64_t identity, bool auth = true) { action create_act; create_act.account = N(identity); create_act.name = N(create); - if (auth) { - create_act.authorization = vector{{string_to_name(account_name.c_str()), config::active_name}}; - } create_act.data = abi_ser.variant_to_binary("create", mutable_variant_object() ("creator", account_name) ("identity", identity) ); - trx.actions.emplace_back(std::move(create_act)); - set_tapos(trx); - if (auth) { - trx.sign(get_private_key(string_to_name(account_name.c_str()), "active"), chain_id_type()); - } - try { - control->push_transaction(trx); - } catch (const fc::exception& ex) { - return error(ex.top_message()); - } - produce_block(); - BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); - return success(); + return push_action( std::move(create_act), (auth ? string_to_name(account_name.c_str()) : 0) ); } fc::variant get_identity(uint64_t idnt) { const auto& db = control->get_database(); - const auto* t_id = db.find(boost::make_tuple(N(identity), N(identity), N(ident))); + const auto* t_id = db.find(boost::make_tuple(N(identity), N(identity), N(ident))); FC_ASSERT(t_id != 0, "object not found"); const auto& idx = db.get_index(); @@ -124,38 +116,22 @@ public: return abi_ser.binary_to_variant("identrow", data); } - string certify(const string& certifier, uint64_t identity, const vector& fields, bool auth = true) { - signed_transaction trx; + action_result certify(const string& certifier, uint64_t identity, const vector& fields, bool auth = true) { action cert_act; cert_act.account = N(identity); cert_act.name = N(certprop); - if (auth) { - cert_act.authorization = vector{{string_to_name(certifier.c_str()), config::active_name}}; - } cert_act.data = abi_ser.variant_to_binary("certprop", mutable_variant_object() ("bill_storage_to", certifier) ("certifier", certifier) ("identity", identity) ("value", fields) ); - trx.actions.emplace_back(std::move(cert_act)); - set_tapos(trx); - if (auth) { - trx.sign(get_private_key(string_to_name(certifier.c_str()), "active"), chain_id_type()); - } - try { - control->push_transaction(trx); - } catch (const fc::exception& ex) { - return error(ex.top_message()); - } - produce_block(); - BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); - return success(); + return push_action( std::move(cert_act), (auth ? string_to_name(certifier.c_str()) : 0) ); } fc::variant get_certrow(uint64_t identity, const string& property, uint64_t trusted, const string& certifier) { const auto& db = control->get_database(); - const auto* t_id = db.find(boost::make_tuple(identity, N(identity), N(certs))); + const auto* t_id = db.find(boost::make_tuple(N(identity), identity, N(certs))); FC_ASSERT(t_id != 0, "certrow not found"); uint64_t prop = string_to_name(property.c_str()); @@ -172,16 +148,16 @@ public: } } - fc::variant get_accountrow(uint64_t identity, const string& account) { + fc::variant get_accountrow(const string& account) { const auto& db = control->get_database(); - const auto* t_id = db.find(boost::make_tuple(identity, N(identity), N(account))); + uint64_t acnt = string_to_name(account.c_str()); + const auto* t_id = db.find(boost::make_tuple(N(identity), acnt, N(account))); if (!t_id) { return fc::variant(nullptr); } const auto& idx = db.get_index(); - uint64_t acnt = string_to_name(account.c_str()); - auto itr = idx.lower_bound(boost::make_tuple(t_id->id, acnt)); - if( itr != idx.end() && itr->t_id == t_id->id && acnt == itr->primary_key) { + auto itr = idx.lower_bound(boost::make_tuple(t_id->id, N(account))); + if( itr != idx.end() && itr->t_id == t_id->id && N(account) == itr->primary_key) { vector data; read_only::copy_row(*itr, data); return abi_ser.binary_to_variant("accountrow", data); @@ -190,59 +166,38 @@ public: } } - - string settrust(const string& trustor, const string& trusting, uint64_t trust, bool auth = true) + action_result settrust(const string& trustor, const string& trusting, uint64_t trust, bool auth = true) { signed_transaction trx; action settrust_act; settrust_act.account = N(identity); settrust_act.name = N(settrust); - auto tr = string_to_name(trustor.c_str()); - if (auth) { - settrust_act.authorization = vector{{tr, config::active_name}}; - } settrust_act.data = abi_ser.variant_to_binary("settrust", mutable_variant_object() ("trustor", trustor) ("trusting", trusting) ("trust", trust) ); - trx.actions.emplace_back(std::move(settrust_act)); - set_tapos(trx); - if (auth) { - trx.sign(get_private_key(tr, "active"), chain_id_type()); - } - try { - control->push_transaction(trx); - } catch (const fc::exception& ex) { - return error(ex.top_message()); - } - produce_block(); - BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); - return success(); + auto tr = string_to_name(trustor.c_str()); + return push_action( std::move(settrust_act), (auth ? tr : 0) ); } - fc::variant get_trustrow(const string& trustor, const string& trusting) { + bool get_trust(const string& trustor, const string& trusting) { const auto& db = control->get_database(); - const auto* t_id = db.find(boost::make_tuple(string_to_name(trustor.c_str()), N(identity), N(trust))); + const auto* t_id = db.find(boost::make_tuple(N(identity), string_to_name(trustor.c_str()), N(trust))); if (!t_id) { - return fc::variant(nullptr); + return false; } uint64_t tng = string_to_name(trusting.c_str()); const auto& idx = db.get_index(); auto itr = idx.lower_bound(boost::make_tuple(t_id->id, tng)); - if ( itr != idx.end() && itr->t_id == t_id->id && tng == itr->primary_key ) { - vector data; - read_only::copy_row(*itr, data); - return abi_ser.binary_to_variant("trustrow", data); - } else { - return fc::variant(nullptr); - } + return ( itr != idx.end() && itr->t_id == t_id->id && tng == itr->primary_key ); //true if found } public: abi_serializer abi_ser; abi_serializer abi_ser_test; + std::string producer_name; }; constexpr uint64_t identity_val = 0xffffffffffffffff; //64-bit value @@ -288,13 +243,13 @@ BOOST_FIXTURE_TEST_CASE( certify_decertify, identity_tester ) try { BOOST_REQUIRE_EQUAL(success(), create_identity("alice", identity_val)); //alice (creator of the identity) certifies 1 property - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector(1, mutable_variant_object() + BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() ("property", "name") ("type", "string") ("data", to_uint8_vector("Alice Smith")) ("memo", "") ("confidence", 100) - ))); + })); auto obj = get_certrow(identity_val, "name", 0, "alice"); BOOST_REQUIRE_EQUAL(true, obj.is_object()); @@ -309,25 +264,47 @@ BOOST_FIXTURE_TEST_CASE( certify_decertify, identity_tester ) try { BOOST_REQUIRE_EQUAL(true, get_certrow(identity_val, "name", 1, "alice").is_null()); //bob certifies 2 properties - vector fields; - fields.push_back(mutable_variant_object() - ("property", "email") - ("type", "string") - ("data", to_uint8_vector("alice@alice.name")) - ("memo", "official email") - ("confidence", 95) - ); - fields.push_back(mutable_variant_object() - ("property", "address") - ("type", "string") - ("data", to_uint8_vector("1750 Kraft Drive SW, Blacksburg, VA 24060")) - ("memo", "official address") - ("confidence", 80) - ); + vector fields = { mutable_variant_object() + ("property", "email") + ("type", "string") + ("data", to_uint8_vector("alice@alice.name")) + ("memo", "official email") + ("confidence", 95), + mutable_variant_object() + ("property", "address") + ("type", "string") + ("data", to_uint8_vector("1750 Kraft Drive SW, Blacksburg, VA 24060")) + ("memo", "official address") + ("confidence", 80) + }; //shouldn't be able to certify without authorization BOOST_REQUIRE_EQUAL(error("missing authority of bob"), certify("bob", identity_val, fields, false)); + //certifying non-existent identity is not allowed + uint64_t non_existent = 11; + BOOST_REQUIRE_EQUAL(error("condition: assertion failed: identity does not exist"), + certify("alice", non_existent, vector{ mutable_variant_object() + ("property", "name") + ("type", "string") + ("data", to_uint8_vector("Alice Smith")) + ("memo", "") + ("confidence", 100) + }) + ); + + //parameter "type" should be not longer than 32 bytes + BOOST_REQUIRE_EQUAL(error("condition: assertion failed: certrow::type should be not longer than 32 bytes"), + certify("alice", identity_val, vector{ mutable_variant_object() + ("property", "height") + ("type", "super_long_type_name_wich_is_not_allowed") + ("data", to_uint8_vector("Alice Smith")) + ("memo", "") + ("confidence", 100) + }) + ); + + //bob also should be able to certify BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, fields)); obj = get_certrow(identity_val, "email", 0, "bob"); @@ -349,13 +326,13 @@ BOOST_FIXTURE_TEST_CASE( certify_decertify, identity_tester ) try { BOOST_REQUIRE_EQUAL( "1750 Kraft Drive SW, Blacksburg, VA 24060", to_string(obj["data"]) ); //now alice certifies another email - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector(1, mutable_variant_object() + BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() ("property", "email") ("type", "string") ("data", to_uint8_vector("alice.smith@gmail.com")) ("memo", "") ("confidence", 100) - ))); + })); obj = get_certrow(identity_val, "email", 0, "alice"); BOOST_REQUIRE_EQUAL(true, obj.is_object()); BOOST_REQUIRE_EQUAL( "email", obj["property"].as_string() ); @@ -371,13 +348,13 @@ BOOST_FIXTURE_TEST_CASE( certify_decertify, identity_tester ) try { BOOST_REQUIRE_EQUAL( "alice@alice.name", to_string(obj["data"]) ); //remove email certification made by alice - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector(1, mutable_variant_object() + BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() ("property", "email") ("type", "string") ("data", to_uint8_vector("")) ("memo", "") ("confidence", 0) - ))); + })); BOOST_REQUIRE_EQUAL(true, get_certrow(identity_val, "email", 0, "alice").is_null()); //email certification made by bob should still be in place @@ -394,32 +371,42 @@ BOOST_FIXTURE_TEST_CASE( certify_decertify, identity_tester ) try { BOOST_FIXTURE_TEST_CASE( trust_untrust, identity_tester ) try { BOOST_REQUIRE_EQUAL(success(), settrust("bob", "alice", 1)); - auto obj = get_trustrow("bob", "alice"); - BOOST_REQUIRE_EQUAL(true, obj.is_object()); - BOOST_REQUIRE_EQUAL( "alice", obj["account"].as_string() ); - BOOST_REQUIRE_EQUAL( 1, obj["trusted"].as_uint64() ); + BOOST_REQUIRE_EQUAL(true, get_trust("bob", "alice")); - obj = get_trustrow("alice", "bob"); - BOOST_REQUIRE_EQUAL(true, obj.is_null()); + //relation of trust in opposite direction should not exist + BOOST_REQUIRE_EQUAL(false, get_trust("alice", "bob")); //remove trust BOOST_REQUIRE_EQUAL(success(), settrust("bob", "alice", 0)); - obj = get_trustrow("bob", "alice"); - BOOST_REQUIRE_EQUAL(true, obj.is_null()); + BOOST_REQUIRE_EQUAL(false, get_trust("bob", "alice")); } FC_LOG_AND_RETHROW() //trust_untrust BOOST_FIXTURE_TEST_CASE( certify_decertify_owner, identity_tester ) try { BOOST_REQUIRE_EQUAL(success(), create_identity("alice", identity_val)); - // certify owner, should populate "account" singleton - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector(1, mutable_variant_object() + //bob certifies ownership for alice + BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(alice))) + ("memo", "claiming onwership") + ("confidence", 100) + })); + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "bob").is_object() ); + //it should not affect "account" singleton in alice's scope since it's not self-certification + BOOST_REQUIRE_EQUAL( true, get_accountrow("alice").is_null() ); + //it also shouldn't affect "account" singleton in bob's scope since he certified not himself + BOOST_REQUIRE_EQUAL( true, get_accountrow("bob").is_null() ); + + // alice certifies her ownership, should populate "account" singleton + BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() ("property", "owner") ("type", "account") ("data", to_uint8_vector(N(alice))) ("memo", "claiming onwership") ("confidence", 100) - ))); + })); fc::variant certrow = get_certrow(identity_val, "owner", 0, "alice"); BOOST_REQUIRE_EQUAL( true, certrow.is_object() ); BOOST_REQUIRE_EQUAL( "owner", certrow["property"].as_string() ); @@ -429,30 +416,245 @@ BOOST_FIXTURE_TEST_CASE( certify_decertify_owner, identity_tester ) try { BOOST_REQUIRE_EQUAL( "account", certrow["type"].as_string() ); BOOST_REQUIRE_EQUAL( N(alice), to_uint64(certrow["data"]) ); - //check that singleton "account" in the scope of identity contains the owner - fc::variant acntrow = get_accountrow(identity_val, "alice"); + //check that singleton "account" in the alice's scope contains the identity + fc::variant acntrow = get_accountrow("alice"); BOOST_REQUIRE_EQUAL( true, certrow.is_object() ); - BOOST_REQUIRE_EQUAL( "alice", acntrow["account"].as_string() ); + BOOST_REQUIRE_EQUAL( identity_val, acntrow["identity"].as_uint64() ); // ownership was certified by alice, but not by a block producer or someone trusted by a block producer BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); + BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); + + //remove bob's certification + BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(alice))) + ("memo", "claiming onwership") + ("confidence", 0) + })); + //singleton "account" in the alice's scope still should contain the identity + acntrow = get_accountrow("alice"); + BOOST_REQUIRE_EQUAL( true, certrow.is_object() ); + BOOST_REQUIRE_EQUAL( identity_val, acntrow["identity"].as_uint64() ); //remove owner certification - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector(1, mutable_variant_object() + BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() ("property", "owner") ("type", "account") ("data", to_uint8_vector(N(alice))) ("memo", "claiming onwership") ("confidence", 0) - ))); + })); certrow = get_certrow(identity_val, "owner", 0, "alice"); BOOST_REQUIRE_EQUAL(true, certrow.is_null()); - //check that singleton "account" in the scope of identity contains the owner - acntrow = get_accountrow(identity_val, "alice"); + //check that singleton "account" in the alice's scope doesn't contain the identity + acntrow = get_accountrow("alice"); BOOST_REQUIRE_EQUAL(true, certrow.is_null()); -} FC_LOG_AND_RETHROW() //certify_owner +} FC_LOG_AND_RETHROW() //certify_decertify_owner + +BOOST_FIXTURE_TEST_CASE( owner_certified_by_producer, identity_tester ) try { + BOOST_REQUIRE_EQUAL(success(), create_identity("alice", identity_val)); + + // certify owner by a block producer, should result in trusted certification + BOOST_REQUIRE_EQUAL(success(), certify( producer_name, identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(alice))) + ("memo", "") + ("confidence", 100) + })); + fc::variant certrow = get_certrow(identity_val, "owner", 1, producer_name); + BOOST_REQUIRE_EQUAL( true, certrow.is_object() ); + BOOST_REQUIRE_EQUAL( "owner", certrow["property"].as_string() ); + BOOST_REQUIRE_EQUAL( 1, certrow["trusted"].as_uint64() ); + BOOST_REQUIRE_EQUAL( producer_name, certrow["certifier"].as_string() ); + BOOST_REQUIRE_EQUAL( N(alice), to_uint64(certrow["data"]) ); + + //uncertified copy of that row shouldn't exist + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, producer_name).is_null()); + + //alice still has not claimed the identity - she is not the official owner yet + BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); + BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); + + + //alice claims it + BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(alice))) + ("memo", "claiming onwership") + ("confidence", 100) + })); + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "alice").is_object()); + + //now alice should be the official owner + BOOST_REQUIRE_EQUAL(N(alice), get_owner_for_identity(identity_val)); + BOOST_REQUIRE_EQUAL(identity_val, get_identity_for_account("alice")); + + //block producer decertifies ownership + BOOST_REQUIRE_EQUAL(success(), certify(producer_name, identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(alice))) + ("memo", "") + ("confidence", 0) + })); + //self-certification made by alice still exists + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "alice").is_object()); + //but now she is not official owner + BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); + BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); + +} FC_LOG_AND_RETHROW() //owner_certified_by_producer + +BOOST_FIXTURE_TEST_CASE( owner_certified_by_trusted_account, identity_tester ) try { + BOOST_REQUIRE_EQUAL(success(), create_identity("bob", identity_val)); + + //alice claims the identity created by bob + BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(alice))) + ("memo", "claiming onwership") + ("confidence", 100) + })); + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "alice").is_object()); + //alice claimed the identity, but it hasn't been certified yet - she is not the official owner + BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); + BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); + + //block producer trusts bob + BOOST_REQUIRE_EQUAL(success(), settrust(producer_name, "bob", 1)); + BOOST_REQUIRE_EQUAL(true, get_trust(producer_name, "bob")); + + // bob (trusted account) certifies alice's ownership, it should result in trusted certification + BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(alice))) + ("memo", "") + ("confidence", 100) + })); + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 1, "bob").is_object() ); + //no untrusted row should exist + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "bob").is_null() ); + + //now alice should be the official owner + BOOST_REQUIRE_EQUAL(N(alice), get_owner_for_identity(identity_val)); + BOOST_REQUIRE_EQUAL(identity_val, get_identity_for_account("alice")); + + //block producer stops trusting bob + BOOST_REQUIRE_EQUAL(success(), settrust(producer_name, "bob", 0)); + BOOST_REQUIRE_EQUAL(false, get_trust(producer_name, "bob")); + + //certification made by bob is still flaged as trusted + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 1, "bob").is_object() ); + + //but now alice shouldn't be the official owner + BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); + BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); + +} FC_LOG_AND_RETHROW() //owner_certified_by_trusted_account + +BOOST_FIXTURE_TEST_CASE( owner_certification_becomes_trusted, identity_tester ) try { + BOOST_REQUIRE_EQUAL(success(), create_identity("bob", identity_val)); + + // bob (not trusted so far) certifies alice's ownership, it should result in untrusted certification + BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(alice))) + ("memo", "") + ("confidence", 100) + })); + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "bob").is_object() ); + //no trusted row should exist + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 1, "bob").is_null() ); + + //alice claims the identity created by bob + BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(alice))) + ("memo", "claiming onwership") + ("confidence", 100) + })); + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "alice").is_object()); + //alice claimed the identity, but it is certified by untrusted accounts only - she is not the official owner + BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); + BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); + + //block producer trusts bob + BOOST_REQUIRE_EQUAL(success(), settrust(producer_name, "bob", 1)); + BOOST_REQUIRE_EQUAL(true, get_trust(producer_name, "bob")); + + //old certification made by bob still shouldn't be flaged as trusted + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "bob").is_object() ); + + //but effectively bob's certification should became trusted + BOOST_REQUIRE_EQUAL(N(alice), get_owner_for_identity(identity_val)); + BOOST_REQUIRE_EQUAL(identity_val, get_identity_for_account("alice")); + +} FC_LOG_AND_RETHROW() //owner_certification_becomes_trusted + +BOOST_FIXTURE_TEST_CASE( ownership_contradiction, identity_tester ) try { + BOOST_REQUIRE_EQUAL(success(), create_identity("alice", identity_val)); + + //alice claims identity + BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(alice))) + ("memo", "claiming onwership") + ("confidence", 100) + })); + + // block producer certifies alice's ownership + BOOST_REQUIRE_EQUAL(success(), certify(producer_name, identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(alice))) + ("memo", "") + ("confidence", 100) + })); + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 1, producer_name).is_object() ); + + //now alice is the official owner of the identity + BOOST_REQUIRE_EQUAL(N(alice), get_owner_for_identity(identity_val)); + BOOST_REQUIRE_EQUAL(identity_val, get_identity_for_account("alice")); + + //bob claims identity + BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(bob))) + ("memo", "claiming onwership") + ("confidence", 100) + })); + + + //block producer trusts carol + BOOST_REQUIRE_EQUAL(success(), settrust(producer_name, "carol", 1)); + BOOST_REQUIRE_EQUAL(true, get_trust(producer_name, "carol")); + + //another trusted delegate certifies bob's identity (to the identity already certified to alice) + BOOST_REQUIRE_EQUAL(success(), certify("carol", identity_val, vector{ mutable_variant_object() + ("property", "owner") + ("type", "account") + ("data", to_uint8_vector(N(bob))) + ("memo", "") + ("confidence", 100) + })); + BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 1, producer_name).is_object() ); + + //now neither alice or bob are official owners, because we have 2 trusted certifications in contradiction to each other + BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); + BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); + +} FC_LOG_AND_RETHROW() //ownership_contradiction BOOST_AUTO_TEST_SUITE_END() -#endif diff --git a/tests/wasm_tests/test_wasts.hpp b/tests/wasm_tests/test_wasts.hpp index 8b2e148283102cec7486a8f088944860b9e1abea..37501cd907d5da78c45799f73331b329cb6a0b2b 100644 --- a/tests/wasm_tests/test_wasts.hpp +++ b/tests/wasm_tests/test_wasts.hpp @@ -96,4 +96,78 @@ static const char grow_memory_wast[] = R"=====( ) ) ) -)====="; \ No newline at end of file +)====="; + +static const char biggest_memory_wast[] = R"=====( +(module + (import "env" "sbrk" (func $sbrk (param i32) (result i32))) + (table 0 anyfunc) + (memory $0 16) + (export "memory" (memory $0)) + (export "apply" (func $apply)) + + (func $apply (param $0 i64) (param $1 i64) + (drop + (call $sbrk + (i32.const 1) + ) + ) + ) +) +)====="; + +static const char too_big_memory_wast[] = R"=====( +(module + (table 0 anyfunc) + (memory $0 17) + (export "memory" (memory $0)) + (export "apply" (func $apply)) + (func $apply (param $0 i64) (param $1 i64)) +) +)====="; + +static const char valid_sparse_table[] = R"=====( +(module + (table 1024 anyfunc) + (func $apply (param $0 i64) (param $1 i64)) + (elem (i32.const 0) $apply) + (elem (i32.const 1022) $apply $apply) +) +)====="; + +static const char too_big_table[] = R"=====( +(module + (table 1025 anyfunc) + (func $apply (param $0 i64) (param $1 i64)) + (elem (i32.const 0) $apply) + (elem (i32.const 1022) $apply $apply) +) +)====="; + +static const char memory_init_borderline[] = R"=====( +(module + (memory $0 16) + (data (i32.const 65532) "sup!") +) +)====="; + +static const char memory_init_toolong[] = R"=====( +(module + (memory $0 16) + (data (i32.const 65533) "sup!") +) +)====="; + +static const char memory_init_negative[] = R"=====( +(module + (memory $0 16) + (data (i32.const -1) "sup!") +) +)====="; + +static const char memory_table_import[] = R"=====( +(module + (table (import "foo" "table") 10 anyfunc) + (memory (import "nom" "memory") 0) +) +)====="; diff --git a/tests/wasm_tests/wasm_tests.cpp b/tests/wasm_tests/wasm_tests.cpp index ec55f4f923ed3e65397a1d3fe3d7ffdb9a635be9..5abf8c0b12d06370fe0f8c6ebd05613c3016d38f 100644 --- a/tests/wasm_tests/wasm_tests.cpp +++ b/tests/wasm_tests/wasm_tests.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -9,6 +10,9 @@ #include #include +#include +#include + #include #include @@ -268,8 +272,8 @@ BOOST_FIXTURE_TEST_CASE( test_api_bootstrap, tester ) try { BOOST_FIXTURE_TEST_CASE( test_proxy, tester ) try { produce_blocks(2); - create_account( N(proxy), asset::from_string("10000.0000 EOS") ); - create_accounts( {N(alice), N(bob)}, asset::from_string("1000.0000 EOS") ); + create_account( N(proxy), asset::from_string("0.0000 EOS") ); + create_accounts( {N(alice), N(bob)}, asset::from_string("0.0000 EOS") ); transfer( N(inita), N(alice), "10.0000 EOS", "memo" ); produce_block(); @@ -324,8 +328,8 @@ BOOST_FIXTURE_TEST_CASE( test_proxy, tester ) try { BOOST_FIXTURE_TEST_CASE( test_deferred_failure, tester ) try { produce_blocks(2); - create_accounts( {N(proxy), N(bob)}, asset::from_string("10000.0000 EOS") ); - create_account( N(alice), asset::from_string("1000.0000 EOS") ); + create_accounts( {N(proxy), N(bob)}, asset::from_string("0.0000 EOS") ); + create_account( N(alice), asset::from_string("0.0000 EOS") ); transfer( N(inita), N(alice), "10.0000 EOS", "memo" ); produce_block(); @@ -490,7 +494,7 @@ BOOST_FIXTURE_TEST_CASE( check_global_reset, tester ) try { { action act; act.account = N(globalreset); - act.name = 0ULL; + act.name = name(0ULL); act.authorization = vector{{N(globalreset),config::active_name}}; trx.actions.push_back(act); } @@ -519,36 +523,241 @@ BOOST_FIXTURE_TEST_CASE( memory_operators, tester ) try { transfer( N(inita), N(current_memory), "10.0000 EOS", "memo" ); produce_block(); - set_code(N(current_memory), current_memory_wast); + BOOST_CHECK_THROW(set_code(N(current_memory), current_memory_wast), eosio::chain::wasm_execution_error); + produce_blocks(1); + + BOOST_CHECK_THROW(set_code(N(current_memory), grow_memory_wast), eosio::chain::wasm_execution_error); + produce_blocks(1); + +} FC_LOG_AND_RETHROW() + +//Make sure we can create a wasm with 16 pages, but not grow it any +BOOST_FIXTURE_TEST_CASE( big_memory, tester ) try { + produce_blocks(2); + + create_accounts( {N(bigmem)}, asset::from_string("1000.0000 EOS") ); + transfer( N(inita), N(bigmem), "10.0000 EOS", "memo" ); + produce_block(); + + set_code(N(bigmem), biggest_memory_wast); //should pass, 16 pages is fine + produce_blocks(1); + + signed_transaction trx; + action act; + act.account = N(bigmem); + act.name = N(); + act.authorization = vector{{N(bigmem),config::active_name}}; + trx.actions.push_back(act); + + set_tapos(trx); + trx.sign(get_private_key( N(bigmem), "active" ), chain_id_type()); + //but should not be able to grow beyond 16th page + BOOST_CHECK_THROW(push_transaction(trx), fc::exception); + produce_blocks(1); + + //should fail, 17 blocks is no no + BOOST_CHECK_THROW(set_code(N(bigmem), too_big_memory_wast), eosio::chain::wasm_execution_error); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( table_init_tests, tester ) try { + produce_blocks(2); + + create_accounts( {N(tableinit)}, asset::from_string("1000.0000 EOS") ); + transfer( N(inita), N(tableinit), "10.0000 EOS", "memo" ); + produce_block(); + + set_code(N(tableinit), valid_sparse_table); + produce_blocks(1); + + BOOST_CHECK_THROW(set_code(N(tableinit), too_big_table), eosio::chain::wasm_execution_error); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( memory_init_border, tester ) try { + produce_blocks(2); + + create_accounts( {N(memoryborder)}, asset::from_string("1000.0000 EOS") ); + transfer( N(inita), N(memoryborder), "10.0000 EOS", "memo" ); + produce_block(); + + set_code(N(memoryborder), memory_init_borderline); + produce_blocks(1); + + BOOST_CHECK_THROW(set_code(N(memoryborder), memory_init_toolong), eosio::chain::wasm_execution_error); + BOOST_CHECK_THROW(set_code(N(memoryborder), memory_init_negative), eosio::chain::wasm_execution_error); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( imports, tester ) try { + produce_blocks(2); + + create_accounts( {N(imports)}, asset::from_string("1000.0000 EOS") ); + transfer( N(inita), N(imports), "10.0000 EOS", "memo" ); + produce_block(); + + //this will fail to link but that's okay; mainly looking to make sure that the constraint + // system doesn't choke when memories and tables exist only as imports + BOOST_CHECK_THROW(set_code(N(imports), memory_table_import), fc::exception); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( lotso_globals, tester ) try { + produce_blocks(2); + + create_accounts( {N(globals)}, asset::from_string("1000.0000 EOS") ); + transfer( N(inita), N(globals), "10.0000 EOS", "memo" ); + produce_block(); + + std::stringstream ss; + ss << "(module "; + for(unsigned int i = 0; i < 85; ++i) + ss << "(global $g" << i << " (mut i32) (i32.const 0))" << "(global $g" << i+100 << " (mut i64) (i64.const 0))"; + //that gives us 1020 bytes of mutable globals + //add a few immutable ones for good measure + for(unsigned int i = 0; i < 10; ++i) + ss << "(global $g" << i+200 << " i32 (i32.const 0))"; + + set_code(N(globals), + string(ss.str() + ")") + .c_str()); + //1024 should pass + set_code(N(globals), + string(ss.str() + "(global $z (mut i32) (i32.const -12)))") + .c_str()); + //1028 should fail + BOOST_CHECK_THROW(set_code(N(globals), + string(ss.str() + "(global $z (mut i64) (i64.const -12)))") + .c_str()), eosio::chain::wasm_execution_error);; + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( offset_check, tester ) try { + produce_blocks(2); + + create_accounts( {N(offsets)}, asset::from_string("1000.0000 EOS") ); + transfer( N(inita), N(offsets), "10.0000 EOS", "memo" ); + produce_block(); + + //floats not tested since they are blocked in the serializer before eosio_constraints + vector loadops = { + "i32.load", "i64.load", /* "f32.load", "f64.load",*/ "i32.load8_s", "i32.load8_u", + "i32.load16_s", "i32.load16_u", "i64.load8_s", "i64.load8_u", "i64.load16_s", + "i64.load16_u", "i64.load32_s", "i64.load32_u" + }; + vector> storeops = { + {"i32.store", "i32"}, + {"i64.store", "i64"}, + /*{"f32.store", "f32"}, + {"f64.store", "f64"},*/ + {"i32.store8", "i32"}, + {"i32.store16", "i32"}, + {"i64.store8", "i64"}, + {"i64.store16", "i64"}, + {"i64.store32", "i64"}, + }; + + for(const string& s : loadops) { + std::stringstream ss; + ss << "(module (memory $0 16) (func $apply (param $0 i64) (param $1 i64) "; + ss << "(drop (" << s << " offset=1048574 (i32.const 0)))"; + ss << "))"; + + set_code(N(offsets), ss.str().c_str()); + produce_block(); + } + for(const vector& o : storeops) { + std::stringstream ss; + ss << "(module (memory $0 16) (func $apply (param $0 i64) (param $1 i64) "; + ss << "(" << o[0] << " offset=1048574 (i32.const 0) (" << o[1] << ".const 0))"; + ss << "))"; + + set_code(N(offsets), ss.str().c_str()); + produce_block(); + } + + for(const string& s : loadops) { + std::stringstream ss; + ss << "(module (memory $0 16) (func $apply (param $0 i64) (param $1 i64) "; + ss << "(drop (" << s << " offset=1048580 (i32.const 0)))"; + ss << "))"; + + BOOST_CHECK_THROW(set_code(N(offsets), ss.str().c_str()), eosio::chain::wasm_execution_error); + produce_block(); + } + for(const vector& o : storeops) { + std::stringstream ss; + ss << "(module (memory $0 16) (func $apply (param $0 i64) (param $1 i64) "; + ss << "(" << o[0] << " offset=1048580 (i32.const 0) (" << o[1] << ".const 0))"; + ss << "))"; + + BOOST_CHECK_THROW(set_code(N(offsets), ss.str().c_str()), eosio::chain::wasm_execution_error); + produce_block(); + } + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(noop, tester) try { + produce_blocks(2); + create_accounts( {N(noop), N(alice)}, asset::from_string("1000.0000 EOS") ); + produce_block(); + + set_code(N(noop), noop_wast); + set_abi(N(noop), noop_abi); + const auto& accnt = control->get_database().get(N(noop)); + abi_def abi; + BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); + abi_serializer abi_ser(abi); + { + produce_blocks(5); signed_transaction trx; action act; - act.account = N(current_memory); - act.authorization = vector{{N(current_memory),config::active_name}}; - trx.actions.push_back(act); + act.account = N(noop); + act.name = N(anyaction); + act.authorization = vector{{N(noop), config::active_name}}; + + act.data = abi_ser.variant_to_binary("anyaction", mutable_variant_object() + ("from", "noop") + ("type", "some type") + ("data", "some data goes here") + ); + + trx.actions.emplace_back(std::move(act)); + set_tapos(trx); - trx.sign(get_private_key( N(current_memory), "active" ), chain_id_type()); + trx.sign(get_private_key(N(noop), "active"), chain_id_type()); + push_transaction(trx); + produce_block(); - BOOST_CHECK_THROW(push_transaction(trx), fc::unhandled_exception); + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); } - produce_blocks(1); - set_code(N(current_memory), grow_memory_wast); - produce_blocks(1); { + produce_blocks(5); signed_transaction trx; action act; - act.account = N(current_memory); - act.authorization = vector{{N(current_memory),config::active_name}}; - trx.actions.push_back(act); + act.account = N(noop); + act.name = N(anyaction); + act.authorization = vector{{N(alice), config::active_name}}; + + act.data = abi_ser.variant_to_binary("anyaction", mutable_variant_object() + ("from", "alice") + ("type", "some type") + ("data", "some data goes here") + ); + + trx.actions.emplace_back(std::move(act)); + set_tapos(trx); - trx.sign(get_private_key( N(current_memory), "active" ), chain_id_type()); + trx.sign(get_private_key(N(alice), "active"), chain_id_type()); + push_transaction(trx); + produce_block(); - BOOST_CHECK_THROW(push_transaction(trx), fc::unhandled_exception); - produce_blocks(1); + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); } -} FC_LOG_AND_RETHROW() + } FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5113c371342bf9b132cac9efe086ee1a1b60b03e..3aa84e954d5b9fc2959b5cd206b312455fa98fa1 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,2 +1,2 @@ -configure_file( eoscpp.in eoscpp @ONLY) -install( FILES ${CMAKE_CURRENT_BINARY_DIR}/eoscpp DESTINATION bin/ PERMISSIONS WORLD_EXECUTE OWNER_EXECUTE GROUP_EXECUTE WORLD_READ GROUP_READ OWNER_READ ) +configure_file( eosiocpp.in eosiocpp @ONLY) +install( FILES ${CMAKE_CURRENT_BINARY_DIR}/eosiocpp DESTINATION bin/ PERMISSIONS WORLD_EXECUTE OWNER_EXECUTE GROUP_EXECUTE WORLD_READ GROUP_READ OWNER_READ ) diff --git a/tools/eoscpp.in b/tools/eosiocpp.in similarity index 100% rename from tools/eoscpp.in rename to tools/eosiocpp.in